diff options
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/radeon.h | 61 | ||||
-rw-r--r-- | src/radeon_crtc.c | 25 | ||||
-rw-r--r-- | src/radeon_display.c | 33 | ||||
-rw-r--r-- | src/radeon_driver.c | 440 | ||||
-rw-r--r-- | src/radeon_modes.c | 15 | ||||
-rw-r--r-- | src/radeon_output.c | 23 | ||||
-rw-r--r-- | src/radeon_probe.h | 17 | ||||
-rw-r--r-- | src/radeon_reg.h | 84 | ||||
-rw-r--r-- | src/radeon_tv.c | 656 | ||||
-rw-r--r-- | src/radeon_tv.h | 46 |
11 files changed, 1373 insertions, 30 deletions
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, int crtc_num); 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, DisplayModePtr mode, 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, DisplayModePtr mode, } 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, DisplayModePtr mode, } 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, DisplayModePtr mode, 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 output, BOOL bEnable) 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 output, BOOL bEnable) 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(ScrnInfoPtr pScrn, RADEONSavePtr save); 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(ScrnInfoPtr pScrn) 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(ScrnInfoPtr pScrn) 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(ScrnInfoPtr pScrn) /* Original Radeon/7200 */ info->ChipFamily = CHIP_FAMILY_RADEON; pRADEONEnt->HasCRTC2 = FALSE; + info->InternalTVOut = FALSE; } @@ -4101,6 +4104,9 @@ void RADEONRestoreDACRegisters(ScrnInfoPtr pScrn, 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(ScrnInfoPtr pScrn, 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(ScrnInfoPtr pScrn, RADEONSavePtr restore) 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(ScrnInfoPtr pScrn, RADEONSavePtr restore) } +/* 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 reference_freq, CARD16 ref_div, 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 pScrn) /* 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, RADEONSavePtr restore) 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(ScrnInfoPtr pScrn, RADEONSavePtr save) 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(ScrnInfoPtr pScrn, RADEONSavePtr save) } +/* 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 pScrn, RADEONSavePtr save) 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 output) 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, RADEONSavePtr save) 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(xf86OutputPtr output, RADEONSavePtr save, /*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 pScrn, RADEONSavePtr save, } 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, DisplayModePtr mode, 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 |