]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c
Merge remote-tracking branches 'asoc/topic/tas6424', 'asoc/topic/tfa9879', 'asoc...
[mirror_ubuntu-focal-kernel.git] / drivers / gpu / drm / amd / display / dc / dce110 / dce110_timing_generator_v.c
CommitLineData
bf93b448
AD
1/*
2 * Copyright 2017 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 */
23
4562236b
HW
24#include "dm_services.h"
25
26/* include DCE11 register header files */
27#include "dce/dce_11_0_d.h"
28#include "dce/dce_11_0_sh_mask.h"
29
30#include "dc_types.h"
31#include "dc_bios_types.h"
32#include "dc.h"
33
34#include "include/grph_object_id.h"
35#include "include/logger_interface.h"
36#include "dce110_timing_generator.h"
37#include "dce110_timing_generator_v.h"
38
39#include "timing_generator.h"
40
41/** ********************************************************************************
42 *
43 * DCE11 Timing Generator Implementation
44 *
45 **********************************************************************************/
46
47/**
48* Enable CRTCV
49*/
50
51static bool dce110_timing_generator_v_enable_crtc(struct timing_generator *tg)
52{
53/*
54* Set MASTER_UPDATE_MODE to 0
55* This is needed for DRR, and also suggested to be default value by Syed.
56*/
57
58 uint32_t value;
59
60 value = 0;
61 set_reg_field_value(value, 0,
62 CRTCV_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE);
63 dm_write_reg(tg->ctx,
64 mmCRTCV_MASTER_UPDATE_MODE, value);
65
66 /* TODO: may want this on for looking for underflow */
67 value = 0;
68 dm_write_reg(tg->ctx, mmCRTCV_MASTER_UPDATE_MODE, value);
69
70 value = 0;
71 set_reg_field_value(value, 1,
72 CRTCV_MASTER_EN, CRTC_MASTER_EN);
73 dm_write_reg(tg->ctx,
74 mmCRTCV_MASTER_EN, value);
75
76 return true;
77}
78
79static bool dce110_timing_generator_v_disable_crtc(struct timing_generator *tg)
80{
81 uint32_t value;
82
83 value = dm_read_reg(tg->ctx,
84 mmCRTCV_CONTROL);
85 set_reg_field_value(value, 0,
86 CRTCV_CONTROL, CRTC_DISABLE_POINT_CNTL);
87 set_reg_field_value(value, 0,
88 CRTCV_CONTROL, CRTC_MASTER_EN);
89 dm_write_reg(tg->ctx,
90 mmCRTCV_CONTROL, value);
91 /*
92 * TODO: call this when adding stereo support
93 * tg->funcs->disable_stereo(tg);
94 */
95 return true;
96}
97
4b5e7d62 98static void dce110_timing_generator_v_blank_crtc(struct timing_generator *tg)
4562236b 99{
4562236b
HW
100 uint32_t addr = mmCRTCV_BLANK_CONTROL;
101 uint32_t value = dm_read_reg(tg->ctx, addr);
4562236b
HW
102
103 set_reg_field_value(
104 value,
105 1,
106 CRTCV_BLANK_CONTROL,
107 CRTC_BLANK_DATA_EN);
108
109 set_reg_field_value(
110 value,
111 0,
112 CRTCV_BLANK_CONTROL,
113 CRTC_BLANK_DE_MODE);
114
115 dm_write_reg(tg->ctx, addr, value);
4562236b
HW
116}
117
4b5e7d62 118static void dce110_timing_generator_v_unblank_crtc(struct timing_generator *tg)
4562236b
HW
119{
120 uint32_t addr = mmCRTCV_BLANK_CONTROL;
121 uint32_t value = dm_read_reg(tg->ctx, addr);
122
123 set_reg_field_value(
124 value,
125 0,
126 CRTCV_BLANK_CONTROL,
127 CRTC_BLANK_DATA_EN);
128
129 set_reg_field_value(
130 value,
131 0,
132 CRTCV_BLANK_CONTROL,
133 CRTC_BLANK_DE_MODE);
134
135 dm_write_reg(tg->ctx, addr, value);
4562236b
HW
136}
137
138static bool dce110_timing_generator_v_is_in_vertical_blank(
139 struct timing_generator *tg)
140{
141 uint32_t addr = 0;
142 uint32_t value = 0;
143 uint32_t field = 0;
144
145 addr = mmCRTCV_STATUS;
146 value = dm_read_reg(tg->ctx, addr);
147 field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK);
148 return field == 1;
149}
150
151static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg)
152{
153 uint32_t value;
154 uint32_t h1 = 0;
155 uint32_t h2 = 0;
156 uint32_t v1 = 0;
157 uint32_t v2 = 0;
158
159 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
160
161 h1 = get_reg_field_value(
162 value,
163 CRTCV_STATUS_POSITION,
164 CRTC_HORZ_COUNT);
165
166 v1 = get_reg_field_value(
167 value,
168 CRTCV_STATUS_POSITION,
169 CRTC_VERT_COUNT);
170
171 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION);
172
173 h2 = get_reg_field_value(
174 value,
175 CRTCV_STATUS_POSITION,
176 CRTC_HORZ_COUNT);
177
178 v2 = get_reg_field_value(
179 value,
180 CRTCV_STATUS_POSITION,
181 CRTC_VERT_COUNT);
182
183 if (h1 == h2 && v1 == v2)
184 return false;
185 else
186 return true;
187}
188
189static void dce110_timing_generator_v_wait_for_vblank(struct timing_generator *tg)
190{
191 /* We want to catch beginning of VBlank here, so if the first try are
192 * in VBlank, we might be very close to Active, in this case wait for
193 * another frame
194 */
195 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
196 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
197 /* error - no point to wait if counter is not moving */
198 break;
199 }
200 }
201
202 while (!dce110_timing_generator_v_is_in_vertical_blank(tg)) {
203 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
204 /* error - no point to wait if counter is not moving */
205 break;
206 }
207 }
208}
209
210/**
211* Wait till we are in VActive (anywhere in VActive)
212*/
213static void dce110_timing_generator_v_wait_for_vactive(struct timing_generator *tg)
214{
215 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) {
216 if (!dce110_timing_generator_v_is_counter_moving(tg)) {
217 /* error - no point to wait if counter is not moving */
218 break;
219 }
220 }
221}
222
223static void dce110_timing_generator_v_wait_for_state(struct timing_generator *tg,
224 enum crtc_state state)
225{
226 switch (state) {
227 case CRTC_STATE_VBLANK:
228 dce110_timing_generator_v_wait_for_vblank(tg);
229 break;
230
231 case CRTC_STATE_VACTIVE:
232 dce110_timing_generator_v_wait_for_vactive(tg);
233 break;
234
235 default:
236 break;
237 }
238}
239
240static void dce110_timing_generator_v_program_blanking(
241 struct timing_generator *tg,
242 const struct dc_crtc_timing *timing)
243{
244 uint32_t vsync_offset = timing->v_border_bottom +
245 timing->v_front_porch;
246 uint32_t v_sync_start = timing->v_addressable + vsync_offset;
247
248 uint32_t hsync_offset = timing->h_border_right +
249 timing->h_front_porch;
250 uint32_t h_sync_start = timing->h_addressable + hsync_offset;
251
252 struct dc_context *ctx = tg->ctx;
253 uint32_t value = 0;
254 uint32_t addr = 0;
255 uint32_t tmp = 0;
256
257 addr = mmCRTCV_H_TOTAL;
258 value = dm_read_reg(ctx, addr);
259 set_reg_field_value(
260 value,
261 timing->h_total - 1,
262 CRTCV_H_TOTAL,
263 CRTC_H_TOTAL);
264 dm_write_reg(ctx, addr, value);
265
266 addr = mmCRTCV_V_TOTAL;
267 value = dm_read_reg(ctx, addr);
268 set_reg_field_value(
269 value,
270 timing->v_total - 1,
271 CRTCV_V_TOTAL,
272 CRTC_V_TOTAL);
273 dm_write_reg(ctx, addr, value);
274
275 addr = mmCRTCV_H_BLANK_START_END;
276 value = dm_read_reg(ctx, addr);
277
278 tmp = timing->h_total -
279 (h_sync_start + timing->h_border_left);
280
281 set_reg_field_value(
282 value,
283 tmp,
284 CRTCV_H_BLANK_START_END,
285 CRTC_H_BLANK_END);
286
287 tmp = tmp + timing->h_addressable +
288 timing->h_border_left + timing->h_border_right;
289
290 set_reg_field_value(
291 value,
292 tmp,
293 CRTCV_H_BLANK_START_END,
294 CRTC_H_BLANK_START);
295
296 dm_write_reg(ctx, addr, value);
297
298 addr = mmCRTCV_V_BLANK_START_END;
299 value = dm_read_reg(ctx, addr);
300
301 tmp = timing->v_total - (v_sync_start + timing->v_border_top);
302
303 set_reg_field_value(
304 value,
305 tmp,
306 CRTCV_V_BLANK_START_END,
307 CRTC_V_BLANK_END);
308
309 tmp = tmp + timing->v_addressable + timing->v_border_top +
310 timing->v_border_bottom;
311
312 set_reg_field_value(
313 value,
314 tmp,
315 CRTCV_V_BLANK_START_END,
316 CRTC_V_BLANK_START);
317
318 dm_write_reg(ctx, addr, value);
319
320 addr = mmCRTCV_H_SYNC_A;
321 value = 0;
322 set_reg_field_value(
323 value,
324 timing->h_sync_width,
325 CRTCV_H_SYNC_A,
326 CRTC_H_SYNC_A_END);
327 dm_write_reg(ctx, addr, value);
328
329 addr = mmCRTCV_H_SYNC_A_CNTL;
330 value = dm_read_reg(ctx, addr);
331 if (timing->flags.HSYNC_POSITIVE_POLARITY) {
332 set_reg_field_value(
333 value,
334 0,
335 CRTCV_H_SYNC_A_CNTL,
336 CRTC_H_SYNC_A_POL);
337 } else {
338 set_reg_field_value(
339 value,
340 1,
341 CRTCV_H_SYNC_A_CNTL,
342 CRTC_H_SYNC_A_POL);
343 }
344 dm_write_reg(ctx, addr, value);
345
346 addr = mmCRTCV_V_SYNC_A;
347 value = 0;
348 set_reg_field_value(
349 value,
350 timing->v_sync_width,
351 CRTCV_V_SYNC_A,
352 CRTC_V_SYNC_A_END);
353 dm_write_reg(ctx, addr, value);
354
355 addr = mmCRTCV_V_SYNC_A_CNTL;
356 value = dm_read_reg(ctx, addr);
357 if (timing->flags.VSYNC_POSITIVE_POLARITY) {
358 set_reg_field_value(
359 value,
360 0,
361 CRTCV_V_SYNC_A_CNTL,
362 CRTC_V_SYNC_A_POL);
363 } else {
364 set_reg_field_value(
365 value,
366 1,
367 CRTCV_V_SYNC_A_CNTL,
368 CRTC_V_SYNC_A_POL);
369 }
370 dm_write_reg(ctx, addr, value);
371
372 addr = mmCRTCV_INTERLACE_CONTROL;
373 value = dm_read_reg(ctx, addr);
374 set_reg_field_value(
375 value,
376 timing->flags.INTERLACE,
377 CRTCV_INTERLACE_CONTROL,
378 CRTC_INTERLACE_ENABLE);
379 dm_write_reg(ctx, addr, value);
380}
381
382static void dce110_timing_generator_v_enable_advanced_request(
383 struct timing_generator *tg,
384 bool enable,
385 const struct dc_crtc_timing *timing)
386{
387 uint32_t addr = mmCRTCV_START_LINE_CONTROL;
388 uint32_t value = dm_read_reg(tg->ctx, addr);
389
390 if (enable) {
391 if ((timing->v_sync_width + timing->v_front_porch) <= 3) {
392 set_reg_field_value(
393 value,
394 3,
395 CRTCV_START_LINE_CONTROL,
396 CRTC_ADVANCED_START_LINE_POSITION);
397 } else {
398 set_reg_field_value(
399 value,
400 4,
401 CRTCV_START_LINE_CONTROL,
402 CRTC_ADVANCED_START_LINE_POSITION);
403 }
404 set_reg_field_value(
405 value,
406 0,
407 CRTCV_START_LINE_CONTROL,
408 CRTC_LEGACY_REQUESTOR_EN);
409 } else {
410 set_reg_field_value(
411 value,
412 2,
413 CRTCV_START_LINE_CONTROL,
414 CRTC_ADVANCED_START_LINE_POSITION);
415 set_reg_field_value(
416 value,
417 1,
418 CRTCV_START_LINE_CONTROL,
419 CRTC_LEGACY_REQUESTOR_EN);
420 }
421
422 dm_write_reg(tg->ctx, addr, value);
423}
424
4b5e7d62 425static void dce110_timing_generator_v_set_blank(struct timing_generator *tg,
4562236b
HW
426 bool enable_blanking)
427{
428 if (enable_blanking)
4b5e7d62 429 dce110_timing_generator_v_blank_crtc(tg);
4562236b 430 else
4b5e7d62 431 dce110_timing_generator_v_unblank_crtc(tg);
4562236b
HW
432}
433
434static void dce110_timing_generator_v_program_timing(struct timing_generator *tg,
435 const struct dc_crtc_timing *timing,
436 bool use_vbios)
437{
438 if (use_vbios)
439 dce110_timing_generator_program_timing_generator(tg, timing);
440 else
441 dce110_timing_generator_v_program_blanking(tg, timing);
442}
443
444static void dce110_timing_generator_v_program_blank_color(
445 struct timing_generator *tg,
446 const struct tg_color *black_color)
447{
448 uint32_t addr = mmCRTCV_BLACK_COLOR;
449 uint32_t value = dm_read_reg(tg->ctx, addr);
450
451 set_reg_field_value(
452 value,
453 black_color->color_b_cb,
454 CRTCV_BLACK_COLOR,
455 CRTC_BLACK_COLOR_B_CB);
456 set_reg_field_value(
457 value,
458 black_color->color_g_y,
459 CRTCV_BLACK_COLOR,
460 CRTC_BLACK_COLOR_G_Y);
461 set_reg_field_value(
462 value,
463 black_color->color_r_cr,
464 CRTCV_BLACK_COLOR,
465 CRTC_BLACK_COLOR_R_CR);
466
467 dm_write_reg(tg->ctx, addr, value);
468}
469
470static void dce110_timing_generator_v_set_overscan_color_black(
471 struct timing_generator *tg,
472 const struct tg_color *color)
473{
474 struct dc_context *ctx = tg->ctx;
475 uint32_t addr;
476 uint32_t value = 0;
477
478 set_reg_field_value(
479 value,
480 color->color_b_cb,
481 CRTC_OVERSCAN_COLOR,
482 CRTC_OVERSCAN_COLOR_BLUE);
483
484 set_reg_field_value(
485 value,
486 color->color_r_cr,
487 CRTC_OVERSCAN_COLOR,
488 CRTC_OVERSCAN_COLOR_RED);
489
490 set_reg_field_value(
491 value,
492 color->color_g_y,
493 CRTC_OVERSCAN_COLOR,
494 CRTC_OVERSCAN_COLOR_GREEN);
495
496 addr = mmCRTCV_OVERSCAN_COLOR;
497 dm_write_reg(ctx, addr, value);
498 addr = mmCRTCV_BLACK_COLOR;
499 dm_write_reg(ctx, addr, value);
500 /* This is desirable to have a constant DAC output voltage during the
501 * blank time that is higher than the 0 volt reference level that the
502 * DAC outputs when the NBLANK signal
503 * is asserted low, such as for output to an analog TV. */
504 addr = mmCRTCV_BLANK_DATA_COLOR;
505 dm_write_reg(ctx, addr, value);
506
507 /* TO DO we have to program EXT registers and we need to know LB DATA
508 * format because it is used when more 10 , i.e. 12 bits per color
509 *
510 * m_mmDxCRTC_OVERSCAN_COLOR_EXT
511 * m_mmDxCRTC_BLACK_COLOR_EXT
512 * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
513 */
514}
515
516static void dce110_tg_v_program_blank_color(struct timing_generator *tg,
517 const struct tg_color *black_color)
518{
519 uint32_t addr = mmCRTCV_BLACK_COLOR;
520 uint32_t value = dm_read_reg(tg->ctx, addr);
521
522 set_reg_field_value(
523 value,
524 black_color->color_b_cb,
525 CRTCV_BLACK_COLOR,
526 CRTC_BLACK_COLOR_B_CB);
527 set_reg_field_value(
528 value,
529 black_color->color_g_y,
530 CRTCV_BLACK_COLOR,
531 CRTC_BLACK_COLOR_G_Y);
532 set_reg_field_value(
533 value,
534 black_color->color_r_cr,
535 CRTCV_BLACK_COLOR,
536 CRTC_BLACK_COLOR_R_CR);
537
538 dm_write_reg(tg->ctx, addr, value);
539
540 addr = mmCRTCV_BLANK_DATA_COLOR;
541 dm_write_reg(tg->ctx, addr, value);
542}
543
544static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg,
545 const struct tg_color *overscan_color)
546{
547 struct dc_context *ctx = tg->ctx;
548 uint32_t value = 0;
549 uint32_t addr;
550
551 set_reg_field_value(
552 value,
553 overscan_color->color_b_cb,
554 CRTCV_OVERSCAN_COLOR,
555 CRTC_OVERSCAN_COLOR_BLUE);
556
557 set_reg_field_value(
558 value,
559 overscan_color->color_g_y,
560 CRTCV_OVERSCAN_COLOR,
561 CRTC_OVERSCAN_COLOR_GREEN);
562
563 set_reg_field_value(
564 value,
565 overscan_color->color_r_cr,
566 CRTCV_OVERSCAN_COLOR,
567 CRTC_OVERSCAN_COLOR_RED);
568
569 addr = mmCRTCV_OVERSCAN_COLOR;
570 dm_write_reg(ctx, addr, value);
571}
572
573static void dce110_timing_generator_v_set_colors(struct timing_generator *tg,
574 const struct tg_color *blank_color,
575 const struct tg_color *overscan_color)
576{
577 if (blank_color != NULL)
578 dce110_tg_v_program_blank_color(tg, blank_color);
579 if (overscan_color != NULL)
580 dce110_timing_generator_v_set_overscan_color(tg, overscan_color);
581}
582
583static void dce110_timing_generator_v_set_early_control(
584 struct timing_generator *tg,
585 uint32_t early_cntl)
586{
587 uint32_t regval;
588 uint32_t address = mmCRTC_CONTROL;
589
590 regval = dm_read_reg(tg->ctx, address);
591 set_reg_field_value(regval, early_cntl,
592 CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
593 dm_write_reg(tg->ctx, address, regval);
594}
595
4562236b
HW
596static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg)
597{
598 uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT;
599 uint32_t value = dm_read_reg(tg->ctx, addr);
600 uint32_t field = get_reg_field_value(
601 value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
602
603 return field;
604}
605
606static bool dce110_timing_generator_v_did_triggered_reset_occur(
607 struct timing_generator *tg)
608{
609 dm_logger_write(tg->ctx->logger, LOG_ERROR,
610 "Timing Sync not supported on underlay pipe\n");
611 return false;
612}
613
614static void dce110_timing_generator_v_setup_global_swap_lock(
615 struct timing_generator *tg,
616 const struct dcp_gsl_params *gsl_params)
617{
618 dm_logger_write(tg->ctx->logger, LOG_ERROR,
619 "Timing Sync not supported on underlay pipe\n");
620 return;
621}
622
623static void dce110_timing_generator_v_enable_reset_trigger(
624 struct timing_generator *tg,
625 int source_tg_inst)
626{
627 dm_logger_write(tg->ctx->logger, LOG_ERROR,
628 "Timing Sync not supported on underlay pipe\n");
629 return;
630}
631
632static void dce110_timing_generator_v_disable_reset_trigger(
633 struct timing_generator *tg)
634{
635 dm_logger_write(tg->ctx->logger, LOG_ERROR,
636 "Timing Sync not supported on underlay pipe\n");
637 return;
638}
639
640static void dce110_timing_generator_v_tear_down_global_swap_lock(
641 struct timing_generator *tg)
642{
643 dm_logger_write(tg->ctx->logger, LOG_ERROR,
644 "Timing Sync not supported on underlay pipe\n");
645 return;
646}
647
648static void dce110_timing_generator_v_disable_vga(
649 struct timing_generator *tg)
650{
651 return;
652}
653
654static bool dce110_tg_v_is_blanked(struct timing_generator *tg)
655{
656 /* Signal comes from the primary pipe, underlay is never blanked. */
657 return false;
658}
659
660/** ********************************************************************************************
661 *
662 * DCE11 Timing Generator Constructor / Destructor
663 *
664 *********************************************************************************************/
665static const struct timing_generator_funcs dce110_tg_v_funcs = {
666 .validate_timing = dce110_tg_validate_timing,
667 .program_timing = dce110_timing_generator_v_program_timing,
668 .enable_crtc = dce110_timing_generator_v_enable_crtc,
669 .disable_crtc = dce110_timing_generator_v_disable_crtc,
670 .is_counter_moving = dce110_timing_generator_v_is_counter_moving,
aed8b319 671 .get_position = NULL, /* Not to be implemented for underlay*/
4562236b
HW
672 .get_frame_count = dce110_timing_generator_v_get_vblank_counter,
673 .set_early_control = dce110_timing_generator_v_set_early_control,
674 .wait_for_state = dce110_timing_generator_v_wait_for_state,
675 .set_blank = dce110_timing_generator_v_set_blank,
676 .is_blanked = dce110_tg_v_is_blanked,
677 .set_colors = dce110_timing_generator_v_set_colors,
678 .set_overscan_blank_color =
679 dce110_timing_generator_v_set_overscan_color_black,
680 .set_blank_color = dce110_timing_generator_v_program_blank_color,
681 .disable_vga = dce110_timing_generator_v_disable_vga,
682 .did_triggered_reset_occur =
683 dce110_timing_generator_v_did_triggered_reset_occur,
684 .setup_global_swap_lock =
685 dce110_timing_generator_v_setup_global_swap_lock,
686 .enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger,
687 .disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger,
688 .tear_down_global_swap_lock =
689 dce110_timing_generator_v_tear_down_global_swap_lock,
690 .enable_advanced_request =
691 dce110_timing_generator_v_enable_advanced_request
692};
693
c13b408b 694void dce110_timing_generator_v_construct(
4562236b
HW
695 struct dce110_timing_generator *tg110,
696 struct dc_context *ctx)
697{
4562236b
HW
698 tg110->controller_id = CONTROLLER_ID_UNDERLAY0;
699
700 tg110->base.funcs = &dce110_tg_v_funcs;
701
702 tg110->base.ctx = ctx;
703 tg110->base.bp = ctx->dc_bios;
704
705 tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
706 tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
707
708 tg110->min_h_blank = 56;
709 tg110->min_h_front_porch = 4;
710 tg110->min_h_back_porch = 4;
4562236b 711}