xf86-video-ati: Branch 'randr-1.2' - 20 commits

Alex Deucher agd5f at kemper.freedesktop.org
Sun Aug 5 01:03:24 PDT 2007


 src/Makefile.am      |    3 
 src/radeon.h         |   64 ++++
 src/radeon_bios.c    |  273 ++++++++++++++++++
 src/radeon_crtc.c    |   27 +
 src/radeon_display.c |   26 -
 src/radeon_driver.c  |  504 ++++++++++++++++++++++++++++++++-
 src/radeon_modes.c   |   15 +
 src/radeon_output.c  |  227 ++++++++-------
 src/radeon_probe.h   |   21 +
 src/radeon_reg.h     |   88 +++++
 src/radeon_tv.c      |  759 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/radeon_tv.h      |   56 +++
 12 files changed, 1914 insertions(+), 149 deletions(-)

New commits:
diff-tree d1abdad167aa24ac970c69422435df443c82ebd6 (from 0cca25d8d6a0cb0d29b68e6cd9c699d1390aede1)
Author: Alex Deucher <alex at botch2.com>
Date:   Sun Aug 5 03:45:02 2007 -0400

    RADEON: fixes
    
    - fix output ordering
    - set tv-out to return un-connected for now in radeon_detect()

diff --git a/src/radeon_bios.c b/src/radeon_bios.c
index fe1d091..4556552 100644
--- a/src/radeon_bios.c
+++ b/src/radeon_bios.c
@@ -200,13 +200,13 @@ static Bool RADEONGetATOMConnectorInfoFr
 
     /* DVI-I ports have 2 entries: one for analog, one for digital.  combine them */
     if (info->BiosConnector[0].valid && info->BiosConnector[7].valid) {
-	info->BiosConnector[0].TMDSType = info->BiosConnector[7].TMDSType;
-	info->BiosConnector[7].valid = FALSE;
+	info->BiosConnector[7].DACType = info->BiosConnector[0].DACType;
+	info->BiosConnector[0].valid = FALSE;
     }
 
     if (info->BiosConnector[4].valid && info->BiosConnector[3].valid) {
-	info->BiosConnector[4].TMDSType = info->BiosConnector[3].TMDSType;
-	info->BiosConnector[3].valid = FALSE;
+	info->BiosConnector[3].DACType = info->BiosConnector[4].DACType;
+	info->BiosConnector[4].valid = FALSE;
     }
 
 
diff --git a/src/radeon_output.c b/src/radeon_output.c
index 0cd1183..f65507a 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -1038,9 +1038,11 @@ radeon_detect(xf86OutputPtr output)
 
     /* assume tv is connected for now */
     if (radeon_output->type == OUTPUT_STV) {
-	radeon_output->MonType = MT_STV;
+	/*radeon_output->MonType = MT_STV;*/
+	radeon_output->MonType = MT_NONE;
     } else if (radeon_output->type == OUTPUT_CTV) {
-	radeon_output->MonType = MT_CTV;
+	/*radeon_output->MonType = MT_CTV;*/
+	radeon_output->MonType = MT_NONE;
     } else {
 	radeon_output->MonType = MT_UNKNOWN;
 	RADEONConnectorFindMonitor(pScrn, output);
@@ -1851,17 +1853,17 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 		    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I_ATOM) ||
 		    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A_ATOM)) {
 		    if (num_dvi > 1) {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-1");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0");
 			num_dvi--;
 		    } else {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-1");
 		    }
 		} else if (info->BiosConnector[0].ConnectorType == CONNECTOR_VGA_ATOM) {
 		    if (num_vga > 1) {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0");
 			num_vga--;
 		    } else {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1");
 		    }
 		} else
 		    output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
@@ -1869,17 +1871,17 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 		if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) ||
 		     (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I)) {
 		    if (num_dvi > 1) {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-1");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0");
 			num_dvi--;
 		    } else {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-1");
 		    }
 		} else if (info->BiosConnector[0].ConnectorType == CONNECTOR_CRT) {
 		    if (num_vga > 1) {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0");
 			num_vga--;
 		    } else {
-			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0");
+			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1");
 		    }
 		} else
 		    output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
diff-tree 0cca25d8d6a0cb0d29b68e6cd9c699d1390aede1 (from ba5496ae7973786802962bf649dd91c219531749)
Author: Alex Deucher <alex at botch2.com>
Date:   Sun Aug 5 03:19:24 2007 -0400

    RADEON: Fix DVI-I support in ATOM bios connector table parsing

diff --git a/src/radeon_bios.c b/src/radeon_bios.c
index b79fea7..fe1d091 100644
--- a/src/radeon_bios.c
+++ b/src/radeon_bios.c
@@ -198,6 +198,18 @@ static Bool RADEONGetATOMConnectorInfoFr
 	return FALSE;
     }
 
+    /* DVI-I ports have 2 entries: one for analog, one for digital.  combine them */
+    if (info->BiosConnector[0].valid && info->BiosConnector[7].valid) {
+	info->BiosConnector[0].TMDSType = info->BiosConnector[7].TMDSType;
+	info->BiosConnector[7].valid = FALSE;
+    }
+
+    if (info->BiosConnector[4].valid && info->BiosConnector[3].valid) {
+	info->BiosConnector[4].TMDSType = info->BiosConnector[3].TMDSType;
+	info->BiosConnector[3].valid = FALSE;
+    }
+
+
     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bios Connector table: \n");
     for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
 	if (info->BiosConnector[i].valid) {
diff-tree ba5496ae7973786802962bf649dd91c219531749 (from 2ec22783ddf4c522df9e5fd1b2003854486d7a2b)
Author: Alex Deucher <alex at botch2.com>
Date:   Sun Aug 5 02:27:32 2007 -0400

    RADEON: refactor output init to handle multiple DVI or VGA
    
    - refactor output init to handle multiple DVI or VGA with the new
    bios table parsing

diff --git a/src/radeon_output.c b/src/radeon_output.c
index d0225aa..0cd1183 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -1701,7 +1701,8 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
     xf86OutputPtr output;
     char *optstr;
     int i = 0;
-
+    int num_vga = 0;
+    int num_dvi = 0;
 
     /* We first get the information about all connectors from BIOS.
      * This is how the card is phyiscally wired up.
@@ -1795,6 +1796,27 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 
     for (i = 0 ; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
 	if (info->BiosConnector[i].valid) {
+	    if (info->IsAtomBios) {
+		if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D_ATOM) ||
+		    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I_ATOM) ||
+		    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A_ATOM)) {
+		    num_dvi++;
+		} else if (info->BiosConnector[i].ConnectorType == CONNECTOR_VGA_ATOM) {
+		    num_vga++;
+		}
+	    } else {
+		if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) ||
+		    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I)) {
+		    num_dvi++;
+		} else if (info->BiosConnector[i].ConnectorType == CONNECTOR_CRT) {
+		    num_vga++;
+		}
+	    }
+	}
+    }
+
+    for (i = 0 ; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
+	if (info->BiosConnector[i].valid) {
 	    RADEONOutputPrivatePtr radeon_output = xnfcalloc(sizeof(RADEONOutputPrivateRec), 1);
 	    if (!radeon_output) {
 		return FALSE;
@@ -1825,39 +1847,40 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 	    }
 	    RADEONSetOutputType(pScrn, radeon_output);
 	    if (info->IsAtomBios) {
-		if (((info->BiosConnector[0].ConnectorType == CONNECTOR_DVI_D_ATOM) ||
-		     (info->BiosConnector[0].ConnectorType == CONNECTOR_DVI_I_ATOM) ||
-		     (info->BiosConnector[0].ConnectorType == CONNECTOR_DVI_A_ATOM)) &&
-		    ((info->BiosConnector[1].ConnectorType == CONNECTOR_DVI_D_ATOM) ||
-		     (info->BiosConnector[1].ConnectorType == CONNECTOR_DVI_I_ATOM) ||
-		     (info->BiosConnector[1].ConnectorType == CONNECTOR_DVI_A_ATOM))) {
-		    if (i > 0)
+		if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D_ATOM) ||
+		    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I_ATOM) ||
+		    (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A_ATOM)) {
+		    if (num_dvi > 1) {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-1");
-		    else
+			num_dvi--;
+		    } else {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0");
-		} else if ((info->BiosConnector[0].ConnectorType == CONNECTOR_VGA_ATOM) &&
-			   (info->BiosConnector[1].ConnectorType == CONNECTOR_VGA_ATOM)) {
-		    if (i > 0)
+		    }
+		} else if (info->BiosConnector[0].ConnectorType == CONNECTOR_VGA_ATOM) {
+		    if (num_vga > 1) {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1");
-		    else
+			num_vga--;
+		    } else {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0");
+		    }
 		} else
 		    output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
 	    } else {
-		if (((info->BiosConnector[0].ConnectorType == CONNECTOR_DVI_D) ||
-		     (info->BiosConnector[0].ConnectorType == CONNECTOR_DVI_I)) &&
-		    ((info->BiosConnector[1].ConnectorType == CONNECTOR_DVI_D) ||
-		     (info->BiosConnector[1].ConnectorType == CONNECTOR_DVI_I))) {
-		    if (i > 0)
+		if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) ||
+		     (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I)) {
+		    if (num_dvi > 1) {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-1");
-		    else
+			num_dvi--;
+		    } else {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0");
-		} else if ((info->BiosConnector[0].ConnectorType == CONNECTOR_CRT) &&
-			   (info->BiosConnector[1].ConnectorType == CONNECTOR_CRT)) {
-		    if (i > 0)
+		    }
+		} else if (info->BiosConnector[0].ConnectorType == CONNECTOR_CRT) {
+		    if (num_vga > 1) {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1");
-		    else
+			num_vga--;
+		    } else {
 			output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0");
+		    }
 		} else
 		    output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
 	    }
diff-tree 2ec22783ddf4c522df9e5fd1b2003854486d7a2b (from cc8e1d95f1b90a259beea4e8cc4d7e29af660919)
Author: Alex Deucher <alex at botch2.com>
Date:   Sun Aug 5 01:39:35 2007 -0400

    RADEON: attempt to do the right thing for standards other than PAL or NTSC

diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index ec355e2..3c12dfd 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -203,7 +203,10 @@ static Bool RADEONInitTVRestarts(xf86Out
     const TVModeConstants *constPtr;
 
     /* FIXME: need to revisit this when we add more modes */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	constPtr = &availableTVModes[0];
     else
 	constPtr = &availableTVModes[1];
@@ -211,7 +214,10 @@ static Bool RADEONInitTVRestarts(xf86Out
     hTotal = constPtr->horTotal;
     vTotal = constPtr->verTotal;
     
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	fTotal = NTSC_TV_VFTOTAL + 1;
     else
 	fTotal = PAL_TV_VFTOTAL + 1;
@@ -219,7 +225,9 @@ static Bool RADEONInitTVRestarts(xf86Out
     /* Adjust positions 1&2 in hor. code timing table */
     hOffset = radeon_output->hPos * H_POS_UNIT;
 
-    if (radeon_output->tvStd == TV_STD_NTSC) {
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M) {
 	p1 = hor_timing_NTSC[ H_TABLE_POS1 ];
 	p2 = hor_timing_NTSC[ H_TABLE_POS2 ];
     } else {
@@ -247,7 +255,10 @@ static Bool RADEONInitTVRestarts(xf86Out
      * Convert vPos TV lines to n. of CRTC pixels
      * Be verrrrry careful when mixing signed & unsigned values in C..
      */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M||
+	radeon_output->tvStd == TV_STD_PAL_60)
 	vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(NTSC_TV_LINES_PER_FRAME);
     else
 	vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(PAL_TV_LINES_PER_FRAME);
@@ -267,7 +278,10 @@ static Bool RADEONInitTVRestarts(xf86Out
 	   save->tv_frestart , save->tv_vrestart , save->tv_hrestart);
 
     /* Compute H_INC from hSize */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M ||
+	radeon_output->tvStd == TV_STD_PAL_60)
 	hInc = (CARD16)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) /
 			(radeon_output->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE)));
     else
@@ -298,7 +312,10 @@ void RADEONInitTVRegisters(xf86OutputPtr
 
 
     /* FIXME: need to revisit this when we add more modes */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	constPtr = &availableTVModes[0];
     else
 	constPtr = &availableTVModes[1];
@@ -330,16 +347,18 @@ void RADEONInitTVRegisters(xf86OutputPtr
 	                       | (0x3b << RADEON_BLANK_LEVEL_SHIFT)
 	                       | (0x6 << RADEON_CY_FILT_BLEND_SHIFT);
 
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M ||
+	radeon_output->tvStd == TV_STD_PAL_60 ||
+	radeon_output->tvStd == TV_STD_SCART_PAL) {
 	save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT);
-    else
+	save->tv_modulator_cntl2 = 0x00000191;
+    } else {
 	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN
 	                            | (0x3b << RADEON_SET_UP_LEVEL_SHIFT);
-
-    if (radeon_output->tvStd == TV_STD_NTSC)
-	save->tv_modulator_cntl2 = 0x00000191;
-    else
 	save->tv_modulator_cntl2 = 0x003e01b2;
+    }
 
     save->pll_test_cntl = 0;
 
@@ -364,7 +383,10 @@ void RADEONInitTVRegisters(xf86OutputPtr
 
     save->tv_sync_size = constPtr->horResolution + 8;
 
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M ||
+	radeon_output->tvStd == TV_STD_PAL_60)
 	vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME;
     else
 	vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME;
@@ -378,7 +400,10 @@ void RADEONInitTVRegisters(xf86OutputPtr
     else
 	save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT);
 
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+        radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	flicker_removal =
 	    (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5;
     else
@@ -416,12 +441,16 @@ void RADEONInitTVRegisters(xf86OutputPtr
 
     save->tv_dac_cntl = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | (8 << 16) | (6 << 20);
 
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+        radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
     else
 	save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
 
 #if 0
+    /* needs fixes for r4xx */
     save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD
 	                 | RADEON_TV_DAC_BDACPD);
 
@@ -435,7 +464,10 @@ void RADEONInitTVRegisters(xf86OutputPtr
     }
 #endif
 
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+        radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	save->tv_pll_cntl = (NTSC_TV_PLL_M & RADEON_TV_M0LO_MASK) |
 	    (((NTSC_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
 	    ((NTSC_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
@@ -454,18 +486,30 @@ void RADEONInitTVRegisters(xf86OutputPtr
 
     save->tv_vdisp = constPtr->verResolution - 1;
 
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+        radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	save->tv_ftotal = NTSC_TV_VFTOTAL;
     else
 	save->tv_ftotal = PAL_TV_VFTOTAL;
 
     save->tv_vtotal = constPtr->verTotal - 1;
 
-    if (radeon_output->tvStd == TV_STD_NTSC) {
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M) {
 	hor_timing = hor_timing_NTSC;
-	vert_timing = vert_timing_NTSC;
     } else {
 	hor_timing = hor_timing_PAL;
+    }
+
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+	radeon_output->tvStd == TV_STD_PAL_M ||
+	radeon_output->tvStd == TV_STD_PAL_60) {
+	vert_timing = vert_timing_NTSC;
+    } else {
 	vert_timing = vert_timing_PAL;
     }
 
@@ -546,7 +590,10 @@ void RADEONAdjustCrtcRegistersForTV(Scrn
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
     /* FIXME: need to revisit this when we add more modes */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	constPtr = &availableTVModes[0];
     else
 	constPtr = &availableTVModes[1];
@@ -576,7 +623,10 @@ void RADEONAdjustPLLRegistersForTV(ScrnI
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
     /* FIXME: need to revisit this when we add more modes */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	constPtr = &availableTVModes[0];
     else
 	constPtr = &availableTVModes[1];
@@ -627,7 +677,10 @@ void RADEONAdjustCrtc2RegistersForTV(Scr
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
     /* FIXME: need to revisit this when we add more modes */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	constPtr = &availableTVModes[0];
     else
 	constPtr = &availableTVModes[1];
@@ -657,7 +710,10 @@ void RADEONAdjustPLL2RegistersForTV(Scrn
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
     /* FIXME: need to revisit this when we add more modes */
-    if (radeon_output->tvStd == TV_STD_NTSC)
+    if (radeon_output->tvStd == TV_STD_NTSC ||
+	radeon_output->tvStd == TV_STD_NTSC_J ||
+        radeon_output->tvStd == TV_STD_PAL_M ||
+        radeon_output->tvStd == TV_STD_PAL_60)
 	constPtr = &availableTVModes[0];
     else
 	constPtr = &availableTVModes[1];
diff-tree cc8e1d95f1b90a259beea4e8cc4d7e29af660919 (from b61a49f2a5401560f85e11bcdd005287433cad12)
Author: Alex Deucher <alex at botch2.com>
Date:   Sun Aug 5 01:14:36 2007 -0400

    RADEON: Major rework of BIOS table parsing
    
    - greatly simplify ATOM and legacy connector table parsing
    - use bios tables to detect LVDS and TV outputs
    - add support for TV table parsing (legacy only)

diff --git a/src/radeon.h b/src/radeon.h
index 7792f31..432ee89 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -875,6 +875,7 @@ extern Bool        RADEONGetConnectorInf
 extern Bool        RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn);
 extern Bool        RADEONGetLVDSInfoFromBIOS (xf86OutputPtr output);
 extern Bool        RADEONGetTMDSInfoFromBIOS (xf86OutputPtr output);
+extern Bool        RADEONGetTVInfoFromBIOS (xf86OutputPtr output);
 extern Bool        RADEONGetHardCodedEDIDFromBIOS (xf86OutputPtr output);
 
 extern void        RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn,
diff --git a/src/radeon_bios.c b/src/radeon_bios.c
index 26019ba..b79fea7 100644
--- a/src/radeon_bios.c
+++ b/src/radeon_bios.c
@@ -141,6 +141,175 @@ Bool RADEONGetBIOSInfo(ScrnInfoPtr pScrn
     return TRUE;
 }
 
+static Bool RADEONGetATOMConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR (pScrn);
+    int offset, i, tmp, tmp0, crtc, portinfo, gpio;
+
+    if (!info->VBIOS) return FALSE;
+
+    offset = RADEON_BIOS16(info->MasterDataStart + 22);
+
+    if (offset) {
+	tmp = RADEON_BIOS16(offset + 4);
+	for (i = 0; i < 8; i++) {
+	    if (tmp & (1 << i)) {
+		info->BiosConnector[i].valid = TRUE;
+		portinfo = RADEON_BIOS16(offset + 6 + i * 2);
+		info->BiosConnector[i].DACType = (portinfo & 0xf) - 1;
+		info->BiosConnector[i].ConnectorType = (portinfo >> 4) & 0xf;
+		crtc = (portinfo >> 8) & 0xf;
+		tmp0 = RADEON_BIOS16(info->MasterDataStart + 24);
+		gpio = RADEON_BIOS16(tmp0 + 4 + 27 * crtc) * 4;
+		switch(gpio) {
+		case RADEON_GPIO_MONID:
+		    info->BiosConnector[i].DDCType = DDC_MONID;
+		    break;
+		case RADEON_GPIO_DVI_DDC:
+		    info->BiosConnector[i].DDCType = DDC_DVI;
+		    break;
+		case RADEON_GPIO_VGA_DDC:
+		    info->BiosConnector[i].DDCType = DDC_VGA;
+		    break;
+		case RADEON_GPIO_CRT2_DDC:
+		    info->BiosConnector[i].DDCType = DDC_CRT2;
+		    break;
+		case RADEON_LCD_GPIO_MASK:
+		    info->BiosConnector[i].DDCType = DDC_LCD;
+		    break;
+		default:
+		    info->BiosConnector[i].DDCType = DDC_NONE_DETECTED;
+		    break;
+		}
+
+		if (i == 3)
+		    info->BiosConnector[i].TMDSType = TMDS_INT;
+		else if (i == 7)
+		    info->BiosConnector[i].TMDSType = TMDS_EXT;
+		else
+		    info->BiosConnector[i].TMDSType = TMDS_UNKNOWN;
+
+	    } else {
+		info->BiosConnector[i].valid = FALSE;
+	    }
+	}   
+    } else {
+	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n");
+	return FALSE;
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bios Connector table: \n");
+    for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
+	if (info->BiosConnector[i].valid) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n",
+		       i, info->BiosConnector[i].DDCType, info->BiosConnector[i].DACType,
+		       info->BiosConnector[i].TMDSType, info->BiosConnector[i].ConnectorType);
+	}
+    }
+
+    return TRUE;
+}
+
+static Bool RADEONGetLegacyConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR (pScrn);
+    int offset, i, entry, tmp, tmp0, tmp1;
+
+    offset = RADEON_BIOS16(info->ROMHeaderStart + 0x50);
+    if (offset) {
+	for (i = 0; i < 4; i++) {
+	    entry = offset + 2 + i*2;
+
+	    if (!RADEON_BIOS16(entry)) {
+		break;
+	    }
+	    info->BiosConnector[i].valid = TRUE;
+	    tmp = RADEON_BIOS16(entry);
+	    info->BiosConnector[i].ConnectorType = (tmp >> 12) & 0xf;
+	    info->BiosConnector[i].DDCType = (tmp >> 8) & 0xf;
+	    info->BiosConnector[i].DACType = tmp & 0x3;
+	    if (tmp & 0x10)
+		info->BiosConnector[i].TMDSType = TMDS_EXT;
+	    else
+		info->BiosConnector[i].TMDSType = TMDS_INT;
+
+	}
+    } else {
+	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n");
+	return FALSE;
+    }
+
+    /* check LVDS table */
+    if (info->IsMobility) {
+	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x40);
+	if (offset) {
+	    info->BiosConnector[4].valid = TRUE;
+	    info->BiosConnector[4].ConnectorType = CONNECTOR_PROPRIETARY;
+	    info->BiosConnector[4].DACType = DAC_NONE;
+	    info->BiosConnector[4].TMDSType = TMDS_NONE;
+
+	    tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42);
+	    if (tmp) {
+		tmp0 = RADEON_BIOS16(tmp + 0x15);
+		if (tmp0) {
+		    tmp1 = RADEON_BIOS8(tmp0+2) & 0x07;
+		    if (tmp1) {	    
+			info->BiosConnector[4].DDCType	= tmp1;      
+			if (info->BiosConnector[4].DDCType > DDC_LCD) {
+			    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+				       "Unknown DDCType %d found\n",
+				       info->BiosConnector[4].DDCType);
+			    info->BiosConnector[4].DDCType = DDC_NONE_DETECTED;
+			}
+			xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n");
+		    }
+		}
+	    } else {
+		info->BiosConnector[4].DDCType = DDC_NONE_DETECTED;
+	    }
+	}
+    }
+
+    /* check TV table */
+    if (info->InternalTVOut) {
+	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
+	if (offset) {
+	    if (RADEON_BIOS8(offset + 6) == 'T') {
+		info->BiosConnector[5].valid = TRUE;
+		/* assume s-video for now */
+		info->BiosConnector[5].ConnectorType = CONNECTOR_STV;
+		info->BiosConnector[5].DACType = DAC_TVDAC;
+		info->BiosConnector[5].TMDSType = TMDS_NONE;
+		info->BiosConnector[5].DDCType = DDC_NONE_DETECTED;
+	    }
+	}
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bios Connector table: \n");
+    for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
+	if (info->BiosConnector[i].valid) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n",
+		       i, info->BiosConnector[i].DDCType, info->BiosConnector[i].DACType,
+		       info->BiosConnector[i].TMDSType, info->BiosConnector[i].ConnectorType);
+	}
+    }
+
+    return TRUE;
+}
+
+Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
+{
+    RADEONInfoPtr info = RADEONPTR (pScrn);
+
+    if(!info->VBIOS) return FALSE;
+
+    if (info->IsAtomBios)
+	return RADEONGetATOMConnectorInfoFromBIOS(pScrn);
+    else
+	return RADEONGetLegacyConnectorInfoFromBIOS(pScrn);
+}
+
+#if 0
 Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
 {
     RADEONInfoPtr info = RADEONPTR (pScrn);
@@ -350,6 +519,98 @@ Bool RADEONGetConnectorInfoFromBIOS (Scr
     }
     return TRUE;
 }
