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