]>
Commit | Line | Data |
---|---|---|
70ccab60 HW |
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 | #include "reg_helper.h" | |
27 | #include "dcn10_timing_generator.h" | |
f6cb588a | 28 | #include "dc.h" |
70ccab60 HW |
29 | |
30 | #define REG(reg)\ | |
31 | tgn10->tg_regs->reg | |
32 | ||
33 | #define CTX \ | |
34 | tgn10->base.ctx | |
35 | ||
36 | #undef FN | |
37 | #define FN(reg_name, field_name) \ | |
38 | tgn10->tg_shift->field_name, tgn10->tg_mask->field_name | |
39 | ||
40 | #define STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN 0x100 | |
41 | ||
42 | /** | |
43 | * apply_front_porch_workaround TODO FPGA still need? | |
44 | * | |
45 | * This is a workaround for a bug that has existed since R5xx and has not been | |
46 | * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. | |
47 | */ | |
62a3213a | 48 | static void tgn10_apply_front_porch_workaround( |
70ccab60 HW |
49 | struct timing_generator *tg, |
50 | struct dc_crtc_timing *timing) | |
51 | { | |
52 | if (timing->flags.INTERLACE == 1) { | |
53 | if (timing->v_front_porch < 2) | |
54 | timing->v_front_porch = 2; | |
55 | } else { | |
56 | if (timing->v_front_porch < 1) | |
57 | timing->v_front_porch = 1; | |
58 | } | |
59 | } | |
60 | ||
62a3213a | 61 | static void tgn10_program_global_sync( |
70ccab60 HW |
62 | struct timing_generator *tg) |
63 | { | |
64 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
65 | ||
66 | if (tg->dlg_otg_param.vstartup_start == 0) { | |
67 | BREAK_TO_DEBUGGER(); | |
68 | return; | |
69 | } | |
70 | ||
71 | REG_SET(OTG_VSTARTUP_PARAM, 0, | |
72 | VSTARTUP_START, tg->dlg_otg_param.vstartup_start); | |
73 | ||
74 | REG_SET_2(OTG_VUPDATE_PARAM, 0, | |
75 | VUPDATE_OFFSET, tg->dlg_otg_param.vupdate_offset, | |
76 | VUPDATE_WIDTH, tg->dlg_otg_param.vupdate_width); | |
77 | ||
78 | REG_SET(OTG_VREADY_PARAM, 0, | |
79 | VREADY_OFFSET, tg->dlg_otg_param.vready_offset); | |
80 | } | |
81 | ||
62a3213a | 82 | static void tgn10_disable_stereo(struct timing_generator *tg) |
70ccab60 HW |
83 | { |
84 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
85 | ||
86 | REG_SET(OTG_STEREO_CONTROL, 0, | |
9edba557 | 87 | OTG_STEREO_EN, 0); |
70ccab60 HW |
88 | |
89 | REG_SET_3(OTG_3D_STRUCTURE_CONTROL, 0, | |
9edba557 VP |
90 | OTG_3D_STRUCTURE_EN, 0, |
91 | OTG_3D_STRUCTURE_V_UPDATE_MODE, 0, | |
92 | OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0); | |
70ccab60 HW |
93 | |
94 | REG_UPDATE(OPPBUF_CONTROL, | |
9edba557 | 95 | OPPBUF_ACTIVE_WIDTH, 0); |
70ccab60 | 96 | REG_UPDATE(OPPBUF_3D_PARAMETERS_0, |
9edba557 | 97 | OPPBUF_3D_VACT_SPACE1_SIZE, 0); |
70ccab60 HW |
98 | } |
99 | ||
100 | /** | |
101 | * program_timing_generator used by mode timing set | |
102 | * Program CRTC Timing Registers - OTG_H_*, OTG_V_*, Pixel repetition. | |
103 | * Including SYNC. Call BIOS command table to program Timings. | |
104 | */ | |
62a3213a | 105 | static void tgn10_program_timing( |
70ccab60 | 106 | struct timing_generator *tg, |
62a3213a DL |
107 | const struct dc_crtc_timing *dc_crtc_timing, |
108 | bool use_vbios) | |
70ccab60 HW |
109 | { |
110 | struct dc_crtc_timing patched_crtc_timing; | |
111 | uint32_t vesa_sync_start; | |
112 | uint32_t asic_blank_end; | |
113 | uint32_t asic_blank_start; | |
114 | uint32_t v_total; | |
115 | uint32_t v_sync_end; | |
116 | uint32_t v_init, v_fp2; | |
117 | uint32_t h_sync_polarity, v_sync_polarity; | |
118 | uint32_t interlace_factor; | |
119 | uint32_t start_point = 0; | |
120 | uint32_t field_num = 0; | |
121 | uint32_t h_div_2; | |
649e0c76 | 122 | int32_t vertical_line_start; |
70ccab60 | 123 | |
70ccab60 HW |
124 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); |
125 | ||
126 | patched_crtc_timing = *dc_crtc_timing; | |
62a3213a | 127 | tgn10_apply_front_porch_workaround(tg, &patched_crtc_timing); |
70ccab60 HW |
128 | |
129 | /* Load horizontal timing */ | |
130 | ||
131 | /* CRTC_H_TOTAL = vesa.h_total - 1 */ | |
132 | REG_SET(OTG_H_TOTAL, 0, | |
133 | OTG_H_TOTAL, patched_crtc_timing.h_total - 1); | |
134 | ||
135 | /* h_sync_start = 0, h_sync_end = vesa.h_sync_width */ | |
136 | REG_UPDATE_2(OTG_H_SYNC_A, | |
137 | OTG_H_SYNC_A_START, 0, | |
138 | OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width); | |
139 | ||
140 | /* asic_h_blank_end = HsyncWidth + HbackPorch = | |
141 | * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart - | |
142 | * vesa.h_left_border | |
143 | */ | |
144 | vesa_sync_start = patched_crtc_timing.h_addressable + | |
145 | patched_crtc_timing.h_border_right + | |
146 | patched_crtc_timing.h_front_porch; | |
147 | ||
148 | asic_blank_end = patched_crtc_timing.h_total - | |
149 | vesa_sync_start - | |
150 | patched_crtc_timing.h_border_left; | |
151 | ||
152 | /* h_blank_start = v_blank_end + v_active */ | |
153 | asic_blank_start = asic_blank_end + | |
154 | patched_crtc_timing.h_border_left + | |
155 | patched_crtc_timing.h_addressable + | |
156 | patched_crtc_timing.h_border_right; | |
157 | ||
158 | REG_UPDATE_2(OTG_H_BLANK_START_END, | |
159 | OTG_H_BLANK_START, asic_blank_start, | |
160 | OTG_H_BLANK_END, asic_blank_end); | |
161 | ||
162 | /* h_sync polarity */ | |
163 | h_sync_polarity = patched_crtc_timing.flags.HSYNC_POSITIVE_POLARITY ? | |
164 | 0 : 1; | |
165 | ||
166 | REG_UPDATE(OTG_H_SYNC_A_CNTL, | |
167 | OTG_H_SYNC_A_POL, h_sync_polarity); | |
168 | ||
169 | /* Load vertical timing */ | |
170 | ||
171 | /* CRTC_V_TOTAL = v_total - 1 */ | |
172 | if (patched_crtc_timing.flags.INTERLACE) { | |
173 | interlace_factor = 2; | |
174 | v_total = 2 * patched_crtc_timing.v_total; | |
175 | } else { | |
176 | interlace_factor = 1; | |
177 | v_total = patched_crtc_timing.v_total - 1; | |
178 | } | |
179 | REG_SET(OTG_V_TOTAL, 0, | |
180 | OTG_V_TOTAL, v_total); | |
181 | ||
97416d4c YS |
182 | /* In case of V_TOTAL_CONTROL is on, make sure OTG_V_TOTAL_MAX and |
183 | * OTG_V_TOTAL_MIN are equal to V_TOTAL. | |
184 | */ | |
185 | REG_SET(OTG_V_TOTAL_MAX, 0, | |
186 | OTG_V_TOTAL_MAX, v_total); | |
187 | REG_SET(OTG_V_TOTAL_MIN, 0, | |
188 | OTG_V_TOTAL_MIN, v_total); | |
189 | ||
70ccab60 HW |
190 | /* v_sync_start = 0, v_sync_end = v_sync_width */ |
191 | v_sync_end = patched_crtc_timing.v_sync_width * interlace_factor; | |
192 | ||
193 | REG_UPDATE_2(OTG_V_SYNC_A, | |
194 | OTG_V_SYNC_A_START, 0, | |
195 | OTG_V_SYNC_A_END, v_sync_end); | |
196 | ||
197 | vesa_sync_start = patched_crtc_timing.v_addressable + | |
198 | patched_crtc_timing.v_border_bottom + | |
199 | patched_crtc_timing.v_front_porch; | |
200 | ||
201 | asic_blank_end = (patched_crtc_timing.v_total - | |
202 | vesa_sync_start - | |
203 | patched_crtc_timing.v_border_top) | |
204 | * interlace_factor; | |
205 | ||
206 | /* v_blank_start = v_blank_end + v_active */ | |
207 | asic_blank_start = asic_blank_end + | |
208 | (patched_crtc_timing.v_border_top + | |
209 | patched_crtc_timing.v_addressable + | |
210 | patched_crtc_timing.v_border_bottom) | |
211 | * interlace_factor; | |
212 | ||
213 | REG_UPDATE_2(OTG_V_BLANK_START_END, | |
214 | OTG_V_BLANK_START, asic_blank_start, | |
215 | OTG_V_BLANK_END, asic_blank_end); | |
216 | ||
4486201c YS |
217 | /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt, |
218 | * program the reg for interrupt postition. | |
219 | */ | |
649e0c76 YS |
220 | vertical_line_start = asic_blank_end - tg->dlg_otg_param.vstartup_start + 1; |
221 | if (vertical_line_start < 0) { | |
222 | ASSERT(0); | |
223 | vertical_line_start = 0; | |
224 | } | |
4486201c | 225 | REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, |
649e0c76 | 226 | OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start); |
70ccab60 HW |
227 | |
228 | /* v_sync polarity */ | |
229 | v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? | |
230 | 0 : 1; | |
231 | ||
232 | REG_UPDATE(OTG_V_SYNC_A_CNTL, | |
233 | OTG_V_SYNC_A_POL, v_sync_polarity); | |
234 | ||
235 | v_init = asic_blank_start; | |
236 | if (tg->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT || | |
237 | tg->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT_MST || | |
238 | tg->dlg_otg_param.signal == SIGNAL_TYPE_EDP) { | |
70ccab60 HW |
239 | start_point = 1; |
240 | if (patched_crtc_timing.flags.INTERLACE == 1) | |
241 | field_num = 1; | |
242 | } | |
70ccab60 HW |
243 | v_fp2 = 0; |
244 | if (tg->dlg_otg_param.vstartup_start > asic_blank_end) | |
245 | v_fp2 = tg->dlg_otg_param.vstartup_start > asic_blank_end; | |
246 | ||
247 | /* Interlace */ | |
248 | if (patched_crtc_timing.flags.INTERLACE == 1) { | |
249 | REG_UPDATE(OTG_INTERLACE_CONTROL, | |
250 | OTG_INTERLACE_ENABLE, 1); | |
251 | v_init = v_init / 2; | |
252 | if ((tg->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end) | |
253 | v_fp2 = v_fp2 / 2; | |
254 | } | |
255 | else | |
256 | REG_UPDATE(OTG_INTERLACE_CONTROL, | |
257 | OTG_INTERLACE_ENABLE, 0); | |
258 | ||
259 | ||
260 | /* VTG enable set to 0 first VInit */ | |
261 | REG_UPDATE(CONTROL, | |
262 | VTG0_ENABLE, 0); | |
263 | ||
264 | REG_UPDATE_2(CONTROL, | |
265 | VTG0_FP2, v_fp2, | |
266 | VTG0_VCOUNT_INIT, v_init); | |
267 | ||
268 | /* original code is using VTG offset to address OTG reg, seems wrong */ | |
269 | REG_UPDATE_2(OTG_CONTROL, | |
270 | OTG_START_POINT_CNTL, start_point, | |
271 | OTG_FIELD_NUMBER_CNTL, field_num); | |
272 | ||
62a3213a | 273 | tgn10_program_global_sync(tg); |
70ccab60 HW |
274 | |
275 | /* TODO | |
276 | * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1 | |
277 | * program_horz_count_by_2 | |
278 | * for DVI 30bpp mode, 0 otherwise | |
279 | * program_horz_count_by_2(tg, &patched_crtc_timing); | |
280 | */ | |
281 | ||
282 | /* Enable stereo - only when we need to pack 3D frame. Other types | |
283 | * of stereo handled in explicit call | |
284 | */ | |
285 | h_div_2 = (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ? | |
286 | 1 : 0; | |
287 | ||
288 | REG_UPDATE(OTG_H_TIMING_CNTL, | |
289 | OTG_H_TIMING_DIV_BY2, h_div_2); | |
290 | ||
70ccab60 HW |
291 | } |
292 | ||
70ccab60 HW |
293 | /** |
294 | * unblank_crtc | |
295 | * Call ASIC Control Object to UnBlank CRTC. | |
296 | */ | |
62a3213a | 297 | static void tgn10_unblank_crtc(struct timing_generator *tg) |
70ccab60 HW |
298 | { |
299 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
0fc899b0 YS |
300 | uint32_t vertical_interrupt_enable = 0; |
301 | ||
302 | REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, | |
303 | OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &vertical_interrupt_enable); | |
304 | ||
305 | /* temporary work around for vertical interrupt, once vertical interrupt enabled, | |
306 | * this check will be removed. | |
307 | */ | |
308 | if (vertical_interrupt_enable) | |
309 | REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, | |
310 | OTG_BLANK_DATA_DOUBLE_BUFFER_EN, 1); | |
70ccab60 HW |
311 | |
312 | REG_UPDATE_2(OTG_BLANK_CONTROL, | |
313 | OTG_BLANK_DATA_EN, 0, | |
314 | OTG_BLANK_DE_MODE, 0); | |
315 | } | |
316 | ||
317 | /** | |
318 | * blank_crtc | |
319 | * Call ASIC Control Object to Blank CRTC. | |
320 | */ | |
321 | ||
62a3213a | 322 | static void tgn10_blank_crtc(struct timing_generator *tg) |
70ccab60 HW |
323 | { |
324 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
325 | ||
326 | REG_UPDATE_2(OTG_BLANK_CONTROL, | |
327 | OTG_BLANK_DATA_EN, 1, | |
328 | OTG_BLANK_DE_MODE, 0); | |
329 | ||
330 | /* todo: why are we waiting for BLANK_DATA_EN? shouldn't we be waiting | |
331 | * for status? | |
332 | */ | |
333 | REG_WAIT(OTG_BLANK_CONTROL, | |
334 | OTG_BLANK_DATA_EN, 1, | |
8a5d8245 | 335 | 1, 100000); |
70ccab60 HW |
336 | |
337 | REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, | |
338 | OTG_BLANK_DATA_DOUBLE_BUFFER_EN, 0); | |
339 | } | |
340 | ||
62a3213a | 341 | static void tgn10_set_blank(struct timing_generator *tg, |
70ccab60 HW |
342 | bool enable_blanking) |
343 | { | |
344 | if (enable_blanking) | |
62a3213a | 345 | tgn10_blank_crtc(tg); |
70ccab60 | 346 | else |
62a3213a | 347 | tgn10_unblank_crtc(tg); |
70ccab60 HW |
348 | } |
349 | ||
62a3213a | 350 | static bool tgn10_is_blanked(struct timing_generator *tg) |
70ccab60 HW |
351 | { |
352 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
353 | uint32_t blank_en; | |
354 | uint32_t blank_state; | |
355 | ||
356 | REG_GET_2(OTG_BLANK_CONTROL, | |
357 | OTG_BLANK_DATA_EN, &blank_en, | |
358 | OTG_CURRENT_BLANK_STATE, &blank_state); | |
359 | ||
360 | return blank_en && blank_state; | |
361 | } | |
362 | ||
62a3213a | 363 | static void tgn10_enable_optc_clock(struct timing_generator *tg, bool enable) |
70ccab60 HW |
364 | { |
365 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
366 | ||
367 | if (enable) { | |
51666631 DL |
368 | REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, |
369 | OPTC_INPUT_CLK_EN, 1, | |
370 | OPTC_INPUT_CLK_GATE_DIS, 1); | |
70ccab60 HW |
371 | |
372 | REG_WAIT(OPTC_INPUT_CLOCK_CONTROL, | |
373 | OPTC_INPUT_CLK_ON, 1, | |
8a5d8245 | 374 | 1, 1000); |
70ccab60 HW |
375 | |
376 | /* Enable clock */ | |
51666631 DL |
377 | REG_UPDATE_2(OTG_CLOCK_CONTROL, |
378 | OTG_CLOCK_EN, 1, | |
379 | OTG_CLOCK_GATE_DIS, 1); | |
70ccab60 HW |
380 | REG_WAIT(OTG_CLOCK_CONTROL, |
381 | OTG_CLOCK_ON, 1, | |
8a5d8245 | 382 | 1, 1000); |
70ccab60 HW |
383 | } else { |
384 | REG_UPDATE_2(OTG_CLOCK_CONTROL, | |
385 | OTG_CLOCK_GATE_DIS, 0, | |
386 | OTG_CLOCK_EN, 0); | |
387 | ||
51666631 DL |
388 | if (tg->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) |
389 | REG_WAIT(OTG_CLOCK_CONTROL, | |
390 | OTG_CLOCK_ON, 0, | |
8a5d8245 | 391 | 1, 1000); |
70ccab60 HW |
392 | |
393 | REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, | |
394 | OPTC_INPUT_CLK_GATE_DIS, 0, | |
395 | OPTC_INPUT_CLK_EN, 0); | |
396 | ||
51666631 DL |
397 | if (tg->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) |
398 | REG_WAIT(OPTC_INPUT_CLOCK_CONTROL, | |
399 | OPTC_INPUT_CLK_ON, 0, | |
8a5d8245 | 400 | 1, 1000); |
70ccab60 HW |
401 | } |
402 | } | |
403 | ||
404 | /** | |
405 | * Enable CRTC | |
406 | * Enable CRTC - call ASIC Control Object to enable Timing generator. | |
407 | */ | |
62a3213a | 408 | static bool tgn10_enable_crtc(struct timing_generator *tg) |
70ccab60 HW |
409 | { |
410 | /* TODO FPGA wait for answer | |
411 | * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE | |
412 | * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK | |
413 | */ | |
414 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
415 | ||
416 | /* opp instance for OTG. For DCN1.0, ODM is remoed. | |
417 | * OPP and OPTC should 1:1 mapping | |
418 | */ | |
419 | REG_UPDATE(OPTC_DATA_SOURCE_SELECT, | |
420 | OPTC_SRC_SEL, tg->inst); | |
421 | ||
422 | /* VTG enable first is for HW workaround */ | |
423 | REG_UPDATE(CONTROL, | |
424 | VTG0_ENABLE, 1); | |
425 | ||
426 | /* Enable CRTC */ | |
427 | REG_UPDATE_2(OTG_CONTROL, | |
428 | OTG_DISABLE_POINT_CNTL, 3, | |
429 | OTG_MASTER_EN, 1); | |
430 | ||
431 | return true; | |
432 | } | |
433 | ||
434 | /* disable_crtc - call ASIC Control Object to disable Timing generator. */ | |
62a3213a | 435 | static bool tgn10_disable_crtc(struct timing_generator *tg) |
70ccab60 HW |
436 | { |
437 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
438 | ||
439 | /* disable otg request until end of the first line | |
440 | * in the vertical blank region | |
441 | */ | |
442 | REG_UPDATE_2(OTG_CONTROL, | |
443 | OTG_DISABLE_POINT_CNTL, 3, | |
444 | OTG_MASTER_EN, 0); | |
445 | ||
446 | REG_UPDATE(CONTROL, | |
447 | VTG0_ENABLE, 0); | |
448 | ||
449 | /* CRTC disabled, so disable clock. */ | |
450 | REG_WAIT(OTG_CLOCK_CONTROL, | |
451 | OTG_BUSY, 0, | |
8a5d8245 | 452 | 1, 100000); |
70ccab60 HW |
453 | |
454 | return true; | |
455 | } | |
456 | ||
457 | ||
62a3213a | 458 | static void tgn10_program_blank_color( |
70ccab60 HW |
459 | struct timing_generator *tg, |
460 | const struct tg_color *black_color) | |
461 | { | |
462 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
463 | ||
464 | REG_SET_3(OTG_BLACK_COLOR, 0, | |
465 | OTG_BLACK_COLOR_B_CB, black_color->color_b_cb, | |
466 | OTG_BLACK_COLOR_G_Y, black_color->color_g_y, | |
467 | OTG_BLACK_COLOR_R_CR, black_color->color_r_cr); | |
468 | } | |
469 | ||
62a3213a | 470 | static bool tgn10_validate_timing( |
70ccab60 HW |
471 | struct timing_generator *tg, |
472 | const struct dc_crtc_timing *timing) | |
473 | { | |
474 | uint32_t interlace_factor; | |
475 | uint32_t v_blank; | |
476 | uint32_t h_blank; | |
477 | uint32_t min_v_blank; | |
478 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
479 | ||
480 | ASSERT(timing != NULL); | |
481 | ||
482 | interlace_factor = timing->flags.INTERLACE ? 2 : 1; | |
483 | v_blank = (timing->v_total - timing->v_addressable - | |
484 | timing->v_border_top - timing->v_border_bottom) * | |
485 | interlace_factor; | |
486 | ||
487 | h_blank = (timing->h_total - timing->h_addressable - | |
488 | timing->h_border_right - | |
489 | timing->h_border_left); | |
490 | ||
491 | if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE && | |
492 | timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING && | |
493 | timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM && | |
494 | timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE && | |
9edba557 VP |
495 | timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE && |
496 | timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA) | |
70ccab60 HW |
497 | return false; |
498 | ||
499 | /* Temporarily blocking interlacing mode until it's supported */ | |
500 | if (timing->flags.INTERLACE == 1) | |
501 | return false; | |
502 | ||
503 | /* Check maximum number of pixels supported by Timing Generator | |
504 | * (Currently will never fail, in order to fail needs display which | |
505 | * needs more than 8192 horizontal and | |
506 | * more than 8192 vertical total pixels) | |
507 | */ | |
508 | if (timing->h_total > tgn10->max_h_total || | |
509 | timing->v_total > tgn10->max_v_total) | |
510 | return false; | |
511 | ||
512 | ||
513 | if (h_blank < tgn10->min_h_blank) | |
514 | return false; | |
515 | ||
516 | if (timing->h_sync_width < tgn10->min_h_sync_width || | |
517 | timing->v_sync_width < tgn10->min_v_sync_width) | |
518 | return false; | |
519 | ||
520 | min_v_blank = timing->flags.INTERLACE?tgn10->min_v_blank_interlace:tgn10->min_v_blank; | |
521 | ||
522 | if (v_blank < min_v_blank) | |
523 | return false; | |
524 | ||
525 | return true; | |
526 | ||
527 | } | |
528 | ||
529 | /* | |
530 | * get_vblank_counter | |
531 | * | |
532 | * @brief | |
533 | * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which | |
534 | * holds the counter of frames. | |
535 | * | |
536 | * @param | |
537 | * struct timing_generator *tg - [in] timing generator which controls the | |
538 | * desired CRTC | |
539 | * | |
540 | * @return | |
541 | * Counter of frames, which should equal to number of vblanks. | |
542 | */ | |
62a3213a | 543 | static uint32_t tgn10_get_vblank_counter(struct timing_generator *tg) |
70ccab60 HW |
544 | { |
545 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
546 | uint32_t frame_count; | |
547 | ||
548 | REG_GET(OTG_STATUS_FRAME_COUNT, | |
549 | OTG_FRAME_COUNT, &frame_count); | |
550 | ||
551 | return frame_count; | |
552 | } | |
553 | ||
62a3213a | 554 | static void tgn10_lock(struct timing_generator *tg) |
70ccab60 HW |
555 | { |
556 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
557 | ||
cfe4645e DL |
558 | REG_SET(OTG_GLOBAL_CONTROL0, 0, |
559 | OTG_MASTER_UPDATE_LOCK_SEL, tg->inst); | |
70ccab60 HW |
560 | REG_SET(OTG_MASTER_UPDATE_LOCK, 0, |
561 | OTG_MASTER_UPDATE_LOCK, 1); | |
38917a1e | 562 | |
51666631 DL |
563 | if (tg->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) |
564 | REG_WAIT(OTG_MASTER_UPDATE_LOCK, | |
565 | UPDATE_LOCK_STATUS, 1, | |
566 | 1, 100); | |
70ccab60 HW |
567 | } |
568 | ||
62a3213a | 569 | static void tgn10_unlock(struct timing_generator *tg) |
70ccab60 HW |
570 | { |
571 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
572 | ||
573 | REG_SET(OTG_MASTER_UPDATE_LOCK, 0, | |
574 | OTG_MASTER_UPDATE_LOCK, 0); | |
575 | ||
576 | /* why are we waiting here? */ | |
51666631 | 577 | REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL, |
70ccab60 | 578 | OTG_UPDATE_PENDING, 0, |
8a5d8245 | 579 | 1, 100000); |
70ccab60 HW |
580 | } |
581 | ||
62a3213a | 582 | static void tgn10_get_position(struct timing_generator *tg, |
70ccab60 HW |
583 | struct crtc_position *position) |
584 | { | |
585 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
586 | ||
587 | REG_GET_2(OTG_STATUS_POSITION, | |
588 | OTG_HORZ_COUNT, &position->horizontal_count, | |
589 | OTG_VERT_COUNT, &position->vertical_count); | |
590 | ||
591 | REG_GET(OTG_NOM_VERT_POSITION, | |
592 | OTG_VERT_COUNT_NOM, &position->nominal_vcount); | |
593 | } | |
594 | ||
62a3213a | 595 | static bool tgn10_is_counter_moving(struct timing_generator *tg) |
70ccab60 HW |
596 | { |
597 | struct crtc_position position1, position2; | |
598 | ||
599 | tg->funcs->get_position(tg, &position1); | |
600 | tg->funcs->get_position(tg, &position2); | |
601 | ||
602 | if (position1.horizontal_count == position2.horizontal_count && | |
603 | position1.vertical_count == position2.vertical_count) | |
604 | return false; | |
605 | else | |
606 | return true; | |
607 | } | |
608 | ||
62a3213a | 609 | static bool tgn10_did_triggered_reset_occur( |
70ccab60 HW |
610 | struct timing_generator *tg) |
611 | { | |
612 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
613 | uint32_t occurred; | |
614 | ||
615 | REG_GET(OTG_FORCE_COUNT_NOW_CNTL, | |
616 | OTG_FORCE_COUNT_NOW_OCCURRED, &occurred); | |
617 | ||
618 | return occurred != 0; | |
619 | } | |
620 | ||
62a3213a | 621 | static void tgn10_enable_reset_trigger(struct timing_generator *tg, int source_tg_inst) |
70ccab60 HW |
622 | { |
623 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
624 | uint32_t falling_edge; | |
625 | ||
626 | REG_GET(OTG_V_SYNC_A_CNTL, | |
627 | OTG_V_SYNC_A_POL, &falling_edge); | |
628 | ||
629 | if (falling_edge) | |
630 | REG_SET_3(OTG_TRIGA_CNTL, 0, | |
631 | /* vsync signal from selected OTG pipe based | |
632 | * on OTG_TRIG_SOURCE_PIPE_SELECT setting | |
633 | */ | |
634 | OTG_TRIGA_SOURCE_SELECT, 20, | |
635 | OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, | |
636 | /* always detect falling edge */ | |
637 | OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 1); | |
638 | else | |
639 | REG_SET_3(OTG_TRIGA_CNTL, 0, | |
640 | /* vsync signal from selected OTG pipe based | |
641 | * on OTG_TRIG_SOURCE_PIPE_SELECT setting | |
642 | */ | |
643 | OTG_TRIGA_SOURCE_SELECT, 20, | |
644 | OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, | |
645 | /* always detect rising edge */ | |
646 | OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1); | |
647 | ||
648 | REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, | |
649 | /* force H count to H_TOTAL and V count to V_TOTAL in | |
650 | * progressive mode and V_TOTAL-1 in interlaced mode | |
651 | */ | |
652 | OTG_FORCE_COUNT_NOW_MODE, 2); | |
653 | } | |
654 | ||
62a3213a | 655 | static void tgn10_disable_reset_trigger(struct timing_generator *tg) |
70ccab60 HW |
656 | { |
657 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
658 | ||
659 | REG_WRITE(OTG_TRIGA_CNTL, 0); | |
660 | ||
661 | REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, | |
662 | OTG_FORCE_COUNT_NOW_CLEAR, 1); | |
663 | } | |
664 | ||
62a3213a | 665 | static void tgn10_wait_for_state(struct timing_generator *tg, |
70ccab60 HW |
666 | enum crtc_state state) |
667 | { | |
668 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
669 | ||
670 | switch (state) { | |
671 | case CRTC_STATE_VBLANK: | |
672 | REG_WAIT(OTG_STATUS, | |
673 | OTG_V_BLANK, 1, | |
8a5d8245 | 674 | 1, 100000); /* 1 vupdate at 10hz */ |
70ccab60 HW |
675 | break; |
676 | ||
677 | case CRTC_STATE_VACTIVE: | |
678 | REG_WAIT(OTG_STATUS, | |
679 | OTG_V_ACTIVE_DISP, 1, | |
8a5d8245 | 680 | 1, 100000); /* 1 vupdate at 10hz */ |
70ccab60 HW |
681 | break; |
682 | ||
683 | default: | |
684 | break; | |
685 | } | |
686 | } | |
687 | ||
62a3213a | 688 | static void tgn10_set_early_control( |
70ccab60 HW |
689 | struct timing_generator *tg, |
690 | uint32_t early_cntl) | |
691 | { | |
692 | /* asic design change, do not need this control | |
693 | * empty for share caller logic | |
694 | */ | |
695 | } | |
696 | ||
697 | ||
62a3213a | 698 | static void tgn10_set_static_screen_control( |
70ccab60 HW |
699 | struct timing_generator *tg, |
700 | uint32_t value) | |
701 | { | |
702 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
703 | ||
704 | /* Bit 8 is no longer applicable in RV for PSR case, | |
705 | * set bit 8 to 0 if given | |
706 | */ | |
707 | if ((value & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN) | |
708 | != 0) | |
709 | value = value & | |
710 | ~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN; | |
711 | ||
712 | REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0, | |
713 | OTG_STATIC_SCREEN_EVENT_MASK, value, | |
714 | OTG_STATIC_SCREEN_FRAME_COUNT, 2); | |
715 | } | |
716 | ||
717 | ||
718 | /** | |
719 | ***************************************************************************** | |
720 | * Function: set_drr | |
721 | * | |
722 | * @brief | |
723 | * Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*. | |
724 | * | |
725 | ***************************************************************************** | |
726 | */ | |
62a3213a | 727 | static void tgn10_set_drr( |
70ccab60 HW |
728 | struct timing_generator *tg, |
729 | const struct drr_params *params) | |
730 | { | |
731 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
732 | ||
733 | if (params != NULL && | |
734 | params->vertical_total_max > 0 && | |
735 | params->vertical_total_min > 0) { | |
736 | ||
737 | REG_SET(OTG_V_TOTAL_MAX, 0, | |
738 | OTG_V_TOTAL_MAX, params->vertical_total_max - 1); | |
739 | ||
740 | REG_SET(OTG_V_TOTAL_MIN, 0, | |
741 | OTG_V_TOTAL_MIN, params->vertical_total_min - 1); | |
742 | ||
743 | REG_UPDATE_5(OTG_V_TOTAL_CONTROL, | |
744 | OTG_V_TOTAL_MIN_SEL, 1, | |
745 | OTG_V_TOTAL_MAX_SEL, 1, | |
746 | OTG_FORCE_LOCK_ON_EVENT, 0, | |
747 | OTG_SET_V_TOTAL_MIN_MASK_EN, 0, | |
748 | OTG_SET_V_TOTAL_MIN_MASK, 0); | |
749 | } else { | |
750 | REG_SET(OTG_V_TOTAL_MIN, 0, | |
751 | OTG_V_TOTAL_MIN, 0); | |
752 | ||
753 | REG_SET(OTG_V_TOTAL_MAX, 0, | |
754 | OTG_V_TOTAL_MAX, 0); | |
755 | ||
756 | REG_UPDATE_4(OTG_V_TOTAL_CONTROL, | |
757 | OTG_SET_V_TOTAL_MIN_MASK, 0, | |
758 | OTG_V_TOTAL_MIN_SEL, 0, | |
759 | OTG_V_TOTAL_MAX_SEL, 0, | |
760 | OTG_FORCE_LOCK_ON_EVENT, 0); | |
761 | } | |
762 | } | |
763 | ||
62a3213a | 764 | static void tgn10_set_test_pattern( |
70ccab60 HW |
765 | struct timing_generator *tg, |
766 | /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' | |
767 | * because this is not DP-specific (which is probably somewhere in DP | |
768 | * encoder) */ | |
769 | enum controller_dp_test_pattern test_pattern, | |
770 | enum dc_color_depth color_depth) | |
771 | { | |
772 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
773 | enum test_pattern_color_format bit_depth; | |
774 | enum test_pattern_dyn_range dyn_range; | |
775 | enum test_pattern_mode mode; | |
776 | uint32_t pattern_mask; | |
777 | uint32_t pattern_data; | |
778 | /* color ramp generator mixes 16-bits color */ | |
779 | uint32_t src_bpc = 16; | |
780 | /* requested bpc */ | |
781 | uint32_t dst_bpc; | |
782 | uint32_t index; | |
783 | /* RGB values of the color bars. | |
784 | * Produce two RGB colors: RGB0 - white (all Fs) | |
785 | * and RGB1 - black (all 0s) | |
786 | * (three RGB components for two colors) | |
787 | */ | |
788 | uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, | |
789 | 0x0000, 0x0000}; | |
790 | /* dest color (converted to the specified color format) */ | |
791 | uint16_t dst_color[6]; | |
792 | uint32_t inc_base; | |
793 | ||
794 | /* translate to bit depth */ | |
795 | switch (color_depth) { | |
796 | case COLOR_DEPTH_666: | |
797 | bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; | |
798 | break; | |
799 | case COLOR_DEPTH_888: | |
800 | bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; | |
801 | break; | |
802 | case COLOR_DEPTH_101010: | |
803 | bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; | |
804 | break; | |
805 | case COLOR_DEPTH_121212: | |
806 | bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; | |
807 | break; | |
808 | default: | |
809 | bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; | |
810 | break; | |
811 | } | |
812 | ||
813 | switch (test_pattern) { | |
814 | case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: | |
815 | case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: | |
816 | { | |
817 | dyn_range = (test_pattern == | |
818 | CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? | |
819 | TEST_PATTERN_DYN_RANGE_CEA : | |
820 | TEST_PATTERN_DYN_RANGE_VESA); | |
821 | mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; | |
822 | ||
823 | REG_UPDATE_2(OTG_TEST_PATTERN_PARAMETERS, | |
824 | OTG_TEST_PATTERN_VRES, 6, | |
825 | OTG_TEST_PATTERN_HRES, 6); | |
826 | ||
827 | REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, | |
828 | OTG_TEST_PATTERN_EN, 1, | |
829 | OTG_TEST_PATTERN_MODE, mode, | |
830 | OTG_TEST_PATTERN_DYNAMIC_RANGE, dyn_range, | |
831 | OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); | |
832 | } | |
833 | break; | |
834 | ||
835 | case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: | |
836 | case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: | |
837 | { | |
838 | mode = (test_pattern == | |
839 | CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? | |
840 | TEST_PATTERN_MODE_VERTICALBARS : | |
841 | TEST_PATTERN_MODE_HORIZONTALBARS); | |
842 | ||
843 | switch (bit_depth) { | |
844 | case TEST_PATTERN_COLOR_FORMAT_BPC_6: | |
845 | dst_bpc = 6; | |
846 | break; | |
847 | case TEST_PATTERN_COLOR_FORMAT_BPC_8: | |
848 | dst_bpc = 8; | |
849 | break; | |
850 | case TEST_PATTERN_COLOR_FORMAT_BPC_10: | |
851 | dst_bpc = 10; | |
852 | break; | |
853 | default: | |
854 | dst_bpc = 8; | |
855 | break; | |
856 | } | |
857 | ||
858 | /* adjust color to the required colorFormat */ | |
859 | for (index = 0; index < 6; index++) { | |
860 | /* dst = 2^dstBpc * src / 2^srcBpc = src >> | |
861 | * (srcBpc - dstBpc); | |
862 | */ | |
863 | dst_color[index] = | |
864 | src_color[index] >> (src_bpc - dst_bpc); | |
865 | /* CRTC_TEST_PATTERN_DATA has 16 bits, | |
866 | * lowest 6 are hardwired to ZERO | |
867 | * color bits should be left aligned aligned to MSB | |
868 | * XXXXXXXXXX000000 for 10 bit, | |
869 | * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6 | |
870 | */ | |
871 | dst_color[index] <<= (16 - dst_bpc); | |
872 | } | |
873 | ||
874 | REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); | |
875 | ||
876 | /* We have to write the mask before data, similar to pipeline. | |
877 | * For example, for 8 bpc, if we want RGB0 to be magenta, | |
878 | * and RGB1 to be cyan, | |
879 | * we need to make 7 writes: | |
880 | * MASK DATA | |
881 | * 000001 00000000 00000000 set mask to R0 | |
882 | * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 | |
883 | * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 | |
884 | * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 | |
885 | * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 | |
886 | * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 | |
887 | * 100000 11111111 00000000 B1 255, 0xFF00 | |
888 | * | |
889 | * we will make a loop of 6 in which we prepare the mask, | |
890 | * then write, then prepare the color for next write. | |
891 | * first iteration will write mask only, | |
892 | * but each next iteration color prepared in | |
893 | * previous iteration will be written within new mask, | |
894 | * the last component will written separately, | |
895 | * mask is not changing between 6th and 7th write | |
896 | * and color will be prepared by last iteration | |
897 | */ | |
898 | ||
899 | /* write color, color values mask in CRTC_TEST_PATTERN_MASK | |
900 | * is B1, G1, R1, B0, G0, R0 | |
901 | */ | |
902 | pattern_data = 0; | |
903 | for (index = 0; index < 6; index++) { | |
904 | /* prepare color mask, first write PATTERN_DATA | |
905 | * will have all zeros | |
906 | */ | |
907 | pattern_mask = (1 << index); | |
908 | ||
909 | /* write color component */ | |
910 | REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, | |
911 | OTG_TEST_PATTERN_MASK, pattern_mask, | |
912 | OTG_TEST_PATTERN_DATA, pattern_data); | |
913 | ||
914 | /* prepare next color component, | |
915 | * will be written in the next iteration | |
916 | */ | |
917 | pattern_data = dst_color[index]; | |
918 | } | |
919 | /* write last color component, | |
920 | * it's been already prepared in the loop | |
921 | */ | |
922 | REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, | |
923 | OTG_TEST_PATTERN_MASK, pattern_mask, | |
924 | OTG_TEST_PATTERN_DATA, pattern_data); | |
925 | ||
926 | /* enable test pattern */ | |
927 | REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, | |
928 | OTG_TEST_PATTERN_EN, 1, | |
929 | OTG_TEST_PATTERN_MODE, mode, | |
930 | OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, | |
931 | OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); | |
932 | } | |
933 | break; | |
934 | ||
935 | case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: | |
936 | { | |
937 | mode = (bit_depth == | |
938 | TEST_PATTERN_COLOR_FORMAT_BPC_10 ? | |
939 | TEST_PATTERN_MODE_DUALRAMP_RGB : | |
940 | TEST_PATTERN_MODE_SINGLERAMP_RGB); | |
941 | ||
942 | switch (bit_depth) { | |
943 | case TEST_PATTERN_COLOR_FORMAT_BPC_6: | |
944 | dst_bpc = 6; | |
945 | break; | |
946 | case TEST_PATTERN_COLOR_FORMAT_BPC_8: | |
947 | dst_bpc = 8; | |
948 | break; | |
949 | case TEST_PATTERN_COLOR_FORMAT_BPC_10: | |
950 | dst_bpc = 10; | |
951 | break; | |
952 | default: | |
953 | dst_bpc = 8; | |
954 | break; | |
955 | } | |
956 | ||
957 | /* increment for the first ramp for one color gradation | |
958 | * 1 gradation for 6-bit color is 2^10 | |
959 | * gradations in 16-bit color | |
960 | */ | |
961 | inc_base = (src_bpc - dst_bpc); | |
962 | ||
963 | switch (bit_depth) { | |
964 | case TEST_PATTERN_COLOR_FORMAT_BPC_6: | |
965 | { | |
966 | REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, | |
967 | OTG_TEST_PATTERN_INC0, inc_base, | |
968 | OTG_TEST_PATTERN_INC1, 0, | |
969 | OTG_TEST_PATTERN_HRES, 6, | |
970 | OTG_TEST_PATTERN_VRES, 6, | |
971 | OTG_TEST_PATTERN_RAMP0_OFFSET, 0); | |
972 | } | |
973 | break; | |
974 | case TEST_PATTERN_COLOR_FORMAT_BPC_8: | |
975 | { | |
976 | REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, | |
977 | OTG_TEST_PATTERN_INC0, inc_base, | |
978 | OTG_TEST_PATTERN_INC1, 0, | |
979 | OTG_TEST_PATTERN_HRES, 8, | |
980 | OTG_TEST_PATTERN_VRES, 6, | |
981 | OTG_TEST_PATTERN_RAMP0_OFFSET, 0); | |
982 | } | |
983 | break; | |
984 | case TEST_PATTERN_COLOR_FORMAT_BPC_10: | |
985 | { | |
986 | REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, | |
987 | OTG_TEST_PATTERN_INC0, inc_base, | |
988 | OTG_TEST_PATTERN_INC1, inc_base + 2, | |
989 | OTG_TEST_PATTERN_HRES, 8, | |
990 | OTG_TEST_PATTERN_VRES, 5, | |
991 | OTG_TEST_PATTERN_RAMP0_OFFSET, 384 << 6); | |
992 | } | |
993 | break; | |
994 | default: | |
995 | break; | |
996 | } | |
997 | ||
998 | REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); | |
999 | ||
1000 | /* enable test pattern */ | |
1001 | REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); | |
1002 | ||
1003 | REG_SET_4(OTG_TEST_PATTERN_CONTROL, 0, | |
1004 | OTG_TEST_PATTERN_EN, 1, | |
1005 | OTG_TEST_PATTERN_MODE, mode, | |
1006 | OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, | |
1007 | OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); | |
1008 | } | |
1009 | break; | |
1010 | case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: | |
1011 | { | |
1012 | REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); | |
1013 | REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); | |
1014 | REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); | |
1015 | } | |
1016 | break; | |
1017 | default: | |
1018 | break; | |
1019 | ||
1020 | } | |
1021 | } | |
1022 | ||
62a3213a | 1023 | static void tgn10_get_crtc_scanoutpos( |
70ccab60 HW |
1024 | struct timing_generator *tg, |
1025 | uint32_t *v_blank_start, | |
1026 | uint32_t *v_blank_end, | |
1027 | uint32_t *h_position, | |
1028 | uint32_t *v_position) | |
1029 | { | |
1030 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
1031 | struct crtc_position position; | |
1032 | ||
1033 | REG_GET_2(OTG_V_BLANK_START_END, | |
1034 | OTG_V_BLANK_START, v_blank_start, | |
1035 | OTG_V_BLANK_END, v_blank_end); | |
1036 | ||
62a3213a | 1037 | tgn10_get_position(tg, &position); |
70ccab60 HW |
1038 | |
1039 | *h_position = position.horizontal_count; | |
1040 | *v_position = position.vertical_count; | |
1041 | } | |
1042 | ||
9edba557 VP |
1043 | |
1044 | ||
62a3213a | 1045 | static void tgn10_enable_stereo(struct timing_generator *tg, |
9edba557 VP |
1046 | const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) |
1047 | { | |
1048 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
1049 | ||
1050 | uint32_t active_width = timing->h_addressable; | |
1051 | uint32_t space1_size = timing->v_total - timing->v_addressable; | |
1052 | ||
1053 | if (flags) { | |
1054 | uint32_t stereo_en; | |
1055 | stereo_en = flags->FRAME_PACKED == 0 ? 1 : 0; | |
1056 | ||
1057 | if (flags->PROGRAM_STEREO) | |
1058 | REG_UPDATE_3(OTG_STEREO_CONTROL, | |
1059 | OTG_STEREO_EN, stereo_en, | |
1060 | OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0, | |
1061 | OTG_STEREO_SYNC_OUTPUT_POLARITY, 0); | |
1062 | ||
1063 | if (flags->PROGRAM_POLARITY) | |
1064 | REG_UPDATE(OTG_STEREO_CONTROL, | |
1065 | OTG_STEREO_EYE_FLAG_POLARITY, | |
1066 | flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1); | |
1067 | ||
1068 | if (flags->DISABLE_STEREO_DP_SYNC) | |
1069 | REG_UPDATE(OTG_STEREO_CONTROL, | |
1070 | OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1); | |
1071 | ||
061d3499 | 1072 | if (flags->PROGRAM_STEREO) |
9edba557 | 1073 | REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL, |
061d3499 KC |
1074 | OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED, |
1075 | OTG_3D_STRUCTURE_V_UPDATE_MODE, flags->FRAME_PACKED, | |
1076 | OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED); | |
9edba557 VP |
1077 | |
1078 | } | |
1079 | ||
1080 | REG_UPDATE(OPPBUF_CONTROL, | |
1081 | OPPBUF_ACTIVE_WIDTH, active_width); | |
1082 | ||
1083 | REG_UPDATE(OPPBUF_3D_PARAMETERS_0, | |
1084 | OPPBUF_3D_VACT_SPACE1_SIZE, space1_size); | |
1085 | } | |
1086 | ||
62a3213a | 1087 | static void tgn10_program_stereo(struct timing_generator *tg, |
9edba557 VP |
1088 | const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) |
1089 | { | |
1090 | if (flags->PROGRAM_STEREO) | |
62a3213a | 1091 | tgn10_enable_stereo(tg, timing, flags); |
9edba557 | 1092 | else |
62a3213a | 1093 | tgn10_disable_stereo(tg); |
9edba557 VP |
1094 | } |
1095 | ||
1096 | ||
62a3213a | 1097 | static bool tgn10_is_stereo_left_eye(struct timing_generator *tg) |
9edba557 VP |
1098 | { |
1099 | bool ret = false; | |
1100 | uint32_t left_eye = 0; | |
1101 | struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); | |
1102 | ||
1103 | REG_GET(OTG_STEREO_STATUS, | |
1104 | OTG_STEREO_CURRENT_EYE, &left_eye); | |
1105 | if (left_eye == 1) | |
1106 | ret = true; | |
1107 | else | |
1108 | ret = false; | |
1109 | ||
1110 | return ret; | |
1111 | } | |
1112 | ||
214435ff CM |
1113 | void tgn10_read_otg_state(struct dcn10_timing_generator *tgn10, |
1114 | struct dcn_otg_state *s) | |
1115 | { | |
6f54d0b1 LT |
1116 | REG_GET(OTG_CONTROL, |
1117 | OTG_MASTER_EN, &s->otg_enabled); | |
1118 | ||
214435ff CM |
1119 | REG_GET_2(OTG_V_BLANK_START_END, |
1120 | OTG_V_BLANK_START, &s->v_blank_start, | |
1121 | OTG_V_BLANK_END, &s->v_blank_end); | |
1122 | ||
1123 | REG_GET(OTG_V_SYNC_A_CNTL, | |
1124 | OTG_V_SYNC_A_POL, &s->v_sync_a_pol); | |
1125 | ||
1126 | REG_GET(OTG_V_TOTAL, | |
1127 | OTG_V_TOTAL, &s->v_total); | |
1128 | ||
1129 | REG_GET(OTG_V_TOTAL_MAX, | |
1130 | OTG_V_TOTAL_MAX, &s->v_total_max); | |
1131 | ||
1132 | REG_GET(OTG_V_TOTAL_MIN, | |
1133 | OTG_V_TOTAL_MIN, &s->v_total_min); | |
1134 | ||
1135 | REG_GET_2(OTG_V_SYNC_A, | |
1136 | OTG_V_SYNC_A_START, &s->v_sync_a_start, | |
1137 | OTG_V_SYNC_A_END, &s->v_sync_a_end); | |
1138 | ||
1139 | REG_GET_2(OTG_H_BLANK_START_END, | |
1140 | OTG_H_BLANK_START, &s->h_blank_start, | |
1141 | OTG_H_BLANK_END, &s->h_blank_end); | |
1142 | ||
1143 | REG_GET_2(OTG_H_SYNC_A, | |
1144 | OTG_H_SYNC_A_START, &s->h_sync_a_start, | |
1145 | OTG_H_SYNC_A_END, &s->h_sync_a_end); | |
1146 | ||
1147 | REG_GET(OTG_H_SYNC_A_CNTL, | |
1148 | OTG_H_SYNC_A_POL, &s->h_sync_a_pol); | |
1149 | ||
1150 | REG_GET(OTG_H_TOTAL, | |
1151 | OTG_H_TOTAL, &s->h_total); | |
1152 | ||
1153 | REG_GET(OPTC_INPUT_GLOBAL_CONTROL, | |
1154 | OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status); | |
1155 | } | |
1156 | ||
1157 | ||
395f669e | 1158 | static const struct timing_generator_funcs dcn10_tg_funcs = { |
62a3213a DL |
1159 | .validate_timing = tgn10_validate_timing, |
1160 | .program_timing = tgn10_program_timing, | |
1161 | .program_global_sync = tgn10_program_global_sync, | |
1162 | .enable_crtc = tgn10_enable_crtc, | |
1163 | .disable_crtc = tgn10_disable_crtc, | |
70ccab60 | 1164 | /* used by enable_timing_synchronization. Not need for FPGA */ |
62a3213a DL |
1165 | .is_counter_moving = tgn10_is_counter_moving, |
1166 | .get_position = tgn10_get_position, | |
1167 | .get_frame_count = tgn10_get_vblank_counter, | |
1168 | .get_scanoutpos = tgn10_get_crtc_scanoutpos, | |
1169 | .set_early_control = tgn10_set_early_control, | |
70ccab60 | 1170 | /* used by enable_timing_synchronization. Not need for FPGA */ |
62a3213a DL |
1171 | .wait_for_state = tgn10_wait_for_state, |
1172 | .set_blank = tgn10_set_blank, | |
1173 | .is_blanked = tgn10_is_blanked, | |
1174 | .set_blank_color = tgn10_program_blank_color, | |
62a3213a DL |
1175 | .did_triggered_reset_occur = tgn10_did_triggered_reset_occur, |
1176 | .enable_reset_trigger = tgn10_enable_reset_trigger, | |
1177 | .disable_reset_trigger = tgn10_disable_reset_trigger, | |
1178 | .lock = tgn10_lock, | |
1179 | .unlock = tgn10_unlock, | |
1180 | .enable_optc_clock = tgn10_enable_optc_clock, | |
1181 | .set_drr = tgn10_set_drr, | |
1182 | .set_static_screen_control = tgn10_set_static_screen_control, | |
1183 | .set_test_pattern = tgn10_set_test_pattern, | |
1184 | .program_stereo = tgn10_program_stereo, | |
1185 | .is_stereo_left_eye = tgn10_is_stereo_left_eye | |
70ccab60 HW |
1186 | }; |
1187 | ||
1188 | void dcn10_timing_generator_init(struct dcn10_timing_generator *tgn10) | |
1189 | { | |
1190 | tgn10->base.funcs = &dcn10_tg_funcs; | |
1191 | ||
1192 | tgn10->max_h_total = tgn10->tg_mask->OTG_H_TOTAL + 1; | |
1193 | tgn10->max_v_total = tgn10->tg_mask->OTG_V_TOTAL + 1; | |
1194 | ||
1195 | tgn10->min_h_blank = 32; | |
1196 | tgn10->min_v_blank = 3; | |
1197 | tgn10->min_v_blank_interlace = 5; | |
1198 | tgn10->min_h_sync_width = 8; | |
1199 | tgn10->min_v_sync_width = 1; | |
1200 | } |