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