summaryrefslogtreecommitdiff
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
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.
-rw-r--r--src/radeon_pm.c147
-rw-r--r--src/radeon_reg.h16
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