summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c38
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c31
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h1
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 e08808b7e2d6..8e2520ba6bed 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 10cce51d31d2..a9a5d176cb70 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 73ff78f9cae1..4940fdbc6e80 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 860259913d78..e5c7e0e1db14 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 5dc4ecf618ff..03431134c088 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 {