#include <linux/io.h>
#include <linux/limits.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/sram.h>
+#include <mach/clock.h>
+#include <mach/sram.h>
#include <asm/div64.h>
#include <asm/bitops.h>
-#include "memory.h"
+#include <mach/sdrc.h>
#include "clock.h"
#include "clock34xx.h"
#include "prm.h"
dd = clk->dpll_data;
- v = __raw_readl(dd->control_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg);
v &= ~dd->enable_mask;
v |= clken_bits << __ffs(dd->enable_mask);
- __raw_writel(v, dd->control_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg);
}
/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific 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 (((cm_read_mod_reg(clk->prcm_mod, dd->idlest_reg)
+ & dd->idlest_mask) != state) &&
i < MAX_DPLL_WAIT_TRIES) {
i++;
udelay(1);
}
/*
- * omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
+ * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
* @clk: pointer to a DPLL struct clk
*
* Instructs a non-CORE DPLL to enter low-power bypass mode. In
static int omap3_noncore_dpll_enable(struct clk *clk)
{
int r;
+ struct dpll_data *dd;
if (clk == &dpll3_ck)
return -EINVAL;
- if (clk->parent->rate == omap2_get_dpll_rate(clk))
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (clk->rate == dd->bypass_clk->rate)
r = _omap3_noncore_dpll_bypass(clk);
else
r = _omap3_noncore_dpll_lock(clk);
+ if (!r)
+ clk->rate = omap2_get_dpll_rate(clk);
+
return r;
}
* on 3430ES1 prevents us from changing DPLL multipliers or dividers
* on DPLL4.
*/
- if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0) &&
+ if (system_rev == OMAP3430_REV_ES1_0 &&
!strcmp("dpll4_ck", clk->name)) {
printk(KERN_ERR "clock: DPLL4 cannot change rate due to "
"silicon 'Limitation 2.5' on 3430ES1.\n");
_omap3_noncore_dpll_bypass(clk);
/* Set jitter correction */
- v = __raw_readl(dd->control_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg);
v &= ~dd->freqsel_mask;
v |= freqsel << __ffs(dd->freqsel_mask);
- __raw_writel(v, dd->control_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg);
/* Set DPLL multiplier, divider */
- v = __raw_readl(dd->mult_div1_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg);
v &= ~(dd->mult_mask | dd->div1_mask);
v |= m << __ffs(dd->mult_mask);
v |= (n - 1) << __ffs(dd->div1_mask);
- __raw_writel(v, dd->mult_div1_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->mult_div1_reg);
/* We let the clock framework set the other output dividers later */
* @clk: struct clk * of DPLL to set
* @rate: rounded target rate
*
- * Program the DPLL with the rounded target rate. Returns -EINVAL upon
- * error, or 0 upon success.
+ * Set the DPLL CLKOUT to the target rate. If the DPLL can enter
+ * low-power bypass, and the target rate is the bypass source clock
+ * rate, then configure the DPLL for bypass. Otherwise, round the
+ * target rate if it hasn't been done already, then program and lock
+ * the DPLL. Returns -EINVAL upon error, or 0 upon success.
*/
static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
{
u16 freqsel;
struct dpll_data *dd;
+ int ret;
if (!clk || !rate)
return -EINVAL;
if (rate == omap2_get_dpll_rate(clk))
return 0;
- if (dd->last_rounded_rate != rate)
- omap2_dpll_round_rate(clk, rate);
+ if (dd->bypass_clk->rate == rate &&
+ (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
- if (dd->last_rounded_rate == 0)
- return -EINVAL;
+ pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);
+
+ ret = _omap3_noncore_dpll_bypass(clk);
+ if (!ret)
+ clk->rate = rate;
+
+ } else {
+
+ if (dd->last_rounded_rate != rate)
+ omap2_dpll_round_rate(clk, rate);
+
+ if (dd->last_rounded_rate == 0)
+ return -EINVAL;
+
+ freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
+ if (!freqsel)
+ WARN_ON(1);
- freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
- if (!freqsel)
- WARN_ON(1);
+ pr_debug("clock: %s: set rate: locking rate to %lu.\n",
+ clk->name, rate);
- omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n,
- freqsel);
+ ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
+ dd->last_rounded_n, freqsel);
+
+ if (!ret)
+ clk->rate = rate;
+
+ }
omap3_dpll_recalc(clk);
return 0;
}
+
+/*
+ * 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 */
+ local_irq_disable();
+ omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
+ sp->actim_ctrlb, new_div);
+ local_irq_enable();
+
+ omap2_clksel_recalc(clk);
+
+ return 0;
+}
+
+
/* DPLL autoidle read/set code */
dd = clk->dpll_data;
- v = __raw_readl(dd->autoidle_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
v &= dd->autoidle_mask;
v >>= __ffs(dd->autoidle_mask);
* by writing 0x5 instead of 0x1. Add some mechanism to
* optionally enter this mode.
*/
- v = __raw_readl(dd->autoidle_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
v &= ~dd->autoidle_mask;
v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
- __raw_writel(v, dd->autoidle_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg);
}
/**
dd = clk->dpll_data;
- v = __raw_readl(dd->autoidle_reg);
+ v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
v &= ~dd->autoidle_mask;
v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
- __raw_writel(v, dd->autoidle_reg);
+ cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg);
}
/* Clock control for DPLL outputs */
dd = pclk->dpll_data;
- WARN_ON(!dd->control_reg || !dd->enable_mask);
+ WARN_ON(!dd->idlest_reg || !dd->idlest_mask);
- v = __raw_readl(dd->control_reg) & dd->enable_mask;
- v >>= __ffs(dd->enable_mask);
- if (v != DPLL_LOCKED)
+ v = cm_read_mod_reg(pclk->prcm_mod, dd->idlest_reg) & dd->idlest_mask;
+ if (!v)
clk->rate = clk->parent->rate;
else
clk->rate = clk->parent->rate * 2;
* Update this if there are further clock changes between ES2
* and production parts
*/
- if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {
+ if (system_rev == OMAP3430_REV_ES1_0) {
/* No 3430ES1-only rates exist, so no RATE_IN_3430ES1 */
cpu_clkflg |= CLOCK_IN_OMAP3430ES1;
} else {