]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/mach-omap2/clock.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / clock.c
index 1d891e4a69337d76aba8a75cb931e58477935161..be5c6169f4790e8e273ca73cb78b1f2c0d98e730 100644 (file)
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <asm/bitops.h>
-
-#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
 
 #include <mach/clock.h>
+#include <mach/clockdomain.h>
 #include <mach/sram.h>
 #include <mach/cpu.h>
+#include <mach/prcm.h>
 #include <asm/div64.h>
 
-#include "memory.h"
+#include <mach/sdrc.h>
 #include "sdrc.h"
 #include "clock.h"
 #include "prm.h"
 u8 cpu_mask;
 
 /*-------------------------------------------------------------------------
- * Omap2 specific clock functions
+ * OMAP2/3 specific clock functions
  *-------------------------------------------------------------------------*/
 
+/**
+ * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
+ * @clk: OMAP clock struct ptr to use
+ *
+ * Convert a clockdomain name stored in a struct clk 'clk' into a
+ * clockdomain pointer, and save it into the struct clk.  Intended to be
+ * called during clk_register().  No return value.
+ */
+void omap2_init_clk_clkdm(struct clk *clk)
+{
+       struct clockdomain *clkdm;
+
+       if (!clk->clkdm.name)
+               return;
+
+       clkdm = clkdm_lookup(clk->clkdm.name);
+       if (clkdm) {
+               pr_debug("clock: associated clk %s to clkdm %s\n",
+                        clk->name, clk->clkdm.name);
+               clk->clkdm.ptr = clkdm;
+       } else {
+               pr_debug("clock: could not associate clk %s to "
+                        "clkdm %s\n", clk->name, clk->clkdm.name);
+       }
+}
+
 /**
  * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware
  * @clk: OMAP clock struct ptr to use
@@ -164,11 +191,10 @@ int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
         * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
         * 34xx reverses this, just to keep us on our toes
         */
-       if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) {
+       if (cpu_mask & (RATE_IN_242X | RATE_IN_243X))
                ena = mask;
-       } else if (cpu_mask & RATE_IN_343X) {
+       else if (cpu_mask & RATE_IN_343X)
                ena = 0;
-       }
 
        /* Wait for lock */
        while (((__raw_readl(reg) & mask) != ena) &&
@@ -191,57 +217,104 @@ int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
  * Note: We don't need special code here for INVERT_ENABLE
  * for the time being since INVERT_ENABLE only applies to clocks enabled by
  * CM_CLKEN_PLL
+ *
+ * REVISIT: This code is ugly and does not belong here.
  */
 static void omap2_clk_wait_ready(struct clk *clk)
 {
-       void __iomem *reg, *other_reg, *st_reg;
-       u32 bit;
+       u32 other_bit, idlest_bit;
+       unsigned long reg, other_reg, idlest_reg, prcm_mod, prcm_regid;
 
-       /*
-        * REVISIT: This code is pretty ugly.  It would be nice to generalize
-        * it and pull it into struct clk itself somehow.
-        */
-       reg = clk->enable_reg;
-       if ((((u32)reg & 0xff) >= CM_FCLKEN1) &&
-           (((u32)reg & 0xff) <= OMAP24XX_CM_FCLKEN2))
-               other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x10); /* CM_ICLKEN* */
-       else if ((((u32)reg & 0xff) >= CM_ICLKEN1) &&
-                (((u32)reg & 0xff) <= OMAP24XX_CM_ICLKEN4))
-               other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x00); /* CM_FCLKEN* */
+       reg = (unsigned long)clk->enable_reg;
+       prcm_mod = reg & ~0xff;
+       prcm_regid = reg & 0xff;
+
+       if (prcm_regid >= CM_FCLKEN1 && prcm_regid <= OMAP24XX_CM_FCLKEN2)
+               other_reg = ((reg & ~0xf0) | 0x10); /* CM_ICLKEN* */
+       else if (prcm_regid >= CM_ICLKEN1 && prcm_regid <= OMAP24XX_CM_ICLKEN4)
+               other_reg = ((reg & ~0xf0) | 0x00); /* CM_FCLKEN* */
        else
                return;
 
