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