1254885Sdumbbell#include <sys/cdefs.h>
2254885Sdumbbell__FBSDID("$FreeBSD$");
3254885Sdumbbell
4254885Sdumbbell#include <dev/drm2/drmP.h>
5254885Sdumbbell#include <dev/drm2/drm_crtc_helper.h>
6254885Sdumbbell#include "radeon.h"
7254885Sdumbbell
8254885Sdumbbell/*
9254885Sdumbbell * Integrated TV out support based on the GATOS code by
10254885Sdumbbell * Federico Ulivi <fulivi@lycos.com>
11254885Sdumbbell */
12254885Sdumbbell
13254885Sdumbbell
14254885Sdumbbell/*
15254885Sdumbbell * Limits of h/v positions (hPos & vPos)
16254885Sdumbbell */
17254885Sdumbbell#define MAX_H_POSITION 5 /* Range: [-5..5], negative is on the left, 0 is default, positive is on the right */
18254885Sdumbbell#define MAX_V_POSITION 5 /* Range: [-5..5], negative is up, 0 is default, positive is down */
19254885Sdumbbell
20254885Sdumbbell/*
21254885Sdumbbell * Unit for hPos (in TV clock periods)
22254885Sdumbbell */
23254885Sdumbbell#define H_POS_UNIT 10
24254885Sdumbbell
25254885Sdumbbell/*
26254885Sdumbbell * Indexes in h. code timing table for horizontal line position adjustment
27254885Sdumbbell */
28254885Sdumbbell#define H_TABLE_POS1 6
29254885Sdumbbell#define H_TABLE_POS2 8
30254885Sdumbbell
31254885Sdumbbell/*
32254885Sdumbbell * Limits of hor. size (hSize)
33254885Sdumbbell */
34254885Sdumbbell#define MAX_H_SIZE 5 /* Range: [-5..5], negative is smaller, positive is larger */
35254885Sdumbbell
36254885Sdumbbell/* tv standard constants */
37254885Sdumbbell#define NTSC_TV_CLOCK_T 233
38254885Sdumbbell#define NTSC_TV_VFTOTAL 1
39254885Sdumbbell#define NTSC_TV_LINES_PER_FRAME 525
40254885Sdumbbell#define NTSC_TV_ZERO_H_SIZE 479166
41254885Sdumbbell#define NTSC_TV_H_SIZE_UNIT 9478
42254885Sdumbbell
43254885Sdumbbell#define PAL_TV_CLOCK_T 188
44254885Sdumbbell#define PAL_TV_VFTOTAL 3
45254885Sdumbbell#define PAL_TV_LINES_PER_FRAME 625
46254885Sdumbbell#define PAL_TV_ZERO_H_SIZE 473200
47254885Sdumbbell#define PAL_TV_H_SIZE_UNIT 9360
48254885Sdumbbell
49254885Sdumbbell/* tv pll setting for 27 mhz ref clk */
50254885Sdumbbell#define NTSC_TV_PLL_M_27 22
51254885Sdumbbell#define NTSC_TV_PLL_N_27 175
52254885Sdumbbell#define NTSC_TV_PLL_P_27 5
53254885Sdumbbell
54254885Sdumbbell#define PAL_TV_PLL_M_27 113
55254885Sdumbbell#define PAL_TV_PLL_N_27 668
56254885Sdumbbell#define PAL_TV_PLL_P_27 3
57254885Sdumbbell
58254885Sdumbbell/* tv pll setting for 14 mhz ref clk */
59254885Sdumbbell#define NTSC_TV_PLL_M_14 33
60254885Sdumbbell#define NTSC_TV_PLL_N_14 693
61254885Sdumbbell#define NTSC_TV_PLL_P_14 7
62254885Sdumbbell
63254885Sdumbbell#define PAL_TV_PLL_M_14 19
64254885Sdumbbell#define PAL_TV_PLL_N_14 353
65254885Sdumbbell#define PAL_TV_PLL_P_14 5
66254885Sdumbbell
67254885Sdumbbell#define VERT_LEAD_IN_LINES 2
68254885Sdumbbell#define FRAC_BITS 0xe
69254885Sdumbbell#define FRAC_MASK 0x3fff
70254885Sdumbbell
71254885Sdumbbellstruct radeon_tv_mode_constants {
72254885Sdumbbell	uint16_t hor_resolution;
73254885Sdumbbell	uint16_t ver_resolution;
74254885Sdumbbell	enum radeon_tv_std standard;
75254885Sdumbbell	uint16_t hor_total;
76254885Sdumbbell	uint16_t ver_total;
77254885Sdumbbell	uint16_t hor_start;
78254885Sdumbbell	uint16_t hor_syncstart;
79254885Sdumbbell	uint16_t ver_syncstart;
80254885Sdumbbell	unsigned def_restart;
81254885Sdumbbell	uint16_t crtcPLL_N;
82254885Sdumbbell	uint8_t  crtcPLL_M;
83254885Sdumbbell	uint8_t  crtcPLL_post_div;
84254885Sdumbbell	unsigned pix_to_tv;
85254885Sdumbbell};
86254885Sdumbbell
87254885Sdumbbellstatic const uint16_t hor_timing_NTSC[MAX_H_CODE_TIMING_LEN] = {
88254885Sdumbbell	0x0007,
89254885Sdumbbell	0x003f,
90254885Sdumbbell	0x0263,
91254885Sdumbbell	0x0a24,
92254885Sdumbbell	0x2a6b,
93254885Sdumbbell	0x0a36,
94254885Sdumbbell	0x126d, /* H_TABLE_POS1 */
95254885Sdumbbell	0x1bfe,
96254885Sdumbbell	0x1a8f, /* H_TABLE_POS2 */
97254885Sdumbbell	0x1ec7,
98254885Sdumbbell	0x3863,
99254885Sdumbbell	0x1bfe,
100254885Sdumbbell	0x1bfe,
101254885Sdumbbell	0x1a2a,
102254885Sdumbbell	0x1e95,
103254885Sdumbbell	0x0e31,
104254885Sdumbbell	0x201b,
105254885Sdumbbell	0
106254885Sdumbbell};
107254885Sdumbbell
108254885Sdumbbellstatic const uint16_t vert_timing_NTSC[MAX_V_CODE_TIMING_LEN] = {
109254885Sdumbbell	0x2001,
110254885Sdumbbell	0x200d,
111254885Sdumbbell	0x1006,
112254885Sdumbbell	0x0c06,
113254885Sdumbbell	0x1006,
114254885Sdumbbell	0x1818,
115254885Sdumbbell	0x21e3,
116254885Sdumbbell	0x1006,
117254885Sdumbbell	0x0c06,
118254885Sdumbbell	0x1006,
119254885Sdumbbell	0x1817,
120254885Sdumbbell	0x21d4,
121254885Sdumbbell	0x0002,
122254885Sdumbbell	0
123254885Sdumbbell};
124254885Sdumbbell
125254885Sdumbbellstatic const uint16_t hor_timing_PAL[MAX_H_CODE_TIMING_LEN] = {
126254885Sdumbbell	0x0007,
127254885Sdumbbell	0x0058,
128254885Sdumbbell	0x027c,
129254885Sdumbbell	0x0a31,
130254885Sdumbbell	0x2a77,
131254885Sdumbbell	0x0a95,
132254885Sdumbbell	0x124f, /* H_TABLE_POS1 */
133254885Sdumbbell	0x1bfe,
134254885Sdumbbell	0x1b22, /* H_TABLE_POS2 */
135254885Sdumbbell	0x1ef9,
136254885Sdumbbell	0x387c,
137254885Sdumbbell	0x1bfe,
138254885Sdumbbell	0x1bfe,
139254885Sdumbbell	0x1b31,
140254885Sdumbbell	0x1eb5,
141254885Sdumbbell	0x0e43,
142254885Sdumbbell	0x201b,
143254885Sdumbbell	0
144254885Sdumbbell};
145254885Sdumbbell
146254885Sdumbbellstatic const uint16_t vert_timing_PAL[MAX_V_CODE_TIMING_LEN] = {
147254885Sdumbbell	0x2001,
148254885Sdumbbell	0x200c,
149254885Sdumbbell	0x1005,
150254885Sdumbbell	0x0c05,
151254885Sdumbbell	0x1005,
152254885Sdumbbell	0x1401,
153254885Sdumbbell	0x1821,
154254885Sdumbbell	0x2240,
155254885Sdumbbell	0x1005,
156254885Sdumbbell	0x0c05,
157254885Sdumbbell	0x1005,
158254885Sdumbbell	0x1401,
159254885Sdumbbell	0x1822,
160254885Sdumbbell	0x2230,
161254885Sdumbbell	0x0002,
162254885Sdumbbell	0
163254885Sdumbbell};
164254885Sdumbbell
165254885Sdumbbell/**********************************************************************
166254885Sdumbbell *
167254885Sdumbbell * availableModes
168254885Sdumbbell *
169254885Sdumbbell * Table of all allowed modes for tv output
170254885Sdumbbell *
171254885Sdumbbell **********************************************************************/
172254885Sdumbbellstatic const struct radeon_tv_mode_constants available_tv_modes[] = {
173254885Sdumbbell	{   /* NTSC timing for 27 Mhz ref clk */
174254885Sdumbbell		800,                /* horResolution */
175254885Sdumbbell		600,                /* verResolution */
176254885Sdumbbell		TV_STD_NTSC,        /* standard */
177254885Sdumbbell		990,                /* horTotal */
178254885Sdumbbell		740,                /* verTotal */
179254885Sdumbbell		813,                /* horStart */
180254885Sdumbbell		824,                /* horSyncStart */
181254885Sdumbbell		632,                /* verSyncStart */
182254885Sdumbbell		625592,             /* defRestart */
183254885Sdumbbell		592,                /* crtcPLL_N */
184254885Sdumbbell		91,                 /* crtcPLL_M */
185254885Sdumbbell		4,                  /* crtcPLL_postDiv */
186254885Sdumbbell		1022,               /* pixToTV */
187254885Sdumbbell	},
188254885Sdumbbell	{   /* PAL timing for 27 Mhz ref clk */
189254885Sdumbbell		800,               /* horResolution */
190254885Sdumbbell		600,               /* verResolution */
191254885Sdumbbell		TV_STD_PAL,        /* standard */
192254885Sdumbbell		1144,              /* horTotal */
193254885Sdumbbell		706,               /* verTotal */
194254885Sdumbbell		812,               /* horStart */
195254885Sdumbbell		824,               /* horSyncStart */
196254885Sdumbbell		669,               /* verSyncStart */
197254885Sdumbbell		696700,            /* defRestart */
198254885Sdumbbell		1382,              /* crtcPLL_N */
199254885Sdumbbell		231,               /* crtcPLL_M */
200254885Sdumbbell		4,                 /* crtcPLL_postDiv */
201254885Sdumbbell		759,               /* pixToTV */
202254885Sdumbbell	},
203254885Sdumbbell	{   /* NTSC timing for 14 Mhz ref clk */
204254885Sdumbbell		800,                /* horResolution */
205254885Sdumbbell		600,                /* verResolution */
206254885Sdumbbell		TV_STD_NTSC,        /* standard */
207254885Sdumbbell		1018,               /* horTotal */
208254885Sdumbbell		727,                /* verTotal */
209254885Sdumbbell		813,                /* horStart */
210254885Sdumbbell		840,                /* horSyncStart */
211254885Sdumbbell		633,                /* verSyncStart */
212254885Sdumbbell		630627,             /* defRestart */
213254885Sdumbbell		347,                /* crtcPLL_N */
214254885Sdumbbell		14,                 /* crtcPLL_M */
215254885Sdumbbell		8,                  /* crtcPLL_postDiv */
216254885Sdumbbell		1022,               /* pixToTV */
217254885Sdumbbell	},
218254885Sdumbbell	{ /* PAL timing for 14 Mhz ref clk */
219254885Sdumbbell		800,                /* horResolution */
220254885Sdumbbell		600,                /* verResolution */
221254885Sdumbbell		TV_STD_PAL,         /* standard */
222254885Sdumbbell		1131,               /* horTotal */
223254885Sdumbbell		742,                /* verTotal */
224254885Sdumbbell		813,                /* horStart */
225254885Sdumbbell		840,                /* horSyncStart */
226254885Sdumbbell		633,                /* verSyncStart */
227254885Sdumbbell		708369,             /* defRestart */
228254885Sdumbbell		211,                /* crtcPLL_N */
229254885Sdumbbell		9,                  /* crtcPLL_M */
230254885Sdumbbell		8,                  /* crtcPLL_postDiv */
231254885Sdumbbell		759,                /* pixToTV */
232254885Sdumbbell	},
233254885Sdumbbell};
234254885Sdumbbell
235254885Sdumbbell#define N_AVAILABLE_MODES DRM_ARRAY_SIZE(available_tv_modes)
236254885Sdumbbell
237254885Sdumbbellstatic const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(struct radeon_encoder *radeon_encoder,
238254885Sdumbbell									    uint16_t *pll_ref_freq)
239254885Sdumbbell{
240254885Sdumbbell	struct drm_device *dev = radeon_encoder->base.dev;
241254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
242254885Sdumbbell	struct radeon_crtc *radeon_crtc;
243254885Sdumbbell	struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
244254885Sdumbbell	const struct radeon_tv_mode_constants *const_ptr;
245254885Sdumbbell	struct radeon_pll *pll;
246254885Sdumbbell
247254885Sdumbbell	radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc);
248254885Sdumbbell	if (radeon_crtc->crtc_id == 1)
249254885Sdumbbell		pll = &rdev->clock.p2pll;
250254885Sdumbbell	else
251254885Sdumbbell		pll = &rdev->clock.p1pll;
252254885Sdumbbell
253254885Sdumbbell	if (pll_ref_freq)
254254885Sdumbbell		*pll_ref_freq = pll->reference_freq;
255254885Sdumbbell
256254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
257254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
258254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M) {
259254885Sdumbbell		if (pll->reference_freq == 2700)
260254885Sdumbbell			const_ptr = &available_tv_modes[0];
261254885Sdumbbell		else
262254885Sdumbbell			const_ptr = &available_tv_modes[2];
263254885Sdumbbell	} else {
264254885Sdumbbell		if (pll->reference_freq == 2700)
265254885Sdumbbell			const_ptr = &available_tv_modes[1];
266254885Sdumbbell		else
267254885Sdumbbell			const_ptr = &available_tv_modes[3];
268254885Sdumbbell	}
269254885Sdumbbell	return const_ptr;
270254885Sdumbbell}
271254885Sdumbbell
272254885Sdumbbellstatic long YCOEF_value[5] = { 2, 2, 0, 4, 0 };
273254885Sdumbbellstatic long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 };
274254885Sdumbbellstatic long SLOPE_value[5] = { 1, 2, 2, 4, 8 };
275254885Sdumbbellstatic long SLOPE_limit[5] = { 6, 5, 4, 3, 2 };
276254885Sdumbbell
277254885Sdumbbellstatic void radeon_wait_pll_lock(struct drm_encoder *encoder, unsigned n_tests,
278254885Sdumbbell				 unsigned n_wait_loops, unsigned cnt_threshold)
279254885Sdumbbell{
280254885Sdumbbell	struct drm_device *dev = encoder->dev;
281254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
282254885Sdumbbell	uint32_t save_pll_test;
283254885Sdumbbell	unsigned int i, j;
284254885Sdumbbell
285254885Sdumbbell	WREG32(RADEON_TEST_DEBUG_MUX, (RREG32(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100);
286254885Sdumbbell	save_pll_test = RREG32_PLL(RADEON_PLL_TEST_CNTL);
287254885Sdumbbell	WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test & ~RADEON_PLL_MASK_READ_B);
288254885Sdumbbell
289254885Sdumbbell	WREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL);
290254885Sdumbbell	for (i = 0; i < n_tests; i++) {
291254885Sdumbbell		WREG8(RADEON_CLOCK_CNTL_DATA + 3, 0);
292254885Sdumbbell		for (j = 0; j < n_wait_loops; j++)
293254885Sdumbbell			if (RREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cnt_threshold)
294254885Sdumbbell				break;
295254885Sdumbbell	}
296254885Sdumbbell	WREG32_PLL(RADEON_PLL_TEST_CNTL, save_pll_test);
297254885Sdumbbell	WREG32(RADEON_TEST_DEBUG_MUX, RREG32(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff);
298254885Sdumbbell}
299254885Sdumbbell
300254885Sdumbbell
301254885Sdumbbellstatic void radeon_legacy_tv_write_fifo(struct radeon_encoder *radeon_encoder,
302254885Sdumbbell					uint16_t addr, uint32_t value)
303254885Sdumbbell{
304254885Sdumbbell	struct drm_device *dev = radeon_encoder->base.dev;
305254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
306254885Sdumbbell	uint32_t tmp;
307254885Sdumbbell	int i = 0;
308254885Sdumbbell
309254885Sdumbbell	WREG32(RADEON_TV_HOST_WRITE_DATA, value);
310254885Sdumbbell
311254885Sdumbbell	WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr);
312254885Sdumbbell	WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT);
313254885Sdumbbell
314254885Sdumbbell	do {
315254885Sdumbbell		tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL);
316254885Sdumbbell		if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0)
317254885Sdumbbell			break;
318254885Sdumbbell		i++;
319254885Sdumbbell	} while (i < 10000);
320254885Sdumbbell	WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0);
321254885Sdumbbell}
322254885Sdumbbell
323254885Sdumbbell#if 0 /* included for completeness */
324254885Sdumbbellstatic uint32_t radeon_legacy_tv_read_fifo(struct radeon_encoder *radeon_encoder, uint16_t addr)
325254885Sdumbbell{
326254885Sdumbbell	struct drm_device *dev = radeon_encoder->base.dev;
327254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
328254885Sdumbbell	uint32_t tmp;
329254885Sdumbbell	int i = 0;
330254885Sdumbbell
331254885Sdumbbell	WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr);
332254885Sdumbbell	WREG32(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD);
333254885Sdumbbell
334254885Sdumbbell	do {
335254885Sdumbbell		tmp = RREG32(RADEON_TV_HOST_RD_WT_CNTL);
336254885Sdumbbell		if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0)
337254885Sdumbbell			break;
338254885Sdumbbell		i++;
339254885Sdumbbell	} while (i < 10000);
340254885Sdumbbell	WREG32(RADEON_TV_HOST_RD_WT_CNTL, 0);
341254885Sdumbbell	return RREG32(RADEON_TV_HOST_READ_DATA);
342254885Sdumbbell}
343254885Sdumbbell#endif
344254885Sdumbbell
345254885Sdumbbellstatic uint16_t radeon_get_htiming_tables_addr(uint32_t tv_uv_adr)
346254885Sdumbbell{
347254885Sdumbbell	uint16_t h_table;
348254885Sdumbbell
349254885Sdumbbell	switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) {
350254885Sdumbbell	case 0:
351254885Sdumbbell		h_table = RADEON_TV_MAX_FIFO_ADDR_INTERNAL;
352254885Sdumbbell		break;
353254885Sdumbbell	case 1:
354254885Sdumbbell		h_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2;
355254885Sdumbbell		break;
356254885Sdumbbell	case 2:
357254885Sdumbbell		h_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2;
358254885Sdumbbell		break;
359254885Sdumbbell	default:
360254885Sdumbbell		h_table = 0;
361254885Sdumbbell		break;
362254885Sdumbbell	}
363254885Sdumbbell	return h_table;
364254885Sdumbbell}
365254885Sdumbbell
366254885Sdumbbellstatic uint16_t radeon_get_vtiming_tables_addr(uint32_t tv_uv_adr)
367254885Sdumbbell{
368254885Sdumbbell	uint16_t v_table;
369254885Sdumbbell
370254885Sdumbbell	switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) {
371254885Sdumbbell	case 0:
372254885Sdumbbell		v_table = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1;
373254885Sdumbbell		break;
374254885Sdumbbell	case 1:
375254885Sdumbbell		v_table = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
376254885Sdumbbell		break;
377254885Sdumbbell	case 2:
378254885Sdumbbell		v_table = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
379254885Sdumbbell		break;
380254885Sdumbbell	default:
381254885Sdumbbell		v_table = 0;
382254885Sdumbbell		break;
383254885Sdumbbell	}
384254885Sdumbbell	return v_table;
385254885Sdumbbell}
386254885Sdumbbell
387254885Sdumbbellstatic void radeon_restore_tv_timing_tables(struct radeon_encoder *radeon_encoder)
388254885Sdumbbell{
389254885Sdumbbell	struct drm_device *dev = radeon_encoder->base.dev;
390254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
391254885Sdumbbell	struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
392254885Sdumbbell	uint16_t h_table, v_table;
393254885Sdumbbell	uint32_t tmp;
394254885Sdumbbell	int i;
395254885Sdumbbell
396254885Sdumbbell	WREG32(RADEON_TV_UV_ADR, tv_dac->tv.tv_uv_adr);
397254885Sdumbbell	h_table = radeon_get_htiming_tables_addr(tv_dac->tv.tv_uv_adr);
398254885Sdumbbell	v_table = radeon_get_vtiming_tables_addr(tv_dac->tv.tv_uv_adr);
399254885Sdumbbell
400254885Sdumbbell	for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, h_table--) {
401254885Sdumbbell		tmp = ((uint32_t)tv_dac->tv.h_code_timing[i] << 14) | ((uint32_t)tv_dac->tv.h_code_timing[i+1]);
402254885Sdumbbell		radeon_legacy_tv_write_fifo(radeon_encoder, h_table, tmp);
403254885Sdumbbell		if (tv_dac->tv.h_code_timing[i] == 0 || tv_dac->tv.h_code_timing[i + 1] == 0)
404254885Sdumbbell			break;
405254885Sdumbbell	}
406254885Sdumbbell	for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, v_table++) {
407254885Sdumbbell		tmp = ((uint32_t)tv_dac->tv.v_code_timing[i+1] << 14) | ((uint32_t)tv_dac->tv.v_code_timing[i]);
408254885Sdumbbell		radeon_legacy_tv_write_fifo(radeon_encoder, v_table, tmp);
409254885Sdumbbell		if (tv_dac->tv.v_code_timing[i] == 0 || tv_dac->tv.v_code_timing[i + 1] == 0)
410254885Sdumbbell			break;
411254885Sdumbbell	}
412254885Sdumbbell}
413254885Sdumbbell
414254885Sdumbbellstatic void radeon_legacy_write_tv_restarts(struct radeon_encoder *radeon_encoder)
415254885Sdumbbell{
416254885Sdumbbell	struct drm_device *dev = radeon_encoder->base.dev;
417254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
418254885Sdumbbell	struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
419254885Sdumbbell	WREG32(RADEON_TV_FRESTART, tv_dac->tv.frestart);
420254885Sdumbbell	WREG32(RADEON_TV_HRESTART, tv_dac->tv.hrestart);
421254885Sdumbbell	WREG32(RADEON_TV_VRESTART, tv_dac->tv.vrestart);
422254885Sdumbbell}
423254885Sdumbbell
424254885Sdumbbellstatic bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder)
425254885Sdumbbell{
426254885Sdumbbell	struct drm_device *dev = encoder->dev;
427254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
428254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
429254885Sdumbbell	struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
430254885Sdumbbell	struct radeon_crtc *radeon_crtc;
431254885Sdumbbell	int restart;
432254885Sdumbbell	unsigned int h_total, v_total, f_total;
433254885Sdumbbell	int v_offset, h_offset;
434254885Sdumbbell	u16 p1, p2, h_inc;
435254885Sdumbbell	bool h_changed;
436254885Sdumbbell	const struct radeon_tv_mode_constants *const_ptr;
437254885Sdumbbell	struct radeon_pll *pll;
438254885Sdumbbell
439254885Sdumbbell	radeon_crtc = to_radeon_crtc(radeon_encoder->base.crtc);
440254885Sdumbbell	if (radeon_crtc->crtc_id == 1)
441254885Sdumbbell		pll = &rdev->clock.p2pll;
442254885Sdumbbell	else
443254885Sdumbbell		pll = &rdev->clock.p1pll;
444254885Sdumbbell
445254885Sdumbbell	const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
446254885Sdumbbell	if (!const_ptr)
447254885Sdumbbell		return false;
448254885Sdumbbell
449254885Sdumbbell	h_total = const_ptr->hor_total;
450254885Sdumbbell	v_total = const_ptr->ver_total;
451254885Sdumbbell
452254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
453254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
454254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M ||
455254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_60)
456254885Sdumbbell		f_total = NTSC_TV_VFTOTAL + 1;
457254885Sdumbbell	else
458254885Sdumbbell		f_total = PAL_TV_VFTOTAL + 1;
459254885Sdumbbell
460254885Sdumbbell	/* adjust positions 1&2 in hor. cod timing table */
461254885Sdumbbell	h_offset = tv_dac->h_pos * H_POS_UNIT;
462254885Sdumbbell
463254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
464254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
465254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M) {
466254885Sdumbbell		h_offset -= 50;
467254885Sdumbbell		p1 = hor_timing_NTSC[H_TABLE_POS1];
468254885Sdumbbell		p2 = hor_timing_NTSC[H_TABLE_POS2];
469254885Sdumbbell	} else {
470254885Sdumbbell		p1 = hor_timing_PAL[H_TABLE_POS1];
471254885Sdumbbell		p2 = hor_timing_PAL[H_TABLE_POS2];
472254885Sdumbbell	}
473254885Sdumbbell
474254885Sdumbbell	p1 = (u16)((int)p1 + h_offset);
475254885Sdumbbell	p2 = (u16)((int)p2 - h_offset);
476254885Sdumbbell
477254885Sdumbbell	h_changed = (p1 != tv_dac->tv.h_code_timing[H_TABLE_POS1] ||
478254885Sdumbbell		     p2 != tv_dac->tv.h_code_timing[H_TABLE_POS2]);
479254885Sdumbbell
480254885Sdumbbell	tv_dac->tv.h_code_timing[H_TABLE_POS1] = p1;
481254885Sdumbbell	tv_dac->tv.h_code_timing[H_TABLE_POS2] = p2;
482254885Sdumbbell
483254885Sdumbbell	/* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */
484254885Sdumbbell	h_offset = (h_offset * (int)(const_ptr->pix_to_tv)) / 1000;
485254885Sdumbbell
486254885Sdumbbell	/* adjust restart */
487254885Sdumbbell	restart = const_ptr->def_restart;
488254885Sdumbbell
489254885Sdumbbell	/*
490254885Sdumbbell	 * convert v_pos TV lines to n. of CRTC pixels
491254885Sdumbbell	 */
492254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
493254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
494254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M ||
495254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_60)
496254885Sdumbbell		v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(NTSC_TV_LINES_PER_FRAME);
497254885Sdumbbell	else
498254885Sdumbbell		v_offset = ((int)(v_total * h_total) * 2 * tv_dac->v_pos) / (int)(PAL_TV_LINES_PER_FRAME);
499254885Sdumbbell
500254885Sdumbbell	restart -= v_offset + h_offset;
501254885Sdumbbell
502254885Sdumbbell	DRM_DEBUG_KMS("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n",
503254885Sdumbbell		  const_ptr->def_restart, tv_dac->h_pos, tv_dac->v_pos, p1, p2, restart);
504254885Sdumbbell
505254885Sdumbbell	tv_dac->tv.hrestart = restart % h_total;
506254885Sdumbbell	restart /= h_total;
507254885Sdumbbell	tv_dac->tv.vrestart = restart % v_total;
508254885Sdumbbell	restart /= v_total;
509254885Sdumbbell	tv_dac->tv.frestart = restart % f_total;
510254885Sdumbbell
511254885Sdumbbell	DRM_DEBUG_KMS("compute_restart: F/H/V=%u,%u,%u\n",
512254885Sdumbbell		  (unsigned)tv_dac->tv.frestart,
513254885Sdumbbell		  (unsigned)tv_dac->tv.vrestart,
514254885Sdumbbell		  (unsigned)tv_dac->tv.hrestart);
515254885Sdumbbell
516254885Sdumbbell	/* compute h_inc from hsize */
517254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
518254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
519254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M)
520254885Sdumbbell		h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * NTSC_TV_CLOCK_T) /
521254885Sdumbbell			      (tv_dac->h_size * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE)));
522254885Sdumbbell	else
523254885Sdumbbell		h_inc = (u16)((int)(const_ptr->hor_resolution * 4096 * PAL_TV_CLOCK_T) /
524254885Sdumbbell			      (tv_dac->h_size * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE)));
525254885Sdumbbell
526254885Sdumbbell	tv_dac->tv.timing_cntl = (tv_dac->tv.timing_cntl & ~RADEON_H_INC_MASK) |
527254885Sdumbbell		((u32)h_inc << RADEON_H_INC_SHIFT);
528254885Sdumbbell
529254885Sdumbbell	DRM_DEBUG_KMS("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc);
530254885Sdumbbell
531254885Sdumbbell	return h_changed;
532254885Sdumbbell}
533254885Sdumbbell
534254885Sdumbbellvoid radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
535254885Sdumbbell			       struct drm_display_mode *mode,
536254885Sdumbbell			       struct drm_display_mode *adjusted_mode)
537254885Sdumbbell{
538254885Sdumbbell	struct drm_device *dev = encoder->dev;
539254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
540254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
541254885Sdumbbell	struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
542254885Sdumbbell	const struct radeon_tv_mode_constants *const_ptr;
543254885Sdumbbell	struct radeon_crtc *radeon_crtc;
544254885Sdumbbell	int i;
545254885Sdumbbell	uint16_t pll_ref_freq;
546254885Sdumbbell	uint32_t vert_space, flicker_removal, tmp;
547254885Sdumbbell	uint32_t tv_master_cntl, tv_rgb_cntl, tv_dac_cntl;
548254885Sdumbbell	uint32_t tv_modulator_cntl1, tv_modulator_cntl2;
549254885Sdumbbell	uint32_t tv_vscaler_cntl1, tv_vscaler_cntl2;
550254885Sdumbbell	uint32_t tv_pll_cntl, tv_pll_cntl1, tv_ftotal;
551254885Sdumbbell	uint32_t tv_y_fall_cntl, tv_y_rise_cntl, tv_y_saw_tooth_cntl;
552254885Sdumbbell	uint32_t m, n, p;
553254885Sdumbbell	const uint16_t *hor_timing;
554254885Sdumbbell	const uint16_t *vert_timing;
555254885Sdumbbell
556254885Sdumbbell	const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, &pll_ref_freq);
557254885Sdumbbell	if (!const_ptr)
558254885Sdumbbell		return;
559254885Sdumbbell
560254885Sdumbbell	radeon_crtc = to_radeon_crtc(encoder->crtc);
561254885Sdumbbell
562254885Sdumbbell	tv_master_cntl = (RADEON_VIN_ASYNC_RST |
563254885Sdumbbell			  RADEON_CRT_FIFO_CE_EN |
564254885Sdumbbell			  RADEON_TV_FIFO_CE_EN |
565254885Sdumbbell			  RADEON_TV_ON);
566254885Sdumbbell
567254885Sdumbbell	if (!ASIC_IS_R300(rdev))
568254885Sdumbbell		tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb;
569254885Sdumbbell
570254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
571254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J)
572254885Sdumbbell		tv_master_cntl |= RADEON_RESTART_PHASE_FIX;
573254885Sdumbbell
574254885Sdumbbell	tv_modulator_cntl1 = (RADEON_SLEW_RATE_LIMIT |
575254885Sdumbbell			      RADEON_SYNC_TIP_LEVEL |
576254885Sdumbbell			      RADEON_YFLT_EN |
577254885Sdumbbell			      RADEON_UVFLT_EN |
578254885Sdumbbell			      (6 << RADEON_CY_FILT_BLEND_SHIFT));
579254885Sdumbbell
580254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
581254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J) {
582254885Sdumbbell		tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT) |
583254885Sdumbbell			(0x3b << RADEON_BLANK_LEVEL_SHIFT);
584254885Sdumbbell		tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) |
585254885Sdumbbell			((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
586254885Sdumbbell	} else if (tv_dac->tv_std == TV_STD_SCART_PAL) {
587254885Sdumbbell		tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN;
588254885Sdumbbell		tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) |
589254885Sdumbbell			((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
590254885Sdumbbell	} else {
591254885Sdumbbell		tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN |
592254885Sdumbbell			(0x3b << RADEON_SET_UP_LEVEL_SHIFT) |
593254885Sdumbbell			(0x3b << RADEON_BLANK_LEVEL_SHIFT);
594254885Sdumbbell		tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) |
595254885Sdumbbell			((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
596254885Sdumbbell	}
597254885Sdumbbell
598254885Sdumbbell
599254885Sdumbbell	tv_rgb_cntl = (RADEON_RGB_DITHER_EN
600254885Sdumbbell		       | RADEON_TVOUT_SCALE_EN
601254885Sdumbbell		       | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT)
602254885Sdumbbell		       | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT)
603254885Sdumbbell		       | RADEON_RGB_ATTEN_SEL(0x3)
604254885Sdumbbell		       | RADEON_RGB_ATTEN_VAL(0xc));
605254885Sdumbbell
606254885Sdumbbell	if (radeon_crtc->crtc_id == 1)
607254885Sdumbbell		tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2;
608254885Sdumbbell	else {
609254885Sdumbbell		if (radeon_crtc->rmx_type != RMX_OFF)
610254885Sdumbbell			tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX;
611254885Sdumbbell		else
612254885Sdumbbell			tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1;
613254885Sdumbbell	}
614254885Sdumbbell
615254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
616254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
617254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M ||
618254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_60)
619254885Sdumbbell		vert_space = const_ptr->ver_total * 2 * 10000 / NTSC_TV_LINES_PER_FRAME;
620254885Sdumbbell	else
621254885Sdumbbell		vert_space = const_ptr->ver_total * 2 * 10000 / PAL_TV_LINES_PER_FRAME;
622254885Sdumbbell
623254885Sdumbbell	tmp = RREG32(RADEON_TV_VSCALER_CNTL1);
624254885Sdumbbell	tmp &= 0xe3ff0000;
625254885Sdumbbell	tmp |= (vert_space * (1 << FRAC_BITS) / 10000);
626254885Sdumbbell	tv_vscaler_cntl1 = tmp;
627254885Sdumbbell
628254885Sdumbbell	if (pll_ref_freq == 2700)
629254885Sdumbbell		tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
630254885Sdumbbell
631254885Sdumbbell	if (const_ptr->hor_resolution == 1024)
632254885Sdumbbell		tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT);
633254885Sdumbbell	else
634254885Sdumbbell		tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT);
635254885Sdumbbell
636254885Sdumbbell	/* scale up for int divide */
637254885Sdumbbell	tmp = const_ptr->ver_total * 2 * 1000;
638254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
639254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
640254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M ||
641254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_60) {
642254885Sdumbbell		tmp /= NTSC_TV_LINES_PER_FRAME;
643254885Sdumbbell	} else {
644254885Sdumbbell		tmp /= PAL_TV_LINES_PER_FRAME;
645254885Sdumbbell	}
646254885Sdumbbell	flicker_removal = (tmp + 500) / 1000;
647254885Sdumbbell
648254885Sdumbbell	if (flicker_removal < 3)
649254885Sdumbbell		flicker_removal = 3;
650254885Sdumbbell	for (i = 0; i < DRM_ARRAY_SIZE(SLOPE_limit); ++i) {
651254885Sdumbbell		if (flicker_removal == SLOPE_limit[i])
652254885Sdumbbell			break;
653254885Sdumbbell	}
654254885Sdumbbell
655254885Sdumbbell	tv_y_saw_tooth_cntl = (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) +
656254885Sdumbbell				5001) / 10000 / 8 | ((SLOPE_value[i] *
657254885Sdumbbell				(1 << (FRAC_BITS - 1)) / 8) << 16);
658254885Sdumbbell	tv_y_fall_cntl =
659254885Sdumbbell		(YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) |
660254885Sdumbbell		RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) /
661254885Sdumbbell		1024;
662254885Sdumbbell	tv_y_rise_cntl = RADEON_Y_RISE_PING_PONG|
663254885Sdumbbell		(flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024;
664254885Sdumbbell
665254885Sdumbbell	tv_vscaler_cntl2 = RREG32(RADEON_TV_VSCALER_CNTL2) & 0x00fffff0;
666254885Sdumbbell	tv_vscaler_cntl2 |= (0x10 << 24) |
667254885Sdumbbell		RADEON_DITHER_MODE |
668254885Sdumbbell		RADEON_Y_OUTPUT_DITHER_EN |
669254885Sdumbbell		RADEON_UV_OUTPUT_DITHER_EN |
670254885Sdumbbell		RADEON_UV_TO_BUF_DITHER_EN;
671254885Sdumbbell
672254885Sdumbbell	tmp = (tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
673254885Sdumbbell	tmp = ((16384 * 256 * 10) / tmp + 5) / 10;
674254885Sdumbbell	tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
675254885Sdumbbell	tv_dac->tv.timing_cntl = tmp;
676254885Sdumbbell
677254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
678254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
679254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M ||
680254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_60)
681254885Sdumbbell		tv_dac_cntl = tv_dac->ntsc_tvdac_adj;
682254885Sdumbbell	else
683254885Sdumbbell		tv_dac_cntl = tv_dac->pal_tvdac_adj;
684254885Sdumbbell
685254885Sdumbbell	tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD;
686254885Sdumbbell
687254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
688254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J)
689254885Sdumbbell		tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
690254885Sdumbbell	else
691254885Sdumbbell		tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
692254885Sdumbbell
693254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
694254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J) {
695254885Sdumbbell		if (pll_ref_freq == 2700) {
696254885Sdumbbell			m = NTSC_TV_PLL_M_27;
697254885Sdumbbell			n = NTSC_TV_PLL_N_27;
698254885Sdumbbell			p = NTSC_TV_PLL_P_27;
699254885Sdumbbell		} else {
700254885Sdumbbell			m = NTSC_TV_PLL_M_14;
701254885Sdumbbell			n = NTSC_TV_PLL_N_14;
702254885Sdumbbell			p = NTSC_TV_PLL_P_14;
703254885Sdumbbell		}
704254885Sdumbbell	} else {
705254885Sdumbbell		if (pll_ref_freq == 2700) {
706254885Sdumbbell			m = PAL_TV_PLL_M_27;
707254885Sdumbbell			n = PAL_TV_PLL_N_27;
708254885Sdumbbell			p = PAL_TV_PLL_P_27;
709254885Sdumbbell		} else {
710254885Sdumbbell			m = PAL_TV_PLL_M_14;
711254885Sdumbbell			n = PAL_TV_PLL_N_14;
712254885Sdumbbell			p = PAL_TV_PLL_P_14;
713254885Sdumbbell		}
714254885Sdumbbell	}
715254885Sdumbbell
716254885Sdumbbell	tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) |
717254885Sdumbbell		(((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
718254885Sdumbbell		((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
719254885Sdumbbell		(((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
720254885Sdumbbell		((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
721254885Sdumbbell
722254885Sdumbbell	tv_pll_cntl1 = (((4 & RADEON_TVPCP_MASK) << RADEON_TVPCP_SHIFT) |
723254885Sdumbbell			((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) |
724254885Sdumbbell			((1 & RADEON_TVPDC_MASK) << RADEON_TVPDC_SHIFT) |
725254885Sdumbbell			RADEON_TVCLK_SRC_SEL_TVPLL |
726254885Sdumbbell			RADEON_TVPLL_TEST_DIS);
727254885Sdumbbell
728254885Sdumbbell	tv_dac->tv.tv_uv_adr = 0xc8;
729254885Sdumbbell
730254885Sdumbbell	if (tv_dac->tv_std == TV_STD_NTSC ||
731254885Sdumbbell	    tv_dac->tv_std == TV_STD_NTSC_J ||
732254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_M ||
733254885Sdumbbell	    tv_dac->tv_std == TV_STD_PAL_60) {
734254885Sdumbbell		tv_ftotal = NTSC_TV_VFTOTAL;
735254885Sdumbbell		hor_timing = hor_timing_NTSC;
736254885Sdumbbell		vert_timing = vert_timing_NTSC;
737254885Sdumbbell	} else {
738254885Sdumbbell		hor_timing = hor_timing_PAL;
739254885Sdumbbell		vert_timing = vert_timing_PAL;
740254885Sdumbbell		tv_ftotal = PAL_TV_VFTOTAL;
741254885Sdumbbell	}
742254885Sdumbbell
743254885Sdumbbell	for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
744254885Sdumbbell		if ((tv_dac->tv.h_code_timing[i] = hor_timing[i]) == 0)
745254885Sdumbbell			break;
746254885Sdumbbell	}
747254885Sdumbbell
748254885Sdumbbell	for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) {
749254885Sdumbbell		if ((tv_dac->tv.v_code_timing[i] = vert_timing[i]) == 0)
750254885Sdumbbell			break;
751254885Sdumbbell	}
752254885Sdumbbell
753254885Sdumbbell	radeon_legacy_tv_init_restarts(encoder);
754254885Sdumbbell
755254885Sdumbbell	/* play with DAC_CNTL */
756254885Sdumbbell	/* play with GPIOPAD_A */
757254885Sdumbbell	/* DISP_OUTPUT_CNTL */
758254885Sdumbbell	/* use reference freq */
759254885Sdumbbell
760254885Sdumbbell	/* program the TV registers */
761254885Sdumbbell	WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST |
762254885Sdumbbell				       RADEON_CRT_ASYNC_RST | RADEON_TV_FIFO_ASYNC_RST));
763254885Sdumbbell
764254885Sdumbbell	tmp = RREG32(RADEON_TV_DAC_CNTL);
765254885Sdumbbell	tmp &= ~RADEON_TV_DAC_NBLANK;
766254885Sdumbbell	tmp |= RADEON_TV_DAC_BGSLEEP |
767254885Sdumbbell		RADEON_TV_DAC_RDACPD |
768254885Sdumbbell		RADEON_TV_DAC_GDACPD |
769254885Sdumbbell		RADEON_TV_DAC_BDACPD;
770254885Sdumbbell	WREG32(RADEON_TV_DAC_CNTL, tmp);
771254885Sdumbbell
772254885Sdumbbell	/* TV PLL */
773254885Sdumbbell	WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL);
774254885Sdumbbell	WREG32_PLL(RADEON_TV_PLL_CNTL, tv_pll_cntl);
775254885Sdumbbell	WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET);
776254885Sdumbbell
777254885Sdumbbell	radeon_wait_pll_lock(encoder, 200, 800, 135);
778254885Sdumbbell
779254885Sdumbbell	WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET);
780254885Sdumbbell
781254885Sdumbbell	radeon_wait_pll_lock(encoder, 300, 160, 27);
782254885Sdumbbell	radeon_wait_pll_lock(encoder, 200, 800, 135);
783254885Sdumbbell
784254885Sdumbbell	WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~0xf);
785254885Sdumbbell	WREG32_PLL_P(RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL);
786254885Sdumbbell
787254885Sdumbbell	WREG32_PLL_P(RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK);
788254885Sdumbbell	WREG32_PLL_P(RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP);
789254885Sdumbbell
790254885Sdumbbell	/* TV HV */
791254885Sdumbbell	WREG32(RADEON_TV_RGB_CNTL, tv_rgb_cntl);
792254885Sdumbbell	WREG32(RADEON_TV_HTOTAL, const_ptr->hor_total - 1);
793254885Sdumbbell	WREG32(RADEON_TV_HDISP, const_ptr->hor_resolution - 1);
794254885Sdumbbell	WREG32(RADEON_TV_HSTART, const_ptr->hor_start);
795254885Sdumbbell
796254885Sdumbbell	WREG32(RADEON_TV_VTOTAL, const_ptr->ver_total - 1);
797254885Sdumbbell	WREG32(RADEON_TV_VDISP, const_ptr->ver_resolution - 1);
798254885Sdumbbell	WREG32(RADEON_TV_FTOTAL, tv_ftotal);
799254885Sdumbbell	WREG32(RADEON_TV_VSCALER_CNTL1, tv_vscaler_cntl1);
800254885Sdumbbell	WREG32(RADEON_TV_VSCALER_CNTL2, tv_vscaler_cntl2);
801254885Sdumbbell
802254885Sdumbbell	WREG32(RADEON_TV_Y_FALL_CNTL, tv_y_fall_cntl);
803254885Sdumbbell	WREG32(RADEON_TV_Y_RISE_CNTL, tv_y_rise_cntl);
804254885Sdumbbell	WREG32(RADEON_TV_Y_SAW_TOOTH_CNTL, tv_y_saw_tooth_cntl);
805254885Sdumbbell
806254885Sdumbbell	WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST |
807254885Sdumbbell				       RADEON_CRT_ASYNC_RST));
808254885Sdumbbell
809254885Sdumbbell	/* TV restarts */
810254885Sdumbbell	radeon_legacy_write_tv_restarts(radeon_encoder);
811254885Sdumbbell
812254885Sdumbbell	/* tv timings */
813254885Sdumbbell	radeon_restore_tv_timing_tables(radeon_encoder);
814254885Sdumbbell
815254885Sdumbbell	WREG32(RADEON_TV_MASTER_CNTL, (tv_master_cntl | RADEON_TV_ASYNC_RST));
816254885Sdumbbell
817254885Sdumbbell	/* tv std */
818254885Sdumbbell	WREG32(RADEON_TV_SYNC_CNTL, (RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE));
819254885Sdumbbell	WREG32(RADEON_TV_TIMING_CNTL, tv_dac->tv.timing_cntl);
820254885Sdumbbell	WREG32(RADEON_TV_MODULATOR_CNTL1, tv_modulator_cntl1);
821254885Sdumbbell	WREG32(RADEON_TV_MODULATOR_CNTL2, tv_modulator_cntl2);
822254885Sdumbbell	WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, (RADEON_Y_RED_EN |
823254885Sdumbbell					    RADEON_C_GRN_EN |
824254885Sdumbbell					    RADEON_CMP_BLU_EN |
825254885Sdumbbell					    RADEON_DAC_DITHER_EN));
826254885Sdumbbell
827254885Sdumbbell	WREG32(RADEON_TV_CRC_CNTL, 0);
828254885Sdumbbell
829254885Sdumbbell	WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
830254885Sdumbbell
831254885Sdumbbell	WREG32(RADEON_TV_GAIN_LIMIT_SETTINGS, ((0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) |
832254885Sdumbbell					       (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT)));
833254885Sdumbbell	WREG32(RADEON_TV_LINEAR_GAIN_SETTINGS, ((0x100 << RADEON_UV_GAIN_SHIFT) |
834254885Sdumbbell						(0x100 << RADEON_Y_GAIN_SHIFT)));
835254885Sdumbbell
836254885Sdumbbell	WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
837254885Sdumbbell
838254885Sdumbbell}
839254885Sdumbbell
840254885Sdumbbellvoid radeon_legacy_tv_adjust_crtc_reg(struct drm_encoder *encoder,
841254885Sdumbbell				      uint32_t *h_total_disp, uint32_t *h_sync_strt_wid,
842254885Sdumbbell				      uint32_t *v_total_disp, uint32_t *v_sync_strt_wid)
843254885Sdumbbell{
844254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
845254885Sdumbbell	const struct radeon_tv_mode_constants *const_ptr;
846254885Sdumbbell	uint32_t tmp;
847254885Sdumbbell
848254885Sdumbbell	const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
849254885Sdumbbell	if (!const_ptr)
850254885Sdumbbell		return;
851254885Sdumbbell
852254885Sdumbbell	*h_total_disp = (((const_ptr->hor_resolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
853254885Sdumbbell		(((const_ptr->hor_total / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
854254885Sdumbbell
855254885Sdumbbell	tmp = *h_sync_strt_wid;
856254885Sdumbbell	tmp &= ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR);
857254885Sdumbbell	tmp |= (((const_ptr->hor_syncstart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
858254885Sdumbbell		(const_ptr->hor_syncstart & 7);
859254885Sdumbbell	*h_sync_strt_wid = tmp;
860254885Sdumbbell
861254885Sdumbbell	*v_total_disp = ((const_ptr->ver_resolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
862254885Sdumbbell		((const_ptr->ver_total - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
863254885Sdumbbell
864254885Sdumbbell	tmp = *v_sync_strt_wid;
865254885Sdumbbell	tmp &= ~RADEON_CRTC_V_SYNC_STRT;
866254885Sdumbbell	tmp |= ((const_ptr->ver_syncstart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
867254885Sdumbbell	*v_sync_strt_wid = tmp;
868254885Sdumbbell}
869254885Sdumbbell
870254885Sdumbbellstatic int get_post_div(int value)
871254885Sdumbbell{
872254885Sdumbbell	int post_div;
873254885Sdumbbell	switch (value) {
874254885Sdumbbell	case 1: post_div = 0; break;
875254885Sdumbbell	case 2: post_div = 1; break;
876254885Sdumbbell	case 3: post_div = 4; break;
877254885Sdumbbell	case 4: post_div = 2; break;
878254885Sdumbbell	case 6: post_div = 6; break;
879254885Sdumbbell	case 8: post_div = 3; break;
880254885Sdumbbell	case 12: post_div = 7; break;
881254885Sdumbbell	case 16:
882254885Sdumbbell	default: post_div = 5; break;
883254885Sdumbbell	}
884254885Sdumbbell	return post_div;
885254885Sdumbbell}
886254885Sdumbbell
887254885Sdumbbellvoid radeon_legacy_tv_adjust_pll1(struct drm_encoder *encoder,
888254885Sdumbbell				  uint32_t *htotal_cntl, uint32_t *ppll_ref_div,
889254885Sdumbbell				  uint32_t *ppll_div_3, uint32_t *pixclks_cntl)
890254885Sdumbbell{
891254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
892254885Sdumbbell	const struct radeon_tv_mode_constants *const_ptr;
893254885Sdumbbell
894254885Sdumbbell	const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
895254885Sdumbbell	if (!const_ptr)
896254885Sdumbbell		return;
897254885Sdumbbell
898254885Sdumbbell	*htotal_cntl = (const_ptr->hor_total & 0x7) | RADEON_HTOT_CNTL_VGA_EN;
899254885Sdumbbell
900254885Sdumbbell	*ppll_ref_div = const_ptr->crtcPLL_M;
901254885Sdumbbell
902254885Sdumbbell	*ppll_div_3 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16);
903254885Sdumbbell	*pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL);
904254885Sdumbbell	*pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK;
905254885Sdumbbell}
906254885Sdumbbell
907254885Sdumbbellvoid radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder,
908254885Sdumbbell				  uint32_t *htotal2_cntl, uint32_t *p2pll_ref_div,
909254885Sdumbbell				  uint32_t *p2pll_div_0, uint32_t *pixclks_cntl)
910254885Sdumbbell{
911254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
912254885Sdumbbell	const struct radeon_tv_mode_constants *const_ptr;
913254885Sdumbbell
914254885Sdumbbell	const_ptr = radeon_legacy_tv_get_std_mode(radeon_encoder, NULL);
915254885Sdumbbell	if (!const_ptr)
916254885Sdumbbell		return;
917254885Sdumbbell
918254885Sdumbbell	*htotal2_cntl = (const_ptr->hor_total & 0x7);
919254885Sdumbbell
920254885Sdumbbell	*p2pll_ref_div = const_ptr->crtcPLL_M;
921254885Sdumbbell
922254885Sdumbbell	*p2pll_div_0 = (const_ptr->crtcPLL_N & 0x7ff) | (get_post_div(const_ptr->crtcPLL_post_div) << 16);
923254885Sdumbbell	*pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK;
924254885Sdumbbell	*pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK | RADEON_PIXCLK_TV_SRC_SEL;
925254885Sdumbbell}
926254885Sdumbbell
927