Home | History | Annotate | Line # | Download | only in dcn20
      1 /*	$NetBSD: amdgpu_dcn20_optc.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012-15 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  * Authors: AMD
     25  *
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dcn20_optc.c,v 1.2 2021/12/18 23:45:03 riastradh Exp $");
     30 
     31 #include "reg_helper.h"
     32 #include "dcn20_optc.h"
     33 #include "dc.h"
     34 
     35 #define REG(reg)\
     36 	optc1->tg_regs->reg
     37 
     38 #define CTX \
     39 	optc1->base.ctx
     40 
     41 #undef FN
     42 #define FN(reg_name, field_name) \
     43 	optc1->tg_shift->field_name, optc1->tg_mask->field_name
     44 
     45 /**
     46  * Enable CRTC
     47  * Enable CRTC - call ASIC Control Object to enable Timing generator.
     48  */
     49 bool optc2_enable_crtc(struct timing_generator *optc)
     50 {
     51 	/* TODO FPGA wait for answer
     52 	 * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE
     53 	 * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK
     54 	 */
     55 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
     56 
     57 	/* opp instance for OTG. For DCN1.0, ODM is remoed.
     58 	 * OPP and OPTC should 1:1 mapping
     59 	 */
     60 	REG_UPDATE(OPTC_DATA_SOURCE_SELECT,
     61 			OPTC_SEG0_SRC_SEL, optc->inst);
     62 
     63 	/* VTG enable first is for HW workaround */
     64 	REG_UPDATE(CONTROL,
     65 			VTG0_ENABLE, 1);
     66 
     67 	REG_SEQ_START();
     68 
     69 	/* Enable CRTC */
     70 	REG_UPDATE_2(OTG_CONTROL,
     71 			OTG_DISABLE_POINT_CNTL, 3,
     72 			OTG_MASTER_EN, 1);
     73 
     74 	REG_SEQ_SUBMIT();
     75 	REG_SEQ_WAIT_DONE();
     76 
     77 	return true;
     78 }
     79 
     80 /**
     81  * DRR double buffering control to select buffer point
     82  * for V_TOTAL, H_TOTAL, VTOTAL_MIN, VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers
     83  * Options: anytime, start of frame, dp start of frame (range timing)
     84  */
     85 void optc2_set_timing_db_mode(struct timing_generator *optc, bool enable)
     86 {
     87 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
     88 
     89 	uint32_t blank_data_double_buffer_enable = enable ? 1 : 0;
     90 
     91 	REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL,
     92 		OTG_RANGE_TIMING_DBUF_UPDATE_MODE, blank_data_double_buffer_enable);
     93 }
     94 
     95 /**
     96  *For the below, I'm not sure how your GSL parameters are stored in your env,
     97  * so I will assume a gsl_params struct for now
     98  */
     99 void optc2_set_gsl(struct timing_generator *optc,
    100 		   const struct gsl_params *params)
    101 {
    102 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    103 
    104 /**
    105  * There are (MAX_OPTC+1)/2 gsl groups available for use.
    106  * In each group (assign an OTG to a group by setting OTG_GSLX_EN = 1,
    107  * set one of the OTGs to be the master (OTG_GSL_MASTER_EN = 1) and the rest are slaves.
    108  */
    109 	REG_UPDATE_5(OTG_GSL_CONTROL,
    110 		OTG_GSL0_EN, params->gsl0_en,
    111 		OTG_GSL1_EN, params->gsl1_en,
    112 		OTG_GSL2_EN, params->gsl2_en,
    113 		OTG_GSL_MASTER_EN, params->gsl_master_en,
    114 		OTG_GSL_MASTER_MODE, params->gsl_master_mode);
    115 }
    116 
    117 
    118 /* Use the gsl allow flip as the master update lock */
    119 void optc2_use_gsl_as_master_update_lock(struct timing_generator *optc,
    120 		   const struct gsl_params *params)
    121 {
    122 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    123 
    124 	REG_UPDATE(OTG_GSL_CONTROL,
    125 		OTG_MASTER_UPDATE_LOCK_GSL_EN, params->master_update_lock_gsl_en);
    126 }
    127 
    128 /* You can control the GSL timing by limiting GSL to a window (X,Y) */
    129 void optc2_set_gsl_window(struct timing_generator *optc,
    130 		   const struct gsl_params *params)
    131 {
    132 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    133 
    134 	REG_SET_2(OTG_GSL_WINDOW_X, 0,
    135 		OTG_GSL_WINDOW_START_X, params->gsl_window_start_x,
    136 		OTG_GSL_WINDOW_END_X, params->gsl_window_end_x);
    137 	REG_SET_2(OTG_GSL_WINDOW_Y, 0,
    138 		OTG_GSL_WINDOW_START_Y, params->gsl_window_start_y,
    139 		OTG_GSL_WINDOW_END_Y, params->gsl_window_end_y);
    140 }
    141 
    142 /**
    143  * Vupdate keepout can be set to a window to block the update lock for that pipe from changing.
    144  * Start offset begins with vstartup and goes for x number of clocks,
    145  * end offset starts from end of vupdate to x number of clocks.
    146  */
    147 void optc2_set_vupdate_keepout(struct timing_generator *optc,
    148 		   const struct vupdate_keepout_params *params)
    149 {
    150 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    151 
    152 	REG_SET_3(OTG_VUPDATE_KEEPOUT, 0,
    153 		MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, params->start_offset,
    154 		MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, params->end_offset,
    155 		OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, params->enable);
    156 }
    157 
    158 void optc2_set_gsl_source_select(
    159 		struct timing_generator *optc,
    160 		int group_idx,
    161 		uint32_t gsl_ready_signal)
    162 {
    163 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    164 
    165 	switch (group_idx) {
    166 	case 1:
    167 		REG_UPDATE(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, gsl_ready_signal);
    168 		break;
    169 	case 2:
    170 		REG_UPDATE(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, gsl_ready_signal);
    171 		break;
    172 	case 3:
    173 		REG_UPDATE(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, gsl_ready_signal);
    174 		break;
    175 	default:
    176 		break;
    177 	}
    178 }
    179 
    180 /* DSC encoder frame start controls: x = h position, line_num = # of lines from vstartup */
    181 void optc2_set_dsc_encoder_frame_start(struct timing_generator *optc,
    182 					int x_position,
    183 					int line_num)
    184 {
    185 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    186 
    187 	REG_SET_2(OTG_DSC_START_POSITION, 0,
    188 			OTG_DSC_START_POSITION_X, x_position,
    189 			OTG_DSC_START_POSITION_LINE_NUM, line_num);
    190 }
    191 
    192 /* Set DSC-related configuration.
    193  *   dsc_mode: 0 disables DSC, other values enable DSC in specified format
    194  *   sc_bytes_per_pixel: Bytes per pixel in u3.28 format
    195  *   dsc_slice_width: Slice width in pixels
    196  */
    197 void optc2_set_dsc_config(struct timing_generator *optc,
    198 					enum optc_dsc_mode dsc_mode,
    199 					uint32_t dsc_bytes_per_pixel,
    200 					uint32_t dsc_slice_width)
    201 {
    202 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    203 
    204 	REG_UPDATE(OPTC_DATA_FORMAT_CONTROL,
    205 		OPTC_DSC_MODE, dsc_mode);
    206 
    207 	REG_SET(OPTC_BYTES_PER_PIXEL, 0,
    208 		OPTC_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel);
    209 
    210 	REG_UPDATE(OPTC_WIDTH_CONTROL,
    211 		OPTC_DSC_SLICE_WIDTH, dsc_slice_width);
    212 }
    213 
    214 /*TEMP: Need to figure out inheritance model here.*/
    215 bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
    216 {
    217 	return optc1_is_two_pixels_per_containter(timing);
    218 }
    219 
    220 void optc2_set_odm_bypass(struct timing_generator *optc,
    221 		const struct dc_crtc_timing *dc_crtc_timing)
    222 {
    223 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    224 	uint32_t h_div_2 = 0;
    225 
    226 	REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0,
    227 			OPTC_NUM_OF_INPUT_SEGMENT, 0,
    228 			OPTC_SEG0_SRC_SEL, optc->inst,
    229 			OPTC_SEG1_SRC_SEL, 0xf);
    230 	REG_WRITE(OTG_H_TIMING_CNTL, 0);
    231 
    232 	h_div_2 = optc2_is_two_pixels_per_containter(dc_crtc_timing);
    233 	REG_UPDATE(OTG_H_TIMING_CNTL,
    234 			OTG_H_TIMING_DIV_BY2, h_div_2);
    235 	REG_SET(OPTC_MEMORY_CONFIG, 0,
    236 			OPTC_MEM_SEL, 0);
    237 	optc1->opp_count = 1;
    238 }
    239 
    240 void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
    241 		struct dc_crtc_timing *timing)
    242 {
    243 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    244 	int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
    245 			/ opp_cnt;
    246 	uint32_t memory_mask;
    247 	uint32_t data_fmt = 0;
    248 
    249 	ASSERT(opp_cnt == 2);
    250 
    251 	/* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic
    252 	 * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1);
    253 	 * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start
    254 	 * REG_SET_2(OTG_GLOBAL_CONTROL1, 0,
    255 	 *		MASTER_UPDATE_LOCK_DB_X, 160,
    256 	 *		MASTER_UPDATE_LOCK_DB_Y, 240);
    257 	 */
    258 
    259 	/* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192,
    260 	 * however, for ODM combine we can simplify by always using 4.
    261 	 * To make sure there's no overlap, each instance "reserves" 2 memories and
    262 	 * they are uniquely combined here.
    263 	 */
    264 	memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2);
    265 
    266 	if (REG(OPTC_MEMORY_CONFIG))
    267 		REG_SET(OPTC_MEMORY_CONFIG, 0,
    268 			OPTC_MEM_SEL, memory_mask);
    269 
    270 	if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
    271 		data_fmt = 1;
    272 	else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
    273 		data_fmt = 2;
    274 
    275 	REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt);
    276 
    277 	REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0,
    278 			OPTC_NUM_OF_INPUT_SEGMENT, 1,
    279 			OPTC_SEG0_SRC_SEL, opp_id[0],
    280 			OPTC_SEG1_SRC_SEL, opp_id[1]);
    281 
    282 	REG_UPDATE(OPTC_WIDTH_CONTROL,
    283 			OPTC_SEGMENT_WIDTH, mpcc_hactive);
    284 
    285 	REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1);
    286 	optc1->opp_count = opp_cnt;
    287 }
    288 
    289 void optc2_get_optc_source(struct timing_generator *optc,
    290 		uint32_t *num_of_src_opp,
    291 		uint32_t *src_opp_id_0,
    292 		uint32_t *src_opp_id_1)
    293 {
    294 	uint32_t num_of_input_segments;
    295 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    296 
    297 	REG_GET_3(OPTC_DATA_SOURCE_SELECT,
    298 			OPTC_NUM_OF_INPUT_SEGMENT, &num_of_input_segments,
    299 			OPTC_SEG0_SRC_SEL, src_opp_id_0,
    300 			OPTC_SEG1_SRC_SEL, src_opp_id_1);
    301 
    302 	if (num_of_input_segments == 1)
    303 		*num_of_src_opp = 2;
    304 	else
    305 		*num_of_src_opp = 1;
    306 
    307 	/* Work around VBIOS not updating OPTC_NUM_OF_INPUT_SEGMENT */
    308 	if (*src_opp_id_1 == 0xf)
    309 		*num_of_src_opp = 1;
    310 }
    311 
    312 void optc2_set_dwb_source(struct timing_generator *optc,
    313 		uint32_t dwb_pipe_inst)
    314 {
    315 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    316 
    317 	if (dwb_pipe_inst == 0)
    318 		REG_UPDATE(DWB_SOURCE_SELECT,
    319 				OPTC_DWB0_SOURCE_SELECT, optc->inst);
    320 	else if (dwb_pipe_inst == 1)
    321 		REG_UPDATE(DWB_SOURCE_SELECT,
    322 				OPTC_DWB1_SOURCE_SELECT, optc->inst);
    323 }
    324 
    325 void optc2_triplebuffer_lock(struct timing_generator *optc)
    326 {
    327 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    328 
    329 	REG_SET(OTG_GLOBAL_CONTROL0, 0,
    330 		OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
    331 
    332 	REG_SET(OTG_VUPDATE_KEEPOUT, 0,
    333 		OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1);
    334 
    335 	REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
    336 		OTG_MASTER_UPDATE_LOCK, 1);
    337 
    338 	if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
    339 		REG_WAIT(OTG_MASTER_UPDATE_LOCK,
    340 				UPDATE_LOCK_STATUS, 1,
    341 				1, 10);
    342 }
    343 
    344 void optc2_triplebuffer_unlock(struct timing_generator *optc)
    345 {
    346 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    347 
    348 	REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
    349 		OTG_MASTER_UPDATE_LOCK, 0);
    350 
    351 	REG_SET(OTG_VUPDATE_KEEPOUT, 0,
    352 		OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0);
    353 
    354 }
    355 
    356 void optc2_lock_doublebuffer_enable(struct timing_generator *optc)
    357 {
    358 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    359 	uint32_t v_blank_start = 0;
    360 	uint32_t h_blank_start = 0;
    361 
    362 	REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 1);
    363 
    364 	REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1,
    365 			DIG_UPDATE_LOCATION, 20);
    366 
    367 	REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start);
    368 
    369 	REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start);
    370 
    371 	REG_UPDATE_2(OTG_GLOBAL_CONTROL1,
    372 			MASTER_UPDATE_LOCK_DB_X,
    373 			h_blank_start - 200 - 1,
    374 			MASTER_UPDATE_LOCK_DB_Y,
    375 			v_blank_start - 1);
    376 }
    377 
    378 void optc2_lock_doublebuffer_disable(struct timing_generator *optc)
    379 {
    380 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    381 
    382 	REG_UPDATE_2(OTG_GLOBAL_CONTROL1,
    383 				MASTER_UPDATE_LOCK_DB_X,
    384 				0,
    385 				MASTER_UPDATE_LOCK_DB_Y,
    386 				0);
    387 
    388 	REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0,
    389 				DIG_UPDATE_LOCATION, 0);
    390 
    391 	REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 0);
    392 }
    393 
    394 void optc2_setup_manual_trigger(struct timing_generator *optc)
    395 {
    396 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    397 
    398 	REG_SET_8(OTG_TRIGA_CNTL, 0,
    399 			OTG_TRIGA_SOURCE_SELECT, 21,
    400 			OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst,
    401 			OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1,
    402 			OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0,
    403 			OTG_TRIGA_POLARITY_SELECT, 0,
    404 			OTG_TRIGA_FREQUENCY_SELECT, 0,
    405 			OTG_TRIGA_DELAY, 0,
    406 			OTG_TRIGA_CLEAR, 1);
    407 }
    408 
    409 void optc2_program_manual_trigger(struct timing_generator *optc)
    410 {
    411 	struct optc *optc1 = DCN10TG_FROM_TG(optc);
    412 
    413 	REG_SET(OTG_TRIGA_MANUAL_TRIG, 0,
    414 			OTG_TRIGA_MANUAL_TRIG, 1);
    415 }
    416 
    417 static struct timing_generator_funcs dcn20_tg_funcs = {
    418 		.validate_timing = optc1_validate_timing,
    419 		.program_timing = optc1_program_timing,
    420 		.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
    421 		.setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1,
    422 		.setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2,
    423 		.program_global_sync = optc1_program_global_sync,
    424 		.enable_crtc = optc2_enable_crtc,
    425 		.disable_crtc = optc1_disable_crtc,
    426 		/* used by enable_timing_synchronization. Not need for FPGA */
    427 		.is_counter_moving = optc1_is_counter_moving,
    428 		.get_position = optc1_get_position,
    429 		.get_frame_count = optc1_get_vblank_counter,
    430 		.get_scanoutpos = optc1_get_crtc_scanoutpos,
    431 		.get_otg_active_size = optc1_get_otg_active_size,
    432 		.set_early_control = optc1_set_early_control,
    433 		/* used by enable_timing_synchronization. Not need for FPGA */
    434 		.wait_for_state = optc1_wait_for_state,
    435 		.set_blank = optc1_set_blank,
    436 		.is_blanked = optc1_is_blanked,
    437 		.set_blank_color = optc1_program_blank_color,
    438 		.enable_reset_trigger = optc1_enable_reset_trigger,
    439 		.enable_crtc_reset = optc1_enable_crtc_reset,
    440 		.did_triggered_reset_occur = optc1_did_triggered_reset_occur,
    441 		.triplebuffer_lock = optc2_triplebuffer_lock,
    442 		.triplebuffer_unlock = optc2_triplebuffer_unlock,
    443 		.disable_reset_trigger = optc1_disable_reset_trigger,
    444 		.lock = optc1_lock,
    445 		.unlock = optc1_unlock,
    446 		.lock_doublebuffer_enable = optc2_lock_doublebuffer_enable,
    447 		.lock_doublebuffer_disable = optc2_lock_doublebuffer_disable,
    448 		.enable_optc_clock = optc1_enable_optc_clock,
    449 		.set_drr = optc1_set_drr,
    450 		.set_static_screen_control = optc1_set_static_screen_control,
    451 		.program_stereo = optc1_program_stereo,
    452 		.is_stereo_left_eye = optc1_is_stereo_left_eye,
    453 		.set_blank_data_double_buffer = optc1_set_blank_data_double_buffer,
    454 		.tg_init = optc1_tg_init,
    455 		.is_tg_enabled = optc1_is_tg_enabled,
    456 		.is_optc_underflow_occurred = optc1_is_optc_underflow_occurred,
    457 		.clear_optc_underflow = optc1_clear_optc_underflow,
    458 		.setup_global_swap_lock = NULL,
    459 		.get_crc = optc1_get_crc,
    460 		.configure_crc = optc1_configure_crc,
    461 		.set_dsc_config = optc2_set_dsc_config,
    462 		.set_dwb_source = optc2_set_dwb_source,
    463 		.set_odm_bypass = optc2_set_odm_bypass,
    464 		.set_odm_combine = optc2_set_odm_combine,
    465 		.get_optc_source = optc2_get_optc_source,
    466 		.set_gsl = optc2_set_gsl,
    467 		.set_gsl_source_select = optc2_set_gsl_source_select,
    468 		.set_vtg_params = optc1_set_vtg_params,
    469 		.program_manual_trigger = optc2_program_manual_trigger,
    470 		.setup_manual_trigger = optc2_setup_manual_trigger,
    471 		.get_hw_timing = optc1_get_hw_timing,
    472 };
    473 
    474 void dcn20_timing_generator_init(struct optc *optc1)
    475 {
    476 	optc1->base.funcs = &dcn20_tg_funcs;
    477 
    478 	optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1;
    479 	optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1;
    480 
    481 	optc1->min_h_blank = 32;
    482 	optc1->min_v_blank = 3;
    483 	optc1->min_v_blank_interlace = 5;
    484 	optc1->min_h_sync_width = 4;//	Minimum HSYNC = 8 pixels asked By HW in the first place for no actual reason. Oculus Rift S will not light up with 8 as it's hsyncWidth is 6. Changing it to 4 to fix that issue.
    485 	optc1->min_v_sync_width = 1;
    486 }
    487 
    488