aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1824-drm-amd-display-Refactor-CRTC-interrupt-toggling-log.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1824-drm-amd-display-Refactor-CRTC-interrupt-toggling-log.patch')
-rw-r--r--meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1824-drm-amd-display-Refactor-CRTC-interrupt-toggling-log.patch234
1 files changed, 234 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1824-drm-amd-display-Refactor-CRTC-interrupt-toggling-log.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1824-drm-amd-display-Refactor-CRTC-interrupt-toggling-log.patch
new file mode 100644
index 00000000..c43d619e
--- /dev/null
+++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/1824-drm-amd-display-Refactor-CRTC-interrupt-toggling-log.patch
@@ -0,0 +1,234 @@
+From b8576a2773e4fdc8aed1dfe6ae0954ba53245da1 Mon Sep 17 00:00:00 2001
+From: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Date: Fri, 5 Apr 2019 09:35:14 -0400
+Subject: [PATCH 1824/2940] drm/amd/display: Refactor CRTC interrupt toggling
+ logic
+
+[Why]
+The vblank and pageflip interrupts should only be enabled for a CRTC
+that's enabled and has active planes.
+
+The current logic takes care of this, but isn't setup to handle the case
+where the active plane count goes to zero but the stream remains
+enabled.
+
+We currently block this case since we don't allow commits that enable a
+CRTC with no active planes, but shouldn't be any reason we can't support
+this from a hardware perspective and many userspace applications expect
+to be able to do it (like IGT).
+
+[How]
+The count_crtc_active_planes function fills in the number of
+"active_planes" on the dm_crtc_state. This should be the same as
+DC's plane_count on the stream_status but easier to access since we
+don't need to lock the private atomic state with the DC context.
+
+Add the "interrupts_enabled" flag to the dm_crtc_state and set it based
+on whether the stream exists and if there are active planes on the
+stream.
+
+Update the disable and enable logic to make use of this new flag.
+
+There shouldn't be any functional change (yet) with this patch.
+
+Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
+Reviewed-by: David Francis <David.Francis@amd.com>
+Acked-by: Leo Li <sunpeng.li@amd.com>
+Signed-off-by: Chaudhary Amit Kumar <Chaudharyamit.Kumar@amd.com>
+---
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 104 +++++++++++++-----
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 +
+ 2 files changed, 80 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index ac3ac629d4cb..65c15ae620bd 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -3525,6 +3525,8 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
+ dc_stream_retain(state->stream);
+ }
+
++ state->active_planes = cur->active_planes;
++ state->interrupts_enabled = cur->interrupts_enabled;
+ state->vrr_params = cur->vrr_params;
+ state->vrr_infopacket = cur->vrr_infopacket;
+ state->abm_level = cur->abm_level;
+@@ -3974,7 +3976,7 @@ static void dm_crtc_helper_disable(struct drm_crtc *crtc)
+ {
+ }
+
+-static bool does_crtc_have_active_plane(struct drm_crtc_state *new_crtc_state)
++static int count_crtc_active_planes(struct drm_crtc_state *new_crtc_state)
+ {
+ struct drm_atomic_state *state = new_crtc_state->state;
+ struct drm_plane *plane;
+@@ -4003,7 +4005,32 @@ static bool does_crtc_have_active_plane(struct drm_crtc_state *new_crtc_state)
+ num_active += (new_plane_state->fb != NULL);
+ }
+
+- return num_active > 0;
++ return num_active;
++}
++
++/*
++ * Sets whether interrupts should be enabled on a specific CRTC.
++ * We require that the stream be enabled and that there exist active
++ * DC planes on the stream.
++ */
++static void
++dm_update_crtc_interrupt_state(struct drm_crtc *crtc,
++ struct drm_crtc_state *new_crtc_state)
++{
++ struct dm_crtc_state *dm_new_crtc_state =
++ to_dm_crtc_state(new_crtc_state);
++
++ dm_new_crtc_state->active_planes = 0;
++ dm_new_crtc_state->interrupts_enabled = false;
++
++ if (!dm_new_crtc_state->stream)
++ return;
++
++ dm_new_crtc_state->active_planes =
++ count_crtc_active_planes(new_crtc_state);
++
++ dm_new_crtc_state->interrupts_enabled =
++ dm_new_crtc_state->active_planes > 0;
+ }
+
+ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
+@@ -4014,6 +4041,14 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
+ struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state);
+ int ret = -EINVAL;
+
++ /*
++ * Update interrupt state for the CRTC. This needs to happen whenever
++ * the CRTC has changed or whenever any of its planes have changed.
++ * Atomic check satisfies both of these requirements since the CRTC
++ * is added to the state by DRM during drm_atomic_helper_check_planes.
++ */
++ dm_update_crtc_interrupt_state(crtc, state);
++
+ if (unlikely(!dm_crtc_state->stream &&
+ modeset_required(state, NULL, dm_crtc_state->stream))) {
+ WARN_ON(1);
+@@ -4026,7 +4061,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
+
+ /* We want at least one hardware plane enabled to use the stream. */
+ if (state->enable && state->active &&
+- !does_crtc_have_active_plane(state))
++ dm_crtc_state->active_planes == 0)
+ return -EINVAL;
+
+ if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
+@@ -5510,28 +5545,43 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
+ struct amdgpu_device *adev = dev->dev_private;
+ int i;
+
+- /*
+- * We evade vblanks and pflips on crtc that
+- * should be changed. We do it here to flush & disable
+- * interrupts before drm_swap_state is called in drm_atomic_helper_commit
+- * it will update crtc->dm_crtc_state->stream pointer which is used in
+- * the ISRs.
++ /*
++ * We evade vblank and pflip interrupts on CRTCs that are undergoing
++ * a modeset, being disabled, or have no active planes.
++ *
++ * It's done in atomic commit rather than commit tail for now since
++ * some of these interrupt handlers access the current CRTC state and
++ * potentially the stream pointer itself.
++ *
++ * Since the atomic state is swapped within atomic commit and not within
++ * commit tail this would leave to new state (that hasn't been committed yet)
++ * being accesssed from within the handlers.
++ *
++ * TODO: Fix this so we can do this in commit tail and not have to block
++ * in atomic check.
+ */
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+ struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+
+- if (drm_atomic_crtc_needs_modeset(new_crtc_state)
+- && dm_old_crtc_state->stream) {
++ if (dm_old_crtc_state->interrupts_enabled &&
++ (!dm_new_crtc_state->interrupts_enabled ||
++ drm_atomic_crtc_needs_modeset(new_crtc_state))) {
+ /*
+- * CRC capture was enabled but not disabled.
+- * Release the vblank reference.
+- */
+- if (dm_new_crtc_state->crc_enabled) {
+- drm_crtc_vblank_put(crtc);
+- dm_new_crtc_state->crc_enabled = false;
+- }
++ * Drop the extra vblank reference added by CRC
++ * capture if applicable.
++ */
++ if (dm_new_crtc_state->crc_enabled)
++ drm_crtc_vblank_put(crtc);
++
++ /*
++ * Only keep CRC capture enabled if there's
++ * still a stream for the CRTC.
++ */
++ if (!dm_new_crtc_state->stream)
++ dm_new_crtc_state->crc_enabled = false;
++
+
+ manage_dm_interrupts(adev, acrtc, false);
+ }
+@@ -5751,13 +5801,14 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
+ pre_update_freesync_state_on_stream(dm, dm_new_crtc_state);
+ }
+
++ /*
++ * Enable interrupts on CRTCs that are newly active, undergone
++ * a modeset, or have active planes again.
++ */
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
+ new_crtc_state, i) {
+- /*
+- * loop to enable interrupts on newly arrived crtc
+- */
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+- bool modeset_needed;
++ bool enable;
+
+ if (old_crtc_state->active && !new_crtc_state->active)
+ crtc_disable_count++;
+@@ -5769,12 +5820,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
+ amdgpu_dm_handle_vrr_transition(dm_old_crtc_state,
+ dm_new_crtc_state);
+
+- modeset_needed = modeset_required(
+- new_crtc_state,
+- dm_new_crtc_state->stream,
+- dm_old_crtc_state->stream);
++ enable = dm_new_crtc_state->interrupts_enabled &&
++ (!dm_old_crtc_state->interrupts_enabled ||
++ drm_atomic_crtc_needs_modeset(new_crtc_state));
+
+- if (dm_new_crtc_state->stream == NULL || !modeset_needed)
++ if (!enable)
+ continue;
+
+ manage_dm_interrupts(adev, acrtc, true);
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+index e194bf79ca90..715a2d66a0a7 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+@@ -268,6 +268,9 @@ struct dm_crtc_state {
+ struct drm_crtc_state base;
+ struct dc_stream_state *stream;
+
++ int active_planes;
++ bool interrupts_enabled;
++
+ int crc_skip_count;
+ bool crc_enabled;
+
+--
+2.17.1
+