From 88a9e98341d96e5e7f48b69aed597d1bada6313a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 May 2009 17:11:34 -0400 Subject: Pre-atom: Improve engine clock setup code Also remove SetMemoryClk() for pre-atom cards for now as it requires quite a bit more asic specific work. To set the mclk we'll need to use the mem reset/dll tables in the bios. --- src/radeon_pm.c | 147 +++++++++++++++++++++++++++++++++++++++---------------- src/radeon_reg.h | 16 ++++-- 2 files changed, 119 insertions(+), 44 deletions(-) diff --git a/src/radeon_pm.c b/src/radeon_pm.c index 5267fbc3..131a9fd4 100644 --- a/src/radeon_pm.c +++ b/src/radeon_pm.c @@ -38,66 +38,131 @@ #include "radeon_macros.h" #include "radeon_atombios.h" -static int calc_div(uint32_t num, uint32_t den) +/* 10 khz */ +static uint32_t calc_eng_mem_clock(ScrnInfoPtr pScrn, + uint32_t req_clock, + int ref_div, + int *fb_div, + int *post_div) { - int div = (num + (den / 2)) / den; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPLLPtr pll = &info->pll; - if ((div < 2) || (div > 0xff)) - return 0; - else - return div; + if (req_clock < 15000) { + *post_div = 8; + req_clock *= 8; + } else if (req_clock < 30000) { + *post_div = 4; + req_clock *= 4; + } else if (req_clock < 60000) { + *post_div = 2; + req_clock *= 2; + } else + *post_div = 1; + + req_clock *= ref_div; + req_clock += pll->reference_freq; + req_clock /= (2 * pll->reference_freq); + + *fb_div = req_clock & 0xff; + + req_clock = (req_clock & 0xffff) << 1; + req_clock *= pll->reference_freq; + req_clock /= ref_div; + req_clock /= *post_div; + + return req_clock; } -/* 10 khz */ static void RADEONSetEngineClock(ScrnInfoPtr pScrn, uint32_t eng_clock) { - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONPLLPtr pll = &info->pll; - uint32_t ref_div, fb_div; - uint32_t m_spll_ref_fb_div; + uint32_t tmp; + int ref_div, fb_div, post_div; RADEONWaitForIdleMMIO(pScrn); - m_spll_ref_fb_div = INPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV); - ref_div = m_spll_ref_fb_div & RADEON_M_SPLL_REF_DIV_MASK; - fb_div = calc_div(eng_clock * ref_div, pll->reference_freq); + tmp = INPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV); + ref_div = tmp & RADEON_M_SPLL_REF_DIV_MASK; - if (!fb_div) - return; + eng_clock = calc_eng_mem_clock(pScrn, eng_clock, ref_div, &fb_div, &post_div); - m_spll_ref_fb_div &= ~(RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT); - m_spll_ref_fb_div |= (fb_div & RADEON_SPLL_FB_DIV_MASK) << RADEON_SPLL_FB_DIV_SHIFT; - OUTPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV, m_spll_ref_fb_div); - usleep(16000); /* Let the pll settle */ -} + tmp = INPLL(pScrn, RADEON_CLK_PIN_CNTL); + tmp &= ~RADEON_DONT_USE_XTALIN; + OUTPLL(pScrn, RADEON_CLK_PIN_CNTL, tmp); -/* 10 khz */ -static void -RADEONSetMemoryClock(ScrnInfoPtr pScrn, uint32_t mem_clock) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONPLLPtr pll = &info->pll; - uint32_t ref_div, fb_div; - uint32_t m_spll_ref_fb_div; + tmp = INPLL(pScrn, RADEON_SCLK_CNTL); + tmp &= ~RADEON_SCLK_SRC_SEL_MASK; + OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp); - if (info->IsIGP) - return; + usleep(10); - RADEONWaitForIdleMMIO(pScrn); + tmp = INPLL(pScrn, RADEON_SPLL_CNTL); + tmp |= RADEON_SPLL_SLEEP; + OUTPLL(pScrn, RADEON_SPLL_CNTL, tmp); - m_spll_ref_fb_div = INPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV); - ref_div = m_spll_ref_fb_div & RADEON_M_SPLL_REF_DIV_MASK; - fb_div = calc_div(mem_clock * ref_div, pll->reference_freq); + usleep(2); - if (!fb_div) - return; + tmp = INPLL(pScrn, RADEON_SPLL_CNTL); + tmp |= RADEON_SPLL_RESET; + OUTPLL(pScrn, RADEON_SPLL_CNTL, tmp); + + usleep(200); + + tmp = INPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV); + tmp &= ~(RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT); + tmp |= (fb_div & RADEON_SPLL_FB_DIV_MASK) << RADEON_SPLL_FB_DIV_SHIFT; + OUTPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV, tmp); + + /* XXX: verify on different asics */ + tmp = INPLL(pScrn, RADEON_SPLL_CNTL); + tmp &= ~RADEON_SPLL_PVG_MASK; + if ((eng_clock * post_div) >= 90000) + tmp |= (0x7 << RADEON_SPLL_PVG_SHIFT); + else + tmp |= (0x4 << RADEON_SPLL_PVG_SHIFT); + OUTPLL(pScrn, RADEON_SPLL_CNTL, tmp); + + tmp = INPLL(pScrn, RADEON_SPLL_CNTL); + tmp &= ~RADEON_SPLL_SLEEP; + OUTPLL(pScrn, RADEON_SPLL_CNTL, tmp); + + usleep(2); + + tmp = INPLL(pScrn, RADEON_SPLL_CNTL); + tmp &= ~RADEON_SPLL_RESET; + OUTPLL(pScrn, RADEON_SPLL_CNTL, tmp); + + usleep(200); + + tmp = INPLL(pScrn, RADEON_SCLK_CNTL); + tmp &= ~RADEON_SCLK_SRC_SEL_MASK; + switch (post_div) { + case 1: + default: + tmp |= 1; + break; + case 2: + tmp |= 2; + break; + case 4: + tmp |= 3; + break; + case 8: + tmp |= 4; + break; + } + OUTPLL(pScrn, RADEON_SCLK_CNTL, tmp); + + usleep(20); + + tmp = INPLL(pScrn, RADEON_CLK_PIN_CNTL); + tmp |= RADEON_DONT_USE_XTALIN; + OUTPLL(pScrn, RADEON_CLK_PIN_CNTL, tmp); + + usleep(10); - m_spll_ref_fb_div &= ~(RADEON_MPLL_FB_DIV_MASK << RADEON_MPLL_FB_DIV_SHIFT); - m_spll_ref_fb_div |= (fb_div & RADEON_MPLL_FB_DIV_MASK) << RADEON_MPLL_FB_DIV_SHIFT; - OUTPLL(pScrn, RADEON_M_SPLL_REF_FB_DIV, m_spll_ref_fb_div); - usleep(16000); /* Let the pll settle */ } static void LegacySetClockGating(ScrnInfoPtr pScrn, Bool enable) diff --git a/src/radeon_reg.h b/src/radeon_reg.h index 9261b39d..8da513b9 100644 --- a/src/radeon_reg.h +++ b/src/radeon_reg.h @@ -305,20 +305,30 @@ #define RADEON_CAPABILITIES_ID 0x0f50 /* PCI */ #define RADEON_CAPABILITIES_PTR 0x0f34 /* PCI */ #define RADEON_CLK_PIN_CNTL 0x0001 /* PLL */ +# define RADEON_DONT_USE_XTALIN (1 << 4) # define RADEON_SCLK_DYN_START_CNTL (1 << 15) #define RADEON_CLOCK_CNTL_DATA 0x000c #define RADEON_CLOCK_CNTL_INDEX 0x0008 # define RADEON_PLL_WR_EN (1 << 7) # define RADEON_PLL_DIV_SEL (3 << 8) # define RADEON_PLL2_DIV_SEL_MASK ~(3 << 8) -#define RADEON_M_SPLL_REF_FB_DIV 0x000a +#define RADEON_M_SPLL_REF_FB_DIV 0x000a /* PLL */ # define RADEON_M_SPLL_REF_DIV_MASK 0xff # define RADEON_M_SPLL_REF_DIV_SHIFT 0 # define RADEON_MPLL_FB_DIV_MASK 0xff # define RADEON_MPLL_FB_DIV_SHIFT 8 # define RADEON_SPLL_FB_DIV_MASK 0xff # define RADEON_SPLL_FB_DIV_SHIFT 16 -#define RADEON_CLK_PWRMGT_CNTL 0x0014 +#define RADEON_SPLL_CNTL 0x000c /* PLL */ +# define RADEON_SPLL_SLEEP (1 << 0) +# define RADEON_SPLL_RESET (1 << 1) +# define RADEON_SPLL_PCP_MASK 0x7 +# define RADEON_SPLL_PCP_SHIFT 8 +# define RADEON_SPLL_PVG_MASK 0x7 +# define RADEON_SPLL_PVG_SHIFT 11 +# define RADEON_SPLL_PDC_MASK 0x3 +# define RADEON_SPLL_PDC_SHIFT 14 +#define RADEON_CLK_PWRMGT_CNTL 0x0014 /* PLL */ # define RADEON_ENGIN_DYNCLK_MODE (1 << 12) # define RADEON_ACTIVE_HILO_LAT_MASK (3 << 13) # define RADEON_ACTIVE_HILO_LAT_SHIFT 13 @@ -330,7 +340,7 @@ # define RADEON_DYN_STOP_MODE_MASK (7 << 21) # define RADEON_TVPLL_PWRMGT_OFF (1 << 30) # define RADEON_TVCLK_TURNOFF (1 << 31) -#define RADEON_PLL_PWRMGT_CNTL 0x0015 +#define RADEON_PLL_PWRMGT_CNTL 0x0015 /* PLL */ # define RADEON_TCL_BYPASS_DISABLE (1 << 20) #define RADEON_CLR_CMP_CLR_3D 0x1a24 #define RADEON_CLR_CMP_CLR_DST 0x15c8 -- cgit v1.2.3