#include <mach/sram.h>
#include <mach/cpu.h>
#include <mach/prcm.h>
+#include <mach/control.h>
#include <asm/div64.h>
#include <mach/sdrc.h>
#define ST_CORE_CLK_REF 0x1
#define ST_CORE_CLK_32K 0x3
+/* Bitmask to isolate the register type of clk.enable_reg */
+#define PRCM_REGTYPE_MASK 0xf0
+/* various CM register type options */
+#define CM_FCLKEN_REGTYPE 0x00
+#define CM_ICLKEN_REGTYPE 0x10
+#define CM_IDLEST_REGTYPE 0x20
+
u8 cpu_mask;
/*-------------------------------------------------------------------------
* OMAP2/3 specific clock functions
*-------------------------------------------------------------------------*/
+/*
+ * _omap2_clk_read_reg - read a clock register
+ * @clk: struct clk *
+ *
+ * Given a struct clk *, returns the value of the clock's register.
+ */
+static u32 _omap2_clk_read_reg(u16 reg_offset, struct clk *clk)
+{
+ if (clk->prcm_mod & CLK_REG_IN_SCM)
+ return omap_ctrl_readl(reg_offset);
+ else if (clk->prcm_mod & CLK_REG_IN_PRM)
+ return prm_read_mod_reg(clk->prcm_mod & PRCM_MOD_ADDR_MASK,
+ reg_offset);
+ else
+ return cm_read_mod_reg(clk->prcm_mod, reg_offset);
+}
+
+/*
+ * _omap2_clk_write_reg - write a clock's register
+ * @v: value to write to the clock's enable_reg
+ * @clk: struct clk *
+ *
+ * Given a register value @v and struct clk * @clk, writes the value of @v to
+ * the clock's enable register. No return value.
+ */
+static void _omap2_clk_write_reg(u32 v, u16 reg_offset, struct clk *clk)
+{
+ if (clk->prcm_mod & CLK_REG_IN_SCM)
+ omap_ctrl_writel(v, reg_offset);
+ else if (clk->prcm_mod & CLK_REG_IN_PRM)
+ prm_write_mod_reg(v, clk->prcm_mod & PRCM_MOD_ADDR_MASK,
+ reg_offset);
+ else
+ cm_write_mod_reg(v, clk->prcm_mod, reg_offset);
+}
+
+
/**
* omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
* @clk: OMAP clock struct ptr to use
if (!clk->clksel)
return;
- r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
+ r = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ r &= clk->clksel_mask;
r >>= __ffs(clk->clksel_mask);
for (clks = clk->clksel; clks->parent && !found; clks++) {
return 0;
/* Return bypass rate if DPLL is bypassed */
- v = __raw_readl(dd->idlest_reg) & dd->idlest_mask;
+ v = cm_read_mod_reg(clk->prcm_mod, dd->idlest_reg);
+ v &= dd->idlest_mask;
v >>= __ffs(dd->idlest_mask);
if (cpu_is_omap24xx()) {
}
- v = __raw_readl(dd->mult_div1_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg);
dpll_mult = v & dd->mult_mask;
dpll_mult >>= __ffs(dd->mult_mask);
dpll_div = v & dd->div1_mask;
/**
* omap2_wait_clock_ready - wait for clock to enable
- * @reg: physical address of clock IDLEST register
+ * @prcm_mod: CM submodule offset from CM_BASE (e.g., "MPU_MOD")
+ * @reg_index: offset of CM register address from prcm_mod
* @mask: value to mask against to determine if the clock is active
* @name: name of the clock (for printk)
*
* Returns 1 if the clock enabled in time, or 0 if it failed to enable
* in roughly MAX_CLOCK_ENABLE_WAIT microseconds.
*/
-int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
+int omap2_wait_clock_ready(s16 prcm_mod, u16 reg_index, u32 mask,
+ const char *name)
{
- int i = 0;
- int ena = 0;
+ int i = 0, ena = 0;
/*
* 24xx uses 0 to indicate not ready, and 1 to indicate ready.
ena = 0;
/* Wait for lock */
- while (((__raw_readl(reg) & mask) != ena) &&
+ while (((cm_read_mod_reg(prcm_mod, reg_index) & mask) != ena) &&
(i++ < MAX_CLOCK_ENABLE_WAIT)) {
udelay(1);
}
printk(KERN_ERR "Clock %s didn't enable in %d tries\n",
name, MAX_CLOCK_ENABLE_WAIT);
-
return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0;
};
*/
static void omap2_clk_wait_ready(struct clk *clk)
{
+ u16 other_reg, idlest_reg;
u32 other_bit, idlest_bit;
- unsigned long reg, other_reg, idlest_reg, prcm_mod, prcm_regid;
- reg = (unsigned long)clk->enable_reg;
- prcm_mod = reg & ~0xff;
- prcm_regid = reg & 0xff;
+ /* Only CM-controlled clocks affect module IDLEST */
+ if (clk->prcm_mod & ~PRCM_MOD_ADDR_MASK)
+ return;
+
+ other_reg = clk->enable_reg & ~PRCM_REGTYPE_MASK;
- 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* */
+ /* If we are enabling an iclk, also test the fclk; and vice versa */
+ if (clk->enable_reg & CM_ICLKEN_REGTYPE)
+ other_reg |= CM_FCLKEN_REGTYPE;
else
- return;
+ other_reg |= CM_ICLKEN_REGTYPE;
/* 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 (cpu_is_omap24xx() && clk->prcm_mod == CORE_MOD &&
+ (clk->enable_reg == CM_FCLKEN1 || clk->enable_reg == CM_ICLKEN1)) {
if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT ||
clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT ||
if (cpu_is_omap34xx()) {
/* SSI */
- if (prcm_mod == OMAP34XX_CM_REGADDR(CORE_MOD, 0) &&
- (reg & 0x0f) == 0 &&
+ if (clk->prcm_mod == CORE_MOD &&
+ (clk->enable_reg == CM_FCLKEN1 ||
+ clk->enable_reg == CM_ICLKEN1) &&
clk->enable_bit == OMAP3430_EN_SSI_SHIFT) {
if (system_rev == OMAP3430_REV_ES1_0)
return;
- idlest_bit = OMAP3430ES2_ST_SSI_IDLE;
+ idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
}
/* DSS */
- if (prcm_mod == OMAP34XX_CM_REGADDR(OMAP3430_DSS_MOD, 0)) {
+ if (clk->prcm_mod == OMAP3430_DSS_MOD) {
/* 3430ES1 DSS has no target idlest bits */
if (system_rev == OMAP3430_REV_ES1_0)
if (clk->enable_bit != OMAP3430_EN_DSS1_SHIFT)
return;
- idlest_bit = OMAP3430ES2_ST_DSS_IDLE;
+ idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT;
}
/* USBHOST */
if (system_rev > OMAP3430_REV_ES1_0 &&
- prcm_mod == OMAP34XX_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, 0)) {
+ clk->prcm_mod == OMAP3430ES2_USBHOST_MOD) {
/*
* The 120MHz clock apparently has nothing to do with
if (clk->enable_bit == OMAP3430ES2_EN_USBHOST2_SHIFT)
return;
- idlest_bit = OMAP3430ES2_ST_USBHOST_IDLE;
+ idlest_bit = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT;
}
}
- /* Check if both functional and interface clocks
- * are running. */
- if (!(__raw_readl((void __iomem *)other_reg) & other_bit))
+ /* Check if both functional and interface clocks are running. */
+ if (!(cm_read_mod_reg(clk->prcm_mod, other_reg) & other_bit))
return;
- idlest_reg = ((other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */
+ idlest_reg = other_reg & ~PRCM_REGTYPE_MASK;
+ idlest_reg |= CM_IDLEST_REGTYPE;
- omap2_wait_clock_ready((void __iomem *)idlest_reg, idlest_bit,
+ omap2_wait_clock_ready(clk->prcm_mod, idlest_reg, idlest_bit,
clk->name);
}
*/
static int _omap2_clk_enable(struct clk *clk)
{
- u32 regval32;
+ u32 v;
if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
return 0;
if (clk->enable)
return clk->enable(clk);
- if (unlikely(clk->enable_reg == NULL)) {
- printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
- clk->name);
- return 0; /* REVISIT: -EINVAL */
- }
-
- regval32 = __raw_readl(clk->enable_reg);
+ v = _omap2_clk_read_reg(clk->enable_reg, clk);
if (clk->flags & INVERT_ENABLE)
- regval32 &= ~(1 << clk->enable_bit);
+ v &= ~(1 << clk->enable_bit);
else
- regval32 |= (1 << clk->enable_bit);
- __raw_writel(regval32, clk->enable_reg);
+ v |= (1 << clk->enable_bit);
+ _omap2_clk_write_reg(v, clk->enable_reg, clk);
wmb();
omap2_clk_wait_ready(clk);
/* Disables clock without considering parent dependencies or use count */
static void _omap2_clk_disable(struct clk *clk)
{
- u32 regval32;
+ u32 v;
if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
return;
return;
}
- if (clk->enable_reg == NULL) {
- /*
- * 'Independent' here refers to a clock which is not
- * controlled by its parent.
- */
- printk(KERN_ERR "clock: clk_disable called on independent "
- "clock %s which has no enable_reg\n", clk->name);
- return;
- }
-
- regval32 = __raw_readl(clk->enable_reg);
+ v = _omap2_clk_read_reg(clk->enable_reg, clk);
if (clk->flags & INVERT_ENABLE)
- regval32 |= (1 << clk->enable_bit);
+ v |= (1 << clk->enable_bit);
else
- regval32 &= ~(1 << clk->enable_bit);
- __raw_writel(regval32, clk->enable_reg);
+ v &= ~(1 << clk->enable_bit);
+ _omap2_clk_write_reg(v, clk->enable_reg, clk);
wmb();
}
return clkr->val;
}
-/**
- * omap2_get_clksel - find clksel register addr & field mask for a clk
- * @clk: struct clk to use
- * @field_mask: ptr to u32 to store the register field mask
- *
- * Returns the address of the clksel register upon success or NULL on error.
- */
-static void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
-{
- if (unlikely((clk->clksel_reg == NULL) || (clk->clksel_mask == NULL)))
- return NULL;
-
- *field_mask = clk->clksel_mask;
-
- return clk->clksel_reg;
-}
-
/**
* omap2_clksel_get_divisor - get current divider applied to parent clock.
* @clk: OMAP struct clk to use.
*/
u32 omap2_clksel_get_divisor(struct clk *clk)
{
- u32 field_mask, field_val;
- void __iomem *div_addr;
+ u32 v;
- div_addr = omap2_get_clksel(clk, &field_mask);
- if (div_addr == NULL)
+ if (!clk->clksel_mask)
return 0;
- field_val = __raw_readl(div_addr) & field_mask;
- field_val >>= __ffs(field_mask);
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ v &= clk->clksel_mask;
+ v >>= __ffs(clk->clksel_mask);
- return omap2_clksel_to_divisor(clk, field_val);
+ return omap2_clksel_to_divisor(clk, v);
}
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
{
- u32 field_mask, field_val, validrate, new_div = 0;
- void __iomem *div_addr;
- u32 v;
+ u32 v, field_val, validrate, new_div = 0;
- validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
- if (validrate != rate)
+ if (!clk->clksel_mask)
return -EINVAL;
- div_addr = omap2_get_clksel(clk, &field_mask);
- if (div_addr == NULL)
- return -EINVAL;
+ validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
+ if (validrate != rate)
+ return -EINVAL;
field_val = omap2_divisor_to_clksel(clk, new_div);
if (field_val == ~0)
return -EINVAL;
- v = __raw_readl(div_addr);
- v &= ~field_mask;
- v |= field_val << __ffs(field_mask);
- __raw_writel(v, div_addr);
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ v &= ~clk->clksel_mask;
+ v |= field_val << __ffs(clk->clksel_mask);
+ _omap2_clk_write_reg(v, clk->clksel_reg, clk);
wmb();
/*
* Converts encoded control register address into a full address
- * On error, *src_addr will be returned as 0.
+ * On error, the return value (parent_div) will be 0.
*/
-static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
- struct clk *src_clk, u32 *field_mask,
- struct clk *clk, u32 *parent_div)
+static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
+ u32 *field_val)
{
const struct clksel *clks;
const struct clksel_rate *clkr;
- *parent_div = 0;
- *src_addr = NULL;
-
clks = omap2_get_clksel_by_parent(clk, src_clk);
if (!clks)
return 0;
/* Should never happen. Add a clksel mask to the struct clk. */
WARN_ON(clk->clksel_mask == 0);
- *field_mask = clk->clksel_mask;
- *src_addr = clk->clksel_reg;
- *parent_div = clkr->div;
+ *field_val = clkr->val;
- return clkr->val;
+ return clkr->div;
}
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;
+ u32 field_val, v, parent_div;
if (clk->flags & CONFIG_PARTICIPANT)
return -EINVAL;
if (!clk->clksel)
return -EINVAL;
- field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
- &field_mask, clk, &parent_div);
- if (src_addr == NULL)
+ parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val);
+ if (!parent_div)
return -EINVAL;
if (clk->usecount > 0)
_omap2_clk_disable(clk);
/* Set new source value (previous dividers if any in effect) */
- reg_val = __raw_readl(src_addr) & ~field_mask;
- reg_val |= (field_val << __ffs(field_mask));
- __raw_writel(reg_val, src_addr);
+ v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+ v &= ~clk->clksel_mask;
+ v |= field_val << __ffs(clk->clksel_mask);
+ _omap2_clk_write_reg(v, clk->clksel_reg, clk);
wmb();
if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
- regval32 = __raw_readl(clk->enable_reg);
+ regval32 = _omap2_clk_read_reg(clk->enable_reg, clk);
if ((regval32 & (1 << clk->enable_bit)) == v)
return;