-       /* REVISIT: What are the appropriate exclusions for 34XX? */
-       /* No check for DSS or cam clocks */
-       if (cpu_is_omap24xx() && ((u32)reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */
+       /* Covers most of the cases - a few exceptions are below */
+       other_bit = 1 << clk->enable_bit;
+       idlest_bit = other_bit;
+
+       /* 24xx: DSS and CAM have no idlest bits for their target agents */
+       if (cpu_is_omap24xx() &&
+           (prcm_mod == OMAP2420_CM_REGADDR(CORE_MOD, 0) ||
+            prcm_mod == OMAP2430_CM_REGADDR(CORE_MOD, 0)) &&
+           (reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */
+
                if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT ||
                    clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT ||
                    clk->enable_bit == OMAP24XX_EN_CAM_SHIFT)
                        return;
+
        }
 
        /* REVISIT: What are the appropriate exclusions for 34XX? */
-       /* OMAP3: ignore DSS-mod clocks */
-       if (cpu_is_omap34xx() &&
-           (((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(OMAP3430_DSS_MOD, 0) ||
-            ((((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(CORE_MOD, 0)) &&
-            clk->enable_bit == OMAP3430_EN_SSI_SHIFT)))
-               return;
+       if (cpu_is_omap34xx()) {
+
+               /* SSI */
+               if (prcm_mod == OMAP34XX_CM_REGADDR(CORE_MOD, 0) &&
+                   (reg & 0x0f) == 0 &&
+                   clk->enable_bit == OMAP3430_EN_SSI_SHIFT) {
+
+                       if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0))
+                               return;
+
+                       idlest_bit = OMAP3430ES2_ST_SSI_IDLE;
+               }
+
+               /* DSS */
+               if (prcm_mod == OMAP34XX_CM_REGADDR(OMAP3430_DSS_MOD, 0)) {
+
+                       /* 3430ES1 DSS has no target idlest bits */
+                       if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0))
+                               return;
+
+                       /*
+                        * For 3430ES2+ DSS, only wait once (dss1_alwon_fclk,
+                        * dss_l3_iclk, dss_l4_iclk) are enabled
+                        */
+                       if (clk->enable_bit != OMAP3430_EN_DSS1_SHIFT)
+                               return;
+
+                       idlest_bit = OMAP3430ES2_ST_DSS_IDLE;
+               }
+
+               /* USBHOST */
+               if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0) &&
+                   prcm_mod == OMAP34XX_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, 0)) {
+
+                       /*
+                        * The 120MHz clock apparently has nothing to do with
+                        * USBHOST module accessibility
+                        */
+                       if (clk->enable_bit == OMAP3430ES2_EN_USBHOST2_SHIFT)
+                               return;
+
+                       idlest_bit = OMAP3430ES2_ST_USBHOST_IDLE;
+
+               }
+       }
 
        /* Check if both functional and interface clocks
         * are running. */
-       bit = 1 << clk->enable_bit;
-       if (!(__raw_readl(other_reg) & bit))
+       if (!(__raw_readl((void __iomem *)other_reg) & other_bit))
                return;
-       st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */
 
-       omap2_wait_clock_ready(st_reg, bit, clk->name);
+       idlest_reg = ((other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */
+
+       omap2_wait_clock_ready((void __iomem *)idlest_reg, idlest_bit,
+                              clk->name);
 }
 
 /* Enables clock without considering parent dependencies or use count
  * REVISIT: Maybe change this to use clk->enable like on omap1?
  */
-int _omap2_clk_enable(struct clk *clk)
+static int _omap2_clk_enable(struct clk *clk)
 {
        u32 regval32;
 
@@ -251,7 +324,7 @@ int _omap2_clk_enable(struct clk *clk)
        if (clk->enable)
                return clk->enable(clk);
 
-       if (unlikely(clk->enable_reg == 0)) {
+       if (!clk->enable_reg) {
                printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
                       clk->name);
                return 0; /* REVISIT: -EINVAL */
@@ -271,7 +344,7 @@ int _omap2_clk_enable(struct clk *clk)
 }
 
 /* Disables clock without considering parent dependencies or use count */
-void _omap2_clk_disable(struct clk *clk)
+static void _omap2_clk_disable(struct clk *clk)
 {
        u32 regval32;
 
@@ -283,7 +356,7 @@ void _omap2_clk_disable(struct clk *clk)
                return;
        }
 
-       if (clk->enable_reg == 0) {
+       if (!clk->enable_reg) {
                /*
                 * 'Independent' here refers to a clock which is not
                 * controlled by its parent.
@@ -306,8 +379,11 @@ void omap2_clk_disable(struct clk *clk)
 {
        if (clk->usecount > 0 && !(--clk->usecount)) {
                _omap2_clk_disable(clk);
-               if (likely((u32)clk->parent))
+               if (clk->parent)
                        omap2_clk_disable(clk->parent);
+               if (clk->clkdm.ptr)
+                       omap2_clkdm_clk_disable(clk->clkdm.ptr, clk);
+
        }
 }
 
@@ -316,19 +392,27 @@ int omap2_clk_enable(struct clk *clk)
        int ret = 0;
 
        if (clk->usecount++ == 0) {
-               if (likely((u32)clk->parent))
+               if (clk->parent)
                        ret = omap2_clk_enable(clk->parent);
 
-               if (unlikely(ret != 0)) {
+               if (ret != 0) {
                        clk->usecount--;
                        return ret;
                }
 
+               if (clk->clkdm.ptr)
+                       omap2_clkdm_clk_enable(clk->clkdm.ptr, clk);
+
                ret = _omap2_clk_enable(clk);
 
-               if (unlikely(ret != 0) && clk->parent) {
-                       omap2_clk_disable(clk->parent);
-                       clk->usecount--;
+               if (ret != 0) {
+                       if (clk->clkdm.ptr)
+                               omap2_clkdm_clk_disable(clk->clkdm.ptr, clk);
+
+                       if (clk->parent) {
+                               omap2_clk_disable(clk->parent);
+                               clk->usecount--;
+                       }
                }
        }
 
@@ -349,13 +433,13 @@ void omap2_clksel_recalc(struct clk *clk)
        if (div == 0)
                return;
 
-       if (unlikely(clk->rate == clk->parent->rate / div))
+       if (clk->rate == (clk->parent->rate / div))
                return;
        clk->rate = clk->parent->rate / div;
 
        pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
 
-       if (unlikely(clk->flags & RATE_PROPAGATES))
+       if (clk->flags & RATE_PROPAGATES)
                propagate_rate(clk);
 }
 
@@ -368,8 +452,8 @@ void omap2_clksel_recalc(struct clk *clk)
  * the element associated with the supplied parent clock address.
  * Returns a pointer to the struct clksel on success or NULL on error.
  */
-const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
-                                               struct clk *src_clk)
+static const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
+                                                      struct clk *src_clk)
 {
        const struct clksel *clks;
 
@@ -418,7 +502,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
        *new_div = 1;
 
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return ~0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -477,7 +561,7 @@ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
 /* Given a clock and a rate apply a clock specific rounding function */
 long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->round_rate != 0)
+       if (clk->round_rate)
                return clk->round_rate(clk, rate);
 
        if (clk->flags & RATE_FIXED)
@@ -503,7 +587,7 @@ u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val)
        const struct clksel_rate *clkr;
 
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return 0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -539,7 +623,7 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
        WARN_ON(div == 0);
 
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return 0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -564,9 +648,9 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
  *
  * Returns the address of the clksel register upon success or NULL on error.
  */
-void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
+static void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
 {
-       if (unlikely((clk->clksel_reg == 0) || (clk->clksel_mask == 0)))
+       if (!clk->clksel_reg || (clk->clksel_mask == 0))
                return NULL;
 
        *field_mask = clk->clksel_mask;
@@ -586,7 +670,7 @@ u32 omap2_clksel_get_divisor(struct clk *clk)
        void __iomem *div_addr;
 
        div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == 0)
+       if (!div_addr)
                return 0;
 
        field_val = __raw_readl(div_addr) & field_mask;
@@ -597,25 +681,27 @@ u32 omap2_clksel_get_divisor(struct clk *clk)
 
 int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 field_mask, field_val, reg_val, validrate, new_div = 0;
+       u32 field_mask, field_val, validrate, new_div = 0;
        void __iomem *div_addr;
+       u32 v;
 
        validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
        if (validrate != rate)
                return -EINVAL;
 
        div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == 0)
