Line data Source code
1 : /*
2 : * Copyright 2012-15 Advanced Micro Devices, Inc.
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a
5 : * copy of this software and associated documentation files (the "Software"),
6 : * to deal in the Software without restriction, including without limitation
7 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 : * and/or sell copies of the Software, and to permit persons to whom the
9 : * Software is furnished to do so, subject to the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included in
12 : * all copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 : * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 : * OTHER DEALINGS IN THE SOFTWARE.
21 : *
22 : * Authors: AMD
23 : *
24 : */
25 :
26 : #include "dm_services.h"
27 :
28 : /* include DCE11 register header files */
29 : #include "dce/dce_11_0_d.h"
30 : #include "dce/dce_11_0_sh_mask.h"
31 :
32 : #include "dc_types.h"
33 : #include "dc_bios_types.h"
34 : #include "dc.h"
35 :
36 : #include "include/grph_object_id.h"
37 : #include "include/logger_interface.h"
38 : #include "dce110_timing_generator.h"
39 :
40 : #include "timing_generator.h"
41 :
42 :
43 : #define NUMBER_OF_FRAME_TO_WAIT_ON_TRIGGERED_RESET 10
44 :
45 : #define MAX_H_TOTAL (CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1)
46 : #define MAX_V_TOTAL (CRTC_V_TOTAL__CRTC_V_TOTAL_MASKhw + 1)
47 :
48 : #define CRTC_REG(reg) (reg + tg110->offsets.crtc)
49 : #define DCP_REG(reg) (reg + tg110->offsets.dcp)
50 :
51 : /* Flowing register offsets are same in files of
52 : * dce/dce_11_0_d.h
53 : * dce/vi_polaris10_p/vi_polaris10_d.h
54 : *
55 : * So we can create dce110 timing generator to use it.
56 : */
57 :
58 :
59 : /*
60 : * apply_front_porch_workaround
61 : *
62 : * This is a workaround for a bug that has existed since R5xx and has not been
63 : * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
64 : */
65 : static void dce110_timing_generator_apply_front_porch_workaround(
66 : struct timing_generator *tg,
67 : struct dc_crtc_timing *timing)
68 : {
69 0 : if (timing->flags.INTERLACE == 1) {
70 0 : if (timing->v_front_porch < 2)
71 0 : timing->v_front_porch = 2;
72 : } else {
73 0 : if (timing->v_front_porch < 1)
74 0 : timing->v_front_porch = 1;
75 : }
76 : }
77 :
78 : /*
79 : *****************************************************************************
80 : * Function: is_in_vertical_blank
81 : *
82 : * @brief
83 : * check the current status of CRTC to check if we are in Vertical Blank
84 : * regioneased" state
85 : *
86 : * @return
87 : * true if currently in blank region, false otherwise
88 : *
89 : *****************************************************************************
90 : */
91 : static bool dce110_timing_generator_is_in_vertical_blank(
92 : struct timing_generator *tg)
93 : {
94 0 : uint32_t addr = 0;
95 0 : uint32_t value = 0;
96 0 : uint32_t field = 0;
97 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
98 :
99 0 : addr = CRTC_REG(mmCRTC_STATUS);
100 0 : value = dm_read_reg(tg->ctx, addr);
101 0 : field = get_reg_field_value(value, CRTC_STATUS, CRTC_V_BLANK);
102 : return field == 1;
103 : }
104 :
105 0 : void dce110_timing_generator_set_early_control(
106 : struct timing_generator *tg,
107 : uint32_t early_cntl)
108 : {
109 : uint32_t regval;
110 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
111 0 : uint32_t address = CRTC_REG(mmCRTC_CONTROL);
112 :
113 0 : regval = dm_read_reg(tg->ctx, address);
114 0 : set_reg_field_value(regval, early_cntl,
115 : CRTC_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
116 0 : dm_write_reg(tg->ctx, address, regval);
117 0 : }
118 :
119 : /*
120 : * Enable CRTC
121 : * Enable CRTC - call ASIC Control Object to enable Timing generator.
122 : */
123 0 : bool dce110_timing_generator_enable_crtc(struct timing_generator *tg)
124 : {
125 : enum bp_result result;
126 :
127 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
128 0 : uint32_t value = 0;
129 :
130 : /*
131 : * 3 is used to make sure V_UPDATE occurs at the beginning of the first
132 : * line of vertical front porch
133 : */
134 0 : set_reg_field_value(
135 : value,
136 : 0,
137 : CRTC_MASTER_UPDATE_MODE,
138 : MASTER_UPDATE_MODE);
139 :
140 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_MODE), value);
141 :
142 : /* TODO: may want this on to catch underflow */
143 0 : value = 0;
144 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_LOCK), value);
145 :
146 0 : result = tg->bp->funcs->enable_crtc(tg->bp, tg110->controller_id, true);
147 :
148 0 : return result == BP_RESULT_OK;
149 : }
150 :
151 0 : void dce110_timing_generator_program_blank_color(
152 : struct timing_generator *tg,
153 : const struct tg_color *black_color)
154 : {
155 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
156 0 : uint32_t addr = CRTC_REG(mmCRTC_BLACK_COLOR);
157 0 : uint32_t value = dm_read_reg(tg->ctx, addr);
158 :
159 0 : set_reg_field_value(
160 : value,
161 : black_color->color_b_cb,
162 : CRTC_BLACK_COLOR,
163 : CRTC_BLACK_COLOR_B_CB);
164 0 : set_reg_field_value(
165 : value,
166 : black_color->color_g_y,
167 : CRTC_BLACK_COLOR,
168 : CRTC_BLACK_COLOR_G_Y);
169 0 : set_reg_field_value(
170 : value,
171 : black_color->color_r_cr,
172 : CRTC_BLACK_COLOR,
173 : CRTC_BLACK_COLOR_R_CR);
174 :
175 0 : dm_write_reg(tg->ctx, addr, value);
176 0 : }
177 :
178 : /*
179 : *****************************************************************************
180 : * Function: disable_stereo
181 : *
182 : * @brief
183 : * Disables active stereo on controller
184 : * Frame Packing need to be disabled in vBlank or when CRTC not running
185 : *****************************************************************************
186 : */
187 : #if 0
188 : @TODOSTEREO
189 : static void disable_stereo(struct timing_generator *tg)
190 : {
191 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
192 : uint32_t addr = CRTC_REG(mmCRTC_3D_STRUCTURE_CONTROL);
193 : uint32_t value = 0;
194 : uint32_t test = 0;
195 : uint32_t field = 0;
196 : uint32_t struc_en = 0;
197 : uint32_t struc_stereo_sel_ovr = 0;
198 :
199 : value = dm_read_reg(tg->ctx, addr);
200 : struc_en = get_reg_field_value(
201 : value,
202 : CRTC_3D_STRUCTURE_CONTROL,
203 : CRTC_3D_STRUCTURE_EN);
204 :
205 : struc_stereo_sel_ovr = get_reg_field_value(
206 : value,
207 : CRTC_3D_STRUCTURE_CONTROL,
208 : CRTC_3D_STRUCTURE_STEREO_SEL_OVR);
209 :
210 : /*
211 : * When disabling Frame Packing in 2 step mode, we need to program both
212 : * registers at the same frame
213 : * Programming it in the beginning of VActive makes sure we are ok
214 : */
215 :
216 : if (struc_en != 0 && struc_stereo_sel_ovr == 0) {
217 : tg->funcs->wait_for_vblank(tg);
218 : tg->funcs->wait_for_vactive(tg);
219 : }
220 :
221 : value = 0;
222 : dm_write_reg(tg->ctx, addr, value);
223 :
224 : addr = tg->regs[IDX_CRTC_STEREO_CONTROL];
225 : dm_write_reg(tg->ctx, addr, value);
226 : }
227 : #endif
228 :
229 : /*
230 : * disable_crtc - call ASIC Control Object to disable Timing generator.
231 : */
232 0 : bool dce110_timing_generator_disable_crtc(struct timing_generator *tg)
233 : {
234 : enum bp_result result;
235 :
236 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
237 :
238 0 : result = tg->bp->funcs->enable_crtc(tg->bp, tg110->controller_id, false);
239 :
240 : /* Need to make sure stereo is disabled according to the DCE5.0 spec */
241 :
242 : /*
243 : * @TODOSTEREO call this when adding stereo support
244 : * tg->funcs->disable_stereo(tg);
245 : */
246 :
247 0 : return result == BP_RESULT_OK;
248 : }
249 :
250 : /*
251 : * program_horz_count_by_2
252 : * Programs DxCRTC_HORZ_COUNT_BY2_EN - 1 for DVI 30bpp mode, 0 otherwise
253 : */
254 0 : static void program_horz_count_by_2(
255 : struct timing_generator *tg,
256 : const struct dc_crtc_timing *timing)
257 : {
258 : uint32_t regval;
259 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
260 :
261 0 : regval = dm_read_reg(tg->ctx,
262 : CRTC_REG(mmCRTC_COUNT_CONTROL));
263 :
264 0 : set_reg_field_value(regval, 0, CRTC_COUNT_CONTROL,
265 : CRTC_HORZ_COUNT_BY2_EN);
266 :
267 0 : if (timing->flags.HORZ_COUNT_BY_TWO)
268 0 : set_reg_field_value(regval, 1, CRTC_COUNT_CONTROL,
269 : CRTC_HORZ_COUNT_BY2_EN);
270 :
271 0 : dm_write_reg(tg->ctx,
272 : CRTC_REG(mmCRTC_COUNT_CONTROL), regval);
273 0 : }
274 :
275 : /*
276 : * program_timing_generator
277 : * Program CRTC Timing Registers - DxCRTC_H_*, DxCRTC_V_*, Pixel repetition.
278 : * Call ASIC Control Object to program Timings.
279 : */
280 0 : bool dce110_timing_generator_program_timing_generator(
281 : struct timing_generator *tg,
282 : const struct dc_crtc_timing *dc_crtc_timing)
283 : {
284 : enum bp_result result;
285 : struct bp_hw_crtc_timing_parameters bp_params;
286 : struct dc_crtc_timing patched_crtc_timing;
287 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
288 :
289 0 : uint32_t vsync_offset = dc_crtc_timing->v_border_bottom +
290 0 : dc_crtc_timing->v_front_porch;
291 0 : uint32_t v_sync_start =dc_crtc_timing->v_addressable + vsync_offset;
292 :
293 0 : uint32_t hsync_offset = dc_crtc_timing->h_border_right +
294 0 : dc_crtc_timing->h_front_porch;
295 0 : uint32_t h_sync_start = dc_crtc_timing->h_addressable + hsync_offset;
296 :
297 0 : memset(&bp_params, 0, sizeof(struct bp_hw_crtc_timing_parameters));
298 :
299 : /* Due to an asic bug we need to apply the Front Porch workaround prior
300 : * to programming the timing.
301 : */
302 :
303 0 : patched_crtc_timing = *dc_crtc_timing;
304 :
305 0 : dce110_timing_generator_apply_front_porch_workaround(tg, &patched_crtc_timing);
306 :
307 0 : bp_params.controller_id = tg110->controller_id;
308 :
309 0 : bp_params.h_total = patched_crtc_timing.h_total;
310 0 : bp_params.h_addressable =
311 0 : patched_crtc_timing.h_addressable;
312 0 : bp_params.v_total = patched_crtc_timing.v_total;
313 0 : bp_params.v_addressable = patched_crtc_timing.v_addressable;
314 :
315 0 : bp_params.h_sync_start = h_sync_start;
316 0 : bp_params.h_sync_width = patched_crtc_timing.h_sync_width;
317 0 : bp_params.v_sync_start = v_sync_start;
318 0 : bp_params.v_sync_width = patched_crtc_timing.v_sync_width;
319 :
320 : /* Set overscan */
321 0 : bp_params.h_overscan_left =
322 0 : patched_crtc_timing.h_border_left;
323 0 : bp_params.h_overscan_right =
324 0 : patched_crtc_timing.h_border_right;
325 0 : bp_params.v_overscan_top = patched_crtc_timing.v_border_top;
326 0 : bp_params.v_overscan_bottom =
327 0 : patched_crtc_timing.v_border_bottom;
328 :
329 : /* Set flags */
330 0 : if (patched_crtc_timing.flags.HSYNC_POSITIVE_POLARITY == 1)
331 0 : bp_params.flags.HSYNC_POSITIVE_POLARITY = 1;
332 :
333 0 : if (patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY == 1)
334 0 : bp_params.flags.VSYNC_POSITIVE_POLARITY = 1;
335 :
336 0 : if (patched_crtc_timing.flags.INTERLACE == 1)
337 0 : bp_params.flags.INTERLACE = 1;
338 :
339 0 : if (patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1)
340 0 : bp_params.flags.HORZ_COUNT_BY_TWO = 1;
341 :
342 0 : result = tg->bp->funcs->program_crtc_timing(tg->bp, &bp_params);
343 :
344 0 : program_horz_count_by_2(tg, &patched_crtc_timing);
345 :
346 0 : tg110->base.funcs->enable_advanced_request(tg, true, &patched_crtc_timing);
347 :
348 : /* Enable stereo - only when we need to pack 3D frame. Other types
349 : * of stereo handled in explicit call */
350 :
351 0 : return result == BP_RESULT_OK;
352 : }
353 :
354 : /*
355 : *****************************************************************************
356 : * Function: set_drr
357 : *
358 : * @brief
359 : * Program dynamic refresh rate registers m_DxCRTC_V_TOTAL_*.
360 : *
361 : * @param [in] pHwCrtcTiming: point to H
362 : * wCrtcTiming struct
363 : *****************************************************************************
364 : */
365 0 : void dce110_timing_generator_set_drr(
366 : struct timing_generator *tg,
367 : const struct drr_params *params)
368 : {
369 : /* register values */
370 0 : uint32_t v_total_min = 0;
371 0 : uint32_t v_total_max = 0;
372 0 : uint32_t v_total_cntl = 0;
373 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
374 :
375 0 : uint32_t addr = 0;
376 :
377 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_MIN);
378 0 : v_total_min = dm_read_reg(tg->ctx, addr);
379 :
380 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_MAX);
381 0 : v_total_max = dm_read_reg(tg->ctx, addr);
382 :
383 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_CONTROL);
384 0 : v_total_cntl = dm_read_reg(tg->ctx, addr);
385 :
386 0 : if (params != NULL &&
387 0 : params->vertical_total_max > 0 &&
388 0 : params->vertical_total_min > 0) {
389 :
390 0 : set_reg_field_value(v_total_max,
391 : params->vertical_total_max - 1,
392 : CRTC_V_TOTAL_MAX,
393 : CRTC_V_TOTAL_MAX);
394 :
395 0 : set_reg_field_value(v_total_min,
396 : params->vertical_total_min - 1,
397 : CRTC_V_TOTAL_MIN,
398 : CRTC_V_TOTAL_MIN);
399 :
400 0 : set_reg_field_value(v_total_cntl,
401 : 1,
402 : CRTC_V_TOTAL_CONTROL,
403 : CRTC_V_TOTAL_MIN_SEL);
404 :
405 0 : set_reg_field_value(v_total_cntl,
406 : 1,
407 : CRTC_V_TOTAL_CONTROL,
408 : CRTC_V_TOTAL_MAX_SEL);
409 :
410 0 : set_reg_field_value(v_total_cntl,
411 : 0,
412 : CRTC_V_TOTAL_CONTROL,
413 : CRTC_FORCE_LOCK_ON_EVENT);
414 0 : set_reg_field_value(v_total_cntl,
415 : 0,
416 : CRTC_V_TOTAL_CONTROL,
417 : CRTC_FORCE_LOCK_TO_MASTER_VSYNC);
418 :
419 0 : set_reg_field_value(v_total_cntl,
420 : 0,
421 : CRTC_V_TOTAL_CONTROL,
422 : CRTC_SET_V_TOTAL_MIN_MASK_EN);
423 :
424 0 : set_reg_field_value(v_total_cntl,
425 : 0,
426 : CRTC_V_TOTAL_CONTROL,
427 : CRTC_SET_V_TOTAL_MIN_MASK);
428 : } else {
429 0 : set_reg_field_value(v_total_cntl,
430 : 0,
431 : CRTC_V_TOTAL_CONTROL,
432 : CRTC_SET_V_TOTAL_MIN_MASK);
433 0 : set_reg_field_value(v_total_cntl,
434 : 0,
435 : CRTC_V_TOTAL_CONTROL,
436 : CRTC_V_TOTAL_MIN_SEL);
437 0 : set_reg_field_value(v_total_cntl,
438 : 0,
439 : CRTC_V_TOTAL_CONTROL,
440 : CRTC_V_TOTAL_MAX_SEL);
441 0 : set_reg_field_value(v_total_min,
442 : 0,
443 : CRTC_V_TOTAL_MIN,
444 : CRTC_V_TOTAL_MIN);
445 0 : set_reg_field_value(v_total_max,
446 : 0,
447 : CRTC_V_TOTAL_MAX,
448 : CRTC_V_TOTAL_MAX);
449 0 : set_reg_field_value(v_total_cntl,
450 : 0,
451 : CRTC_V_TOTAL_CONTROL,
452 : CRTC_FORCE_LOCK_ON_EVENT);
453 0 : set_reg_field_value(v_total_cntl,
454 : 0,
455 : CRTC_V_TOTAL_CONTROL,
456 : CRTC_FORCE_LOCK_TO_MASTER_VSYNC);
457 : }
458 :
459 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_MIN);
460 0 : dm_write_reg(tg->ctx, addr, v_total_min);
461 :
462 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_MAX);
463 0 : dm_write_reg(tg->ctx, addr, v_total_max);
464 :
465 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_CONTROL);
466 0 : dm_write_reg(tg->ctx, addr, v_total_cntl);
467 0 : }
468 :
469 0 : void dce110_timing_generator_set_static_screen_control(
470 : struct timing_generator *tg,
471 : uint32_t event_triggers,
472 : uint32_t num_frames)
473 : {
474 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
475 0 : uint32_t static_screen_cntl = 0;
476 0 : uint32_t addr = 0;
477 :
478 : // By register spec, it only takes 8 bit value
479 0 : if (num_frames > 0xFF)
480 0 : num_frames = 0xFF;
481 :
482 0 : addr = CRTC_REG(mmCRTC_STATIC_SCREEN_CONTROL);
483 0 : static_screen_cntl = dm_read_reg(tg->ctx, addr);
484 :
485 0 : set_reg_field_value(static_screen_cntl,
486 : event_triggers,
487 : CRTC_STATIC_SCREEN_CONTROL,
488 : CRTC_STATIC_SCREEN_EVENT_MASK);
489 :
490 0 : set_reg_field_value(static_screen_cntl,
491 : num_frames,
492 : CRTC_STATIC_SCREEN_CONTROL,
493 : CRTC_STATIC_SCREEN_FRAME_COUNT);
494 :
495 0 : dm_write_reg(tg->ctx, addr, static_screen_cntl);
496 0 : }
497 :
498 : /*
499 : * get_vblank_counter
500 : *
501 : * @brief
502 : * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which
503 : * holds the counter of frames.
504 : *
505 : * @param
506 : * struct timing_generator *tg - [in] timing generator which controls the
507 : * desired CRTC
508 : *
509 : * @return
510 : * Counter of frames, which should equal to number of vblanks.
511 : */
512 0 : uint32_t dce110_timing_generator_get_vblank_counter(struct timing_generator *tg)
513 : {
514 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
515 0 : uint32_t addr = CRTC_REG(mmCRTC_STATUS_FRAME_COUNT);
516 0 : uint32_t value = dm_read_reg(tg->ctx, addr);
517 0 : uint32_t field = get_reg_field_value(
518 : value, CRTC_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
519 :
520 0 : return field;
521 : }
522 :
523 : /*
524 : *****************************************************************************
525 : * Function: dce110_timing_generator_get_position
526 : *
527 : * @brief
528 : * Returns CRTC vertical/horizontal counters
529 : *
530 : * @param [out] position
531 : *****************************************************************************
532 : */
533 0 : void dce110_timing_generator_get_position(struct timing_generator *tg,
534 : struct crtc_position *position)
535 : {
536 : uint32_t value;
537 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
538 :
539 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_STATUS_POSITION));
540 :
541 0 : position->horizontal_count = get_reg_field_value(
542 : value,
543 : CRTC_STATUS_POSITION,
544 : CRTC_HORZ_COUNT);
545 :
546 0 : position->vertical_count = get_reg_field_value(
547 : value,
548 : CRTC_STATUS_POSITION,
549 : CRTC_VERT_COUNT);
550 :
551 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_NOM_VERT_POSITION));
552 :
553 0 : position->nominal_vcount = get_reg_field_value(
554 : value,
555 : CRTC_NOM_VERT_POSITION,
556 : CRTC_VERT_COUNT_NOM);
557 0 : }
558 :
559 : /*
560 : *****************************************************************************
561 : * Function: get_crtc_scanoutpos
562 : *
563 : * @brief
564 : * Returns CRTC vertical/horizontal counters
565 : *
566 : * @param [out] vpos, hpos
567 : *****************************************************************************
568 : */
569 0 : void dce110_timing_generator_get_crtc_scanoutpos(
570 : struct timing_generator *tg,
571 : uint32_t *v_blank_start,
572 : uint32_t *v_blank_end,
573 : uint32_t *h_position,
574 : uint32_t *v_position)
575 : {
576 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
577 : struct crtc_position position;
578 :
579 0 : uint32_t value = dm_read_reg(tg->ctx,
580 : CRTC_REG(mmCRTC_V_BLANK_START_END));
581 :
582 0 : *v_blank_start = get_reg_field_value(value,
583 : CRTC_V_BLANK_START_END,
584 : CRTC_V_BLANK_START);
585 0 : *v_blank_end = get_reg_field_value(value,
586 : CRTC_V_BLANK_START_END,
587 : CRTC_V_BLANK_END);
588 :
589 0 : dce110_timing_generator_get_position(
590 : tg, &position);
591 :
592 0 : *h_position = position.horizontal_count;
593 0 : *v_position = position.vertical_count;
594 0 : }
595 :
596 : /* TODO: is it safe to assume that mask/shift of Primary and Underlay
597 : * are the same?
598 : * For example: today CRTC_H_TOTAL == CRTCV_H_TOTAL but is it always
599 : * guaranteed? */
600 0 : void dce110_timing_generator_program_blanking(
601 : struct timing_generator *tg,
602 : const struct dc_crtc_timing *timing)
603 : {
604 0 : uint32_t vsync_offset = timing->v_border_bottom +
605 0 : timing->v_front_porch;
606 0 : uint32_t v_sync_start =timing->v_addressable + vsync_offset;
607 :
608 0 : uint32_t hsync_offset = timing->h_border_right +
609 0 : timing->h_front_porch;
610 0 : uint32_t h_sync_start = timing->h_addressable + hsync_offset;
611 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
612 :
613 0 : struct dc_context *ctx = tg->ctx;
614 0 : uint32_t value = 0;
615 0 : uint32_t addr = 0;
616 0 : uint32_t tmp = 0;
617 :
618 0 : addr = CRTC_REG(mmCRTC_H_TOTAL);
619 0 : value = dm_read_reg(ctx, addr);
620 0 : set_reg_field_value(
621 : value,
622 : timing->h_total - 1,
623 : CRTC_H_TOTAL,
624 : CRTC_H_TOTAL);
625 0 : dm_write_reg(ctx, addr, value);
626 :
627 0 : addr = CRTC_REG(mmCRTC_V_TOTAL);
628 0 : value = dm_read_reg(ctx, addr);
629 0 : set_reg_field_value(
630 : value,
631 : timing->v_total - 1,
632 : CRTC_V_TOTAL,
633 : CRTC_V_TOTAL);
634 0 : dm_write_reg(ctx, addr, value);
635 :
636 : /* In case of V_TOTAL_CONTROL is on, make sure V_TOTAL_MAX and
637 : * V_TOTAL_MIN are equal to V_TOTAL.
638 : */
639 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_MAX);
640 0 : value = dm_read_reg(ctx, addr);
641 0 : set_reg_field_value(
642 : value,
643 : timing->v_total - 1,
644 : CRTC_V_TOTAL_MAX,
645 : CRTC_V_TOTAL_MAX);
646 0 : dm_write_reg(ctx, addr, value);
647 :
648 0 : addr = CRTC_REG(mmCRTC_V_TOTAL_MIN);
649 0 : value = dm_read_reg(ctx, addr);
650 0 : set_reg_field_value(
651 : value,
652 : timing->v_total - 1,
653 : CRTC_V_TOTAL_MIN,
654 : CRTC_V_TOTAL_MIN);
655 0 : dm_write_reg(ctx, addr, value);
656 :
657 0 : addr = CRTC_REG(mmCRTC_H_BLANK_START_END);
658 0 : value = dm_read_reg(ctx, addr);
659 :
660 0 : tmp = timing->h_total -
661 0 : (h_sync_start + timing->h_border_left);
662 :
663 0 : set_reg_field_value(
664 : value,
665 : tmp,
666 : CRTC_H_BLANK_START_END,
667 : CRTC_H_BLANK_END);
668 :
669 0 : tmp = tmp + timing->h_addressable +
670 0 : timing->h_border_left + timing->h_border_right;
671 :
672 0 : set_reg_field_value(
673 : value,
674 : tmp,
675 : CRTC_H_BLANK_START_END,
676 : CRTC_H_BLANK_START);
677 :
678 0 : dm_write_reg(ctx, addr, value);
679 :
680 0 : addr = CRTC_REG(mmCRTC_V_BLANK_START_END);
681 0 : value = dm_read_reg(ctx, addr);
682 :
683 0 : tmp = timing->v_total - (v_sync_start + timing->v_border_top);
684 :
685 0 : set_reg_field_value(
686 : value,
687 : tmp,
688 : CRTC_V_BLANK_START_END,
689 : CRTC_V_BLANK_END);
690 :
691 0 : tmp = tmp + timing->v_addressable + timing->v_border_top +
692 0 : timing->v_border_bottom;
693 :
694 0 : set_reg_field_value(
695 : value,
696 : tmp,
697 : CRTC_V_BLANK_START_END,
698 : CRTC_V_BLANK_START);
699 :
700 0 : dm_write_reg(ctx, addr, value);
701 0 : }
702 :
703 0 : void dce110_timing_generator_set_test_pattern(
704 : struct timing_generator *tg,
705 : /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
706 : * because this is not DP-specific (which is probably somewhere in DP
707 : * encoder) */
708 : enum controller_dp_test_pattern test_pattern,
709 : enum dc_color_depth color_depth)
710 : {
711 0 : struct dc_context *ctx = tg->ctx;
712 : uint32_t value;
713 : uint32_t addr;
714 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
715 : enum test_pattern_color_format bit_depth;
716 : enum test_pattern_dyn_range dyn_range;
717 : enum test_pattern_mode mode;
718 : /* color ramp generator mixes 16-bits color */
719 0 : uint32_t src_bpc = 16;
720 : /* requested bpc */
721 : uint32_t dst_bpc;
722 : uint32_t index;
723 : /* RGB values of the color bars.
724 : * Produce two RGB colors: RGB0 - white (all Fs)
725 : * and RGB1 - black (all 0s)
726 : * (three RGB components for two colors)
727 : */
728 0 : uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000,
729 : 0x0000, 0x0000};
730 : /* dest color (converted to the specified color format) */
731 : uint16_t dst_color[6];
732 : uint32_t inc_base;
733 :
734 : /* translate to bit depth */
735 : switch (color_depth) {
736 : case COLOR_DEPTH_666:
737 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6;
738 : break;
739 : case COLOR_DEPTH_888:
740 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
741 : break;
742 : case COLOR_DEPTH_101010:
743 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10;
744 : break;
745 : case COLOR_DEPTH_121212:
746 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12;
747 : break;
748 : default:
749 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
750 : break;
751 : }
752 :
753 0 : switch (test_pattern) {
754 : case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES:
755 : case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA:
756 : {
757 0 : dyn_range = (test_pattern ==
758 : CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ?
759 0 : TEST_PATTERN_DYN_RANGE_CEA :
760 : TEST_PATTERN_DYN_RANGE_VESA);
761 0 : mode = TEST_PATTERN_MODE_COLORSQUARES_RGB;
762 0 : value = 0;
763 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_PARAMETERS);
764 :
765 0 : set_reg_field_value(
766 : value,
767 : 6,
768 : CRTC_TEST_PATTERN_PARAMETERS,
769 : CRTC_TEST_PATTERN_VRES);
770 0 : set_reg_field_value(
771 : value,
772 : 6,
773 : CRTC_TEST_PATTERN_PARAMETERS,
774 : CRTC_TEST_PATTERN_HRES);
775 :
776 0 : dm_write_reg(ctx, addr, value);
777 :
778 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_CONTROL);
779 0 : value = 0;
780 :
781 0 : set_reg_field_value(
782 : value,
783 : 1,
784 : CRTC_TEST_PATTERN_CONTROL,
785 : CRTC_TEST_PATTERN_EN);
786 :
787 0 : set_reg_field_value(
788 : value,
789 : mode,
790 : CRTC_TEST_PATTERN_CONTROL,
791 : CRTC_TEST_PATTERN_MODE);
792 :
793 0 : set_reg_field_value(
794 : value,
795 : dyn_range,
796 : CRTC_TEST_PATTERN_CONTROL,
797 : CRTC_TEST_PATTERN_DYNAMIC_RANGE);
798 0 : set_reg_field_value(
799 : value,
800 : bit_depth,
801 : CRTC_TEST_PATTERN_CONTROL,
802 : CRTC_TEST_PATTERN_COLOR_FORMAT);
803 0 : dm_write_reg(ctx, addr, value);
804 : }
805 0 : break;
806 :
807 : case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS:
808 : case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS:
809 : {
810 0 : mode = (test_pattern ==
811 : CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ?
812 0 : TEST_PATTERN_MODE_VERTICALBARS :
813 : TEST_PATTERN_MODE_HORIZONTALBARS);
814 :
815 : switch (bit_depth) {
816 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
817 : dst_bpc = 6;
818 : break;
819 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
820 : dst_bpc = 8;
821 : break;
822 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
823 : dst_bpc = 10;
824 : break;
825 : default:
826 : dst_bpc = 8;
827 : break;
828 : }
829 :
830 : /* adjust color to the required colorFormat */
831 0 : for (index = 0; index < 6; index++) {
832 : /* dst = 2^dstBpc * src / 2^srcBpc = src >>
833 : * (srcBpc - dstBpc);
834 : */
835 0 : dst_color[index] =
836 0 : src_color[index] >> (src_bpc - dst_bpc);
837 : /* CRTC_TEST_PATTERN_DATA has 16 bits,
838 : * lowest 6 are hardwired to ZERO
839 : * color bits should be left aligned aligned to MSB
840 : * XXXXXXXXXX000000 for 10 bit,
841 : * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6
842 : */
843 0 : dst_color[index] <<= (16 - dst_bpc);
844 : }
845 :
846 0 : value = 0;
847 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_PARAMETERS);
848 0 : dm_write_reg(ctx, addr, value);
849 :
850 : /* We have to write the mask before data, similar to pipeline.
851 : * For example, for 8 bpc, if we want RGB0 to be magenta,
852 : * and RGB1 to be cyan,
853 : * we need to make 7 writes:
854 : * MASK DATA
855 : * 000001 00000000 00000000 set mask to R0
856 : * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0
857 : * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0
858 : * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1
859 : * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1
860 : * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1
861 : * 100000 11111111 00000000 B1 255, 0xFF00
862 : *
863 : * we will make a loop of 6 in which we prepare the mask,
864 : * then write, then prepare the color for next write.
865 : * first iteration will write mask only,
866 : * but each next iteration color prepared in
867 : * previous iteration will be written within new mask,
868 : * the last component will written separately,
869 : * mask is not changing between 6th and 7th write
870 : * and color will be prepared by last iteration
871 : */
872 :
873 : /* write color, color values mask in CRTC_TEST_PATTERN_MASK
874 : * is B1, G1, R1, B0, G0, R0
875 : */
876 0 : value = 0;
877 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_COLOR);
878 0 : for (index = 0; index < 6; index++) {
879 : /* prepare color mask, first write PATTERN_DATA
880 : * will have all zeros
881 : */
882 0 : set_reg_field_value(
883 : value,
884 : (1 << index),
885 : CRTC_TEST_PATTERN_COLOR,
886 : CRTC_TEST_PATTERN_MASK);
887 : /* write color component */
888 0 : dm_write_reg(ctx, addr, value);
889 : /* prepare next color component,
890 : * will be written in the next iteration
891 : */
892 0 : set_reg_field_value(
893 : value,
894 : dst_color[index],
895 : CRTC_TEST_PATTERN_COLOR,
896 : CRTC_TEST_PATTERN_DATA);
897 : }
898 : /* write last color component,
899 : * it's been already prepared in the loop
900 : */
901 0 : dm_write_reg(ctx, addr, value);
902 :
903 : /* enable test pattern */
904 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_CONTROL);
905 0 : value = 0;
906 :
907 0 : set_reg_field_value(
908 : value,
909 : 1,
910 : CRTC_TEST_PATTERN_CONTROL,
911 : CRTC_TEST_PATTERN_EN);
912 :
913 0 : set_reg_field_value(
914 : value,
915 : mode,
916 : CRTC_TEST_PATTERN_CONTROL,
917 : CRTC_TEST_PATTERN_MODE);
918 :
919 0 : set_reg_field_value(
920 : value,
921 : 0,
922 : CRTC_TEST_PATTERN_CONTROL,
923 : CRTC_TEST_PATTERN_DYNAMIC_RANGE);
924 :
925 0 : set_reg_field_value(
926 : value,
927 : bit_depth,
928 : CRTC_TEST_PATTERN_CONTROL,
929 : CRTC_TEST_PATTERN_COLOR_FORMAT);
930 :
931 0 : dm_write_reg(ctx, addr, value);
932 : }
933 0 : break;
934 :
935 : case CONTROLLER_DP_TEST_PATTERN_COLORRAMP:
936 : {
937 0 : mode = (bit_depth ==
938 : TEST_PATTERN_COLOR_FORMAT_BPC_10 ?
939 0 : 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 0 : inc_base = (src_bpc - dst_bpc);
962 :
963 0 : value = 0;
964 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_PARAMETERS);
965 :
966 0 : switch (bit_depth) {
967 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
968 : {
969 0 : set_reg_field_value(
970 : value,
971 : inc_base,
972 : CRTC_TEST_PATTERN_PARAMETERS,
973 : CRTC_TEST_PATTERN_INC0);
974 0 : set_reg_field_value(
975 : value,
976 : 0,
977 : CRTC_TEST_PATTERN_PARAMETERS,
978 : CRTC_TEST_PATTERN_INC1);
979 0 : set_reg_field_value(
980 : value,
981 : 6,
982 : CRTC_TEST_PATTERN_PARAMETERS,
983 : CRTC_TEST_PATTERN_HRES);
984 0 : set_reg_field_value(
985 : value,
986 : 6,
987 : CRTC_TEST_PATTERN_PARAMETERS,
988 : CRTC_TEST_PATTERN_VRES);
989 0 : set_reg_field_value(
990 : value,
991 : 0,
992 : CRTC_TEST_PATTERN_PARAMETERS,
993 : CRTC_TEST_PATTERN_RAMP0_OFFSET);
994 : }
995 0 : break;
996 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
997 : {
998 0 : set_reg_field_value(
999 : value,
1000 : inc_base,
1001 : CRTC_TEST_PATTERN_PARAMETERS,
1002 : CRTC_TEST_PATTERN_INC0);
1003 0 : set_reg_field_value(
1004 : value,
1005 : 0,
1006 : CRTC_TEST_PATTERN_PARAMETERS,
1007 : CRTC_TEST_PATTERN_INC1);
1008 0 : set_reg_field_value(
1009 : value,
1010 : 8,
1011 : CRTC_TEST_PATTERN_PARAMETERS,
1012 : CRTC_TEST_PATTERN_HRES);
1013 0 : set_reg_field_value(
1014 : value,
1015 : 6,
1016 : CRTC_TEST_PATTERN_PARAMETERS,
1017 : CRTC_TEST_PATTERN_VRES);
1018 0 : set_reg_field_value(
1019 : value,
1020 : 0,
1021 : CRTC_TEST_PATTERN_PARAMETERS,
1022 : CRTC_TEST_PATTERN_RAMP0_OFFSET);
1023 : }
1024 0 : break;
1025 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
1026 : {
1027 0 : set_reg_field_value(
1028 : value,
1029 : inc_base,
1030 : CRTC_TEST_PATTERN_PARAMETERS,
1031 : CRTC_TEST_PATTERN_INC0);
1032 0 : set_reg_field_value(
1033 : value,
1034 : inc_base + 2,
1035 : CRTC_TEST_PATTERN_PARAMETERS,
1036 : CRTC_TEST_PATTERN_INC1);
1037 0 : set_reg_field_value(
1038 : value,
1039 : 8,
1040 : CRTC_TEST_PATTERN_PARAMETERS,
1041 : CRTC_TEST_PATTERN_HRES);
1042 0 : set_reg_field_value(
1043 : value,
1044 : 5,
1045 : CRTC_TEST_PATTERN_PARAMETERS,
1046 : CRTC_TEST_PATTERN_VRES);
1047 0 : set_reg_field_value(
1048 : value,
1049 : 384 << 6,
1050 : CRTC_TEST_PATTERN_PARAMETERS,
1051 : CRTC_TEST_PATTERN_RAMP0_OFFSET);
1052 : }
1053 0 : break;
1054 : default:
1055 : break;
1056 : }
1057 0 : dm_write_reg(ctx, addr, value);
1058 :
1059 0 : value = 0;
1060 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_COLOR);
1061 0 : dm_write_reg(ctx, addr, value);
1062 :
1063 : /* enable test pattern */
1064 0 : addr = CRTC_REG(mmCRTC_TEST_PATTERN_CONTROL);
1065 0 : value = 0;
1066 :
1067 0 : set_reg_field_value(
1068 : value,
1069 : 1,
1070 : CRTC_TEST_PATTERN_CONTROL,
1071 : CRTC_TEST_PATTERN_EN);
1072 :
1073 0 : set_reg_field_value(
1074 : value,
1075 : mode,
1076 : CRTC_TEST_PATTERN_CONTROL,
1077 : CRTC_TEST_PATTERN_MODE);
1078 :
1079 0 : set_reg_field_value(
1080 : value,
1081 : 0,
1082 : CRTC_TEST_PATTERN_CONTROL,
1083 : CRTC_TEST_PATTERN_DYNAMIC_RANGE);
1084 : /* add color depth translation here */
1085 0 : set_reg_field_value(
1086 : value,
1087 : bit_depth,
1088 : CRTC_TEST_PATTERN_CONTROL,
1089 : CRTC_TEST_PATTERN_COLOR_FORMAT);
1090 :
1091 0 : dm_write_reg(ctx, addr, value);
1092 : }
1093 0 : break;
1094 : case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE:
1095 : {
1096 0 : value = 0;
1097 0 : dm_write_reg(ctx, CRTC_REG(mmCRTC_TEST_PATTERN_CONTROL), value);
1098 0 : dm_write_reg(ctx, CRTC_REG(mmCRTC_TEST_PATTERN_COLOR), value);
1099 0 : dm_write_reg(ctx, CRTC_REG(mmCRTC_TEST_PATTERN_PARAMETERS),
1100 : value);
1101 : }
1102 0 : break;
1103 : default:
1104 : break;
1105 : }
1106 0 : }
1107 :
1108 : /*
1109 : * dce110_timing_generator_validate_timing
1110 : * The timing generators support a maximum display size of is 8192 x 8192 pixels,
1111 : * including both active display and blanking periods. Check H Total and V Total.
1112 : */
1113 0 : bool dce110_timing_generator_validate_timing(
1114 : struct timing_generator *tg,
1115 : const struct dc_crtc_timing *timing,
1116 : enum signal_type signal)
1117 : {
1118 : uint32_t h_blank;
1119 : uint32_t h_back_porch, hsync_offset, h_sync_start;
1120 :
1121 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1122 :
1123 0 : ASSERT(timing != NULL);
1124 :
1125 0 : if (!timing)
1126 : return false;
1127 :
1128 0 : hsync_offset = timing->h_border_right + timing->h_front_porch;
1129 0 : h_sync_start = timing->h_addressable + hsync_offset;
1130 :
1131 : /* Currently we don't support 3D, so block all 3D timings */
1132 0 : if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE)
1133 : return false;
1134 :
1135 : /* Temporarily blocking interlacing mode until it's supported */
1136 0 : if (timing->flags.INTERLACE == 1)
1137 : return false;
1138 :
1139 : /* Check maximum number of pixels supported by Timing Generator
1140 : * (Currently will never fail, in order to fail needs display which
1141 : * needs more than 8192 horizontal and
1142 : * more than 8192 vertical total pixels)
1143 : */
1144 0 : if (timing->h_total > tg110->max_h_total ||
1145 0 : timing->v_total > tg110->max_v_total)
1146 : return false;
1147 :
1148 0 : h_blank = (timing->h_total - timing->h_addressable -
1149 : timing->h_border_right -
1150 0 : timing->h_border_left);
1151 :
1152 0 : if (h_blank < tg110->min_h_blank)
1153 : return false;
1154 :
1155 0 : if (timing->h_front_porch < tg110->min_h_front_porch)
1156 : return false;
1157 :
1158 0 : h_back_porch = h_blank - (h_sync_start -
1159 0 : timing->h_addressable -
1160 0 : timing->h_border_right -
1161 0 : timing->h_sync_width);
1162 :
1163 0 : if (h_back_porch < tg110->min_h_back_porch)
1164 : return false;
1165 :
1166 0 : return true;
1167 : }
1168 :
1169 : /*
1170 : * Wait till we are at the beginning of VBlank.
1171 : */
1172 0 : void dce110_timing_generator_wait_for_vblank(struct timing_generator *tg)
1173 : {
1174 : /* We want to catch beginning of VBlank here, so if the first try are
1175 : * in VBlank, we might be very close to Active, in this case wait for
1176 : * another frame
1177 : */
1178 0 : while (dce110_timing_generator_is_in_vertical_blank(tg)) {
1179 0 : if (!dce110_timing_generator_is_counter_moving(tg)) {
1180 : /* error - no point to wait if counter is not moving */
1181 : break;
1182 : }
1183 : }
1184 :
1185 0 : while (!dce110_timing_generator_is_in_vertical_blank(tg)) {
1186 0 : if (!dce110_timing_generator_is_counter_moving(tg)) {
1187 : /* error - no point to wait if counter is not moving */
1188 : break;
1189 : }
1190 : }
1191 0 : }
1192 :
1193 : /*
1194 : * Wait till we are in VActive (anywhere in VActive)
1195 : */
1196 0 : void dce110_timing_generator_wait_for_vactive(struct timing_generator *tg)
1197 : {
1198 0 : while (dce110_timing_generator_is_in_vertical_blank(tg)) {
1199 0 : if (!dce110_timing_generator_is_counter_moving(tg)) {
1200 : /* error - no point to wait if counter is not moving */
1201 : break;
1202 : }
1203 : }
1204 0 : }
1205 :
1206 : /*
1207 : *****************************************************************************
1208 : * Function: dce110_timing_generator_setup_global_swap_lock
1209 : *
1210 : * @brief
1211 : * Setups Global Swap Lock group for current pipe
1212 : * Pipe can join or leave GSL group, become a TimingServer or TimingClient
1213 : *
1214 : * @param [in] gsl_params: setup data
1215 : *****************************************************************************
1216 : */
1217 0 : void dce110_timing_generator_setup_global_swap_lock(
1218 : struct timing_generator *tg,
1219 : const struct dcp_gsl_params *gsl_params)
1220 : {
1221 : uint32_t value;
1222 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1223 0 : uint32_t address = DCP_REG(mmDCP_GSL_CONTROL);
1224 0 : uint32_t check_point = FLIP_READY_BACK_LOOKUP;
1225 :
1226 0 : value = dm_read_reg(tg->ctx, address);
1227 :
1228 : /* This pipe will belong to GSL Group zero. */
1229 0 : set_reg_field_value(value,
1230 : 1,
1231 : DCP_GSL_CONTROL,
1232 : DCP_GSL0_EN);
1233 :
1234 0 : set_reg_field_value(value,
1235 : gsl_params->gsl_master == tg->inst,
1236 : DCP_GSL_CONTROL,
1237 : DCP_GSL_MASTER_EN);
1238 :
1239 0 : set_reg_field_value(value,
1240 : HFLIP_READY_DELAY,
1241 : DCP_GSL_CONTROL,
1242 : DCP_GSL_HSYNC_FLIP_FORCE_DELAY);
1243 :
1244 : /* Keep signal low (pending high) during 6 lines.
1245 : * Also defines minimum interval before re-checking signal. */
1246 0 : set_reg_field_value(value,
1247 : HFLIP_CHECK_DELAY,
1248 : DCP_GSL_CONTROL,
1249 : DCP_GSL_HSYNC_FLIP_CHECK_DELAY);
1250 :
1251 0 : dm_write_reg(tg->ctx, CRTC_REG(mmDCP_GSL_CONTROL), value);
1252 0 : value = 0;
1253 :
1254 0 : set_reg_field_value(value,
1255 : gsl_params->gsl_master,
1256 : DCIO_GSL0_CNTL,
1257 : DCIO_GSL0_VSYNC_SEL);
1258 :
1259 0 : set_reg_field_value(value,
1260 : 0,
1261 : DCIO_GSL0_CNTL,
1262 : DCIO_GSL0_TIMING_SYNC_SEL);
1263 :
1264 0 : set_reg_field_value(value,
1265 : 0,
1266 : DCIO_GSL0_CNTL,
1267 : DCIO_GSL0_GLOBAL_UNLOCK_SEL);
1268 :
1269 0 : dm_write_reg(tg->ctx, CRTC_REG(mmDCIO_GSL0_CNTL), value);
1270 :
1271 :
1272 : {
1273 : uint32_t value_crtc_vtotal;
1274 :
1275 0 : value_crtc_vtotal = dm_read_reg(tg->ctx,
1276 : CRTC_REG(mmCRTC_V_TOTAL));
1277 :
1278 0 : set_reg_field_value(value,
1279 : 0,/* DCP_GSL_PURPOSE_SURFACE_FLIP */
1280 : DCP_GSL_CONTROL,
1281 : DCP_GSL_SYNC_SOURCE);
1282 :
1283 : /* Checkpoint relative to end of frame */
1284 0 : check_point = get_reg_field_value(value_crtc_vtotal,
1285 : CRTC_V_TOTAL,
1286 : CRTC_V_TOTAL);
1287 :
1288 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_GSL_WINDOW), 0);
1289 : }
1290 :
1291 0 : set_reg_field_value(value,
1292 : 1,
1293 : DCP_GSL_CONTROL,
1294 : DCP_GSL_DELAY_SURFACE_UPDATE_PENDING);
1295 :
1296 0 : dm_write_reg(tg->ctx, address, value);
1297 :
1298 : /********************************************************************/
1299 0 : address = CRTC_REG(mmCRTC_GSL_CONTROL);
1300 :
1301 0 : value = dm_read_reg(tg->ctx, address);
1302 0 : set_reg_field_value(value,
1303 : check_point - FLIP_READY_BACK_LOOKUP,
1304 : CRTC_GSL_CONTROL,
1305 : CRTC_GSL_CHECK_LINE_NUM);
1306 :
1307 0 : set_reg_field_value(value,
1308 : VFLIP_READY_DELAY,
1309 : CRTC_GSL_CONTROL,
1310 : CRTC_GSL_FORCE_DELAY);
1311 :
1312 0 : dm_write_reg(tg->ctx, address, value);
1313 0 : }
1314 :
1315 0 : void dce110_timing_generator_tear_down_global_swap_lock(
1316 : struct timing_generator *tg)
1317 : {
1318 : /* Clear all the register writes done by
1319 : * dce110_timing_generator_setup_global_swap_lock
1320 : */
1321 :
1322 : uint32_t value;
1323 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1324 0 : uint32_t address = DCP_REG(mmDCP_GSL_CONTROL);
1325 :
1326 0 : value = 0;
1327 :
1328 : /* This pipe will belong to GSL Group zero. */
1329 : /* Settig HW default values from reg specs */
1330 0 : set_reg_field_value(value,
1331 : 0,
1332 : DCP_GSL_CONTROL,
1333 : DCP_GSL0_EN);
1334 :
1335 0 : set_reg_field_value(value,
1336 : 0,
1337 : DCP_GSL_CONTROL,
1338 : DCP_GSL_MASTER_EN);
1339 :
1340 0 : set_reg_field_value(value,
1341 : 0x2,
1342 : DCP_GSL_CONTROL,
1343 : DCP_GSL_HSYNC_FLIP_FORCE_DELAY);
1344 :
1345 0 : set_reg_field_value(value,
1346 : 0x6,
1347 : DCP_GSL_CONTROL,
1348 : DCP_GSL_HSYNC_FLIP_CHECK_DELAY);
1349 :
1350 : /* Restore DCP_GSL_PURPOSE_SURFACE_FLIP */
1351 : {
1352 0 : dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_V_TOTAL));
1353 :
1354 0 : set_reg_field_value(value,
1355 : 0,
1356 : DCP_GSL_CONTROL,
1357 : DCP_GSL_SYNC_SOURCE);
1358 : }
1359 :
1360 0 : set_reg_field_value(value,
1361 : 0,
1362 : DCP_GSL_CONTROL,
1363 : DCP_GSL_DELAY_SURFACE_UPDATE_PENDING);
1364 :
1365 0 : dm_write_reg(tg->ctx, address, value);
1366 :
1367 : /********************************************************************/
1368 0 : address = CRTC_REG(mmCRTC_GSL_CONTROL);
1369 :
1370 0 : value = 0;
1371 0 : set_reg_field_value(value,
1372 : 0,
1373 : CRTC_GSL_CONTROL,
1374 : CRTC_GSL_CHECK_LINE_NUM);
1375 :
1376 0 : set_reg_field_value(value,
1377 : 0x2,
1378 : CRTC_GSL_CONTROL,
1379 : CRTC_GSL_FORCE_DELAY);
1380 :
1381 0 : dm_write_reg(tg->ctx, address, value);
1382 0 : }
1383 : /*
1384 : *****************************************************************************
1385 : * Function: is_counter_moving
1386 : *
1387 : * @brief
1388 : * check if the timing generator is currently going
1389 : *
1390 : * @return
1391 : * true if currently going, false if currently paused or stopped.
1392 : *
1393 : *****************************************************************************
1394 : */
1395 0 : bool dce110_timing_generator_is_counter_moving(struct timing_generator *tg)
1396 : {
1397 : struct crtc_position position1, position2;
1398 :
1399 0 : tg->funcs->get_position(tg, &position1);
1400 0 : tg->funcs->get_position(tg, &position2);
1401 :
1402 0 : if (position1.horizontal_count == position2.horizontal_count &&
1403 0 : position1.vertical_count == position2.vertical_count)
1404 : return false;
1405 : else
1406 0 : return true;
1407 : }
1408 :
1409 0 : void dce110_timing_generator_enable_advanced_request(
1410 : struct timing_generator *tg,
1411 : bool enable,
1412 : const struct dc_crtc_timing *timing)
1413 : {
1414 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1415 0 : uint32_t addr = CRTC_REG(mmCRTC_START_LINE_CONTROL);
1416 0 : uint32_t value = dm_read_reg(tg->ctx, addr);
1417 :
1418 0 : if (enable) {
1419 0 : set_reg_field_value(
1420 : value,
1421 : 0,
1422 : CRTC_START_LINE_CONTROL,
1423 : CRTC_LEGACY_REQUESTOR_EN);
1424 : } else {
1425 0 : set_reg_field_value(
1426 : value,
1427 : 1,
1428 : CRTC_START_LINE_CONTROL,
1429 : CRTC_LEGACY_REQUESTOR_EN);
1430 : }
1431 :
1432 0 : if ((timing->v_sync_width + timing->v_front_porch) <= 3) {
1433 0 : set_reg_field_value(
1434 : value,
1435 : 3,
1436 : CRTC_START_LINE_CONTROL,
1437 : CRTC_ADVANCED_START_LINE_POSITION);
1438 0 : set_reg_field_value(
1439 : value,
1440 : 0,
1441 : CRTC_START_LINE_CONTROL,
1442 : CRTC_PREFETCH_EN);
1443 : } else {
1444 0 : set_reg_field_value(
1445 : value,
1446 : 4,
1447 : CRTC_START_LINE_CONTROL,
1448 : CRTC_ADVANCED_START_LINE_POSITION);
1449 0 : set_reg_field_value(
1450 : value,
1451 : 1,
1452 : CRTC_START_LINE_CONTROL,
1453 : CRTC_PREFETCH_EN);
1454 : }
1455 :
1456 0 : set_reg_field_value(
1457 : value,
1458 : 1,
1459 : CRTC_START_LINE_CONTROL,
1460 : CRTC_PROGRESSIVE_START_LINE_EARLY);
1461 :
1462 0 : set_reg_field_value(
1463 : value,
1464 : 1,
1465 : CRTC_START_LINE_CONTROL,
1466 : CRTC_INTERLACE_START_LINE_EARLY);
1467 :
1468 0 : dm_write_reg(tg->ctx, addr, value);
1469 0 : }
1470 :
1471 : /*TODO: Figure out if we need this function. */
1472 0 : void dce110_timing_generator_set_lock_master(struct timing_generator *tg,
1473 : bool lock)
1474 : {
1475 0 : struct dc_context *ctx = tg->ctx;
1476 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1477 0 : uint32_t addr = CRTC_REG(mmCRTC_MASTER_UPDATE_LOCK);
1478 0 : uint32_t value = dm_read_reg(ctx, addr);
1479 :
1480 0 : set_reg_field_value(
1481 : value,
1482 : lock ? 1 : 0,
1483 : CRTC_MASTER_UPDATE_LOCK,
1484 : MASTER_UPDATE_LOCK);
1485 :
1486 0 : dm_write_reg(ctx, addr, value);
1487 0 : }
1488 :
1489 0 : void dce110_timing_generator_enable_reset_trigger(
1490 : struct timing_generator *tg,
1491 : int source_tg_inst)
1492 : {
1493 : uint32_t value;
1494 0 : uint32_t rising_edge = 0;
1495 0 : uint32_t falling_edge = 0;
1496 0 : enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO;
1497 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1498 :
1499 : /* Setup trigger edge */
1500 : {
1501 0 : uint32_t pol_value = dm_read_reg(tg->ctx,
1502 : CRTC_REG(mmCRTC_V_SYNC_A_CNTL));
1503 :
1504 : /* Register spec has reversed definition:
1505 : * 0 for positive, 1 for negative */
1506 0 : if (get_reg_field_value(pol_value,
1507 : CRTC_V_SYNC_A_CNTL,
1508 : CRTC_V_SYNC_A_POL) == 0) {
1509 : rising_edge = 1;
1510 : } else {
1511 0 : falling_edge = 1;
1512 : }
1513 : }
1514 :
1515 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL));
1516 :
1517 0 : trig_src_select = TRIGGER_SOURCE_SELECT_GSL_GROUP0;
1518 :
1519 0 : set_reg_field_value(value,
1520 : trig_src_select,
1521 : CRTC_TRIGB_CNTL,
1522 : CRTC_TRIGB_SOURCE_SELECT);
1523 :
1524 0 : set_reg_field_value(value,
1525 : TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
1526 : CRTC_TRIGB_CNTL,
1527 : CRTC_TRIGB_POLARITY_SELECT);
1528 :
1529 0 : set_reg_field_value(value,
1530 : rising_edge,
1531 : CRTC_TRIGB_CNTL,
1532 : CRTC_TRIGB_RISING_EDGE_DETECT_CNTL);
1533 :
1534 0 : set_reg_field_value(value,
1535 : falling_edge,
1536 : CRTC_TRIGB_CNTL,
1537 : CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL);
1538 :
1539 0 : set_reg_field_value(value,
1540 : 0, /* send every signal */
1541 : CRTC_TRIGB_CNTL,
1542 : CRTC_TRIGB_FREQUENCY_SELECT);
1543 :
1544 0 : set_reg_field_value(value,
1545 : 0, /* no delay */
1546 : CRTC_TRIGB_CNTL,
1547 : CRTC_TRIGB_DELAY);
1548 :
1549 0 : set_reg_field_value(value,
1550 : 1, /* clear trigger status */
1551 : CRTC_TRIGB_CNTL,
1552 : CRTC_TRIGB_CLEAR);
1553 :
1554 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL), value);
1555 :
1556 : /**************************************************************/
1557 :
1558 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
1559 :
1560 0 : set_reg_field_value(value,
1561 : 2, /* force H count to H_TOTAL and V count to V_TOTAL */
1562 : CRTC_FORCE_COUNT_NOW_CNTL,
1563 : CRTC_FORCE_COUNT_NOW_MODE);
1564 :
1565 0 : set_reg_field_value(value,
1566 : 1, /* TriggerB - we never use TriggerA */
1567 : CRTC_FORCE_COUNT_NOW_CNTL,
1568 : CRTC_FORCE_COUNT_NOW_TRIG_SEL);
1569 :
1570 0 : set_reg_field_value(value,
1571 : 1, /* clear trigger status */
1572 : CRTC_FORCE_COUNT_NOW_CNTL,
1573 : CRTC_FORCE_COUNT_NOW_CLEAR);
1574 :
1575 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
1576 0 : }
1577 :
1578 0 : void dce110_timing_generator_enable_crtc_reset(
1579 : struct timing_generator *tg,
1580 : int source_tg_inst,
1581 : struct crtc_trigger_info *crtc_tp)
1582 : {
1583 0 : uint32_t value = 0;
1584 0 : uint32_t rising_edge = 0;
1585 0 : uint32_t falling_edge = 0;
1586 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1587 :
1588 : /* Setup trigger edge */
1589 0 : switch (crtc_tp->event) {
1590 : case CRTC_EVENT_VSYNC_RISING:
1591 0 : rising_edge = 1;
1592 0 : break;
1593 :
1594 : case CRTC_EVENT_VSYNC_FALLING:
1595 0 : falling_edge = 1;
1596 0 : break;
1597 : }
1598 :
1599 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL));
1600 :
1601 0 : set_reg_field_value(value,
1602 : source_tg_inst,
1603 : CRTC_TRIGB_CNTL,
1604 : CRTC_TRIGB_SOURCE_SELECT);
1605 :
1606 0 : set_reg_field_value(value,
1607 : TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
1608 : CRTC_TRIGB_CNTL,
1609 : CRTC_TRIGB_POLARITY_SELECT);
1610 :
1611 0 : set_reg_field_value(value,
1612 : rising_edge,
1613 : CRTC_TRIGB_CNTL,
1614 : CRTC_TRIGB_RISING_EDGE_DETECT_CNTL);
1615 :
1616 0 : set_reg_field_value(value,
1617 : falling_edge,
1618 : CRTC_TRIGB_CNTL,
1619 : CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL);
1620 :
1621 0 : set_reg_field_value(value,
1622 : 1, /* clear trigger status */
1623 : CRTC_TRIGB_CNTL,
1624 : CRTC_TRIGB_CLEAR);
1625 :
1626 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL), value);
1627 :
1628 : /**************************************************************/
1629 :
1630 0 : switch (crtc_tp->delay) {
1631 : case TRIGGER_DELAY_NEXT_LINE:
1632 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
1633 :
1634 0 : set_reg_field_value(value,
1635 : 0, /* force H count to H_TOTAL and V count to V_TOTAL */
1636 : CRTC_FORCE_COUNT_NOW_CNTL,
1637 : CRTC_FORCE_COUNT_NOW_MODE);
1638 :
1639 0 : set_reg_field_value(value,
1640 : 0, /* TriggerB - we never use TriggerA */
1641 : CRTC_FORCE_COUNT_NOW_CNTL,
1642 : CRTC_FORCE_COUNT_NOW_TRIG_SEL);
1643 :
1644 0 : set_reg_field_value(value,
1645 : 1, /* clear trigger status */
1646 : CRTC_FORCE_COUNT_NOW_CNTL,
1647 : CRTC_FORCE_COUNT_NOW_CLEAR);
1648 :
1649 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
1650 :
1651 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
1652 :
1653 0 : set_reg_field_value(value,
1654 : 1,
1655 : CRTC_VERT_SYNC_CONTROL,
1656 : CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR);
1657 :
1658 0 : set_reg_field_value(value,
1659 : 2,
1660 : CRTC_VERT_SYNC_CONTROL,
1661 : CRTC_AUTO_FORCE_VSYNC_MODE);
1662 :
1663 0 : break;
1664 :
1665 : case TRIGGER_DELAY_NEXT_PIXEL:
1666 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
1667 :
1668 0 : set_reg_field_value(value,
1669 : 1,
1670 : CRTC_VERT_SYNC_CONTROL,
1671 : CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR);
1672 :
1673 0 : set_reg_field_value(value,
1674 : 0,
1675 : CRTC_VERT_SYNC_CONTROL,
1676 : CRTC_AUTO_FORCE_VSYNC_MODE);
1677 :
1678 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL), value);
1679 :
1680 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
1681 :
1682 0 : set_reg_field_value(value,
1683 : 2, /* force H count to H_TOTAL and V count to V_TOTAL */
1684 : CRTC_FORCE_COUNT_NOW_CNTL,
1685 : CRTC_FORCE_COUNT_NOW_MODE);
1686 :
1687 0 : set_reg_field_value(value,
1688 : 1, /* TriggerB - we never use TriggerA */
1689 : CRTC_FORCE_COUNT_NOW_CNTL,
1690 : CRTC_FORCE_COUNT_NOW_TRIG_SEL);
1691 :
1692 0 : set_reg_field_value(value,
1693 : 1, /* clear trigger status */
1694 : CRTC_FORCE_COUNT_NOW_CNTL,
1695 : CRTC_FORCE_COUNT_NOW_CLEAR);
1696 :
1697 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
1698 0 : break;
1699 : }
1700 :
1701 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_MODE));
1702 :
1703 0 : set_reg_field_value(value,
1704 : 2,
1705 : CRTC_MASTER_UPDATE_MODE,
1706 : MASTER_UPDATE_MODE);
1707 :
1708 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_MODE), value);
1709 0 : }
1710 0 : void dce110_timing_generator_disable_reset_trigger(
1711 : struct timing_generator *tg)
1712 : {
1713 : uint32_t value;
1714 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1715 :
1716 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
1717 :
1718 0 : set_reg_field_value(value,
1719 : 0, /* force counter now mode is disabled */
1720 : CRTC_FORCE_COUNT_NOW_CNTL,
1721 : CRTC_FORCE_COUNT_NOW_MODE);
1722 :
1723 0 : set_reg_field_value(value,
1724 : 1, /* clear trigger status */
1725 : CRTC_FORCE_COUNT_NOW_CNTL,
1726 : CRTC_FORCE_COUNT_NOW_CLEAR);
1727 :
1728 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value);
1729 :
1730 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
1731 :
1732 0 : set_reg_field_value(value,
1733 : 1,
1734 : CRTC_VERT_SYNC_CONTROL,
1735 : CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR);
1736 :
1737 0 : set_reg_field_value(value,
1738 : 0,
1739 : CRTC_VERT_SYNC_CONTROL,
1740 : CRTC_AUTO_FORCE_VSYNC_MODE);
1741 :
1742 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL), value);
1743 :
1744 : /********************************************************************/
1745 0 : value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL));
1746 :
1747 0 : set_reg_field_value(value,
1748 : TRIGGER_SOURCE_SELECT_LOGIC_ZERO,
1749 : CRTC_TRIGB_CNTL,
1750 : CRTC_TRIGB_SOURCE_SELECT);
1751 :
1752 0 : set_reg_field_value(value,
1753 : TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
1754 : CRTC_TRIGB_CNTL,
1755 : CRTC_TRIGB_POLARITY_SELECT);
1756 :
1757 0 : set_reg_field_value(value,
1758 : 1, /* clear trigger status */
1759 : CRTC_TRIGB_CNTL,
1760 : CRTC_TRIGB_CLEAR);
1761 :
1762 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL), value);
1763 0 : }
1764 :
1765 : /*
1766 : *****************************************************************************
1767 : * @brief
1768 : * Checks whether CRTC triggered reset occurred
1769 : *
1770 : * @return
1771 : * true if triggered reset occurred, false otherwise
1772 : *****************************************************************************
1773 : */
1774 0 : bool dce110_timing_generator_did_triggered_reset_occur(
1775 : struct timing_generator *tg)
1776 : {
1777 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1778 0 : uint32_t value = dm_read_reg(tg->ctx,
1779 : CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL));
1780 0 : uint32_t value1 = dm_read_reg(tg->ctx,
1781 : CRTC_REG(mmCRTC_VERT_SYNC_CONTROL));
1782 0 : bool force = get_reg_field_value(value,
1783 : CRTC_FORCE_COUNT_NOW_CNTL,
1784 : CRTC_FORCE_COUNT_NOW_OCCURRED) != 0;
1785 0 : bool vert_sync = get_reg_field_value(value1,
1786 : CRTC_VERT_SYNC_CONTROL,
1787 : CRTC_FORCE_VSYNC_NEXT_LINE_OCCURRED) != 0;
1788 :
1789 0 : return (force || vert_sync);
1790 : }
1791 :
1792 : /*
1793 : * dce110_timing_generator_disable_vga
1794 : * Turn OFF VGA Mode and Timing - DxVGA_CONTROL
1795 : * VGA Mode and VGA Timing is used by VBIOS on CRT Monitors;
1796 : */
1797 0 : void dce110_timing_generator_disable_vga(
1798 : struct timing_generator *tg)
1799 : {
1800 0 : uint32_t addr = 0;
1801 0 : uint32_t value = 0;
1802 :
1803 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1804 :
1805 0 : switch (tg110->controller_id) {
1806 : case CONTROLLER_ID_D0:
1807 : addr = mmD1VGA_CONTROL;
1808 : break;
1809 : case CONTROLLER_ID_D1:
1810 : addr = mmD2VGA_CONTROL;
1811 : break;
1812 : case CONTROLLER_ID_D2:
1813 : addr = mmD3VGA_CONTROL;
1814 : break;
1815 : case CONTROLLER_ID_D3:
1816 : addr = mmD4VGA_CONTROL;
1817 : break;
1818 : case CONTROLLER_ID_D4:
1819 : addr = mmD5VGA_CONTROL;
1820 : break;
1821 : case CONTROLLER_ID_D5:
1822 : addr = mmD6VGA_CONTROL;
1823 : break;
1824 : default:
1825 : break;
1826 : }
1827 0 : value = dm_read_reg(tg->ctx, addr);
1828 :
1829 0 : set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_MODE_ENABLE);
1830 0 : set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_TIMING_SELECT);
1831 0 : set_reg_field_value(
1832 : value, 0, D1VGA_CONTROL, D1VGA_SYNC_POLARITY_SELECT);
1833 0 : set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_OVERSCAN_COLOR_EN);
1834 :
1835 0 : dm_write_reg(tg->ctx, addr, value);
1836 0 : }
1837 :
1838 : /*
1839 : * set_overscan_color_black
1840 : *
1841 : * @param :black_color is one of the color space
1842 : * :this routine will set overscan black color according to the color space.
1843 : * @return none
1844 : */
1845 0 : void dce110_timing_generator_set_overscan_color_black(
1846 : struct timing_generator *tg,
1847 : const struct tg_color *color)
1848 : {
1849 0 : struct dc_context *ctx = tg->ctx;
1850 : uint32_t addr;
1851 0 : uint32_t value = 0;
1852 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1853 :
1854 0 : set_reg_field_value(
1855 : value,
1856 : color->color_b_cb,
1857 : CRTC_OVERSCAN_COLOR,
1858 : CRTC_OVERSCAN_COLOR_BLUE);
1859 :
1860 0 : set_reg_field_value(
1861 : value,
1862 : color->color_r_cr,
1863 : CRTC_OVERSCAN_COLOR,
1864 : CRTC_OVERSCAN_COLOR_RED);
1865 :
1866 0 : set_reg_field_value(
1867 : value,
1868 : color->color_g_y,
1869 : CRTC_OVERSCAN_COLOR,
1870 : CRTC_OVERSCAN_COLOR_GREEN);
1871 :
1872 0 : addr = CRTC_REG(mmCRTC_OVERSCAN_COLOR);
1873 0 : dm_write_reg(ctx, addr, value);
1874 0 : addr = CRTC_REG(mmCRTC_BLACK_COLOR);
1875 0 : dm_write_reg(ctx, addr, value);
1876 : /* This is desirable to have a constant DAC output voltage during the
1877 : * blank time that is higher than the 0 volt reference level that the
1878 : * DAC outputs when the NBLANK signal
1879 : * is asserted low, such as for output to an analog TV. */
1880 0 : addr = CRTC_REG(mmCRTC_BLANK_DATA_COLOR);
1881 0 : dm_write_reg(ctx, addr, value);
1882 :
1883 : /* TO DO we have to program EXT registers and we need to know LB DATA
1884 : * format because it is used when more 10 , i.e. 12 bits per color
1885 : *
1886 : * m_mmDxCRTC_OVERSCAN_COLOR_EXT
1887 : * m_mmDxCRTC_BLACK_COLOR_EXT
1888 : * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
1889 : */
1890 :
1891 0 : }
1892 :
1893 0 : void dce110_tg_program_blank_color(struct timing_generator *tg,
1894 : const struct tg_color *black_color)
1895 : {
1896 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1897 0 : uint32_t addr = CRTC_REG(mmCRTC_BLACK_COLOR);
1898 0 : uint32_t value = dm_read_reg(tg->ctx, addr);
1899 :
1900 0 : set_reg_field_value(
1901 : value,
1902 : black_color->color_b_cb,
1903 : CRTC_BLACK_COLOR,
1904 : CRTC_BLACK_COLOR_B_CB);
1905 0 : set_reg_field_value(
1906 : value,
1907 : black_color->color_g_y,
1908 : CRTC_BLACK_COLOR,
1909 : CRTC_BLACK_COLOR_G_Y);
1910 0 : set_reg_field_value(
1911 : value,
1912 : black_color->color_r_cr,
1913 : CRTC_BLACK_COLOR,
1914 : CRTC_BLACK_COLOR_R_CR);
1915 :
1916 0 : dm_write_reg(tg->ctx, addr, value);
1917 :
1918 0 : addr = CRTC_REG(mmCRTC_BLANK_DATA_COLOR);
1919 0 : dm_write_reg(tg->ctx, addr, value);
1920 0 : }
1921 :
1922 0 : void dce110_tg_set_overscan_color(struct timing_generator *tg,
1923 : const struct tg_color *overscan_color)
1924 : {
1925 0 : struct dc_context *ctx = tg->ctx;
1926 0 : uint32_t value = 0;
1927 : uint32_t addr;
1928 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1929 :
1930 0 : set_reg_field_value(
1931 : value,
1932 : overscan_color->color_b_cb,
1933 : CRTC_OVERSCAN_COLOR,
1934 : CRTC_OVERSCAN_COLOR_BLUE);
1935 :
1936 0 : set_reg_field_value(
1937 : value,
1938 : overscan_color->color_g_y,
1939 : CRTC_OVERSCAN_COLOR,
1940 : CRTC_OVERSCAN_COLOR_GREEN);
1941 :
1942 0 : set_reg_field_value(
1943 : value,
1944 : overscan_color->color_r_cr,
1945 : CRTC_OVERSCAN_COLOR,
1946 : CRTC_OVERSCAN_COLOR_RED);
1947 :
1948 0 : addr = CRTC_REG(mmCRTC_OVERSCAN_COLOR);
1949 0 : dm_write_reg(ctx, addr, value);
1950 0 : }
1951 :
1952 0 : void dce110_tg_program_timing(struct timing_generator *tg,
1953 : const struct dc_crtc_timing *timing,
1954 : int vready_offset,
1955 : int vstartup_start,
1956 : int vupdate_offset,
1957 : int vupdate_width,
1958 : const enum signal_type signal,
1959 : bool use_vbios)
1960 : {
1961 0 : if (use_vbios)
1962 0 : dce110_timing_generator_program_timing_generator(tg, timing);
1963 : else
1964 0 : dce110_timing_generator_program_blanking(tg, timing);
1965 0 : }
1966 :
1967 0 : bool dce110_tg_is_blanked(struct timing_generator *tg)
1968 : {
1969 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1970 0 : uint32_t value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_BLANK_CONTROL));
1971 :
1972 0 : if (get_reg_field_value(
1973 : value,
1974 : CRTC_BLANK_CONTROL,
1975 0 : CRTC_BLANK_DATA_EN) == 1 &&
1976 0 : get_reg_field_value(
1977 : value,
1978 : CRTC_BLANK_CONTROL,
1979 : CRTC_CURRENT_BLANK_STATE) == 1)
1980 : return true;
1981 : return false;
1982 : }
1983 :
1984 0 : void dce110_tg_set_blank(struct timing_generator *tg,
1985 : bool enable_blanking)
1986 : {
1987 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1988 0 : uint32_t value = 0;
1989 :
1990 0 : set_reg_field_value(
1991 : value,
1992 : 1,
1993 : CRTC_DOUBLE_BUFFER_CONTROL,
1994 : CRTC_BLANK_DATA_DOUBLE_BUFFER_EN);
1995 :
1996 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_DOUBLE_BUFFER_CONTROL), value);
1997 0 : value = 0;
1998 :
1999 0 : if (enable_blanking) {
2000 0 : set_reg_field_value(
2001 : value,
2002 : 1,
2003 : CRTC_BLANK_CONTROL,
2004 : CRTC_BLANK_DATA_EN);
2005 :
2006 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_BLANK_CONTROL), value);
2007 :
2008 : } else
2009 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_BLANK_CONTROL), 0);
2010 0 : }
2011 :
2012 0 : bool dce110_tg_validate_timing(struct timing_generator *tg,
2013 : const struct dc_crtc_timing *timing)
2014 : {
2015 0 : return dce110_timing_generator_validate_timing(tg, timing, SIGNAL_TYPE_NONE);
2016 : }
2017 :
2018 0 : void dce110_tg_wait_for_state(struct timing_generator *tg,
2019 : enum crtc_state state)
2020 : {
2021 0 : switch (state) {
2022 : case CRTC_STATE_VBLANK:
2023 0 : dce110_timing_generator_wait_for_vblank(tg);
2024 0 : break;
2025 :
2026 : case CRTC_STATE_VACTIVE:
2027 0 : dce110_timing_generator_wait_for_vactive(tg);
2028 0 : break;
2029 :
2030 : default:
2031 : break;
2032 : }
2033 0 : }
2034 :
2035 0 : void dce110_tg_set_colors(struct timing_generator *tg,
2036 : const struct tg_color *blank_color,
2037 : const struct tg_color *overscan_color)
2038 : {
2039 0 : if (blank_color != NULL)
2040 0 : dce110_tg_program_blank_color(tg, blank_color);
2041 0 : if (overscan_color != NULL)
2042 0 : dce110_tg_set_overscan_color(tg, overscan_color);
2043 0 : }
2044 :
2045 : /* Gets first line of blank region of the display timing for CRTC
2046 : * and programms is as a trigger to fire vertical interrupt
2047 : */
2048 0 : bool dce110_arm_vert_intr(struct timing_generator *tg, uint8_t width)
2049 : {
2050 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
2051 0 : uint32_t v_blank_start = 0;
2052 0 : uint32_t v_blank_end = 0;
2053 0 : uint32_t val = 0;
2054 : uint32_t h_position, v_position;
2055 :
2056 0 : tg->funcs->get_scanoutpos(
2057 : tg,
2058 : &v_blank_start,
2059 : &v_blank_end,
2060 : &h_position,
2061 : &v_position);
2062 :
2063 0 : if (v_blank_start == 0 || v_blank_end == 0)
2064 : return false;
2065 :
2066 0 : set_reg_field_value(
2067 : val,
2068 : v_blank_start,
2069 : CRTC_VERTICAL_INTERRUPT0_POSITION,
2070 : CRTC_VERTICAL_INTERRUPT0_LINE_START);
2071 :
2072 : /* Set interval width for interrupt to fire to 1 scanline */
2073 0 : set_reg_field_value(
2074 : val,
2075 : v_blank_start + width,
2076 : CRTC_VERTICAL_INTERRUPT0_POSITION,
2077 : CRTC_VERTICAL_INTERRUPT0_LINE_END);
2078 :
2079 0 : dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERTICAL_INTERRUPT0_POSITION), val);
2080 :
2081 0 : return true;
2082 : }
2083 :
2084 0 : static bool dce110_is_tg_enabled(struct timing_generator *tg)
2085 : {
2086 0 : uint32_t addr = 0;
2087 0 : uint32_t value = 0;
2088 0 : uint32_t field = 0;
2089 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
2090 :
2091 0 : addr = CRTC_REG(mmCRTC_CONTROL);
2092 0 : value = dm_read_reg(tg->ctx, addr);
2093 0 : field = get_reg_field_value(value, CRTC_CONTROL,
2094 : CRTC_CURRENT_MASTER_EN_STATE);
2095 0 : return field == 1;
2096 : }
2097 :
2098 0 : bool dce110_configure_crc(struct timing_generator *tg,
2099 : const struct crc_params *params)
2100 : {
2101 0 : uint32_t cntl_addr = 0;
2102 0 : uint32_t addr = 0;
2103 : uint32_t value;
2104 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
2105 :
2106 : /* Cannot configure crc on a CRTC that is disabled */
2107 0 : if (!dce110_is_tg_enabled(tg))
2108 : return false;
2109 :
2110 0 : cntl_addr = CRTC_REG(mmCRTC_CRC_CNTL);
2111 :
2112 : /* First, disable CRC before we configure it. */
2113 0 : dm_write_reg(tg->ctx, cntl_addr, 0);
2114 :
2115 0 : if (!params->enable)
2116 : return true;
2117 :
2118 : /* Program frame boundaries */
2119 : /* Window A x axis start and end. */
2120 0 : value = 0;
2121 0 : addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_X_CONTROL);
2122 0 : set_reg_field_value(value, params->windowa_x_start,
2123 : CRTC_CRC0_WINDOWA_X_CONTROL,
2124 : CRTC_CRC0_WINDOWA_X_START);
2125 0 : set_reg_field_value(value, params->windowa_x_end,
2126 : CRTC_CRC0_WINDOWA_X_CONTROL,
2127 : CRTC_CRC0_WINDOWA_X_END);
2128 0 : dm_write_reg(tg->ctx, addr, value);
2129 :
2130 : /* Window A y axis start and end. */
2131 0 : value = 0;
2132 0 : addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_Y_CONTROL);
2133 0 : set_reg_field_value(value, params->windowa_y_start,
2134 : CRTC_CRC0_WINDOWA_Y_CONTROL,
2135 : CRTC_CRC0_WINDOWA_Y_START);
2136 0 : set_reg_field_value(value, params->windowa_y_end,
2137 : CRTC_CRC0_WINDOWA_Y_CONTROL,
2138 : CRTC_CRC0_WINDOWA_Y_END);
2139 0 : dm_write_reg(tg->ctx, addr, value);
2140 :
2141 : /* Window B x axis start and end. */
2142 0 : value = 0;
2143 0 : addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_X_CONTROL);
2144 0 : set_reg_field_value(value, params->windowb_x_start,
2145 : CRTC_CRC0_WINDOWB_X_CONTROL,
2146 : CRTC_CRC0_WINDOWB_X_START);
2147 0 : set_reg_field_value(value, params->windowb_x_end,
2148 : CRTC_CRC0_WINDOWB_X_CONTROL,
2149 : CRTC_CRC0_WINDOWB_X_END);
2150 0 : dm_write_reg(tg->ctx, addr, value);
2151 :
2152 : /* Window B y axis start and end. */
2153 0 : value = 0;
2154 0 : addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_Y_CONTROL);
2155 0 : set_reg_field_value(value, params->windowb_y_start,
2156 : CRTC_CRC0_WINDOWB_Y_CONTROL,
2157 : CRTC_CRC0_WINDOWB_Y_START);
2158 0 : set_reg_field_value(value, params->windowb_y_end,
2159 : CRTC_CRC0_WINDOWB_Y_CONTROL,
2160 : CRTC_CRC0_WINDOWB_Y_END);
2161 0 : dm_write_reg(tg->ctx, addr, value);
2162 :
2163 : /* Set crc mode and selection, and enable. Only using CRC0*/
2164 0 : value = 0;
2165 0 : set_reg_field_value(value, params->continuous_mode ? 1 : 0,
2166 : CRTC_CRC_CNTL, CRTC_CRC_CONT_EN);
2167 0 : set_reg_field_value(value, params->selection,
2168 : CRTC_CRC_CNTL, CRTC_CRC0_SELECT);
2169 0 : set_reg_field_value(value, 1, CRTC_CRC_CNTL, CRTC_CRC_EN);
2170 0 : dm_write_reg(tg->ctx, cntl_addr, value);
2171 :
2172 0 : return true;
2173 : }
2174 :
2175 0 : bool dce110_get_crc(struct timing_generator *tg,
2176 : uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
2177 : {
2178 0 : uint32_t addr = 0;
2179 0 : uint32_t value = 0;
2180 0 : uint32_t field = 0;
2181 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
2182 :
2183 0 : addr = CRTC_REG(mmCRTC_CRC_CNTL);
2184 0 : value = dm_read_reg(tg->ctx, addr);
2185 0 : field = get_reg_field_value(value, CRTC_CRC_CNTL, CRTC_CRC_EN);
2186 :
2187 : /* Early return if CRC is not enabled for this CRTC */
2188 0 : if (!field)
2189 : return false;
2190 :
2191 0 : addr = CRTC_REG(mmCRTC_CRC0_DATA_RG);
2192 0 : value = dm_read_reg(tg->ctx, addr);
2193 0 : *r_cr = get_reg_field_value(value, CRTC_CRC0_DATA_RG, CRC0_R_CR);
2194 0 : *g_y = get_reg_field_value(value, CRTC_CRC0_DATA_RG, CRC0_G_Y);
2195 :
2196 0 : addr = CRTC_REG(mmCRTC_CRC0_DATA_B);
2197 0 : value = dm_read_reg(tg->ctx, addr);
2198 0 : *b_cb = get_reg_field_value(value, CRTC_CRC0_DATA_B, CRC0_B_CB);
2199 :
2200 0 : return true;
2201 : }
2202 :
2203 : static const struct timing_generator_funcs dce110_tg_funcs = {
2204 : .validate_timing = dce110_tg_validate_timing,
2205 : .program_timing = dce110_tg_program_timing,
2206 : .enable_crtc = dce110_timing_generator_enable_crtc,
2207 : .disable_crtc = dce110_timing_generator_disable_crtc,
2208 : .is_counter_moving = dce110_timing_generator_is_counter_moving,
2209 : .get_position = dce110_timing_generator_get_position,
2210 : .get_frame_count = dce110_timing_generator_get_vblank_counter,
2211 : .get_scanoutpos = dce110_timing_generator_get_crtc_scanoutpos,
2212 : .set_early_control = dce110_timing_generator_set_early_control,
2213 : .wait_for_state = dce110_tg_wait_for_state,
2214 : .set_blank = dce110_tg_set_blank,
2215 : .is_blanked = dce110_tg_is_blanked,
2216 : .set_colors = dce110_tg_set_colors,
2217 : .set_overscan_blank_color =
2218 : dce110_timing_generator_set_overscan_color_black,
2219 : .set_blank_color = dce110_timing_generator_program_blank_color,
2220 : .disable_vga = dce110_timing_generator_disable_vga,
2221 : .did_triggered_reset_occur =
2222 : dce110_timing_generator_did_triggered_reset_occur,
2223 : .setup_global_swap_lock =
2224 : dce110_timing_generator_setup_global_swap_lock,
2225 : .enable_reset_trigger = dce110_timing_generator_enable_reset_trigger,
2226 : .enable_crtc_reset = dce110_timing_generator_enable_crtc_reset,
2227 : .disable_reset_trigger = dce110_timing_generator_disable_reset_trigger,
2228 : .tear_down_global_swap_lock =
2229 : dce110_timing_generator_tear_down_global_swap_lock,
2230 : .enable_advanced_request =
2231 : dce110_timing_generator_enable_advanced_request,
2232 : .set_drr =
2233 : dce110_timing_generator_set_drr,
2234 : .get_last_used_drr_vtotal = NULL,
2235 : .set_static_screen_control =
2236 : dce110_timing_generator_set_static_screen_control,
2237 : .set_test_pattern = dce110_timing_generator_set_test_pattern,
2238 : .arm_vert_intr = dce110_arm_vert_intr,
2239 : .is_tg_enabled = dce110_is_tg_enabled,
2240 : .configure_crc = dce110_configure_crc,
2241 : .get_crc = dce110_get_crc,
2242 : };
2243 :
2244 0 : void dce110_timing_generator_construct(
2245 : struct dce110_timing_generator *tg110,
2246 : struct dc_context *ctx,
2247 : uint32_t instance,
2248 : const struct dce110_timing_generator_offsets *offsets)
2249 : {
2250 0 : tg110->controller_id = CONTROLLER_ID_D0 + instance;
2251 0 : tg110->base.inst = instance;
2252 :
2253 0 : tg110->offsets = *offsets;
2254 :
2255 0 : tg110->base.funcs = &dce110_tg_funcs;
2256 :
2257 0 : tg110->base.ctx = ctx;
2258 0 : tg110->base.bp = ctx->dc_bios;
2259 :
2260 0 : tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
2261 0 : tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
2262 :
2263 0 : tg110->min_h_blank = 56;
2264 0 : tg110->min_h_front_porch = 4;
2265 0 : tg110->min_h_back_porch = 4;
2266 0 : }
|