* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#undef DEBUG
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
+#include <asm/arch/cpu.h>
#include <asm/div64.h>
#include "memory.h"
#include "cm.h"
#include "cm_regbits_24xx.h"
-#undef DEBUG
-
-#define MAX_PLL_LOCK_WAIT 100000
+#define MAX_CLOCK_ENABLE_WAIT 100000
u8 cpu_mask;
if (!clk->clksel)
return;
- /* XXX Should be __raw_readl for non-CM 3430 clocks ? */
- r = cm_read_reg(clk->clksel_reg) & clk->clksel_mask;
+ r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
r >>= mask_to_shift(clk->clksel_mask);
for (clks = clk->clksel; clks->parent && !found; clks++) {
pr_debug("clock: inited %s parent "
"to %s (was %s)\n",
clk->name, clks->parent->name,
- ((clk->parent->name) ?
+ ((clk->parent) ?
clk->parent->name : "NULL"));
clk->parent = clks->parent;
};
dpll_clk = (long long)clk->parent->rate * dpll_mult;
do_div(dpll_clk, dpll_div + 1);
+ /* 34XX only */
+ if (dd->div2_reg) {
+ dpll = cm_read_reg(dd->div2_reg);
+ dpll_div = dpll & dd->div2_mask;
+ dpll_div >>= mask_to_shift(dd->div2_mask);
+ do_div(dpll_clk, dpll_div + 1);
+ }
+
return dpll_clk;
}
propagate_rate(clk);
}
-/*
- * omap2_wait_clock_ready - wait for PLL to lock
+/**
+ * omap2_wait_clock_ready - wait for clock to enable
+ * @reg: physical address of clock IDLEST register
+ * @mask: value to mask against to determine if the clock is active
+ * @name: name of the clock (for printk)
*
- * Returns 1 if the PLL locked, 0 if it failed to lock.
+ * 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 cval, const char *name)
+int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
{
int i = 0;
+ int ena = 0;
+
+ /*
+ * 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)) {
+ ena = mask;
+ } else if (cpu_mask & RATE_IN_343X) {
+ ena = 0;
+ }
/* Wait for lock */
- while (!(cm_read_reg(reg) & cval)) {
- ++i;
+ while (((cm_read_reg(reg) & mask) != ena) &&
+ (i++ < MAX_CLOCK_ENABLE_WAIT)) {
udelay(1);
- if (i == MAX_PLL_LOCK_WAIT) {
- printk(KERN_ERR "Clock %s didn't lock in %d tries\n",
- name, MAX_PLL_LOCK_WAIT);
- break;
- }
}
- if (i)
+ if (i < MAX_CLOCK_ENABLE_WAIT)
pr_debug("Clock %s stable after %d loops\n", name, i);
+ else
+ printk(KERN_ERR "Clock %s didn't enable in %d tries\n",
+ name, MAX_CLOCK_ENABLE_WAIT);
+
- return (i < MAX_PLL_LOCK_WAIT) ? 1 : 0;
+ return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0;
};
+/*
+ * 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
+ */
static void omap2_clk_wait_ready(struct clk *clk)
{
void __iomem *reg, *other_reg, *st_reg;
u32 bit;
+ /*
+ * 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 (reg == OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1) ||
reg == OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2))
else
return;
+ /* REVISIT: What are the appropriate exclusions for 34XX? */
/* No check for DSS or cam clocks */
- if (((u32)reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */
+ if (cpu_is_omap24xx() && ((u32)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)
if (unlikely(clk->enable_reg == 0)) {
printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
clk->name);
- return -EINVAL;
+ return 0; /* REVISIT: -EINVAL */
}
regval32 = cm_read_reg(clk->enable_reg);
- regval32 |= (1 << clk->enable_bit);
+ if (clk->flags & INVERT_ENABLE)
+ regval32 &= ~(1 << clk->enable_bit);
+ else
+ regval32 |= (1 << clk->enable_bit);
cm_write_reg(regval32, clk->enable_reg);
wmb();
}
regval32 = cm_read_reg(clk->enable_reg);
- regval32 &= ~(1 << clk->enable_bit);
+ if (clk->flags & INVERT_ENABLE)
+ regval32 |= (1 << clk->enable_bit);
+ else
+ regval32 &= ~(1 << clk->enable_bit);
cm_write_reg(regval32, clk->enable_reg);
wmb();
}
clk->rate = clk->parent->rate / new_div;
- if (clk->flags & DELAYED_APP) {
+ if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
prm_write_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL);
wmb();
}
__raw_writel(reg_val, src_addr);
wmb();
- if (clk->flags & DELAYED_APP) {
+ if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
prm_write_reg(OMAP24XX_VALID_CONFIG,
OMAP24XX_PRCM_CLKCFG_CTRL);
wmb();
*-------------------------------------------------------------------------*/
#ifdef CONFIG_OMAP_RESET_CLOCKS
-void __init omap2_clk_disable_unused(struct clk *clk)
+void omap2_clk_disable_unused(struct clk *clk)
{
- u32 regval32;
+ u32 regval32, v;
+
+ v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
regval32 = cm_read_reg(clk->enable_reg);
- if ((regval32 & (1 << clk->enable_bit)) == 0)
+ if ((regval32 & (1 << clk->enable_bit)) == v)
return;
printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);