summaryrefslogtreecommitdiff
path: root/src/radeon_tv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/radeon_tv.c')
-rw-r--r--src/radeon_tv.c759
1 files changed, 759 insertions, 0 deletions
diff --git a/src/radeon_tv.c b/src/radeon_tv.c
new file mode 100644
index 00000000..3a26a0a7
--- /dev/null
+++ b/src/radeon_tv.c
@@ -0,0 +1,759 @@
+/*
+ * Integrated TV out support based on the GATOS code by
+ * Federico Ulivi <fulivi@lycos.com>
+ */
+
+#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 "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;
+ CARD16 crtcPLL_N;
+ CARD8 crtcPLL_M;
+ CARD8 crtcPLL_postDiv;
+ unsigned pixToTV;
+} TVModeConstants;
+
+static const CARD16 hor_timing_NTSC[] =
+{
+ 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 vert_timing_NTSC[] =
+{
+ 0x2001,
+ 0x200d,
+ 0x1006,
+ 0x0c06,
+ 0x1006,
+ 0x1818,
+ 0x21e3,
+ 0x1006,
+ 0x0c06,
+ 0x1006,
+ 0x1817,
+ 0x21d4,
+ 0x0002,
+ 0
+};
+
+static const CARD16 hor_timing_PAL[] =
+{
+ 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 vert_timing_PAL[] =
+{
+ 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 */
+ 592, /* crtcPLL_N */
+ 91, /* crtcPLL_M */
+ 4, /* crtcPLL_postDiv */
+ 1022, /* pixToTV */
+ },
+ {
+ 800, /* horResolution */
+ 600, /* verResolution */
+ TV_STD_PAL, /* standard */
+ 1144, /* horTotal */
+ 706, /* verTotal */
+ 812, /* horStart */
+ 824, /* horSyncStart */
+ 669, /* verSyncStart */
+ 696700, /* defRestart */
+ 1382, /* crtcPLL_N */
+ 231, /* crtcPLL_M */
+ 4, /* crtcPLL_postDiv */
+ 759, /* pixToTV */
+ }
+};
+
+#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
+ */
+static Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save,
+ DisplayModePtr mode)
+{
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ int restart;
+ unsigned hTotal;
+ unsigned vTotal;
+ unsigned fTotal;
+ int vOffset;
+ int hOffset;
+ CARD16 p1;
+ CARD16 p2;
+ Bool hChanged;
+ CARD16 hInc;
+ const TVModeConstants *constPtr;
+
+ /* FIXME: need to revisit this when we add more modes */
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M)
+ constPtr = &availableTVModes[0];
+ else
+ constPtr = &availableTVModes[1];
+
+ hTotal = constPtr->horTotal;
+ vTotal = constPtr->verTotal;
+
+ 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;
+
+ /* Adjust positions 1&2 in hor. code timing table */
+ hOffset = radeon_output->hPos * H_POS_UNIT;
+
+ 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 {
+ p1 = hor_timing_PAL[ H_TABLE_POS1 ];
+ p2 = hor_timing_PAL[ 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 ||
+ 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);
+
+ 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",
+ (unsigned)save->tv_frestart, (unsigned)save->tv_vrestart,
+ (unsigned)save->tv_hrestart);
+
+ /* Compute H_INC from hSize */
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M)
+ 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;
+ unsigned long vert_space, flicker_removal;
+ CARD32 tmp;
+ const TVModeConstants *constPtr;
+ const CARD16 *hor_timing;
+ const CARD16 *vert_timing;
+
+
+ /* FIXME: need to revisit this when we add more modes */
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M)
+ constPtr = &availableTVModes[0];
+ else
+ constPtr = &availableTVModes[1];
+
+ 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_VIN_ASYNC_RST
+ | RADEON_CRT_FIFO_CE_EN
+ | RADEON_TV_FIFO_CE_EN
+ | RADEON_TV_ON);
+
+ if (!IS_R300_VARIANT)
+ save->tv_master_cntl |= RADEON_TVCLK_ALWAYS_ONb;
+
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J)
+ save->tv_master_cntl |= RADEON_RESTART_PHASE_FIX;
+
+ save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT
+ | RADEON_SYNC_TIP_LEVEL
+ | RADEON_YFLT_EN
+ | RADEON_UVFLT_EN
+ | (6 << RADEON_CY_FILT_BLEND_SHIFT);
+
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J) {
+ save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT)
+ | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
+ save->tv_modulator_cntl2 = (-111 & RADEON_TV_U_BURST_LEVEL_MASK) |
+ ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
+ } else if (radeon_output->tvStd == TV_STD_SCART_PAL) {
+ save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN;
+ save->tv_modulator_cntl2 = (0 & RADEON_TV_U_BURST_LEVEL_MASK) |
+ ((0 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
+ } else {
+ save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN
+ | (0x3b << RADEON_SET_UP_LEVEL_SHIFT)
+ | (0x3b << RADEON_BLANK_LEVEL_SHIFT);
+ save->tv_modulator_cntl2 = (-78 & RADEON_TV_U_BURST_LEVEL_MASK) |
+ ((62 & RADEON_TV_V_BURST_LEVEL_MASK) << RADEON_TV_V_BURST_LEVEL_SHIFT);
+ }
+
+ 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 = (RADEON_RGB_DITHER_EN
+ | RADEON_TVOUT_SCALE_EN
+ | (0x0b << RADEON_UVRAM_READ_MARGIN_SHIFT)
+ | (0x07 << RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT));
+
+ 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;
+
+ 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;
+
+ 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 ||
+ 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
+ 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;
+
+ save->tv_dac_cntl = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | (8 << 16) | (6 << 20);
+
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J)
+ 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);
+
+ if (radeon_output->MonType == MT_CTV) {
+ save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD;
+ }
+
+ if (radeon_output->MonType == MT_STV) {
+ save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
+ RADEON_TV_DAC_GDACPD);
+ }
+#endif
+
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J)
+ 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_pll_cntl1 = (((4 & RADEON_TVPCP_MASK)<< RADEON_TVPCP_SHIFT) |
+ ((4 & RADEON_TVPVG_MASK) << RADEON_TVPVG_SHIFT) |
+ ((1 & RADEON_TVPDC_MASK)<< RADEON_TVPDC_SHIFT) |
+ RADEON_TVCLK_SRC_SEL_TVPLL |
+ RADEON_TVPLL_TEST_DIS);
+
+ 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 ||
+ 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 ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M) {
+ hor_timing = hor_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;
+ }
+
+ for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) {
+ 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 ] = vert_timing[ i ]) == 0)
+ break;
+ }
+
+ /*
+ * This must be called AFTER loading timing tables as they are modified by this function
+ */
+ RADEONInitTVRestarts(output, save, mode);
+
+ 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 */
+void RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ 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;
+
+ /* FIXME: need to revisit this when we add more modes */
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M)
+ 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);
+
+ 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);
+
+}
+
+void RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+ DisplayModePtr mode, xf86OutputPtr output)
+{
+ unsigned postDiv;
+ const TVModeConstants *constPtr;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ /* FIXME: need to revisit this when we add more modes */
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M)
+ constPtr = &availableTVModes[0];
+ else
+ constPtr = &availableTVModes[1];
+
+ 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;
+
+ /* FIXME: need to revisit this when we add more modes */
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M)
+ 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);
+
+ 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);
+
+}
+
+void RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save,
+ DisplayModePtr mode, xf86OutputPtr output)
+{
+ unsigned postDiv;
+ const TVModeConstants *constPtr;
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+
+ /* FIXME: need to revisit this when we add more modes */
+ if (radeon_output->tvStd == TV_STD_NTSC ||
+ radeon_output->tvStd == TV_STD_NTSC_J ||
+ radeon_output->tvStd == TV_STD_PAL_M)
+ constPtr = &availableTVModes[0];
+ else
+ constPtr = &availableTVModes[1];
+
+ 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);
+
+}