summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/armv7/tegra2
diff options
context:
space:
mode:
authorDilan Lee <dilee@nvidia.com>2011-06-22 12:55:27 +0800
committerSimon Glass <sjg@chromium.org>2011-08-29 10:39:36 -0700
commitdf2eeffdf8446bc8ceb8ae0bb3f476a0299180a6 (patch)
tree73b047e0d2535ddc6f0c609fb3b32a5956394484 /arch/arm/cpu/armv7/tegra2
parent6e584dd2426b27ecbd5fc6913d8723c316943eba (diff)
Tegra: Add clock_set_rate() to adjust main PLLs
In original code, the output frequency of PLLP is incorrect when OSC is 26Mhz, it always set the DIVM to 0x0c. It should base on different OSC to program the parameters of each PLL, the DIVM should be 0x1a with 26Mhz OSC for PLLP. BUG=none TEST=test on Aebl Kaen, UART and LCD work fine. Change-Id: I94170d442cd80410c4c11d7577dbf2136aa1d016 Signed-off-by: Dilan Lee <dilee@nvidia.com> Reviewed-on: http://gerrit.chromium.org/gerrit/2980 Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'arch/arm/cpu/armv7/tegra2')
-rw-r--r--arch/arm/cpu/armv7/tegra2/clock.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c
index fe7f4a30305..fba6234f570 100644
--- a/arch/arm/cpu/armv7/tegra2/clock.c
+++ b/arch/arm/cpu/armv7/tegra2/clock.c
@@ -794,6 +794,79 @@ unsigned clock_get_rate(enum clock_id clkid)
return rate;
}
+/**
+ * Set the output frequency you want for each PLL clock.
+ * PLL output frequencies are programmed by setting their N, M and P values.
+ * The governing equations are:
+ * VCO = (Fi / m) * n, Fo = VCO / (2^p)
+ * where Fo is the output frequency from the PLL.
+ * Example: Set the output frequency to 216Mhz(Fo) with 12Mhz OSC(Fi)
+ * 216Mhz = ((12Mhz / m) * n) / (2^p) so n=432,m=12,p=1
+ * Please see Tegra TRM section 5.3 to get the detail for PLL Programming
+ *
+ * @param n PLL feedback divider(DIVN)
+ * @param m PLL input divider(DIVN)
+ * @param p post divider(DIVP)
+ * @param cpcon base PLL charge pump(CPCON)
+ * @return 0 if ok, -1 on error (the requested PLL cannot be overriden)
+ */
+static int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
+{
+ u32 base_reg;
+ u32 misc_reg;
+ struct clk_pll *pll;
+
+ pll = get_pll(clkid);
+
+ base_reg = readl(&pll->pll_base);
+
+ if(clkid == CLOCK_ID_PERIPH)
+ if(base_reg & bf_mask(PLL_BASE_OVRRIDE))
+ return -1;
+
+ /* Set BYPASS, m, n and p to PLL_BASE */
+ bf_update(PLL_BYPASS, base_reg, 1);
+ if(clkid == CLOCK_ID_PERIPH)
+ bf_update(PLL_BASE_OVRRIDE, base_reg, 1);
+ bf_update(PLL_DIVM, base_reg, m);
+ bf_update(PLL_DIVN, base_reg, n);
+ bf_update(PLL_DIVP, base_reg, p);
+ writel(base_reg, &pll->pll_base);
+
+ /* Set cpcon to PLL_MISC */
+ misc_reg = readl(&pll->pll_misc);
+ bf_update(PLL_CPCON, misc_reg, cpcon);
+ writel(misc_reg, &pll->pll_misc);
+
+ /* Enable PLL */
+ bf_update(PLL_ENABLE, base_reg, 1);
+ writel(base_reg, &pll->pll_base);
+
+ /* Disable BYPASS */
+ bf_update(PLL_BYPASS, base_reg, 0);
+ writel(base_reg, &pll->pll_base);
+
+ return 0;
+}
+
+void common_pll_init(void)
+{
+ /*
+ * PLLP output frequency set to 216Mh
+ * PLLC output frequency set to 600Mhz
+ */
+ switch (clock_get_rate(CLOCK_ID_OSC)) {
+ case 12000000: /* OSC is 12Mhz */
+ clock_set_rate(CLOCK_ID_PERIPH, 432, 12, 1, 8);
+ clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
+ break;
+ case 26000000: /* OSC is 26Mhz */
+ clock_set_rate(CLOCK_ID_PERIPH, 432, 26, 1, 8);
+ clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
+ break;
+ }
+}
+
void clock_init(void)
{
pll_rate[CLOCK_ID_MEMORY] = clock_get_rate(CLOCK_ID_MEMORY);