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