diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/legacy_crtc.c | 579 | ||||
-rw-r--r-- | src/legacy_output.c | 159 | ||||
-rw-r--r-- | src/radeon.h | 2 | ||||
-rw-r--r-- | src/radeon_driver.c | 1107 | ||||
-rw-r--r-- | src/radeon_tv.c | 395 |
5 files changed, 1138 insertions, 1104 deletions
diff --git a/src/legacy_crtc.c b/src/legacy_crtc.c index f1bf9be1..4a7071af 100644 --- a/src/legacy_crtc.c +++ b/src/legacy_crtc.c @@ -53,6 +53,585 @@ #include "sarea.h" #endif +/* Write common registers */ +void +RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (info->IsSecondary) + return; + + OUTREG(RADEON_OVR_CLR, restore->ovr_clr); + OUTREG(RADEON_OVR_WID_LEFT_RIGHT, restore->ovr_wid_left_right); + OUTREG(RADEON_OVR_WID_TOP_BOTTOM, restore->ovr_wid_top_bottom); + OUTREG(RADEON_OV0_SCALE_CNTL, restore->ov0_scale_cntl); + OUTREG(RADEON_SUBPIC_CNTL, restore->subpic_cntl); + OUTREG(RADEON_VIPH_CONTROL, restore->viph_control); + OUTREG(RADEON_I2C_CNTL_1, restore->i2c_cntl_1); + OUTREG(RADEON_GEN_INT_CNTL, restore->gen_int_cntl); + OUTREG(RADEON_CAP0_TRIG_CNTL, restore->cap0_trig_cntl); + OUTREG(RADEON_CAP1_TRIG_CNTL, restore->cap1_trig_cntl); + OUTREG(RADEON_BUS_CNTL, restore->bus_cntl); + OUTREG(RADEON_SURFACE_CNTL, restore->surface_cntl); + + /* Workaround for the VT switching problem in dual-head mode. This + * problem only occurs on RV style chips, typically when a FP and + * CRT are connected. + */ + if (pRADEONEnt->HasCRTC2 && + info->ChipFamily != CHIP_FAMILY_R200 && + !IS_R300_VARIANT) { + CARD32 tmp; + + tmp = INREG(RADEON_DAC_CNTL2); + OUTREG(RADEON_DAC_CNTL2, tmp & ~RADEON_DAC2_DAC_CLK_SEL); + usleep(100000); + } +} + + +/* Write CRTC registers */ +void +RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Programming CRTC1, offset: 0x%08x\n", + (unsigned)restore->crtc_offset); + + /* We prevent the CRTC from hitting the memory controller until + * fully programmed + */ + OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl | + RADEON_CRTC_DISP_REQ_EN_B); + + OUTREGP(RADEON_CRTC_EXT_CNTL, + restore->crtc_ext_cntl, + RADEON_CRTC_VSYNC_DIS | + RADEON_CRTC_HSYNC_DIS | + RADEON_CRTC_DISPLAY_DIS); + + OUTREG(RADEON_CRTC_H_TOTAL_DISP, restore->crtc_h_total_disp); + OUTREG(RADEON_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid); + OUTREG(RADEON_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); + OUTREG(RADEON_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid); + + OUTREG(RADEON_FP_H_SYNC_STRT_WID, restore->fp_h_sync_strt_wid); + OUTREG(RADEON_FP_V_SYNC_STRT_WID, restore->fp_v_sync_strt_wid); + OUTREG(RADEON_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp); + OUTREG(RADEON_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp); + + if (IS_R300_VARIANT) + OUTREG(R300_CRTC_TILE_X0_Y0, restore->crtc_tile_x0_y0); + OUTREG(RADEON_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); + OUTREG(RADEON_CRTC_OFFSET, restore->crtc_offset); + + OUTREG(RADEON_CRTC_PITCH, restore->crtc_pitch); + OUTREG(RADEON_DISP_MERGE_CNTL, restore->disp_merge_cntl); + OUTREG(RADEON_CRTC_MORE_CNTL, restore->crtc_more_cntl); + + if (info->IsDellServer) { + OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); + OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); + OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); + OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl); + } + + OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl); +} + +/* Write CRTC2 registers */ +void +RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + /* CARD32 crtc2_gen_cntl;*/ + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Programming CRTC2, offset: 0x%08x\n", + (unsigned)restore->crtc2_offset); + + /* We prevent the CRTC from hitting the memory controller until + * fully programmed + */ + OUTREG(RADEON_CRTC2_GEN_CNTL, + restore->crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS | + RADEON_CRTC2_DISP_REQ_EN_B); + + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, restore->crtc2_v_total_disp); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid); + + OUTREG(RADEON_FP_H2_SYNC_STRT_WID, restore->fp_h2_sync_strt_wid); + OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp_v2_sync_strt_wid); + + if (IS_R300_VARIANT) + OUTREG(R300_CRTC2_TILE_X0_Y0, restore->crtc2_tile_x0_y0); + OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); + OUTREG(RADEON_CRTC2_OFFSET, restore->crtc2_offset); + + OUTREG(RADEON_CRTC2_PITCH, restore->crtc2_pitch); + OUTREG(RADEON_DISP2_MERGE_CNTL, restore->disp2_merge_cntl); + + if (info->ChipFamily == CHIP_FAMILY_RS400) { + OUTREG(RADEON_RS480_UNK_e30, restore->rs480_unk_e30); + OUTREG(RADEON_RS480_UNK_e34, restore->rs480_unk_e34); + OUTREG(RADEON_RS480_UNK_e38, restore->rs480_unk_e38); + OUTREG(RADEON_RS480_UNK_e3c, restore->rs480_unk_e3c); + } + OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl); + +} + +static void +RADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn) +{ + int i = 0; + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + i++); +} + +static void +RADEONPLLWriteUpdate(ScrnInfoPtr pScrn) +{ + while (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + RADEON_PPLL_ATOMIC_UPDATE_W, + ~(RADEON_PPLL_ATOMIC_UPDATE_W)); +} + +static void +RADEONPLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn) +{ + int i = 0; + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + i++); +} + +static void +RADEONPLL2WriteUpdate(ScrnInfoPtr pScrn) +{ + while (INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + + OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV, + RADEON_P2PLL_ATOMIC_UPDATE_W, + ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); +} + +static CARD8 +RADEONComputePLLGain(CARD16 reference_freq, CARD16 ref_div, + CARD16 fb_div) +{ + unsigned vcoFreq; + + if (!ref_div) + return 1; + + 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) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD8 pllGain; + +#if defined(__powerpc__) + /* apparently restoring the pll causes a hang??? */ + if (info->MacModel == RADEON_MAC_IBOOK) + return; +#endif + + 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. + This appears to related to the PLL divider registers (fail to lock?). + It occurs even when all dividers are the same with their old settings. + In this case we really don't need to fiddle with PLL registers. + By doing this we can avoid the blanking problem with some panels. + */ + if ((restore->ppll_ref_div == (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && + (restore->ppll_div_3 == (INPLL(pScrn, RADEON_PPLL_DIV_3) & + (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { + OUTREGP(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + RADEONPllErrataAfterIndex(info); + return; + } + } + + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_CPUCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + + OUTPLLP(pScrn, + RADEON_PPLL_CNTL, + RADEON_PPLL_RESET + | RADEON_PPLL_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_PVG_MASK)); + + OUTREGP(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + RADEONPllErrataAfterIndex(info); + + if (IS_R300_VARIANT || + (info->ChipFamily == CHIP_FAMILY_RS300) || + (info->ChipFamily == CHIP_FAMILY_RS400)) { + if (restore->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { + /* When restoring console mode, use saved PPLL_REF_DIV + * setting. + */ + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + restore->ppll_ref_div, + 0); + } else { + /* R300 uses ref_div_acc field as real ref divider */ + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + ~R300_PPLL_REF_DIV_ACC_MASK); + } + } else { + OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, + restore->ppll_ref_div, + ~RADEON_PPLL_REF_DIV_MASK); + } + + OUTPLLP(pScrn, RADEON_PPLL_DIV_3, + restore->ppll_div_3, + ~RADEON_PPLL_FB3_DIV_MASK); + + OUTPLLP(pScrn, RADEON_PPLL_DIV_3, + restore->ppll_div_3, + ~RADEON_PPLL_POST3_DIV_MASK); + + RADEONPLLWriteUpdate(pScrn); + RADEONPLLWaitForReadUpdateComplete(pScrn); + + OUTPLL(pScrn, RADEON_HTOTAL_CNTL, restore->htotal_cntl); + + OUTPLLP(pScrn, RADEON_PPLL_CNTL, + 0, + ~(RADEON_PPLL_RESET + | RADEON_PPLL_SLEEP + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + restore->ppll_ref_div, + restore->ppll_div_3, + (unsigned)restore->htotal_cntl, + INPLL(pScrn, RADEON_PPLL_CNTL)); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Wrote: rd=%d, fd=%d, pd=%d\n", + restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, + (restore->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); + + usleep(50000); /* Let the clock to lock */ + + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_PPLLCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + + /*OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, restore->vclk_ecp_cntl);*/ + + ErrorF("finished PLL1\n"); + +} + +/* Write PLL2 registers */ +void +RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, + 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)); + + OUTPLLP(pScrn, + RADEON_P2PLL_CNTL, + RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | ((CARD32)pllGain << RADEON_P2PLL_PVG_SHIFT), + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_PVG_MASK)); + + + OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV, + restore->p2pll_ref_div, + ~RADEON_P2PLL_REF_DIV_MASK); + + OUTPLLP(pScrn, RADEON_P2PLL_DIV_0, + restore->p2pll_div_0, + ~RADEON_P2PLL_FB0_DIV_MASK); + + OUTPLLP(pScrn, RADEON_P2PLL_DIV_0, + restore->p2pll_div_0, + ~RADEON_P2PLL_POST0_DIV_MASK); + + RADEONPLL2WriteUpdate(pScrn); + RADEONPLL2WaitForReadUpdateComplete(pScrn); + + OUTPLL(pScrn, RADEON_HTOTAL2_CNTL, restore->htotal_cntl2); + + OUTPLLP(pScrn, RADEON_P2PLL_CNTL, + 0, + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_SLEEP + | RADEON_P2PLL_ATOMIC_UPDATE_EN)); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + (unsigned)restore->p2pll_ref_div, + (unsigned)restore->p2pll_div_0, + (unsigned)restore->htotal_cntl2, + INPLL(pScrn, RADEON_P2PLL_CNTL)); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Wrote2: rd=%u, fd=%u, pd=%u\n", + (unsigned)restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + (unsigned)restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK, + (unsigned)((restore->p2pll_div_0 & + RADEON_P2PLL_POST0_DIV_MASK) >>16)); + + usleep(5000); /* Let the clock to lock */ + + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl); + + ErrorF("finished PLL2\n"); + +} + +/* Read common registers */ +void +RADEONSaveCommonRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->ovr_clr = INREG(RADEON_OVR_CLR); + save->ovr_wid_left_right = INREG(RADEON_OVR_WID_LEFT_RIGHT); + save->ovr_wid_top_bottom = INREG(RADEON_OVR_WID_TOP_BOTTOM); + save->ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL); + save->subpic_cntl = INREG(RADEON_SUBPIC_CNTL); + save->viph_control = INREG(RADEON_VIPH_CONTROL); + save->i2c_cntl_1 = INREG(RADEON_I2C_CNTL_1); + save->gen_int_cntl = INREG(RADEON_GEN_INT_CNTL); + save->cap0_trig_cntl = INREG(RADEON_CAP0_TRIG_CNTL); + save->cap1_trig_cntl = INREG(RADEON_CAP1_TRIG_CNTL); + save->bus_cntl = INREG(RADEON_BUS_CNTL); + save->surface_cntl = INREG(RADEON_SURFACE_CNTL); + save->grph_buffer_cntl = INREG(RADEON_GRPH_BUFFER_CNTL); + save->grph2_buffer_cntl = INREG(RADEON_GRPH2_BUFFER_CNTL); +} + +void +RADEONSaveBIOSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->bios_4_scratch = INREG(RADEON_BIOS_4_SCRATCH); + save->bios_5_scratch = INREG(RADEON_BIOS_5_SCRATCH); + save->bios_6_scratch = INREG(RADEON_BIOS_6_SCRATCH); +} + +/* Read CRTC registers */ +void +RADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); + save->crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); + save->crtc_h_total_disp = INREG(RADEON_CRTC_H_TOTAL_DISP); + save->crtc_h_sync_strt_wid = INREG(RADEON_CRTC_H_SYNC_STRT_WID); + save->crtc_v_total_disp = INREG(RADEON_CRTC_V_TOTAL_DISP); + save->crtc_v_sync_strt_wid = INREG(RADEON_CRTC_V_SYNC_STRT_WID); + + save->fp_h_sync_strt_wid = INREG(RADEON_FP_H_SYNC_STRT_WID); + save->fp_v_sync_strt_wid = INREG(RADEON_FP_V_SYNC_STRT_WID); + save->fp_crtc_h_total_disp = INREG(RADEON_FP_CRTC_H_TOTAL_DISP); + save->fp_crtc_v_total_disp = INREG(RADEON_FP_CRTC_V_TOTAL_DISP); + + save->crtc_offset = INREG(RADEON_CRTC_OFFSET); + save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL); + save->crtc_pitch = INREG(RADEON_CRTC_PITCH); + save->disp_merge_cntl = INREG(RADEON_DISP_MERGE_CNTL); + save->crtc_more_cntl = INREG(RADEON_CRTC_MORE_CNTL); + + if (IS_R300_VARIANT) + save->crtc_tile_x0_y0 = INREG(R300_CRTC_TILE_X0_Y0); + + if (info->IsDellServer) { + save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + save->dac2_cntl = INREG(RADEON_DAC_CNTL2); + save->disp_hw_debug = INREG (RADEON_DISP_HW_DEBUG); + save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + } + + /* track if the crtc is enabled for text restore */ + if (save->crtc_ext_cntl & RADEON_CRTC_DISPLAY_DIS) + info->crtc_on = FALSE; + else + info->crtc_on = TRUE; + +} + +/* Read CRTC2 registers */ +void +RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + save->crtc2_h_total_disp = INREG(RADEON_CRTC2_H_TOTAL_DISP); + save->crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); + save->crtc2_v_total_disp = INREG(RADEON_CRTC2_V_TOTAL_DISP); + save->crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); + save->crtc2_offset = INREG(RADEON_CRTC2_OFFSET); + save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); + save->crtc2_pitch = INREG(RADEON_CRTC2_PITCH); + + if (IS_R300_VARIANT) + save->crtc2_tile_x0_y0 = INREG(R300_CRTC2_TILE_X0_Y0); + + save->fp_h2_sync_strt_wid = INREG (RADEON_FP_H2_SYNC_STRT_WID); + save->fp_v2_sync_strt_wid = INREG (RADEON_FP_V2_SYNC_STRT_WID); + + if (info->ChipFamily == CHIP_FAMILY_RS400) { + save->rs480_unk_e30 = INREG(RADEON_RS480_UNK_e30); + save->rs480_unk_e34 = INREG(RADEON_RS480_UNK_e34); + save->rs480_unk_e38 = INREG(RADEON_RS480_UNK_e38); + save->rs480_unk_e3c = INREG(RADEON_RS480_UNK_e3c); + } + + save->disp2_merge_cntl = INREG(RADEON_DISP2_MERGE_CNTL); + + /* track if the crtc is enabled for text restore */ + if (save->crtc2_gen_cntl & RADEON_CRTC2_DISP_DIS) + info->crtc2_on = FALSE; + else + info->crtc2_on = TRUE; + +} + +/* Read PLL registers */ +void +RADEONSavePLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + 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_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Read: 0x%08x 0x%08x 0x%08x\n", + save->ppll_ref_div, + save->ppll_div_3, + (unsigned)save->htotal_cntl); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Read: rd=%d, fd=%d, pd=%d\n", + save->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + save->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, + (save->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); +} + +/* Read PLL registers */ +void +RADEONSavePLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + save->p2pll_ref_div = INPLL(pScrn, RADEON_P2PLL_REF_DIV); + save->p2pll_div_0 = INPLL(pScrn, RADEON_P2PLL_DIV_0); + save->htotal_cntl2 = INPLL(pScrn, RADEON_HTOTAL2_CNTL); + save->pixclks_cntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Read: 0x%08x 0x%08x 0x%08x\n", + (unsigned)save->p2pll_ref_div, + (unsigned)save->p2pll_div_0, + (unsigned)save->htotal_cntl2); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Read: rd=%u, fd=%u, pd=%u\n", + (unsigned)(save->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK), + (unsigned)(save->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK), + (unsigned)((save->p2pll_div_0 & RADEON_P2PLL_POST0_DIV_MASK) + >> 16)); +} void legacy_crtc_dpms(xf86CrtcPtr crtc, int mode) diff --git a/src/legacy_output.c b/src/legacy_output.c index 6f55ae2d..799aa2ea 100644 --- a/src/legacy_output.c +++ b/src/legacy_output.c @@ -53,6 +53,165 @@ static RADEONMonitorType radeon_detect_primary_dac(ScrnInfoPtr pScrn, Bool color static RADEONMonitorType radeon_detect_tv_dac(ScrnInfoPtr pScrn, Bool color); static RADEONMonitorType radeon_detect_ext_dac(ScrnInfoPtr pScrn); +void +RADEONRestoreDACRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + 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 | + RADEON_DAC_BLANKING); + + OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); + + 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_TV_OUT_CNTL, restore->disp_tv_out_cntl); + } else { + OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); + } + + OUTREG(RADEON_DAC_MACRO_CNTL, restore->dac_macro_cntl); + + /* R200 DAC connected via DVO */ + if (info->ChipFamily == CHIP_FAMILY_R200) + OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); +} + + +/* Write TMDS registers */ +void +RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_TMDS_PLL_CNTL, restore->tmds_pll_cntl); + OUTREG(RADEON_TMDS_TRANSMITTER_CNTL,restore->tmds_transmitter_cntl); + OUTREG(RADEON_FP_GEN_CNTL, restore->fp_gen_cntl); + + /* old AIW Radeon has some BIOS initialization problem + * with display buffer underflow, only occurs to DFP + */ + if (!pRADEONEnt->HasCRTC2) + OUTREG(RADEON_GRPH_BUFFER_CNTL, + INREG(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); + +} + +/* Write FP2 registers */ +void +RADEONRestoreFP2Registers(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); + +} + +/* Write RMX registers */ +void +RADEONRestoreRMXRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_FP_HORZ_STRETCH, restore->fp_horz_stretch); + OUTREG(RADEON_FP_VERT_STRETCH, restore->fp_vert_stretch); + +} + +/* Write LVDS registers */ +void +RADEONRestoreLVDSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (info->IsMobility) { + OUTREG(RADEON_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + OUTREG(RADEON_LVDS_PLL_CNTL, restore->lvds_pll_cntl); + + if (info->ChipFamily == CHIP_FAMILY_RV410) { + OUTREG(RADEON_CLOCK_CNTL_INDEX, 0); + } + } + +} + +void +RADEONRestoreBIOSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 bios_5_scratch = INREG(RADEON_BIOS_5_SCRATCH); + CARD32 bios_6_scratch = INREG(RADEON_BIOS_6_SCRATCH); + + OUTREG(RADEON_BIOS_4_SCRATCH, restore->bios_4_scratch); + bios_5_scratch &= 0xF; + bios_5_scratch |= (restore->bios_5_scratch & ~0xF); + OUTREG(RADEON_BIOS_5_SCRATCH, bios_5_scratch); + if (restore->bios_6_scratch & 0x40000000) + bios_6_scratch |= 0x40000000; + else + bios_6_scratch &= ~0x40000000; + OUTREG(RADEON_BIOS_6_SCRATCH, bios_6_scratch); + +} + +void +RADEONSaveDACRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->dac_cntl = INREG(RADEON_DAC_CNTL); + save->dac2_cntl = INREG(RADEON_DAC_CNTL2); + save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + save->disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); + 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 */ +void +RADEONSaveFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->fp_gen_cntl = INREG(RADEON_FP_GEN_CNTL); + save->fp2_gen_cntl = INREG (RADEON_FP2_GEN_CNTL); + save->fp_horz_stretch = INREG(RADEON_FP_HORZ_STRETCH); + save->fp_vert_stretch = INREG(RADEON_FP_VERT_STRETCH); + save->lvds_gen_cntl = INREG(RADEON_LVDS_GEN_CNTL); + save->lvds_pll_cntl = INREG(RADEON_LVDS_PLL_CNTL); + save->tmds_pll_cntl = INREG(RADEON_TMDS_PLL_CNTL); + save->tmds_transmitter_cntl= INREG(RADEON_TMDS_TRANSMITTER_CNTL); + + if (info->ChipFamily == CHIP_FAMILY_RV280) { + /* bit 22 of TMDS_PLL_CNTL is read-back inverted */ + save->tmds_pll_cntl ^= (1 << 22); + } +} + Bool RADEONDVOReadByte(I2CDevPtr dvo, int addr, CARD8 *ch) diff --git a/src/radeon.h b/src/radeon.h index 47e1b890..5c15888a 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -902,8 +902,6 @@ extern void RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save, DisplayModePtr mode, BOOL IsPrimary); extern void RADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore); -extern void RADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore); -extern void RADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore); #ifdef XF86DRI #ifdef USE_XAA diff --git a/src/radeon_driver.c b/src/radeon_driver.c index 7b9cd85a..1662e04e 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -125,11 +125,9 @@ static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); #endif -DisplayModePtr +extern DisplayModePtr RADEONCrtcFindClosestMode(xf86CrtcPtr crtc, DisplayModePtr pMode); -static void RADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests, - unsigned nWaitLoops, unsigned cntThreshold); static const OptionInfoRec RADEONOptions[] = { { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, @@ -3910,820 +3908,6 @@ static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) } #endif -/* Write common registers */ -void RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn, - RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - if (info->IsSecondary) - return; - - OUTREG(RADEON_OVR_CLR, restore->ovr_clr); - OUTREG(RADEON_OVR_WID_LEFT_RIGHT, restore->ovr_wid_left_right); - OUTREG(RADEON_OVR_WID_TOP_BOTTOM, restore->ovr_wid_top_bottom); - OUTREG(RADEON_OV0_SCALE_CNTL, restore->ov0_scale_cntl); - OUTREG(RADEON_SUBPIC_CNTL, restore->subpic_cntl); - OUTREG(RADEON_VIPH_CONTROL, restore->viph_control); - OUTREG(RADEON_I2C_CNTL_1, restore->i2c_cntl_1); - OUTREG(RADEON_GEN_INT_CNTL, restore->gen_int_cntl); - OUTREG(RADEON_CAP0_TRIG_CNTL, restore->cap0_trig_cntl); - OUTREG(RADEON_CAP1_TRIG_CNTL, restore->cap1_trig_cntl); - OUTREG(RADEON_BUS_CNTL, restore->bus_cntl); - OUTREG(RADEON_SURFACE_CNTL, restore->surface_cntl); - - /* Workaround for the VT switching problem in dual-head mode. This - * problem only occurs on RV style chips, typically when a FP and - * CRT are connected. - */ - if (pRADEONEnt->HasCRTC2 && - info->ChipFamily != CHIP_FAMILY_R200 && - !IS_R300_VARIANT) { - CARD32 tmp; - - tmp = INREG(RADEON_DAC_CNTL2); - OUTREG(RADEON_DAC_CNTL2, tmp & ~RADEON_DAC2_DAC_CLK_SEL); - usleep(100000); - } -} - -void RADEONRestoreDACRegisters(ScrnInfoPtr pScrn, - RADEONSavePtr restore) -{ - 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 | - RADEON_DAC_BLANKING); - - OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); - - 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_TV_OUT_CNTL, restore->disp_tv_out_cntl); - } else { - OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); - } - - OUTREG(RADEON_DAC_MACRO_CNTL, restore->dac_macro_cntl); - - /* R200 DAC connected via DVO */ - if (info->ChipFamily == CHIP_FAMILY_R200) - OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); -} - -/* Write CRTC registers */ -void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, - RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Programming CRTC1, offset: 0x%08x\n", - (unsigned)restore->crtc_offset); - - /* We prevent the CRTC from hitting the memory controller until - * fully programmed - */ - OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl | - RADEON_CRTC_DISP_REQ_EN_B); - - OUTREGP(RADEON_CRTC_EXT_CNTL, - restore->crtc_ext_cntl, - RADEON_CRTC_VSYNC_DIS | - RADEON_CRTC_HSYNC_DIS | - RADEON_CRTC_DISPLAY_DIS); - - OUTREG(RADEON_CRTC_H_TOTAL_DISP, restore->crtc_h_total_disp); - OUTREG(RADEON_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid); - OUTREG(RADEON_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); - OUTREG(RADEON_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid); - - OUTREG(RADEON_FP_H_SYNC_STRT_WID, restore->fp_h_sync_strt_wid); - OUTREG(RADEON_FP_V_SYNC_STRT_WID, restore->fp_v_sync_strt_wid); - OUTREG(RADEON_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp); - OUTREG(RADEON_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp); - - if (IS_R300_VARIANT) - OUTREG(R300_CRTC_TILE_X0_Y0, restore->crtc_tile_x0_y0); - OUTREG(RADEON_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); - OUTREG(RADEON_CRTC_OFFSET, restore->crtc_offset); - - OUTREG(RADEON_CRTC_PITCH, restore->crtc_pitch); - OUTREG(RADEON_DISP_MERGE_CNTL, restore->disp_merge_cntl); - OUTREG(RADEON_CRTC_MORE_CNTL, restore->crtc_more_cntl); - - if (info->IsDellServer) { - OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); - OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); - OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); - OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl); - } - - OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl); -} - -/* Write CRTC2 registers */ -void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, - RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - /* CARD32 crtc2_gen_cntl;*/ - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Programming CRTC2, offset: 0x%08x\n", - (unsigned)restore->crtc2_offset); - - /* We prevent the CRTC from hitting the memory controller until - * fully programmed - */ - OUTREG(RADEON_CRTC2_GEN_CNTL, - restore->crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS | - RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS | - RADEON_CRTC2_DISP_REQ_EN_B); - - OUTREG(RADEON_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp); - OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid); - OUTREG(RADEON_CRTC2_V_TOTAL_DISP, restore->crtc2_v_total_disp); - OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid); - - OUTREG(RADEON_FP_H2_SYNC_STRT_WID, restore->fp_h2_sync_strt_wid); - OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp_v2_sync_strt_wid); - - if (IS_R300_VARIANT) - OUTREG(R300_CRTC2_TILE_X0_Y0, restore->crtc2_tile_x0_y0); - OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); - OUTREG(RADEON_CRTC2_OFFSET, restore->crtc2_offset); - - OUTREG(RADEON_CRTC2_PITCH, restore->crtc2_pitch); - OUTREG(RADEON_DISP2_MERGE_CNTL, restore->disp2_merge_cntl); - - if (info->ChipFamily == CHIP_FAMILY_RS400) { - OUTREG(RADEON_RS480_UNK_e30, restore->rs480_unk_e30); - OUTREG(RADEON_RS480_UNK_e34, restore->rs480_unk_e34); - OUTREG(RADEON_RS480_UNK_e38, restore->rs480_unk_e38); - OUTREG(RADEON_RS480_UNK_e3c, restore->rs480_unk_e3c); - } - OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl); - -} - -/* Write TMDS registers */ -void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - OUTREG(RADEON_TMDS_PLL_CNTL, restore->tmds_pll_cntl); - OUTREG(RADEON_TMDS_TRANSMITTER_CNTL,restore->tmds_transmitter_cntl); - OUTREG(RADEON_FP_GEN_CNTL, restore->fp_gen_cntl); - - /* old AIW Radeon has some BIOS initialization problem - * with display buffer underflow, only occurs to DFP - */ - if (!pRADEONEnt->HasCRTC2) - OUTREG(RADEON_GRPH_BUFFER_CNTL, - INREG(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); - -} - -/* Write FP2 registers */ -void RADEONRestoreFP2Registers(ScrnInfoPtr pScrn, RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); - -} - -/* Write RMX registers */ -void RADEONRestoreRMXRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - OUTREG(RADEON_FP_HORZ_STRETCH, restore->fp_horz_stretch); - OUTREG(RADEON_FP_VERT_STRETCH, restore->fp_vert_stretch); - -} - -/* Write LVDS registers */ -void RADEONRestoreLVDSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - if (info->IsMobility) { - OUTREG(RADEON_LVDS_GEN_CNTL, restore->lvds_gen_cntl); - OUTREG(RADEON_LVDS_PLL_CNTL, restore->lvds_pll_cntl); - - if (info->ChipFamily == CHIP_FAMILY_RV410) { - OUTREG(RADEON_CLOCK_CNTL_INDEX, 0); - } - } - -} - -void RADEONRestoreBIOSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - CARD32 bios_5_scratch = INREG(RADEON_BIOS_5_SCRATCH); - CARD32 bios_6_scratch = INREG(RADEON_BIOS_6_SCRATCH); - - OUTREG(RADEON_BIOS_4_SCRATCH, restore->bios_4_scratch); - bios_5_scratch &= 0xF; - bios_5_scratch |= (restore->bios_5_scratch & ~0xF); - OUTREG(RADEON_BIOS_5_SCRATCH, bios_5_scratch); - if (restore->bios_6_scratch & 0x40000000) - bios_6_scratch |= 0x40000000; - else - bios_6_scratch &= ~0x40000000; - OUTREG(RADEON_BIOS_6_SCRATCH, bios_6_scratch); - -} - -/* 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; - int i = 0; - - 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); - if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) - break; - i++; - } - while (i < 10000); - /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/ - - OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); -} - -/* 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); - if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) - break; - i++; - } - while (i < 10000); - /*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 */ -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); - - 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 ]); - RADEONWriteTVFIFO(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 */ -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); -} - -/* 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_ASYNC_RST - | RADEON_CRT_ASYNC_RST - | 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)); - - ErrorF("Restore TV Restarts\n"); - RADEONRestoreTVRestarts(pScrn, restore); - - ErrorF("Restore Timing Tables\n"); - RADEONRestoreTVTimingTables(pScrn, restore); - - - OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl - | RADEON_TV_ASYNC_RST)); - - ErrorF("Restore TV standard\n"); - RADEONRestoreTVOutputStd(pScrn, restore); - - OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); - - OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings); - OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings); - - OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); - - ErrorF("Leaving Restore TV\n"); -} - -static void RADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn) -{ - int i = 0; - - /* FIXME: Certain revisions of R300 can't recover here. Not sure of - the cause yet, but this workaround will mask the problem for now. - Other chips usually will pass at the very first test, so the - workaround shouldn't have any effect on them. */ - for (i = 0; - (i < 10000 && - INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); - i++); -} - -static void RADEONPLLWriteUpdate(ScrnInfoPtr pScrn) -{ - while (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); - - OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, - RADEON_PPLL_ATOMIC_UPDATE_W, - ~(RADEON_PPLL_ATOMIC_UPDATE_W)); -} - -static void RADEONPLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn) -{ - int i = 0; - - /* FIXME: Certain revisions of R300 can't recover here. Not sure of - the cause yet, but this workaround will mask the problem for now. - Other chips usually will pass at the very first test, so the - workaround shouldn't have any effect on them. */ - for (i = 0; - (i < 10000 && - INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); - i++); -} - -static void RADEONPLL2WriteUpdate(ScrnInfoPtr pScrn) -{ - while (INPLL(pScrn, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); - - OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV, - RADEON_P2PLL_ATOMIC_UPDATE_W, - ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); -} - -static CARD8 RADEONComputePLLGain(CARD16 reference_freq, CARD16 ref_div, - CARD16 fb_div) -{ - unsigned vcoFreq; - - if (!ref_div) - return 1; - - 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; -} - -/* 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) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - CARD8 pllGain; - -#if defined(__powerpc__) - /* apparently restoring the pll causes a hang??? */ - if (info->MacModel == RADEON_MAC_IBOOK) - return; -#endif - - 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. - This appears to related to the PLL divider registers (fail to lock?). - It occurs even when all dividers are the same with their old settings. - In this case we really don't need to fiddle with PLL registers. - By doing this we can avoid the blanking problem with some panels. - */ - if ((restore->ppll_ref_div == (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && - (restore->ppll_div_3 == (INPLL(pScrn, RADEON_PPLL_DIV_3) & - (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { - OUTREGP(RADEON_CLOCK_CNTL_INDEX, - RADEON_PLL_DIV_SEL, - ~(RADEON_PLL_DIV_SEL)); - RADEONPllErrataAfterIndex(info); - return; - } - } - - OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, - RADEON_VCLK_SRC_SEL_CPUCLK, - ~(RADEON_VCLK_SRC_SEL_MASK)); - - OUTPLLP(pScrn, - RADEON_PPLL_CNTL, - RADEON_PPLL_RESET - | RADEON_PPLL_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_PVG_MASK)); - - OUTREGP(RADEON_CLOCK_CNTL_INDEX, - RADEON_PLL_DIV_SEL, - ~(RADEON_PLL_DIV_SEL)); - RADEONPllErrataAfterIndex(info); - - if (IS_R300_VARIANT || - (info->ChipFamily == CHIP_FAMILY_RS300) || - (info->ChipFamily == CHIP_FAMILY_RS400)) { - if (restore->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { - /* When restoring console mode, use saved PPLL_REF_DIV - * setting. - */ - OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, - restore->ppll_ref_div, - 0); - } else { - /* R300 uses ref_div_acc field as real ref divider */ - OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, - (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), - ~R300_PPLL_REF_DIV_ACC_MASK); - } - } else { - OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, - restore->ppll_ref_div, - ~RADEON_PPLL_REF_DIV_MASK); - } - - OUTPLLP(pScrn, RADEON_PPLL_DIV_3, - restore->ppll_div_3, - ~RADEON_PPLL_FB3_DIV_MASK); - - OUTPLLP(pScrn, RADEON_PPLL_DIV_3, - restore->ppll_div_3, - ~RADEON_PPLL_POST3_DIV_MASK); - - RADEONPLLWriteUpdate(pScrn); - RADEONPLLWaitForReadUpdateComplete(pScrn); - - OUTPLL(pScrn, RADEON_HTOTAL_CNTL, restore->htotal_cntl); - - OUTPLLP(pScrn, RADEON_PPLL_CNTL, - 0, - ~(RADEON_PPLL_RESET - | RADEON_PPLL_SLEEP - | RADEON_PPLL_ATOMIC_UPDATE_EN - | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", - restore->ppll_ref_div, - restore->ppll_div_3, - (unsigned)restore->htotal_cntl, - INPLL(pScrn, RADEON_PPLL_CNTL)); - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Wrote: rd=%d, fd=%d, pd=%d\n", - restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, - restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, - (restore->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); - - usleep(50000); /* Let the clock to lock */ - - OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, - RADEON_VCLK_SRC_SEL_PPLLCLK, - ~(RADEON_VCLK_SRC_SEL_MASK)); - - /*OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, restore->vclk_ecp_cntl);*/ - - ErrorF("finished PLL1\n"); - -} - - -/* Write PLL2 registers */ -void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, - 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)); - - OUTPLLP(pScrn, - RADEON_P2PLL_CNTL, - RADEON_P2PLL_RESET - | RADEON_P2PLL_ATOMIC_UPDATE_EN - | ((CARD32)pllGain << RADEON_P2PLL_PVG_SHIFT), - ~(RADEON_P2PLL_RESET - | RADEON_P2PLL_ATOMIC_UPDATE_EN - | RADEON_P2PLL_PVG_MASK)); - - - OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV, - restore->p2pll_ref_div, - ~RADEON_P2PLL_REF_DIV_MASK); - - OUTPLLP(pScrn, RADEON_P2PLL_DIV_0, - restore->p2pll_div_0, - ~RADEON_P2PLL_FB0_DIV_MASK); - - OUTPLLP(pScrn, RADEON_P2PLL_DIV_0, - restore->p2pll_div_0, - ~RADEON_P2PLL_POST0_DIV_MASK); - - RADEONPLL2WriteUpdate(pScrn); - RADEONPLL2WaitForReadUpdateComplete(pScrn); - - OUTPLL(pScrn, RADEON_HTOTAL2_CNTL, restore->htotal_cntl2); - - OUTPLLP(pScrn, RADEON_P2PLL_CNTL, - 0, - ~(RADEON_P2PLL_RESET - | RADEON_P2PLL_SLEEP - | RADEON_P2PLL_ATOMIC_UPDATE_EN)); - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", - (unsigned)restore->p2pll_ref_div, - (unsigned)restore->p2pll_div_0, - (unsigned)restore->htotal_cntl2, - INPLL(pScrn, RADEON_P2PLL_CNTL)); - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Wrote2: rd=%u, fd=%u, pd=%u\n", - (unsigned)restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, - (unsigned)restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK, - (unsigned)((restore->p2pll_div_0 & - RADEON_P2PLL_POST0_DIV_MASK) >>16)); - - usleep(5000); /* Let the clock to lock */ - - OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, - RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, - ~(RADEON_PIX2CLK_SRC_SEL_MASK)); - - OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl); - - ErrorF("finished PLL2\n"); - -} - - /* restore original surface info (for fb console). */ static void RADEONRestoreSurfaces(ScrnInfoPtr pScrn, RADEONSavePtr restore) { @@ -4922,289 +4106,6 @@ static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) } } -/* Read common registers */ -static void RADEONSaveCommonRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - save->ovr_clr = INREG(RADEON_OVR_CLR); - save->ovr_wid_left_right = INREG(RADEON_OVR_WID_LEFT_RIGHT); - save->ovr_wid_top_bottom = INREG(RADEON_OVR_WID_TOP_BOTTOM); - save->ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL); - save->subpic_cntl = INREG(RADEON_SUBPIC_CNTL); - save->viph_control = INREG(RADEON_VIPH_CONTROL); - save->i2c_cntl_1 = INREG(RADEON_I2C_CNTL_1); - save->gen_int_cntl = INREG(RADEON_GEN_INT_CNTL); - save->cap0_trig_cntl = INREG(RADEON_CAP0_TRIG_CNTL); - save->cap1_trig_cntl = INREG(RADEON_CAP1_TRIG_CNTL); - save->bus_cntl = INREG(RADEON_BUS_CNTL); - save->surface_cntl = INREG(RADEON_SURFACE_CNTL); - save->grph_buffer_cntl = INREG(RADEON_GRPH_BUFFER_CNTL); - save->grph2_buffer_cntl = INREG(RADEON_GRPH2_BUFFER_CNTL); -} - -/* Read CRTC registers */ -static void RADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - save->crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); - save->crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); - save->crtc_h_total_disp = INREG(RADEON_CRTC_H_TOTAL_DISP); - save->crtc_h_sync_strt_wid = INREG(RADEON_CRTC_H_SYNC_STRT_WID); - save->crtc_v_total_disp = INREG(RADEON_CRTC_V_TOTAL_DISP); - save->crtc_v_sync_strt_wid = INREG(RADEON_CRTC_V_SYNC_STRT_WID); - - save->fp_h_sync_strt_wid = INREG(RADEON_FP_H_SYNC_STRT_WID); - save->fp_v_sync_strt_wid = INREG(RADEON_FP_V_SYNC_STRT_WID); - save->fp_crtc_h_total_disp = INREG(RADEON_FP_CRTC_H_TOTAL_DISP); - save->fp_crtc_v_total_disp = INREG(RADEON_FP_CRTC_V_TOTAL_DISP); - - save->crtc_offset = INREG(RADEON_CRTC_OFFSET); - save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL); - save->crtc_pitch = INREG(RADEON_CRTC_PITCH); - save->disp_merge_cntl = INREG(RADEON_DISP_MERGE_CNTL); - save->crtc_more_cntl = INREG(RADEON_CRTC_MORE_CNTL); - - if (IS_R300_VARIANT) - save->crtc_tile_x0_y0 = INREG(R300_CRTC_TILE_X0_Y0); - - if (info->IsDellServer) { - save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); - save->dac2_cntl = INREG(RADEON_DAC_CNTL2); - save->disp_hw_debug = INREG (RADEON_DISP_HW_DEBUG); - save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); - } - - /* track if the crtc is enabled for text restore */ - if (save->crtc_ext_cntl & RADEON_CRTC_DISPLAY_DIS) - info->crtc_on = FALSE; - else - info->crtc_on = TRUE; - -} - -/* Read DAC registers */ -static void RADEONSaveDACRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - save->dac_cntl = INREG(RADEON_DAC_CNTL); - save->dac2_cntl = INREG(RADEON_DAC_CNTL2); - save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); - save->disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); - 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); - -} - -static void RADEONSaveBIOSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - save->bios_4_scratch = INREG(RADEON_BIOS_4_SCRATCH); - save->bios_5_scratch = INREG(RADEON_BIOS_5_SCRATCH); - save->bios_6_scratch = INREG(RADEON_BIOS_6_SCRATCH); -} - -/* Read flat panel registers */ -static void RADEONSaveFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - save->fp_gen_cntl = INREG(RADEON_FP_GEN_CNTL); - save->fp2_gen_cntl = INREG (RADEON_FP2_GEN_CNTL); - save->fp_horz_stretch = INREG(RADEON_FP_HORZ_STRETCH); - save->fp_vert_stretch = INREG(RADEON_FP_VERT_STRETCH); - save->lvds_gen_cntl = INREG(RADEON_LVDS_GEN_CNTL); - save->lvds_pll_cntl = INREG(RADEON_LVDS_PLL_CNTL); - save->tmds_pll_cntl = INREG(RADEON_TMDS_PLL_CNTL); - save->tmds_transmitter_cntl= INREG(RADEON_TMDS_TRANSMITTER_CNTL); - - if (info->ChipFamily == CHIP_FAMILY_RV280) { - /* bit 22 of TMDS_PLL_CNTL is read-back inverted */ - save->tmds_pll_cntl ^= (1 << 22); - } -} - -/* Read CRTC2 registers */ -static void RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); - save->crtc2_h_total_disp = INREG(RADEON_CRTC2_H_TOTAL_DISP); - save->crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); - save->crtc2_v_total_disp = INREG(RADEON_CRTC2_V_TOTAL_DISP); - save->crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); - save->crtc2_offset = INREG(RADEON_CRTC2_OFFSET); - save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); - save->crtc2_pitch = INREG(RADEON_CRTC2_PITCH); - - if (IS_R300_VARIANT) - save->crtc2_tile_x0_y0 = INREG(R300_CRTC2_TILE_X0_Y0); - - save->fp_h2_sync_strt_wid = INREG (RADEON_FP_H2_SYNC_STRT_WID); - save->fp_v2_sync_strt_wid = INREG (RADEON_FP_V2_SYNC_STRT_WID); - - if (info->ChipFamily == CHIP_FAMILY_RS400) { - save->rs480_unk_e30 = INREG(RADEON_RS480_UNK_e30); - save->rs480_unk_e34 = INREG(RADEON_RS480_UNK_e34); - save->rs480_unk_e38 = INREG(RADEON_RS480_UNK_e38); - save->rs480_unk_e3c = INREG(RADEON_RS480_UNK_e3c); - } - - save->disp2_merge_cntl = INREG(RADEON_DISP2_MERGE_CNTL); - - /* track if the crtc is enabled for text restore */ - if (save->crtc2_gen_cntl & RADEON_CRTC2_DISP_DIS) - info->crtc2_on = FALSE; - else - info->crtc2_on = TRUE; - -} - -/* 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, (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"); - - 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; - - 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); - save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1); - - ErrorF("Save TV timing tables\n"); - - RADEONSaveTVTimingTables(pScrn, save); - - ErrorF("TV Save done\n"); -} - -/* Read PLL registers */ -static void RADEONSavePLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - 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_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Read: 0x%08x 0x%08x 0x%08x\n", - save->ppll_ref_div, - save->ppll_div_3, - (unsigned)save->htotal_cntl); - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Read: rd=%d, fd=%d, pd=%d\n", - save->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, - save->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, - (save->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); -} - -/* Read PLL registers */ -static void RADEONSavePLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - save->p2pll_ref_div = INPLL(pScrn, RADEON_P2PLL_REF_DIV); - save->p2pll_div_0 = INPLL(pScrn, RADEON_P2PLL_DIV_0); - save->htotal_cntl2 = INPLL(pScrn, RADEON_HTOTAL2_CNTL); - save->pixclks_cntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Read: 0x%08x 0x%08x 0x%08x\n", - (unsigned)save->p2pll_ref_div, - (unsigned)save->p2pll_div_0, - (unsigned)save->htotal_cntl2); - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Read: rd=%u, fd=%u, pd=%u\n", - (unsigned)(save->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK), - (unsigned)(save->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK), - (unsigned)((save->p2pll_div_0 & RADEON_P2PLL_POST0_DIV_MASK) - >> 16)); -} #if 0 /* Read palette data */ @@ -5228,7 +4129,8 @@ static void RADEONSavePalette(ScrnInfoPtr pScrn, RADEONSavePtr save) } #endif -void avivo_save(ScrnInfoPtr pScrn, RADEONSavePtr save) +void +avivo_save(ScrnInfoPtr pScrn, RADEONSavePtr save) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; @@ -5382,7 +4284,8 @@ void avivo_save(ScrnInfoPtr pScrn, RADEONSavePtr save) } -void avivo_restore(ScrnInfoPtr pScrn, RADEONSavePtr restore) +void +avivo_restore(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; diff --git a/src/radeon_tv.c b/src/radeon_tv.c index 5e9a9c8f..99592954 100644 --- a/src/radeon_tv.c +++ b/src/radeon_tv.c @@ -180,6 +180,401 @@ static long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; +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 to TV FIFO RAM */ +static void +RADEONWriteTVFIFO(ScrnInfoPtr pScrn, CARD16 addr, + CARD32 value) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 tmp; + int i = 0; + + 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); + if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) + break; + i++; + } + while (i < 10000); + /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/ + + OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); +} + +/* 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); + if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) + break; + i++; + } + while (i < 10000); + /*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); + + 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 ]); + RADEONWriteTVFIFO(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); +} + +/* 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_ASYNC_RST + | RADEON_CRT_ASYNC_RST + | 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)); + + ErrorF("Restore TV Restarts\n"); + RADEONRestoreTVRestarts(pScrn, restore); + + ErrorF("Restore Timing Tables\n"); + RADEONRestoreTVTimingTables(pScrn, restore); + + + OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl + | RADEON_TV_ASYNC_RST)); + + ErrorF("Restore TV standard\n"); + RADEONRestoreTVOutputStd(pScrn, restore); + + OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); + + OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings); + OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings); + + OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); + + ErrorF("Leaving Restore TV\n"); +} + +/* 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, (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"); + + 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 */ +void +RADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + 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); + save->tv_pll_cntl1 = INPLL(pScrn, RADEON_TV_PLL_CNTL1); + + ErrorF("Save TV timing tables\n"); + + RADEONSaveTVTimingTables(pScrn, save); + + ErrorF("TV Save done\n"); +} + + /* Compute F,V,H restarts from default restart position and hPos & vPos * Return TRUE when code timing table was changed */ |