+#endif
+
+Bool RADEONGetTVInfoFromBIOS (xf86OutputPtr output) {
+    ScrnInfoPtr pScrn = output->scrn;
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    int offset, refclk, stds;
+
+    if (!info->VBIOS) return FALSE;
+
+    if (info->IsAtomBios) {
+	/* no idea where TV table is on ATOM bios */
+	return FALSE;
+    } else {
+	offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32);
+	if (offset) {
+	    if (RADEON_BIOS8(offset + 6) == 'T') {
+		switch (RADEON_BIOS8(offset + 7) & 0xf) {
+		case 1:
+		    radeon_output->tvStd = TV_STD_NTSC;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
+		    break;
+		case 2:
+		    radeon_output->tvStd = TV_STD_PAL;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
+		    break;
+		case 3:
+		    radeon_output->tvStd = TV_STD_PAL_M;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
+		    break;
+		case 4:
+		    radeon_output->tvStd = TV_STD_PAL_60;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
+		    break;
+		case 5:
+		    radeon_output->tvStd = TV_STD_NTSC_J;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
+		    break;
+		case 6:
+		    radeon_output->tvStd = TV_STD_SCART_PAL;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: SCART-PAL\n");
+		    break;
+		default:
+		    radeon_output->tvStd = TV_STD_NTSC;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Unknown TV standard; defaulting to NTSC\n");
+		    break;
+		}
+
+		refclk = (RADEON_BIOS8(offset + 9) >> 2) & 0x3;
+		if (refclk == 0)
+		    radeon_output->TVRefClk = 29.498928713; /* MHz */
+		else if (refclk == 1)
+		    radeon_output->TVRefClk = 28.636360000;
+		else if (refclk == 2)
+		    radeon_output->TVRefClk = 14.318180000;
+		else if (refclk == 3)
+		    radeon_output->TVRefClk = 27.000000000;
+
+		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
+		stds = RADEON_BIOS8(offset + 10) & 0x1f;
+		if (stds & TV_STD_NTSC) {
+		    radeon_output->SupportedTVStds |= TV_STD_NTSC;
+		    ErrorF("NTSC ");
+		}
+		if (stds & TV_STD_PAL) {
+		    radeon_output->SupportedTVStds |= TV_STD_PAL;
+		    ErrorF("PAL ");
+		}
+		if (stds & TV_STD_PAL_M) {
+		    radeon_output->SupportedTVStds |= TV_STD_PAL_M;
+		    ErrorF("PAL-M ");
+		}
+		if (stds & TV_STD_PAL_60) {
+		    radeon_output->SupportedTVStds |= TV_STD_PAL_60;
+		    ErrorF("PAL-60 ");
+		}
+		if (stds & TV_STD_NTSC_J) {
+		    radeon_output->SupportedTVStds |= TV_STD_NTSC_J;
+		    ErrorF("NTSC-J ");
+		}
+		if (stds & TV_STD_SCART_PAL) {
+		    radeon_output->SupportedTVStds |= TV_STD_SCART_PAL;
+		    ErrorF("SCART-PAL");
+		}
+		ErrorF("\n");
+
+		return TRUE;
+	    } else
+		return FALSE;
+	}
+    }
+}
 
 /* Read PLL parameters from BIOS block.  Default to typical values if there
    is no BIOS. */
diff --git a/src/radeon_output.c b/src/radeon_output.c
index fa6fb4f..d0225aa 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -611,6 +611,7 @@ radeon_mode_valid(xf86OutputPtr output, 
 
     if (radeon_output->type == OUTPUT_STV ||
 	radeon_output->type == OUTPUT_CTV) {
+	/* FIXME: Update when more modes are added */
 	if (pMode->HDisplay == 800 && pMode->VDisplay == 600)
 	    return MODE_OK;
 	else
@@ -1630,6 +1631,27 @@ RADEONGetTMDSInfo(xf86OutputPtr output)
     }
 }
 
