Commit 72002056 authored by Meenakshikumar Somasundaram's avatar Meenakshikumar Somasundaram Committed by Alex Deucher

drm/amd/display: Display distortion after hotplug 5K tiled display

[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: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarWayne Lin <wayne.lin@amd.com>
Signed-off-by: default avatarMeenakshikumar Somasundaram <meenakshikumar.somasundaram@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 056fb8cf
...@@ -99,7 +99,7 @@ static int dcn31_get_active_display_cnt_wa( ...@@ -99,7 +99,7 @@ static int dcn31_get_active_display_cnt_wa(
return display_count; 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; struct dc *dc = clk_mgr_base->ctx->dc;
int i; int i;
...@@ -110,9 +110,10 @@ static void dcn31_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) ...@@ -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) if (pipe->top_pipe || pipe->prev_odm_pipe)
continue; continue;
if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { 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); 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); 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, ...@@ -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)) { 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; clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
dcn31_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.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; update_dispclk = true;
} }
......
...@@ -119,7 +119,7 @@ static int dcn314_get_active_display_cnt_wa( ...@@ -119,7 +119,7 @@ static int dcn314_get_active_display_cnt_wa(
return display_count; 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; struct dc *dc = clk_mgr_base->ctx->dc;
int i; int i;
...@@ -131,9 +131,10 @@ static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) ...@@ -131,9 +131,10 @@ static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
continue; continue;
if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
dc_is_virtual_signal(pipe->stream->signal))) { dc_is_virtual_signal(pipe->stream->signal))) {
if (disable) if (disable) {
pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); 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); 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, ...@@ -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)) { 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; clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
dcn314_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.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; update_dispclk = true;
} }
......
...@@ -79,7 +79,7 @@ static int dcn315_get_active_display_cnt_wa( ...@@ -79,7 +79,7 @@ static int dcn315_get_active_display_cnt_wa(
return display_count; 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; struct dc *dc = clk_mgr_base->ctx->dc;
int i; int i;
...@@ -91,9 +91,10 @@ static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) ...@@ -91,9 +91,10 @@ static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
continue; continue;
if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
dc_is_virtual_signal(pipe->stream->signal))) { dc_is_virtual_signal(pipe->stream->signal))) {
if (disable) if (disable) {
pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); 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); 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, ...@@ -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)) { 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 */ /* No need to apply the w/a if we haven't taken over from bios yet */
if (clk_mgr_base->clks.dispclk_khz) 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; clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
if (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; update_dispclk = true;
} }
......
...@@ -112,7 +112,7 @@ static int dcn316_get_active_display_cnt_wa( ...@@ -112,7 +112,7 @@ static int dcn316_get_active_display_cnt_wa(
return display_count; 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; struct dc *dc = clk_mgr_base->ctx->dc;
int i; int i;
...@@ -124,9 +124,10 @@ static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable) ...@@ -124,9 +124,10 @@ static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
continue; continue;
if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
dc_is_virtual_signal(pipe->stream->signal))) { dc_is_virtual_signal(pipe->stream->signal))) {
if (disable) if (disable) {
pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); 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); 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, ...@@ -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)) { 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; clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.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; update_dispclk = true;
} }
......
...@@ -3584,6 +3584,23 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, ...@@ -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) uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
{ {
/* TODO - get transmitter to phy idx mapping from DMUB */ /* TODO - get transmitter to phy idx mapping from DMUB */
......
...@@ -219,6 +219,10 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, ...@@ -219,6 +219,10 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
struct dc_state *context, struct dc_state *context,
uint8_t disabled_master_pipe_idx); 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); 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, const struct link_hwss *get_link_hwss(const struct dc_link *link,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment