From 11cca264ff57ad0b234bd1cd2c9a2366b967feb7 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Fri, 23 Apr 2010 15:32:50 +0000 Subject: i.MX31/Gigabeat S: Implement frequency and voltage scaling-- 1.6V for 528MHz, and 1.35V for 264MHz and 132MHz. Keep DPTC overdrive ( > 400MHz) voltage scaling off for now because of uncertainties. Simplify the (working) mess later. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25699 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/imx31/ccm-imx31.c | 62 ++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 15 deletions(-) (limited to 'firmware/target/arm/imx31/ccm-imx31.c') diff --git a/firmware/target/arm/imx31/ccm-imx31.c b/firmware/target/arm/imx31/ccm-imx31.c index 0d166e5dbf..2cf2080cf1 100644 --- a/firmware/target/arm/imx31/ccm-imx31.c +++ b/firmware/target/arm/imx31/ccm-imx31.c @@ -24,7 +24,8 @@ #include "cpu.h" #include "ccm-imx31.h" -unsigned int ccm_get_src_pll(void) +/* Return the current source pll for MCU */ +enum IMX31_PLLS ccm_get_src_pll(void) { return (CCM_PMCR0 & 0xC0000000) == 0 ? PLL_SERIAL : PLL_MCU; } @@ -45,8 +46,21 @@ void ccm_module_clock_gating(enum IMX31_CG_LIST cg, enum IMX31_CG_MODES mode) imx31_regmod32(reg, mode << shift, mask); } +/* Decode PLL output frequency from register value */ +unsigned int ccm_calc_pll_rate(unsigned int infreq, unsigned long regval) +{ + uint32_t mfn = regval & 0x3ff; + uint32_t pd = ((regval >> 26) & 0xf) + 1; + uint32_t mfd = ((regval >> 16) & 0x3ff) + 1; + uint32_t mfi = (regval >> 10) & 0xf; + + mfi = mfi <= 5 ? 5 : mfi; + + return 2ull*infreq*(mfi * mfd + mfn) / (mfd * pd); +} + /* Get the PLL reference clock frequency in HZ */ -unsigned int ccm_get_pll_ref_clk(void) +unsigned int ccm_get_pll_ref_clk_rate(void) { if ((CCM_CCMR & (3 << 1)) == (1 << 1)) return CONFIG_CKIL_FREQ * 1024; @@ -55,41 +69,59 @@ unsigned int ccm_get_pll_ref_clk(void) } /* Return PLL frequency in HZ */ -unsigned int ccm_get_pll(enum IMX31_PLLS pll) +unsigned int ccm_get_pll_rate(enum IMX31_PLLS pll) { - uint32_t infreq = ccm_get_pll_ref_clk(); - uint32_t reg = (&CCM_MPCTL)[pll]; - uint32_t mfn = reg & 0x3ff; - uint32_t pd = ((reg >> 26) & 0xf) + 1; - uint64_t mfd = ((reg >> 16) & 0x3ff) + 1; - uint32_t mfi = (reg >> 10) & 0xf; + return ccm_calc_pll_rate(ccm_get_pll_ref_clk_rate(), (&CCM_MPCTL)[pll]); +} - mfi = mfi <= 5 ? 5 : mfi; +unsigned int ccm_get_mcu_clk(void) +{ + unsigned int pllnum = ccm_get_src_pll(); + unsigned int fpll = ccm_get_pll_rate(pllnum); + unsigned int mcu_podf = (CCM_PDR0 & 0x7) + 1; - return 2*infreq*(mfi * mfd + mfn) / (mfd * pd); + return fpll / mcu_podf; } unsigned int ccm_get_ipg_clk(void) { unsigned int pllnum = ccm_get_src_pll(); - unsigned int pll = ccm_get_pll(pllnum); + unsigned int fpll = ccm_get_pll_rate(pllnum); uint32_t reg = CCM_PDR0; unsigned int max_pdf = ((reg >> 3) & 0x7) + 1; unsigned int ipg_pdf = ((reg >> 6) & 0x3) + 1; - return pll / (max_pdf * ipg_pdf); + return fpll / (max_pdf * ipg_pdf); } unsigned int ccm_get_ahb_clk(void) { unsigned int pllnum = ccm_get_src_pll(); - unsigned int pll = ccm_get_pll(pllnum); + unsigned int fpll = ccm_get_pll_rate(pllnum); unsigned int max_pdf = ((CCM_PDR0 >> 3) & 0x7) + 1; - return pll / max_pdf; + return fpll / max_pdf; } unsigned int ccm_get_ata_clk(void) { return ccm_get_ipg_clk(); } + +/* Write new values to the current PLL and post-dividers */ +void ccm_set_mcupll_and_pdr(unsigned long pllctl, unsigned long pdr) +{ + unsigned int pll = ccm_get_src_pll(); + volatile unsigned long *pllreg = &(&CCM_MPCTL)[pll]; + unsigned long fref = ccm_get_pll_ref_clk_rate(); + unsigned long curfreq = ccm_calc_pll_rate(fref, *pllreg); + unsigned long newfreq = ccm_calc_pll_rate(fref, pllctl); + + if (newfreq > curfreq) + CCM_PDR0 = pdr; + + *pllreg = pllctl; + + if (newfreq <= curfreq) + CCM_PDR0 = pdr; +} -- cgit v1.2.3