+       if (!div_addr)
                return -EINVAL;
 
        field_val = omap2_divisor_to_clksel(clk, new_div);
        if (field_val == ~0)
                return -EINVAL;
 
-       reg_val = __raw_readl(div_addr);
-       reg_val &= ~field_mask;
-       reg_val |= (field_val << __ffs(field_mask));
-       __raw_writel(reg_val, div_addr);
+       v = __raw_readl(div_addr);
+       v &= ~field_mask;
+       v |= field_val << __ffs(field_mask);
+       __raw_writel(v, div_addr);
+
        wmb();
 
        clk->rate = clk->parent->rate / new_div;
@@ -643,10 +729,10 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
-       if (clk->set_rate != 0)
+       if (clk->set_rate)
                ret = clk->set_rate(clk, rate);
 
-       if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
+       if (ret == 0 && (clk->flags & RATE_PROPAGATES))
                propagate_rate(clk);
 
        return ret;
@@ -664,10 +750,10 @@ static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
        const struct clksel_rate *clkr;
 
        *parent_div = 0;
-       *src_addr = 0;
+       *src_addr = NULL;
 
        clks = omap2_get_clksel_by_parent(clk, src_clk);
-       if (clks == NULL)
+       if (!clks)
                return 0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -697,7 +783,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
        void __iomem *src_addr;
        u32 field_val, field_mask, reg_val, parent_div;
 
-       if (unlikely(clk->flags & CONFIG_PARTICIPANT))
+       if (clk->flags & CONFIG_PARTICIPANT)
                return -EINVAL;
 
        if (!clk->clksel)
@@ -705,7 +791,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
 
        field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
                                               &field_mask, clk, &parent_div);
-       if (src_addr == 0)
+       if (!src_addr)
                return -EINVAL;
 
        if (clk->usecount > 0)
@@ -718,7 +804,8 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
        wmb();
 
        if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
-               __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL);
+               prm_write_mod_reg(OMAP24XX_VALID_CONFIG,
+                       OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
                wmb();
        }
 
@@ -736,7 +823,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
        pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
                 clk->name, clk->parent->name, clk->rate);
 
-       if (unlikely(clk->flags & RATE_PROPAGATES))
+       if (clk->flags & RATE_PROPAGATES)
                propagate_rate(clk);
 
        return 0;
@@ -768,7 +855,8 @@ int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance)
        return 0;
 }
 
-static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, unsigned int m, unsigned int n)
+static unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
+                                           unsigned int m, unsigned int n)
 {
        unsigned long long num;