summaryrefslogtreecommitdiff
path: root/src/radeon_pm.c
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2009-05-19 17:11:34 -0400
committerAlex Deucher <alexdeucher@gmail.com>2009-05-19 17:23:20 -0400
commit88a9e98341d96e5e7f48b69aed597d1bada6313a (patch)
treee2d85ca5dd8e0ec754d1277e5564c6b66dc881cc /src/radeon_pm.c
parent1429133ffdbfe046249fcaaa4cbee432a1012e55 (diff)
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.
Diffstat (limited to 'src/radeon_pm.c')
-rw-r--r--src/radeon_pm.c147
1 files changed, 106 insertions, 41 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)