diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/2893-drm-amd-display-Implement-work-around-for-optc-under.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.14.71/2893-drm-amd-display-Implement-work-around-for-optc-under.patch | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/2893-drm-amd-display-Implement-work-around-for-optc-under.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/2893-drm-amd-display-Implement-work-around-for-optc-under.patch new file mode 100644 index 00000000..81e27a18 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/2893-drm-amd-display-Implement-work-around-for-optc-under.patch @@ -0,0 +1,196 @@ +From 73b9e343583b559a3a2307957a8e9aadbaf480e4 Mon Sep 17 00:00:00 2001 +From: Yongqiang Sun <yongqiang.sun@amd.com> +Date: Wed, 15 Nov 2017 16:21:34 -0500 +Subject: [PATCH 2893/4131] drm/amd/display: Implement work around for optc + underflow. + +Work around for a hw bug causing optc underflow if blank data +double buffer disable and remove mpcc. +Checking optc status after otg unlock, after wait mpcc idle +check status again, if optc underflow just happens after wait +mpcc idle, clear underflow status and enable blank data double +buffer. + +Signed-off-by: Yongqiang Sun <yongqiang.sun@amd.com> +Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> +Acked-by: Harry Wentland <harry.wentland@amd.com> +--- + .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 38 ++++++++++++++++++++-- + .../gpu/drm/amd/display/dc/dcn10/dcn10_resource.c | 1 + + .../amd/display/dc/dcn10/dcn10_timing_generator.c | 31 +++++++++++++----- + .../drm/amd/display/dc/inc/hw/timing_generator.h | 2 ++ + drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 1 + + 5 files changed, 62 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +index e08808b..8e2520b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +@@ -425,6 +425,34 @@ static void bios_golden_init(struct dc *dc) + } + } + ++static void false_optc_underflow_wa( ++ struct dc *dc, ++ const struct dc_stream_state *stream, ++ struct timing_generator *tg) ++{ ++ int i; ++ bool underflow; ++ ++ if (!dc->hwseq->wa.false_optc_underflow) ++ return; ++ ++ underflow = tg->funcs->is_optc_underflow_occurred(tg); ++ ++ for (i = 0; i < dc->res_pool->pipe_count; i++) { ++ struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; ++ ++ if (old_pipe_ctx->stream != stream) ++ continue; ++ ++ dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); ++ } ++ ++ tg->funcs->set_blank_data_double_buffer(tg, true); ++ ++ if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) ++ tg->funcs->clear_optc_underflow(tg); ++} ++ + static enum dc_status dcn10_prog_pixclk_crtc_otg( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, +@@ -493,8 +521,11 @@ static enum dc_status dcn10_prog_pixclk_crtc_otg( + pipe_ctx->stream_res.tg, + &black_color); + +- pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); +- hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); ++ if (!pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) { ++ pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); ++ hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); ++ false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg); ++ } + + /* VTG is within DCHUB command block. DCFCLK is always on */ + if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { +@@ -2252,6 +2283,9 @@ static void dcn10_apply_ctx_for_surface( + + tg->funcs->unlock(tg); + ++ if (num_planes == 0) ++ false_optc_underflow_wa(dc, stream, tg); ++ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *old_pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +index 10cce51d..a9a5d17 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +@@ -678,6 +678,7 @@ static struct dce_hwseq *dcn10_hwseq_create( + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + hws->wa.DEGVIDCN10_253 = true; ++ hws->wa.false_optc_underflow = true; + } + return hws; + } +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c +index 73ff78f..4940fdb 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c +@@ -336,13 +336,6 @@ static void tgn10_blank_crtc(struct timing_generator *tg) + OTG_BLANK_DATA_EN, 1, + OTG_BLANK_DE_MODE, 0); + +- /* todo: why are we waiting for BLANK_DATA_EN? shouldn't we be waiting +- * for status? +- */ +- REG_WAIT(OTG_BLANK_CONTROL, +- OTG_BLANK_DATA_EN, 1, +- 1, 100000); +- + tgn10_set_blank_data_double_buffer(tg, false); + } + +@@ -1199,14 +1192,19 @@ void tgn10_read_otg_state(struct dcn10_timing_generator *tgn10, + OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status); + } + +-static void tgn10_tg_init(struct timing_generator *tg) ++static void tgn10_clear_optc_underflow(struct timing_generator *tg) + { + struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); + +- tgn10_set_blank_data_double_buffer(tg, true); + REG_UPDATE(OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, 1); + } + ++static void tgn10_tg_init(struct timing_generator *tg) ++{ ++ tgn10_set_blank_data_double_buffer(tg, true); ++ tgn10_clear_optc_underflow(tg); ++} ++ + static bool tgn10_is_tg_enabled(struct timing_generator *tg) + { + struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); +@@ -1217,6 +1215,19 @@ static bool tgn10_is_tg_enabled(struct timing_generator *tg) + return (otg_enabled != 0); + + } ++ ++static bool tgn10_is_optc_underflow_occurred(struct timing_generator *tg) ++{ ++ struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); ++ uint32_t underflow_occurred = 0; ++ ++ REG_GET(OPTC_INPUT_GLOBAL_CONTROL, ++ OPTC_UNDERFLOW_OCCURRED_STATUS, ++ &underflow_occurred); ++ ++ return (underflow_occurred == 1); ++} ++ + static const struct timing_generator_funcs dcn10_tg_funcs = { + .validate_timing = tgn10_validate_timing, + .program_timing = tgn10_program_timing, +@@ -1249,6 +1260,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { + .set_blank_data_double_buffer = tgn10_set_blank_data_double_buffer, + .tg_init = tgn10_tg_init, + .is_tg_enabled = tgn10_is_tg_enabled, ++ .is_optc_underflow_occurred = tgn10_is_optc_underflow_occurred, ++ .clear_optc_underflow = tgn10_clear_optc_underflow, + }; + + void dcn10_timing_generator_init(struct dcn10_timing_generator *tgn10) +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +index 8602599..e5c7e0e 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +@@ -187,6 +187,8 @@ struct timing_generator_funcs { + + void (*tg_init)(struct timing_generator *tg); + bool (*is_tg_enabled)(struct timing_generator *tg); ++ bool (*is_optc_underflow_occurred)(struct timing_generator *tg); ++ void (*clear_optc_underflow)(struct timing_generator *tg); + }; + + #endif +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +index 5dc4ecf..0343113 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +@@ -40,6 +40,7 @@ enum pipe_gating_control { + struct dce_hwseq_wa { + bool blnd_crtc_trigger; + bool DEGVIDCN10_253; ++ bool false_optc_underflow; + }; + + struct hwseq_wa_state { +-- +2.7.4 + |