]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/mach-omap2/clock34xx.c
[ARM] OMAP2/3 clock: don't tinker with hardirqs when they are supposed to be disabled
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / clock34xx.c
index 439a66918d38627231ad1873128a01b3b81f74b0..3b6e27bc9fe39eb55a7c48d1694b6961123c7fd2 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/div64.h>
 #include <asm/clkdev.h>
 
-#include "memory.h"
+#include <mach/sdrc.h>
 #include "clock.h"
 #include "prm.h"
 #include "prm-regbits-34xx.h"
@@ -206,6 +206,7 @@ static struct omap_clk omap34xx_clks[] = {
        CLK(NULL,       "dss_ick",      &dss_ick,       CK_343X),
        CLK(NULL,       "cam_mclk",     &cam_mclk,      CK_343X),
        CLK(NULL,       "cam_ick",      &cam_ick,       CK_343X),
+       CLK(NULL,       "csi2_96m_fck", &csi2_96m_fck,  CK_343X),
        CLK(NULL,       "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2),
        CLK(NULL,       "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2),
        CLK(NULL,       "usbhost_ick",  &usbhost_ick,   CK_3430ES2),
@@ -313,14 +314,12 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
        const struct dpll_data *dd;
        int i = 0;
        int ret = -EINVAL;
-       u32 idlest_mask;
 
        dd = clk->dpll_data;
 
-       state <<= dd->idlest_bit;
-       idlest_mask = 1 << dd->idlest_bit;
+       state <<= __ffs(dd->idlest_mask);
 
-       while (((__raw_readl(dd->idlest_reg) & idlest_mask) != state) &&
+       while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) &&
               i < MAX_DPLL_WAIT_TRIES) {
                i++;
                udelay(1);
@@ -399,19 +398,14 @@ static int _omap3_noncore_dpll_lock(struct clk *clk)
 
        ai = omap3_dpll_autoidle_read(clk);
 
+       omap3_dpll_deny_idle(clk);
+
        _omap3_dpll_write_clken(clk, DPLL_LOCKED);
 
-       if (ai) {
-               /*
-                * If no downstream clocks are enabled, CM_IDLEST bit
-                * may never become active, so don't wait for DPLL to lock.
-                */
-               r = 0;
+       r = _omap3_wait_dpll_status(clk, 1);
+
+       if (ai)
                omap3_dpll_allow_idle(clk);
-       } else {
-               r = _omap3_wait_dpll_status(clk, 1);
-               omap3_dpll_deny_idle(clk);
-       };
 
        return r;
 }
@@ -562,14 +556,17 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
        /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
        _omap3_noncore_dpll_bypass(clk);
 
+       /* Set jitter correction */
+       v = __raw_readl(dd->control_reg);
+       v &= ~dd->freqsel_mask;
+       v |= freqsel << __ffs(dd->freqsel_mask);
+       __raw_writel(v, dd->control_reg);
+
+       /* Set DPLL multiplier, divider */
        v = __raw_readl(dd->mult_div1_reg);
        v &= ~(dd->mult_mask | dd->div1_mask);
-
-       /* Set mult (M), div1 (N), freqsel */
        v |= m << __ffs(dd->mult_mask);
-       v |= n << __ffs(dd->div1_mask);
-       v |= freqsel << __ffs(dd->freqsel_mask);
-
+       v |= (n - 1) << __ffs(dd->div1_mask);
        __raw_writel(v, dd->mult_div1_reg);
 
        /* We let the clock framework set the other output dividers later */
@@ -617,8 +614,6 @@ static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
        omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n,
                                   freqsel);
 
-       omap3_dpll_recalc(clk);
-
        return 0;
 }
 
@@ -637,6 +632,67 @@ static int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
        return omap3_noncore_dpll_set_rate(clk, rate);
 }
 
+
+/*
+ * CORE DPLL (DPLL3) rate programming functions
+ *
+ * These call into SRAM code to do the actual CM writes, since the SDRAM
+ * is clocked from DPLL3.
+ */
+
+/**
+ * omap3_core_dpll_m2_set_rate - set CORE DPLL M2 divider
+ * @clk: struct clk * of DPLL to set
+ * @rate: rounded target rate
+ *
+ * Program the DPLL M2 divider with the rounded target rate.  Returns
+ * -EINVAL upon error, or 0 upon success.
+ */
+static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 new_div = 0;
+       unsigned long validrate, sdrcrate;
+       struct omap_sdrc_params *sp;
+
+       if (!clk || !rate)
+               return -EINVAL;
+
+       if (clk != &dpll3_m2_ck)
+               return -EINVAL;
+
+       if (rate == clk->rate)
+               return 0;
+
+       validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
+       if (validrate != rate)
+               return -EINVAL;
+
+       sdrcrate = sdrc_ick.rate;
+       if (rate > clk->rate)
+               sdrcrate <<= ((rate / clk->rate) - 1);
+       else
+               sdrcrate >>= ((clk->rate / rate) - 1);
+
+       sp = omap2_sdrc_get_params(sdrcrate);
+       if (!sp)
+               return -EINVAL;
+
+       pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
+               validrate);
+       pr_info("clock: SDRC timing params used: %08x %08x %08x\n",
+               sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
+
+       /* REVISIT: SRAM code doesn't support other M2 divisors yet */
+       WARN_ON(new_div != 1 && new_div != 2);
+
+       /* REVISIT: Add SDRC_MR changing to this code also */
+       omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
+                                 sp->actim_ctrlb, new_div);
+
+       return 0;
+}
+
+
 static const struct clkops clkops_noncore_dpll_ops = {
        .enable         = &omap3_noncore_dpll_enable,
        .disable        = &omap3_noncore_dpll_disable,
@@ -804,7 +860,7 @@ static int __init omap2_clk_arch_init(void)
 
        /* REVISIT: not yet ready for 343x */
 #if 0
-       if (omap2_select_table_rate(&virt_prcm_set, mpurate))
+       if (clk_set_rate(&virt_prcm_set, mpurate))
                printk(KERN_ERR "Could not find matching MPU rate\n");
 #endif
 
@@ -845,6 +901,9 @@ int __init omap2_clk_init(void)
 
        clk_init(&omap2_clk_functions);
 
+       for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
+               clk_init_one(c->lk.clk);
+
        for (c = omap34xx_clks; c < omap34xx_clks + ARRAY_SIZE(omap34xx_clks); c++)
                if (c->cpu & cpu_clkflg) {
                        clkdev_add(&c->lk);