aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/2893-drm-amd-display-Implement-work-around-for-optc-under.patch
blob: 81e27a18f7f6684da92fbb9f87cb65bb59b5ec50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
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