File Index
Files and directories
Sign in
FILE

dce110_timing_generator_v.c

File preview with syntax highlighting.

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