radeon_tv.c revision 209ff23f
1209ff23fSmrg/*
2209ff23fSmrg * Integrated TV out support based on the GATOS code by
3209ff23fSmrg * Federico Ulivi <fulivi@lycos.com>
4209ff23fSmrg */
5209ff23fSmrg
6209ff23fSmrg#ifdef HAVE_CONFIG_H
7209ff23fSmrg#include "config.h"
8209ff23fSmrg#endif
9209ff23fSmrg
10209ff23fSmrg#include <string.h>
11209ff23fSmrg#include <stdio.h>
12209ff23fSmrg
13209ff23fSmrg/* X and server generic header files */
14209ff23fSmrg#include "xf86.h"
15209ff23fSmrg#include "xf86_OSproc.h"
16209ff23fSmrg#include "vgaHW.h"
17209ff23fSmrg#include "xf86Modes.h"
18209ff23fSmrg
19209ff23fSmrg/* Driver data structures */
20209ff23fSmrg#include "radeon.h"
21209ff23fSmrg#include "radeon_reg.h"
22209ff23fSmrg#include "radeon_macros.h"
23209ff23fSmrg#include "radeon_probe.h"
24209ff23fSmrg#include "radeon_version.h"
25209ff23fSmrg#include "radeon_tv.h"
26209ff23fSmrg
27209ff23fSmrg/**********************************************************************
28209ff23fSmrg *
29209ff23fSmrg * ModeConstants
30209ff23fSmrg *
31209ff23fSmrg * Storage of constants related to a single video mode
32209ff23fSmrg *
33209ff23fSmrg **********************************************************************/
34209ff23fSmrg
35209ff23fSmrgtypedef struct
36209ff23fSmrg{
37209ff23fSmrg    uint16_t horResolution;
38209ff23fSmrg    uint16_t verResolution;
39209ff23fSmrg    TVStd  standard;
40209ff23fSmrg    uint16_t horTotal;
41209ff23fSmrg    uint16_t verTotal;
42209ff23fSmrg    uint16_t horStart;
43209ff23fSmrg    uint16_t horSyncStart;
44209ff23fSmrg    uint16_t verSyncStart;
45209ff23fSmrg    unsigned defRestart;
46209ff23fSmrg    uint16_t crtcPLL_N;
47209ff23fSmrg    uint8_t  crtcPLL_M;
48209ff23fSmrg    uint8_t  crtcPLL_postDiv;
49209ff23fSmrg    unsigned pixToTV;
50209ff23fSmrg} TVModeConstants;
51209ff23fSmrg
52209ff23fSmrgstatic const uint16_t hor_timing_NTSC[] =
53209ff23fSmrg{
54209ff23fSmrg    0x0007,
55209ff23fSmrg    0x003f,
56209ff23fSmrg    0x0263,
57209ff23fSmrg    0x0a24,
58209ff23fSmrg    0x2a6b,
59209ff23fSmrg    0x0a36,
60209ff23fSmrg    0x126d, /* H_TABLE_POS1 */
61209ff23fSmrg    0x1bfe,
62209ff23fSmrg    0x1a8f, /* H_TABLE_POS2 */
63209ff23fSmrg    0x1ec7,
64209ff23fSmrg    0x3863,
65209ff23fSmrg    0x1bfe,
66209ff23fSmrg    0x1bfe,
67209ff23fSmrg    0x1a2a,
68209ff23fSmrg    0x1e95,
69209ff23fSmrg    0x0e31,
70209ff23fSmrg    0x201b,
71209ff23fSmrg    0
72209ff23fSmrg};
73209ff23fSmrg
74209ff23fSmrgstatic const uint16_t vert_timing_NTSC[] =
75209ff23fSmrg{
76209ff23fSmrg    0x2001,
77209ff23fSmrg    0x200d,
78209ff23fSmrg    0x1006,
79209ff23fSmrg    0x0c06,
80209ff23fSmrg    0x1006,
81209ff23fSmrg    0x1818,
82209ff23fSmrg    0x21e3,
83209ff23fSmrg    0x1006,
84209ff23fSmrg    0x0c06,
85209ff23fSmrg    0x1006,
86209ff23fSmrg    0x1817,
87209ff23fSmrg    0x21d4,
88209ff23fSmrg    0x0002,
89209ff23fSmrg    0
90209ff23fSmrg};
91209ff23fSmrg
92209ff23fSmrgstatic const uint16_t hor_timing_PAL[] =
93209ff23fSmrg{
94209ff23fSmrg    0x0007,
95209ff23fSmrg    0x0058,
96209ff23fSmrg    0x027c,
97209ff23fSmrg    0x0a31,
98209ff23fSmrg    0x2a77,
99209ff23fSmrg    0x0a95,
100209ff23fSmrg    0x124f, /* H_TABLE_POS1 */
101209ff23fSmrg    0x1bfe,
102209ff23fSmrg    0x1b22, /* H_TABLE_POS2 */
103209ff23fSmrg    0x1ef9,
104209ff23fSmrg    0x387c,
105209ff23fSmrg    0x1bfe,
106209ff23fSmrg    0x1bfe,
107209ff23fSmrg    0x1b31,
108209ff23fSmrg    0x1eb5,
109209ff23fSmrg    0x0e43,
110209ff23fSmrg    0x201b,
111209ff23fSmrg    0
112209ff23fSmrg};
113209ff23fSmrg
114209ff23fSmrgstatic const uint16_t vert_timing_PAL[] =
115209ff23fSmrg{
116209ff23fSmrg    0x2001,
117209ff23fSmrg    0x200c,
118209ff23fSmrg    0x1005,
119209ff23fSmrg    0x0c05,
120209ff23fSmrg    0x1005,
121209ff23fSmrg    0x1401,
122209ff23fSmrg    0x1821,
123209ff23fSmrg    0x2240,
124209ff23fSmrg    0x1005,
125209ff23fSmrg    0x0c05,
126209ff23fSmrg    0x1005,
127209ff23fSmrg    0x1401,
128209ff23fSmrg    0x1822,
129209ff23fSmrg    0x2230,
130209ff23fSmrg    0x0002,
131209ff23fSmrg    0
132209ff23fSmrg};
133209ff23fSmrg
134209ff23fSmrg/**********************************************************************
135209ff23fSmrg *
136209ff23fSmrg * availableModes
137209ff23fSmrg *
138209ff23fSmrg * Table of all allowed modes for tv output
139209ff23fSmrg *
140209ff23fSmrg **********************************************************************/
141209ff23fSmrgstatic const TVModeConstants availableTVModes[] =
142209ff23fSmrg{
143209ff23fSmrg    {
144209ff23fSmrg	800,                /* horResolution */
145209ff23fSmrg	600,                /* verResolution */
146209ff23fSmrg	TV_STD_NTSC,        /* standard */
147209ff23fSmrg	990,                /* horTotal */
148209ff23fSmrg	740,                /* verTotal */
149209ff23fSmrg	813,                /* horStart */
150209ff23fSmrg	824,                /* horSyncStart */
151209ff23fSmrg	632,                /* verSyncStart */
152209ff23fSmrg	625592,             /* defRestart */
153209ff23fSmrg	592,                /* crtcPLL_N */
154209ff23fSmrg	91,                 /* crtcPLL_M */
155209ff23fSmrg	4,                  /* crtcPLL_postDiv */
156209ff23fSmrg	1022,               /* pixToTV */
157209ff23fSmrg    },
158209ff23fSmrg    {
159209ff23fSmrg	800,               /* horResolution */
160209ff23fSmrg	600,               /* verResolution */
161209ff23fSmrg	TV_STD_PAL,        /* standard */
162209ff23fSmrg	1144,              /* horTotal */
163209ff23fSmrg	706,               /* verTotal */
164209ff23fSmrg	812,               /* horStart */
165209ff23fSmrg	824,               /* horSyncStart */
166209ff23fSmrg	669,               /* verSyncStart */
167209ff23fSmrg	696700,            /* defRestart */
168209ff23fSmrg	1382,              /* crtcPLL_N */
169209ff23fSmrg	231,               /* crtcPLL_M */
170209ff23fSmrg	4,                 /* crtcPLL_postDiv */
171209ff23fSmrg	759,               /* pixToTV */
172209ff23fSmrg    }
173209ff23fSmrg};
174209ff23fSmrg
175209ff23fSmrg#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ]))
176209ff23fSmrg
177209ff23fSmrgstatic long YCOEF_value[5] = { 2, 2, 0, 4, 0 };
178209ff23fSmrgstatic long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 };
179209ff23fSmrgstatic long SLOPE_value[5] = { 1, 2, 2, 4, 8 };
180209ff23fSmrgstatic long SLOPE_limit[5] = { 6, 5, 4, 3, 2 };
181209ff23fSmrg
182209ff23fSmrg
183209ff23fSmrgstatic void
184209ff23fSmrgRADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests,
185209ff23fSmrg		  unsigned nWaitLoops, unsigned cntThreshold)
186209ff23fSmrg{
187209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
188209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
189209ff23fSmrg    uint32_t savePLLTest;
190209ff23fSmrg    unsigned i;
191209ff23fSmrg    unsigned j;
192209ff23fSmrg
193209ff23fSmrg    OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100);
194209ff23fSmrg
195209ff23fSmrg    savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL);
196209ff23fSmrg
197209ff23fSmrg    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B);
198209ff23fSmrg
199209ff23fSmrg    /* XXX: these should probably be OUTPLL to avoid various PLL errata */
200209ff23fSmrg
201209ff23fSmrg    OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL);
202209ff23fSmrg
203209ff23fSmrg    for (i = 0; i < nTests; i++) {
204209ff23fSmrg	OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0);
205209ff23fSmrg
206209ff23fSmrg	for (j = 0; j < nWaitLoops; j++)
207209ff23fSmrg	    if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold)
208209ff23fSmrg		break;
209209ff23fSmrg    }
210209ff23fSmrg
211209ff23fSmrg    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest);
212209ff23fSmrg
213209ff23fSmrg    OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff);
214209ff23fSmrg}
215209ff23fSmrg
216209ff23fSmrg/* Write to TV FIFO RAM */
217209ff23fSmrgstatic void
218209ff23fSmrgRADEONWriteTVFIFO(ScrnInfoPtr pScrn, uint16_t addr,
219209ff23fSmrg		  uint32_t value)
220209ff23fSmrg{
221209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
222209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
223209ff23fSmrg    uint32_t tmp;
224209ff23fSmrg    int i = 0;
225209ff23fSmrg
226209ff23fSmrg    OUTREG(RADEON_TV_HOST_WRITE_DATA, value);
227209ff23fSmrg
228209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
229209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT);
230209ff23fSmrg
231209ff23fSmrg    do {
232209ff23fSmrg	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
233209ff23fSmrg	if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0)
234209ff23fSmrg	    break;
235209ff23fSmrg	i++;
236209ff23fSmrg    }
237209ff23fSmrg    while (i < 10000);
238209ff23fSmrg    /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/
239209ff23fSmrg
240209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
241209ff23fSmrg}
242209ff23fSmrg
243209ff23fSmrg/* Read from TV FIFO RAM */
244209ff23fSmrgstatic uint32_t
245209ff23fSmrgRADEONReadTVFIFO(ScrnInfoPtr pScrn, uint16_t addr)
246209ff23fSmrg{
247209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
248209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
249209ff23fSmrg    uint32_t tmp;
250209ff23fSmrg    int i = 0;
251209ff23fSmrg
252209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
253209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD);
254209ff23fSmrg
255209ff23fSmrg    do {
256209ff23fSmrg	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
257209ff23fSmrg	if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0)
258209ff23fSmrg	    break;
259209ff23fSmrg	i++;
260209ff23fSmrg    }
261209ff23fSmrg    while (i < 10000);
262209ff23fSmrg    /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/
263209ff23fSmrg
264209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
265209ff23fSmrg
266209ff23fSmrg    return INREG(RADEON_TV_HOST_READ_DATA);
267209ff23fSmrg}
268209ff23fSmrg
269209ff23fSmrg/* Get FIFO addresses of horizontal & vertical code timing tables from
270209ff23fSmrg * settings of uv_adr register.
271209ff23fSmrg */
272209ff23fSmrgstatic uint16_t
273209ff23fSmrgRADEONGetHTimingTablesAddr(uint32_t tv_uv_adr)
274209ff23fSmrg{
275209ff23fSmrg    uint16_t hTable;
276209ff23fSmrg
277209ff23fSmrg    switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) {
278209ff23fSmrg    case 0:
279209ff23fSmrg	hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL;
280209ff23fSmrg	break;
281209ff23fSmrg    case 1:
282209ff23fSmrg	hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2;
283209ff23fSmrg	break;
284209ff23fSmrg    case 2:
285209ff23fSmrg	hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2;
286209ff23fSmrg	break;
287209ff23fSmrg    default:
288209ff23fSmrg	/* Of course, this should never happen */
289209ff23fSmrg	hTable = 0;
290209ff23fSmrg	break;
291209ff23fSmrg    }
292209ff23fSmrg    return hTable;
293209ff23fSmrg}
294209ff23fSmrg
295209ff23fSmrgstatic uint16_t
296209ff23fSmrgRADEONGetVTimingTablesAddr(uint32_t tv_uv_adr)
297209ff23fSmrg{
298209ff23fSmrg    uint16_t vTable;
299209ff23fSmrg
300209ff23fSmrg    switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) {
301209ff23fSmrg    case 0:
302209ff23fSmrg	vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1;
303209ff23fSmrg	break;
304209ff23fSmrg    case 1:
305209ff23fSmrg	vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
306209ff23fSmrg	break;
307209ff23fSmrg    case 2:
308209ff23fSmrg	vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
309209ff23fSmrg	break;
310209ff23fSmrg    default:
311209ff23fSmrg	/* Of course, this should never happen */
312209ff23fSmrg	vTable = 0;
313209ff23fSmrg	break;
314209ff23fSmrg    }
315209ff23fSmrg    return vTable;
316209ff23fSmrg}
317209ff23fSmrg
318209ff23fSmrg/* Restore horizontal/vertical timing code tables */
319209ff23fSmrgstatic void
320209ff23fSmrgRADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore)
321209ff23fSmrg{
322209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
323209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
324209ff23fSmrg    uint16_t hTable;
325209ff23fSmrg    uint16_t vTable;
326209ff23fSmrg    uint32_t tmp;
327209ff23fSmrg    unsigned i;
328209ff23fSmrg
329209ff23fSmrg    OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr);
330209ff23fSmrg    hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr);
331209ff23fSmrg    vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr);
332209ff23fSmrg
333209ff23fSmrg    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) {
334209ff23fSmrg	tmp = ((uint32_t)restore->h_code_timing[ i ] << 14) | ((uint32_t)restore->h_code_timing[ i + 1 ]);
335209ff23fSmrg	RADEONWriteTVFIFO(pScrn, hTable, tmp);
336209ff23fSmrg	if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0)
337209ff23fSmrg	    break;
338209ff23fSmrg    }
339209ff23fSmrg
340209ff23fSmrg    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) {
341209ff23fSmrg	tmp = ((uint32_t)restore->v_code_timing[ i + 1 ] << 14) | ((uint32_t)restore->v_code_timing[ i ]);
342209ff23fSmrg	RADEONWriteTVFIFO(pScrn, vTable, tmp);
343209ff23fSmrg	if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0)
344209ff23fSmrg	    break;
345209ff23fSmrg    }
346209ff23fSmrg}
347209ff23fSmrg
348209ff23fSmrg/* restore TV PLLs */
349209ff23fSmrgstatic void
350209ff23fSmrgRADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
351209ff23fSmrg{
352209ff23fSmrg
353209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL);
354209ff23fSmrg    OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl);
355209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET);
356209ff23fSmrg
357209ff23fSmrg    RADEONWaitPLLLock(pScrn, 200, 800, 135);
358209ff23fSmrg
359209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET);
360209ff23fSmrg
361209ff23fSmrg    RADEONWaitPLLLock(pScrn, 300, 160, 27);
362209ff23fSmrg    RADEONWaitPLLLock(pScrn, 200, 800, 135);
363209ff23fSmrg
364209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf);
365209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL);
366209ff23fSmrg
367209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK);
368209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP);
369209ff23fSmrg}
370209ff23fSmrg
371209ff23fSmrg/* Restore TV horizontal/vertical settings */
372209ff23fSmrgstatic void
373209ff23fSmrgRADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
374209ff23fSmrg{
375209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
376209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
377209ff23fSmrg
378209ff23fSmrg    OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl);
379209ff23fSmrg
380209ff23fSmrg    OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal);
381209ff23fSmrg    OUTREG(RADEON_TV_HDISP, restore->tv_hdisp);
382209ff23fSmrg    OUTREG(RADEON_TV_HSTART, restore->tv_hstart);
383209ff23fSmrg
384209ff23fSmrg    OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal);
385209ff23fSmrg    OUTREG(RADEON_TV_VDISP, restore->tv_vdisp);
386209ff23fSmrg
387209ff23fSmrg    OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal);
388209ff23fSmrg
389209ff23fSmrg    OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1);
390209ff23fSmrg    OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2);
391209ff23fSmrg
392209ff23fSmrg    OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl);
393209ff23fSmrg    OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl);
394209ff23fSmrg    OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl);
395209ff23fSmrg}
396209ff23fSmrg
397209ff23fSmrg/* restore TV RESTART registers */
398209ff23fSmrgstatic void
399209ff23fSmrgRADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore)
400209ff23fSmrg{
401209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
402209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
403209ff23fSmrg
404209ff23fSmrg    OUTREG(RADEON_TV_FRESTART, restore->tv_frestart);
405209ff23fSmrg    OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart);
406209ff23fSmrg    OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart);
407209ff23fSmrg}
408209ff23fSmrg
409209ff23fSmrg/* restore tv standard & output muxes */
410209ff23fSmrgstatic void
411209ff23fSmrgRADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore)
412209ff23fSmrg{
413209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
414209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
415209ff23fSmrg
416209ff23fSmrg    OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl);
417209ff23fSmrg
418209ff23fSmrg    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
419209ff23fSmrg
420209ff23fSmrg    OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1);
421209ff23fSmrg    OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2);
422209ff23fSmrg
423209ff23fSmrg    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl);
424209ff23fSmrg
425209ff23fSmrg    OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl);
426209ff23fSmrg}
427209ff23fSmrg
428209ff23fSmrg/* Restore TV out regs */
429209ff23fSmrgvoid
430209ff23fSmrgRADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
431209ff23fSmrg{
432209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
433209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
434209ff23fSmrg
435209ff23fSmrg    ErrorF("Entering Restore TV\n");
436209ff23fSmrg
437209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
438209ff23fSmrg				   | RADEON_TV_ASYNC_RST
439209ff23fSmrg				   | RADEON_CRT_ASYNC_RST
440209ff23fSmrg				   | RADEON_TV_FIFO_ASYNC_RST));
441209ff23fSmrg
442209ff23fSmrg    /* Temporarily turn the TV DAC off */
443209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK)
444209ff23fSmrg				| RADEON_TV_DAC_BGSLEEP
445209ff23fSmrg				| RADEON_TV_DAC_RDACPD
446209ff23fSmrg				| RADEON_TV_DAC_GDACPD
447209ff23fSmrg				| RADEON_TV_DAC_BDACPD));
448209ff23fSmrg
449209ff23fSmrg    ErrorF("Restore TV PLL\n");
450209ff23fSmrg    RADEONRestoreTVPLLRegisters(pScrn, restore);
451209ff23fSmrg
452209ff23fSmrg    ErrorF("Restore TVHV\n");
453209ff23fSmrg    RADEONRestoreTVHVRegisters(pScrn, restore);
454209ff23fSmrg
455209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
456209ff23fSmrg				   | RADEON_TV_ASYNC_RST
457209ff23fSmrg				   | RADEON_CRT_ASYNC_RST));
458209ff23fSmrg
459209ff23fSmrg    ErrorF("Restore TV Restarts\n");
460209ff23fSmrg    RADEONRestoreTVRestarts(pScrn, restore);
461209ff23fSmrg
462209ff23fSmrg    ErrorF("Restore Timing Tables\n");
463209ff23fSmrg    RADEONRestoreTVTimingTables(pScrn, restore);
464209ff23fSmrg
465209ff23fSmrg
466209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
467209ff23fSmrg				   | RADEON_TV_ASYNC_RST));
468209ff23fSmrg
469209ff23fSmrg    ErrorF("Restore TV standard\n");
470209ff23fSmrg    RADEONRestoreTVOutputStd(pScrn, restore);
471209ff23fSmrg
472209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
473209ff23fSmrg
474209ff23fSmrg    OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings);
475209ff23fSmrg    OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings);
476209ff23fSmrg
477209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
478209ff23fSmrg
479209ff23fSmrg    ErrorF("Leaving Restore TV\n");
480209ff23fSmrg}
481209ff23fSmrg
482209ff23fSmrg/* Save horizontal/vertical timing code tables */
483209ff23fSmrgstatic void
484209ff23fSmrgRADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save)
485209ff23fSmrg{
486209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
487209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
488209ff23fSmrg    uint16_t hTable;
489209ff23fSmrg    uint16_t vTable;
490209ff23fSmrg    uint32_t tmp;
491209ff23fSmrg    unsigned i;
492209ff23fSmrg
493209ff23fSmrg    save->tv_uv_adr = INREG(RADEON_TV_UV_ADR);
494209ff23fSmrg    hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr);
495209ff23fSmrg    vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr);
496209ff23fSmrg
497209ff23fSmrg    /*
498209ff23fSmrg     * Reset FIFO arbiter in order to be able to access FIFO RAM
499209ff23fSmrg     */
500209ff23fSmrg
501209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
502209ff23fSmrg				   | RADEON_CRT_ASYNC_RST
503209ff23fSmrg				   | RADEON_RESTART_PHASE_FIX
504209ff23fSmrg				   | RADEON_CRT_FIFO_CE_EN
505209ff23fSmrg				   | RADEON_TV_FIFO_CE_EN
506209ff23fSmrg				   | RADEON_TV_ON));
507209ff23fSmrg
508209ff23fSmrg    /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/
509209ff23fSmrg
510209ff23fSmrg    ErrorF("saveTimingTables: reading timing tables\n");
511209ff23fSmrg
512209ff23fSmrg    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) {
513209ff23fSmrg	tmp = RADEONReadTVFIFO(pScrn, hTable--);
514209ff23fSmrg	save->h_code_timing[ i     ] = (uint16_t)((tmp >> 14) & 0x3fff);
515209ff23fSmrg	save->h_code_timing[ i + 1 ] = (uint16_t)(tmp & 0x3fff);
516209ff23fSmrg
517209ff23fSmrg	if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0)
518209ff23fSmrg	    break;
519209ff23fSmrg    }
520209ff23fSmrg
521209ff23fSmrg    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) {
522209ff23fSmrg	tmp = RADEONReadTVFIFO(pScrn, vTable++);
523209ff23fSmrg	save->v_code_timing[ i     ] = (uint16_t)(tmp & 0x3fff);
524209ff23fSmrg	save->v_code_timing[ i + 1 ] = (uint16_t)((tmp >> 14) & 0x3fff);
525209ff23fSmrg
526209ff23fSmrg	if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0)
527209ff23fSmrg	    break;
528209ff23fSmrg    }
529209ff23fSmrg}
530209ff23fSmrg
531209ff23fSmrg/* read TV regs */
532209ff23fSmrgvoid
533209ff23fSmrgRADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
534209ff23fSmrg{
535209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
536209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
537209ff23fSmrg
538209ff23fSmrg    ErrorF("Entering TV Save\n");
539209ff23fSmrg
540209ff23fSmrg    save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL);
541209ff23fSmrg    save->tv_frestart = INREG(RADEON_TV_FRESTART);
542209ff23fSmrg    save->tv_hrestart = INREG(RADEON_TV_HRESTART);
543209ff23fSmrg    save->tv_vrestart = INREG(RADEON_TV_VRESTART);
544209ff23fSmrg    save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS);
545209ff23fSmrg    save->tv_hdisp = INREG(RADEON_TV_HDISP);
546209ff23fSmrg    save->tv_hstart = INREG(RADEON_TV_HSTART);
547209ff23fSmrg    save->tv_htotal = INREG(RADEON_TV_HTOTAL);
548209ff23fSmrg    save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS);
549209ff23fSmrg    save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL);
550209ff23fSmrg    save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL);
551209ff23fSmrg    save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1);
552209ff23fSmrg    save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2);
553209ff23fSmrg    save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL);
554209ff23fSmrg    save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL);
555209ff23fSmrg    save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL);
556209ff23fSmrg    save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
557209ff23fSmrg    save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL);
558209ff23fSmrg    save->tv_vdisp = INREG(RADEON_TV_VDISP);
559209ff23fSmrg    save->tv_ftotal = INREG(RADEON_TV_FTOTAL);
560209ff23fSmrg    save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1);
561209ff23fSmrg    save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2);
562209ff23fSmrg    save->tv_vtotal = INREG(RADEON_TV_VTOTAL);
563209ff23fSmrg    save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL);
564209ff23fSmrg    save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL);
565209ff23fSmrg    save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL);
566209ff23fSmrg
567209ff23fSmrg    save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL);
568209ff23fSmrg    save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1);
569209ff23fSmrg
570209ff23fSmrg    ErrorF("Save TV timing tables\n");
571209ff23fSmrg
572209ff23fSmrg    RADEONSaveTVTimingTables(pScrn, save);
573209ff23fSmrg
574209ff23fSmrg    ErrorF("TV Save done\n");
575209ff23fSmrg}
576209ff23fSmrg
577209ff23fSmrg
578209ff23fSmrg/* Compute F,V,H restarts from default restart position and hPos & vPos
579209ff23fSmrg * Return TRUE when code timing table was changed
580209ff23fSmrg */
581209ff23fSmrgstatic Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save,
582209ff23fSmrg				 DisplayModePtr mode)
583209ff23fSmrg{
584209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
585209ff23fSmrg    int restart;
586209ff23fSmrg    unsigned hTotal;
587209ff23fSmrg    unsigned vTotal;
588209ff23fSmrg    unsigned fTotal;
589209ff23fSmrg    int vOffset;
590209ff23fSmrg    int hOffset;
591209ff23fSmrg    uint16_t p1;
592209ff23fSmrg    uint16_t p2;
593209ff23fSmrg    Bool hChanged;
594209ff23fSmrg    uint16_t hInc;
595209ff23fSmrg    const TVModeConstants *constPtr;
596209ff23fSmrg
597209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
598209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
599209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
600209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M)
601209ff23fSmrg	constPtr = &availableTVModes[0];
602209ff23fSmrg    else
603209ff23fSmrg	constPtr = &availableTVModes[1];
604209ff23fSmrg
605209ff23fSmrg    hTotal = constPtr->horTotal;
606209ff23fSmrg    vTotal = constPtr->verTotal;
607209ff23fSmrg
608209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
609209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
610209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M ||
611209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_60)
612209ff23fSmrg	fTotal = NTSC_TV_VFTOTAL + 1;
613209ff23fSmrg    else
614209ff23fSmrg	fTotal = PAL_TV_VFTOTAL + 1;
615209ff23fSmrg
616209ff23fSmrg    /* Adjust positions 1&2 in hor. code timing table */
617209ff23fSmrg    hOffset = radeon_output->hPos * H_POS_UNIT;
618209ff23fSmrg
619209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
620209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
621209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_M) {
622209ff23fSmrg	/* improve image centering */
623209ff23fSmrg	hOffset -= 50;
624209ff23fSmrg	p1 = hor_timing_NTSC[ H_TABLE_POS1 ];
625209ff23fSmrg	p2 = hor_timing_NTSC[ H_TABLE_POS2 ];
626209ff23fSmrg    } else {
627209ff23fSmrg	p1 = hor_timing_PAL[ H_TABLE_POS1 ];
628209ff23fSmrg	p2 = hor_timing_PAL[ H_TABLE_POS2 ];
629209ff23fSmrg    }
630209ff23fSmrg
631209ff23fSmrg
632209ff23fSmrg    p1 = (uint16_t)((int)p1 + hOffset);
633209ff23fSmrg    p2 = (uint16_t)((int)p2 - hOffset);
634209ff23fSmrg
635209ff23fSmrg    hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] ||
636209ff23fSmrg		p2 != save->h_code_timing[ H_TABLE_POS2 ]);
637209ff23fSmrg
638209ff23fSmrg    save->h_code_timing[ H_TABLE_POS1 ] = p1;
639209ff23fSmrg    save->h_code_timing[ H_TABLE_POS2 ] = p2;
640209ff23fSmrg
641209ff23fSmrg    /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */
642209ff23fSmrg    hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000;
643209ff23fSmrg
644209ff23fSmrg    /* Adjust restart */
645209ff23fSmrg    restart = constPtr->defRestart;
646209ff23fSmrg
647209ff23fSmrg    /*
648209ff23fSmrg     * Convert vPos TV lines to n. of CRTC pixels
649209ff23fSmrg     * Be verrrrry careful when mixing signed & unsigned values in C..
650209ff23fSmrg     */
651209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
652209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
653209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_M ||
654209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_60)
655209ff23fSmrg	vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(NTSC_TV_LINES_PER_FRAME);
656209ff23fSmrg    else
657209ff23fSmrg	vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(PAL_TV_LINES_PER_FRAME);
658209ff23fSmrg
659209ff23fSmrg    restart -= vOffset + hOffset;
660209ff23fSmrg
661209ff23fSmrg    ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n",
662209ff23fSmrg	   constPtr->defRestart , radeon_output->hPos , radeon_output->vPos , p1 , p2 , restart);
663209ff23fSmrg
664209ff23fSmrg    save->tv_hrestart = restart % hTotal;
665209ff23fSmrg    restart /= hTotal;
666209ff23fSmrg    save->tv_vrestart = restart % vTotal;
667209ff23fSmrg    restart /= vTotal;
668209ff23fSmrg    save->tv_frestart = restart % fTotal;
669209ff23fSmrg
670209ff23fSmrg    ErrorF("computeRestarts: F/H/V=%u,%u,%u\n",
671209ff23fSmrg	   (unsigned)save->tv_frestart, (unsigned)save->tv_vrestart,
672209ff23fSmrg	   (unsigned)save->tv_hrestart);
673209ff23fSmrg
674209ff23fSmrg    /* Compute H_INC from hSize */
675209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
676209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
677209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_M)
678209ff23fSmrg	hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) /
679209ff23fSmrg			(radeon_output->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE)));
680209ff23fSmrg    else
681209ff23fSmrg	hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) /
682209ff23fSmrg			(radeon_output->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE)));
683209ff23fSmrg
684209ff23fSmrg    save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) |
685209ff23fSmrg	((uint32_t)hInc << RADEON_H_INC_SHIFT);
686209ff23fSmrg
687209ff23fSmrg    ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , radeon_output->hSize , hInc);
688209ff23fSmrg
689209ff23fSmrg    return hChanged;
690209ff23fSmrg}
691209ff23fSmrg
692209ff23fSmrg/* intit TV-out regs */
693209ff23fSmrgvoid RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save,
694209ff23fSmrg                                  DisplayModePtr mode, BOOL IsPrimary)
695209ff23fSmrg{
696209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
697209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
698209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(pScrn);
699209ff23fSmrg    unsigned i;
700209ff23fSmrg    unsigned long vert_space, flicker_removal;
701209ff23fSmrg    uint32_t tmp;
702209ff23fSmrg    const TVModeConstants *constPtr;
703209ff23fSmrg    const uint16_t *hor_timing;
704209ff23fSmrg    const uint16_t *vert_timing;
705209ff23fSmrg
706209ff23fSmrg
707209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
708209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
709209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
710209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_M)
711209ff23fSmrg	constPtr = &availableTVModes[0];
712209ff23fSmrg    else
713209ff23fSmrg	constPtr = &availableTVModes[1];
714209ff23fSmrg
715209ff23fSmrg    save->tv_crc_cntl = 0;
716209ff23fSmrg
717209ff23fSmrg    save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) |
718209ff23fSmrg	                           (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT);
719209ff23fSmrg
720209ff23fSmrg    save->tv_hdisp = constPtr->horResolution - 1;
721209ff23fSmrg    save->tv_hstart = constPtr->horStart;
722209ff23fSmrg    save->tv_htotal = constPtr->horTotal - 1;
723209ff23fSmrg
724209ff23fSmrg    save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) |
725209ff23fSmrg	                            (0x100 << RADEON_Y_GAIN_SHIFT);
726209ff23fSmrg
727209ff23fSmrg    save->tv_master_cntl = (RADEON_VIN_ASYNC_RST
728209ff23fSmrg			    | RADEON_CRT_FIFO_CE_EN
729209ff23fSmrg			    | RADEON_TV_FIFO_CE_EN
730209ff23fSmrg			    | RADEON_TV_ON);
731209ff23fSmrg
732209ff23fSmrg    if (!IS_R300_VARIANT)
733209ff23fSmrg	save->tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb;
734209ff23fSmrg
735209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
736209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J)
737209ff23fSmrg	save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX;
738209ff23fSmrg
739209ff23fSmrg    save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT
740209ff23fSmrg	                       | RADEON_SYNC_TIP_LEVEL
741209ff23fSmrg	                       | RADEON_YFLT_EN
742209ff23fSmrg	                       | RADEON_UVFLT_EN
743209ff23fSmrg	                       | (6 << RADEON_CY_FILT_BLEND_SHIFT);
744209ff23fSmrg
745209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
746209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J) {
747209ff23fSmrg	save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT)
748209ff23fSmrg	                            | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
749209ff23fSmrg	save->tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) |
750209ff23fSmrg	    ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
751209ff23fSmrg    } else if (radeon_output->tvStd == TV_STD_SCART_PAL) {
752209ff23fSmrg	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN;
753209ff23fSmrg	save->tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) |
754209ff23fSmrg	    ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
755209ff23fSmrg    } else {
756209ff23fSmrg	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN
757209ff23fSmrg	                            | (0x3b << RADEON_SET_UP_LEVEL_SHIFT)
758209ff23fSmrg	                            | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
759209ff23fSmrg	save->tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) |
760209ff23fSmrg	    ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
761209ff23fSmrg    }
762209ff23fSmrg
763209ff23fSmrg    save->pll_test_cntl = 0;
764209ff23fSmrg
765209ff23fSmrg    save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN
766209ff23fSmrg				 | RADEON_C_GRN_EN
767209ff23fSmrg				 | RADEON_CMP_BLU_EN
768209ff23fSmrg				 | RADEON_DAC_DITHER_EN);
769209ff23fSmrg
770209ff23fSmrg    save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN
771209ff23fSmrg			 | RADEON_TVOUT_SCALE_EN
772209ff23fSmrg			 | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT)
773209ff23fSmrg			 | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT));
774209ff23fSmrg
775209ff23fSmrg    if (IsPrimary) {
776209ff23fSmrg	if (radeon_output->Flags & RADEON_USE_RMX)
777209ff23fSmrg	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX;
778209ff23fSmrg	else
779209ff23fSmrg	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1;
780209ff23fSmrg    } else {
781209ff23fSmrg	save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2;
782209ff23fSmrg    }
783209ff23fSmrg
784209ff23fSmrg    save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE;
785209ff23fSmrg
786209ff23fSmrg    save->tv_sync_size = constPtr->horResolution + 8;
787209ff23fSmrg
788209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
789209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
790209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_M ||
791209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_60)
792209ff23fSmrg	vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME;
793209ff23fSmrg    else
794209ff23fSmrg	vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME;
795209ff23fSmrg
796209ff23fSmrg    save->tv_vscaler_cntl1 = RADEON_Y_W_EN;
797209ff23fSmrg    save->tv_vscaler_cntl1 =
798209ff23fSmrg	(save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000);
799209ff23fSmrg    save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
800209ff23fSmrg    if (constPtr->horResolution == 1024)
801209ff23fSmrg	save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT);
802209ff23fSmrg    else
803209ff23fSmrg	save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT);
804209ff23fSmrg
805209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
806209ff23fSmrg        radeon_output->tvStd == TV_STD_NTSC_J ||
807209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M ||
808209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_60)
809209ff23fSmrg	flicker_removal =
810209ff23fSmrg	    (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5;
811209ff23fSmrg    else
812209ff23fSmrg	flicker_removal =
813209ff23fSmrg	    (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5;
814209ff23fSmrg
815209ff23fSmrg    if (flicker_removal < 3)
816209ff23fSmrg	flicker_removal = 3;
817209ff23fSmrg    for (i = 0; i < 6; ++i) {
818209ff23fSmrg	if (flicker_removal == SLOPE_limit[i])
819209ff23fSmrg	    break;
820209ff23fSmrg    }
821209ff23fSmrg    save->tv_y_saw_tooth_cntl =
822209ff23fSmrg	(vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8
823209ff23fSmrg	| ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16);
824209ff23fSmrg    save->tv_y_fall_cntl =
825209ff23fSmrg	(YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) |
826209ff23fSmrg	RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) /
827209ff23fSmrg	1024;
828209ff23fSmrg    save->tv_y_rise_cntl =
829209ff23fSmrg	RADEON_Y_RISE_PING_PONG
830209ff23fSmrg	| (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024;
831209ff23fSmrg
832209ff23fSmrg    save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0)
833209ff23fSmrg			      | (0x10 << 24)
834209ff23fSmrg			      | RADEON_DITHER_MODE
835209ff23fSmrg			      | RADEON_Y_OUTPUT_DITHER_EN
836209ff23fSmrg			      | RADEON_UV_OUTPUT_DITHER_EN
837209ff23fSmrg			      | RADEON_UV_TO_BUF_DITHER_EN);
838209ff23fSmrg
839209ff23fSmrg    tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
840209ff23fSmrg    tmp = ((16384 * 256 * 10) / tmp + 5) / 10;
841209ff23fSmrg    tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
842209ff23fSmrg    save->tv_timing_cntl = tmp;
843209ff23fSmrg
844209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
845209ff23fSmrg        radeon_output->tvStd == TV_STD_NTSC_J ||
846209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M ||
847209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_60)
848209ff23fSmrg	save->tv_dac_cntl = radeon_output->ntsc_tvdac_adj;
849209ff23fSmrg    else
850209ff23fSmrg	save->tv_dac_cntl = radeon_output->pal_tvdac_adj;
851209ff23fSmrg
852209ff23fSmrg    save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
853209ff23fSmrg
854209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
855209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J)
856209ff23fSmrg	save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
857209ff23fSmrg    else
858209ff23fSmrg	save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
859209ff23fSmrg
860209ff23fSmrg#if 0
861209ff23fSmrg    /* needs fixes for r4xx */
862209ff23fSmrg    save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD
863209ff23fSmrg	                 | RADEON_TV_DAC_BDACPD);
864209ff23fSmrg
865209ff23fSmrg    if (radeon_output->MonType == MT_CTV) {
866209ff23fSmrg	save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD;
867209ff23fSmrg    }
868209ff23fSmrg
869209ff23fSmrg    if (radeon_output->MonType == MT_STV) {
870209ff23fSmrg	save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
871209ff23fSmrg			       RADEON_TV_DAC_GDACPD);
872209ff23fSmrg    }
873209ff23fSmrg#endif
874209ff23fSmrg
875209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
876209ff23fSmrg        radeon_output->tvStd == TV_STD_NTSC_J)
877209ff23fSmrg	save->tv_pll_cntl = (NTSC_TV_PLL_M & RADEON_TV_M0LO_MASK) |
878209ff23fSmrg	    (((NTSC_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
879209ff23fSmrg	    ((NTSC_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
880209ff23fSmrg	    (((NTSC_TV_PLL_N >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
881209ff23fSmrg	    ((NTSC_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
882209ff23fSmrg    else
883209ff23fSmrg	save->tv_pll_cntl = (PAL_TV_PLL_M & RADEON_TV_M0LO_MASK) |
884209ff23fSmrg	    (((PAL_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
885209ff23fSmrg	    ((PAL_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
886209ff23fSmrg	    (((PAL_TV_PLL_N >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
887209ff23fSmrg	    ((PAL_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
888209ff23fSmrg
889209ff23fSmrg    save->tv_pll_cntl1 =  (((4 & RADEON_TVPCP_MASK)<< RADEON_TVPCP_SHIFT) |
890209ff23fSmrg			   ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) |
891209ff23fSmrg			   ((1 & RADEON_TVPDC_MASK)<< RADEON_TVPDC_SHIFT) |
892209ff23fSmrg			   RADEON_TVCLK_SRC_SEL_TVPLL |
893209ff23fSmrg			   RADEON_TVPLL_TEST_DIS);
894209ff23fSmrg
895209ff23fSmrg    save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN;
896209ff23fSmrg
897209ff23fSmrg    save->tv_uv_adr = 0xc8;
898209ff23fSmrg
899209ff23fSmrg    save->tv_vdisp = constPtr->verResolution - 1;
900209ff23fSmrg
901209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
902209ff23fSmrg        radeon_output->tvStd == TV_STD_NTSC_J ||
903209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M ||
904209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_60)
905209ff23fSmrg	save->tv_ftotal = NTSC_TV_VFTOTAL;
906209ff23fSmrg    else
907209ff23fSmrg	save->tv_ftotal = PAL_TV_VFTOTAL;
908209ff23fSmrg
909209ff23fSmrg    save->tv_vtotal = constPtr->verTotal - 1;
910209ff23fSmrg
911209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
912209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
913209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_M) {
914209ff23fSmrg	hor_timing = hor_timing_NTSC;
915209ff23fSmrg    } else {
916209ff23fSmrg	hor_timing = hor_timing_PAL;
917209ff23fSmrg    }
918209ff23fSmrg
919209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
920209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
921209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_M ||
922209ff23fSmrg	radeon_output->tvStd == TV_STD_PAL_60) {
923209ff23fSmrg	vert_timing = vert_timing_NTSC;
924209ff23fSmrg    } else {
925209ff23fSmrg	vert_timing = vert_timing_PAL;
926209ff23fSmrg    }
927209ff23fSmrg
928209ff23fSmrg    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
929209ff23fSmrg	if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0)
930209ff23fSmrg	    break;
931209ff23fSmrg    }
932209ff23fSmrg
933209ff23fSmrg    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) {
934209ff23fSmrg	if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0)
935209ff23fSmrg	    break;
936209ff23fSmrg    }
937209ff23fSmrg
938209ff23fSmrg    /*
939209ff23fSmrg     * This must be called AFTER loading timing tables as they are modified by this function
940209ff23fSmrg     */
941209ff23fSmrg    RADEONInitTVRestarts(output, save, mode);
942209ff23fSmrg
943209ff23fSmrg    save->dac_cntl &= ~RADEON_DAC_TVO_EN;
944209ff23fSmrg
945209ff23fSmrg    if (IS_R300_VARIANT)
946209ff23fSmrg        save->gpiopad_a = info->SavedReg->gpiopad_a & ~1;
947209ff23fSmrg
948209ff23fSmrg    if (IsPrimary) {
949209ff23fSmrg	save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
950209ff23fSmrg	save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC
951209ff23fSmrg				   | RADEON_DISP_TV_SOURCE_CRTC);
952209ff23fSmrg    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
953209ff23fSmrg	    save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2;
954209ff23fSmrg    	} else {
955209ff23fSmrg            save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
956209ff23fSmrg    	}
957209ff23fSmrg    } else {
958209ff23fSmrg	save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
959209ff23fSmrg	save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC;
960209ff23fSmrg
961209ff23fSmrg    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
962209ff23fSmrg	    save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2;
963209ff23fSmrg    	} else {
964209ff23fSmrg            save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
965209ff23fSmrg    	}
966209ff23fSmrg    }
967209ff23fSmrg}
968209ff23fSmrg
969209ff23fSmrg
970209ff23fSmrg/* Set hw registers for a new h/v position & h size */
971209ff23fSmrgvoid RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode)
972209ff23fSmrg{
973209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
974209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(pScrn);
975209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
976209ff23fSmrg    Bool reloadTable;
977209ff23fSmrg    RADEONSavePtr restore = info->ModeReg;
978209ff23fSmrg
979209ff23fSmrg    reloadTable = RADEONInitTVRestarts(output, restore, mode);
980209ff23fSmrg
981209ff23fSmrg    RADEONRestoreTVRestarts(pScrn, restore);
982209ff23fSmrg
983209ff23fSmrg    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
984209ff23fSmrg
985209ff23fSmrg    if (reloadTable) {
986209ff23fSmrg	 OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl
987209ff23fSmrg		                       | RADEON_TV_ASYNC_RST
988209ff23fSmrg		                       | RADEON_CRT_ASYNC_RST
989209ff23fSmrg		                       | RADEON_RESTART_PHASE_FIX);
990209ff23fSmrg
991209ff23fSmrg	RADEONRestoreTVTimingTables(pScrn, restore);
992209ff23fSmrg
993209ff23fSmrg	OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
994209ff23fSmrg    }
995209ff23fSmrg}
996209ff23fSmrg
997209ff23fSmrgvoid RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
998209ff23fSmrg				    DisplayModePtr mode, xf86OutputPtr output)
999209ff23fSmrg{
1000209ff23fSmrg    const TVModeConstants *constPtr;
1001209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1002209ff23fSmrg
1003209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1004209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
1005209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
1006209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M)
1007209ff23fSmrg	constPtr = &availableTVModes[0];
1008209ff23fSmrg    else
1009209ff23fSmrg	constPtr = &availableTVModes[1];
1010209ff23fSmrg
1011209ff23fSmrg    save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
1012209ff23fSmrg	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
1013209ff23fSmrg
1014209ff23fSmrg    save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid
1015209ff23fSmrg				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
1016209ff23fSmrg	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
1017209ff23fSmrg	(constPtr->horSyncStart & 7);
1018209ff23fSmrg
1019209ff23fSmrg    save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
1020209ff23fSmrg	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
1021209ff23fSmrg
1022209ff23fSmrg    save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
1023209ff23fSmrg	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
1024209ff23fSmrg
1025209ff23fSmrg}
1026209ff23fSmrg
1027209ff23fSmrgvoid RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1028209ff23fSmrg				   DisplayModePtr mode, xf86OutputPtr output)
1029209ff23fSmrg{
1030209ff23fSmrg    unsigned postDiv;
1031209ff23fSmrg    const TVModeConstants *constPtr;
1032209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1033209ff23fSmrg
1034209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1035209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
1036209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
1037209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M)
1038209ff23fSmrg	constPtr = &availableTVModes[0];
1039209ff23fSmrg    else
1040209ff23fSmrg	constPtr = &availableTVModes[1];
1041209ff23fSmrg
1042209ff23fSmrg    save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN;
1043209ff23fSmrg
1044209ff23fSmrg    save->ppll_ref_div = constPtr->crtcPLL_M;
1045209ff23fSmrg
1046209ff23fSmrg    switch (constPtr->crtcPLL_postDiv) {
1047209ff23fSmrg    case 1:
1048209ff23fSmrg	postDiv = 0;
1049209ff23fSmrg	break;
1050209ff23fSmrg    case 2:
1051209ff23fSmrg	postDiv = 1;
1052209ff23fSmrg	break;
1053209ff23fSmrg    case 3:
1054209ff23fSmrg	postDiv = 4;
1055209ff23fSmrg	break;
1056209ff23fSmrg    case 4:
1057209ff23fSmrg	postDiv = 2;
1058209ff23fSmrg	break;
1059209ff23fSmrg    case 6:
1060209ff23fSmrg	postDiv = 6;
1061209ff23fSmrg	break;
1062209ff23fSmrg    case 8:
1063209ff23fSmrg	postDiv = 3;
1064209ff23fSmrg	break;
1065209ff23fSmrg    case 12:
1066209ff23fSmrg	postDiv = 7;
1067209ff23fSmrg	break;
1068209ff23fSmrg    case 16:
1069209ff23fSmrg    default:
1070209ff23fSmrg	postDiv = 5;
1071209ff23fSmrg	break;
1072209ff23fSmrg    }
1073209ff23fSmrg
1074209ff23fSmrg    save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
1075209ff23fSmrg
1076209ff23fSmrg    save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL);
1077209ff23fSmrg    save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK;
1078209ff23fSmrg
1079209ff23fSmrg}
1080209ff23fSmrg
1081209ff23fSmrgvoid RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1082209ff23fSmrg				     DisplayModePtr mode, xf86OutputPtr output)
1083209ff23fSmrg{
1084209ff23fSmrg    const TVModeConstants *constPtr;
1085209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1086209ff23fSmrg
1087209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1088209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
1089209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
1090209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M)
1091209ff23fSmrg	constPtr = &availableTVModes[0];
1092209ff23fSmrg    else
1093209ff23fSmrg	constPtr = &availableTVModes[1];
1094209ff23fSmrg
1095209ff23fSmrg    save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
1096209ff23fSmrg	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
1097209ff23fSmrg
1098209ff23fSmrg    save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid
1099209ff23fSmrg				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
1100209ff23fSmrg	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
1101209ff23fSmrg	(constPtr->horSyncStart & 7);
1102209ff23fSmrg
1103209ff23fSmrg    save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
1104209ff23fSmrg	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
1105209ff23fSmrg
1106209ff23fSmrg    save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
1107209ff23fSmrg	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
1108209ff23fSmrg
1109209ff23fSmrg}
1110209ff23fSmrg
1111209ff23fSmrgvoid RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1112209ff23fSmrg				    DisplayModePtr mode, xf86OutputPtr output)
1113209ff23fSmrg{
1114209ff23fSmrg    unsigned postDiv;
1115209ff23fSmrg    const TVModeConstants *constPtr;
1116209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1117209ff23fSmrg
1118209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1119209ff23fSmrg    if (radeon_output->tvStd == TV_STD_NTSC ||
1120209ff23fSmrg	radeon_output->tvStd == TV_STD_NTSC_J ||
1121209ff23fSmrg        radeon_output->tvStd == TV_STD_PAL_M)
1122209ff23fSmrg	constPtr = &availableTVModes[0];
1123209ff23fSmrg    else
1124209ff23fSmrg	constPtr = &availableTVModes[1];
1125209ff23fSmrg
1126209ff23fSmrg    save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */
1127209ff23fSmrg
1128209ff23fSmrg    save->p2pll_ref_div = constPtr->crtcPLL_M;
1129209ff23fSmrg
1130209ff23fSmrg    switch (constPtr->crtcPLL_postDiv) {
1131209ff23fSmrg    case 1:
1132209ff23fSmrg	postDiv = 0;
1133209ff23fSmrg	break;
1134209ff23fSmrg    case 2:
1135209ff23fSmrg	postDiv = 1;
1136209ff23fSmrg	break;
1137209ff23fSmrg    case 3:
1138209ff23fSmrg	postDiv = 4;
1139209ff23fSmrg	break;
1140209ff23fSmrg    case 4:
1141209ff23fSmrg	postDiv = 2;
1142209ff23fSmrg	break;
1143209ff23fSmrg    case 6:
1144209ff23fSmrg	postDiv = 6;
1145209ff23fSmrg	break;
1146209ff23fSmrg    case 8:
1147209ff23fSmrg	postDiv = 3;
1148209ff23fSmrg	break;
1149209ff23fSmrg    case 12:
1150209ff23fSmrg	postDiv = 7;
1151209ff23fSmrg	break;
1152209ff23fSmrg    case 16:
1153209ff23fSmrg    default:
1154209ff23fSmrg	postDiv = 5;
1155209ff23fSmrg	break;
1156209ff23fSmrg    }
1157209ff23fSmrg
1158209ff23fSmrg    save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
1159209ff23fSmrg
1160209ff23fSmrg    save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK;
1161209ff23fSmrg    save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK
1162209ff23fSmrg			   | RADEON_PIXCLK_TV_SRC_SEL);
1163209ff23fSmrg
1164209ff23fSmrg}
1165