hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
....@@ -46,9 +46,7 @@
4646 * This is a workaround for a bug that has existed since R5xx and has not been
4747 * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
4848 */
49
-static void optc1_apply_front_porch_workaround(
50
- struct timing_generator *optc,
51
- struct dc_crtc_timing *timing)
49
+static void apply_front_porch_workaround(struct dc_crtc_timing *timing)
5250 {
5351 if (timing->flags.INTERLACE == 1) {
5452 if (timing->v_front_porch < 2)
....@@ -60,24 +58,33 @@
6058 }
6159
6260 void optc1_program_global_sync(
63
- struct timing_generator *optc)
61
+ struct timing_generator *optc,
62
+ int vready_offset,
63
+ int vstartup_start,
64
+ int vupdate_offset,
65
+ int vupdate_width)
6466 {
6567 struct optc *optc1 = DCN10TG_FROM_TG(optc);
6668
67
- if (optc->dlg_otg_param.vstartup_start == 0) {
69
+ optc1->vready_offset = vready_offset;
70
+ optc1->vstartup_start = vstartup_start;
71
+ optc1->vupdate_offset = vupdate_offset;
72
+ optc1->vupdate_width = vupdate_width;
73
+
74
+ if (optc1->vstartup_start == 0) {
6875 BREAK_TO_DEBUGGER();
6976 return;
7077 }
7178
7279 REG_SET(OTG_VSTARTUP_PARAM, 0,
73
- VSTARTUP_START, optc->dlg_otg_param.vstartup_start);
80
+ VSTARTUP_START, optc1->vstartup_start);
7481
7582 REG_SET_2(OTG_VUPDATE_PARAM, 0,
76
- VUPDATE_OFFSET, optc->dlg_otg_param.vupdate_offset,
77
- VUPDATE_WIDTH, optc->dlg_otg_param.vupdate_width);
83
+ VUPDATE_OFFSET, optc1->vupdate_offset,
84
+ VUPDATE_WIDTH, optc1->vupdate_width);
7885
7986 REG_SET(OTG_VREADY_PARAM, 0,
80
- VREADY_OFFSET, optc->dlg_otg_param.vready_offset);
87
+ VREADY_OFFSET, optc1->vready_offset);
8188 }
8289
8390 static void optc1_disable_stereo(struct timing_generator *optc)
....@@ -87,85 +94,41 @@
8794 REG_SET(OTG_STEREO_CONTROL, 0,
8895 OTG_STEREO_EN, 0);
8996
90
- REG_SET_3(OTG_3D_STRUCTURE_CONTROL, 0,
97
+ REG_SET_2(OTG_3D_STRUCTURE_CONTROL, 0,
9198 OTG_3D_STRUCTURE_EN, 0,
92
- OTG_3D_STRUCTURE_V_UPDATE_MODE, 0,
9399 OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
94100 }
95101
96
-static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing)
97
-{
98
- struct dc_crtc_timing patched_crtc_timing;
99
- int vesa_sync_start;
100
- int asic_blank_end;
101
- int interlace_factor;
102
- int vertical_line_start;
103
-
104
- patched_crtc_timing = *dc_crtc_timing;
105
- optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
106
-
107
- vesa_sync_start = patched_crtc_timing.h_addressable +
108
- patched_crtc_timing.h_border_right +
109
- patched_crtc_timing.h_front_porch;
110
-
111
- asic_blank_end = patched_crtc_timing.h_total -
112
- vesa_sync_start -
113
- patched_crtc_timing.h_border_left;
114
-
115
- interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1;
116
-
117
- vesa_sync_start = patched_crtc_timing.v_addressable +
118
- patched_crtc_timing.v_border_bottom +
119
- patched_crtc_timing.v_front_porch;
120
-
121
- asic_blank_end = (patched_crtc_timing.v_total -
122
- vesa_sync_start -
123
- patched_crtc_timing.v_border_top)
124
- * interlace_factor;
125
-
126
- vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
127
- if (vertical_line_start < 0) {
128
- ASSERT(0);
129
- vertical_line_start = 0;
130
- }
131
-
132
- return vertical_line_start;
133
-}
134
-
135
-void optc1_program_vline_interrupt(
102
+void optc1_setup_vertical_interrupt0(
136103 struct timing_generator *optc,
137
- const struct dc_crtc_timing *dc_crtc_timing,
138
- unsigned long long vsync_delta)
104
+ uint32_t start_line,
105
+ uint32_t end_line)
139106 {
140
-
141107 struct optc *optc1 = DCN10TG_FROM_TG(optc);
142
-
143
- unsigned long long req_delta_tens_of_usec = div64_u64((vsync_delta + 9999), 10000);
144
- unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_khz + 99), 100);
145
- uint32_t req_delta_lines = (uint32_t) div64_u64(
146
- (req_delta_tens_of_usec * pix_clk_hundreds_khz + dc_crtc_timing->h_total - 1),
147
- dc_crtc_timing->h_total);
148
-
149
- uint32_t vsync_line = get_start_vline(optc, dc_crtc_timing);
150
- uint32_t start_line = 0;
151
- uint32_t endLine = 0;
152
-
153
- if (req_delta_lines != 0)
154
- req_delta_lines--;
155
-
156
- if (req_delta_lines > vsync_line)
157
- start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) - 1;
158
- else
159
- start_line = vsync_line - req_delta_lines;
160
-
161
- endLine = start_line + 2;
162
-
163
- if (endLine >= dc_crtc_timing->v_total)
164
- endLine = 2;
165108
166109 REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0,
167110 OTG_VERTICAL_INTERRUPT0_LINE_START, start_line,
168
- OTG_VERTICAL_INTERRUPT0_LINE_END, endLine);
111
+ OTG_VERTICAL_INTERRUPT0_LINE_END, end_line);
112
+}
113
+
114
+void optc1_setup_vertical_interrupt1(
115
+ struct timing_generator *optc,
116
+ uint32_t start_line)
117
+{
118
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
119
+
120
+ REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0,
121
+ OTG_VERTICAL_INTERRUPT1_LINE_START, start_line);
122
+}
123
+
124
+void optc1_setup_vertical_interrupt2(
125
+ struct timing_generator *optc,
126
+ uint32_t start_line)
127
+{
128
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
129
+
130
+ REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
131
+ OTG_VERTICAL_INTERRUPT2_LINE_START, start_line);
169132 }
170133
171134 /**
....@@ -176,26 +139,32 @@
176139 void optc1_program_timing(
177140 struct timing_generator *optc,
178141 const struct dc_crtc_timing *dc_crtc_timing,
142
+ int vready_offset,
143
+ int vstartup_start,
144
+ int vupdate_offset,
145
+ int vupdate_width,
146
+ const enum signal_type signal,
179147 bool use_vbios)
180148 {
181149 struct dc_crtc_timing patched_crtc_timing;
182
- uint32_t vesa_sync_start;
183150 uint32_t asic_blank_end;
184151 uint32_t asic_blank_start;
185152 uint32_t v_total;
186153 uint32_t v_sync_end;
187
- uint32_t v_init, v_fp2;
188154 uint32_t h_sync_polarity, v_sync_polarity;
189
- uint32_t interlace_factor;
190155 uint32_t start_point = 0;
191156 uint32_t field_num = 0;
192
- uint32_t h_div_2;
193
- int32_t vertical_line_start;
157
+ enum h_timing_div_mode h_div = H_TIMING_NO_DIV;
194158
195159 struct optc *optc1 = DCN10TG_FROM_TG(optc);
196160
161
+ optc1->signal = signal;
162
+ optc1->vready_offset = vready_offset;
163
+ optc1->vstartup_start = vstartup_start;
164
+ optc1->vupdate_offset = vupdate_offset;
165
+ optc1->vupdate_width = vupdate_width;
197166 patched_crtc_timing = *dc_crtc_timing;
198
- optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
167
+ apply_front_porch_workaround(&patched_crtc_timing);
199168
200169 /* Load horizontal timing */
201170
....@@ -208,23 +177,15 @@
208177 OTG_H_SYNC_A_START, 0,
209178 OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width);
210179
211
- /* asic_h_blank_end = HsyncWidth + HbackPorch =
212
- * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart -
213
- * vesa.h_left_border
214
- */
215
- vesa_sync_start = patched_crtc_timing.h_addressable +
216
- patched_crtc_timing.h_border_right +
180
+ /* blank_start = line end - front porch */
181
+ asic_blank_start = patched_crtc_timing.h_total -
217182 patched_crtc_timing.h_front_porch;
218183
219
- asic_blank_end = patched_crtc_timing.h_total -
220
- vesa_sync_start -
184
+ /* blank_end = blank_start - active */
185
+ asic_blank_end = asic_blank_start -
186
+ patched_crtc_timing.h_border_right -
187
+ patched_crtc_timing.h_addressable -
221188 patched_crtc_timing.h_border_left;
222
-
223
- /* h_blank_start = v_blank_end + v_active */
224
- asic_blank_start = asic_blank_end +
225
- patched_crtc_timing.h_border_left +
226
- patched_crtc_timing.h_addressable +
227
- patched_crtc_timing.h_border_right;
228189
229190 REG_UPDATE_2(OTG_H_BLANK_START_END,
230191 OTG_H_BLANK_START, asic_blank_start,
....@@ -237,16 +198,8 @@
237198 REG_UPDATE(OTG_H_SYNC_A_CNTL,
238199 OTG_H_SYNC_A_POL, h_sync_polarity);
239200
240
- /* Load vertical timing */
201
+ v_total = patched_crtc_timing.v_total - 1;
241202
242
- /* CRTC_V_TOTAL = v_total - 1 */
243
- if (patched_crtc_timing.flags.INTERLACE) {
244
- interlace_factor = 2;
245
- v_total = 2 * patched_crtc_timing.v_total;
246
- } else {
247
- interlace_factor = 1;
248
- v_total = patched_crtc_timing.v_total - 1;
249
- }
250203 REG_SET(OTG_V_TOTAL, 0,
251204 OTG_V_TOTAL, v_total);
252205
....@@ -259,88 +212,67 @@
259212 OTG_V_TOTAL_MIN, v_total);
260213
261214 /* v_sync_start = 0, v_sync_end = v_sync_width */
262
- v_sync_end = patched_crtc_timing.v_sync_width * interlace_factor;
215
+ v_sync_end = patched_crtc_timing.v_sync_width;
263216
264217 REG_UPDATE_2(OTG_V_SYNC_A,
265218 OTG_V_SYNC_A_START, 0,
266219 OTG_V_SYNC_A_END, v_sync_end);
267220
268
- vesa_sync_start = patched_crtc_timing.v_addressable +
269
- patched_crtc_timing.v_border_bottom +
221
+ /* blank_start = frame end - front porch */
222
+ asic_blank_start = patched_crtc_timing.v_total -
270223 patched_crtc_timing.v_front_porch;
271224
272
- asic_blank_end = (patched_crtc_timing.v_total -
273
- vesa_sync_start -
274
- patched_crtc_timing.v_border_top)
275
- * interlace_factor;
276
-
277
- /* v_blank_start = v_blank_end + v_active */
278
- asic_blank_start = asic_blank_end +
279
- (patched_crtc_timing.v_border_top +
280
- patched_crtc_timing.v_addressable +
281
- patched_crtc_timing.v_border_bottom)
282
- * interlace_factor;
225
+ /* blank_end = blank_start - active */
226
+ asic_blank_end = asic_blank_start -
227
+ patched_crtc_timing.v_border_bottom -
228
+ patched_crtc_timing.v_addressable -
229
+ patched_crtc_timing.v_border_top;
283230
284231 REG_UPDATE_2(OTG_V_BLANK_START_END,
285232 OTG_V_BLANK_START, asic_blank_start,
286233 OTG_V_BLANK_END, asic_blank_end);
287
-
288
- /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt,
289
- * program the reg for interrupt postition.
290
- */
291
- vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
292
- if (vertical_line_start < 0) {
293
- ASSERT(0);
294
- vertical_line_start = 0;
295
- }
296
- REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
297
- OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start);
298234
299235 /* v_sync polarity */
300236 v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ?
301237 0 : 1;
302238
303239 REG_UPDATE(OTG_V_SYNC_A_CNTL,
304
- OTG_V_SYNC_A_POL, v_sync_polarity);
240
+ OTG_V_SYNC_A_POL, v_sync_polarity);
305241
306
- v_init = asic_blank_start;
307
- if (optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT ||
308
- optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
309
- optc->dlg_otg_param.signal == SIGNAL_TYPE_EDP) {
242
+ if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT ||
243
+ optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
244
+ optc1->signal == SIGNAL_TYPE_EDP) {
310245 start_point = 1;
311246 if (patched_crtc_timing.flags.INTERLACE == 1)
312247 field_num = 1;
313248 }
314
- v_fp2 = 0;
315
- if (optc->dlg_otg_param.vstartup_start > asic_blank_end)
316
- v_fp2 = optc->dlg_otg_param.vstartup_start > asic_blank_end;
317249
318250 /* Interlace */
319
- if (patched_crtc_timing.flags.INTERLACE == 1) {
320
- REG_UPDATE(OTG_INTERLACE_CONTROL,
321
- OTG_INTERLACE_ENABLE, 1);
322
- v_init = v_init / 2;
323
- if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end)
324
- v_fp2 = v_fp2 / 2;
325
- } else
326
- REG_UPDATE(OTG_INTERLACE_CONTROL,
327
- OTG_INTERLACE_ENABLE, 0);
328
-
251
+ if (REG(OTG_INTERLACE_CONTROL)) {
252
+ if (patched_crtc_timing.flags.INTERLACE == 1)
253
+ REG_UPDATE(OTG_INTERLACE_CONTROL,
254
+ OTG_INTERLACE_ENABLE, 1);
255
+ else
256
+ REG_UPDATE(OTG_INTERLACE_CONTROL,
257
+ OTG_INTERLACE_ENABLE, 0);
258
+ }
329259
330260 /* VTG enable set to 0 first VInit */
331261 REG_UPDATE(CONTROL,
332262 VTG0_ENABLE, 0);
333
-
334
- REG_UPDATE_2(CONTROL,
335
- VTG0_FP2, v_fp2,
336
- VTG0_VCOUNT_INIT, v_init);
337263
338264 /* original code is using VTG offset to address OTG reg, seems wrong */
339265 REG_UPDATE_2(OTG_CONTROL,
340266 OTG_START_POINT_CNTL, start_point,
341267 OTG_FIELD_NUMBER_CNTL, field_num);
342268
343
- optc1_program_global_sync(optc);
269
+ optc->funcs->program_global_sync(optc,
270
+ vready_offset,
271
+ vstartup_start,
272
+ vupdate_offset,
273
+ vupdate_width);
274
+
275
+ optc->funcs->set_vtg_params(optc, dc_crtc_timing);
344276
345277 /* TODO
346278 * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1
....@@ -352,12 +284,76 @@
352284 /* Enable stereo - only when we need to pack 3D frame. Other types
353285 * of stereo handled in explicit call
354286 */
355
- h_div_2 = (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ?
356
- 1 : 0;
357287
358
- REG_UPDATE(OTG_H_TIMING_CNTL,
359
- OTG_H_TIMING_DIV_BY2, h_div_2);
288
+ if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2)
289
+ h_div = H_TIMING_DIV_BY2;
360290
291
+ if (REG(OPTC_DATA_FORMAT_CONTROL)) {
292
+ uint32_t data_fmt = 0;
293
+
294
+ if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
295
+ data_fmt = 1;
296
+ else if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
297
+ data_fmt = 2;
298
+
299
+ REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt);
300
+ }
301
+
302
+#if defined(CONFIG_DRM_AMD_DC_DCN3_0)
303
+ if (optc1->tg_mask->OTG_H_TIMING_DIV_MODE != 0) {
304
+ if (optc1->opp_count == 4)
305
+ h_div = H_TIMING_DIV_BY4;
306
+
307
+ REG_UPDATE(OTG_H_TIMING_CNTL,
308
+ OTG_H_TIMING_DIV_MODE, h_div);
309
+ } else
310
+#endif
311
+ {
312
+ REG_UPDATE(OTG_H_TIMING_CNTL,
313
+ OTG_H_TIMING_DIV_BY2, h_div);
314
+ }
315
+}
316
+
317
+void optc1_set_vtg_params(struct timing_generator *optc,
318
+ const struct dc_crtc_timing *dc_crtc_timing)
319
+{
320
+ struct dc_crtc_timing patched_crtc_timing;
321
+ uint32_t asic_blank_end;
322
+ uint32_t v_init;
323
+ uint32_t v_fp2 = 0;
324
+ int32_t vertical_line_start;
325
+
326
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
327
+
328
+ patched_crtc_timing = *dc_crtc_timing;
329
+ apply_front_porch_workaround(&patched_crtc_timing);
330
+
331
+ /* VCOUNT_INIT is the start of blank */
332
+ v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch;
333
+
334
+ /* end of blank = v_init - active */
335
+ asic_blank_end = v_init -
336
+ patched_crtc_timing.v_border_bottom -
337
+ patched_crtc_timing.v_addressable -
338
+ patched_crtc_timing.v_border_top;
339
+
340
+ /* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */
341
+ vertical_line_start = asic_blank_end - optc1->vstartup_start + 1;
342
+ if (vertical_line_start < 0)
343
+ v_fp2 = -vertical_line_start;
344
+
345
+ /* Interlace */
346
+ if (REG(OTG_INTERLACE_CONTROL)) {
347
+ if (patched_crtc_timing.flags.INTERLACE == 1) {
348
+ v_init = v_init / 2;
349
+ if ((optc1->vstartup_start/2)*2 > asic_blank_end)
350
+ v_fp2 = v_fp2 / 2;
351
+ }
352
+ }
353
+
354
+ REG_UPDATE_2(CONTROL,
355
+ VTG0_FP2, v_fp2,
356
+ VTG0_VCOUNT_INIT, v_init);
361357 }
362358
363359 void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable)
....@@ -371,26 +367,42 @@
371367 }
372368
373369 /**
370
+ * optc1_set_timing_double_buffer() - DRR double buffering control
371
+ *
372
+ * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN,
373
+ * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers.
374
+ *
375
+ * Options: any time, start of frame, dp start of frame (range timing)
376
+ */
377
+void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable)
378
+{
379
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
380
+ uint32_t mode = enable ? 2 : 0;
381
+
382
+ REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL,
383
+ OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mode);
384
+}
385
+
386
+/**
374387 * unblank_crtc
375388 * Call ASIC Control Object to UnBlank CRTC.
376389 */
377390 static void optc1_unblank_crtc(struct timing_generator *optc)
378391 {
379392 struct optc *optc1 = DCN10TG_FROM_TG(optc);
380
- uint32_t vertical_interrupt_enable = 0;
381
-
382
- REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL,
383
- OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &vertical_interrupt_enable);
384
-
385
- /* temporary work around for vertical interrupt, once vertical interrupt enabled,
386
- * this check will be removed.
387
- */
388
- if (vertical_interrupt_enable)
389
- optc1_set_blank_data_double_buffer(optc, true);
390393
391394 REG_UPDATE_2(OTG_BLANK_CONTROL,
392395 OTG_BLANK_DATA_EN, 0,
393396 OTG_BLANK_DE_MODE, 0);
397
+
398
+ /* W/A for automated testing
399
+ * Automated testing will fail underflow test as there
400
+ * sporadic underflows which occur during the optc blank
401
+ * sequence. As a w/a, clear underflow on unblank.
402
+ * This prevents the failure, but will not mask actual
403
+ * underflow that affect real use cases.
404
+ */
405
+ optc1_clear_optc_underflow(optc);
394406 }
395407
396408 /**
....@@ -452,6 +464,11 @@
452464 OTG_CLOCK_ON, 1,
453465 1, 1000);
454466 } else {
467
+
468
+ //last chance to clear underflow, otherwise, it will always there due to clock is off.
469
+ if (optc->funcs->is_optc_underflow_occurred(optc) == true)
470
+ optc->funcs->clear_optc_underflow(optc);
471
+
455472 REG_UPDATE_2(OTG_CLOCK_CONTROL,
456473 OTG_CLOCK_GATE_DIS, 0,
457474 OTG_CLOCK_EN, 0);
....@@ -484,10 +501,15 @@
484501 REG_UPDATE(CONTROL,
485502 VTG0_ENABLE, 1);
486503
504
+ REG_SEQ_START();
505
+
487506 /* Enable CRTC */
488507 REG_UPDATE_2(OTG_CONTROL,
489508 OTG_DISABLE_POINT_CNTL, 3,
490509 OTG_MASTER_EN, 1);
510
+
511
+ REG_SEQ_SUBMIT();
512
+ REG_SEQ_WAIT_DONE();
491513
492514 return true;
493515 }
....@@ -532,7 +554,6 @@
532554 struct timing_generator *optc,
533555 const struct dc_crtc_timing *timing)
534556 {
535
- uint32_t interlace_factor;
536557 uint32_t v_blank;
537558 uint32_t h_blank;
538559 uint32_t min_v_blank;
....@@ -540,10 +561,8 @@
540561
541562 ASSERT(timing != NULL);
542563
543
- interlace_factor = timing->flags.INTERLACE ? 2 : 1;
544564 v_blank = (timing->v_total - timing->v_addressable -
545
- timing->v_border_top - timing->v_border_bottom) *
546
- interlace_factor;
565
+ timing->v_border_top - timing->v_border_bottom);
547566
548567 h_blank = (timing->h_total - timing->h_addressable -
549568 timing->h_border_right -
....@@ -615,6 +634,13 @@
615634 void optc1_lock(struct timing_generator *optc)
616635 {
617636 struct optc *optc1 = DCN10TG_FROM_TG(optc);
637
+ uint32_t regval = 0;
638
+
639
+ regval = REG_READ(OTG_CONTROL);
640
+
641
+ /* otg is not running, do not need to be locked */
642
+ if ((regval & 0x1) == 0x0)
643
+ return;
618644
619645 REG_SET(OTG_GLOBAL_CONTROL0, 0,
620646 OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
....@@ -622,10 +648,12 @@
622648 OTG_MASTER_UPDATE_LOCK, 1);
623649
624650 /* Should be fast, status does not update on maximus */
625
- if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
651
+ if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) {
652
+
626653 REG_WAIT(OTG_MASTER_UPDATE_LOCK,
627654 UPDATE_LOCK_STATUS, 1,
628655 1, 10);
656
+ }
629657 }
630658
631659 void optc1_unlock(struct timing_generator *optc)
....@@ -805,21 +833,55 @@
805833
806834 void optc1_set_static_screen_control(
807835 struct timing_generator *optc,
808
- uint32_t value)
836
+ uint32_t event_triggers,
837
+ uint32_t num_frames)
809838 {
810839 struct optc *optc1 = DCN10TG_FROM_TG(optc);
840
+
841
+ // By register spec, it only takes 8 bit value
842
+ if (num_frames > 0xFF)
843
+ num_frames = 0xFF;
811844
812845 /* Bit 8 is no longer applicable in RV for PSR case,
813846 * set bit 8 to 0 if given
814847 */
815
- if ((value & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN)
848
+ if ((event_triggers & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN)
816849 != 0)
817
- value = value &
850
+ event_triggers = event_triggers &
818851 ~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN;
819852
820853 REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0,
821
- OTG_STATIC_SCREEN_EVENT_MASK, value,
822
- OTG_STATIC_SCREEN_FRAME_COUNT, 2);
854
+ OTG_STATIC_SCREEN_EVENT_MASK, event_triggers,
855
+ OTG_STATIC_SCREEN_FRAME_COUNT, num_frames);
856
+}
857
+
858
+void optc1_setup_manual_trigger(struct timing_generator *optc)
859
+{
860
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
861
+
862
+ REG_SET(OTG_GLOBAL_CONTROL2, 0,
863
+ MANUAL_FLOW_CONTROL_SEL, optc->inst);
864
+
865
+ REG_SET_8(OTG_TRIGA_CNTL, 0,
866
+ OTG_TRIGA_SOURCE_SELECT, 22,
867
+ OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst,
868
+ OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1,
869
+ OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0,
870
+ OTG_TRIGA_POLARITY_SELECT, 0,
871
+ OTG_TRIGA_FREQUENCY_SELECT, 0,
872
+ OTG_TRIGA_DELAY, 0,
873
+ OTG_TRIGA_CLEAR, 1);
874
+}
875
+
876
+void optc1_program_manual_trigger(struct timing_generator *optc)
877
+{
878
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
879
+
880
+ REG_SET(OTG_MANUAL_FLOW_CONTROL, 0,
881
+ MANUAL_FLOW_CONTROL, 1);
882
+
883
+ REG_SET(OTG_MANUAL_FLOW_CONTROL, 0,
884
+ MANUAL_FLOW_CONTROL, 0);
823885 }
824886
825887
....@@ -842,6 +904,18 @@
842904 params->vertical_total_max > 0 &&
843905 params->vertical_total_min > 0) {
844906
907
+ if (params->vertical_total_mid != 0) {
908
+
909
+ REG_SET(OTG_V_TOTAL_MID, 0,
910
+ OTG_V_TOTAL_MID, params->vertical_total_mid - 1);
911
+
912
+ REG_UPDATE_2(OTG_V_TOTAL_CONTROL,
913
+ OTG_VTOTAL_MID_REPLACING_MAX_EN, 1,
914
+ OTG_VTOTAL_MID_FRAME_NUM,
915
+ (uint8_t)params->vertical_total_mid_frame_num);
916
+
917
+ }
918
+
845919 REG_SET(OTG_V_TOTAL_MAX, 0,
846920 OTG_V_TOTAL_MAX, params->vertical_total_max - 1);
847921
....@@ -854,6 +928,10 @@
854928 OTG_FORCE_LOCK_ON_EVENT, 0,
855929 OTG_SET_V_TOTAL_MIN_MASK_EN, 0,
856930 OTG_SET_V_TOTAL_MIN_MASK, 0);
931
+
932
+ // Setup manual flow control for EOF via TRIG_A
933
+ optc->funcs->setup_manual_trigger(optc);
934
+
857935 } else {
858936 REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
859937 OTG_SET_V_TOTAL_MIN_MASK, 0,
....@@ -1161,7 +1239,7 @@
11611239 REG_UPDATE_3(OTG_STEREO_CONTROL,
11621240 OTG_STEREO_EN, stereo_en,
11631241 OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0,
1164
- OTG_STEREO_SYNC_OUTPUT_POLARITY, 0);
1242
+ OTG_STEREO_SYNC_OUTPUT_POLARITY, flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1);
11651243
11661244 if (flags->PROGRAM_POLARITY)
11671245 REG_UPDATE(OTG_STEREO_CONTROL,
....@@ -1173,9 +1251,8 @@
11731251 OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1);
11741252
11751253 if (flags->PROGRAM_STEREO)
1176
- REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL,
1254
+ REG_UPDATE_2(OTG_3D_STRUCTURE_CONTROL,
11771255 OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED,
1178
- OTG_3D_STRUCTURE_V_UPDATE_MODE, flags->FRAME_PACKED,
11791256 OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED);
11801257
11811258 }
....@@ -1206,6 +1283,30 @@
12061283
12071284 return ret;
12081285 }
1286
+
1287
+bool optc1_get_hw_timing(struct timing_generator *tg,
1288
+ struct dc_crtc_timing *hw_crtc_timing)
1289
+{
1290
+ struct dcn_otg_state s = {0};
1291
+
1292
+ if (tg == NULL || hw_crtc_timing == NULL)
1293
+ return false;
1294
+
1295
+ optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
1296
+
1297
+ hw_crtc_timing->h_total = s.h_total + 1;
1298
+ hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end);
1299
+ hw_crtc_timing->h_front_porch = s.h_total + 1 - s.h_blank_start;
1300
+ hw_crtc_timing->h_sync_width = s.h_sync_a_end - s.h_sync_a_start;
1301
+
1302
+ hw_crtc_timing->v_total = s.v_total + 1;
1303
+ hw_crtc_timing->v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end);
1304
+ hw_crtc_timing->v_front_porch = s.v_total + 1 - s.v_blank_start;
1305
+ hw_crtc_timing->v_sync_width = s.v_sync_a_end - s.v_sync_a_start;
1306
+
1307
+ return true;
1308
+}
1309
+
12091310
12101311 void optc1_read_otg_state(struct optc *optc1,
12111312 struct dcn_otg_state *s)
....@@ -1298,6 +1399,7 @@
12981399 void optc1_tg_init(struct timing_generator *optc)
12991400 {
13001401 optc1_set_blank_data_double_buffer(optc, true);
1402
+ optc1_set_timing_double_buffer(optc, true);
13011403 optc1_clear_optc_underflow(optc);
13021404 }
13031405
....@@ -1393,7 +1495,9 @@
13931495 static const struct timing_generator_funcs dcn10_tg_funcs = {
13941496 .validate_timing = optc1_validate_timing,
13951497 .program_timing = optc1_program_timing,
1396
- .program_vline_interrupt = optc1_program_vline_interrupt,
1498
+ .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
1499
+ .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1,
1500
+ .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2,
13971501 .program_global_sync = optc1_program_global_sync,
13981502 .enable_crtc = optc1_enable_crtc,
13991503 .disable_crtc = optc1_disable_crtc,
....@@ -1428,6 +1532,10 @@
14281532 .clear_optc_underflow = optc1_clear_optc_underflow,
14291533 .get_crc = optc1_get_crc,
14301534 .configure_crc = optc1_configure_crc,
1535
+ .set_vtg_params = optc1_set_vtg_params,
1536
+ .program_manual_trigger = optc1_program_manual_trigger,
1537
+ .setup_manual_trigger = optc1_setup_manual_trigger,
1538
+ .get_hw_timing = optc1_get_hw_timing,
14311539 };
14321540
14331541 void dcn10_timing_generator_init(struct optc *optc1)
....@@ -1443,3 +1551,25 @@
14431551 optc1->min_h_sync_width = 8;
14441552 optc1->min_v_sync_width = 1;
14451553 }
1554
+
1555
+/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this:
1556
+ *
1557
+ * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as
1558
+ * containter rate.
1559
+ *
1560
+ * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be
1561
+ * halved to maintain the correct pixel rate.
1562
+ *
1563
+ * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied
1564
+ * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well.
1565
+ *
1566
+ */
1567
+bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
1568
+{
1569
+ bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
1570
+
1571
+ two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
1572
+ && !timing->dsc_cfg.ycbcr422_simple);
1573
+ return two_pix;
1574
+}
1575
+