drm/amd/display: Fix video glitch while drag window in PSR-SU
authorTom Chung <chiahsuan.chung@amd.com>
Wed, 1 Feb 2023 09:37:51 +0000 (17:37 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 14 Feb 2023 21:04:17 +0000 (16:04 -0500)
[Why]
Dmub will cache the video position data during PSR-SU enable.
The dmub will use an outdated MPO video position if user try
to drag the video window and it will cause video glitch.

[How]
Disable the PSR-SU temporarily while user drag the video window.
The PSR-SU will be re-enabled after the video window is stable.

Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com>
Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/dc_link.h

index e532ef2..c13efba 100644 (file)
@@ -5044,6 +5044,7 @@ out:
  * @new_plane_state: New state of @plane
  * @crtc_state: New state of CRTC connected to the @plane
  * @flip_addrs: DC flip tracking struct, which also tracts dirty rects
+ * @dirty_regions_changed: dirty regions changed
  *
  * For PSR SU, DC informs the DMUB uController of dirty rectangle regions
  * (referred to as "damage clips" in DRM nomenclature) that require updating on
@@ -5060,7 +5061,8 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
                                struct drm_plane_state *old_plane_state,
                                struct drm_plane_state *new_plane_state,
                                struct drm_crtc_state *crtc_state,
-                               struct dc_flip_addrs *flip_addrs)
+                               struct dc_flip_addrs *flip_addrs,
+                               bool *dirty_regions_changed)
 {
        struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
        struct rect *dirty_rects = flip_addrs->dirty_rects;
@@ -5069,6 +5071,7 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
        bool bb_changed;
        bool fb_changed;
        u32 i = 0;
+       *dirty_regions_changed = false;
 
        /*
         * Cursor plane has it's own dirty rect update interface. See
@@ -5113,6 +5116,8 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
                new_plane_state->plane->base.id,
                bb_changed, fb_changed, num_clips);
 
+       *dirty_regions_changed = bb_changed;
+
        if (bb_changed) {
                fill_dc_dirty_rect(new_plane_state->plane, &dirty_rects[i],
                                   new_plane_state->crtc_x,
@@ -7863,7 +7868,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                    bool wait_for_vblank)
 {
        u32 i;
-       u64 timestamp_ns;
+       u64 timestamp_ns = ktime_get_ns();
        struct drm_plane *plane;
        struct drm_plane_state *old_plane_state, *new_plane_state;
        struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
@@ -7878,6 +7883,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
        bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
        bool cursor_update = false;
        bool pflip_present = false;
+       bool dirty_rects_changed = false;
        struct {
                struct dc_surface_update surface_updates[MAX_SURFACES];
                struct dc_plane_info plane_infos[MAX_SURFACES];
@@ -7965,10 +7971,32 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                bundle->surface_updates[planes_count].plane_info =
                        &bundle->plane_infos[planes_count];
 
-               if (acrtc_state->stream->link->psr_settings.psr_feature_enabled)
+               if (acrtc_state->stream->link->psr_settings.psr_feature_enabled) {
                        fill_dc_dirty_rects(plane, old_plane_state,
                                            new_plane_state, new_crtc_state,
-                                           &bundle->flip_addrs[planes_count]);
+                                           &bundle->flip_addrs[planes_count],
+                                           &dirty_rects_changed);
+
+                       /*
+                        * If the dirty regions changed, PSR-SU need to be disabled temporarily
+                        * and enabled it again after dirty regions are stable to avoid video glitch.
+                        * PSR-SU will be enabled in vblank_control_worker() if user pause the video
+                        * during the PSR-SU was disabled.
+                        */
+                       if (acrtc_state->stream->link->psr_settings.psr_version >= DC_PSR_VERSION_SU_1 &&
+                           acrtc_attach->dm_irq_params.allow_psr_entry &&
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+                           !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
+#endif
+                           dirty_rects_changed) {
+                               mutex_lock(&dm->dc_lock);
+                               acrtc_state->stream->link->psr_settings.psr_dirty_rects_change_timestamp_ns =
+                               timestamp_ns;
+                               if (acrtc_state->stream->link->psr_settings.psr_allow_active)
+                                       amdgpu_dm_psr_disable(acrtc_state->stream);
+                               mutex_unlock(&dm->dc_lock);
+                       }
+               }
 
                /*
                 * Only allow immediate flips for fast updates that don't
@@ -8187,7 +8215,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
 #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
                            !amdgpu_dm_crc_window_is_activated(acrtc_state->base.crtc) &&
 #endif
-                           !acrtc_state->stream->link->psr_settings.psr_allow_active)
+                           !acrtc_state->stream->link->psr_settings.psr_allow_active &&
+                           (timestamp_ns -
+                           acrtc_state->stream->link->psr_settings.psr_dirty_rects_change_timestamp_ns) >
+                           500000000)
                                amdgpu_dm_psr_enable(acrtc_state->stream);
                } else {
                        acrtc_attach->dm_irq_params.allow_psr_entry = false;
index 99cfe6c..ae51e4c 100644 (file)
@@ -102,6 +102,7 @@ struct psr_settings {
        bool psr_allow_active;                  // PSR is currently active
        enum dc_psr_version psr_version;                // Internal PSR version, determined based on DPCD
        bool psr_vtotal_control_support;        // Vtotal control is supported by sink
+       unsigned long long psr_dirty_rects_change_timestamp_ns; // for delay of enabling PSR-SU
 
        /* These parameters are calculated in Driver,
         * based on display timing and Sink capabilities.