radeon_tv.c revision c503f109
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"
26b7e1c893Smrg#include "radeon_atombios.h"
27209ff23fSmrg
28209ff23fSmrg/**********************************************************************
29209ff23fSmrg *
30209ff23fSmrg * ModeConstants
31209ff23fSmrg *
32209ff23fSmrg * Storage of constants related to a single video mode
33209ff23fSmrg *
34209ff23fSmrg **********************************************************************/
35209ff23fSmrg
36209ff23fSmrgtypedef struct
37209ff23fSmrg{
38209ff23fSmrg    uint16_t horResolution;
39209ff23fSmrg    uint16_t verResolution;
40209ff23fSmrg    TVStd  standard;
41209ff23fSmrg    uint16_t horTotal;
42209ff23fSmrg    uint16_t verTotal;
43209ff23fSmrg    uint16_t horStart;
44209ff23fSmrg    uint16_t horSyncStart;
45209ff23fSmrg    uint16_t verSyncStart;
46209ff23fSmrg    unsigned defRestart;
47209ff23fSmrg    uint16_t crtcPLL_N;
48209ff23fSmrg    uint8_t  crtcPLL_M;
49209ff23fSmrg    uint8_t  crtcPLL_postDiv;
50209ff23fSmrg    unsigned pixToTV;
51209ff23fSmrg} TVModeConstants;
52209ff23fSmrg
53209ff23fSmrgstatic const uint16_t hor_timing_NTSC[] =
54209ff23fSmrg{
55209ff23fSmrg    0x0007,
56209ff23fSmrg    0x003f,
57209ff23fSmrg    0x0263,
58209ff23fSmrg    0x0a24,
59209ff23fSmrg    0x2a6b,
60209ff23fSmrg    0x0a36,
61209ff23fSmrg    0x126d, /* H_TABLE_POS1 */
62209ff23fSmrg    0x1bfe,
63209ff23fSmrg    0x1a8f, /* H_TABLE_POS2 */
64209ff23fSmrg    0x1ec7,
65209ff23fSmrg    0x3863,
66209ff23fSmrg    0x1bfe,
67209ff23fSmrg    0x1bfe,
68209ff23fSmrg    0x1a2a,
69209ff23fSmrg    0x1e95,
70209ff23fSmrg    0x0e31,
71209ff23fSmrg    0x201b,
72209ff23fSmrg    0
73209ff23fSmrg};
74209ff23fSmrg
75209ff23fSmrgstatic const uint16_t vert_timing_NTSC[] =
76209ff23fSmrg{
77209ff23fSmrg    0x2001,
78209ff23fSmrg    0x200d,
79209ff23fSmrg    0x1006,
80209ff23fSmrg    0x0c06,
81209ff23fSmrg    0x1006,
82209ff23fSmrg    0x1818,
83209ff23fSmrg    0x21e3,
84209ff23fSmrg    0x1006,
85209ff23fSmrg    0x0c06,
86209ff23fSmrg    0x1006,
87209ff23fSmrg    0x1817,
88209ff23fSmrg    0x21d4,
89209ff23fSmrg    0x0002,
90209ff23fSmrg    0
91209ff23fSmrg};
92209ff23fSmrg
93209ff23fSmrgstatic const uint16_t hor_timing_PAL[] =
94209ff23fSmrg{
95209ff23fSmrg    0x0007,
96209ff23fSmrg    0x0058,
97209ff23fSmrg    0x027c,
98209ff23fSmrg    0x0a31,
99209ff23fSmrg    0x2a77,
100209ff23fSmrg    0x0a95,
101209ff23fSmrg    0x124f, /* H_TABLE_POS1 */
102209ff23fSmrg    0x1bfe,
103209ff23fSmrg    0x1b22, /* H_TABLE_POS2 */
104209ff23fSmrg    0x1ef9,
105209ff23fSmrg    0x387c,
106209ff23fSmrg    0x1bfe,
107209ff23fSmrg    0x1bfe,
108209ff23fSmrg    0x1b31,
109209ff23fSmrg    0x1eb5,
110209ff23fSmrg    0x0e43,
111209ff23fSmrg    0x201b,
112209ff23fSmrg    0
113209ff23fSmrg};
114209ff23fSmrg
115209ff23fSmrgstatic const uint16_t vert_timing_PAL[] =
116209ff23fSmrg{
117209ff23fSmrg    0x2001,
118209ff23fSmrg    0x200c,
119209ff23fSmrg    0x1005,
120209ff23fSmrg    0x0c05,
121209ff23fSmrg    0x1005,
122209ff23fSmrg    0x1401,
123209ff23fSmrg    0x1821,
124209ff23fSmrg    0x2240,
125209ff23fSmrg    0x1005,
126209ff23fSmrg    0x0c05,
127209ff23fSmrg    0x1005,
128209ff23fSmrg    0x1401,
129209ff23fSmrg    0x1822,
130209ff23fSmrg    0x2230,
131209ff23fSmrg    0x0002,
132209ff23fSmrg    0
133209ff23fSmrg};
134209ff23fSmrg
135209ff23fSmrg/**********************************************************************
136209ff23fSmrg *
137209ff23fSmrg * availableModes
138209ff23fSmrg *
139209ff23fSmrg * Table of all allowed modes for tv output
140209ff23fSmrg *
141209ff23fSmrg **********************************************************************/
142209ff23fSmrgstatic const TVModeConstants availableTVModes[] =
143209ff23fSmrg{
144b7e1c893Smrg    {   /* NTSC timing for 27 Mhz ref clk */
145209ff23fSmrg	800,                /* horResolution */
146209ff23fSmrg	600,                /* verResolution */
147209ff23fSmrg	TV_STD_NTSC,        /* standard */
148209ff23fSmrg	990,                /* horTotal */
149209ff23fSmrg	740,                /* verTotal */
150209ff23fSmrg	813,                /* horStart */
151209ff23fSmrg	824,                /* horSyncStart */
152209ff23fSmrg	632,                /* verSyncStart */
153209ff23fSmrg	625592,             /* defRestart */
154209ff23fSmrg	592,                /* crtcPLL_N */
155209ff23fSmrg	91,                 /* crtcPLL_M */
156209ff23fSmrg	4,                  /* crtcPLL_postDiv */
157209ff23fSmrg	1022,               /* pixToTV */
158209ff23fSmrg    },
159b7e1c893Smrg    {   /* PAL timing for 27 Mhz ref clk */
160209ff23fSmrg	800,               /* horResolution */
161209ff23fSmrg	600,               /* verResolution */
162209ff23fSmrg	TV_STD_PAL,        /* standard */
163209ff23fSmrg	1144,              /* horTotal */
164209ff23fSmrg	706,               /* verTotal */
165209ff23fSmrg	812,               /* horStart */
166209ff23fSmrg	824,               /* horSyncStart */
167209ff23fSmrg	669,               /* verSyncStart */
168209ff23fSmrg	696700,            /* defRestart */
169209ff23fSmrg	1382,              /* crtcPLL_N */
170209ff23fSmrg	231,               /* crtcPLL_M */
171209ff23fSmrg	4,                 /* crtcPLL_postDiv */
172209ff23fSmrg	759,               /* pixToTV */
173b7e1c893Smrg    },
174b7e1c893Smrg    {   /* NTSC timing for 14 Mhz ref clk */
175b7e1c893Smrg	800,                /* horResolution */
176b7e1c893Smrg	600,                /* verResolution */
177b7e1c893Smrg	TV_STD_NTSC,        /* standard */
178b7e1c893Smrg	1018,               /* horTotal */
179b7e1c893Smrg	727,                /* verTotal */
180b7e1c893Smrg	813,                /* horStart */
181b7e1c893Smrg	840,                /* horSyncStart */
182b7e1c893Smrg	633,                /* verSyncStart */
183b7e1c893Smrg	630627,             /* defRestart */
184b7e1c893Smrg	347,                /* crtcPLL_N */
185b7e1c893Smrg	14,                 /* crtcPLL_M */
186b7e1c893Smrg	8,                  /* crtcPLL_postDiv */
187b7e1c893Smrg	1022,               /* pixToTV */
188b7e1c893Smrg    },
189209ff23fSmrg};
190209ff23fSmrg
191209ff23fSmrg#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ]))
192209ff23fSmrg
193209ff23fSmrgstatic long YCOEF_value[5] = { 2, 2, 0, 4, 0 };
194209ff23fSmrgstatic long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 };
195209ff23fSmrgstatic long SLOPE_value[5] = { 1, 2, 2, 4, 8 };
196209ff23fSmrgstatic long SLOPE_limit[5] = { 6, 5, 4, 3, 2 };
197209ff23fSmrg
198209ff23fSmrg
199209ff23fSmrgstatic void
200209ff23fSmrgRADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests,
201209ff23fSmrg		  unsigned nWaitLoops, unsigned cntThreshold)
202209ff23fSmrg{
203209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
204209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
205209ff23fSmrg    uint32_t savePLLTest;
206209ff23fSmrg    unsigned i;
207209ff23fSmrg    unsigned j;
208209ff23fSmrg
209209ff23fSmrg    OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100);
210209ff23fSmrg
211209ff23fSmrg    savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL);
212209ff23fSmrg
213209ff23fSmrg    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B);
214209ff23fSmrg
215209ff23fSmrg    /* XXX: these should probably be OUTPLL to avoid various PLL errata */
216209ff23fSmrg
217209ff23fSmrg    OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL);
218209ff23fSmrg
219209ff23fSmrg    for (i = 0; i < nTests; i++) {
220209ff23fSmrg	OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0);
221209ff23fSmrg
222209ff23fSmrg	for (j = 0; j < nWaitLoops; j++)
223209ff23fSmrg	    if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold)
224209ff23fSmrg		break;
225209ff23fSmrg    }
226209ff23fSmrg
227209ff23fSmrg    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest);
228209ff23fSmrg
229209ff23fSmrg    OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff);
230209ff23fSmrg}
231209ff23fSmrg
232209ff23fSmrg/* Write to TV FIFO RAM */
233209ff23fSmrgstatic void
234209ff23fSmrgRADEONWriteTVFIFO(ScrnInfoPtr pScrn, uint16_t addr,
235209ff23fSmrg		  uint32_t value)
236209ff23fSmrg{
237209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
238209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
239209ff23fSmrg    uint32_t tmp;
240209ff23fSmrg    int i = 0;
241209ff23fSmrg
242209ff23fSmrg    OUTREG(RADEON_TV_HOST_WRITE_DATA, value);
243209ff23fSmrg
244209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
245209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT);
246209ff23fSmrg
247209ff23fSmrg    do {
248209ff23fSmrg	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
249209ff23fSmrg	if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0)
250209ff23fSmrg	    break;
251209ff23fSmrg	i++;
252209ff23fSmrg    }
253209ff23fSmrg    while (i < 10000);
254209ff23fSmrg    /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/
255209ff23fSmrg
256209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
257209ff23fSmrg}
258209ff23fSmrg
259209ff23fSmrg/* Read from TV FIFO RAM */
260209ff23fSmrgstatic uint32_t
261209ff23fSmrgRADEONReadTVFIFO(ScrnInfoPtr pScrn, uint16_t addr)
262209ff23fSmrg{
263209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
264209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
265209ff23fSmrg    uint32_t tmp;
266209ff23fSmrg    int i = 0;
267209ff23fSmrg
268209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
269209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD);
270209ff23fSmrg
271209ff23fSmrg    do {
272209ff23fSmrg	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
273209ff23fSmrg	if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0)
274209ff23fSmrg	    break;
275209ff23fSmrg	i++;
276209ff23fSmrg    }
277209ff23fSmrg    while (i < 10000);
278209ff23fSmrg    /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/
279209ff23fSmrg
280209ff23fSmrg    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
281209ff23fSmrg
282209ff23fSmrg    return INREG(RADEON_TV_HOST_READ_DATA);
283209ff23fSmrg}
284209ff23fSmrg
285209ff23fSmrg/* Get FIFO addresses of horizontal & vertical code timing tables from
286209ff23fSmrg * settings of uv_adr register.
287209ff23fSmrg */
288209ff23fSmrgstatic uint16_t
289209ff23fSmrgRADEONGetHTimingTablesAddr(uint32_t tv_uv_adr)
290209ff23fSmrg{
291209ff23fSmrg    uint16_t hTable;
292209ff23fSmrg
293209ff23fSmrg    switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) {
294209ff23fSmrg    case 0:
295209ff23fSmrg	hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL;
296209ff23fSmrg	break;
297209ff23fSmrg    case 1:
298209ff23fSmrg	hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2;
299209ff23fSmrg	break;
300209ff23fSmrg    case 2:
301209ff23fSmrg	hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2;
302209ff23fSmrg	break;
303209ff23fSmrg    default:
304209ff23fSmrg	/* Of course, this should never happen */
305209ff23fSmrg	hTable = 0;
306209ff23fSmrg	break;
307209ff23fSmrg    }
308209ff23fSmrg    return hTable;
309209ff23fSmrg}
310209ff23fSmrg
311209ff23fSmrgstatic uint16_t
312209ff23fSmrgRADEONGetVTimingTablesAddr(uint32_t tv_uv_adr)
313209ff23fSmrg{
314209ff23fSmrg    uint16_t vTable;
315209ff23fSmrg
316209ff23fSmrg    switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) {
317209ff23fSmrg    case 0:
318209ff23fSmrg	vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1;
319209ff23fSmrg	break;
320209ff23fSmrg    case 1:
321209ff23fSmrg	vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
322209ff23fSmrg	break;
323209ff23fSmrg    case 2:
324209ff23fSmrg	vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
325209ff23fSmrg	break;
326209ff23fSmrg    default:
327209ff23fSmrg	/* Of course, this should never happen */
328209ff23fSmrg	vTable = 0;
329209ff23fSmrg	break;
330209ff23fSmrg    }
331209ff23fSmrg    return vTable;
332209ff23fSmrg}
333209ff23fSmrg
334209ff23fSmrg/* Restore horizontal/vertical timing code tables */
335209ff23fSmrgstatic void
336209ff23fSmrgRADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore)
337209ff23fSmrg{
338209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
339209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
340209ff23fSmrg    uint16_t hTable;
341209ff23fSmrg    uint16_t vTable;
342209ff23fSmrg    uint32_t tmp;
343209ff23fSmrg    unsigned i;
344209ff23fSmrg
345209ff23fSmrg    OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr);
346209ff23fSmrg    hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr);
347209ff23fSmrg    vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr);
348209ff23fSmrg
349209ff23fSmrg    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) {
350209ff23fSmrg	tmp = ((uint32_t)restore->h_code_timing[ i ] << 14) | ((uint32_t)restore->h_code_timing[ i + 1 ]);
351209ff23fSmrg	RADEONWriteTVFIFO(pScrn, hTable, tmp);
352209ff23fSmrg	if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0)
353209ff23fSmrg	    break;
354209ff23fSmrg    }
355209ff23fSmrg
356209ff23fSmrg    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) {
357209ff23fSmrg	tmp = ((uint32_t)restore->v_code_timing[ i + 1 ] << 14) | ((uint32_t)restore->v_code_timing[ i ]);
358209ff23fSmrg	RADEONWriteTVFIFO(pScrn, vTable, tmp);
359209ff23fSmrg	if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0)
360209ff23fSmrg	    break;
361209ff23fSmrg    }
362209ff23fSmrg}
363209ff23fSmrg
364209ff23fSmrg/* restore TV PLLs */
365209ff23fSmrgstatic void
366209ff23fSmrgRADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
367209ff23fSmrg{
368209ff23fSmrg
369209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL);
370209ff23fSmrg    OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl);
371209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET);
372209ff23fSmrg
373209ff23fSmrg    RADEONWaitPLLLock(pScrn, 200, 800, 135);
374209ff23fSmrg
375209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET);
376209ff23fSmrg
377209ff23fSmrg    RADEONWaitPLLLock(pScrn, 300, 160, 27);
378209ff23fSmrg    RADEONWaitPLLLock(pScrn, 200, 800, 135);
379209ff23fSmrg
380209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf);
381209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL);
382209ff23fSmrg
383209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK);
384209ff23fSmrg    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP);
385209ff23fSmrg}
386209ff23fSmrg
387209ff23fSmrg/* Restore TV horizontal/vertical settings */
388209ff23fSmrgstatic void
389209ff23fSmrgRADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
390209ff23fSmrg{
391209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
392209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
393209ff23fSmrg
394209ff23fSmrg    OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl);
395209ff23fSmrg
396209ff23fSmrg    OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal);
397209ff23fSmrg    OUTREG(RADEON_TV_HDISP, restore->tv_hdisp);
398209ff23fSmrg    OUTREG(RADEON_TV_HSTART, restore->tv_hstart);
399209ff23fSmrg
400209ff23fSmrg    OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal);
401209ff23fSmrg    OUTREG(RADEON_TV_VDISP, restore->tv_vdisp);
402209ff23fSmrg
403209ff23fSmrg    OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal);
404209ff23fSmrg
405209ff23fSmrg    OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1);
406209ff23fSmrg    OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2);
407209ff23fSmrg
408209ff23fSmrg    OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl);
409209ff23fSmrg    OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl);
410209ff23fSmrg    OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl);
411209ff23fSmrg}
412209ff23fSmrg
413209ff23fSmrg/* restore TV RESTART registers */
414209ff23fSmrgstatic void
415209ff23fSmrgRADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore)
416209ff23fSmrg{
417209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
418209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
419209ff23fSmrg
420209ff23fSmrg    OUTREG(RADEON_TV_FRESTART, restore->tv_frestart);
421209ff23fSmrg    OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart);
422209ff23fSmrg    OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart);
423209ff23fSmrg}
424209ff23fSmrg
425209ff23fSmrg/* restore tv standard & output muxes */
426209ff23fSmrgstatic void
427209ff23fSmrgRADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore)
428209ff23fSmrg{
429209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
430209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
431209ff23fSmrg
432209ff23fSmrg    OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl);
433209ff23fSmrg
434209ff23fSmrg    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
435209ff23fSmrg
436209ff23fSmrg    OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1);
437209ff23fSmrg    OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2);
438209ff23fSmrg
439209ff23fSmrg    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl);
440209ff23fSmrg
441209ff23fSmrg    OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl);
442209ff23fSmrg}
443209ff23fSmrg
444209ff23fSmrg/* Restore TV out regs */
445209ff23fSmrgvoid
446209ff23fSmrgRADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
447209ff23fSmrg{
448209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
449209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
450209ff23fSmrg
451209ff23fSmrg    ErrorF("Entering Restore TV\n");
452209ff23fSmrg
453209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
454209ff23fSmrg				   | RADEON_TV_ASYNC_RST
455209ff23fSmrg				   | RADEON_CRT_ASYNC_RST
456209ff23fSmrg				   | RADEON_TV_FIFO_ASYNC_RST));
457209ff23fSmrg
458209ff23fSmrg    /* Temporarily turn the TV DAC off */
459209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK)
460209ff23fSmrg				| RADEON_TV_DAC_BGSLEEP
461209ff23fSmrg				| RADEON_TV_DAC_RDACPD
462209ff23fSmrg				| RADEON_TV_DAC_GDACPD
463209ff23fSmrg				| RADEON_TV_DAC_BDACPD));
464209ff23fSmrg
465209ff23fSmrg    ErrorF("Restore TV PLL\n");
466209ff23fSmrg    RADEONRestoreTVPLLRegisters(pScrn, restore);
467209ff23fSmrg
468209ff23fSmrg    ErrorF("Restore TVHV\n");
469209ff23fSmrg    RADEONRestoreTVHVRegisters(pScrn, restore);
470209ff23fSmrg
471209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
472209ff23fSmrg				   | RADEON_TV_ASYNC_RST
473209ff23fSmrg				   | RADEON_CRT_ASYNC_RST));
474209ff23fSmrg
475209ff23fSmrg    ErrorF("Restore TV Restarts\n");
476209ff23fSmrg    RADEONRestoreTVRestarts(pScrn, restore);
477209ff23fSmrg
478209ff23fSmrg    ErrorF("Restore Timing Tables\n");
479209ff23fSmrg    RADEONRestoreTVTimingTables(pScrn, restore);
480209ff23fSmrg
481209ff23fSmrg
482209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
483209ff23fSmrg				   | RADEON_TV_ASYNC_RST));
484209ff23fSmrg
485209ff23fSmrg    ErrorF("Restore TV standard\n");
486209ff23fSmrg    RADEONRestoreTVOutputStd(pScrn, restore);
487209ff23fSmrg
488209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
489209ff23fSmrg
490209ff23fSmrg    OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings);
491209ff23fSmrg    OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings);
492209ff23fSmrg
493209ff23fSmrg    OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
494209ff23fSmrg
495209ff23fSmrg    ErrorF("Leaving Restore TV\n");
496209ff23fSmrg}
497209ff23fSmrg
498209ff23fSmrg/* Save horizontal/vertical timing code tables */
499209ff23fSmrgstatic void
500209ff23fSmrgRADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save)
501209ff23fSmrg{
502209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
503209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
504209ff23fSmrg    uint16_t hTable;
505209ff23fSmrg    uint16_t vTable;
506209ff23fSmrg    uint32_t tmp;
507209ff23fSmrg    unsigned i;
508209ff23fSmrg
509209ff23fSmrg    save->tv_uv_adr = INREG(RADEON_TV_UV_ADR);
510209ff23fSmrg    hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr);
511209ff23fSmrg    vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr);
512209ff23fSmrg
513209ff23fSmrg    /*
514209ff23fSmrg     * Reset FIFO arbiter in order to be able to access FIFO RAM
515209ff23fSmrg     */
516209ff23fSmrg
517209ff23fSmrg    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
518209ff23fSmrg				   | RADEON_CRT_ASYNC_RST
519209ff23fSmrg				   | RADEON_RESTART_PHASE_FIX
520209ff23fSmrg				   | RADEON_CRT_FIFO_CE_EN
521209ff23fSmrg				   | RADEON_TV_FIFO_CE_EN
522209ff23fSmrg				   | RADEON_TV_ON));
523209ff23fSmrg
524209ff23fSmrg    /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/
525209ff23fSmrg
526209ff23fSmrg    ErrorF("saveTimingTables: reading timing tables\n");
527209ff23fSmrg
528209ff23fSmrg    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) {
529209ff23fSmrg	tmp = RADEONReadTVFIFO(pScrn, hTable--);
530209ff23fSmrg	save->h_code_timing[ i     ] = (uint16_t)((tmp >> 14) & 0x3fff);
531209ff23fSmrg	save->h_code_timing[ i + 1 ] = (uint16_t)(tmp & 0x3fff);
532209ff23fSmrg
533209ff23fSmrg	if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0)
534209ff23fSmrg	    break;
535209ff23fSmrg    }
536209ff23fSmrg
537209ff23fSmrg    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) {
538209ff23fSmrg	tmp = RADEONReadTVFIFO(pScrn, vTable++);
539209ff23fSmrg	save->v_code_timing[ i     ] = (uint16_t)(tmp & 0x3fff);
540209ff23fSmrg	save->v_code_timing[ i + 1 ] = (uint16_t)((tmp >> 14) & 0x3fff);
541209ff23fSmrg
542209ff23fSmrg	if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0)
543209ff23fSmrg	    break;
544209ff23fSmrg    }
545209ff23fSmrg}
546209ff23fSmrg
547209ff23fSmrg/* read TV regs */
548209ff23fSmrgvoid
549209ff23fSmrgRADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
550209ff23fSmrg{
551209ff23fSmrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
552209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
553209ff23fSmrg
554209ff23fSmrg    ErrorF("Entering TV Save\n");
555209ff23fSmrg
556209ff23fSmrg    save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL);
557209ff23fSmrg    save->tv_frestart = INREG(RADEON_TV_FRESTART);
558209ff23fSmrg    save->tv_hrestart = INREG(RADEON_TV_HRESTART);
559209ff23fSmrg    save->tv_vrestart = INREG(RADEON_TV_VRESTART);
560209ff23fSmrg    save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS);
561209ff23fSmrg    save->tv_hdisp = INREG(RADEON_TV_HDISP);
562209ff23fSmrg    save->tv_hstart = INREG(RADEON_TV_HSTART);
563209ff23fSmrg    save->tv_htotal = INREG(RADEON_TV_HTOTAL);
564209ff23fSmrg    save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS);
565209ff23fSmrg    save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL);
566209ff23fSmrg    save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL);
567209ff23fSmrg    save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1);
568209ff23fSmrg    save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2);
569209ff23fSmrg    save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL);
570209ff23fSmrg    save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL);
571209ff23fSmrg    save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL);
572209ff23fSmrg    save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
573209ff23fSmrg    save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL);
574209ff23fSmrg    save->tv_vdisp = INREG(RADEON_TV_VDISP);
575209ff23fSmrg    save->tv_ftotal = INREG(RADEON_TV_FTOTAL);
576209ff23fSmrg    save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1);
577209ff23fSmrg    save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2);
578209ff23fSmrg    save->tv_vtotal = INREG(RADEON_TV_VTOTAL);
579209ff23fSmrg    save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL);
580209ff23fSmrg    save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL);
581209ff23fSmrg    save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL);
582209ff23fSmrg
583209ff23fSmrg    save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL);
584209ff23fSmrg    save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1);
585209ff23fSmrg
586209ff23fSmrg    ErrorF("Save TV timing tables\n");
587209ff23fSmrg
588209ff23fSmrg    RADEONSaveTVTimingTables(pScrn, save);
589209ff23fSmrg
590209ff23fSmrg    ErrorF("TV Save done\n");
591209ff23fSmrg}
592209ff23fSmrg
593209ff23fSmrg
594209ff23fSmrg/* Compute F,V,H restarts from default restart position and hPos & vPos
595209ff23fSmrg * Return TRUE when code timing table was changed
596209ff23fSmrg */
597209ff23fSmrgstatic Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save,
598209ff23fSmrg				 DisplayModePtr mode)
599209ff23fSmrg{
600209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
601b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
602b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(output->scrn);
603b7e1c893Smrg    RADEONPLLPtr pll = &info->pll;
604209ff23fSmrg    int restart;
605209ff23fSmrg    unsigned hTotal;
606209ff23fSmrg    unsigned vTotal;
607209ff23fSmrg    unsigned fTotal;
608209ff23fSmrg    int vOffset;
609209ff23fSmrg    int hOffset;
610209ff23fSmrg    uint16_t p1;
611209ff23fSmrg    uint16_t p2;
612209ff23fSmrg    Bool hChanged;
613209ff23fSmrg    uint16_t hInc;
614209ff23fSmrg    const TVModeConstants *constPtr;
615209ff23fSmrg
616209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
617b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
618b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
619b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
620b7e1c893Smrg	if (pll->reference_freq == 2700)
621b7e1c893Smrg	    constPtr = &availableTVModes[0];
622b7e1c893Smrg	else
623b7e1c893Smrg	    constPtr = &availableTVModes[2];
624b7e1c893Smrg    } else {
625b7e1c893Smrg	if (pll->reference_freq == 2700)
626b7e1c893Smrg	    constPtr = &availableTVModes[1];
627b7e1c893Smrg	else
628b7e1c893Smrg	    constPtr = &availableTVModes[1]; /* FIXME */
629b7e1c893Smrg    }
630209ff23fSmrg
631209ff23fSmrg    hTotal = constPtr->horTotal;
632209ff23fSmrg    vTotal = constPtr->verTotal;
633b7e1c893Smrg
634b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
635b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
636b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_M ||
637b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_60)
638209ff23fSmrg	fTotal = NTSC_TV_VFTOTAL + 1;
639209ff23fSmrg    else
640209ff23fSmrg	fTotal = PAL_TV_VFTOTAL + 1;
641209ff23fSmrg
642209ff23fSmrg    /* Adjust positions 1&2 in hor. code timing table */
643b7e1c893Smrg    hOffset = tvout->hPos * H_POS_UNIT;
644209ff23fSmrg
645b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
646b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
647b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
648209ff23fSmrg	/* improve image centering */
649209ff23fSmrg	hOffset -= 50;
650209ff23fSmrg	p1 = hor_timing_NTSC[ H_TABLE_POS1 ];
651209ff23fSmrg	p2 = hor_timing_NTSC[ H_TABLE_POS2 ];
652209ff23fSmrg    } else {
653209ff23fSmrg	p1 = hor_timing_PAL[ H_TABLE_POS1 ];
654209ff23fSmrg	p2 = hor_timing_PAL[ H_TABLE_POS2 ];
655209ff23fSmrg    }
656209ff23fSmrg
657209ff23fSmrg
658209ff23fSmrg    p1 = (uint16_t)((int)p1 + hOffset);
659209ff23fSmrg    p2 = (uint16_t)((int)p2 - hOffset);
660209ff23fSmrg
661209ff23fSmrg    hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] ||
662209ff23fSmrg		p2 != save->h_code_timing[ H_TABLE_POS2 ]);
663209ff23fSmrg
664209ff23fSmrg    save->h_code_timing[ H_TABLE_POS1 ] = p1;
665209ff23fSmrg    save->h_code_timing[ H_TABLE_POS2 ] = p2;
666209ff23fSmrg
667209ff23fSmrg    /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */
668209ff23fSmrg    hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000;
669209ff23fSmrg
670209ff23fSmrg    /* Adjust restart */
671209ff23fSmrg    restart = constPtr->defRestart;
672209ff23fSmrg
673209ff23fSmrg    /*
674209ff23fSmrg     * Convert vPos TV lines to n. of CRTC pixels
675209ff23fSmrg     * Be verrrrry careful when mixing signed & unsigned values in C..
676209ff23fSmrg     */
677b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
678b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
679b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M ||
680b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_60)
681b7e1c893Smrg	vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(NTSC_TV_LINES_PER_FRAME);
682209ff23fSmrg    else
683b7e1c893Smrg	vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(PAL_TV_LINES_PER_FRAME);
684209ff23fSmrg
685209ff23fSmrg    restart -= vOffset + hOffset;
686209ff23fSmrg
687209ff23fSmrg    ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n",
688b7e1c893Smrg	   constPtr->defRestart , tvout->hPos , tvout->vPos , p1 , p2 , restart);
689209ff23fSmrg
690209ff23fSmrg    save->tv_hrestart = restart % hTotal;
691209ff23fSmrg    restart /= hTotal;
692209ff23fSmrg    save->tv_vrestart = restart % vTotal;
693209ff23fSmrg    restart /= vTotal;
694209ff23fSmrg    save->tv_frestart = restart % fTotal;
695209ff23fSmrg
696209ff23fSmrg    ErrorF("computeRestarts: F/H/V=%u,%u,%u\n",
697209ff23fSmrg	   (unsigned)save->tv_frestart, (unsigned)save->tv_vrestart,
698209ff23fSmrg	   (unsigned)save->tv_hrestart);
699209ff23fSmrg
700209ff23fSmrg    /* Compute H_INC from hSize */
701b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
702b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
703b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M)
704209ff23fSmrg	hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) /
705b7e1c893Smrg			(tvout->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE)));
706209ff23fSmrg    else
707209ff23fSmrg	hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) /
708b7e1c893Smrg			(tvout->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE)));
709209ff23fSmrg
710209ff23fSmrg    save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) |
711209ff23fSmrg	((uint32_t)hInc << RADEON_H_INC_SHIFT);
712209ff23fSmrg
713b7e1c893Smrg    ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , tvout->hSize , hInc);
714209ff23fSmrg
715209ff23fSmrg    return hChanged;
716209ff23fSmrg}
717209ff23fSmrg
718209ff23fSmrg/* intit TV-out regs */
719209ff23fSmrgvoid RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save,
720209ff23fSmrg                                  DisplayModePtr mode, BOOL IsPrimary)
721209ff23fSmrg{
722209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
723209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
724b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
725209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(pScrn);
726b7e1c893Smrg    RADEONPLLPtr pll = &info->pll;
727b7e1c893Smrg    unsigned m, n, p;
728209ff23fSmrg    unsigned i;
729209ff23fSmrg    unsigned long vert_space, flicker_removal;
730209ff23fSmrg    uint32_t tmp;
731209ff23fSmrg    const TVModeConstants *constPtr;
732209ff23fSmrg    const uint16_t *hor_timing;
733209ff23fSmrg    const uint16_t *vert_timing;
734b7e1c893Smrg    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
735b7e1c893Smrg    radeon_tvdac_ptr tvdac = NULL;
736b7e1c893Smrg
737b7e1c893Smrg    if (radeon_encoder == NULL)
738b7e1c893Smrg	return;
739b7e1c893Smrg
740b7e1c893Smrg    tvdac = (radeon_tvdac_ptr)radeon_encoder->dev_priv;
741209ff23fSmrg
742b7e1c893Smrg    if (tvdac == NULL)
743b7e1c893Smrg	return;
744209ff23fSmrg
745209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
746b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
747b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
748b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
749b7e1c893Smrg	if (pll->reference_freq == 2700)
750b7e1c893Smrg	    constPtr = &availableTVModes[0];
751b7e1c893Smrg	else
752b7e1c893Smrg	    constPtr = &availableTVModes[2];
753b7e1c893Smrg    } else {
754b7e1c893Smrg	if (pll->reference_freq == 2700)
755b7e1c893Smrg	    constPtr = &availableTVModes[1];
756b7e1c893Smrg	else
757b7e1c893Smrg	    constPtr = &availableTVModes[1]; /* FIXME */
758b7e1c893Smrg    }
759209ff23fSmrg
760209ff23fSmrg    save->tv_crc_cntl = 0;
761209ff23fSmrg
762209ff23fSmrg    save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) |
763209ff23fSmrg	                           (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT);
764209ff23fSmrg
765209ff23fSmrg    save->tv_hdisp = constPtr->horResolution - 1;
766209ff23fSmrg    save->tv_hstart = constPtr->horStart;
767209ff23fSmrg    save->tv_htotal = constPtr->horTotal - 1;
768209ff23fSmrg
769209ff23fSmrg    save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) |
770209ff23fSmrg	                            (0x100 << RADEON_Y_GAIN_SHIFT);
771209ff23fSmrg
772209ff23fSmrg    save->tv_master_cntl = (RADEON_VIN_ASYNC_RST
773209ff23fSmrg			    | RADEON_CRT_FIFO_CE_EN
774209ff23fSmrg			    | RADEON_TV_FIFO_CE_EN
775209ff23fSmrg			    | RADEON_TV_ON);
776209ff23fSmrg
777209ff23fSmrg    if (!IS_R300_VARIANT)
778209ff23fSmrg	save->tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb;
779209ff23fSmrg
780b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
781b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J)
782209ff23fSmrg	save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX;
783209ff23fSmrg
784209ff23fSmrg    save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT
785209ff23fSmrg	                       | RADEON_SYNC_TIP_LEVEL
786209ff23fSmrg	                       | RADEON_YFLT_EN
787209ff23fSmrg	                       | RADEON_UVFLT_EN
788209ff23fSmrg	                       | (6 << RADEON_CY_FILT_BLEND_SHIFT);
789209ff23fSmrg
790b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
791b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J) {
792209ff23fSmrg	save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT)
793209ff23fSmrg	                            | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
794209ff23fSmrg	save->tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) |
795209ff23fSmrg	    ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
796b7e1c893Smrg    } else if (tvout->tvStd == TV_STD_SCART_PAL) {
797209ff23fSmrg	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN;
798209ff23fSmrg	save->tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) |
799209ff23fSmrg	    ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
800209ff23fSmrg    } else {
801209ff23fSmrg	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN
802209ff23fSmrg	                            | (0x3b << RADEON_SET_UP_LEVEL_SHIFT)
803209ff23fSmrg	                            | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
804209ff23fSmrg	save->tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) |
805209ff23fSmrg	    ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
806209ff23fSmrg    }
807209ff23fSmrg
808209ff23fSmrg    save->pll_test_cntl = 0;
809209ff23fSmrg
810209ff23fSmrg    save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN
811209ff23fSmrg				 | RADEON_C_GRN_EN
812209ff23fSmrg				 | RADEON_CMP_BLU_EN
813209ff23fSmrg				 | RADEON_DAC_DITHER_EN);
814209ff23fSmrg
815209ff23fSmrg    save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN
816209ff23fSmrg			 | RADEON_TVOUT_SCALE_EN
817209ff23fSmrg			 | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT)
818b7e1c893Smrg			 | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT)
819b7e1c893Smrg			 | RADEON_RGB_ATTEN_SEL(0x3)
820b7e1c893Smrg			 | RADEON_RGB_ATTEN_VAL(0xc));
821209ff23fSmrg
822209ff23fSmrg    if (IsPrimary) {
823209ff23fSmrg	if (radeon_output->Flags & RADEON_USE_RMX)
824209ff23fSmrg	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX;
825209ff23fSmrg	else
826209ff23fSmrg	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1;
827209ff23fSmrg    } else {
828209ff23fSmrg	save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2;
829209ff23fSmrg    }
830209ff23fSmrg
831209ff23fSmrg    save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE;
832209ff23fSmrg
833209ff23fSmrg    save->tv_sync_size = constPtr->horResolution + 8;
834209ff23fSmrg
835b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
836b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
837b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M ||
838b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_60)
839209ff23fSmrg	vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME;
840209ff23fSmrg    else
841209ff23fSmrg	vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME;
842209ff23fSmrg
843209ff23fSmrg    save->tv_vscaler_cntl1 = RADEON_Y_W_EN;
844209ff23fSmrg    save->tv_vscaler_cntl1 =
845209ff23fSmrg	(save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000);
846b7e1c893Smrg
847b7e1c893Smrg    if (pll->reference_freq == 2700)
848b7e1c893Smrg	save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
849b7e1c893Smrg
850209ff23fSmrg    if (constPtr->horResolution == 1024)
851209ff23fSmrg	save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT);
852209ff23fSmrg    else
853209ff23fSmrg	save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT);
854209ff23fSmrg
855b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
856b7e1c893Smrg        tvout->tvStd == TV_STD_NTSC_J ||
857b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_M ||
858b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_60)
859209ff23fSmrg	flicker_removal =
860209ff23fSmrg	    (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5;
861209ff23fSmrg    else
862209ff23fSmrg	flicker_removal =
863209ff23fSmrg	    (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5;
864209ff23fSmrg
865209ff23fSmrg    if (flicker_removal < 3)
866209ff23fSmrg	flicker_removal = 3;
867209ff23fSmrg    for (i = 0; i < 6; ++i) {
868209ff23fSmrg	if (flicker_removal == SLOPE_limit[i])
869209ff23fSmrg	    break;
870209ff23fSmrg    }
871209ff23fSmrg    save->tv_y_saw_tooth_cntl =
872209ff23fSmrg	(vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8
873209ff23fSmrg	| ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16);
874209ff23fSmrg    save->tv_y_fall_cntl =
875209ff23fSmrg	(YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) |
876209ff23fSmrg	RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) /
877209ff23fSmrg	1024;
878209ff23fSmrg    save->tv_y_rise_cntl =
879209ff23fSmrg	RADEON_Y_RISE_PING_PONG
880209ff23fSmrg	| (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024;
881209ff23fSmrg
882209ff23fSmrg    save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0)
883209ff23fSmrg			      | (0x10 << 24)
884209ff23fSmrg			      | RADEON_DITHER_MODE
885209ff23fSmrg			      | RADEON_Y_OUTPUT_DITHER_EN
886209ff23fSmrg			      | RADEON_UV_OUTPUT_DITHER_EN
887209ff23fSmrg			      | RADEON_UV_TO_BUF_DITHER_EN);
888209ff23fSmrg
889209ff23fSmrg    tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
890209ff23fSmrg    tmp = ((16384 * 256 * 10) / tmp + 5) / 10;
891209ff23fSmrg    tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
892209ff23fSmrg    save->tv_timing_cntl = tmp;
893209ff23fSmrg
894b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
895b7e1c893Smrg        tvout->tvStd == TV_STD_NTSC_J ||
896b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_M ||
897b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_60)
898b7e1c893Smrg	save->tv_dac_cntl = tvdac->ntsc_tvdac_adj;
899209ff23fSmrg    else
900b7e1c893Smrg	save->tv_dac_cntl = tvdac->pal_tvdac_adj;
901209ff23fSmrg
902209ff23fSmrg    save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
903209ff23fSmrg
904b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
905b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J)
906209ff23fSmrg	save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
907209ff23fSmrg    else
908209ff23fSmrg	save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
909209ff23fSmrg
910209ff23fSmrg#if 0
911209ff23fSmrg    /* needs fixes for r4xx */
912209ff23fSmrg    save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD
913209ff23fSmrg	                 | RADEON_TV_DAC_BDACPD);
914209ff23fSmrg
915209ff23fSmrg    if (radeon_output->MonType == MT_CTV) {
916209ff23fSmrg	save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD;
917209ff23fSmrg    }
918209ff23fSmrg
919209ff23fSmrg    if (radeon_output->MonType == MT_STV) {
920209ff23fSmrg	save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
921209ff23fSmrg			       RADEON_TV_DAC_GDACPD);
922209ff23fSmrg    }
923209ff23fSmrg#endif
924209ff23fSmrg
925b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
926b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J) {
927b7e1c893Smrg	if (pll->reference_freq == 2700) {
928b7e1c893Smrg	    m = NTSC_TV_PLL_M_27;
929b7e1c893Smrg	    n = NTSC_TV_PLL_N_27;
930b7e1c893Smrg	    p = NTSC_TV_PLL_P_27;
931b7e1c893Smrg	} else {
932b7e1c893Smrg	    m = NTSC_TV_PLL_M_14;
933b7e1c893Smrg	    n = NTSC_TV_PLL_N_14;
934b7e1c893Smrg	    p = NTSC_TV_PLL_P_14;
935b7e1c893Smrg	}
936b7e1c893Smrg    } else {
937b7e1c893Smrg	if (pll->reference_freq == 2700) {
938b7e1c893Smrg	    m = PAL_TV_PLL_M_27;
939b7e1c893Smrg	    n = PAL_TV_PLL_N_27;
940b7e1c893Smrg	    p = PAL_TV_PLL_P_27;
941b7e1c893Smrg	} else {
942b7e1c893Smrg	    /* FIXME */
943b7e1c893Smrg	    m = PAL_TV_PLL_M_27;
944b7e1c893Smrg	    n = PAL_TV_PLL_N_27;
945b7e1c893Smrg	    p = PAL_TV_PLL_P_27;
946b7e1c893Smrg	}
947b7e1c893Smrg    }
948b7e1c893Smrg    save->tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) |
949b7e1c893Smrg	(((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
950b7e1c893Smrg	((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
951b7e1c893Smrg	(((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
952b7e1c893Smrg	((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
953209ff23fSmrg
954209ff23fSmrg    save->tv_pll_cntl1 =  (((4 & RADEON_TVPCP_MASK)<< RADEON_TVPCP_SHIFT) |
955209ff23fSmrg			   ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) |
956209ff23fSmrg			   ((1 & RADEON_TVPDC_MASK)<< RADEON_TVPDC_SHIFT) |
957209ff23fSmrg			   RADEON_TVCLK_SRC_SEL_TVPLL |
958209ff23fSmrg			   RADEON_TVPLL_TEST_DIS);
959209ff23fSmrg
960209ff23fSmrg    save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN;
961209ff23fSmrg
962209ff23fSmrg    save->tv_uv_adr = 0xc8;
963209ff23fSmrg
964209ff23fSmrg    save->tv_vdisp = constPtr->verResolution - 1;
965209ff23fSmrg
966b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
967b7e1c893Smrg        tvout->tvStd == TV_STD_NTSC_J ||
968b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_M ||
969b7e1c893Smrg        tvout->tvStd == TV_STD_PAL_60)
970209ff23fSmrg	save->tv_ftotal = NTSC_TV_VFTOTAL;
971209ff23fSmrg    else
972209ff23fSmrg	save->tv_ftotal = PAL_TV_VFTOTAL;
973209ff23fSmrg
974209ff23fSmrg    save->tv_vtotal = constPtr->verTotal - 1;
975209ff23fSmrg
976b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
977b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
978b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
979209ff23fSmrg	hor_timing = hor_timing_NTSC;
980209ff23fSmrg    } else {
981209ff23fSmrg	hor_timing = hor_timing_PAL;
982209ff23fSmrg    }
983209ff23fSmrg
984b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
985b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
986b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M ||
987b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_60) {
988209ff23fSmrg	vert_timing = vert_timing_NTSC;
989209ff23fSmrg    } else {
990209ff23fSmrg	vert_timing = vert_timing_PAL;
991209ff23fSmrg    }
992209ff23fSmrg
993209ff23fSmrg    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
994209ff23fSmrg	if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0)
995209ff23fSmrg	    break;
996209ff23fSmrg    }
997209ff23fSmrg
998209ff23fSmrg    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) {
999209ff23fSmrg	if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0)
1000209ff23fSmrg	    break;
1001209ff23fSmrg    }
1002209ff23fSmrg
1003209ff23fSmrg    /*
1004209ff23fSmrg     * This must be called AFTER loading timing tables as they are modified by this function
1005209ff23fSmrg     */
1006209ff23fSmrg    RADEONInitTVRestarts(output, save, mode);
1007209ff23fSmrg
1008209ff23fSmrg    save->dac_cntl &= ~RADEON_DAC_TVO_EN;
1009209ff23fSmrg
1010209ff23fSmrg    if (IS_R300_VARIANT)
1011209ff23fSmrg        save->gpiopad_a = info->SavedReg->gpiopad_a & ~1;
1012209ff23fSmrg
1013209ff23fSmrg    if (IsPrimary) {
1014209ff23fSmrg	save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
1015209ff23fSmrg	save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC
1016209ff23fSmrg				   | RADEON_DISP_TV_SOURCE_CRTC);
1017209ff23fSmrg    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
1018209ff23fSmrg	    save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2;
1019209ff23fSmrg    	} else {
1020209ff23fSmrg            save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
1021209ff23fSmrg    	}
1022209ff23fSmrg    } else {
1023209ff23fSmrg	save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
1024209ff23fSmrg	save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC;
1025209ff23fSmrg
1026209ff23fSmrg    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
1027209ff23fSmrg	    save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2;
1028209ff23fSmrg    	} else {
1029209ff23fSmrg            save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
1030209ff23fSmrg    	}
1031209ff23fSmrg    }
1032209ff23fSmrg}
1033209ff23fSmrg
1034209ff23fSmrg
1035209ff23fSmrg/* Set hw registers for a new h/v position & h size */
1036209ff23fSmrgvoid RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode)
1037209ff23fSmrg{
1038209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
1039209ff23fSmrg    RADEONInfoPtr  info = RADEONPTR(pScrn);
1040209ff23fSmrg    unsigned char *RADEONMMIO = info->MMIO;
1041209ff23fSmrg    Bool reloadTable;
1042209ff23fSmrg    RADEONSavePtr restore = info->ModeReg;
1043209ff23fSmrg
1044209ff23fSmrg    reloadTable = RADEONInitTVRestarts(output, restore, mode);
1045209ff23fSmrg
1046209ff23fSmrg    RADEONRestoreTVRestarts(pScrn, restore);
1047209ff23fSmrg
1048209ff23fSmrg    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
1049209ff23fSmrg
1050209ff23fSmrg    if (reloadTable) {
1051209ff23fSmrg	 OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl
1052209ff23fSmrg		                       | RADEON_TV_ASYNC_RST
1053209ff23fSmrg		                       | RADEON_CRT_ASYNC_RST
1054209ff23fSmrg		                       | RADEON_RESTART_PHASE_FIX);
1055209ff23fSmrg
1056209ff23fSmrg	RADEONRestoreTVTimingTables(pScrn, restore);
1057209ff23fSmrg
1058209ff23fSmrg	OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
1059209ff23fSmrg    }
1060209ff23fSmrg}
1061209ff23fSmrg
1062209ff23fSmrgvoid RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1063209ff23fSmrg				    DisplayModePtr mode, xf86OutputPtr output)
1064209ff23fSmrg{
1065209ff23fSmrg    const TVModeConstants *constPtr;
1066209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1067b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1068b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1069b7e1c893Smrg    RADEONPLLPtr pll = &info->pll;
1070209ff23fSmrg
1071209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1072b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
1073b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
1074b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
1075b7e1c893Smrg	if (pll->reference_freq == 2700)
1076b7e1c893Smrg	    constPtr = &availableTVModes[0];
1077b7e1c893Smrg	else
1078b7e1c893Smrg	    constPtr = &availableTVModes[2];
1079b7e1c893Smrg    } else {
1080b7e1c893Smrg	if (pll->reference_freq == 2700)
1081b7e1c893Smrg	    constPtr = &availableTVModes[1];
1082b7e1c893Smrg	else
1083b7e1c893Smrg	    constPtr = &availableTVModes[1]; /* FIXME */
1084b7e1c893Smrg    }
1085209ff23fSmrg
1086209ff23fSmrg    save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
1087209ff23fSmrg	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
1088209ff23fSmrg
1089209ff23fSmrg    save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid
1090209ff23fSmrg				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
1091209ff23fSmrg	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
1092209ff23fSmrg	(constPtr->horSyncStart & 7);
1093209ff23fSmrg
1094209ff23fSmrg    save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
1095209ff23fSmrg	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
1096209ff23fSmrg
1097209ff23fSmrg    save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
1098209ff23fSmrg	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
1099209ff23fSmrg
1100209ff23fSmrg}
1101209ff23fSmrg
1102209ff23fSmrgvoid RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1103209ff23fSmrg				   DisplayModePtr mode, xf86OutputPtr output)
1104209ff23fSmrg{
1105209ff23fSmrg    unsigned postDiv;
1106209ff23fSmrg    const TVModeConstants *constPtr;
1107209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1108b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1109b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1110b7e1c893Smrg    RADEONPLLPtr pll = &info->pll;
1111209ff23fSmrg
1112209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1113b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
1114b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
1115b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
1116b7e1c893Smrg	if (pll->reference_freq == 2700)
1117b7e1c893Smrg	    constPtr = &availableTVModes[0];
1118b7e1c893Smrg	else
1119b7e1c893Smrg	    constPtr = &availableTVModes[2];
1120b7e1c893Smrg    } else {
1121b7e1c893Smrg	if (pll->reference_freq == 2700)
1122b7e1c893Smrg	    constPtr = &availableTVModes[1];
1123b7e1c893Smrg	else
1124b7e1c893Smrg	    constPtr = &availableTVModes[1]; /* FIXME */
1125b7e1c893Smrg    }
1126209ff23fSmrg
1127209ff23fSmrg    save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN;
1128209ff23fSmrg
1129209ff23fSmrg    save->ppll_ref_div = constPtr->crtcPLL_M;
1130209ff23fSmrg
1131209ff23fSmrg    switch (constPtr->crtcPLL_postDiv) {
1132209ff23fSmrg    case 1:
1133209ff23fSmrg	postDiv = 0;
1134209ff23fSmrg	break;
1135209ff23fSmrg    case 2:
1136209ff23fSmrg	postDiv = 1;
1137209ff23fSmrg	break;
1138209ff23fSmrg    case 3:
1139209ff23fSmrg	postDiv = 4;
1140209ff23fSmrg	break;
1141209ff23fSmrg    case 4:
1142209ff23fSmrg	postDiv = 2;
1143209ff23fSmrg	break;
1144209ff23fSmrg    case 6:
1145209ff23fSmrg	postDiv = 6;
1146209ff23fSmrg	break;
1147209ff23fSmrg    case 8:
1148209ff23fSmrg	postDiv = 3;
1149209ff23fSmrg	break;
1150209ff23fSmrg    case 12:
1151209ff23fSmrg	postDiv = 7;
1152209ff23fSmrg	break;
1153209ff23fSmrg    case 16:
1154209ff23fSmrg    default:
1155209ff23fSmrg	postDiv = 5;
1156209ff23fSmrg	break;
1157209ff23fSmrg    }
1158209ff23fSmrg
1159209ff23fSmrg    save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
1160209ff23fSmrg
1161209ff23fSmrg    save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL);
1162209ff23fSmrg    save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK;
1163209ff23fSmrg
1164209ff23fSmrg}
1165209ff23fSmrg
1166209ff23fSmrgvoid RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1167209ff23fSmrg				     DisplayModePtr mode, xf86OutputPtr output)
1168209ff23fSmrg{
1169209ff23fSmrg    const TVModeConstants *constPtr;
1170209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1171b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1172b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1173b7e1c893Smrg    RADEONPLLPtr pll = &info->pll;
1174209ff23fSmrg
1175209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1176b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
1177b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
1178b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
1179b7e1c893Smrg	if (pll->reference_freq == 2700)
1180b7e1c893Smrg	    constPtr = &availableTVModes[0];
1181b7e1c893Smrg	else
1182b7e1c893Smrg	    constPtr = &availableTVModes[2];
1183b7e1c893Smrg    } else {
1184b7e1c893Smrg	if (pll->reference_freq == 2700)
1185b7e1c893Smrg	    constPtr = &availableTVModes[1];
1186b7e1c893Smrg	else
1187b7e1c893Smrg	    constPtr = &availableTVModes[1]; /* FIXME */
1188b7e1c893Smrg    }
1189209ff23fSmrg
1190209ff23fSmrg    save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
1191209ff23fSmrg	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
1192209ff23fSmrg
1193209ff23fSmrg    save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid
1194209ff23fSmrg				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
1195209ff23fSmrg	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
1196209ff23fSmrg	(constPtr->horSyncStart & 7);
1197209ff23fSmrg
1198209ff23fSmrg    save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
1199209ff23fSmrg	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
1200209ff23fSmrg
1201c503f109Smrg    save->crtc2_v_sync_strt_wid = (save->crtc2_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
1202209ff23fSmrg	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
1203209ff23fSmrg
1204209ff23fSmrg}
1205209ff23fSmrg
1206209ff23fSmrgvoid RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1207209ff23fSmrg				    DisplayModePtr mode, xf86OutputPtr output)
1208209ff23fSmrg{
1209209ff23fSmrg    unsigned postDiv;
1210209ff23fSmrg    const TVModeConstants *constPtr;
1211209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1212b7e1c893Smrg    radeon_tvout_ptr tvout = &radeon_output->tvout;
1213b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1214b7e1c893Smrg    RADEONPLLPtr pll = &info->pll;
1215209ff23fSmrg
1216209ff23fSmrg    /* FIXME: need to revisit this when we add more modes */
1217b7e1c893Smrg    if (tvout->tvStd == TV_STD_NTSC ||
1218b7e1c893Smrg	tvout->tvStd == TV_STD_NTSC_J ||
1219b7e1c893Smrg	tvout->tvStd == TV_STD_PAL_M) {
1220b7e1c893Smrg	if (pll->reference_freq == 2700)
1221b7e1c893Smrg	    constPtr = &availableTVModes[0];
1222b7e1c893Smrg	else
1223b7e1c893Smrg	    constPtr = &availableTVModes[2];
1224b7e1c893Smrg    } else {
1225b7e1c893Smrg	if (pll->reference_freq == 2700)
1226b7e1c893Smrg	    constPtr = &availableTVModes[1];
1227b7e1c893Smrg	else
1228b7e1c893Smrg	    constPtr = &availableTVModes[1]; /* FIXME */
1229b7e1c893Smrg    }
1230209ff23fSmrg
1231209ff23fSmrg    save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */
1232209ff23fSmrg
1233209ff23fSmrg    save->p2pll_ref_div = constPtr->crtcPLL_M;
1234209ff23fSmrg
1235209ff23fSmrg    switch (constPtr->crtcPLL_postDiv) {
1236209ff23fSmrg    case 1:
1237209ff23fSmrg	postDiv = 0;
1238209ff23fSmrg	break;
1239209ff23fSmrg    case 2:
1240209ff23fSmrg	postDiv = 1;
1241209ff23fSmrg	break;
1242209ff23fSmrg    case 3:
1243209ff23fSmrg	postDiv = 4;
1244209ff23fSmrg	break;
1245209ff23fSmrg    case 4:
1246209ff23fSmrg	postDiv = 2;
1247209ff23fSmrg	break;
1248209ff23fSmrg    case 6:
1249209ff23fSmrg	postDiv = 6;
1250209ff23fSmrg	break;
1251209ff23fSmrg    case 8:
1252209ff23fSmrg	postDiv = 3;
1253209ff23fSmrg	break;
1254209ff23fSmrg    case 12:
1255209ff23fSmrg	postDiv = 7;
1256209ff23fSmrg	break;
1257209ff23fSmrg    case 16:
1258209ff23fSmrg    default:
1259209ff23fSmrg	postDiv = 5;
1260209ff23fSmrg	break;
1261209ff23fSmrg    }
1262209ff23fSmrg
1263209ff23fSmrg    save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
1264209ff23fSmrg
1265209ff23fSmrg    save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK;
1266209ff23fSmrg    save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK
1267209ff23fSmrg			   | RADEON_PIXCLK_TV_SRC_SEL);
1268209ff23fSmrg
1269209ff23fSmrg}
1270