+static void
+RADEONGetTVInfo(xf86OutputPtr output)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    int i;
+
+    radeon_output->hPos = 0;
+    radeon_output->vPos = 0;
+    radeon_output->hSize = 0;
+
+    if (RADEONGetTVInfoFromBIOS(output)) return;
+
+    /* set some reasonable defaults */
+    radeon_output->tvStd = TV_STD_NTSC;
+    radeon_output->TVRefClk = 27.000000000;
+    radeon_output->SupportedTVStds = TV_STD_NTSC | TV_STD_PAL;
+
+}
+
 void RADEONInitConnector(xf86OutputPtr output)
 {
     ScrnInfoPtr	    pScrn = output->scrn;
@@ -1657,12 +1679,11 @@ void RADEONInitConnector(xf86OutputPtr o
 
     if (radeon_output->type == OUTPUT_DVI) {
 	RADEONGetTMDSInfo(output);
+    }
 
-	// FIXME -- this should be done in detect or getmodes
-	/*if (i == 0)
-	  RADEONGetHardCodedEDIDFromBIOS(output);*/
-
-	/*RADEONUpdatePanelSize(output);*/
+    if (radeon_output->type == OUTPUT_STV ||
+	radeon_output->type == OUTPUT_CTV) {
+	RADEONGetTVInfo(output);
     }
 
     if (radeon_output->DACType == DAC_TVDAC) {
@@ -1688,15 +1709,14 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
      * If not, we may have problem -- need to use MonitorLayout option.
      */
     for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
+	info->BiosConnector[i].valid = FALSE;
 	info->BiosConnector[i].DDCType = DDC_NONE_DETECTED;
 	info->BiosConnector[i].DACType = DAC_UNKNOWN;
 	info->BiosConnector[i].TMDSType = TMDS_UNKNOWN;
 	info->BiosConnector[i].ConnectorType = CONNECTOR_NONE;
     }
 
-    if (!RADEONGetConnectorInfoFromBIOS(pScrn) ||
-        ((info->BiosConnector[0].DDCType == 0) &&
-        (info->BiosConnector[1].DDCType == 0))) {
+    if (!RADEONGetConnectorInfoFromBIOS(pScrn)) {
 	if (info->IsMobility) {
 	    /* Below is the most common setting, but may not be true */
 #if defined(__powerpc__)
@@ -1712,6 +1732,7 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 	    info->BiosConnector[1].DACType = DAC_PRIMARY;
 	    info->BiosConnector[1].TMDSType = TMDS_EXT;
 	    info->BiosConnector[1].ConnectorType = CONNECTOR_CRT;
+
 	} else {
 	    /* Below is the most common setting, but may not be true */
 	    info->BiosConnector[0].DDCType = DDC_DVI;
@@ -1725,6 +1746,13 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 	    info->BiosConnector[1].ConnectorType = CONNECTOR_CRT;
 	}
 
+	if (info->InternalTVOut) {
+	    info->BiosConnector[2].ConnectorType = CONNECTOR_STV;
+	    info->BiosConnector[2].DACType = DAC_TVDAC;
+	    info->BiosConnector[2].TMDSType = TMDS_NONE;
+	    info->BiosConnector[2].DDCType = DDC_NONE_DETECTED;
+	}
+
        /* Some cards have the DDC lines swapped and we have no way to
         * detect it yet (Mac cards)
         */
@@ -1766,7 +1794,7 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
     }
 
     for (i = 0 ; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
-	if (info->BiosConnector[i].ConnectorType != CONNECTOR_NONE) {
+	if (info->BiosConnector[i].valid) {
 	    RADEONOutputPrivatePtr radeon_output = xnfcalloc(sizeof(RADEONOutputPrivateRec), 1);
 	    if (!radeon_output) {
 		return FALSE;
@@ -1851,98 +1879,6 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 	}
     }
 
-    /* if it's a mobility make sure we have a LVDS port */
-    if (info->IsMobility) {
-	if (info->IsAtomBios) {
-	    if (info->BiosConnector[0].ConnectorType != CONNECTOR_LVDS_ATOM &&
-		info->BiosConnector[1].ConnectorType != CONNECTOR_LVDS_ATOM) {
-		/* add LVDS port */
-		RADEONOutputPrivatePtr radeon_output = xnfcalloc(sizeof(RADEONOutputPrivateRec), 1);
-		if (!radeon_output) {
-		    return FALSE;
-		}
-		radeon_output->MonType = MT_UNKNOWN;
-		radeon_output->DDCType = DDC_LCD;
-		radeon_output->DACType = DAC_NONE;
-		radeon_output->TMDSType = TMDS_NONE;
-		radeon_output->ConnectorType = CONNECTOR_LVDS_ATOM;
-		RADEONSetOutputType(pScrn, radeon_output);
-		output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
-		if (!output) {
-		    return FALSE;
-		}
-		output->driver_private = radeon_output;
-		output->possible_crtcs = 1;
-		output->possible_clones = 0;
-
-		RADEONInitConnector(output);
-
-	    }
-	} else {
-	    if (info->BiosConnector[0].ConnectorType != CONNECTOR_PROPRIETARY &&
-		info->BiosConnector[1].ConnectorType != CONNECTOR_PROPRIETARY) {
-		/* add LVDS port */
-		RADEONOutputPrivatePtr radeon_output = xnfcalloc(sizeof(RADEONOutputPrivateRec), 1);
-		if (!radeon_output) {
-		    return FALSE;
-		}
-		radeon_output->MonType = MT_UNKNOWN;
-		radeon_output->DDCType = DDC_LCD;
-		radeon_output->DACType = DAC_NONE;
-		radeon_output->TMDSType = TMDS_NONE;
-		radeon_output->ConnectorType = CONNECTOR_PROPRIETARY;
-		RADEONSetOutputType(pScrn, radeon_output);
-		output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
-		if (!output) {
-		    return FALSE;
-		}
-		output->driver_private = radeon_output;
-		output->possible_crtcs = 1;
-		output->possible_clones = 0;
-
-		RADEONInitConnector(output);
-	    }
-	}
-    }
-
-    /* add TV out */
-#if 0
-    if (info->InternalTVOut) {
-	/* need to check the bios tables to see if we really have tv out and what type we have */
-	RADEONOutputPrivatePtr radeon_output = xnfcalloc(sizeof(RADEONOutputPrivateRec), 1);
-	if (!radeon_output) {
-	    return FALSE;
-	}
-	/* hard code type for now */
-	radeon_output->MonType = MT_STV;
-	radeon_output->DDCType = DDC_NONE_DETECTED;
-	radeon_output->DACType = DAC_TVDAC;
-	radeon_output->TMDSType = TMDS_NONE;
-
-	/* hard code type for now */
-	if (info->IsAtomBios)
-	    radeon_output->ConnectorType = CONNECTOR_STV_ATOM;
-	else
-	    radeon_output->ConnectorType = CONNECTOR_STV;
-
-	radeon_output->tvStd = TV_STD_NTSC;
-	radeon_output->hPos = 0;
-	radeon_output->vPos = 0;
-	radeon_output->hSize = 0;
-
-	RADEONSetOutputType(pScrn, radeon_output);
-	output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
-	if (!output) {
-	    return FALSE;
-	}
-	output->driver_private = radeon_output;
-	output->possible_crtcs = 1 | 2;
-	output->possible_clones = 0;
-
-	RADEONInitConnector(output);
-    }
-#endif
-
     return TRUE;
 }
 
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index f0df341..27b78cc 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -140,13 +140,12 @@ typedef enum
 /* standards */
 typedef enum
 {
-    TV_STD_NTSC,
-    TV_STD_PAL,
-    TV_STD_PAL_M,
-    TV_STD_PAL_60,
-    TV_STD_NTSC_J,
-    TV_STD_PAL_CN,
-    TV_STD_PAL_N
+    TV_STD_NTSC      = 1,
+    TV_STD_PAL       = 2,
+    TV_STD_PAL_M     = 4,
+    TV_STD_PAL_60    = 8,
+    TV_STD_NTSC_J    = 16,
+    TV_STD_SCART_PAL = 32,
 } TVStd;
 
 typedef struct _RADEONCrtcPrivateRec {
@@ -167,6 +166,7 @@ typedef struct {
     RADEONDacType DACType;
     RADEONTmdsType TMDSType;
     RADEONConnectorType ConnectorType;
+    Bool valid;
 } RADEONBIOSConnector;
 
 typedef struct _RADEONOutputPrivateRec {
@@ -201,10 +201,12 @@ typedef struct _RADEONOutputPrivateRec {
     int               hPos;
     int               vPos;
     int               hSize;
+    float             TVRefClk;
+    int               SupportedTVStds;
 } RADEONOutputPrivateRec, *RADEONOutputPrivatePtr;
 
 #define RADEON_MAX_CRTC 2
-#define RADEON_MAX_BIOS_CONNECTOR 2
+#define RADEON_MAX_BIOS_CONNECTOR 8
 
 typedef struct
 {
diff-tree b61a49f2a5401560f85e11bcdd005287433cad12 (from 288fa627274cb399059262d4f8bd844fc220a042)
Author: Alex Deucher <alex at botch2.com>
Date:   Fri Aug 3 19:27:59 2007 -0400

    RADEON: Change indexing of TV constants table in preparation for standard re-work

diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index b802234..ec355e2 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -202,7 +202,11 @@ static Bool RADEONInitTVRestarts(xf86Out
     CARD16 hInc;
     const TVModeConstants *constPtr;
 
-    constPtr = &availableTVModes[radeon_output->tvStd];
+    /* FIXME: need to revisit this when we add more modes */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	constPtr = &availableTVModes[0];
+    else
+	constPtr = &availableTVModes[1];
 
     hTotal = constPtr->horTotal;
     vTotal = constPtr->verTotal;
@@ -292,7 +296,12 @@ void RADEONInitTVRegisters(xf86OutputPtr
     const CARD16 *hor_timing;
     const CARD16 *vert_timing;
 
-    constPtr = &availableTVModes[radeon_output->tvStd];
+
+    /* FIXME: need to revisit this when we add more modes */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	constPtr = &availableTVModes[0];
+    else
+	constPtr = &availableTVModes[1];
 
     save->tv_crc_cntl = 0;
 
@@ -536,7 +545,11 @@ void RADEONAdjustCrtcRegistersForTV(Scrn
     const TVModeConstants *constPtr;
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
-    constPtr = &availableTVModes[radeon_output->tvStd];
+    /* FIXME: need to revisit this when we add more modes */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	constPtr = &availableTVModes[0];
+    else
+	constPtr = &availableTVModes[1];
 
     save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
 	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
@@ -562,7 +575,11 @@ void RADEONAdjustPLLRegistersForTV(ScrnI
     const TVModeConstants *constPtr;
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
-    constPtr = &availableTVModes[radeon_output->tvStd];
+    /* FIXME: need to revisit this when we add more modes */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	constPtr = &availableTVModes[0];
+    else
+	constPtr = &availableTVModes[1];
 
     save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN;
 
@@ -609,7 +626,11 @@ void RADEONAdjustCrtc2RegistersForTV(Scr
     const TVModeConstants *constPtr;
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
-    constPtr = &availableTVModes[radeon_output->tvStd];
+    /* FIXME: need to revisit this when we add more modes */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	constPtr = &availableTVModes[0];
+    else
+	constPtr = &availableTVModes[1];
 
     save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
 	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
@@ -635,7 +656,11 @@ void RADEONAdjustPLL2RegistersForTV(Scrn
     const TVModeConstants *constPtr;
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
-    constPtr = &availableTVModes[radeon_output->tvStd];
+    /* FIXME: need to revisit this when we add more modes */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	constPtr = &availableTVModes[0];
+    else
+	constPtr = &availableTVModes[1];
 
     save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */
 
diff-tree 288fa627274cb399059262d4f8bd844fc220a042 (from b66a1bc7994b33d349c1519761e431959311c85f)
Author: Alex Deucher <alex at botch2.com>
Date:   Thu Aug 2 02:37:16 2007 -0400

    RADEON: avoid a divide by 0 and only save tv out regs if the chip has them

diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index a7f5831..c1f0c3c 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -4612,6 +4612,9 @@ static CARD8 RADEONComputePLLGain(CARD16
 {
     unsigned vcoFreq;
 
+    if (!ref_div)
+	return 1;
+
     vcoFreq = ((unsigned)reference_freq * fb_div) / ref_div;
 
     /*
@@ -5417,6 +5420,8 @@ static void RADEONSavePalette(ScrnInfoPt
 /* Save state that defines current video mode */
 static void RADEONSaveMode(ScrnInfoPtr pScrn, RADEONSavePtr save)
 {
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
 		   "RADEONSaveMode(%p)\n", save);
 
@@ -5428,7 +5433,8 @@ static void RADEONSaveMode(ScrnInfoPtr p
     RADEONSaveDACRegisters(pScrn, save);
     RADEONSaveCrtc2Registers(pScrn, save);
     RADEONSavePLL2Registers(pScrn, save);
-    RADEONSaveTVRegisters(pScrn, save);
+    if (info->InternalTVOut)
+	RADEONSaveTVRegisters(pScrn, save);
     /*RADEONSavePalette(pScrn, save);*/
 
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
diff-tree b66a1bc7994b33d349c1519761e431959311c85f (from d86592c8d5ce45d81d8a726c263e870e94fbcf11)
Author: Alex Deucher <alex at botch2.com>
Date:   Thu Aug 2 02:11:20 2007 -0400

    RADEON: fix tv-out enable/disable

diff --git a/src/radeon_display.c b/src/radeon_display.c
index bca0ac1..da2b82f 100644
--- a/src/radeon_display.c
+++ b/src/radeon_display.c
@@ -317,9 +317,8 @@ void RADEONEnableDisplay(xf86OutputPtr o
     RADEONOutputPrivatePtr radeon_output;
     radeon_output = output->driver_private;
 
-    ErrorF("enable montype: %d\n", radeon_output->MonType);
-
     if (bEnable) {
+	ErrorF("enable montype: %d\n", radeon_output->MonType);
         if (radeon_output->MonType == MT_CRT) {
             if (radeon_output->DACType == DAC_PRIMARY) {
                 tmp = INREG(RADEON_CRTC_EXT_CNTL);
@@ -362,20 +361,11 @@ void RADEONEnableDisplay(xf86OutputPtr o
             save->lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
         } else if (radeon_output->MonType == MT_STV ||
 		   radeon_output->MonType == MT_CTV) {
-#if 1
-	    /* TV_MASTER_CNTL ??? */
-
-	    /* XXX: FIXME: STV vs CTV and DACPD bits */
-	    tmp = INREG(RADEON_TV_DAC_CNTL);
-	    tmp |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
-	    tmp &= ~RADEON_TV_DAC_BGSLEEP;
-	    OUTREG(RADEON_TV_DAC_CNTL, tmp);
-	    save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
-	    save->tv_dac_cntl &= ~RADEON_TV_DAC_BGSLEEP;
-#endif
+	    RADEONDacPowerSet(pScrn, bEnable, (radeon_output->DACType == DAC_PRIMARY));
 	}
     } else {
-        if (radeon_output->MonType == MT_CRT || radeon_output->MonType == NONE) {
+	ErrorF("disable montype: %d\n", radeon_output->MonType);
+        if (radeon_output->MonType == MT_CRT) {
             if (radeon_output->DACType == DAC_PRIMARY) {
                 tmp = INREG(RADEON_CRTC_EXT_CNTL);
                 tmp &= ~RADEON_CRTC_CRT_ON;       
@@ -395,9 +385,7 @@ void RADEONEnableDisplay(xf86OutputPtr o
                 }
             }
 	    RADEONDacPowerSet(pScrn, bEnable, (radeon_output->DACType == DAC_PRIMARY));
-        }
-
-        if (radeon_output->MonType == MT_DFP || radeon_output->MonType == NONE) {
+        } else if (radeon_output->MonType == MT_DFP) {
             if (radeon_output->TMDSType == TMDS_INT) {
                 tmp = INREG(RADEON_FP_GEN_CNTL);
                 tmp &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
@@ -409,10 +397,7 @@ void RADEONEnableDisplay(xf86OutputPtr o
                 OUTREG(RADEON_FP2_GEN_CNTL, tmp);
                 save->fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
             }
-        }
-
-        if (radeon_output->MonType == MT_LCD || 
-            (radeon_output->MonType == NONE && radeon_output->ConnectorType == CONNECTOR_PROPRIETARY)) {
+        } else if (radeon_output->MonType == MT_LCD) {
 	    unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
 	    if (info->IsMobility || info->IsIGP) {
 	    /* Asic bug, when turning off LVDS_ON, we have to make sure
@@ -429,21 +414,8 @@ void RADEONEnableDisplay(xf86OutputPtr o
 	    if (info->IsMobility || info->IsIGP) {
 		OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmpPixclksCntl);
 	    }
-        }
-
-	if (radeon_output->MonType == MT_STV ||
-	    radeon_output->MonType == MT_CTV) {
-#if 1
-
-	    /* TV_MASTER_CNTL ??? */
-
-	    tmp = INREG(RADEON_TV_DAC_CNTL);
-	    tmp &= ~(RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
-	    tmp |= RADEON_TV_DAC_BGSLEEP;
-	    OUTREG(RADEON_TV_DAC_CNTL, tmp);
-	    save->tv_dac_cntl &= ~(RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
-	    save->tv_dac_cntl |= RADEON_TV_DAC_BGSLEEP;
-#endif
+        } else if (radeon_output->MonType == MT_STV || radeon_output->MonType == MT_CTV) {
+	    RADEONDacPowerSet(pScrn, bEnable, (radeon_output->DACType == DAC_PRIMARY));
 	}
     }
 }
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 64abf80..a7f5831 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -4541,7 +4541,6 @@ void RADEONRestoreTVRegisters(ScrnInfoPt
     RADEONRestoreTVRestarts(pScrn, restore);
   
     ErrorF("Restore Timing Tables\n");
-
     RADEONRestoreTVTimingTables(pScrn, restore);
   
 
@@ -4554,12 +4553,9 @@ void RADEONRestoreTVRegisters(ScrnInfoPt
 
     OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
 
-    /*OUTREG(RADEON_DISP_MERGE_CNTL, restore->disp_merge_cntl);*/
-
     OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings);
     OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings);
 
-    /* XXX: taken care of in EnableDisplay() */
     OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
 
     ErrorF("Leaving Restore TV\n");
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index 38fbcd0..b802234 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -405,17 +405,14 @@ void RADEONInitTVRegisters(xf86OutputPtr
     tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
     save->tv_timing_cntl = tmp;
 
-    /* XXX: taken care of in enabledisplay() */
-    save->tv_dac_cntl = /*RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD
-			  |*/ (8 << 16) | (6 << 20);
+    save->tv_dac_cntl = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | (8 << 16) | (6 << 20);
 
     if (radeon_output->tvStd == TV_STD_NTSC)
 	save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
     else
 	save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
 
-#if 1
-    /* XXX: taken care of in enabledisplay() */
+#if 0
     save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD
 	                 | RADEON_TV_DAC_BDACPD);
 
diff-tree d86592c8d5ce45d81d8a726c263e870e94fbcf11 (from 971feb34843225030fff05b3f9d3801534fbf2d4)
Author: Alex Deucher <alex at botch2.com>
Date:   Thu Aug 2 00:50:51 2007 -0400

    RADEON: add missing break

diff --git a/src/radeon_output.c b/src/radeon_output.c
index d3bb344..fa6fb4f 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -997,6 +997,7 @@ radeon_mode_set(xf86OutputPtr output, Di
 	if (radeon_crtc->crtc_id == 0)
 	    RADEONRestoreRMXRegisters(pScrn, &info->ModeReg);
 	RADEONRestoreLVDSRegisters(pScrn, &info->ModeReg);
+	break;
     case MT_DFP:
 	if (radeon_crtc->crtc_id == 0)
 	    RADEONRestoreRMXRegisters(pScrn, &info->ModeReg);
diff-tree 971feb34843225030fff05b3f9d3801534fbf2d4 (from 98d7e00437bea78e03180eb30ff30de3455d9d1a)
Author: Alex Deucher <alex at botch2.com>
Date:   Thu Aug 2 00:50:04 2007 -0400

    RADEON: move tv dac enable to enabledisplay()

diff --git a/src/radeon_display.c b/src/radeon_display.c
index 059dfca..bca0ac1 100644
--- a/src/radeon_display.c
+++ b/src/radeon_display.c
@@ -362,18 +362,16 @@ void RADEONEnableDisplay(xf86OutputPtr o
             save->lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
         } else if (radeon_output->MonType == MT_STV ||
 		   radeon_output->MonType == MT_CTV) {
-#if 0
+#if 1
 	    /* TV_MASTER_CNTL ??? */
 
 	    /* XXX: FIXME: STV vs CTV and DACPD bits */
 	    tmp = INREG(RADEON_TV_DAC_CNTL);
-	    tmp |= (TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
-	    tmp &= ~(TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD
-		     | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+	    tmp |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
+	    tmp &= ~RADEON_TV_DAC_BGSLEEP;
 	    OUTREG(RADEON_TV_DAC_CNTL, tmp);
-	    save->tv_dac_cntl |= (TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
-	    save->tv_dac_cntl &= ~(TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD
-				   | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+	    save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
+	    save->tv_dac_cntl &= ~RADEON_TV_DAC_BGSLEEP;
 #endif
 	}
     } else {
@@ -435,15 +433,16 @@ void RADEONEnableDisplay(xf86OutputPtr o
 
 	if (radeon_output->MonType == MT_STV ||
 	    radeon_output->MonType == MT_CTV) {
+#if 1
 
 	    /* TV_MASTER_CNTL ??? */
-#if 0
+
 	    tmp = INREG(RADEON_TV_DAC_CNTL);
-	    tmp &= ~(TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
-	    tmp |= (TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+	    tmp &= ~(RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
+	    tmp |= RADEON_TV_DAC_BGSLEEP;
 	    OUTREG(RADEON_TV_DAC_CNTL, tmp);
-	    save->tv_dac_cntl &= ~(TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
-	    save->tv_dac_cntl |= (TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+	    save->tv_dac_cntl &= ~(RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD);
+	    save->tv_dac_cntl |= RADEON_TV_DAC_BGSLEEP;
 #endif
 	}
     }
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index e4e6763..38fbcd0 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -406,8 +406,8 @@ void RADEONInitTVRegisters(xf86OutputPtr
     save->tv_timing_cntl = tmp;
 
     /* XXX: taken care of in enabledisplay() */
-    save->tv_dac_cntl = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD
-	                | (8 << 16) | (6 << 20);
+    save->tv_dac_cntl = /*RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD
+			  |*/ (8 << 16) | (6 << 20);
 
     if (radeon_output->tvStd == TV_STD_NTSC)
 	save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
diff-tree 98d7e00437bea78e03180eb30ff30de3455d9d1a (from 5c549c1d42f7bbc556942af13aff2661fae856f2)
Author: Alex Deucher <alex at botch2.com>
Date:   Thu Aug 2 00:20:50 2007 -0400

    RADEON: limit tv modes to the only one we can program at the moment

diff --git a/src/radeon_output.c b/src/radeon_output.c
index 2790ddf..d3bb344 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -609,6 +609,14 @@ radeon_mode_valid(xf86OutputPtr output, 
 {
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
 
+    if (radeon_output->type == OUTPUT_STV ||
+	radeon_output->type == OUTPUT_CTV) {
+	if (pMode->HDisplay == 800 && pMode->VDisplay == 600)
+	    return MODE_OK;
+	else
+	    return MODE_CLOCK_RANGE;
+    }
+
     if (radeon_output->type != OUTPUT_LVDS)
 	return MODE_OK;
 
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index 001d013..e4e6763 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -141,7 +141,7 @@ static const CARD16 vert_timing_PAL[] =
  **********************************************************************/
 static const TVModeConstants availableTVModes[] =
 {
-    { 
+    {
 	800,                /* horResolution */
 	600,                /* verResolution */
 	TV_STD_NTSC,        /* standard */
@@ -156,7 +156,7 @@ static const TVModeConstants availableTV
 	4,                  /* crtcPLL_postDiv */
 	1022,               /* pixToTV */
     },
-    { 
+    {
 	800,               /* horResolution */
 	600,               /* verResolution */
 	TV_STD_PAL,        /* standard */
diff-tree 5c549c1d42f7bbc556942af13aff2661fae856f2 (from b03978028fd975eb6946503d3a56a49c5a67f339)
Author: Alex Deucher <alex at botch2.com>
Date:   Wed Aug 1 23:45:07 2007 -0400

    RADEON: remove unused elements

diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index b700b1e..001d013 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -46,11 +46,8 @@ typedef struct
     unsigned defRestart;
     CARD16 crtcPLL_N;
     CARD8  crtcPLL_M;
-    Bool   crtcPLL_divBy2;
-    CARD8  crtcPLL_byteClkDiv;
     CARD8  crtcPLL_postDiv;
     unsigned pixToTV;
-    CARD8  byteClkDelay;
 } TVModeConstants;
 
 static const CARD16 hor_timing_NTSC[] =
@@ -156,11 +153,8 @@ static const TVModeConstants availableTV
 	625592,             /* defRestart */
 	592,                /* crtcPLL_N */
 	91,                 /* crtcPLL_M */
-	TRUE,               /* crtcPLL_divBy2 */
-	0,                  /* crtcPLL_byteClkDiv */
 	4,                  /* crtcPLL_postDiv */
 	1022,               /* pixToTV */
-	1,                  /* byteClkDelay */
     },
     { 
 	800,               /* horResolution */
@@ -174,11 +168,8 @@ static const TVModeConstants availableTV
 	696700,            /* defRestart */
 	1382,              /* crtcPLL_N */
 	231,               /* crtcPLL_M */
-	TRUE,              /* crtcPLL_divBy2 */
-	0,                 /* crtcPLL_byteClkDiv */
 	4,                 /* crtcPLL_postDiv */
 	759,               /* pixToTV */
-	1,                 /* byteClkDelay */
     }
 };
 
diff-tree b03978028fd975eb6946503d3a56a49c5a67f339 (from cf54222f1fa37366b2c2b39c82f8afc02f32e63c)
Author: Alex Deucher <alex at botch2.com>
Date:   Wed Aug 1 22:39:16 2007 -0400

    RADEON: convert hard coded tv out values to calculations

diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 7c5bef4..64abf80 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -4311,7 +4311,7 @@ static void RADEONWriteTVFIFO(ScrnInfoPt
 	    break;
 	i++;
     }
-    while (i < 100000);
+    while (i < 10000);
     /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/
 
     OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
@@ -4334,7 +4334,7 @@ static CARD32 RADEONReadTVFIFO(ScrnInfoP
 	    break;
 	i++;
     }
-    while (i < 100000);
+    while (i < 10000);
     /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/
 
     OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
@@ -4353,15 +4353,12 @@ static CARD16 RADEONGetHTimingTablesAddr
     case 0:
 	hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL;
 	break;
-
     case 1:
 	hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2;
 	break;
-
     case 2:
 	hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2;
 	break;
-
     default:
 	/* Of course, this should never happen */
 	hTable = 0;
@@ -4378,15 +4375,12 @@ static CARD16 RADEONGetVTimingTablesAddr
     case 0:
 	vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1;
 	break;
-
     case 1:
 	vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
 	break;
-
     case 2:
 	vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
 	break;
-
     default:
 	/* Of course, this should never happen */
 	vTable = 0;
@@ -5359,7 +5353,7 @@ static void RADEONSaveTVRegisters(ScrnIn
 
     ErrorF("Save TV timing tables\n");
 
-    RADEONSaveTimingTables(pScrn, save);
+    RADEONSaveTVTimingTables(pScrn, save);
 
     ErrorF("TV Save done\n");
 }
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index 2a9daf3..b700b1e 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -44,25 +44,16 @@ typedef struct
     CARD16 horSyncStart;
     CARD16 verSyncStart;
     unsigned defRestart;
-    CARD32 vScalerCntl1;
-    CARD32 yRiseCntl;
-    CARD32 ySawtoothCntl;
     CARD16 crtcPLL_N;
     CARD8  crtcPLL_M;
     Bool   crtcPLL_divBy2;
     CARD8  crtcPLL_byteClkDiv;
     CARD8  crtcPLL_postDiv;
-    Bool   use888RGB; /* False: RGB data is 565 packed (2 bytes/pixel) */
-                      /* True : RGB data is 888 packed (3 bytes/pixel) */
     unsigned pixToTV;
     CARD8  byteClkDelay;
-    CARD32 tvoDataDelayA;
-    CARD32 tvoDataDelayB;
-    const CARD16 *horTimingTable;
-    const CARD16 *verTimingTable;
 } TVModeConstants;
 
-static const CARD16 horTimingNTSC_BIOS[] =
+static const CARD16 hor_timing_NTSC[] =
 {
     0x0007,
     0x003f,
@@ -84,7 +75,7 @@ static const CARD16 horTimingNTSC_BIOS[]
     0
 };
 
-static const CARD16 verTimingNTSC_BIOS[] =
+static const CARD16 vert_timing_NTSC[] =
 {
     0x2001,
     0x200d,
@@ -102,7 +93,7 @@ static const CARD16 verTimingNTSC_BIOS[]
     0
 };
 
-static const CARD16 horTimingPAL_BIOS[] =
+static const CARD16 hor_timing_PAL[] =
 {
     0x0007,
     0x0058,
@@ -124,7 +115,7 @@ static const CARD16 horTimingPAL_BIOS[] 
     0
 };
 
-static const CARD16 verTimingPAL_BIOS[] =
+static const CARD16 vert_timing_PAL[] =
 {
     0x2001,
     0x200c,
@@ -163,21 +154,13 @@ static const TVModeConstants availableTV
 	824,                /* horSyncStart */
 	632,                /* verSyncStart */
 	625592,             /* defRestart */
-	0x0900b46b,         /* vScalerCntl1 */
-	0x00012c00,         /* yRiseCntl */
-	0x10002d1a,         /* ySawtoothCntl */
 	592,                /* crtcPLL_N */
 	91,                 /* crtcPLL_M */
 	TRUE,               /* crtcPLL_divBy2 */
 	0,                  /* crtcPLL_byteClkDiv */
 	4,                  /* crtcPLL_postDiv */
-	FALSE,              /* use888RGB */
 	1022,               /* pixToTV */
 	1,                  /* byteClkDelay */
-	0x0a0b0907,         /* tvoDataDelayA */
-	0x060a090a,         /* tvoDataDelayB */
-	horTimingNTSC_BIOS, /* horTimingTable */
-	verTimingNTSC_BIOS  /* verTimingTable */
     },
     { 
 	800,               /* horResolution */
@@ -189,26 +172,23 @@ static const TVModeConstants availableTV
 	824,               /* horSyncStart */
 	669,               /* verSyncStart */
 	696700,            /* defRestart */
-	0x09009097,        /* vScalerCntl1 */
-	0x000007da,        /* yRiseCntl */
-	0x10002426,        /* ySawtoothCntl */
 	1382,              /* crtcPLL_N */
 	231,               /* crtcPLL_M */
 	TRUE,              /* crtcPLL_divBy2 */
 	0,                 /* crtcPLL_byteClkDiv */
 	4,                 /* crtcPLL_postDiv */
-	FALSE,             /* use888RGB */
 	759,               /* pixToTV */
 	1,                 /* byteClkDelay */
-	0x0a0b0907,        /* tvoDataDelayA */
-	0x060a090a,        /* tvoDataDelayB */
-	horTimingPAL_BIOS, /* horTimingTable */
-	verTimingPAL_BIOS  /* verTimingTable */
     }
 };
 
 #define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ]))
 
+static long YCOEF_value[5] = { 2, 2, 0, 4, 0 };
+static long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 };
+static long SLOPE_value[5] = { 1, 2, 2, 4, 8 };
+static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 };
+
 
 /* Compute F,V,H restarts from default restart position and hPos & vPos
  * Return TRUE when code timing table was changed
@@ -241,13 +221,17 @@ static Bool RADEONInitTVRestarts(xf86Out
     else
 	fTotal = PAL_TV_VFTOTAL + 1;
 
-    /*
-     * Adjust positions 1&2 in hor. code timing table
-     */
+    /* Adjust positions 1&2 in hor. code timing table */
     hOffset = radeon_output->hPos * H_POS_UNIT;
 
-    p1 = constPtr->horTimingTable[ H_TABLE_POS1 ];
-    p2 = constPtr->horTimingTable[ H_TABLE_POS2 ];
+    if (radeon_output->tvStd == TV_STD_NTSC) {
+	p1 = hor_timing_NTSC[ H_TABLE_POS1 ];
+	p2 = hor_timing_NTSC[ H_TABLE_POS2 ];
+    } else {
+	p1 = hor_timing_PAL[ H_TABLE_POS1 ];
+	p2 = hor_timing_PAL[ H_TABLE_POS2 ];
+    }
+
 
     p1 = (CARD16)((int)p1 + hOffset);
     p2 = (CARD16)((int)p2 - hOffset);
@@ -311,8 +295,11 @@ void RADEONInitTVRegisters(xf86OutputPtr
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
     RADEONInfoPtr  info = RADEONPTR(pScrn);
     unsigned i;
+    unsigned long vert_space, flicker_removal;
     CARD32 tmp;
     const TVModeConstants *constPtr;
+    const CARD16 *hor_timing;
+    const CARD16 *vert_timing;
 
     constPtr = &availableTVModes[radeon_output->tvStd];
 
@@ -361,7 +348,8 @@ void RADEONInitTVRegisters(xf86OutputPtr
 				 | RADEON_CMP_BLU_EN
 				 | RADEON_DAC_DITHER_EN);
 
-    save->tv_rgb_cntl = 0x007b0004;
+    save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN | RADEON_TVOUT_SCALE_EN
+			 | (0x0b << 16) | (0x07 << 20));
 
     if (IsPrimary) {
 	if (radeon_output->Flags & RADEON_USE_RMX)
@@ -375,14 +363,59 @@ void RADEONInitTVRegisters(xf86OutputPtr
     save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE;
 
     save->tv_sync_size = constPtr->horResolution + 8;
-  
-    tmp = (constPtr->vScalerCntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
+
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME;
+    else
+	vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME;
+
+    save->tv_vscaler_cntl1 = RADEON_Y_W_EN;
+    save->tv_vscaler_cntl1 =
+	(save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000);
+    save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
+    if (constPtr->horResolution == 1024)
+	save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT);
+    else
+	save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT);
+
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	flicker_removal =
+	    (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5;
+    else
+	flicker_removal =
+	    (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5;
+
+    if (flicker_removal < 3)
+	flicker_removal = 3;
+    for (i = 0; i < 6; ++i) {
+	if (flicker_removal == SLOPE_limit[i])
+	    break;
+    }
+    save->tv_y_saw_tooth_cntl =
+	(vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8
+	| ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16);
+    save->tv_y_fall_cntl =
+	(YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) |
+	RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) /
+	1024;
+    save->tv_y_rise_cntl =
+	RADEON_Y_RISE_PING_PONG
+	| (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024;
+
+    save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0)
+			      | (0x10 << 24)
+			      | RADEON_DITHER_MODE 
+			      | RADEON_Y_OUTPUT_DITHER_EN
+			      | RADEON_UV_OUTPUT_DITHER_EN
+			      | RADEON_UV_TO_BUF_DITHER_EN);
+
+    tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
     tmp = ((16384 * 256 * 10) / tmp + 5) / 10;
     tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
     save->tv_timing_cntl = tmp;
 
+    /* XXX: taken care of in enabledisplay() */
     save->tv_dac_cntl = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD
-	                | RADEON_TV_MONITOR_DETECT_EN
 	                | (8 << 16) | (6 << 20);
 
     if (radeon_output->tvStd == TV_STD_NTSC)
@@ -390,15 +423,16 @@ void RADEONInitTVRegisters(xf86OutputPtr
     else
 	save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
 
-#if 0
+#if 1
+    /* XXX: taken care of in enabledisplay() */
     save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD
 	                 | RADEON_TV_DAC_BDACPD);
 
-    if (MonType == MT_CTV) {
+    if (radeon_output->MonType == MT_CTV) {
 	save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD;
     }
 
-    if (MonType == MT_STV) {
+    if (radeon_output->MonType == MT_STV) {
 	save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
 			       RADEON_TV_DAC_GDACPD);
     }
@@ -428,26 +462,23 @@ void RADEONInitTVRegisters(xf86OutputPtr
     else
 	save->tv_ftotal = PAL_TV_VFTOTAL;
 
-    save->tv_vscaler_cntl1 = constPtr->vScalerCntl1;
-    save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
-
-    save->tv_vscaler_cntl2 = 0x10000000;
-
     save->tv_vtotal = constPtr->verTotal - 1;
 
-    save->tv_y_fall_cntl = RADEON_Y_FALL_PING_PONG | RADEON_Y_COEF_EN;
-    save->tv_y_fall_cntl |= 0x80000400;
-
-    save->tv_y_rise_cntl = constPtr->yRiseCntl;
-    save->tv_y_saw_tooth_cntl = constPtr->ySawtoothCntl;
+    if (radeon_output->tvStd == TV_STD_NTSC) {
+	hor_timing = hor_timing_NTSC;
+	vert_timing = vert_timing_NTSC;
+    } else {
+	hor_timing = hor_timing_PAL;
+	vert_timing = vert_timing_PAL;
+    }
 
     for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
-	if ((save->h_code_timing[ i ] = constPtr->horTimingTable[ i ]) == 0)
+	if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0)
 	    break;
     }
 
     for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) {
-	if ((save->v_code_timing[ i ] = constPtr->verTimingTable[ i ]) == 0)
+	if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0)
 	    break;
     }
 
diff --git a/src/radeon_tv.h b/src/radeon_tv.h
index 829efba..5c8c8c9 100644
--- a/src/radeon_tv.h
+++ b/src/radeon_tv.h
@@ -49,3 +49,8 @@
 #define PAL_TV_LINES_PER_FRAME 625
 #define PAL_TV_ZERO_H_SIZE 473200
 #define PAL_TV_H_SIZE_UNIT 9360
+
+
+#define VERT_LEAD_IN_LINES 2
+#define FRAC_BITS 0xe
+#define FRAC_MASK 0x3fff
diff-tree cf54222f1fa37366b2c2b39c82f8afc02f32e63c (from 22d460d3ad991223aa1fbd7e5edeb45e36c65dc0)
Author: Alex Deucher <alex at botch2.com>
Date:   Tue Jul 31 02:01:49 2007 -0400

    RADEON: more fixes...

diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 20d43ff..7c5bef4 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -4409,14 +4409,14 @@ static void RADEONRestoreTVTimingTables(
     hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr);
     vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr);
 
-    /*    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
+    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
 				   | RADEON_CRT_ASYNC_RST
 				   | RADEON_RESTART_PHASE_FIX
 				   | RADEON_CRT_FIFO_CE_EN
 				   | RADEON_TV_FIFO_CE_EN
-				   | RADEON_TV_ON));*/
+				   | RADEON_TV_ON));
 
-    OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl | RADEON_TV_ON);
+    /*OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl | RADEON_TV_ON);*/
 
     for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) {
 	tmp = ((CARD32)restore->h_code_timing[ i ] << 14) | ((CARD32)restore->h_code_timing[ i + 1 ]);
@@ -4509,20 +4509,6 @@ static void RADEONRestoreTVOutputStd(Scr
     OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl);
 }
 
-/* Test if tv output would be enabled with a given value in TV_DAC_CNTL */
-static Bool RADEONTVIsOn(CARD32 tv_dac_cntl)
-{
-    /* XXX: Fixme for STV vs. CTV */
-    if (tv_dac_cntl & RADEON_TV_DAC_BGSLEEP)
-	return FALSE;
-    else if ((tv_dac_cntl &
-	      (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD | RADEON_TV_DAC_BDACPD)) ==
-	     (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD | RADEON_TV_DAC_BDACPD))
-	return FALSE;
-    else
-	return TRUE;
-}
-
 /* Restore TV out regs */
 void RADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
 {
@@ -4562,9 +4548,7 @@ void RADEONRestoreTVRegisters(ScrnInfoPt
   
     ErrorF("Restore Timing Tables\n");
 
-    /* Timing tables are only restored when tv output is active */
-    if (RADEONTVIsOn(restore->tv_dac_cntl))
-	RADEONRestoreTVTimingTables(pScrn, restore);
+    RADEONRestoreTVTimingTables(pScrn, restore);
   
 
     OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
@@ -5304,7 +5288,15 @@ static void RADEONSaveTVTimingTables(Scr
     /*
      * Reset FIFO arbiter in order to be able to access FIFO RAM
      */
-    OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);
+
+    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
+				   | RADEON_CRT_ASYNC_RST
+				   | RADEON_RESTART_PHASE_FIX
+				   | RADEON_CRT_FIFO_CE_EN
+				   | RADEON_TV_FIFO_CE_EN
+				   | RADEON_TV_ON));
+
+    /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/
 
     ErrorF("saveTimingTables: reading timing tables\n");
 
@@ -5364,14 +5356,10 @@ static void RADEONSaveTVRegisters(ScrnIn
     save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL);
 
     save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL);
-      
-    /*
-     * Read H/V code timing tables (current tables only are saved)
-     * This step is skipped when tv output is disabled in current RT state
-     * (see RADEONRestoreTVRegisters)
-     */
-    if (RADEONTVIsOn(save->tv_dac_cntl))
-	RADEONSaveTimingTables(pScrn, save);
+
+    ErrorF("Save TV timing tables\n");
+
+    RADEONSaveTimingTables(pScrn, save);
 
     ErrorF("TV Save done\n");
 }
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index a0e680b..2a9daf3 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -456,8 +456,6 @@ void RADEONInitTVRegisters(xf86OutputPtr
      */
     RADEONInitTVRestarts(output, save, mode);
 
-    /*save->hw_debug = 0x00000200;*/
-
     save->dac_cntl &= ~RADEON_DAC_TVO_EN;
 
     if (IS_R300_VARIANT)
diff-tree 22d460d3ad991223aa1fbd7e5edeb45e36c65dc0 (from 4822a2b837334f408f962646ab5ea4f8b0335ac9)
Author: Alex Deucher <alex at botch2.com>
Date:   Tue Jul 31 01:28:05 2007 -0400

    RADEON: fix name of tv output

diff --git a/src/radeon_output.c b/src/radeon_output.c
index 9c11bf6..2790ddf 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -1297,9 +1297,9 @@ void RADEONSetOutputType(ScrnInfoPtr pSc
 	case CONNECTOR_DVI_D:
 	    output = OUTPUT_DVI; break;
 	case CONNECTOR_CTV:
-	    output = OUTPUT_STV; break;
-	case CONNECTOR_STV:
 	    output = OUTPUT_CTV; break;
+	case CONNECTOR_STV:
+	    output = OUTPUT_STV; break;
 	case CONNECTOR_NONE:
 	case CONNECTOR_UNSUPPORTED:
 	default:
diff-tree 4822a2b837334f408f962646ab5ea4f8b0335ac9 (from fe494c9db2995bb8ce7a028ecf9626e0cb0cf506)
Author: Alex Deucher <alex at botch2.com>
Date:   Tue Jul 31 01:18:40 2007 -0400

    RADEON: tv-out fixes.  works now.  tested on rv350.
    
    VT siwtch is busted, and xrandr doesn't play nice yet.
    uncomment code in radeon_output.c to test.

diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 74711ce..20d43ff 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -4298,7 +4298,7 @@ static void RADEONWriteTVFIFO(ScrnInfoPt
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     unsigned char *RADEONMMIO = info->MMIO;
     CARD32 tmp;
-
+    int i = 0;
 
     OUTREG(RADEON_TV_HOST_WRITE_DATA, value);
 
@@ -4307,26 +4307,35 @@ static void RADEONWriteTVFIFO(ScrnInfoPt
 
     do {
 	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
+	if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0)
+	    break;
+	i++;
     }
-    while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);
+    while (i < 100000);
+    /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/
 
     OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
 }
 
-/* Read from RT FIFO RAM */
+/* Read from TV FIFO RAM */
 static CARD32 RADEONReadTVFIFO(ScrnInfoPtr pScrn, CARD16 addr)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     unsigned char *RADEONMMIO = info->MMIO;
     CARD32 tmp;
+    int i = 0;
   
     OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
     OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD);
 
     do {
 	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
-    } 
-    while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);
+	if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0)
+	    break;
+	i++;
+    }
+    while (i < 100000);
+    /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/
 
     OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
 
@@ -4400,12 +4409,14 @@ static void RADEONRestoreTVTimingTables(
     hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr);
     vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr);
 
-    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
+    /*    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
 				   | RADEON_CRT_ASYNC_RST
 				   | RADEON_RESTART_PHASE_FIX
 				   | RADEON_CRT_FIFO_CE_EN
 				   | RADEON_TV_FIFO_CE_EN
-				   | RADEON_TV_ON));
+				   | RADEON_TV_ON));*/
+
+    OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl | RADEON_TV_ON);
 
     for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) {
 	tmp = ((CARD32)restore->h_code_timing[ i ] << 14) | ((CARD32)restore->h_code_timing[ i + 1 ]);
@@ -4416,7 +4427,7 @@ static void RADEONRestoreTVTimingTables(
 
     for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) {
 	tmp = ((CARD32)restore->v_code_timing[ i + 1 ] << 14) | ((CARD32)restore->v_code_timing[ i ]);
-	RADEONWriteFIFO(pScrn, vTable, tmp);
+	RADEONWriteTVFIFO(pScrn, vTable, tmp);
 	if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0)
 	    break;
     }
@@ -4553,7 +4564,7 @@ void RADEONRestoreTVRegisters(ScrnInfoPt
 
     /* Timing tables are only restored when tv output is active */
     if (RADEONTVIsOn(restore->tv_dac_cntl))
-	RADEONRestoreTimingTables(pScrn, restore);
+	RADEONRestoreTVTimingTables(pScrn, restore);
   
 
     OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
diff --git a/src/radeon_output.c b/src/radeon_output.c
index d0a12dd..9c11bf6 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -1025,9 +1025,16 @@ radeon_detect(xf86OutputPtr output)
     ScrnInfoPtr	    pScrn = output->scrn;
     RADEONInfoPtr info = RADEONPTR(pScrn);
     RADEONOutputPrivatePtr radeon_output = output->driver_private;
-    
-    radeon_output->MonType = MT_UNKNOWN;
-    RADEONConnectorFindMonitor(pScrn, output);
+
+    /* assume tv is connected for now */
+    if (radeon_output->type == OUTPUT_STV) {
+	radeon_output->MonType = MT_STV;
+    } else if (radeon_output->type == OUTPUT_CTV) {
+	radeon_output->MonType = MT_CTV;
+    } else {
+	radeon_output->MonType = MT_UNKNOWN;
+	RADEONConnectorFindMonitor(pScrn, output);
+    }
 
     /* force montype based on output property */
     if (radeon_output->type == OUTPUT_DVI) {
@@ -1888,6 +1895,45 @@ Bool RADEONSetupConnectors(ScrnInfoPtr p
 	    }
 	}
     }
+
+    /* add TV out */
+#if 0
+    if (info->InternalTVOut) {
+	/* need to check the bios tables to see if we really have tv out and what type we have */
+	RADEONOutputPrivatePtr radeon_output = xnfcalloc(sizeof(RADEONOutputPrivateRec), 1);
+	if (!radeon_output) {
+	    return FALSE;
+	}
+	/* hard code type for now */
+	radeon_output->MonType = MT_STV;
+	radeon_output->DDCType = DDC_NONE_DETECTED;
+	radeon_output->DACType = DAC_TVDAC;
+	radeon_output->TMDSType = TMDS_NONE;
+
+	/* hard code type for now */
+	if (info->IsAtomBios)
+	    radeon_output->ConnectorType = CONNECTOR_STV_ATOM;
+	else
+	    radeon_output->ConnectorType = CONNECTOR_STV;
+
+	radeon_output->tvStd = TV_STD_NTSC;
+	radeon_output->hPos = 0;
+	radeon_output->vPos = 0;
+	radeon_output->hSize = 0;
+
+	RADEONSetOutputType(pScrn, radeon_output);
+	output = xf86OutputCreate(pScrn, &radeon_output_funcs, OutputType[radeon_output->type]);
+	if (!output) {
+	    return FALSE;
+	}
+	output->driver_private = radeon_output;
+	output->possible_crtcs = 1 | 2;
+	output->possible_clones = 0;
+
+	RADEONInitConnector(output);
+    }
+#endif
+
     return TRUE;
 }
 
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index 5acc4ff..a0e680b 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -333,7 +333,8 @@ void RADEONInitTVRegisters(xf86OutputPtr
 			    | RADEON_AUD_ASYNC_RST
 			    | RADEON_DVS_ASYNC_RST
 			    | RADEON_CRT_FIFO_CE_EN
-			    | RADEON_TV_FIFO_CE_EN);
+			    | RADEON_TV_FIFO_CE_EN
+			    | RADEON_TV_ON);
 
     save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT
 	                       | RADEON_SYNC_TIP_LEVEL
diff-tree fe494c9db2995bb8ce7a028ecf9626e0cb0cf506 (from 6b9b7a7bdc290d07de9b226691ec8025af8db896)
Author: Alex Deucher <alex at botch2.com>
Date:   Sun Jul 29 15:26:34 2007 -0400

    RADEON: add info about tv out code and authorship

diff --git a/src/radeon_tv.c b/src/radeon_tv.c
index 1d0b2c6..5acc4ff 100644
--- a/src/radeon_tv.c
+++ b/src/radeon_tv.c
@@ -1,3 +1,7 @@
+/*
+ * Integrated TV out support based on the GATOS code by
+ * Federico Ulivi <fulivi at lycos.com>
+ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
diff --git a/src/radeon_tv.h b/src/radeon_tv.h
index 179b87b..829efba 100644
--- a/src/radeon_tv.h
+++ b/src/radeon_tv.h
@@ -1,4 +1,9 @@
 /*
+ * Integrated TV out support based on the GATOS code by
+ * Federico Ulivi <fulivi at lycos.com>
+ */
+
+/*
  * Maximum length of horizontal/vertical code timing tables for state storage
  */
 #define MAX_H_CODE_TIMING_LEN 32
diff-tree 6b9b7a7bdc290d07de9b226691ec8025af8db896 (from 8d043db1817d94edeb72ab208dfea60026715d48)
Author: Alex Deucher <alex at botch2.com>
Date:   Sun Jul 29 15:23:14 2007 -0400

    RADEON: Initial pass at integrated tv out support
    
    Based on the GATOS tv-out support by Federico Ulivi <fulivi at lycos.com>
    and information from ati with substantial rework by myself.
    
    Code is not actually hooked up yet.

diff --git a/src/Makefile.am b/src/Makefile.am
index 24665a4..709b98c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,7 +80,7 @@ radeon_drv_la_SOURCES = \
 	radeon_accel.c radeon_cursor.c radeon_dga.c \
 	radeon_driver.c radeon_video.c radeon_bios.c radeon_mm_i2c.c \
 	radeon_vip.c radeon_misc.c radeon_probe.c radeon_display.c \
-	radeon_crtc.c radeon_output.c radeon_modes.c \
+	radeon_crtc.c radeon_output.c radeon_modes.c radeon_tv.c \
 	$(RADEON_DRI_SRCS) $(RADEON_EXA_SOURCES)
 
 theatre_detect_drv_la_LTLIBRARIES = theatre_detect_drv.la
@@ -181,6 +181,7 @@ EXTRA_DIST = \
 	radeon_sarea.h \
 	radeon_version.h \
 	radeon_video.h \
+	radeon_tv.h \
 	theatre200.h \
 	theatre_detect.h \
 	theatre.h \
diff --git a/src/radeon.h b/src/radeon.h
index 96c4632..7792f31 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -65,6 +65,8 @@
 #include "xf86xv.h"
 
 #include "radeon_probe.h"
+#include "radeon_tv.h"
+
 				/* DRI support */
 #ifdef XF86DRI
 #define _XF86DRI_SERVER_
@@ -300,12 +302,54 @@ typedef struct {
     CARD32            palette[256];
     CARD32            palette2[256];
 
-    CARD32            tv_dac_cntl;
-
     CARD32            rs480_unk_e30;
     CARD32            rs480_unk_e34;
     CARD32            rs480_unk_e38;
     CARD32            rs480_unk_e3c;
+
+    /* TV out registers */
+    CARD32 	      tv_master_cntl;
+    CARD32 	      tv_htotal;
+    CARD32 	      tv_hsize;
+    CARD32 	      tv_hdisp;
+    CARD32 	      tv_hstart;
+    CARD32 	      tv_vtotal;
+    CARD32 	      tv_vdisp;
+    CARD32 	      tv_timing_cntl;
+    CARD32 	      tv_vscaler_cntl1;
+    CARD32 	      tv_vscaler_cntl2;
+    CARD32 	      tv_sync_size;
+    CARD32 	      tv_vrestart;
+    CARD32 	      tv_hrestart;
+    CARD32 	      tv_frestart;
+    CARD32 	      tv_ftotal;
+    CARD32 	      tv_clock_sel_cntl;
+    CARD32 	      tv_clkout_cntl;
+    CARD32 	      tv_data_delay_a;
+    CARD32 	      tv_data_delay_b;
+    CARD32 	      tv_dac_cntl;
+    CARD32 	      tv_pll_cntl;
+    CARD32	      tv_pll_fine_cntl;
+    CARD32 	      tv_modulator_cntl1;
+    CARD32 	      tv_modulator_cntl2;
+    CARD32 	      tv_frame_lock_cntl;
+    CARD32 	      tv_pre_dac_mux_cntl;
+    CARD32 	      tv_rgb_cntl;
+    CARD32 	      tv_y_saw_tooth_cntl;
+    CARD32 	      tv_y_rise_cntl;
+    CARD32 	      tv_y_fall_cntl;
+    CARD32 	      tv_uv_adr;
+    CARD32	      tv_upsamp_and_gain_cntl;
+    CARD32	      tv_gain_limit_settings;
+    CARD32	      tv_linear_gain_settings;
+    CARD32	      tv_crc_cntl;
+    CARD32            tv_sync_cntl;
+    CARD32	      gpiopad_a;
+    CARD32            pll_test_cntl;
+
+    CARD16	      h_code_timing[MAX_H_CODE_TIMING_LEN];
+    CARD16	      v_code_timing[MAX_V_CODE_TIMING_LEN];
+
 } RADEONSaveRec, *RADEONSavePtr;
 
 typedef struct {
@@ -752,6 +796,8 @@ typedef struct {
     Bool              crtc_on;
     Bool              crtc2_on;
 
+    Bool              InternalTVOut;
+
     Rotation rotation;
     void (*PointerMoved)(int, int, int);
     CreateScreenResourcesProcPtr CreateScreenResources;
@@ -903,6 +949,17 @@ RADEONEnableOutputs(ScrnInfoPtr pScrn, i
 void
 RADEONChooseOverlayCRTC(ScrnInfoPtr pScrn, BoxPtr dstBox);
 
+extern void RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+					   DisplayModePtr mode, xf86OutputPtr output);
+extern void RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+					  DisplayModePtr mode, xf86OutputPtr output);
+extern void RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+					   DisplayModePtr mode, xf86OutputPtr output);
+extern void RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+					  DisplayModePtr mode, xf86OutputPtr output);
+extern void RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save,
+                                  DisplayModePtr mode, BOOL IsPrimary);
+
 #ifdef XF86DRI
 #ifdef USE_XAA
 extern void        RADEONAccelInitCP(ScreenPtr pScreen, XAAInfoRecPtr a);
diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c
index 3518c9c..cbb50d8 100644
--- a/src/radeon_crtc.c
+++ b/src/radeon_crtc.c
@@ -753,6 +753,8 @@ radeon_crtc_mode_set(xf86CrtcPtr crtc, D
     ScrnInfoPtr pScrn = crtc->scrn;
     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private;
+    xf86OutputPtr output;
+    RADEONOutputPrivatePtr radeon_output;
     RADEONInfoPtr info = RADEONPTR(pScrn);
     RADEONMonitorType montype = MT_NONE;
     Bool           tilingOld   = info->tilingEnabled;
@@ -775,8 +777,8 @@ radeon_crtc_mode_set(xf86CrtcPtr crtc, D
     }
 
     for (i = 0; i < xf86_config->num_output; i++) {
-	xf86OutputPtr output = xf86_config->output[i];
-	RADEONOutputPrivatePtr radeon_output = output->driver_private;
+	output = xf86_config->output[i];
+	radeon_output = output->driver_private;
 
 	if (output->crtc == crtc) {
 	    montype = radeon_output->MonType;
@@ -816,7 +818,20 @@ radeon_crtc_mode_set(xf86CrtcPtr crtc, D
         }
 	break;
     }
-    
+
+    if (montype == MT_STV || montype == MT_CTV) {
+	switch (radeon_crtc->crtc_id) {
+	case 0:
+	    RADEONAdjustCrtcRegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output);
+	    RADEONAdjustPLLRegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output);
+	    break;
+	case 1:
+	    RADEONAdjustCrtc2RegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output);
+	    RADEONAdjustPLL2RegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output);
+	    break;
+	}
+    }
+
     ErrorF("restore memmap\n");
     RADEONRestoreMemMapRegisters(pScrn, &info->ModeReg);
     ErrorF("restore common\n");
@@ -837,6 +852,10 @@ radeon_crtc_mode_set(xf86CrtcPtr crtc, D
 	break;
     }
 
+    /* pixclks_cntl handles tv-out clock routing */
+    if (montype == MT_STV || montype == MT_CTV)
+	RADEONRestorePLL2Registers(pScrn, &info->ModeReg);
+
     if (info->DispPriority)
         RADEONInitDispBandwidth(pScrn);
 
diff --git a/src/radeon_display.c b/src/radeon_display.c
index 79fb352..059dfca 100644
--- a/src/radeon_display.c
+++ b/src/radeon_display.c
@@ -360,12 +360,27 @@ void RADEONEnableDisplay(xf86OutputPtr o
             OUTREG(RADEON_LVDS_GEN_CNTL, tmp);
             save->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON);
             save->lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
-        } 
+        } else if (radeon_output->MonType == MT_STV ||
+		   radeon_output->MonType == MT_CTV) {
+#if 0
+	    /* TV_MASTER_CNTL ??? */
+
+	    /* XXX: FIXME: STV vs CTV and DACPD bits */
+	    tmp = INREG(RADEON_TV_DAC_CNTL);
+	    tmp |= (TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
+	    tmp &= ~(TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD
+		     | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+	    OUTREG(RADEON_TV_DAC_CNTL, tmp);
+	    save->tv_dac_cntl |= (TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
+	    save->tv_dac_cntl &= ~(TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD
+				   | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+#endif
+	}
     } else {
         if (radeon_output->MonType == MT_CRT || radeon_output->MonType == NONE) {
             if (radeon_output->DACType == DAC_PRIMARY) {
                 tmp = INREG(RADEON_CRTC_EXT_CNTL);
-                tmp &= ~RADEON_CRTC_CRT_ON;                    
+                tmp &= ~RADEON_CRTC_CRT_ON;       
                 OUTREG(RADEON_CRTC_EXT_CNTL, tmp);
                 save->crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON;
             } else if (radeon_output->DACType == DAC_TVDAC) {
@@ -417,6 +432,20 @@ void RADEONEnableDisplay(xf86OutputPtr o
 		OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmpPixclksCntl);
 	    }
         }
+
+	if (radeon_output->MonType == MT_STV ||
+	    radeon_output->MonType == MT_CTV) {
+
+	    /* TV_MASTER_CNTL ??? */
+#if 0
+	    tmp = INREG(RADEON_TV_DAC_CNTL);
+	    tmp &= ~(TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
+	    tmp |= (TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+	    OUTREG(RADEON_TV_DAC_CNTL, tmp);
+	    save->tv_dac_cntl &= ~(TV_DAC_CNTL_NBLANK | TV_DAC_CNTL_NHOLD);
+	    save->tv_dac_cntl |= (TV_DAC_CNTL_BGSLEEP | TV_DAC_CNTL_RDACPD | TV_DAC_CNTL_GDACPD | TV_DAC_CNTL_BDACPD);
+#endif
+	}
     }
 }
 
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index e9a0954..74711ce 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -128,9 +128,9 @@ static void RADEONAdjustMemMapRegisters(
 
 DisplayModePtr
 RADEONCrtcFindClosestMode(xf86CrtcPtr crtc, DisplayModePtr pMode);
-/* psuedo xinerama support */
 
-extern Bool 		RADEONnoPanoramiXExtension;
+static void RADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests,
+                              unsigned nWaitLoops, unsigned cntThreshold);
 
 static const OptionInfoRec RADEONOptions[] = {
     { OPTION_NOACCEL,        "NoAccel",          OPTV_BOOLEAN, {0}, FALSE },
@@ -1497,6 +1497,7 @@ static Bool RADEONPreInitChipType(ScrnIn
     info->IsIGP = FALSE;
     info->IsDellServer = FALSE;
     info->HasSingleDAC = FALSE;
+    info->InternalTVOut = TRUE;
     switch (info->Chipset) {
     case PCI_CHIP_RADEON_LY:
     case PCI_CHIP_RADEON_LZ:
@@ -1556,6 +1557,7 @@ static Bool RADEONPreInitChipType(ScrnIn
     case PCI_CHIP_R200_QL:
     case PCI_CHIP_R200_QM:
 	info->ChipFamily = CHIP_FAMILY_R200;
+	info->InternalTVOut = FALSE;
 	break;
 
     case PCI_CHIP_RADEON_LW:
@@ -1738,6 +1740,7 @@ static Bool RADEONPreInitChipType(ScrnIn
 	/* Original Radeon/7200 */
 	info->ChipFamily = CHIP_FAMILY_RADEON;
 	pRADEONEnt->HasCRTC2 = FALSE;
+	info->InternalTVOut = FALSE;
     }
 
 
@@ -4101,6 +4104,9 @@ void RADEONRestoreDACRegisters(ScrnInfoP
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     unsigned char *RADEONMMIO = info->MMIO;
 
+    if (IS_R300_VARIANT)
+	OUTREGP(RADEON_GPIOPAD_A, restore->gpiopad_a, ~1);
+
     OUTREGP(RADEON_DAC_CNTL,
 	    restore->dac_cntl,
 	    RADEON_DAC_RANGE_CNTL |
@@ -4108,14 +4114,14 @@ void RADEONRestoreDACRegisters(ScrnInfoP
 
     OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl);
 
-    //OUTREG(RADEON_TV_DAC_CNTL, 0x00280203);
     if ((info->ChipFamily != CHIP_FAMILY_RADEON) &&
     	(info->ChipFamily != CHIP_FAMILY_R200)) 
     OUTREG (RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
 
+    OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl);
+
     if ((info->ChipFamily == CHIP_FAMILY_R200) ||
 	IS_R300_VARIANT) {
-	OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl);
 	OUTREG(RADEON_DISP_TV_OUT_CNTL, restore->disp_tv_out_cntl);
     } else {
 	OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug);
@@ -4273,7 +4279,6 @@ void RADEONRestoreRMXRegisters(ScrnInfoP
 void RADEONRestoreLVDSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
-    RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
     unsigned char *RADEONMMIO = info->MMIO;
 
     if (info->IsMobility) {
@@ -4286,6 +4291,291 @@ void RADEONRestoreLVDSRegisters(ScrnInfo
 
 }
 
+/* Write to TV FIFO RAM */
+static void RADEONWriteTVFIFO(ScrnInfoPtr pScrn, CARD16 addr,
+			      CARD32 value)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    CARD32 tmp;
+
+
+    OUTREG(RADEON_TV_HOST_WRITE_DATA, value);
+
+    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
+    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT);
+
+    do {
+	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
+    }
+    while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);
+
+    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
+}
+
+/* Read from RT FIFO RAM */
+static CARD32 RADEONReadTVFIFO(ScrnInfoPtr pScrn, CARD16 addr)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    CARD32 tmp;
+  
+    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr);
+    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD);
+
+    do {
+	tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL);
+    } 
+    while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);
+
+    OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0);
+
+    return INREG(RADEON_TV_HOST_READ_DATA);
+}
+
+/* Get FIFO addresses of horizontal & vertical code timing tables from
+ * settings of uv_adr register. 
+ */
+static CARD16 RADEONGetHTimingTablesAddr(CARD32 tv_uv_adr)
+{
+    CARD16 hTable;
+
+    switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) {
+    case 0:
+	hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL;
+	break;
+
+    case 1:
+	hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2;
+	break;
+
+    case 2:
+	hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2;
+	break;
+
+    default:
+	/* Of course, this should never happen */
+	hTable = 0;
+	break;
+    }
+    return hTable;
+}
+
+static CARD16 RADEONGetVTimingTablesAddr(CARD32 tv_uv_adr)
+{
+    CARD16 vTable;
+
+    switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) {
+    case 0:
+	vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1;
+	break;
+
+    case 1:
+	vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1;
+	break;
+
+    case 2:
+	vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1;
+	break;
+
+    default:
+	/* Of course, this should never happen */
+	vTable = 0;
+	break;
+    }
+    return vTable;
+}
+
+/* Restore horizontal/vertical timing code tables */
+static void RADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    CARD16 hTable;
+    CARD16 vTable;
+    CARD32 tmp;
+    unsigned i;
+
+    OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr);
+    hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr);
+    vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr);
+
+    OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST
+				   | RADEON_CRT_ASYNC_RST
+				   | RADEON_RESTART_PHASE_FIX
+				   | RADEON_CRT_FIFO_CE_EN
+				   | RADEON_TV_FIFO_CE_EN
+				   | RADEON_TV_ON));
+
+    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) {
+	tmp = ((CARD32)restore->h_code_timing[ i ] << 14) | ((CARD32)restore->h_code_timing[ i + 1 ]);
+	RADEONWriteTVFIFO(pScrn, hTable, tmp);
+	if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0)
+	    break;
+    }
+
+    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) {
+	tmp = ((CARD32)restore->v_code_timing[ i + 1 ] << 14) | ((CARD32)restore->v_code_timing[ i ]);
+	RADEONWriteFIFO(pScrn, vTable, tmp);
+	if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0)
+	    break;
+    }
+}
+
+/* restore TV PLLs */
+static void RADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
+{
+
+    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL);
+    OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl);
+    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET);
+
+    RADEONWaitPLLLock(pScrn, 200, 800, 135);
+  
+    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET);
+
+    RADEONWaitPLLLock(pScrn, 300, 160, 27);
+    RADEONWaitPLLLock(pScrn, 200, 800, 135);
+  
+    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf);
+    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL);
+  
+    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK);
+    OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP);
+}
+
+/* Restore TV horizontal/vertical settings */
+static void RADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+
+    OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl);
+
+    OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal);
+    OUTREG(RADEON_TV_HDISP, restore->tv_hdisp);
+    OUTREG(RADEON_TV_HSTART, restore->tv_hstart);
+
+    OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal);
+    OUTREG(RADEON_TV_VDISP, restore->tv_vdisp);
+
+    OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal);
+
+    OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1);
+    OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2);
+
+    OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl);
+    OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl);
+    OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl);
+}
+
+/* restore TV RESTART registers */
+static void RADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+
+    OUTREG(RADEON_TV_FRESTART, restore->tv_frestart);
+    OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart);
+    OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart);
+}
+
+/* restore tv standard & output muxes */
+static void RADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+
+    OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl);
+  
+    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
+
+    OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1);
+    OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2);
+ 
+    OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl);
+
+    OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl);
+}
+
+/* Test if tv output would be enabled with a given value in TV_DAC_CNTL */
+static Bool RADEONTVIsOn(CARD32 tv_dac_cntl)
+{
+    /* XXX: Fixme for STV vs. CTV */
+    if (tv_dac_cntl & RADEON_TV_DAC_BGSLEEP)
+	return FALSE;
+    else if ((tv_dac_cntl &
+	      (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD | RADEON_TV_DAC_BDACPD)) ==
+	     (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD | RADEON_TV_DAC_BDACPD))
+	return FALSE;
+    else
+	return TRUE;
+}
+
+/* Restore TV out regs */
+void RADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+
+    ErrorF("Entering Restore TV\n");
+
+    OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl | RADEON_TV_ON);
+
+    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
+				   | RADEON_TV_ASYNC_RST
+				   | RADEON_CRT_ASYNC_RST
+				   | RADEON_RESTART_PHASE_FIX
+				   | RADEON_TV_FIFO_ASYNC_RST));
+
+    /* Temporarily turn the TV DAC off */
+    OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK)
+				| RADEON_TV_DAC_BGSLEEP
+				| RADEON_TV_DAC_RDACPD
+				| RADEON_TV_DAC_GDACPD
+				| RADEON_TV_DAC_BDACPD));
+
+    ErrorF("Restore TV PLL\n");
+    RADEONRestoreTVPLLRegisters(pScrn, restore);
+
+    ErrorF("Restore TVHV\n");
+    RADEONRestoreTVHVRegisters(pScrn, restore);
+
+    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
+				   | RADEON_TV_ASYNC_RST
+				   | RADEON_CRT_ASYNC_RST
+				   | RADEON_RESTART_PHASE_FIX));
+
+    ErrorF("Restore TV Restarts\n");
+    RADEONRestoreTVRestarts(pScrn, restore);
+  
+    ErrorF("Restore Timing Tables\n");
+
+    /* Timing tables are only restored when tv output is active */
+    if (RADEONTVIsOn(restore->tv_dac_cntl))
+	RADEONRestoreTimingTables(pScrn, restore);
+  
+
+    OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl
+				   | RADEON_TV_ASYNC_RST
+				   | RADEON_RESTART_PHASE_FIX));
+
+    ErrorF("Restore TV standard\n");
+    RADEONRestoreTVOutputStd(pScrn, restore);
+
+    OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
+
+    /*OUTREG(RADEON_DISP_MERGE_CNTL, restore->disp_merge_cntl);*/
+
+    OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings);
+    OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings);
+
+    /* XXX: taken care of in EnableDisplay() */
+    OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl);
+
+    ErrorF("Leaving Restore TV\n");
+}
+
 static void RADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn)
 {
     int i = 0;
@@ -4360,6 +4650,39 @@ static CARD8 RADEONComputePLLGain(CARD16
         return 1;
 }
 
+/* Wait for PLLs to lock */
+static void RADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests,
+			      unsigned nWaitLoops, unsigned cntThreshold)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    CARD32 savePLLTest;
+    unsigned i;
+    unsigned j;
+
+    OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100);
+
+    savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL);
+
+    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B);
+
+    /* XXX: these should probably be OUTPLL to avoid various PLL errata */
+
+    OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL);
+
+    for (i = 0; i < nTests; i++) {
+	OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0);
+      
+	for (j = 0; j < nWaitLoops; j++)
+	    if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold)
+		break;
+    }
+
+    OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest);
+
+    OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff);
+}
+
 /* Write PLL registers */
 void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
 			       RADEONSavePtr restore)
