Line data Source code
1 : /*
2 : * Copyright 2012-15 Advanced Micro Devices, Inc.
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a
5 : * copy of this software and associated documentation files (the "Software"),
6 : * to deal in the Software without restriction, including without limitation
7 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 : * and/or sell copies of the Software, and to permit persons to whom the
9 : * Software is furnished to do so, subject to the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included in
12 : * all copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 : * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 : * OTHER DEALINGS IN THE SOFTWARE.
21 : *
22 : * Authors: AMD
23 : *
24 : */
25 :
26 :
27 : #include "reg_helper.h"
28 : #include "dcn10_optc.h"
29 : #include "dc.h"
30 :
31 : #define REG(reg)\
32 : optc1->tg_regs->reg
33 :
34 : #define CTX \
35 : optc1->base.ctx
36 :
37 : #undef FN
38 : #define FN(reg_name, field_name) \
39 : optc1->tg_shift->field_name, optc1->tg_mask->field_name
40 :
41 : #define STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN 0x100
42 :
43 : /**
44 : * apply_front_porch_workaround TODO FPGA still need?
45 : *
46 : * This is a workaround for a bug that has existed since R5xx and has not been
47 : * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
48 : */
49 : static void apply_front_porch_workaround(struct dc_crtc_timing *timing)
50 : {
51 0 : if (timing->flags.INTERLACE == 1) {
52 0 : if (timing->v_front_porch < 2)
53 0 : timing->v_front_porch = 2;
54 : } else {
55 0 : if (timing->v_front_porch < 1)
56 0 : timing->v_front_porch = 1;
57 : }
58 : }
59 :
60 0 : void optc1_program_global_sync(
61 : struct timing_generator *optc,
62 : int vready_offset,
63 : int vstartup_start,
64 : int vupdate_offset,
65 : int vupdate_width)
66 : {
67 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
68 :
69 0 : optc1->vready_offset = vready_offset;
70 0 : optc1->vstartup_start = vstartup_start;
71 0 : optc1->vupdate_offset = vupdate_offset;
72 0 : optc1->vupdate_width = vupdate_width;
73 :
74 0 : if (optc1->vstartup_start == 0) {
75 0 : BREAK_TO_DEBUGGER();
76 0 : return;
77 : }
78 :
79 0 : REG_SET(OTG_VSTARTUP_PARAM, 0,
80 : VSTARTUP_START, optc1->vstartup_start);
81 :
82 0 : REG_SET_2(OTG_VUPDATE_PARAM, 0,
83 : VUPDATE_OFFSET, optc1->vupdate_offset,
84 : VUPDATE_WIDTH, optc1->vupdate_width);
85 :
86 0 : REG_SET(OTG_VREADY_PARAM, 0,
87 : VREADY_OFFSET, optc1->vready_offset);
88 : }
89 :
90 0 : static void optc1_disable_stereo(struct timing_generator *optc)
91 : {
92 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
93 :
94 0 : REG_SET(OTG_STEREO_CONTROL, 0,
95 : OTG_STEREO_EN, 0);
96 :
97 0 : REG_SET_2(OTG_3D_STRUCTURE_CONTROL, 0,
98 : OTG_3D_STRUCTURE_EN, 0,
99 : OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
100 0 : }
101 :
102 0 : void optc1_setup_vertical_interrupt0(
103 : struct timing_generator *optc,
104 : uint32_t start_line,
105 : uint32_t end_line)
106 : {
107 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
108 :
109 0 : REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0,
110 : OTG_VERTICAL_INTERRUPT0_LINE_START, start_line,
111 : OTG_VERTICAL_INTERRUPT0_LINE_END, end_line);
112 0 : }
113 :
114 0 : void optc1_setup_vertical_interrupt1(
115 : struct timing_generator *optc,
116 : uint32_t start_line)
117 : {
118 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
119 :
120 0 : REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0,
121 : OTG_VERTICAL_INTERRUPT1_LINE_START, start_line);
122 0 : }
123 :
124 0 : void optc1_setup_vertical_interrupt2(
125 : struct timing_generator *optc,
126 : uint32_t start_line)
127 : {
128 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
129 :
130 0 : REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0,
131 : OTG_VERTICAL_INTERRUPT2_LINE_START, start_line);
132 0 : }
133 :
134 : /**
135 : * program_timing_generator used by mode timing set
136 : * Program CRTC Timing Registers - OTG_H_*, OTG_V_*, Pixel repetition.
137 : * Including SYNC. Call BIOS command table to program Timings.
138 : */
139 0 : void optc1_program_timing(
140 : struct timing_generator *optc,
141 : 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,
147 : bool use_vbios)
148 : {
149 : struct dc_crtc_timing patched_crtc_timing;
150 : uint32_t asic_blank_end;
151 : uint32_t asic_blank_start;
152 : uint32_t v_total;
153 : uint32_t v_sync_end;
154 : uint32_t h_sync_polarity, v_sync_polarity;
155 0 : uint32_t start_point = 0;
156 0 : uint32_t field_num = 0;
157 0 : enum h_timing_div_mode h_div = H_TIMING_NO_DIV;
158 :
159 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
160 :
161 0 : optc1->signal = signal;
162 0 : optc1->vready_offset = vready_offset;
163 0 : optc1->vstartup_start = vstartup_start;
164 0 : optc1->vupdate_offset = vupdate_offset;
165 0 : optc1->vupdate_width = vupdate_width;
166 0 : patched_crtc_timing = *dc_crtc_timing;
167 0 : apply_front_porch_workaround(&patched_crtc_timing);
168 0 : optc1->orginal_patched_timing = patched_crtc_timing;
169 :
170 : /* Load horizontal timing */
171 :
172 : /* CRTC_H_TOTAL = vesa.h_total - 1 */
173 0 : REG_SET(OTG_H_TOTAL, 0,
174 : OTG_H_TOTAL, patched_crtc_timing.h_total - 1);
175 :
176 : /* h_sync_start = 0, h_sync_end = vesa.h_sync_width */
177 0 : REG_UPDATE_2(OTG_H_SYNC_A,
178 : OTG_H_SYNC_A_START, 0,
179 : OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width);
180 :
181 : /* blank_start = line end - front porch */
182 0 : asic_blank_start = patched_crtc_timing.h_total -
183 : patched_crtc_timing.h_front_porch;
184 :
185 : /* blank_end = blank_start - active */
186 0 : asic_blank_end = asic_blank_start -
187 0 : patched_crtc_timing.h_border_right -
188 : patched_crtc_timing.h_addressable -
189 : patched_crtc_timing.h_border_left;
190 :
191 0 : REG_UPDATE_2(OTG_H_BLANK_START_END,
192 : OTG_H_BLANK_START, asic_blank_start,
193 : OTG_H_BLANK_END, asic_blank_end);
194 :
195 : /* h_sync polarity */
196 0 : h_sync_polarity = patched_crtc_timing.flags.HSYNC_POSITIVE_POLARITY ?
197 0 : 0 : 1;
198 :
199 0 : REG_UPDATE(OTG_H_SYNC_A_CNTL,
200 : OTG_H_SYNC_A_POL, h_sync_polarity);
201 :
202 0 : v_total = patched_crtc_timing.v_total - 1;
203 :
204 0 : REG_SET(OTG_V_TOTAL, 0,
205 : OTG_V_TOTAL, v_total);
206 :
207 : /* In case of V_TOTAL_CONTROL is on, make sure OTG_V_TOTAL_MAX and
208 : * OTG_V_TOTAL_MIN are equal to V_TOTAL.
209 : */
210 0 : REG_SET(OTG_V_TOTAL_MAX, 0,
211 : OTG_V_TOTAL_MAX, v_total);
212 0 : REG_SET(OTG_V_TOTAL_MIN, 0,
213 : OTG_V_TOTAL_MIN, v_total);
214 :
215 : /* v_sync_start = 0, v_sync_end = v_sync_width */
216 0 : v_sync_end = patched_crtc_timing.v_sync_width;
217 :
218 0 : REG_UPDATE_2(OTG_V_SYNC_A,
219 : OTG_V_SYNC_A_START, 0,
220 : OTG_V_SYNC_A_END, v_sync_end);
221 :
222 : /* blank_start = frame end - front porch */
223 0 : asic_blank_start = patched_crtc_timing.v_total -
224 : patched_crtc_timing.v_front_porch;
225 :
226 : /* blank_end = blank_start - active */
227 0 : asic_blank_end = asic_blank_start -
228 0 : patched_crtc_timing.v_border_bottom -
229 : patched_crtc_timing.v_addressable -
230 : patched_crtc_timing.v_border_top;
231 :
232 0 : REG_UPDATE_2(OTG_V_BLANK_START_END,
233 : OTG_V_BLANK_START, asic_blank_start,
234 : OTG_V_BLANK_END, asic_blank_end);
235 :
236 : /* v_sync polarity */
237 0 : v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ?
238 0 : 0 : 1;
239 :
240 0 : REG_UPDATE(OTG_V_SYNC_A_CNTL,
241 : OTG_V_SYNC_A_POL, v_sync_polarity);
242 :
243 0 : if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT ||
244 0 : optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
245 : optc1->signal == SIGNAL_TYPE_EDP) {
246 0 : start_point = 1;
247 0 : if (patched_crtc_timing.flags.INTERLACE == 1)
248 0 : field_num = 1;
249 : }
250 :
251 : /* Interlace */
252 0 : if (REG(OTG_INTERLACE_CONTROL)) {
253 0 : if (patched_crtc_timing.flags.INTERLACE == 1)
254 0 : REG_UPDATE(OTG_INTERLACE_CONTROL,
255 : OTG_INTERLACE_ENABLE, 1);
256 : else
257 0 : REG_UPDATE(OTG_INTERLACE_CONTROL,
258 : OTG_INTERLACE_ENABLE, 0);
259 : }
260 :
261 : /* VTG enable set to 0 first VInit */
262 0 : REG_UPDATE(CONTROL,
263 : VTG0_ENABLE, 0);
264 :
265 : /* original code is using VTG offset to address OTG reg, seems wrong */
266 0 : REG_UPDATE_2(OTG_CONTROL,
267 : OTG_START_POINT_CNTL, start_point,
268 : OTG_FIELD_NUMBER_CNTL, field_num);
269 :
270 0 : optc->funcs->program_global_sync(optc,
271 : vready_offset,
272 : vstartup_start,
273 : vupdate_offset,
274 : vupdate_width);
275 :
276 0 : optc->funcs->set_vtg_params(optc, dc_crtc_timing, true);
277 :
278 : /* TODO
279 : * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1
280 : * program_horz_count_by_2
281 : * for DVI 30bpp mode, 0 otherwise
282 : * program_horz_count_by_2(optc, &patched_crtc_timing);
283 : */
284 :
285 : /* Enable stereo - only when we need to pack 3D frame. Other types
286 : * of stereo handled in explicit call
287 : */
288 :
289 0 : if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2)
290 0 : h_div = H_TIMING_DIV_BY2;
291 :
292 0 : if (REG(OPTC_DATA_FORMAT_CONTROL) && optc1->tg_mask->OPTC_DATA_FORMAT != 0) {
293 0 : uint32_t data_fmt = 0;
294 :
295 0 : if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
296 : data_fmt = 1;
297 0 : else if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
298 0 : data_fmt = 2;
299 :
300 0 : REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt);
301 : }
302 :
303 0 : if (optc1->tg_mask->OTG_H_TIMING_DIV_MODE != 0) {
304 0 : if (optc1->opp_count == 4)
305 0 : h_div = H_TIMING_DIV_BY4;
306 :
307 0 : REG_UPDATE(OTG_H_TIMING_CNTL,
308 : OTG_H_TIMING_DIV_MODE, h_div);
309 : } else {
310 0 : REG_UPDATE(OTG_H_TIMING_CNTL,
311 : OTG_H_TIMING_DIV_BY2, h_div);
312 : }
313 0 : }
314 :
315 : /**
316 : * optc1_set_vtg_params - Set Vertical Timing Generator (VTG) parameters
317 : *
318 : * @optc: timing_generator struct used to extract the optc parameters
319 : * @dc_crtc_timing: Timing parameters configured
320 : * @program_fp2: Boolean value indicating if FP2 will be programmed or not
321 : *
322 : * OTG is responsible for generating the global sync signals, including
323 : * vertical timing information for each HUBP in the dcfclk domain. Each VTG is
324 : * associated with one OTG that provides HUBP with vertical timing information
325 : * (i.e., there is 1:1 correspondence between OTG and VTG). This function is
326 : * responsible for setting the OTG parameters to the VTG during the pipe
327 : * programming.
328 : */
329 0 : void optc1_set_vtg_params(struct timing_generator *optc,
330 : const struct dc_crtc_timing *dc_crtc_timing, bool program_fp2)
331 : {
332 : struct dc_crtc_timing patched_crtc_timing;
333 : uint32_t asic_blank_end;
334 : uint32_t v_init;
335 0 : uint32_t v_fp2 = 0;
336 : int32_t vertical_line_start;
337 :
338 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
339 :
340 0 : patched_crtc_timing = *dc_crtc_timing;
341 0 : apply_front_porch_workaround(&patched_crtc_timing);
342 :
343 : /* VCOUNT_INIT is the start of blank */
344 0 : v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch;
345 :
346 : /* end of blank = v_init - active */
347 0 : asic_blank_end = v_init -
348 0 : patched_crtc_timing.v_border_bottom -
349 : patched_crtc_timing.v_addressable -
350 : patched_crtc_timing.v_border_top;
351 :
352 : /* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */
353 0 : vertical_line_start = asic_blank_end - optc1->vstartup_start + 1;
354 0 : if (vertical_line_start < 0)
355 0 : v_fp2 = -vertical_line_start;
356 :
357 : /* Interlace */
358 0 : if (REG(OTG_INTERLACE_CONTROL)) {
359 0 : if (patched_crtc_timing.flags.INTERLACE == 1) {
360 0 : v_init = v_init / 2;
361 0 : if ((optc1->vstartup_start/2)*2 > asic_blank_end)
362 0 : v_fp2 = v_fp2 / 2;
363 : }
364 : }
365 :
366 0 : if (program_fp2)
367 0 : REG_UPDATE_2(CONTROL,
368 : VTG0_FP2, v_fp2,
369 : VTG0_VCOUNT_INIT, v_init);
370 : else
371 0 : REG_UPDATE(CONTROL, VTG0_VCOUNT_INIT, v_init);
372 0 : }
373 :
374 0 : void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable)
375 : {
376 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
377 :
378 0 : uint32_t blank_data_double_buffer_enable = enable ? 1 : 0;
379 :
380 0 : REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL,
381 : OTG_BLANK_DATA_DOUBLE_BUFFER_EN, blank_data_double_buffer_enable);
382 0 : }
383 :
384 : /**
385 : * optc1_set_timing_double_buffer() - DRR double buffering control
386 : *
387 : * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN,
388 : * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers.
389 : *
390 : * Options: any time, start of frame, dp start of frame (range timing)
391 : */
392 0 : void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable)
393 : {
394 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
395 0 : uint32_t mode = enable ? 2 : 0;
396 :
397 0 : REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL,
398 : OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mode);
399 0 : }
400 :
401 : /**
402 : * unblank_crtc
403 : * Call ASIC Control Object to UnBlank CRTC.
404 : */
405 0 : static void optc1_unblank_crtc(struct timing_generator *optc)
406 : {
407 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
408 :
409 0 : REG_UPDATE_2(OTG_BLANK_CONTROL,
410 : OTG_BLANK_DATA_EN, 0,
411 : OTG_BLANK_DE_MODE, 0);
412 :
413 : /* W/A for automated testing
414 : * Automated testing will fail underflow test as there
415 : * sporadic underflows which occur during the optc blank
416 : * sequence. As a w/a, clear underflow on unblank.
417 : * This prevents the failure, but will not mask actual
418 : * underflow that affect real use cases.
419 : */
420 0 : optc1_clear_optc_underflow(optc);
421 0 : }
422 :
423 : /**
424 : * blank_crtc
425 : * Call ASIC Control Object to Blank CRTC.
426 : */
427 :
428 0 : static void optc1_blank_crtc(struct timing_generator *optc)
429 : {
430 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
431 :
432 0 : REG_UPDATE_2(OTG_BLANK_CONTROL,
433 : OTG_BLANK_DATA_EN, 1,
434 : OTG_BLANK_DE_MODE, 0);
435 :
436 0 : optc1_set_blank_data_double_buffer(optc, false);
437 0 : }
438 :
439 0 : void optc1_set_blank(struct timing_generator *optc,
440 : bool enable_blanking)
441 : {
442 0 : if (enable_blanking)
443 0 : optc1_blank_crtc(optc);
444 : else
445 0 : optc1_unblank_crtc(optc);
446 0 : }
447 :
448 0 : bool optc1_is_blanked(struct timing_generator *optc)
449 : {
450 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
451 : uint32_t blank_en;
452 : uint32_t blank_state;
453 :
454 0 : REG_GET_2(OTG_BLANK_CONTROL,
455 : OTG_BLANK_DATA_EN, &blank_en,
456 : OTG_CURRENT_BLANK_STATE, &blank_state);
457 :
458 0 : return blank_en && blank_state;
459 : }
460 :
461 0 : void optc1_enable_optc_clock(struct timing_generator *optc, bool enable)
462 : {
463 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
464 :
465 0 : if (enable) {
466 0 : REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL,
467 : OPTC_INPUT_CLK_EN, 1,
468 : OPTC_INPUT_CLK_GATE_DIS, 1);
469 :
470 0 : REG_WAIT(OPTC_INPUT_CLOCK_CONTROL,
471 : OPTC_INPUT_CLK_ON, 1,
472 : 1, 1000);
473 :
474 : /* Enable clock */
475 0 : REG_UPDATE_2(OTG_CLOCK_CONTROL,
476 : OTG_CLOCK_EN, 1,
477 : OTG_CLOCK_GATE_DIS, 1);
478 0 : REG_WAIT(OTG_CLOCK_CONTROL,
479 : OTG_CLOCK_ON, 1,
480 : 1, 1000);
481 : } else {
482 :
483 : //last chance to clear underflow, otherwise, it will always there due to clock is off.
484 0 : if (optc->funcs->is_optc_underflow_occurred(optc) == true)
485 0 : optc->funcs->clear_optc_underflow(optc);
486 :
487 0 : REG_UPDATE_2(OTG_CLOCK_CONTROL,
488 : OTG_CLOCK_GATE_DIS, 0,
489 : OTG_CLOCK_EN, 0);
490 :
491 0 : REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL,
492 : OPTC_INPUT_CLK_GATE_DIS, 0,
493 : OPTC_INPUT_CLK_EN, 0);
494 : }
495 0 : }
496 :
497 : /**
498 : * Enable CRTC
499 : * Enable CRTC - call ASIC Control Object to enable Timing generator.
500 : */
501 0 : static bool optc1_enable_crtc(struct timing_generator *optc)
502 : {
503 : /* TODO FPGA wait for answer
504 : * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE
505 : * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK
506 : */
507 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
508 :
509 : /* opp instance for OTG. For DCN1.0, ODM is remoed.
510 : * OPP and OPTC should 1:1 mapping
511 : */
512 0 : REG_UPDATE(OPTC_DATA_SOURCE_SELECT,
513 : OPTC_SRC_SEL, optc->inst);
514 :
515 : /* VTG enable first is for HW workaround */
516 0 : REG_UPDATE(CONTROL,
517 : VTG0_ENABLE, 1);
518 :
519 0 : REG_SEQ_START();
520 :
521 : /* Enable CRTC */
522 0 : REG_UPDATE_2(OTG_CONTROL,
523 : OTG_DISABLE_POINT_CNTL, 3,
524 : OTG_MASTER_EN, 1);
525 :
526 0 : REG_SEQ_SUBMIT();
527 0 : REG_SEQ_WAIT_DONE();
528 :
529 0 : return true;
530 : }
531 :
532 : /* disable_crtc - call ASIC Control Object to disable Timing generator. */
533 0 : bool optc1_disable_crtc(struct timing_generator *optc)
534 : {
535 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
536 :
537 : /* disable otg request until end of the first line
538 : * in the vertical blank region
539 : */
540 0 : REG_UPDATE_2(OTG_CONTROL,
541 : OTG_DISABLE_POINT_CNTL, 3,
542 : OTG_MASTER_EN, 0);
543 :
544 0 : REG_UPDATE(CONTROL,
545 : VTG0_ENABLE, 0);
546 :
547 : /* CRTC disabled, so disable clock. */
548 0 : REG_WAIT(OTG_CLOCK_CONTROL,
549 : OTG_BUSY, 0,
550 : 1, 100000);
551 :
552 0 : return true;
553 : }
554 :
555 :
556 0 : void optc1_program_blank_color(
557 : struct timing_generator *optc,
558 : const struct tg_color *black_color)
559 : {
560 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
561 :
562 0 : REG_SET_3(OTG_BLACK_COLOR, 0,
563 : OTG_BLACK_COLOR_B_CB, black_color->color_b_cb,
564 : OTG_BLACK_COLOR_G_Y, black_color->color_g_y,
565 : OTG_BLACK_COLOR_R_CR, black_color->color_r_cr);
566 0 : }
567 :
568 0 : bool optc1_validate_timing(
569 : struct timing_generator *optc,
570 : const struct dc_crtc_timing *timing)
571 : {
572 : uint32_t v_blank;
573 : uint32_t h_blank;
574 : uint32_t min_v_blank;
575 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
576 :
577 0 : ASSERT(timing != NULL);
578 :
579 0 : v_blank = (timing->v_total - timing->v_addressable -
580 0 : timing->v_border_top - timing->v_border_bottom);
581 :
582 0 : h_blank = (timing->h_total - timing->h_addressable -
583 0 : timing->h_border_right -
584 0 : timing->h_border_left);
585 :
586 0 : if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE &&
587 0 : timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING &&
588 0 : timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM &&
589 0 : timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE &&
590 0 : timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE &&
591 : timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA)
592 : return false;
593 :
594 : /* Temporarily blocking interlacing mode until it's supported */
595 0 : if (timing->flags.INTERLACE == 1)
596 : return false;
597 :
598 : /* Check maximum number of pixels supported by Timing Generator
599 : * (Currently will never fail, in order to fail needs display which
600 : * needs more than 8192 horizontal and
601 : * more than 8192 vertical total pixels)
602 : */
603 0 : if (timing->h_total > optc1->max_h_total ||
604 0 : timing->v_total > optc1->max_v_total)
605 : return false;
606 :
607 :
608 0 : if (h_blank < optc1->min_h_blank)
609 : return false;
610 :
611 0 : if (timing->h_sync_width < optc1->min_h_sync_width ||
612 0 : timing->v_sync_width < optc1->min_v_sync_width)
613 : return false;
614 :
615 0 : min_v_blank = timing->flags.INTERLACE?optc1->min_v_blank_interlace:optc1->min_v_blank;
616 :
617 0 : if (v_blank < min_v_blank)
618 : return false;
619 :
620 0 : return true;
621 :
622 : }
623 :
624 : /*
625 : * get_vblank_counter
626 : *
627 : * @brief
628 : * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which
629 : * holds the counter of frames.
630 : *
631 : * @param
632 : * struct timing_generator *optc - [in] timing generator which controls the
633 : * desired CRTC
634 : *
635 : * @return
636 : * Counter of frames, which should equal to number of vblanks.
637 : */
638 0 : uint32_t optc1_get_vblank_counter(struct timing_generator *optc)
639 : {
640 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
641 : uint32_t frame_count;
642 :
643 0 : REG_GET(OTG_STATUS_FRAME_COUNT,
644 : OTG_FRAME_COUNT, &frame_count);
645 :
646 0 : return frame_count;
647 : }
648 :
649 0 : void optc1_lock(struct timing_generator *optc)
650 : {
651 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
652 0 : uint32_t regval = 0;
653 :
654 0 : regval = REG_READ(OTG_CONTROL);
655 :
656 : /* otg is not running, do not need to be locked */
657 0 : if ((regval & 0x1) == 0x0)
658 : return;
659 :
660 0 : REG_SET(OTG_GLOBAL_CONTROL0, 0,
661 : OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
662 0 : REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
663 : OTG_MASTER_UPDATE_LOCK, 1);
664 :
665 : /* Should be fast, status does not update on maximus */
666 0 : if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) {
667 :
668 0 : REG_WAIT(OTG_MASTER_UPDATE_LOCK,
669 : UPDATE_LOCK_STATUS, 1,
670 : 1, 10);
671 : }
672 : }
673 :
674 0 : void optc1_unlock(struct timing_generator *optc)
675 : {
676 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
677 :
678 0 : REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
679 : OTG_MASTER_UPDATE_LOCK, 0);
680 0 : }
681 :
682 0 : bool optc1_is_locked(struct timing_generator *optc)
683 : {
684 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
685 : uint32_t locked;
686 :
687 0 : REG_GET(OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, &locked);
688 :
689 0 : return (locked == 1);
690 : }
691 :
692 0 : void optc1_get_position(struct timing_generator *optc,
693 : struct crtc_position *position)
694 : {
695 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
696 :
697 0 : REG_GET_2(OTG_STATUS_POSITION,
698 : OTG_HORZ_COUNT, &position->horizontal_count,
699 : OTG_VERT_COUNT, &position->vertical_count);
700 :
701 0 : REG_GET(OTG_NOM_VERT_POSITION,
702 : OTG_VERT_COUNT_NOM, &position->nominal_vcount);
703 0 : }
704 :
705 0 : bool optc1_is_counter_moving(struct timing_generator *optc)
706 : {
707 : struct crtc_position position1, position2;
708 :
709 0 : optc->funcs->get_position(optc, &position1);
710 0 : optc->funcs->get_position(optc, &position2);
711 :
712 0 : if (position1.horizontal_count == position2.horizontal_count &&
713 0 : position1.vertical_count == position2.vertical_count)
714 : return false;
715 : else
716 0 : return true;
717 : }
718 :
719 0 : bool optc1_did_triggered_reset_occur(
720 : struct timing_generator *optc)
721 : {
722 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
723 : uint32_t occurred_force, occurred_vsync;
724 :
725 0 : REG_GET(OTG_FORCE_COUNT_NOW_CNTL,
726 : OTG_FORCE_COUNT_NOW_OCCURRED, &occurred_force);
727 :
728 0 : REG_GET(OTG_VERT_SYNC_CONTROL,
729 : OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, &occurred_vsync);
730 :
731 0 : return occurred_vsync != 0 || occurred_force != 0;
732 : }
733 :
734 0 : void optc1_disable_reset_trigger(struct timing_generator *optc)
735 : {
736 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
737 :
738 0 : REG_WRITE(OTG_TRIGA_CNTL, 0);
739 :
740 0 : REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0,
741 : OTG_FORCE_COUNT_NOW_CLEAR, 1);
742 :
743 0 : REG_SET(OTG_VERT_SYNC_CONTROL, 0,
744 : OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, 1);
745 0 : }
746 :
747 0 : void optc1_enable_reset_trigger(struct timing_generator *optc, int source_tg_inst)
748 : {
749 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
750 : uint32_t falling_edge;
751 :
752 0 : REG_GET(OTG_V_SYNC_A_CNTL,
753 : OTG_V_SYNC_A_POL, &falling_edge);
754 :
755 0 : if (falling_edge)
756 0 : REG_SET_3(OTG_TRIGA_CNTL, 0,
757 : /* vsync signal from selected OTG pipe based
758 : * on OTG_TRIG_SOURCE_PIPE_SELECT setting
759 : */
760 : OTG_TRIGA_SOURCE_SELECT, 20,
761 : OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst,
762 : /* always detect falling edge */
763 : OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 1);
764 : else
765 0 : REG_SET_3(OTG_TRIGA_CNTL, 0,
766 : /* vsync signal from selected OTG pipe based
767 : * on OTG_TRIG_SOURCE_PIPE_SELECT setting
768 : */
769 : OTG_TRIGA_SOURCE_SELECT, 20,
770 : OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst,
771 : /* always detect rising edge */
772 : OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1);
773 :
774 0 : REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0,
775 : /* force H count to H_TOTAL and V count to V_TOTAL in
776 : * progressive mode and V_TOTAL-1 in interlaced mode
777 : */
778 : OTG_FORCE_COUNT_NOW_MODE, 2);
779 0 : }
780 :
781 0 : void optc1_enable_crtc_reset(
782 : struct timing_generator *optc,
783 : int source_tg_inst,
784 : struct crtc_trigger_info *crtc_tp)
785 : {
786 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
787 0 : uint32_t falling_edge = 0;
788 0 : uint32_t rising_edge = 0;
789 :
790 0 : switch (crtc_tp->event) {
791 :
792 : case CRTC_EVENT_VSYNC_RISING:
793 0 : rising_edge = 1;
794 0 : break;
795 :
796 : case CRTC_EVENT_VSYNC_FALLING:
797 0 : falling_edge = 1;
798 0 : break;
799 : }
800 :
801 0 : REG_SET_4(OTG_TRIGA_CNTL, 0,
802 : /* vsync signal from selected OTG pipe based
803 : * on OTG_TRIG_SOURCE_PIPE_SELECT setting
804 : */
805 : OTG_TRIGA_SOURCE_SELECT, 20,
806 : OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst,
807 : /* always detect falling edge */
808 : OTG_TRIGA_RISING_EDGE_DETECT_CNTL, rising_edge,
809 : OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, falling_edge);
810 :
811 0 : switch (crtc_tp->delay) {
812 : case TRIGGER_DELAY_NEXT_LINE:
813 0 : REG_SET(OTG_VERT_SYNC_CONTROL, 0,
814 : OTG_AUTO_FORCE_VSYNC_MODE, 1);
815 0 : break;
816 : case TRIGGER_DELAY_NEXT_PIXEL:
817 0 : REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0,
818 : /* force H count to H_TOTAL and V count to V_TOTAL in
819 : * progressive mode and V_TOTAL-1 in interlaced mode
820 : */
821 : OTG_FORCE_COUNT_NOW_MODE, 2);
822 0 : break;
823 : }
824 0 : }
825 :
826 0 : void optc1_wait_for_state(struct timing_generator *optc,
827 : enum crtc_state state)
828 : {
829 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
830 :
831 0 : switch (state) {
832 : case CRTC_STATE_VBLANK:
833 0 : REG_WAIT(OTG_STATUS,
834 : OTG_V_BLANK, 1,
835 : 1, 100000); /* 1 vupdate at 10hz */
836 0 : break;
837 :
838 : case CRTC_STATE_VACTIVE:
839 0 : REG_WAIT(OTG_STATUS,
840 : OTG_V_ACTIVE_DISP, 1,
841 : 1, 100000); /* 1 vupdate at 10hz */
842 0 : break;
843 :
844 : default:
845 : break;
846 : }
847 0 : }
848 :
849 0 : void optc1_set_early_control(
850 : struct timing_generator *optc,
851 : uint32_t early_cntl)
852 : {
853 : /* asic design change, do not need this control
854 : * empty for share caller logic
855 : */
856 0 : }
857 :
858 :
859 0 : void optc1_set_static_screen_control(
860 : struct timing_generator *optc,
861 : uint32_t event_triggers,
862 : uint32_t num_frames)
863 : {
864 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
865 :
866 : // By register spec, it only takes 8 bit value
867 0 : if (num_frames > 0xFF)
868 0 : num_frames = 0xFF;
869 :
870 : /* Bit 8 is no longer applicable in RV for PSR case,
871 : * set bit 8 to 0 if given
872 : */
873 0 : if ((event_triggers & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN)
874 : != 0)
875 0 : event_triggers = event_triggers &
876 : ~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN;
877 :
878 0 : REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0,
879 : OTG_STATIC_SCREEN_EVENT_MASK, event_triggers,
880 : OTG_STATIC_SCREEN_FRAME_COUNT, num_frames);
881 0 : }
882 :
883 0 : static void optc1_setup_manual_trigger(struct timing_generator *optc)
884 : {
885 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
886 :
887 0 : REG_SET(OTG_GLOBAL_CONTROL2, 0,
888 : MANUAL_FLOW_CONTROL_SEL, optc->inst);
889 :
890 0 : REG_SET_8(OTG_TRIGA_CNTL, 0,
891 : OTG_TRIGA_SOURCE_SELECT, 22,
892 : OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst,
893 : OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1,
894 : OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0,
895 : OTG_TRIGA_POLARITY_SELECT, 0,
896 : OTG_TRIGA_FREQUENCY_SELECT, 0,
897 : OTG_TRIGA_DELAY, 0,
898 : OTG_TRIGA_CLEAR, 1);
899 0 : }
900 :
901 0 : static void optc1_program_manual_trigger(struct timing_generator *optc)
902 : {
903 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
904 :
905 0 : REG_SET(OTG_MANUAL_FLOW_CONTROL, 0,
906 : MANUAL_FLOW_CONTROL, 1);
907 :
908 0 : REG_SET(OTG_MANUAL_FLOW_CONTROL, 0,
909 : MANUAL_FLOW_CONTROL, 0);
910 0 : }
911 :
912 :
913 : /**
914 : *****************************************************************************
915 : * Function: set_drr
916 : *
917 : * @brief
918 : * Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*.
919 : *
920 : *****************************************************************************
921 : */
922 0 : void optc1_set_drr(
923 : struct timing_generator *optc,
924 : const struct drr_params *params)
925 : {
926 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
927 :
928 0 : if (params != NULL &&
929 0 : params->vertical_total_max > 0 &&
930 0 : params->vertical_total_min > 0) {
931 :
932 0 : if (params->vertical_total_mid != 0) {
933 :
934 0 : REG_SET(OTG_V_TOTAL_MID, 0,
935 : OTG_V_TOTAL_MID, params->vertical_total_mid - 1);
936 :
937 0 : REG_UPDATE_2(OTG_V_TOTAL_CONTROL,
938 : OTG_VTOTAL_MID_REPLACING_MAX_EN, 1,
939 : OTG_VTOTAL_MID_FRAME_NUM,
940 : (uint8_t)params->vertical_total_mid_frame_num);
941 :
942 : }
943 :
944 0 : REG_SET(OTG_V_TOTAL_MAX, 0,
945 : OTG_V_TOTAL_MAX, params->vertical_total_max - 1);
946 :
947 0 : REG_SET(OTG_V_TOTAL_MIN, 0,
948 : OTG_V_TOTAL_MIN, params->vertical_total_min - 1);
949 :
950 0 : REG_UPDATE_5(OTG_V_TOTAL_CONTROL,
951 : OTG_V_TOTAL_MIN_SEL, 1,
952 : OTG_V_TOTAL_MAX_SEL, 1,
953 : OTG_FORCE_LOCK_ON_EVENT, 0,
954 : OTG_SET_V_TOTAL_MIN_MASK_EN, 0,
955 : OTG_SET_V_TOTAL_MIN_MASK, 0);
956 :
957 : // Setup manual flow control for EOF via TRIG_A
958 0 : optc->funcs->setup_manual_trigger(optc);
959 :
960 : } else {
961 0 : REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
962 : OTG_SET_V_TOTAL_MIN_MASK, 0,
963 : OTG_V_TOTAL_MIN_SEL, 0,
964 : OTG_V_TOTAL_MAX_SEL, 0,
965 : OTG_FORCE_LOCK_ON_EVENT, 0);
966 :
967 0 : REG_SET(OTG_V_TOTAL_MIN, 0,
968 : OTG_V_TOTAL_MIN, 0);
969 :
970 0 : REG_SET(OTG_V_TOTAL_MAX, 0,
971 : OTG_V_TOTAL_MAX, 0);
972 : }
973 0 : }
974 :
975 0 : void optc1_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max)
976 : {
977 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
978 :
979 0 : REG_SET(OTG_V_TOTAL_MAX, 0,
980 : OTG_V_TOTAL_MAX, vtotal_max);
981 :
982 0 : REG_SET(OTG_V_TOTAL_MIN, 0,
983 : OTG_V_TOTAL_MIN, vtotal_min);
984 0 : }
985 :
986 0 : static void optc1_set_test_pattern(
987 : struct timing_generator *optc,
988 : /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
989 : * because this is not DP-specific (which is probably somewhere in DP
990 : * encoder) */
991 : enum controller_dp_test_pattern test_pattern,
992 : enum dc_color_depth color_depth)
993 : {
994 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
995 : enum test_pattern_color_format bit_depth;
996 : enum test_pattern_dyn_range dyn_range;
997 : enum test_pattern_mode mode;
998 : uint32_t pattern_mask;
999 : uint32_t pattern_data;
1000 : /* color ramp generator mixes 16-bits color */
1001 0 : uint32_t src_bpc = 16;
1002 : /* requested bpc */
1003 : uint32_t dst_bpc;
1004 : uint32_t index;
1005 : /* RGB values of the color bars.
1006 : * Produce two RGB colors: RGB0 - white (all Fs)
1007 : * and RGB1 - black (all 0s)
1008 : * (three RGB components for two colors)
1009 : */
1010 0 : uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000,
1011 : 0x0000, 0x0000};
1012 : /* dest color (converted to the specified color format) */
1013 : uint16_t dst_color[6];
1014 : uint32_t inc_base;
1015 :
1016 : /* translate to bit depth */
1017 : switch (color_depth) {
1018 : case COLOR_DEPTH_666:
1019 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6;
1020 : break;
1021 : case COLOR_DEPTH_888:
1022 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
1023 : break;
1024 : case COLOR_DEPTH_101010:
1025 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10;
1026 : break;
1027 : case COLOR_DEPTH_121212:
1028 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12;
1029 : break;
1030 : default:
1031 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
1032 : break;
1033 : }
1034 :
1035 0 : switch (test_pattern) {
1036 : case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES:
1037 : case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA:
1038 : {
1039 0 : dyn_range = (test_pattern ==
1040 : CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ?
1041 0 : TEST_PATTERN_DYN_RANGE_CEA :
1042 : TEST_PATTERN_DYN_RANGE_VESA);
1043 0 : mode = TEST_PATTERN_MODE_COLORSQUARES_RGB;
1044 :
1045 0 : REG_UPDATE_2(OTG_TEST_PATTERN_PARAMETERS,
1046 : OTG_TEST_PATTERN_VRES, 6,
1047 : OTG_TEST_PATTERN_HRES, 6);
1048 :
1049 0 : REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL,
1050 : OTG_TEST_PATTERN_EN, 1,
1051 : OTG_TEST_PATTERN_MODE, mode,
1052 : OTG_TEST_PATTERN_DYNAMIC_RANGE, dyn_range,
1053 : OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth);
1054 : }
1055 0 : break;
1056 :
1057 : case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS:
1058 : case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS:
1059 : {
1060 0 : mode = (test_pattern ==
1061 : CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ?
1062 0 : TEST_PATTERN_MODE_VERTICALBARS :
1063 : TEST_PATTERN_MODE_HORIZONTALBARS);
1064 :
1065 : switch (bit_depth) {
1066 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
1067 : dst_bpc = 6;
1068 : break;
1069 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
1070 : dst_bpc = 8;
1071 : break;
1072 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
1073 : dst_bpc = 10;
1074 : break;
1075 : default:
1076 : dst_bpc = 8;
1077 : break;
1078 : }
1079 :
1080 : /* adjust color to the required colorFormat */
1081 0 : for (index = 0; index < 6; index++) {
1082 : /* dst = 2^dstBpc * src / 2^srcBpc = src >>
1083 : * (srcBpc - dstBpc);
1084 : */
1085 0 : dst_color[index] =
1086 0 : src_color[index] >> (src_bpc - dst_bpc);
1087 : /* CRTC_TEST_PATTERN_DATA has 16 bits,
1088 : * lowest 6 are hardwired to ZERO
1089 : * color bits should be left aligned to MSB
1090 : * XXXXXXXXXX000000 for 10 bit,
1091 : * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6
1092 : */
1093 0 : dst_color[index] <<= (16 - dst_bpc);
1094 : }
1095 :
1096 0 : REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0);
1097 :
1098 : /* We have to write the mask before data, similar to pipeline.
1099 : * For example, for 8 bpc, if we want RGB0 to be magenta,
1100 : * and RGB1 to be cyan,
1101 : * we need to make 7 writes:
1102 : * MASK DATA
1103 : * 000001 00000000 00000000 set mask to R0
1104 : * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0
1105 : * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0
1106 : * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1
1107 : * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1
1108 : * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1
1109 : * 100000 11111111 00000000 B1 255, 0xFF00
1110 : *
1111 : * we will make a loop of 6 in which we prepare the mask,
1112 : * then write, then prepare the color for next write.
1113 : * first iteration will write mask only,
1114 : * but each next iteration color prepared in
1115 : * previous iteration will be written within new mask,
1116 : * the last component will written separately,
1117 : * mask is not changing between 6th and 7th write
1118 : * and color will be prepared by last iteration
1119 : */
1120 :
1121 : /* write color, color values mask in CRTC_TEST_PATTERN_MASK
1122 : * is B1, G1, R1, B0, G0, R0
1123 : */
1124 0 : pattern_data = 0;
1125 0 : for (index = 0; index < 6; index++) {
1126 : /* prepare color mask, first write PATTERN_DATA
1127 : * will have all zeros
1128 : */
1129 0 : pattern_mask = (1 << index);
1130 :
1131 : /* write color component */
1132 0 : REG_SET_2(OTG_TEST_PATTERN_COLOR, 0,
1133 : OTG_TEST_PATTERN_MASK, pattern_mask,
1134 : OTG_TEST_PATTERN_DATA, pattern_data);
1135 :
1136 : /* prepare next color component,
1137 : * will be written in the next iteration
1138 : */
1139 0 : pattern_data = dst_color[index];
1140 : }
1141 : /* write last color component,
1142 : * it's been already prepared in the loop
1143 : */
1144 0 : REG_SET_2(OTG_TEST_PATTERN_COLOR, 0,
1145 : OTG_TEST_PATTERN_MASK, pattern_mask,
1146 : OTG_TEST_PATTERN_DATA, pattern_data);
1147 :
1148 : /* enable test pattern */
1149 0 : REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL,
1150 : OTG_TEST_PATTERN_EN, 1,
1151 : OTG_TEST_PATTERN_MODE, mode,
1152 : OTG_TEST_PATTERN_DYNAMIC_RANGE, 0,
1153 : OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth);
1154 : }
1155 0 : break;
1156 :
1157 : case CONTROLLER_DP_TEST_PATTERN_COLORRAMP:
1158 : {
1159 0 : mode = (bit_depth ==
1160 : TEST_PATTERN_COLOR_FORMAT_BPC_10 ?
1161 0 : TEST_PATTERN_MODE_DUALRAMP_RGB :
1162 : TEST_PATTERN_MODE_SINGLERAMP_RGB);
1163 :
1164 : switch (bit_depth) {
1165 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
1166 : dst_bpc = 6;
1167 : break;
1168 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
1169 : dst_bpc = 8;
1170 : break;
1171 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
1172 : dst_bpc = 10;
1173 : break;
1174 : default:
1175 : dst_bpc = 8;
1176 : break;
1177 : }
1178 :
1179 : /* increment for the first ramp for one color gradation
1180 : * 1 gradation for 6-bit color is 2^10
1181 : * gradations in 16-bit color
1182 : */
1183 0 : inc_base = (src_bpc - dst_bpc);
1184 :
1185 0 : switch (bit_depth) {
1186 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
1187 : {
1188 0 : REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS,
1189 : OTG_TEST_PATTERN_INC0, inc_base,
1190 : OTG_TEST_PATTERN_INC1, 0,
1191 : OTG_TEST_PATTERN_HRES, 6,
1192 : OTG_TEST_PATTERN_VRES, 6,
1193 : OTG_TEST_PATTERN_RAMP0_OFFSET, 0);
1194 : }
1195 0 : break;
1196 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
1197 : {
1198 0 : REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS,
1199 : OTG_TEST_PATTERN_INC0, inc_base,
1200 : OTG_TEST_PATTERN_INC1, 0,
1201 : OTG_TEST_PATTERN_HRES, 8,
1202 : OTG_TEST_PATTERN_VRES, 6,
1203 : OTG_TEST_PATTERN_RAMP0_OFFSET, 0);
1204 : }
1205 0 : break;
1206 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
1207 : {
1208 0 : REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS,
1209 : OTG_TEST_PATTERN_INC0, inc_base,
1210 : OTG_TEST_PATTERN_INC1, inc_base + 2,
1211 : OTG_TEST_PATTERN_HRES, 8,
1212 : OTG_TEST_PATTERN_VRES, 5,
1213 : OTG_TEST_PATTERN_RAMP0_OFFSET, 384 << 6);
1214 : }
1215 0 : break;
1216 : default:
1217 : break;
1218 : }
1219 :
1220 0 : REG_WRITE(OTG_TEST_PATTERN_COLOR, 0);
1221 :
1222 : /* enable test pattern */
1223 0 : REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0);
1224 :
1225 0 : REG_SET_4(OTG_TEST_PATTERN_CONTROL, 0,
1226 : OTG_TEST_PATTERN_EN, 1,
1227 : OTG_TEST_PATTERN_MODE, mode,
1228 : OTG_TEST_PATTERN_DYNAMIC_RANGE, 0,
1229 : OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth);
1230 : }
1231 0 : break;
1232 : case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE:
1233 : {
1234 0 : REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0);
1235 0 : REG_WRITE(OTG_TEST_PATTERN_COLOR, 0);
1236 0 : REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0);
1237 : }
1238 0 : break;
1239 : default:
1240 : break;
1241 :
1242 : }
1243 0 : }
1244 :
1245 0 : void optc1_get_crtc_scanoutpos(
1246 : struct timing_generator *optc,
1247 : uint32_t *v_blank_start,
1248 : uint32_t *v_blank_end,
1249 : uint32_t *h_position,
1250 : uint32_t *v_position)
1251 : {
1252 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1253 : struct crtc_position position;
1254 :
1255 0 : REG_GET_2(OTG_V_BLANK_START_END,
1256 : OTG_V_BLANK_START, v_blank_start,
1257 : OTG_V_BLANK_END, v_blank_end);
1258 :
1259 0 : optc1_get_position(optc, &position);
1260 :
1261 0 : *h_position = position.horizontal_count;
1262 0 : *v_position = position.vertical_count;
1263 0 : }
1264 :
1265 0 : static void optc1_enable_stereo(struct timing_generator *optc,
1266 : const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags)
1267 : {
1268 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1269 :
1270 0 : if (flags) {
1271 : uint32_t stereo_en;
1272 0 : stereo_en = flags->FRAME_PACKED == 0 ? 1 : 0;
1273 :
1274 0 : if (flags->PROGRAM_STEREO)
1275 0 : REG_UPDATE_3(OTG_STEREO_CONTROL,
1276 : OTG_STEREO_EN, stereo_en,
1277 : OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0,
1278 : OTG_STEREO_SYNC_OUTPUT_POLARITY, flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1);
1279 :
1280 0 : if (flags->PROGRAM_POLARITY)
1281 0 : REG_UPDATE(OTG_STEREO_CONTROL,
1282 : OTG_STEREO_EYE_FLAG_POLARITY,
1283 : flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1);
1284 :
1285 0 : if (flags->DISABLE_STEREO_DP_SYNC)
1286 0 : REG_UPDATE(OTG_STEREO_CONTROL,
1287 : OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1);
1288 :
1289 0 : if (flags->PROGRAM_STEREO)
1290 0 : REG_UPDATE_2(OTG_3D_STRUCTURE_CONTROL,
1291 : OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED,
1292 : OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED);
1293 :
1294 : }
1295 0 : }
1296 :
1297 0 : void optc1_program_stereo(struct timing_generator *optc,
1298 : const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags)
1299 : {
1300 0 : if (flags->PROGRAM_STEREO)
1301 0 : optc1_enable_stereo(optc, timing, flags);
1302 : else
1303 0 : optc1_disable_stereo(optc);
1304 0 : }
1305 :
1306 :
1307 0 : bool optc1_is_stereo_left_eye(struct timing_generator *optc)
1308 : {
1309 0 : bool ret = false;
1310 0 : uint32_t left_eye = 0;
1311 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1312 :
1313 0 : REG_GET(OTG_STEREO_STATUS,
1314 : OTG_STEREO_CURRENT_EYE, &left_eye);
1315 0 : if (left_eye == 1)
1316 : ret = true;
1317 : else
1318 0 : ret = false;
1319 :
1320 0 : return ret;
1321 : }
1322 :
1323 0 : bool optc1_get_hw_timing(struct timing_generator *tg,
1324 : struct dc_crtc_timing *hw_crtc_timing)
1325 : {
1326 0 : struct dcn_otg_state s = {0};
1327 :
1328 0 : if (tg == NULL || hw_crtc_timing == NULL)
1329 : return false;
1330 :
1331 0 : optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
1332 :
1333 0 : hw_crtc_timing->h_total = s.h_total + 1;
1334 0 : hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end);
1335 0 : hw_crtc_timing->h_front_porch = s.h_total + 1 - s.h_blank_start;
1336 0 : hw_crtc_timing->h_sync_width = s.h_sync_a_end - s.h_sync_a_start;
1337 :
1338 0 : hw_crtc_timing->v_total = s.v_total + 1;
1339 0 : hw_crtc_timing->v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end);
1340 0 : hw_crtc_timing->v_front_porch = s.v_total + 1 - s.v_blank_start;
1341 0 : hw_crtc_timing->v_sync_width = s.v_sync_a_end - s.v_sync_a_start;
1342 :
1343 0 : return true;
1344 : }
1345 :
1346 :
1347 0 : void optc1_read_otg_state(struct optc *optc1,
1348 : struct dcn_otg_state *s)
1349 : {
1350 0 : REG_GET(OTG_CONTROL,
1351 : OTG_MASTER_EN, &s->otg_enabled);
1352 :
1353 0 : REG_GET_2(OTG_V_BLANK_START_END,
1354 : OTG_V_BLANK_START, &s->v_blank_start,
1355 : OTG_V_BLANK_END, &s->v_blank_end);
1356 :
1357 0 : REG_GET(OTG_V_SYNC_A_CNTL,
1358 : OTG_V_SYNC_A_POL, &s->v_sync_a_pol);
1359 :
1360 0 : REG_GET(OTG_V_TOTAL,
1361 : OTG_V_TOTAL, &s->v_total);
1362 :
1363 0 : REG_GET(OTG_V_TOTAL_MAX,
1364 : OTG_V_TOTAL_MAX, &s->v_total_max);
1365 :
1366 0 : REG_GET(OTG_V_TOTAL_MIN,
1367 : OTG_V_TOTAL_MIN, &s->v_total_min);
1368 :
1369 0 : REG_GET(OTG_V_TOTAL_CONTROL,
1370 : OTG_V_TOTAL_MAX_SEL, &s->v_total_max_sel);
1371 :
1372 0 : REG_GET(OTG_V_TOTAL_CONTROL,
1373 : OTG_V_TOTAL_MIN_SEL, &s->v_total_min_sel);
1374 :
1375 0 : REG_GET_2(OTG_V_SYNC_A,
1376 : OTG_V_SYNC_A_START, &s->v_sync_a_start,
1377 : OTG_V_SYNC_A_END, &s->v_sync_a_end);
1378 :
1379 0 : REG_GET_2(OTG_H_BLANK_START_END,
1380 : OTG_H_BLANK_START, &s->h_blank_start,
1381 : OTG_H_BLANK_END, &s->h_blank_end);
1382 :
1383 0 : REG_GET_2(OTG_H_SYNC_A,
1384 : OTG_H_SYNC_A_START, &s->h_sync_a_start,
1385 : OTG_H_SYNC_A_END, &s->h_sync_a_end);
1386 :
1387 0 : REG_GET(OTG_H_SYNC_A_CNTL,
1388 : OTG_H_SYNC_A_POL, &s->h_sync_a_pol);
1389 :
1390 0 : REG_GET(OTG_H_TOTAL,
1391 : OTG_H_TOTAL, &s->h_total);
1392 :
1393 0 : REG_GET(OPTC_INPUT_GLOBAL_CONTROL,
1394 : OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status);
1395 :
1396 0 : REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL,
1397 : OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &s->vertical_interrupt2_en);
1398 :
1399 0 : REG_GET(OTG_VERTICAL_INTERRUPT2_POSITION,
1400 : OTG_VERTICAL_INTERRUPT2_LINE_START, &s->vertical_interrupt2_line);
1401 0 : }
1402 :
1403 0 : bool optc1_get_otg_active_size(struct timing_generator *optc,
1404 : uint32_t *otg_active_width,
1405 : uint32_t *otg_active_height)
1406 : {
1407 : uint32_t otg_enabled;
1408 : uint32_t v_blank_start;
1409 : uint32_t v_blank_end;
1410 : uint32_t h_blank_start;
1411 : uint32_t h_blank_end;
1412 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1413 :
1414 :
1415 0 : REG_GET(OTG_CONTROL,
1416 : OTG_MASTER_EN, &otg_enabled);
1417 :
1418 0 : if (otg_enabled == 0)
1419 : return false;
1420 :
1421 0 : REG_GET_2(OTG_V_BLANK_START_END,
1422 : OTG_V_BLANK_START, &v_blank_start,
1423 : OTG_V_BLANK_END, &v_blank_end);
1424 :
1425 0 : REG_GET_2(OTG_H_BLANK_START_END,
1426 : OTG_H_BLANK_START, &h_blank_start,
1427 : OTG_H_BLANK_END, &h_blank_end);
1428 :
1429 0 : *otg_active_width = v_blank_start - v_blank_end;
1430 0 : *otg_active_height = h_blank_start - h_blank_end;
1431 0 : return true;
1432 : }
1433 :
1434 0 : void optc1_clear_optc_underflow(struct timing_generator *optc)
1435 : {
1436 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1437 :
1438 0 : REG_UPDATE(OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, 1);
1439 0 : }
1440 :
1441 0 : void optc1_tg_init(struct timing_generator *optc)
1442 : {
1443 0 : optc1_set_blank_data_double_buffer(optc, true);
1444 0 : optc1_set_timing_double_buffer(optc, true);
1445 0 : optc1_clear_optc_underflow(optc);
1446 0 : }
1447 :
1448 0 : bool optc1_is_tg_enabled(struct timing_generator *optc)
1449 : {
1450 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1451 0 : uint32_t otg_enabled = 0;
1452 :
1453 0 : REG_GET(OTG_CONTROL, OTG_MASTER_EN, &otg_enabled);
1454 :
1455 0 : return (otg_enabled != 0);
1456 :
1457 : }
1458 :
1459 0 : bool optc1_is_optc_underflow_occurred(struct timing_generator *optc)
1460 : {
1461 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1462 0 : uint32_t underflow_occurred = 0;
1463 :
1464 0 : REG_GET(OPTC_INPUT_GLOBAL_CONTROL,
1465 : OPTC_UNDERFLOW_OCCURRED_STATUS,
1466 : &underflow_occurred);
1467 :
1468 0 : return (underflow_occurred == 1);
1469 : }
1470 :
1471 0 : bool optc1_configure_crc(struct timing_generator *optc,
1472 : const struct crc_params *params)
1473 : {
1474 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1475 :
1476 : /* Cannot configure crc on a CRTC that is disabled */
1477 0 : if (!optc1_is_tg_enabled(optc))
1478 : return false;
1479 :
1480 0 : REG_WRITE(OTG_CRC_CNTL, 0);
1481 :
1482 0 : if (!params->enable)
1483 : return true;
1484 :
1485 : /* Program frame boundaries */
1486 : /* Window A x axis start and end. */
1487 0 : REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL,
1488 : OTG_CRC0_WINDOWA_X_START, params->windowa_x_start,
1489 : OTG_CRC0_WINDOWA_X_END, params->windowa_x_end);
1490 :
1491 : /* Window A y axis start and end. */
1492 0 : REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL,
1493 : OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start,
1494 : OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end);
1495 :
1496 : /* Window B x axis start and end. */
1497 0 : REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL,
1498 : OTG_CRC0_WINDOWB_X_START, params->windowb_x_start,
1499 : OTG_CRC0_WINDOWB_X_END, params->windowb_x_end);
1500 :
1501 : /* Window B y axis start and end. */
1502 0 : REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL,
1503 : OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start,
1504 : OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end);
1505 :
1506 : /* Set crc mode and selection, and enable. Only using CRC0*/
1507 0 : REG_UPDATE_3(OTG_CRC_CNTL,
1508 : OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0,
1509 : OTG_CRC0_SELECT, params->selection,
1510 : OTG_CRC_EN, 1);
1511 :
1512 0 : return true;
1513 : }
1514 :
1515 : /**
1516 : * optc1_get_crc - Capture CRC result per component
1517 : *
1518 : * @optc: timing_generator instance.
1519 : * @r_cr: 16-bit primary CRC signature for red data.
1520 : * @g_y: 16-bit primary CRC signature for green data.
1521 : * @b_cb: 16-bit primary CRC signature for blue data.
1522 : *
1523 : * This function reads the CRC signature from the OPTC registers. Notice that
1524 : * we have three registers to keep the CRC result per color component (RGB).
1525 : *
1526 : * Returns:
1527 : * If CRC is disabled, return false; otherwise, return true, and the CRC
1528 : * results in the parameters.
1529 : */
1530 0 : bool optc1_get_crc(struct timing_generator *optc,
1531 : uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
1532 : {
1533 0 : uint32_t field = 0;
1534 0 : struct optc *optc1 = DCN10TG_FROM_TG(optc);
1535 :
1536 0 : REG_GET(OTG_CRC_CNTL, OTG_CRC_EN, &field);
1537 :
1538 : /* Early return if CRC is not enabled for this CRTC */
1539 0 : if (!field)
1540 : return false;
1541 :
1542 : /* OTG_CRC0_DATA_RG has the CRC16 results for the red and green component */
1543 0 : REG_GET_2(OTG_CRC0_DATA_RG,
1544 : CRC0_R_CR, r_cr,
1545 : CRC0_G_Y, g_y);
1546 :
1547 : /* OTG_CRC0_DATA_B has the CRC16 results for the blue component */
1548 0 : REG_GET(OTG_CRC0_DATA_B,
1549 : CRC0_B_CB, b_cb);
1550 :
1551 0 : return true;
1552 : }
1553 :
1554 : static const struct timing_generator_funcs dcn10_tg_funcs = {
1555 : .validate_timing = optc1_validate_timing,
1556 : .program_timing = optc1_program_timing,
1557 : .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
1558 : .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1,
1559 : .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2,
1560 : .program_global_sync = optc1_program_global_sync,
1561 : .enable_crtc = optc1_enable_crtc,
1562 : .disable_crtc = optc1_disable_crtc,
1563 : /* used by enable_timing_synchronization. Not need for FPGA */
1564 : .is_counter_moving = optc1_is_counter_moving,
1565 : .get_position = optc1_get_position,
1566 : .get_frame_count = optc1_get_vblank_counter,
1567 : .get_scanoutpos = optc1_get_crtc_scanoutpos,
1568 : .get_otg_active_size = optc1_get_otg_active_size,
1569 : .set_early_control = optc1_set_early_control,
1570 : /* used by enable_timing_synchronization. Not need for FPGA */
1571 : .wait_for_state = optc1_wait_for_state,
1572 : .set_blank = optc1_set_blank,
1573 : .is_blanked = optc1_is_blanked,
1574 : .set_blank_color = optc1_program_blank_color,
1575 : .did_triggered_reset_occur = optc1_did_triggered_reset_occur,
1576 : .enable_reset_trigger = optc1_enable_reset_trigger,
1577 : .enable_crtc_reset = optc1_enable_crtc_reset,
1578 : .disable_reset_trigger = optc1_disable_reset_trigger,
1579 : .lock = optc1_lock,
1580 : .is_locked = optc1_is_locked,
1581 : .unlock = optc1_unlock,
1582 : .enable_optc_clock = optc1_enable_optc_clock,
1583 : .set_drr = optc1_set_drr,
1584 : .get_last_used_drr_vtotal = NULL,
1585 : .set_static_screen_control = optc1_set_static_screen_control,
1586 : .set_test_pattern = optc1_set_test_pattern,
1587 : .program_stereo = optc1_program_stereo,
1588 : .is_stereo_left_eye = optc1_is_stereo_left_eye,
1589 : .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer,
1590 : .tg_init = optc1_tg_init,
1591 : .is_tg_enabled = optc1_is_tg_enabled,
1592 : .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred,
1593 : .clear_optc_underflow = optc1_clear_optc_underflow,
1594 : .get_crc = optc1_get_crc,
1595 : .configure_crc = optc1_configure_crc,
1596 : .set_vtg_params = optc1_set_vtg_params,
1597 : .program_manual_trigger = optc1_program_manual_trigger,
1598 : .setup_manual_trigger = optc1_setup_manual_trigger,
1599 : .get_hw_timing = optc1_get_hw_timing,
1600 : };
1601 :
1602 0 : void dcn10_timing_generator_init(struct optc *optc1)
1603 : {
1604 0 : optc1->base.funcs = &dcn10_tg_funcs;
1605 :
1606 0 : optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1;
1607 0 : optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1;
1608 :
1609 0 : optc1->min_h_blank = 32;
1610 0 : optc1->min_v_blank = 3;
1611 0 : optc1->min_v_blank_interlace = 5;
1612 0 : optc1->min_h_sync_width = 4;
1613 0 : optc1->min_v_sync_width = 1;
1614 0 : }
1615 :
1616 : /* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this:
1617 : *
1618 : * - 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
1619 : * containter rate.
1620 : *
1621 : * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be
1622 : * halved to maintain the correct pixel rate.
1623 : *
1624 : * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied
1625 : * 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.
1626 : *
1627 : */
1628 0 : bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
1629 : {
1630 0 : bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
1631 :
1632 0 : two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
1633 0 : && !timing->dsc_cfg.ycbcr422_simple);
1634 0 : return two_pix;
1635 : }
1636 :
|