radeon_tv.c revision c503f109
1/*
2 * Integrated TV out support based on the GATOS code by
3 * Federico Ulivi <fulivi@lycos.com>
4 */
5
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
10#include <string.h>
11#include <stdio.h>
12
13/* X and server generic header files */
14#include "xf86.h"
15#include "xf86_OSproc.h"
16#include "vgaHW.h"
17#include "xf86Modes.h"
18
19/* Driver data structures */
20#include "radeon.h"
21#include "radeon_reg.h"
22#include "radeon_macros.h"
23#include "radeon_probe.h"
24#include "radeon_version.h"
25#include "radeon_tv.h"
26#include "radeon_atombios.h"
27
28/**********************************************************************
29 *
30 * ModeConstants
31 *
32 * Storage of constants related to a single video mode
33 *
34 **********************************************************************/
35
36typedef struct
37{
38    uint16_t horResolution;
39    uint16_t verResolution;
40    TVStd  standard;
41    uint16_t horTotal;
42    uint16_t verTotal;
43    uint16_t horStart;
44    uint16_t horSyncStart;
45    uint16_t verSyncStart;
46    unsigned defRestart;
47    uint16_t crtcPLL_N;
48    uint8_t  crtcPLL_M;
49    uint8_t  crtcPLL_postDiv;
50    unsigned pixToTV;
51} TVModeConstants;
52
53static const uint16_t hor_timing_NTSC[] =
54{
55    0x0007,
56    0x003f,
57    0x0263,
58    0x0a24,
59    0x2a6b,
60    0x0a36,
61    0x126d, /* H_TABLE_POS1 */
62    0x1bfe,
63    0x1a8f, /* H_TABLE_POS2 */
64    0x1ec7,
65    0x3863,
66    0x1bfe,
67    0x1bfe,
68    0x1a2a,
69    0x1e95,
70    0x0e31,
71    0x201b,
72    0
73};
74
75static const uint16_t vert_timing_NTSC[] =
76{
77    0x2001,
78    0x200d,
79    0x1006,
80    0x0c06,
81    0x1006,
82    0x1818,
83    0x21e3,
84    0x1006,
85    0x0c06,
86    0x1006,
87    0x1817,
88    0x21d4,
89    0x0002,
90    0
91};
92
93static const uint16_t hor_timing_PAL[] =
94{
95    0x0007,
96    0x0058,
97    0x027c,
98    0x0a31,
99    0x2a77,
100    0x0a95,
101    0x124f, /* H_TABLE_POS1 */
102    0x1bfe,
103    0x1b22, /* H_TABLE_POS2 */
104    0x1ef9,
105    0x387c,
106    0x1bfe,
107    0x1bfe,
108    0x1b31,
109    0x1eb5,
110    0x0e43,
111    0x201b,
112    0
113};
114
115static const uint16_t vert_timing_PAL[] =
116{
117    0x2001,
118    0x200c,
119    0x1005,
120    0x0c05,
121    0x1005,
122    0x1401,
123    0x1821,
124    0x2240,
125    0x1005,
126    0x0c05,
127    0x1005,
128    0x1401,
129    0x1822,
130    0x2230,
131    0x0002,
132    0
133};
134
135/**********************************************************************
136 *
137 * availableModes
138 *
139 * Table of all allowed modes for tv output
140 *
141 **********************************************************************/
142static const TVModeConstants availableTVModes[] =
143{
144    {   /* NTSC timing for 27 Mhz ref clk */
145	800,                /* horResolution */
146	600,                /* verResolution */
147	TV_STD_NTSC,        /* standard */
148	990,                /* horTotal */
149	740,                /* verTotal */
150	813,                /* horStart */
151	824,                /* horSyncStart */
152	632,                /* verSyncStart */
153	625592,             /* defRestart */
154	592,                /* crtcPLL_N */
155	91,                 /* crtcPLL_M */
156	4,                  /* crtcPLL_postDiv */
157	1022,               /* pixToTV */
158    },
159    {   /* PAL timing for 27 Mhz ref clk */
160	800,               /* horResolution */
161	600,               /* verResolution */
162	TV_STD_PAL,        /* standard */
163	1144,              /* horTotal */
164	706,               /* verTotal */
165	812,               /* horStart */
166	824,               /* horSyncStart */
167	669,               /* verSyncStart */
168	696700,            /* defRestart */
169	1382,              /* crtcPLL_N */
170	231,               /* crtcPLL_M */
171	4,                 /* crtcPLL_postDiv */
172	759,               /* pixToTV */
173    },
174    {   /* NTSC timing for 14 Mhz ref clk */
175	800,                /* horResolution */
176	600,                /* verResolution */
177	TV_STD_NTSC,        /* standard */
178	1018,               /* horTotal */
179	727,                /* verTotal */
180	813,                /* horStart */
181	840,                /* horSyncStart */
182	633,                /* verSyncStart */
183	630627,             /* defRestart */
184	347,                /* crtcPLL_N */
185	14,                 /* crtcPLL_M */
186	8,                  /* crtcPLL_postDiv */
187	1022,               /* pixToTV */
188    },
189};
190
191#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ]))
192
193static long YCOEF_value[5] = { 2, 2, 0, 4, 0 };
194static long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 };
195static long SLOPE_value[5] = { 1, 2, 2, 4, 8 };
196static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 };
197
198
199static void
200RADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests,
201		  unsigned nWaitLoops, unsigned cntThreshold)
202{
203    RADEONInfoPtr  info       = RADEONPTR(pScrn);
204    unsigned char *RADEONMMIO = info->MMIO;
205    uint32_t savePLLTest;
206    unsigned i;
207    unsigned j;
208
209    OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100);
210
211    savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL);
212
213    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B);
214
215    /* XXX: these should probably be OUTPLL to avoid various PLL errata */
216
217    OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL);
218
219    for (i = 0; i < nTests; i++) {
220	OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0);
221
222	for (j = 0; j < nWaitLoops; j++)
223	    if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold)
224		break;
225    }
226
227    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest);
228
229    OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff);
230}
231
232/* Write to TV FIFO RAM */
233static void
234RADEONWriteTVFIFO(ScrnInfoPtr pScrn, uint16_t addr,
235		  uint32_t value)
236{
237    RADEONInfoPtr  info       = RADEONPTR(pScrn);
238    unsigned char *RADEONMMIO = info->MMIO;
239    uint32_t tmp;
240    int i = 0;
241
242    OUTREG(RADEON_TV_HOST_WRITE_DATA, value);
243
244    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
245    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT);
246
247    do {
248	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
249	if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0)
250	    break;
251	i++;
252    }
253    while (i < 10000);
254    /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/
255
256    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
257}
258
259/* Read from TV FIFO RAM */
260static uint32_t
261RADEONReadTVFIFO(ScrnInfoPtr pScrn, uint16_t addr)
262{
263    RADEONInfoPtr  info       = RADEONPTR(pScrn);
264    unsigned char *RADEONMMIO = info->MMIO;
265    uint32_t tmp;
266    int i = 0;
267
268    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
269    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD);
270
271    do {
272	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
273	if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0)
274	    break;
275	i++;
276    }
277    while (i < 10000);
278    /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/
279
280    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
281
282    return INREG(RADEON_TV_HOST_READ_DATA);
283}
284
285/* Get FIFO addresses of horizontal & vertical code timing tables from
286 * settings of uv_adr register.
287 */
288static uint16_t
289RADEONGetHTimingTablesAddr(uint32_t tv_uv_adr)
290{
291    uint16_t hTable;
292
293    switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) {
294    case 0:
295	hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL;
296	break;
297    case 1:
298	hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2;
299	break;
300    case 2:
301	hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2;
302	break;
303    default:
304	/* Of course, this should never happen */
305	hTable = 0;
306	break;
307    }
308    return hTable;
309}
310
311static uint16_t
312RADEONGetVTimingTablesAddr(uint32_t tv_uv_adr)
313{
314    uint16_t vTable;
315
316    switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) {
317    case 0:
318	vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1;
319	break;
320    case 1:
321	vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
322	break;
323    case 2:
324	vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
325	break;
326    default:
327	/* Of course, this should never happen */
328	vTable = 0;
329	break;
330    }
331    return vTable;
332}
333
334/* Restore horizontal/vertical timing code tables */
335static void
336RADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore)
337{
338    RADEONInfoPtr  info       = RADEONPTR(pScrn);
339    unsigned char *RADEONMMIO = info->MMIO;
340    uint16_t hTable;
341    uint16_t vTable;
342    uint32_t tmp;
343    unsigned i;
344
345    OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr);
346    hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr);
347    vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr);
348
349    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) {
350	tmp = ((uint32_t)restore->h_code_timing[ i ] << 14) | ((uint32_t)restore->h_code_timing[ i + 1 ]);
351	RADEONWriteTVFIFO(pScrn, hTable, tmp);
352	if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0)
353	    break;
354    }
355
356    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) {
357	tmp = ((uint32_t)restore->v_code_timing[ i + 1 ] << 14) | ((uint32_t)restore->v_code_timing[ i ]);
358	RADEONWriteTVFIFO(pScrn, vTable, tmp);
359	if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0)
360	    break;
361    }
362}
363
364/* restore TV PLLs */
365static void
366RADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
367{
368
369    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL);
370    OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl);
371    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET);
372
373    RADEONWaitPLLLock(pScrn, 200, 800, 135);
374
375    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET);
376
377    RADEONWaitPLLLock(pScrn, 300, 160, 27);
378    RADEONWaitPLLLock(pScrn, 200, 800, 135);
379
380    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf);
381    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL);
382
383    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK);
384    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP);
385}
386
387/* Restore TV horizontal/vertical settings */
388static void
389RADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
390{
391    RADEONInfoPtr  info       = RADEONPTR(pScrn);
392    unsigned char *RADEONMMIO = info->MMIO;
393
394    OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl);
395
396    OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal);
397    OUTREG(RADEON_TV_HDISP, restore->tv_hdisp);
398    OUTREG(RADEON_TV_HSTART, restore->tv_hstart);
399
400    OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal);
401    OUTREG(RADEON_TV_VDISP, restore->tv_vdisp);
402
403    OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal);
404
405    OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1);
406    OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2);
407
408    OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl);
409    OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl);
410    OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl);
411}
412
413/* restore TV RESTART registers */
414static void
415RADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore)
416{
417    RADEONInfoPtr  info       = RADEONPTR(pScrn);
418    unsigned char *RADEONMMIO = info->MMIO;
419
420    OUTREG(RADEON_TV_FRESTART, restore->tv_frestart);
421    OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart);
422    OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart);
423}
424
425/* restore tv standard & output muxes */
426static void
427RADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore)
428{
429    RADEONInfoPtr  info       = RADEONPTR(pScrn);
430    unsigned char *RADEONMMIO = info->MMIO;
431
432    OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl);
433
434    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
435
436    OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1);
437    OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2);
438
439    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl);
440
441    OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl);
442}
443
444/* Restore TV out regs */
445void
446RADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
447{
448    RADEONInfoPtr  info       = RADEONPTR(pScrn);
449    unsigned char *RADEONMMIO = info->MMIO;
450
451    ErrorF("Entering Restore TV\n");
452
453    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
454				   | RADEON_TV_ASYNC_RST
455				   | RADEON_CRT_ASYNC_RST
456				   | RADEON_TV_FIFO_ASYNC_RST));
457
458    /* Temporarily turn the TV DAC off */
459    OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK)
460				| RADEON_TV_DAC_BGSLEEP
461				| RADEON_TV_DAC_RDACPD
462				| RADEON_TV_DAC_GDACPD
463				| RADEON_TV_DAC_BDACPD));
464
465    ErrorF("Restore TV PLL\n");
466    RADEONRestoreTVPLLRegisters(pScrn, restore);
467
468    ErrorF("Restore TVHV\n");
469    RADEONRestoreTVHVRegisters(pScrn, restore);
470
471    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
472				   | RADEON_TV_ASYNC_RST
473				   | RADEON_CRT_ASYNC_RST));
474
475    ErrorF("Restore TV Restarts\n");
476    RADEONRestoreTVRestarts(pScrn, restore);
477
478    ErrorF("Restore Timing Tables\n");
479    RADEONRestoreTVTimingTables(pScrn, restore);
480
481
482    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
483				   | RADEON_TV_ASYNC_RST));
484
485    ErrorF("Restore TV standard\n");
486    RADEONRestoreTVOutputStd(pScrn, restore);
487
488    OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
489
490    OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings);
491    OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings);
492
493    OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
494
495    ErrorF("Leaving Restore TV\n");
496}
497
498/* Save horizontal/vertical timing code tables */
499static void
500RADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save)
501{
502    RADEONInfoPtr  info       = RADEONPTR(pScrn);
503    unsigned char *RADEONMMIO = info->MMIO;
504    uint16_t hTable;
505    uint16_t vTable;
506    uint32_t tmp;
507    unsigned i;
508
509    save->tv_uv_adr = INREG(RADEON_TV_UV_ADR);
510    hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr);
511    vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr);
512
513    /*
514     * Reset FIFO arbiter in order to be able to access FIFO RAM
515     */
516
517    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
518				   | RADEON_CRT_ASYNC_RST
519				   | RADEON_RESTART_PHASE_FIX
520				   | RADEON_CRT_FIFO_CE_EN
521				   | RADEON_TV_FIFO_CE_EN
522				   | RADEON_TV_ON));
523
524    /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/
525
526    ErrorF("saveTimingTables: reading timing tables\n");
527
528    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) {
529	tmp = RADEONReadTVFIFO(pScrn, hTable--);
530	save->h_code_timing[ i     ] = (uint16_t)((tmp >> 14) & 0x3fff);
531	save->h_code_timing[ i + 1 ] = (uint16_t)(tmp & 0x3fff);
532
533	if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0)
534	    break;
535    }
536
537    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) {
538	tmp = RADEONReadTVFIFO(pScrn, vTable++);
539	save->v_code_timing[ i     ] = (uint16_t)(tmp & 0x3fff);
540	save->v_code_timing[ i + 1 ] = (uint16_t)((tmp >> 14) & 0x3fff);
541
542	if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0)
543	    break;
544    }
545}
546
547/* read TV regs */
548void
549RADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
550{
551    RADEONInfoPtr  info       = RADEONPTR(pScrn);
552    unsigned char *RADEONMMIO = info->MMIO;
553
554    ErrorF("Entering TV Save\n");
555
556    save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL);
557    save->tv_frestart = INREG(RADEON_TV_FRESTART);
558    save->tv_hrestart = INREG(RADEON_TV_HRESTART);
559    save->tv_vrestart = INREG(RADEON_TV_VRESTART);
560    save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS);
561    save->tv_hdisp = INREG(RADEON_TV_HDISP);
562    save->tv_hstart = INREG(RADEON_TV_HSTART);
563    save->tv_htotal = INREG(RADEON_TV_HTOTAL);
564    save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS);
565    save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL);
566    save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL);
567    save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1);
568    save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2);
569    save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL);
570    save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL);
571    save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL);
572    save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
573    save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL);
574    save->tv_vdisp = INREG(RADEON_TV_VDISP);
575    save->tv_ftotal = INREG(RADEON_TV_FTOTAL);
576    save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1);
577    save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2);
578    save->tv_vtotal = INREG(RADEON_TV_VTOTAL);
579    save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL);
580    save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL);
581    save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL);
582
583    save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL);
584    save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1);
585
586    ErrorF("Save TV timing tables\n");
587
588    RADEONSaveTVTimingTables(pScrn, save);
589
590    ErrorF("TV Save done\n");
591}
592
593
594/* Compute F,V,H restarts from default restart position and hPos & vPos
595 * Return TRUE when code timing table was changed
596 */
597static Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save,
598				 DisplayModePtr mode)
599{
600    RADEONOutputPrivatePtr radeon_output = output->driver_private;
601    radeon_tvout_ptr tvout = &radeon_output->tvout;
602    RADEONInfoPtr  info       = RADEONPTR(output->scrn);
603    RADEONPLLPtr pll = &info->pll;
604    int restart;
605    unsigned hTotal;
606    unsigned vTotal;
607    unsigned fTotal;
608    int vOffset;
609    int hOffset;
610    uint16_t p1;
611    uint16_t p2;
612    Bool hChanged;
613    uint16_t hInc;
614    const TVModeConstants *constPtr;
615
616    /* FIXME: need to revisit this when we add more modes */
617    if (tvout->tvStd == TV_STD_NTSC ||
618	tvout->tvStd == TV_STD_NTSC_J ||
619	tvout->tvStd == TV_STD_PAL_M) {
620	if (pll->reference_freq == 2700)
621	    constPtr = &availableTVModes[0];
622	else
623	    constPtr = &availableTVModes[2];
624    } else {
625	if (pll->reference_freq == 2700)
626	    constPtr = &availableTVModes[1];
627	else
628	    constPtr = &availableTVModes[1]; /* FIXME */
629    }
630
631    hTotal = constPtr->horTotal;
632    vTotal = constPtr->verTotal;
633
634    if (tvout->tvStd == TV_STD_NTSC ||
635	tvout->tvStd == TV_STD_NTSC_J ||
636        tvout->tvStd == TV_STD_PAL_M ||
637        tvout->tvStd == TV_STD_PAL_60)
638	fTotal = NTSC_TV_VFTOTAL + 1;
639    else
640	fTotal = PAL_TV_VFTOTAL + 1;
641
642    /* Adjust positions 1&2 in hor. code timing table */
643    hOffset = tvout->hPos * H_POS_UNIT;
644
645    if (tvout->tvStd == TV_STD_NTSC ||
646	tvout->tvStd == TV_STD_NTSC_J ||
647	tvout->tvStd == TV_STD_PAL_M) {
648	/* improve image centering */
649	hOffset -= 50;
650	p1 = hor_timing_NTSC[ H_TABLE_POS1 ];
651	p2 = hor_timing_NTSC[ H_TABLE_POS2 ];
652    } else {
653	p1 = hor_timing_PAL[ H_TABLE_POS1 ];
654	p2 = hor_timing_PAL[ H_TABLE_POS2 ];
655    }
656
657
658    p1 = (uint16_t)((int)p1 + hOffset);
659    p2 = (uint16_t)((int)p2 - hOffset);
660
661    hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] ||
662		p2 != save->h_code_timing[ H_TABLE_POS2 ]);
663
664    save->h_code_timing[ H_TABLE_POS1 ] = p1;
665    save->h_code_timing[ H_TABLE_POS2 ] = p2;
666
667    /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */
668    hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000;
669
670    /* Adjust restart */
671    restart = constPtr->defRestart;
672
673    /*
674     * Convert vPos TV lines to n. of CRTC pixels
675     * Be verrrrry careful when mixing signed & unsigned values in C..
676     */
677    if (tvout->tvStd == TV_STD_NTSC ||
678	tvout->tvStd == TV_STD_NTSC_J ||
679	tvout->tvStd == TV_STD_PAL_M ||
680	tvout->tvStd == TV_STD_PAL_60)
681	vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(NTSC_TV_LINES_PER_FRAME);
682    else
683	vOffset = ((int)(vTotal * hTotal) * 2 * tvout->vPos) / (int)(PAL_TV_LINES_PER_FRAME);
684
685    restart -= vOffset + hOffset;
686
687    ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n",
688	   constPtr->defRestart , tvout->hPos , tvout->vPos , p1 , p2 , restart);
689
690    save->tv_hrestart = restart % hTotal;
691    restart /= hTotal;
692    save->tv_vrestart = restart % vTotal;
693    restart /= vTotal;
694    save->tv_frestart = restart % fTotal;
695
696    ErrorF("computeRestarts: F/H/V=%u,%u,%u\n",
697	   (unsigned)save->tv_frestart, (unsigned)save->tv_vrestart,
698	   (unsigned)save->tv_hrestart);
699
700    /* Compute H_INC from hSize */
701    if (tvout->tvStd == TV_STD_NTSC ||
702	tvout->tvStd == TV_STD_NTSC_J ||
703	tvout->tvStd == TV_STD_PAL_M)
704	hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) /
705			(tvout->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE)));
706    else
707	hInc = (uint16_t)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) /
708			(tvout->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE)));
709
710    save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) |
711	((uint32_t)hInc << RADEON_H_INC_SHIFT);
712
713    ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , tvout->hSize , hInc);
714
715    return hChanged;
716}
717
718/* intit TV-out regs */
719void RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save,
720                                  DisplayModePtr mode, BOOL IsPrimary)
721{
722    ScrnInfoPtr pScrn = output->scrn;
723    RADEONOutputPrivatePtr radeon_output = output->driver_private;
724    radeon_tvout_ptr tvout = &radeon_output->tvout;
725    RADEONInfoPtr  info = RADEONPTR(pScrn);
726    RADEONPLLPtr pll = &info->pll;
727    unsigned m, n, p;
728    unsigned i;
729    unsigned long vert_space, flicker_removal;
730    uint32_t tmp;
731    const TVModeConstants *constPtr;
732    const uint16_t *hor_timing;
733    const uint16_t *vert_timing;
734    radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
735    radeon_tvdac_ptr tvdac = NULL;
736
737    if (radeon_encoder == NULL)
738	return;
739
740    tvdac = (radeon_tvdac_ptr)radeon_encoder->dev_priv;
741
742    if (tvdac == NULL)
743	return;
744
745    /* FIXME: need to revisit this when we add more modes */
746    if (tvout->tvStd == TV_STD_NTSC ||
747	tvout->tvStd == TV_STD_NTSC_J ||
748	tvout->tvStd == TV_STD_PAL_M) {
749	if (pll->reference_freq == 2700)
750	    constPtr = &availableTVModes[0];
751	else
752	    constPtr = &availableTVModes[2];
753    } else {
754	if (pll->reference_freq == 2700)
755	    constPtr = &availableTVModes[1];
756	else
757	    constPtr = &availableTVModes[1]; /* FIXME */
758    }
759
760    save->tv_crc_cntl = 0;
761
762    save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) |
763	                           (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT);
764
765    save->tv_hdisp = constPtr->horResolution - 1;
766    save->tv_hstart = constPtr->horStart;
767    save->tv_htotal = constPtr->horTotal - 1;
768
769    save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) |
770	                            (0x100 << RADEON_Y_GAIN_SHIFT);
771
772    save->tv_master_cntl = (RADEON_VIN_ASYNC_RST
773			    | RADEON_CRT_FIFO_CE_EN
774			    | RADEON_TV_FIFO_CE_EN
775			    | RADEON_TV_ON);
776
777    if (!IS_R300_VARIANT)
778	save->tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb;
779
780    if (tvout->tvStd == TV_STD_NTSC ||
781	tvout->tvStd == TV_STD_NTSC_J)
782	save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX;
783
784    save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT
785	                       | RADEON_SYNC_TIP_LEVEL
786	                       | RADEON_YFLT_EN
787	                       | RADEON_UVFLT_EN
788	                       | (6 << RADEON_CY_FILT_BLEND_SHIFT);
789
790    if (tvout->tvStd == TV_STD_NTSC ||
791	tvout->tvStd == TV_STD_NTSC_J) {
792	save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT)
793	                            | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
794	save->tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) |
795	    ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
796    } else if (tvout->tvStd == TV_STD_SCART_PAL) {
797	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN;
798	save->tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) |
799	    ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
800    } else {
801	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN
802	                            | (0x3b << RADEON_SET_UP_LEVEL_SHIFT)
803	                            | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
804	save->tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) |
805	    ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
806    }
807
808    save->pll_test_cntl = 0;
809
810    save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN
811				 | RADEON_C_GRN_EN
812				 | RADEON_CMP_BLU_EN
813				 | RADEON_DAC_DITHER_EN);
814
815    save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN
816			 | RADEON_TVOUT_SCALE_EN
817			 | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT)
818			 | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT)
819			 | RADEON_RGB_ATTEN_SEL(0x3)
820			 | RADEON_RGB_ATTEN_VAL(0xc));
821
822    if (IsPrimary) {
823	if (radeon_output->Flags & RADEON_USE_RMX)
824	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX;
825	else
826	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1;
827    } else {
828	save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2;
829    }
830
831    save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE;
832
833    save->tv_sync_size = constPtr->horResolution + 8;
834
835    if (tvout->tvStd == TV_STD_NTSC ||
836	tvout->tvStd == TV_STD_NTSC_J ||
837	tvout->tvStd == TV_STD_PAL_M ||
838	tvout->tvStd == TV_STD_PAL_60)
839	vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME;
840    else
841	vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME;
842
843    save->tv_vscaler_cntl1 = RADEON_Y_W_EN;
844    save->tv_vscaler_cntl1 =
845	(save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000);
846
847    if (pll->reference_freq == 2700)
848	save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
849
850    if (constPtr->horResolution == 1024)
851	save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT);
852    else
853	save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT);
854
855    if (tvout->tvStd == TV_STD_NTSC ||
856        tvout->tvStd == TV_STD_NTSC_J ||
857        tvout->tvStd == TV_STD_PAL_M ||
858        tvout->tvStd == TV_STD_PAL_60)
859	flicker_removal =
860	    (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5;
861    else
862	flicker_removal =
863	    (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5;
864
865    if (flicker_removal < 3)
866	flicker_removal = 3;
867    for (i = 0; i < 6; ++i) {
868	if (flicker_removal == SLOPE_limit[i])
869	    break;
870    }
871    save->tv_y_saw_tooth_cntl =
872	(vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8
873	| ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16);
874    save->tv_y_fall_cntl =
875	(YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) |
876	RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) /
877	1024;
878    save->tv_y_rise_cntl =
879	RADEON_Y_RISE_PING_PONG
880	| (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024;
881
882    save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0)
883			      | (0x10 << 24)
884			      | RADEON_DITHER_MODE
885			      | RADEON_Y_OUTPUT_DITHER_EN
886			      | RADEON_UV_OUTPUT_DITHER_EN
887			      | RADEON_UV_TO_BUF_DITHER_EN);
888
889    tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
890    tmp = ((16384 * 256 * 10) / tmp + 5) / 10;
891    tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
892    save->tv_timing_cntl = tmp;
893
894    if (tvout->tvStd == TV_STD_NTSC ||
895        tvout->tvStd == TV_STD_NTSC_J ||
896        tvout->tvStd == TV_STD_PAL_M ||
897        tvout->tvStd == TV_STD_PAL_60)
898	save->tv_dac_cntl = tvdac->ntsc_tvdac_adj;
899    else
900	save->tv_dac_cntl = tvdac->pal_tvdac_adj;
901
902    save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
903
904    if (tvout->tvStd == TV_STD_NTSC ||
905	tvout->tvStd == TV_STD_NTSC_J)
906	save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
907    else
908	save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
909
910#if 0
911    /* needs fixes for r4xx */
912    save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD
913	                 | RADEON_TV_DAC_BDACPD);
914
915    if (radeon_output->MonType == MT_CTV) {
916	save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD;
917    }
918
919    if (radeon_output->MonType == MT_STV) {
920	save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
921			       RADEON_TV_DAC_GDACPD);
922    }
923#endif
924
925    if (tvout->tvStd == TV_STD_NTSC ||
926	tvout->tvStd == TV_STD_NTSC_J) {
927	if (pll->reference_freq == 2700) {
928	    m = NTSC_TV_PLL_M_27;
929	    n = NTSC_TV_PLL_N_27;
930	    p = NTSC_TV_PLL_P_27;
931	} else {
932	    m = NTSC_TV_PLL_M_14;
933	    n = NTSC_TV_PLL_N_14;
934	    p = NTSC_TV_PLL_P_14;
935	}
936    } else {
937	if (pll->reference_freq == 2700) {
938	    m = PAL_TV_PLL_M_27;
939	    n = PAL_TV_PLL_N_27;
940	    p = PAL_TV_PLL_P_27;
941	} else {
942	    /* FIXME */
943	    m = PAL_TV_PLL_M_27;
944	    n = PAL_TV_PLL_N_27;
945	    p = PAL_TV_PLL_P_27;
946	}
947    }
948    save->tv_pll_cntl = (m & RADEON_TV_M0LO_MASK) |
949	(((m >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
950	((n & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
951	(((n >> 9) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
952	((p & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
953
954    save->tv_pll_cntl1 =  (((4 & RADEON_TVPCP_MASK)<< RADEON_TVPCP_SHIFT) |
955			   ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) |
956			   ((1 & RADEON_TVPDC_MASK)<< RADEON_TVPDC_SHIFT) |
957			   RADEON_TVCLK_SRC_SEL_TVPLL |
958			   RADEON_TVPLL_TEST_DIS);
959
960    save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN;
961
962    save->tv_uv_adr = 0xc8;
963
964    save->tv_vdisp = constPtr->verResolution - 1;
965
966    if (tvout->tvStd == TV_STD_NTSC ||
967        tvout->tvStd == TV_STD_NTSC_J ||
968        tvout->tvStd == TV_STD_PAL_M ||
969        tvout->tvStd == TV_STD_PAL_60)
970	save->tv_ftotal = NTSC_TV_VFTOTAL;
971    else
972	save->tv_ftotal = PAL_TV_VFTOTAL;
973
974    save->tv_vtotal = constPtr->verTotal - 1;
975
976    if (tvout->tvStd == TV_STD_NTSC ||
977	tvout->tvStd == TV_STD_NTSC_J ||
978	tvout->tvStd == TV_STD_PAL_M) {
979	hor_timing = hor_timing_NTSC;
980    } else {
981	hor_timing = hor_timing_PAL;
982    }
983
984    if (tvout->tvStd == TV_STD_NTSC ||
985	tvout->tvStd == TV_STD_NTSC_J ||
986	tvout->tvStd == TV_STD_PAL_M ||
987	tvout->tvStd == TV_STD_PAL_60) {
988	vert_timing = vert_timing_NTSC;
989    } else {
990	vert_timing = vert_timing_PAL;
991    }
992
993    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
994	if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0)
995	    break;
996    }
997
998    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) {
999	if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0)
1000	    break;
1001    }
1002
1003    /*
1004     * This must be called AFTER loading timing tables as they are modified by this function
1005     */
1006    RADEONInitTVRestarts(output, save, mode);
1007
1008    save->dac_cntl &= ~RADEON_DAC_TVO_EN;
1009
1010    if (IS_R300_VARIANT)
1011        save->gpiopad_a = info->SavedReg->gpiopad_a & ~1;
1012
1013    if (IsPrimary) {
1014	save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
1015	save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC
1016				   | RADEON_DISP_TV_SOURCE_CRTC);
1017    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
1018	    save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2;
1019    	} else {
1020            save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
1021    	}
1022    } else {
1023	save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
1024	save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC;
1025
1026    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
1027	    save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2;
1028    	} else {
1029            save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
1030    	}
1031    }
1032}
1033
1034
1035/* Set hw registers for a new h/v position & h size */
1036void RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode)
1037{
1038    ScrnInfoPtr pScrn = output->scrn;
1039    RADEONInfoPtr  info = RADEONPTR(pScrn);
1040    unsigned char *RADEONMMIO = info->MMIO;
1041    Bool reloadTable;
1042    RADEONSavePtr restore = info->ModeReg;
1043
1044    reloadTable = RADEONInitTVRestarts(output, restore, mode);
1045
1046    RADEONRestoreTVRestarts(pScrn, restore);
1047
1048    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
1049
1050    if (reloadTable) {
1051	 OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl
1052		                       | RADEON_TV_ASYNC_RST
1053		                       | RADEON_CRT_ASYNC_RST
1054		                       | RADEON_RESTART_PHASE_FIX);
1055
1056	RADEONRestoreTVTimingTables(pScrn, restore);
1057
1058	OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
1059    }
1060}
1061
1062void RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1063				    DisplayModePtr mode, xf86OutputPtr output)
1064{
1065    const TVModeConstants *constPtr;
1066    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1067    radeon_tvout_ptr tvout = &radeon_output->tvout;
1068    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1069    RADEONPLLPtr pll = &info->pll;
1070
1071    /* FIXME: need to revisit this when we add more modes */
1072    if (tvout->tvStd == TV_STD_NTSC ||
1073	tvout->tvStd == TV_STD_NTSC_J ||
1074	tvout->tvStd == TV_STD_PAL_M) {
1075	if (pll->reference_freq == 2700)
1076	    constPtr = &availableTVModes[0];
1077	else
1078	    constPtr = &availableTVModes[2];
1079    } else {
1080	if (pll->reference_freq == 2700)
1081	    constPtr = &availableTVModes[1];
1082	else
1083	    constPtr = &availableTVModes[1]; /* FIXME */
1084    }
1085
1086    save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
1087	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
1088
1089    save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid
1090				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
1091	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
1092	(constPtr->horSyncStart & 7);
1093
1094    save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
1095	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
1096
1097    save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
1098	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
1099
1100}
1101
1102void RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1103				   DisplayModePtr mode, xf86OutputPtr output)
1104{
1105    unsigned postDiv;
1106    const TVModeConstants *constPtr;
1107    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1108    radeon_tvout_ptr tvout = &radeon_output->tvout;
1109    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1110    RADEONPLLPtr pll = &info->pll;
1111
1112    /* FIXME: need to revisit this when we add more modes */
1113    if (tvout->tvStd == TV_STD_NTSC ||
1114	tvout->tvStd == TV_STD_NTSC_J ||
1115	tvout->tvStd == TV_STD_PAL_M) {
1116	if (pll->reference_freq == 2700)
1117	    constPtr = &availableTVModes[0];
1118	else
1119	    constPtr = &availableTVModes[2];
1120    } else {
1121	if (pll->reference_freq == 2700)
1122	    constPtr = &availableTVModes[1];
1123	else
1124	    constPtr = &availableTVModes[1]; /* FIXME */
1125    }
1126
1127    save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN;
1128
1129    save->ppll_ref_div = constPtr->crtcPLL_M;
1130
1131    switch (constPtr->crtcPLL_postDiv) {
1132    case 1:
1133	postDiv = 0;
1134	break;
1135    case 2:
1136	postDiv = 1;
1137	break;
1138    case 3:
1139	postDiv = 4;
1140	break;
1141    case 4:
1142	postDiv = 2;
1143	break;
1144    case 6:
1145	postDiv = 6;
1146	break;
1147    case 8:
1148	postDiv = 3;
1149	break;
1150    case 12:
1151	postDiv = 7;
1152	break;
1153    case 16:
1154    default:
1155	postDiv = 5;
1156	break;
1157    }
1158
1159    save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
1160
1161    save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL);
1162    save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK;
1163
1164}
1165
1166void RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1167				     DisplayModePtr mode, xf86OutputPtr output)
1168{
1169    const TVModeConstants *constPtr;
1170    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1171    radeon_tvout_ptr tvout = &radeon_output->tvout;
1172    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1173    RADEONPLLPtr pll = &info->pll;
1174
1175    /* FIXME: need to revisit this when we add more modes */
1176    if (tvout->tvStd == TV_STD_NTSC ||
1177	tvout->tvStd == TV_STD_NTSC_J ||
1178	tvout->tvStd == TV_STD_PAL_M) {
1179	if (pll->reference_freq == 2700)
1180	    constPtr = &availableTVModes[0];
1181	else
1182	    constPtr = &availableTVModes[2];
1183    } else {
1184	if (pll->reference_freq == 2700)
1185	    constPtr = &availableTVModes[1];
1186	else
1187	    constPtr = &availableTVModes[1]; /* FIXME */
1188    }
1189
1190    save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
1191	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
1192
1193    save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid
1194				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
1195	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
1196	(constPtr->horSyncStart & 7);
1197
1198    save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
1199	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
1200
1201    save->crtc2_v_sync_strt_wid = (save->crtc2_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
1202	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
1203
1204}
1205
1206void RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
1207				    DisplayModePtr mode, xf86OutputPtr output)
1208{
1209    unsigned postDiv;
1210    const TVModeConstants *constPtr;
1211    RADEONOutputPrivatePtr radeon_output = output->driver_private;
1212    radeon_tvout_ptr tvout = &radeon_output->tvout;
1213    RADEONInfoPtr  info       = RADEONPTR(pScrn);
1214    RADEONPLLPtr pll = &info->pll;
1215
1216    /* FIXME: need to revisit this when we add more modes */
1217    if (tvout->tvStd == TV_STD_NTSC ||
1218	tvout->tvStd == TV_STD_NTSC_J ||
1219	tvout->tvStd == TV_STD_PAL_M) {
1220	if (pll->reference_freq == 2700)
1221	    constPtr = &availableTVModes[0];
1222	else
1223	    constPtr = &availableTVModes[2];
1224    } else {
1225	if (pll->reference_freq == 2700)
1226	    constPtr = &availableTVModes[1];
1227	else
1228	    constPtr = &availableTVModes[1]; /* FIXME */
1229    }
1230
1231    save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */
1232
1233    save->p2pll_ref_div = constPtr->crtcPLL_M;
1234
1235    switch (constPtr->crtcPLL_postDiv) {
1236    case 1:
1237	postDiv = 0;
1238	break;
1239    case 2:
1240	postDiv = 1;
1241	break;
1242    case 3:
1243	postDiv = 4;
1244	break;
1245    case 4:
1246	postDiv = 2;
1247	break;
1248    case 6:
1249	postDiv = 6;
1250	break;
1251    case 8:
1252	postDiv = 3;
1253	break;
1254    case 12:
1255	postDiv = 7;
1256	break;
1257    case 16:
1258    default:
1259	postDiv = 5;
1260	break;
1261    }
1262
1263    save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
1264
1265    save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK;
1266    save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK
1267			   | RADEON_PIXCLK_TV_SRC_SEL);
1268
1269}
1270