@@ -4733,6 +5056,7 @@ void RADEONChangeSurfaces(ScrnInfoPtr pS
 /* Write out state to define a new video mode */
 void RADEONRestoreMode(ScrnInfoPtr pScrn, RADEONSavePtr restore)
 {
+    RADEONInfoPtr  info     = RADEONPTR(pScrn);
     RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
 
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
@@ -4765,6 +5089,8 @@ void RADEONRestoreMode(ScrnInfoPtr pScrn
     RADEONRestoreFP2Registers(pScrn, restore);
     RADEONRestoreLVDSRegisters(pScrn, restore);
     RADEONRestoreDACRegisters(pScrn, restore);
+    if (info->InternalTVOut)
+	RADEONRestoreTVRegisters(pScrn, restore);
 
 #if 0
     RADEONRestorePalette(pScrn, &info->SavedReg);
@@ -4884,6 +5210,8 @@ static void RADEONSaveDACRegisters(ScrnI
     save->disp_tv_out_cntl      = INREG(RADEON_DISP_TV_OUT_CNTL);
     save->disp_hw_debug         = INREG(RADEON_DISP_HW_DEBUG);
     save->dac_macro_cntl        = INREG(RADEON_DAC_MACRO_CNTL);
+    save->gpiopad_a             = INREG(RADEON_GPIOPAD_A);
+
 }
 
 /* Read flat panel registers */
@@ -4948,6 +5276,95 @@ static void RADEONSaveCrtc2Registers(Scr
 
 }
 
+/* Save horizontal/vertical timing code tables */
+static void RADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    CARD16 hTable;
+    CARD16 vTable;
+    CARD32 tmp;
+    unsigned i;
+
+    save->tv_uv_adr = INREG(RADEON_TV_UV_ADR);
+    hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr);
+    vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr);
+
+    /*
+     * Reset FIFO arbiter in order to be able to access FIFO RAM
+     */
+    OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);
+
+    ErrorF("saveTimingTables: reading timing tables\n");
+
+    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) {
+	tmp = RADEONReadTVFIFO(pScrn, hTable--);
+	save->h_code_timing[ i     ] = (CARD16)((tmp >> 14) & 0x3fff);
+	save->h_code_timing[ i + 1 ] = (CARD16)(tmp & 0x3fff);
+
+	if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0)
+	    break;
+    }
+
+    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) {
+	tmp = RADEONReadTVFIFO(pScrn, vTable++);
+	save->v_code_timing[ i     ] = (CARD16)(tmp & 0x3fff);
+	save->v_code_timing[ i + 1 ] = (CARD16)((tmp >> 14) & 0x3fff);
+
+	if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0)
+	    break;
+    }
+}
+
+/* read TV regs */
+static void RADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
+{
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    unsigned i;
+
+    ErrorF("Entering TV Save\n");
+
+    save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL);
+    save->tv_frestart = INREG(RADEON_TV_FRESTART);
+    save->tv_hrestart = INREG(RADEON_TV_HRESTART);
+    save->tv_vrestart = INREG(RADEON_TV_VRESTART);
+    save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS);
+    save->tv_hdisp = INREG(RADEON_TV_HDISP);
+    save->tv_hstart = INREG(RADEON_TV_HSTART);
+    save->tv_htotal = INREG(RADEON_TV_HTOTAL);
+    save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS);
+    save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL);
+    save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL);
+    save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1);
+    save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2);
+    save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL);
+    save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL);
+    save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL);
+    save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL);
+    save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL);
+    save->tv_vdisp = INREG(RADEON_TV_VDISP);
+    save->tv_ftotal = INREG(RADEON_TV_FTOTAL);
+    save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1);
+    save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2);
+    save->tv_vtotal = INREG(RADEON_TV_VTOTAL);
+    save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL);
+    save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL);
+    save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL);
+
+    save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL);
+      
+    /*
+     * Read H/V code timing tables (current tables only are saved)
+     * This step is skipped when tv output is disabled in current RT state
+     * (see RADEONRestoreTVRegisters)
+     */
+    if (RADEONTVIsOn(save->tv_dac_cntl))
+	RADEONSaveTimingTables(pScrn, save);
+
+    ErrorF("TV Save done\n");
+}
+
 /* Read PLL registers */
 static void RADEONSavePLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
 {
@@ -5016,12 +5433,13 @@ static void RADEONSaveMode(ScrnInfoPtr p
 
     RADEONSaveMemMapRegisters(pScrn, save);
     RADEONSaveCommonRegisters(pScrn, save);
-    RADEONSavePLLRegisters (pScrn, save);
-    RADEONSaveCrtcRegisters (pScrn, save);
-    RADEONSaveFPRegisters (pScrn, save);
-    RADEONSaveDACRegisters (pScrn, save);
-    RADEONSaveCrtc2Registers (pScrn, save);
-    RADEONSavePLL2Registers (pScrn, save);
+    RADEONSavePLLRegisters(pScrn, save);
+    RADEONSaveCrtcRegisters(pScrn, save);
+    RADEONSaveFPRegisters(pScrn, save);
+    RADEONSaveDACRegisters(pScrn, save);
+    RADEONSaveCrtc2Registers(pScrn, save);
+    RADEONSavePLL2Registers(pScrn, save);
+    RADEONSaveTVRegisters(pScrn, save);
     /*RADEONSavePalette(pScrn, save);*/
 
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
diff --git a/src/radeon_modes.c b/src/radeon_modes.c
index 66d8a7f..a5e1cc4 100644
--- a/src/radeon_modes.c
+++ b/src/radeon_modes.c
@@ -78,6 +78,17 @@ void RADEONSetPitch (ScrnInfoPtr pScrn)
 
 }
 
+static DisplayModePtr RADEONTVModes(xf86OutputPtr output)
+{
+    DisplayModePtr new  = NULL;
+
+    /* just a place holder */    
+    new = xf86CVTMode(800, 600, 60.00, FALSE, FALSE);
+    new->type = M_T_DRIVER | M_T_PREFERRED;
+
+    return new;
+}
+
 /* This is used only when no mode is specified for FP and no ddc is
  * available.  We force it to native mode, if possible.
  */
@@ -286,6 +297,10 @@ RADEONProbeOutputModes(xf86OutputPtr out
 	modes = xf86OutputGetEDIDModes (output);
 	return modes;
     }
+    if (radeon_output->type == OUTPUT_STV || radeon_output->type == OUTPUT_CTV) {
+	modes = RADEONTVModes(output);
+	return modes;
+    }
     if (radeon_output->type == OUTPUT_LVDS) {
 	/* okay we got DDC info */
 	if (output->MonInfo) {
diff --git a/src/radeon_output.c b/src/radeon_output.c
index e431bf5..d0a12dd 100644
--- a/src/radeon_output.c
+++ b/src/radeon_output.c
@@ -46,6 +46,7 @@
 #include "radeon_macros.h"
 #include "radeon_probe.h"
 #include "radeon_version.h"
+#include "radeon_tv.h"
 
 
 const char *MonTypeName[7] = {
@@ -890,7 +891,7 @@ RADEONInitTvDacCntl(ScrnInfoPtr pScrn, R
     save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
 			 RADEON_TV_DAC_NHOLD |
 			  RADEON_TV_DAC_STD_PS2);
-			  //			 info->tv_dac_adj);
+
 }
 
 static void RADEONInitDAC2Registers(xf86OutputPtr output, RADEONSavePtr save,
@@ -902,6 +903,9 @@ static void RADEONInitDAC2Registers(xf86
     /*0x0028023;*/
     RADEONInitTvDacCntl(pScrn, save);
 
+    if (IS_R300_VARIANT)
+	save->gpiopad_a = info->SavedReg.gpiopad_a | 1;
+
     if (IsPrimary) {
         save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC2_CLK_SEL;
         if (IS_R300_VARIANT) {
@@ -961,6 +965,9 @@ RADEONInitOutputRegisters(ScrnInfoPtr pS
 	} else {
 	    RADEONInitFP2Registers(output, save, mode, IsPrimary);
 	}
+    } else if (radeon_output->MonType == MT_STV ||
+	       radeon_output->MonType == MT_CTV) {
+	RADEONInitTVRegisters(output, save, mode, IsPrimary);
     }
 }
 
@@ -993,6 +1000,12 @@ radeon_mode_set(xf86OutputPtr output, Di
 	    RADEONRestoreFP2Registers(pScrn, &info->ModeReg);
 	}
 	break;
+    case MT_STV:
+    case MT_CTV:
+	ErrorF("restore tv\n");
+	RADEONRestoreDACRegisters(pScrn, &info->ModeReg);
+	RADEONRestoreTVRegisters(pScrn, &info->ModeReg);
+	break;
     default:
 	ErrorF("restore dac\n");
 	RADEONRestoreDACRegisters(pScrn, &info->ModeReg);
@@ -1041,8 +1054,12 @@ radeon_detect(xf86OutputPtr output)
 
       switch(radeon_output->MonType) {
       case MT_LCD:
-      case MT_DFP: output->subpixel_order = SubPixelHorizontalRGB; break;
-      default: output->subpixel_order = SubPixelNone; break;
+      case MT_DFP:
+	  output->subpixel_order = SubPixelHorizontalRGB;
+	  break;
+      default:
+	  output->subpixel_order = SubPixelNone;
+	  break;
       }
       
       return XF86OutputStatusConnected;
diff --git a/src/radeon_probe.h b/src/radeon_probe.h
index 0dceca9..f0df341 100644
--- a/src/radeon_probe.h
+++ b/src/radeon_probe.h
@@ -137,6 +137,18 @@ typedef enum
     OUTPUT_CTV,
 } RADEONOutputType;
 
+/* standards */
+typedef enum
+{
+    TV_STD_NTSC,
+    TV_STD_PAL,
+    TV_STD_PAL_M,
+    TV_STD_PAL_60,
+    TV_STD_NTSC_J,
+    TV_STD_PAL_CN,
+    TV_STD_PAL_N
+} TVStd;
+
 typedef struct _RADEONCrtcPrivateRec {
 #ifdef USE_XAA
     FBLinearPtr rotate_mem_xaa;
@@ -184,6 +196,11 @@ typedef struct _RADEONOutputPrivateRec {
     int               PanelPwrDly;
     int               DotClock;
     RADEONTMDSPll     tmds_pll[4];
+    /* TV out */
+    TVStd             tvStd;
+    int               hPos;
+    int               vPos;
+    int               hSize;
 } RADEONOutputPrivateRec, *RADEONOutputPrivatePtr;
 
 #define RADEON_MAX_CRTC 2
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index 5fdda45..db2057a 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -467,6 +467,7 @@
 #       define RADEON_DAC_PDWN              (1 << 15)
 #       define RADEON_DAC_MASK_ALL          (0xff << 24)
 #define RADEON_DAC_CNTL2                    0x007c
+#       define RADEON_DAC2_TV_CLK_SEL       (0 <<  1)
 #       define RADEON_DAC2_DAC_CLK_SEL      (1 <<  0)
 #       define RADEON_DAC2_DAC2_CLK_SEL     (1 <<  1)
 #       define RADEON_DAC2_PALETTE_ACC_CTL  (1 <<  5)
@@ -486,9 +487,11 @@
 #       define RADEON_TV_DAC_PEDESTAL       (1 <<  2)
 #       define RADEON_TV_MONITOR_DETECT_EN  (1 <<  4)
 #       define RADEON_TV_DAC_CMPOUT         (1 <<  5)
+#       define RADEON_TV_DAC_STD_MASK       (3 <<  8)
+#       define RADEON_TV_DAC_STD_PAL        (0 <<  8)
 #       define RADEON_TV_DAC_STD_NTSC       (1 <<  8)
-#       define RADEON_TV_DAC_STD_MASK       0x0300
-#       define RADEON_TV_DAC_STD_PS2        0x0200
+#       define RADEON_TV_DAC_STD_PS2        (2 <<  8)
+#       define RADEON_TV_DAC_STD_RS343      (3 <<  8)
 #       define RADEON_TV_DAC_BGSLEEP        (1 <<  6)
 #       define RADEON_TV_DAC_BGADJ_MASK     (0xf <<  16)
 #       define RADEON_TV_DAC_DACADJ_MASK    (0xf <<  20)
@@ -507,9 +510,9 @@
 #       define RADEON_DISP_DAC2_SOURCE_MASK  0x0c
 #       define RADEON_DISP_DAC_SOURCE_CRTC2 0x01
 #       define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04
-#       define RADEON_DISP_TVDAC_SOURCE_MASK  (0x03<<2)
+#       define RADEON_DISP_TVDAC_SOURCE_MASK  (0x03 << 2)
 #       define RADEON_DISP_TVDAC_SOURCE_CRTC  0x0
-#       define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01<<2)
+#       define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01 << 2)
 #       define RADEON_DISP_TV_SOURCE_CRTC   (1 << 16) /* crtc1 or crtc2 */
 #       define RADEON_DISP_TV_SOURCE_LTU    (0 << 16) /* linear transform unit */
 #define RADEON_DISP_TV_OUT_CNTL             0x0d6c
@@ -537,12 +540,12 @@
 #       define RADEON_DISP_ALPHA_MODE_KEY   0
 #       define RADEON_DISP_ALPHA_MODE_PER_PIXEL 1
 #       define RADEON_DISP_ALPHA_MODE_GLOBAL 2
-#       define RADEON_DISP_RGB_OFFSET_EN    (1<<8)
+#       define RADEON_DISP_RGB_OFFSET_EN    (1 << 8)
 #       define RADEON_DISP_GRPH_ALPHA_MASK  (0xff << 16)
 #       define RADEON_DISP_OV0_ALPHA_MASK   (0xff << 24)
 #	define RADEON_DISP_LIN_TRANS_BYPASS (0x01 << 9)
 #define RADEON_DISP2_MERGE_CNTL		    0x0d68
-#       define RADEON_DISP2_RGB_OFFSET_EN   (1<<8)
+#       define RADEON_DISP2_RGB_OFFSET_EN   (1 << 8)
 #define RADEON_DISP_LIN_TRANS_GRPH_A        0x0d80
 #define RADEON_DISP_LIN_TRANS_GRPH_B        0x0d84
 #define RADEON_DISP_LIN_TRANS_GRPH_C        0x0d88
@@ -844,6 +847,7 @@
 #       define RADEON_HDP_SOFT_RESET        (1 << 26)
 #       define RADEON_HDP_APER_CNTL         (1 << 23)
 #define RADEON_HTOTAL_CNTL                  0x0009 /* PLL */
+#       define RADEON_HTOT_CNTL_VGA_EN      (1 << 28)
 #define RADEON_HTOTAL2_CNTL                 0x002e /* PLL */
 
        /* Multimedia I2C bus */
@@ -1267,6 +1271,7 @@
 #       define R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF (1 << 23)
 #define RADEON_PLANE_3D_MASK_C              0x1d44
 #define RADEON_PLL_TEST_CNTL                0x0013 /* PLL */
+#       define RADEON_PLL_MASK_READ_B          (1 << 9)
 #define RADEON_PMI_CAP_ID                   0x0f5c /* PCI */
 #define RADEON_PMI_DATA                     0x0f63 /* PCI */
 #define RADEON_PMI_NXT_CAP_PTR              0x0f5d /* PCI */
@@ -3080,9 +3085,14 @@
 #       define RADEON_TV_ASYNC_RST               (1 <<  0)
 #       define RADEON_CRT_ASYNC_RST              (1 <<  1)
 #       define RADEON_RESTART_PHASE_FIX          (1 <<  3)
+#	define RADEON_TV_FIFO_ASYNC_RST		 (1 <<  4)
+#	define RADEON_VIN_ASYNC_RST		 (1 <<  5)
+#	define RADEON_AUD_ASYNC_RST		 (1 <<  6)
+#	define RADEON_DVS_ASYNC_RST		 (1 <<  7)
 #       define RADEON_CRT_FIFO_CE_EN             (1 <<  9)
 #       define RADEON_TV_FIFO_CE_EN              (1 << 10)
 #       define RADEON_TVCLK_ALWAYS_ONb           (1 << 30)
+#	define RADEON_TV_ON			 (1 << 31)
 #define RADEON_TV_PRE_DAC_MUX_CNTL               0x0888
 #       define RADEON_Y_RED_EN                   (1 << 0)
 #       define RADEON_C_GRN_EN                   (1 << 1)
@@ -3100,7 +3110,14 @@
 #       define RADEON_RGB_SRC_SEL_RMX		  (1 <<  8)
 #       define RADEON_RGB_SRC_SEL_CRTC2		  (2 <<  8)
 #       define RADEON_RGB_CONVERT_BY_PASS	  (1 << 10)
+#	define RADEON_TVOUT_SCALE_EN 		  (1 << 26)
 #define RADEON_TV_SYNC_CNTL                          0x0808
+#       define RADEON_SYNC_OE                     (1 <<  0)
+#       define RADEON_SYNC_OUT                    (1 <<  1)
+#       define RADEON_SYNC_IN                     (1 <<  2)
+#       define RADEON_SYNC_PUB                    (1 <<  3)
+#       define RADEON_SYNC_PD                     (1 <<  4)
+#       define RADEON_TV_SYNC_IO_DRIVE            (1 <<  5)
 #define RADEON_TV_HTOTAL                             0x080c
 #define RADEON_TV_HDISP                              0x0810
 #define RADEON_TV_HSTART                             0x0818
@@ -3116,10 +3133,23 @@
 #define RADEON_TV_HOST_READ_DATA                     0x0840
 #define RADEON_TV_HOST_WRITE_DATA                    0x0844
 #define RADEON_TV_HOST_RD_WT_CNTL                    0x0848
+#	define RADEON_HOST_FIFO_RD		 (1 << 12)
+#	define RADEON_HOST_FIFO_RD_ACK		 (1 << 13)
+#	define RADEON_HOST_FIFO_WT		 (1 << 14)
+#	define RADEON_HOST_FIFO_WT_ACK		 (1 << 15)
 #define RADEON_TV_VSCALER_CNTL1                      0x084c
+#       define RADEON_UV_INC_MASK                0xffff
+#       define RADEON_UV_INC_SHIFT               0
+#       define RADEON_Y_W_EN			 (1 << 24)
 #       define RADEON_RESTART_FIELD              (1 << 29) /* restart on field 0 */
 #       define RADEON_Y_DEL_W_SIG_SHIFT          26
 #define RADEON_TV_TIMING_CNTL                        0x0850
+#       define RADEON_H_INC_MASK                 0xfff
+#       define RADEON_H_INC_SHIFT                0
+#       define RADEON_REQ_Y_FIRST                (1 << 19)
+#       define RADEON_FORCE_BURST_ALWAYS         (1 << 21)
+#       define RADEON_UV_POST_SCALE_BYPASS       (1 << 23)
+#       define RADEON_UV_OUTPUT_POST_SCALE_SHIFT 24
 #define RADEON_TV_VSCALER_CNTL2                      0x0854
 #       define RADEON_DITHER_MODE                (1 <<  0)
 #       define RADEON_Y_OUTPUT_DITHER_EN         (1 <<  1)
@@ -3127,27 +3157,65 @@
 #       define RADEON_UV_TO_BUF_DITHER_EN        (1 <<  3)
 #define RADEON_TV_Y_FALL_CNTL                        0x0858
 #       define RADEON_Y_FALL_PING_PONG           (1 << 16)
+#       define RADEON_Y_COEF_EN                  (1 << 17)
 #define RADEON_TV_Y_RISE_CNTL                        0x085c
 #       define RADEON_Y_RISE_PING_PONG           (1 << 16)
 #define RADEON_TV_Y_SAW_TOOTH_CNTL                   0x0860
 #define RADEON_TV_UPSAMP_AND_GAIN_CNTL               0x0864
+#	define RADEON_YUPSAMP_EN		 (1 <<  0)
+#	define RADEON_UVUPSAMP_EN		 (1 <<  2)
 #define RADEON_TV_GAIN_LIMIT_SETTINGS                0x0868
+#       define RADEON_Y_GAIN_LIMIT_SHIFT         0
+#       define RADEON_UV_GAIN_LIMIT_SHIFT        16
 #define RADEON_TV_LINEAR_GAIN_SETTINGS               0x086c
+#       define RADEON_Y_GAIN_SHIFT               0
+#       define RADEON_UV_GAIN_SHIFT              16
 #define RADEON_TV_MODULATOR_CNTL1                    0x0870
+#	define RADEON_YFLT_EN			 (1 <<  2)
+#	define RADEON_UVFLT_EN			 (1 <<  3)
 #       define RADEON_ALT_PHASE_EN               (1 <<  6)
 #       define RADEON_SYNC_TIP_LEVEL             (1 <<  7)
+#       define RADEON_BLANK_LEVEL_SHIFT          8
+#       define RADEON_SET_UP_LEVEL_SHIFT         16
+#	define RADEON_SLEW_RATE_LIMIT		 (1 << 23)
+#       define RADEON_CY_FILT_BLEND_SHIFT        28
 #define RADEON_TV_MODULATOR_CNTL2                    0x0874
 #define RADEON_TV_CRC_CNTL                           0x0890
 #define RADEON_TV_UV_ADR                             0x08ac
+#	define RADEON_MAX_UV_ADR_MASK		 0x000000ff
+#	define RADEON_MAX_UV_ADR_SHIFT		 0
+#	define RADEON_TABLE1_BOT_ADR_MASK	 0x0000ff00
+#	define RADEON_TABLE1_BOT_ADR_SHIFT	 8
+#	define RADEON_TABLE3_TOP_ADR_MASK	 0x00ff0000
+#	define RADEON_TABLE3_TOP_ADR_SHIFT	 16
+#	define RADEON_HCODE_TABLE_SEL_MASK	 0x06000000
+#	define RADEON_HCODE_TABLE_SEL_SHIFT	 25
+#	define RADEON_VCODE_TABLE_SEL_MASK	 0x18000000
+#	define RADEON_VCODE_TABLE_SEL_SHIFT	 27
+#	define RADEON_TV_MAX_FIFO_ADDR		 0x1a7
+#	define RADEON_TV_MAX_FIFO_ADDR_INTERNAL	 0x1ff
 #define RADEON_TV_PLL_FINE_CNTL			     0x0020	/* PLL */
 #define RADEON_TV_PLL_CNTL                           0x0021	/* PLL */
+#       define RADEON_TV_M0LO_MASK               0xff
+#       define RADEON_TV_M0HI_MASK               0x3
+#       define RADEON_TV_M0HI_SHIFT              18
+#       define RADEON_TV_N0LO_MASK               0xff
+#       define RADEON_TV_N0LO_SHIFT              8
+#       define RADEON_TV_N0HI_MASK               0x3
+#       define RADEON_TV_N0HI_SHIFT              21
+#       define RADEON_TV_P_MASK                  0xf
+#       define RADEON_TV_P_SHIFT                 24
 #       define RADEON_TV_SLIP_EN                 (1 << 23)
 #       define RADEON_TV_DTO_EN                  (1 << 28)
 #define RADEON_TV_PLL_CNTL1                          0x0022	/* PLL */
-#       define RADEON_TVPLL_TEST_DIS             (1 << 31)
-#       define RADEON_TVCLK_SRC_SEL_TVPLL        (1 << 30)
+#       define RADEON_TVPLL_RESET                (1 <<  1)
 #       define RADEON_TVPLL_SLEEP                (1 <<  3)
 #       define RADEON_TVPLL_REFCLK_SEL           (1 <<  4)
+#       define RADEON_TVPDC_SHIFT                14
+#       define RADEON_TVPDC_MASK                 (3 << 14)
+#       define RADEON_TVPLL_TEST_DIS             (1 << 31)
+#       define RADEON_TVCLK_SRC_SEL_TVPLL        (1 << 30)
+#define RADEON_GPIOPAD_A			     0x019c
 
 #define RADEON_RS480_UNK_e30			0xe30
 #define RADEON_RS480_UNK_e34			0xe34
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
new file mode 100644
index 0000000..1d0b2c6
--- /dev/null
+++ b/src/radeon_tv.c
@@ -0,0 +1,656 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+/* X and server generic header files */
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "fbdevhw.h"
+#include "vgaHW.h"
+#include "xf86Modes.h"
+
+/* Driver data structures */
+#include "radeon.h"
+#include "radeon_reg.h"
+#include "radeon_macros.h"
+#include "radeon_probe.h"
+#include "radeon_version.h"
+#include "radeon_tv.h"
+
+/**********************************************************************
+ *
+ * ModeConstants
+ *
+ * Storage of constants related to a single video mode
+ *
+ **********************************************************************/
+
+typedef struct
+{
+    CARD16 horResolution;
+    CARD16 verResolution;
+    TVStd  standard;
+    CARD16 horTotal;
+    CARD16 verTotal;
+    CARD16 horStart;
+    CARD16 horSyncStart;
+    CARD16 verSyncStart;
+    unsigned defRestart;
+    CARD32 vScalerCntl1;
+    CARD32 yRiseCntl;
+    CARD32 ySawtoothCntl;
+    CARD16 crtcPLL_N;
+    CARD8  crtcPLL_M;
+    Bool   crtcPLL_divBy2;
+    CARD8  crtcPLL_byteClkDiv;
+    CARD8  crtcPLL_postDiv;
+    Bool   use888RGB; /* False: RGB data is 565 packed (2 bytes/pixel) */
+                      /* True : RGB data is 888 packed (3 bytes/pixel) */
+    unsigned pixToTV;
+    CARD8  byteClkDelay;
+    CARD32 tvoDataDelayA;
+    CARD32 tvoDataDelayB;
+    const CARD16 *horTimingTable;
+    const CARD16 *verTimingTable;
+} TVModeConstants;
+
+static const CARD16 horTimingNTSC_BIOS[] =
+{
+    0x0007,
+    0x003f,
+    0x0263,
+    0x0a24,
+    0x2a6b,
+    0x0a36,
+    0x126d, /* H_TABLE_POS1 */
+    0x1bfe,
+    0x1a8f, /* H_TABLE_POS2 */
+    0x1ec7,
+    0x3863,
+    0x1bfe,
+    0x1bfe,
+    0x1a2a,
+    0x1e95,
+    0x0e31,
+    0x201b,
+    0
+};
+
+static const CARD16 verTimingNTSC_BIOS[] =
+{
+    0x2001,
+    0x200d,
+    0x1006,
+    0x0c06,
+    0x1006,
+    0x1818,
+    0x21e3,
+    0x1006,
+    0x0c06,
+    0x1006,
+    0x1817,
+    0x21d4,
+    0x0002,
+    0
+};
+
+static const CARD16 horTimingPAL_BIOS[] =
+{
+    0x0007,
+    0x0058,
+    0x027c,
+    0x0a31,
+    0x2a77,
+    0x0a95,
+    0x124f, /* H_TABLE_POS1 */
+    0x1bfe,
+    0x1b22, /* H_TABLE_POS2 */
+    0x1ef9,
+    0x387c,
+    0x1bfe,
+    0x1bfe,
+    0x1b31,
+    0x1eb5,
+    0x0e43,
+    0x201b,
+    0
+};
+
+static const CARD16 verTimingPAL_BIOS[] =
+{
+    0x2001,
+    0x200c,
+    0x1005,
+    0x0c05,
+    0x1005,
+    0x1401,
+    0x1821,
+    0x2240,
+    0x1005,
+    0x0c05,
+    0x1005,
+    0x1401,
+    0x1822,
+    0x2230,
+    0x0002,
+    0
+};
+
+/**********************************************************************
+ *
+ * availableModes
+ *
+ * Table of all allowed modes for tv output
+ *
+ **********************************************************************/
+static const TVModeConstants availableTVModes[] =
+{
+    { 
+	800,                /* horResolution */
+	600,                /* verResolution */
+	TV_STD_NTSC,        /* standard */
+	990,                /* horTotal */
+	740,                /* verTotal */
+	813,                /* horStart */
+	824,                /* horSyncStart */
+	632,                /* verSyncStart */
+	625592,             /* defRestart */
+	0x0900b46b,         /* vScalerCntl1 */
+	0x00012c00,         /* yRiseCntl */
+	0x10002d1a,         /* ySawtoothCntl */
+	592,                /* crtcPLL_N */
+	91,                 /* crtcPLL_M */
+	TRUE,               /* crtcPLL_divBy2 */
+	0,                  /* crtcPLL_byteClkDiv */
+	4,                  /* crtcPLL_postDiv */
+	FALSE,              /* use888RGB */
+	1022,               /* pixToTV */
+	1,                  /* byteClkDelay */
+	0x0a0b0907,         /* tvoDataDelayA */
+	0x060a090a,         /* tvoDataDelayB */
+	horTimingNTSC_BIOS, /* horTimingTable */
+	verTimingNTSC_BIOS  /* verTimingTable */
+    },
+    { 
+	800,               /* horResolution */
+	600,               /* verResolution */
+	TV_STD_PAL,        /* standard */
+	1144,              /* horTotal */
+	706,               /* verTotal */
+	812,               /* horStart */
+	824,               /* horSyncStart */
+	669,               /* verSyncStart */
+	696700,            /* defRestart */
+	0x09009097,        /* vScalerCntl1 */
+	0x000007da,        /* yRiseCntl */
+	0x10002426,        /* ySawtoothCntl */
+	1382,              /* crtcPLL_N */
+	231,               /* crtcPLL_M */
+	TRUE,              /* crtcPLL_divBy2 */
+	0,                 /* crtcPLL_byteClkDiv */
+	4,                 /* crtcPLL_postDiv */
+	FALSE,             /* use888RGB */
+	759,               /* pixToTV */
+	1,                 /* byteClkDelay */
+	0x0a0b0907,        /* tvoDataDelayA */
+	0x060a090a,        /* tvoDataDelayB */
+	horTimingPAL_BIOS, /* horTimingTable */
+	verTimingPAL_BIOS  /* verTimingTable */
+    }
+};
+
+#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ]))
+
+
+/* Compute F,V,H restarts from default restart position and hPos & vPos
+ * Return TRUE when code timing table was changed
+ */
+static Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save,
+				 DisplayModePtr mode)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    RADEONInfoPtr  info = RADEONPTR(pScrn);
+    int restart;
+    unsigned hTotal;
+    unsigned vTotal;
+    unsigned fTotal;
+    int vOffset;
+    int hOffset;
+    CARD16 p1;
+    CARD16 p2;
+    Bool hChanged;
+    CARD16 hInc;
+    const TVModeConstants *constPtr;
+
+    constPtr = &availableTVModes[radeon_output->tvStd];
+
+    hTotal = constPtr->horTotal;
+    vTotal = constPtr->verTotal;
+    
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	fTotal = NTSC_TV_VFTOTAL + 1;
+    else
+	fTotal = PAL_TV_VFTOTAL + 1;
+
+    /*
+     * Adjust positions 1&2 in hor. code timing table
+     */
+    hOffset = radeon_output->hPos * H_POS_UNIT;
+
+    p1 = constPtr->horTimingTable[ H_TABLE_POS1 ];
+    p2 = constPtr->horTimingTable[ H_TABLE_POS2 ];
+
+    p1 = (CARD16)((int)p1 + hOffset);
+    p2 = (CARD16)((int)p2 - hOffset);
+
+    hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] || 
+		p2 != save->h_code_timing[ H_TABLE_POS2 ]);
+
+    save->h_code_timing[ H_TABLE_POS1 ] = p1;
+    save->h_code_timing[ H_TABLE_POS2 ] = p2;
+
+    /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */
+    hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000;
+
+    /* Adjust restart */
+    restart = constPtr->defRestart;
+ 
+    /*
+     * Convert vPos TV lines to n. of CRTC pixels
+     * Be verrrrry careful when mixing signed & unsigned values in C..
+     */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(NTSC_TV_LINES_PER_FRAME);
+    else
+	vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(PAL_TV_LINES_PER_FRAME);
+
+    restart -= vOffset + hOffset;
+
+    ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n",
+	   constPtr->defRestart , radeon_output->hPos , radeon_output->vPos , p1 , p2 , restart);
+
+    save->tv_hrestart = restart % hTotal;
+    restart /= hTotal;
+    save->tv_vrestart = restart % vTotal;
+    restart /= vTotal;
+    save->tv_frestart = restart % fTotal;
+
+    ErrorF("computeRestarts: F/H/V=%u,%u,%u\n",
+	   save->tv_frestart , save->tv_vrestart , save->tv_hrestart);
+
+    /* Compute H_INC from hSize */
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	hInc = (CARD16)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) /
+			(radeon_output->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE)));
+    else
+	hInc = (CARD16)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) /
+			(radeon_output->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE)));
+
+    save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) |
+	((CARD32)hInc << RADEON_H_INC_SHIFT);
+
+    ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , radeon_output->hSize , hInc);
+
+    return hChanged;
+}
+
+/* intit TV-out regs */
+void RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save,
+                                  DisplayModePtr mode, BOOL IsPrimary)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    RADEONInfoPtr  info = RADEONPTR(pScrn);
+    unsigned i;
+    CARD32 tmp;
+    const TVModeConstants *constPtr;
+
+    constPtr = &availableTVModes[radeon_output->tvStd];
+
+    save->tv_crc_cntl = 0;
+
+    save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | 
+	                           (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT);
+
+    save->tv_hdisp = constPtr->horResolution - 1;
+    save->tv_hstart = constPtr->horStart;
+    save->tv_htotal = constPtr->horTotal - 1;
+
+    save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) |
+	                            (0x100 << RADEON_Y_GAIN_SHIFT);
+
+    save->tv_master_cntl = (RADEON_RESTART_PHASE_FIX
+			    | RADEON_VIN_ASYNC_RST
+			    | RADEON_AUD_ASYNC_RST
+			    | RADEON_DVS_ASYNC_RST
+			    | RADEON_CRT_FIFO_CE_EN
+			    | RADEON_TV_FIFO_CE_EN);
+
+    save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT
+	                       | RADEON_SYNC_TIP_LEVEL
+	                       | RADEON_YFLT_EN
+	                       | RADEON_UVFLT_EN
+	                       | (0x3b << RADEON_BLANK_LEVEL_SHIFT)
+	                       | (0x6 << RADEON_CY_FILT_BLEND_SHIFT);
+
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT);
+    else
+	save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN
+	                            | (0x3b << RADEON_SET_UP_LEVEL_SHIFT);
+
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	save->tv_modulator_cntl2 = 0x00000191;
+    else
+	save->tv_modulator_cntl2 = 0x003e01b2;
+
+    save->pll_test_cntl = 0;
+
+    save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN
+				 | RADEON_C_GRN_EN
+				 | RADEON_CMP_BLU_EN
+				 | RADEON_DAC_DITHER_EN);
+
+    save->tv_rgb_cntl = 0x007b0004;
+
+    if (IsPrimary) {
+	if (radeon_output->Flags & RADEON_USE_RMX)
+	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX;
+	else
+	    save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1;
+    } else {
+	save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2;
+    }
+
+    save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE;
+
+    save->tv_sync_size = constPtr->horResolution + 8;
+  
+    tmp = (constPtr->vScalerCntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK;
+    tmp = ((16384 * 256 * 10) / tmp + 5) / 10;
+    tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000;
+    save->tv_timing_cntl = tmp;
+
+    save->tv_dac_cntl = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD
+	                | RADEON_TV_MONITOR_DETECT_EN
+	                | (8 << 16) | (6 << 20);
+
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
+    else
+	save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
+
+#if 0
+    save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD
+	                 | RADEON_TV_DAC_BDACPD);
+
+    if (MonType == MT_CTV) {
+	save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD;
+    }
+
+    if (MonType == MT_STV) {
+	save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
+			       RADEON_TV_DAC_GDACPD);
+    }
+#endif
+
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	save->tv_pll_cntl = (NTSC_TV_PLL_M & RADEON_TV_M0LO_MASK) |
+	    (((NTSC_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
+	    ((NTSC_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
+	    (((NTSC_TV_PLL_N >> 8) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
+	    ((NTSC_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
+    else
+	save->tv_pll_cntl = (PAL_TV_PLL_M & RADEON_TV_M0LO_MASK) |
+	    (((PAL_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) |
+	    ((PAL_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) |
+	    (((PAL_TV_PLL_N >> 8) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) |
+	    ((PAL_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT);
+
+    save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN;
+
+    save->tv_uv_adr = 0xc8;
+
+    save->tv_vdisp = constPtr->verResolution - 1;
+
+    if (radeon_output->tvStd == TV_STD_NTSC)
+	save->tv_ftotal = NTSC_TV_VFTOTAL;
+    else
+	save->tv_ftotal = PAL_TV_VFTOTAL;
+
+    save->tv_vscaler_cntl1 = constPtr->vScalerCntl1;
+    save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD;
+
+    save->tv_vscaler_cntl2 = 0x10000000;
+
+    save->tv_vtotal = constPtr->verTotal - 1;
+
+    save->tv_y_fall_cntl = RADEON_Y_FALL_PING_PONG | RADEON_Y_COEF_EN;
+    save->tv_y_fall_cntl |= 0x80000400;
+
+    save->tv_y_rise_cntl = constPtr->yRiseCntl;
+    save->tv_y_saw_tooth_cntl = constPtr->ySawtoothCntl;
+
+    for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
+	if ((save->h_code_timing[ i ] = constPtr->horTimingTable[ i ]) == 0)
+	    break;
+    }
+
+    for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) {
+	if ((save->v_code_timing[ i ] = constPtr->verTimingTable[ i ]) == 0)
+	    break;
+    }
+
+    /*
+     * This must be called AFTER loading timing tables as they are modified by this function
+     */
+    RADEONInitTVRestarts(output, save, mode);
+
+    /*save->hw_debug = 0x00000200;*/
+
+    save->dac_cntl &= ~RADEON_DAC_TVO_EN;
+
+    if (IS_R300_VARIANT)
+        save->gpiopad_a = info->SavedReg.gpiopad_a & ~1;
+
+    if (IsPrimary) {
+	save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
+	save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC
+				   | RADEON_DISP_TV_SOURCE_CRTC);
+    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
+	    save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2;
+    	} else {
+            save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
+    	}
+    } else {
+	save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK;
+	save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC;
+
+    	if (info->ChipFamily >= CHIP_FAMILY_R200) {
+	    save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2;
+    	} else {
+            save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
+    	}
+    }
+}
+
+
+/* Set hw registers for a new h/v position & h size */
+static void RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    RADEONInfoPtr  info = RADEONPTR(pScrn);
+    unsigned char *RADEONMMIO = info->MMIO;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+    Bool reloadTable;
+    RADEONSavePtr restore = &info->ModeReg;
+
+    reloadTable = RADEONInitTVRestarts(output, restore, mode);
+
+    RADEONRestoreTVRestarts(pScrn, restore);
+
+    OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl);
+
+    if (reloadTable) {
+	 OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl
+		                       | RADEON_TV_ASYNC_RST
+		                       | RADEON_CRT_ASYNC_RST
+		                       | RADEON_RESTART_PHASE_FIX);
+
+	RADEONRestoreTVTimingTables(pScrn, restore);
+
+	OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl);
+    }
+}
+
+void RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+				    DisplayModePtr mode, xf86OutputPtr output)
+{
+    const TVModeConstants *constPtr;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+    constPtr = &availableTVModes[radeon_output->tvStd];
+
+    save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
+	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
+
+    save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid 
+				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
+	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
+	(constPtr->horSyncStart & 7);
+
+    save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
+	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
+
+    save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
+	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
+
+    save->disp_merge_cntl |= RADEON_DISP_RGB_OFFSET_EN;
+}
+
+void RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+				   DisplayModePtr mode, xf86OutputPtr output)
+{
+    unsigned postDiv;
+    const TVModeConstants *constPtr;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+    constPtr = &availableTVModes[radeon_output->tvStd];
+
+    save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN;
+
+    save->ppll_ref_div = constPtr->crtcPLL_M;
+
+    switch (constPtr->crtcPLL_postDiv) {
+    case 1:
+	postDiv = 0;
+	break;
+    case 2:
+	postDiv = 1;
+	break;
+    case 3:
+	postDiv = 4;
+	break;
+    case 4:
+	postDiv = 2;
+	break;
+    case 6:
+	postDiv = 6;
+	break;
+    case 8:
+	postDiv = 3;
+	break;
+    case 12:
+	postDiv = 7;
+	break;
+    case 16:
+    default:
+	postDiv = 5;
+	break;
+    }
+
+    save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
+
+    save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL);
+    save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK;
+
+}
+
+void RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+				     DisplayModePtr mode, xf86OutputPtr output)
+{
+    const TVModeConstants *constPtr;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+    constPtr = &availableTVModes[radeon_output->tvStd];
+
+    save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) |
+	(((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT);
+
+    save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid 
+				  & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) |
+	(((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) |
+	(constPtr->horSyncStart & 7);
+
+    save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) |
+	((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT);
+
+    save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) |
+	((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT);
+
+    save->disp2_merge_cntl |= RADEON_DISP2_RGB_OFFSET_EN;
+}
+
+void RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+				    DisplayModePtr mode, xf86OutputPtr output)
+{
+    unsigned postDiv;
+    const TVModeConstants *constPtr;
+    RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+    constPtr = &availableTVModes[radeon_output->tvStd];
+
+    save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */
+
+    save->p2pll_ref_div = constPtr->crtcPLL_M;
+
+    switch (constPtr->crtcPLL_postDiv) {
+    case 1:
+	postDiv = 0;
+	break;
+    case 2:
+	postDiv = 1;
+	break;
+    case 3:
+	postDiv = 4;
+	break;
+    case 4:
+	postDiv = 2;
+	break;
+    case 6:
+	postDiv = 6;
+	break;
+    case 8:
+	postDiv = 3;
+	break;
+    case 12:
+	postDiv = 7;
+	break;
+    case 16:
+    default:
+	postDiv = 5;
+	break;
+    }
+
+    save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16);
+
+    save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK;
+    save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK
+			   | RADEON_PIXCLK_TV_SRC_SEL);
+
+}
diff --git a/src/radeon_tv.h b/src/radeon_tv.h
new file mode 100644
index 0000000..179b87b
--- /dev/null
+++ b/src/radeon_tv.h
@@ -0,0 +1,46 @@
+/*
+ * Maximum length of horizontal/vertical code timing tables for state storage
+ */
+#define MAX_H_CODE_TIMING_LEN 32
+#define MAX_V_CODE_TIMING_LEN 32
+
+/*
+ * Limits of h/v positions (hPos & vPos)
+ */
+#define MAX_H_POSITION 5 /* Range: [-5..5], negative is on the left, 0 is default, positive is on the right */
+#define MAX_V_POSITION 5 /* Range: [-5..5], negative is up, 0 is default, positive is down */
+
+/*
+ * Unit for hPos (in TV clock periods)
+ */
+#define H_POS_UNIT 10
+
+/*
+ * Indexes in h. code timing table for horizontal line position adjustment
+ */
+#define H_TABLE_POS1 6
+#define H_TABLE_POS2 8
+
+/*
+ * Limits of hor. size (hSize)
+ */
+#define MAX_H_SIZE 5 /* Range: [-5..5], negative is smaller, positive is larger */
+
+/* tv standard constants */
+#define NTSC_TV_PLL_M 22
+#define NTSC_TV_PLL_N 175
+#define NTSC_TV_PLL_P 5
+#define NTSC_TV_CLOCK_T 233
+#define NTSC_TV_VFTOTAL 1
+#define NTSC_TV_LINES_PER_FRAME 525
+#define NTSC_TV_ZERO_H_SIZE 479166
+#define NTSC_TV_H_SIZE_UNIT 9478
+
+#define PAL_TV_PLL_M 113
+#define PAL_TV_PLL_N 668
+#define PAL_TV_PLL_P 3
+#define PAL_TV_CLOCK_T 188
+#define PAL_TV_VFTOTAL 3
+#define PAL_TV_LINES_PER_FRAME 625
+#define PAL_TV_ZERO_H_SIZE 473200
+#define PAL_TV_H_SIZE_UNIT 9360
diff-tree 8d043db1817d94edeb72ab208dfea60026715d48 (from 62f06d89da3f7160d5e4df8d7ce6fe1a94e9d07c)
Author: Alex Deucher <alex at botch2.com>
Date:   Wed Jul 25 20:37:58 2007 -0400

    RADEON: Compute PLL VCO gain

diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index d82e912..e9a0954 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -4332,12 +4332,45 @@ static void RADEONPLL2WriteUpdate(ScrnIn
 	    ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
 }
 
+static CARD8 RADEONComputePLLGain(CARD16 reference_freq, CARD16 ref_div,
+				  CARD16 fb_div)
+{
+    unsigned vcoFreq;
+
+    vcoFreq = ((unsigned)reference_freq * fb_div) / ref_div;
+
+    /*
+     * This is horribly crude: the VCO frequency range is divided into
+     * 3 parts, each part having a fixed PLL gain value.
+     */
+    if (vcoFreq >= 30000)
+	/*
+	 * [300..max] MHz : 7
+	 */
+	return 7;
+    else if (vcoFreq >= 18000)
+	/*
+	 * [180..300) MHz : 4
+	 */
+        return 4;
+    else
+	/*
+	 * [0..180) MHz : 1
+	 */
+        return 1;
+}
+
 /* Write PLL registers */
 void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
-				      RADEONSavePtr restore)
+			       RADEONSavePtr restore)
 {
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     unsigned char *RADEONMMIO = info->MMIO;
+    CARD8 pllGain;
+
+    pllGain = RADEONComputePLLGain(info->pll.reference_freq,
+				   restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
+				   restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK);
 
     if (info->IsMobility) {
         /* A temporal workaround for the occational blanking on certain laptop panels.
@@ -4365,10 +4398,12 @@ void RADEONRestorePLLRegisters(ScrnInfoP
 	    RADEON_PPLL_CNTL,
 	    RADEON_PPLL_RESET
 	    | RADEON_PPLL_ATOMIC_UPDATE_EN
-	    | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN,
+	    | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
+	    | ((CARD32)pllGain << RADEON_PPLL_PVG_SHIFT),
 	    ~(RADEON_PPLL_RESET
 	      | RADEON_PPLL_ATOMIC_UPDATE_EN
-	      | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
+	      | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
+	      | RADEON_PPLL_PVG_MASK));
 
     OUTREGP(RADEON_CLOCK_CNTL_INDEX,
 	    RADEON_PLL_DIV_SEL,
@@ -4443,8 +4478,16 @@ void RADEONRestorePLLRegisters(ScrnInfoP
 
 /* Write PLL2 registers */
 void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn,
-				       RADEONSavePtr restore)
+				RADEONSavePtr restore)
 {
+    RADEONInfoPtr  info       = RADEONPTR(pScrn);
+    CARD8 pllGain;
+
+    pllGain = RADEONComputePLLGain(info->pll.reference_freq,
+                                   restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
+                                   restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK);
+
+
     OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL,
 	    RADEON_PIX2CLK_SRC_SEL_CPUCLK,
 	    ~(RADEON_PIX2CLK_SRC_SEL_MASK));
