drm/amd/display: Display distortion after hotplug 5K tiled display
authorMeenakshikumar Somasundaram <meenakshikumar.somasundaram@amd.com>
Wed, 31 Aug 2022 17:27:07 +0000 (13:27 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 21 Sep 2022 21:27:09 +0000 (17:27 -0400)
[Why]
During hot plug of specific 5K tiled display, sometimes both the tiles
are not synchronized resulting in distortion. The reason is that otgs of
both the tiles goes out of sync when otg workaround (dcnxxx_disable_otg_wa)
is applied for bandwidth optimization. The otg workaround reenables otg
but otg synchronization context is not reset and hence dc_trigger_sync()
does not resynchronize otg again.

[How]
Implement reset_sync_context_for_pipe() to reset the otg synchronization
context for the disabled pipe and its slave pipes when otg workaround is
applied.

Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Wayne Lin <wayne.lin@amd.com>
Signed-off-by: Meenakshikumar Somasundaram <meenakshikumar.somasundaram@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/inc/resource.h

index c09be3f15fe63a0f010f0aeec682f7f8a0d48b28..23a299c929a1369d902979393542ad2bfaf68f55 100644 (file)
@@ -99,7 +99,7 @@ static int dcn31_get_active_display_cnt_wa(
        return display_count;
 }
 
-static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
+static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
 {
        struct dc *dc = clk_mgr_base->ctx->dc;
        int i;
@@ -110,9 +110,10 @@ static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
                if (pipe->top_pipe || pipe->prev_odm_pipe)
                        continue;
                if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) {
-                       if (disable)
+                       if (disable) {
                                pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
-                       else
+                               reset_sync_context_for_pipe(dc, context, i);
+                       } else
                                pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
                }
        }
@@ -211,11 +212,11 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base,
        }
 
        if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
-               dcn31_disable_otg_wa(clk_mgr_base, true);
+               dcn31_disable_otg_wa(clk_mgr_base, context, true);
 
                clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
                dcn31_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
-               dcn31_disable_otg_wa(clk_mgr_base, false);
+               dcn31_disable_otg_wa(clk_mgr_base, context, false);
 
                update_dispclk = true;
        }
index 9781a8dbc2386abb45191c903e7636768b9bc5af..6284c4bd1f5055c0b8a2c752fd8fd76586e6c857 100644 (file)
@@ -119,7 +119,7 @@ static int dcn314_get_active_display_cnt_wa(
        return display_count;
 }
 
-static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
+static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
 {
        struct dc *dc = clk_mgr_base->ctx->dc;
        int i;
@@ -131,9 +131,10 @@ static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
                        continue;
                if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
                                     dc_is_virtual_signal(pipe->stream->signal))) {
-                       if (disable)
+                       if (disable) {
                                pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
-                       else
+                               reset_sync_context_for_pipe(dc, context, i);
+                       } else
                                pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
                }
        }
@@ -233,11 +234,11 @@ void dcn314_update_clocks(struct clk_mgr *clk_mgr_base,
        }
 
        if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
-               dcn314_disable_otg_wa(clk_mgr_base, true);
+               dcn314_disable_otg_wa(clk_mgr_base, context, true);
 
                clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
                dcn314_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
-               dcn314_disable_otg_wa(clk_mgr_base, false);
+               dcn314_disable_otg_wa(clk_mgr_base, context, false);
 
                update_dispclk = true;
        }
index 8c7daffdeae4115766906f7f35986e583abf99e8..0bb37bb72aca35cd15c29d9be756cfd2e7569a02 100644 (file)
@@ -79,7 +79,7 @@ static int dcn315_get_active_display_cnt_wa(
        return display_count;
 }
 
-static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
+static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
 {
        struct dc *dc = clk_mgr_base->ctx->dc;
        int i;
@@ -91,9 +91,10 @@ static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
                        continue;
                if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
                                     dc_is_virtual_signal(pipe->stream->signal))) {
-                       if (disable)
+                       if (disable) {
                                pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
-                       else
+                               reset_sync_context_for_pipe(dc, context, i);
+                       } else
                                pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
                }
        }
@@ -175,12 +176,12 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
        if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
                /* No need to apply the w/a if we haven't taken over from bios yet */
                if (clk_mgr_base->clks.dispclk_khz)
-                       dcn315_disable_otg_wa(clk_mgr_base, true);
+                       dcn315_disable_otg_wa(clk_mgr_base, context, true);
 
                clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
                dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
                if (clk_mgr_base->clks.dispclk_khz)
-                       dcn315_disable_otg_wa(clk_mgr_base, false);
+                       dcn315_disable_otg_wa(clk_mgr_base, context, false);
 
                update_dispclk = true;
        }
index 0cd3d2eb7ac700f26f1bec4166f737114cfe475f..187f5b27fdc80dec1545a7c75d5622dd04d4e368 100644 (file)
@@ -112,7 +112,7 @@ static int dcn316_get_active_display_cnt_wa(
        return display_count;
 }
 
-static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
+static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable)
 {
        struct dc *dc = clk_mgr_base->ctx->dc;
        int i;
@@ -124,9 +124,10 @@ static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
                        continue;
                if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
                                     dc_is_virtual_signal(pipe->stream->signal))) {
-                       if (disable)
+                       if (disable) {
                                pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
-                       else
+                               reset_sync_context_for_pipe(dc, context, i);
+                       } else
                                pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
                }
        }
@@ -221,11 +222,11 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base,
        }
 
        if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
-               dcn316_disable_otg_wa(clk_mgr_base, true);
+               dcn316_disable_otg_wa(clk_mgr_base, context, true);
 
                clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
                dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
-               dcn316_disable_otg_wa(clk_mgr_base, false);
+               dcn316_disable_otg_wa(clk_mgr_base, context, false);
 
                update_dispclk = true;
        }
index 7dbab15bfa68fc0d8cd1ccfc1e242d7901803959..ccf7bd3d90fe7ddd653a07b9bc086c9e73091d2e 100644 (file)
@@ -3584,6 +3584,23 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
        }
 }
 
+void reset_sync_context_for_pipe(const struct dc *dc,
+       struct dc_state *context,
+       uint8_t pipe_idx)
+{
+       int i;
+       struct pipe_ctx *pipe_ctx_reset;
+
+       /* reset the otg sync context for the pipe and its slave pipes if any */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe_ctx_reset = &context->res_ctx.pipe_ctx[i];
+
+               if (((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_reset) == pipe_idx) &&
+                       IS_PIPE_SYNCD_VALID(pipe_ctx_reset)) || (i == pipe_idx))
+                       SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_reset, i);
+       }
+}
+
 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
 {
        /* TODO - get transmitter to phy idx mapping from DMUB */
index 58158764adc0a6f94c326f10f734e9a094abf93e..7614125c92c70b6f284e85e64e86135a2149515d 100644 (file)
@@ -219,6 +219,10 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
        struct dc_state *context,
        uint8_t disabled_master_pipe_idx);
 
+void reset_sync_context_for_pipe(const struct dc *dc,
+       struct dc_state *context,
+       uint8_t pipe_idx);
+
 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter);
 
 const struct link_hwss *get_link_hwss(const struct dc_link *link,