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