@@ -4452,9 +4495,11 @@ void RADEONRestorePLL2Registers(ScrnInfo
     OUTPLLP(pScrn,
 	    RADEON_P2PLL_CNTL,
 	    RADEON_P2PLL_RESET
-	    | RADEON_P2PLL_ATOMIC_UPDATE_EN,
+	    | RADEON_P2PLL_ATOMIC_UPDATE_EN
+	    | ((CARD32)pllGain << RADEON_P2PLL_PVG_SHIFT),
 	    ~(RADEON_P2PLL_RESET
-	      | RADEON_P2PLL_ATOMIC_UPDATE_EN));
+	      | RADEON_P2PLL_ATOMIC_UPDATE_EN
+	      | RADEON_P2PLL_PVG_MASK));
 
 
     OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV,
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index 9423bca..5fdda45 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -1225,6 +1225,8 @@
 #define RADEON_P2PLL_CNTL                   0x002a /* P2PLL */
 #       define RADEON_P2PLL_RESET                (1 <<  0)
 #       define RADEON_P2PLL_SLEEP                (1 <<  1)
+#       define RADEON_P2PLL_PVG_MASK             (7 << 11)
+#       define RADEON_P2PLL_PVG_SHIFT            11
 #       define RADEON_P2PLL_ATOMIC_UPDATE_EN     (1 << 16)
 #       define RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
 #       define RADEON_P2PLL_ATOMIC_UPDATE_VSYNC  (1 << 18)
@@ -1274,6 +1276,8 @@
 #define RADEON_PPLL_CNTL                    0x0002 /* PLL */
 #       define RADEON_PPLL_RESET                (1 <<  0)
 #       define RADEON_PPLL_SLEEP                (1 <<  1)
+#       define RADEON_PPLL_PVG_MASK             (7 << 11)
+#       define RADEON_PPLL_PVG_SHIFT            11
 #       define RADEON_PPLL_ATOMIC_UPDATE_EN     (1 << 16)
 #       define RADEON_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
 #       define RADEON_PPLL_ATOMIC_UPDATE_VSYNC  (1 << 18)
diff-tree 62f06d89da3f7160d5e4df8d7ce6fe1a94e9d07c (from 9cc3ab8320162f371bba15dc131f23c5de2013fc)
Author: Alex Deucher <alex at botch2.com>
Date:   Wed Jul 25 20:22:25 2007 -0400

    RADEON: write out saved vclk and pixclk values

diff --git a/src/radeon.h b/src/radeon.h
index c759b75..96c4632 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -281,7 +281,7 @@ typedef struct {
     unsigned          ppll_ref_div;
     unsigned          ppll_div_3;
     CARD32            htotal_cntl;
-    CARD32            vclk_cntl;
+    CARD32            vclk_ecp_cntl;
 
 				/* Computed values for PLL2 */
     CARD32            dot_clock_freq_2;
diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c
index 5bd2338..3518c9c 100644
--- a/src/radeon_crtc.c
+++ b/src/radeon_crtc.c
@@ -670,7 +670,7 @@ RADEONInitPLLRegisters(ScrnInfoPtr pScrn
     save->ppll_div_3     = (save->feedback_div | (post_div->bitvalue << 16));
     save->htotal_cntl    = 0;
 
-    save->vclk_cntl = (info->SavedReg.vclk_cntl &
+    save->vclk_ecp_cntl = (info->SavedReg.vclk_ecp_cntl &
 	    ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK;
 
 }
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 36e14ff..d82e912 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -4431,9 +4431,10 @@ void RADEONRestorePLLRegisters(ScrnInfoP
 
     usleep(50000); /* Let the clock to lock */
 
-    OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL,
+    /* OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL,
 	    RADEON_VCLK_SRC_SEL_PPLLCLK,
-	    ~(RADEON_VCLK_SRC_SEL_MASK));
+	    ~(RADEON_VCLK_SRC_SEL_MASK));*/
+    OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, restore->vclk_ecp_cntl);
 
     ErrorF("finished PLL1\n");
 
@@ -4493,9 +4494,10 @@ void RADEONRestorePLL2Registers(ScrnInfo
 
     usleep(5000); /* Let the clock to lock */
 
-    OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL,
+    /*OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL,
 	    RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
-	    ~(RADEON_PIX2CLK_SRC_SEL_MASK));
+	    ~(RADEON_PIX2CLK_SRC_SEL_MASK));*/
+    OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl);
 
     ErrorF("finished PLL2\n");
 
@@ -4907,7 +4909,7 @@ static void RADEONSavePLLRegisters(ScrnI
     save->ppll_ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV);
     save->ppll_div_3   = INPLL(pScrn, RADEON_PPLL_DIV_3);
     save->htotal_cntl  = INPLL(pScrn, RADEON_HTOTAL_CNTL);
-    save->vclk_cntl    = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+    save->vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
 
     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
 		   "Read: 0x%08x 0x%08x 0x%08lx\n",


More information about the xorg-commit mailing list