Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 137362
b: refs/heads/master
c: c0bf313
h: refs/heads/master
v: v3
  • Loading branch information
Russell King authored and Russell King committed Feb 19, 2009
1 parent 9a8b576 commit fe26d18
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 200 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8b9dbc16d4f5786c6c930ab028722e3ed7e4285b
refs/heads/master: c0bf31320dea2cbcbab1f53ee15a8520f762409b
47 changes: 37 additions & 10 deletions trunk/arch/arm/mach-omap2/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,25 +211,52 @@ void omap2_init_clksel_parent(struct clk *clk)
return;
}

/* Returns the DPLL rate */
/**
* omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
* @clk: struct clk * of a DPLL
*
* DPLLs can be locked or bypassed - basically, enabled or disabled.
* When locked, the DPLL output depends on the M and N values. When
* bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
* or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
* 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
* (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
* Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
* locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
* if the clock @clk is not a DPLL.
*/
u32 omap2_get_dpll_rate(struct clk *clk)
{
long long dpll_clk;
u32 dpll_mult, dpll_div, dpll;
u32 dpll_mult, dpll_div, v;
struct dpll_data *dd;

dd = clk->dpll_data;
/* REVISIT: What do we return on error? */
if (!dd)
return 0;

dpll = __raw_readl(dd->mult_div1_reg);
dpll_mult = dpll & dd->mult_mask;
/* Return bypass rate if DPLL is bypassed */
v = __raw_readl(dd->control_reg);
v &= dd->enable_mask;
v >>= __ffs(dd->enable_mask);

if (cpu_is_omap24xx()) {
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
v == OMAP2XXX_EN_DPLL_FRBYPASS)
return dd->clk_bypass->rate;
} else if (cpu_is_omap34xx()) {
if (v == OMAP3XXX_EN_DPLL_LPBYPASS ||
v == OMAP3XXX_EN_DPLL_FRBYPASS)
return dd->clk_bypass->rate;
}

v = __raw_readl(dd->mult_div1_reg);
dpll_mult = v & dd->mult_mask;
dpll_mult >>= __ffs(dd->mult_mask);
dpll_div = dpll & dd->div1_mask;
dpll_div = v & dd->div1_mask;
dpll_div >>= __ffs(dd->div1_mask);

dpll_clk = (long long)clk->parent->rate * dpll_mult;
dpll_clk = (long long)dd->clk_ref->rate * dpll_mult;
do_div(dpll_clk, dpll_div + 1);

return dpll_clk;
Expand Down Expand Up @@ -930,7 +957,7 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
pr_debug("clock: starting DPLL round_rate for clock %s, target rate "
"%ld\n", clk->name, target_rate);

scaled_rt_rp = target_rate / (clk->parent->rate / DPLL_SCALE_FACTOR);
scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR);
scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;

dd->last_rounded_rate = 0;
Expand All @@ -957,7 +984,7 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
break;

r = _dpll_test_mult(&m, n, &new_rate, target_rate,
clk->parent->rate);
dd->clk_ref->rate);

/* m can't be set low enough for this n - try with a larger n */
if (r == DPLL_MULT_UNDERFLOW)
Expand Down Expand Up @@ -988,7 +1015,7 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)

dd->last_rounded_m = min_e_m;
dd->last_rounded_n = min_e_n;
dd->last_rounded_rate = _dpll_compute_new_rate(clk->parent->rate,
dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate,
min_e_m, min_e_n);

pr_debug("clock: final least error: e = %d, m = %d, n = %d\n",
Expand Down
15 changes: 15 additions & 0 deletions trunk/arch/arm/mach-omap2/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@
/* The maximum error between a target DPLL rate and the rounded rate in Hz */
#define DEFAULT_DPLL_RATE_TOLERANCE 50000

/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
#define CORE_CLK_SRC_32K 0x0
#define CORE_CLK_SRC_DPLL 0x1
#define CORE_CLK_SRC_DPLL_X2 0x2

/* OMAP2xxx CM_CLKEN_PLL.EN_DPLL bits - for omap2_get_dpll_rate() */
#define OMAP2XXX_EN_DPLL_LPBYPASS 0x1
#define OMAP2XXX_EN_DPLL_FRBYPASS 0x2
#define OMAP2XXX_EN_DPLL_LOCKED 0x3

/* OMAP3xxx CM_CLKEN_PLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */
#define OMAP3XXX_EN_DPLL_LPBYPASS 0x5
#define OMAP3XXX_EN_DPLL_FRBYPASS 0x6
#define OMAP3XXX_EN_DPLL_LOCKED 0x7

int omap2_clk_init(void);
int omap2_clk_enable(struct clk *clk);
void omap2_clk_disable(struct clk *clk);
Expand Down
39 changes: 26 additions & 13 deletions trunk/arch/arm/mach-omap2/clock24xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,19 +236,32 @@ static struct clk *sclk;
* Omap24xx specific clock functions
*-------------------------------------------------------------------------*/

/* This actually returns the rate of core_ck, not dpll_ck. */
static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
/**
* omap2xxx_clk_get_core_rate - return the CORE_CLK rate
* @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck")
*
* Returns the CORE_CLK rate. CORE_CLK can have one of three rate
* sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
* (the latter is unusual). This currently should be called with
* struct clk *dpll_ck, which is a composite clock of dpll_ck and
* core_ck.
*/
static unsigned long omap2xxx_clk_get_core_rate(struct clk *clk)
{
long long dpll_clk;
u8 amult;
long long core_clk;
u32 v;

dpll_clk = omap2_get_dpll_rate(tclk);
core_clk = omap2_get_dpll_rate(clk);

amult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
amult &= OMAP24XX_CORE_CLK_SRC_MASK;
dpll_clk *= amult;
v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
v &= OMAP24XX_CORE_CLK_SRC_MASK;

if (v == CORE_CLK_SRC_32K)
core_clk = 32768;
else
core_clk *= v;

return dpll_clk;
return core_clk;
}

static int omap2_enable_osc_ck(struct clk *clk)
Expand Down Expand Up @@ -371,7 +384,7 @@ static long omap2_dpllcore_round_rate(unsigned long target_rate)

static unsigned long omap2_dpllcore_recalc(struct clk *clk)
{
return omap2_get_dpll_rate_24xx(clk);
return omap2xxx_clk_get_core_rate(clk);
}

static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
Expand All @@ -381,7 +394,7 @@ static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
struct prcm_config tmpset;
const struct dpll_data *dd;

cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck);
mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
mult &= OMAP24XX_CORE_CLK_SRC_MASK;

Expand Down Expand Up @@ -516,7 +529,7 @@ static int omap2_select_table_rate(struct clk *clk, unsigned long rate)
}

curr_prcm_set = prcm;
cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck);

if (prcm->dpll_speed == cur_rate / 2) {
omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
Expand Down Expand Up @@ -728,7 +741,7 @@ int __init omap2_clk_init(void)
}

/* Check the MPU rate set by bootloader */
clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
clkrate = omap2xxx_clk_get_core_rate(&dpll_ck);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
Expand Down
4 changes: 4 additions & 0 deletions trunk/arch/arm/mach-omap2/clock24xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,10 @@ static struct dpll_data dpll_dd = {
.mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
.mult_mask = OMAP24XX_DPLL_MULT_MASK,
.div1_mask = OMAP24XX_DPLL_DIV_MASK,
.clk_bypass = &sys_ck,
.clk_ref = &sys_ck,
.control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
.enable_mask = OMAP24XX_EN_DPLL_MASK,
.max_multiplier = 1024,
.min_divider = 1,
.max_divider = 16,
Expand Down
90 changes: 71 additions & 19 deletions trunk/arch/arm/mach-omap2/clock34xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ static struct omap_clk omap34xx_clks[] = {
CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck, CK_343X),
CLK(NULL, "omap_96m_fck", &omap_96m_fck, CK_343X),
CLK(NULL, "cm_96m_fck", &cm_96m_fck, CK_343X),
CLK(NULL, "virt_omap_54m_fck", &virt_omap_54m_fck, CK_343X),
CLK(NULL, "omap_54m_fck", &omap_54m_fck, CK_343X),
CLK(NULL, "omap_48m_fck", &omap_48m_fck, CK_343X),
CLK(NULL, "omap_12m_fck", &omap_12m_fck, CK_343X),
Expand All @@ -110,7 +109,6 @@ static struct omap_clk omap34xx_clks[] = {
CLK(NULL, "emu_per_alwon_ck", &emu_per_alwon_ck, CK_343X),
CLK(NULL, "dpll5_ck", &dpll5_ck, CK_3430ES2),
CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck, CK_3430ES2),
CLK(NULL, "omap_120m_fck", &omap_120m_fck, CK_3430ES2),
CLK(NULL, "clkout2_src_ck", &clkout2_src_ck, CK_343X),
CLK(NULL, "sys_clkout2", &sys_clkout2, CK_343X),
CLK(NULL, "corex2_fck", &corex2_fck, CK_343X),
Expand Down Expand Up @@ -344,7 +342,7 @@ static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n)
unsigned long fint;
u16 f = 0;

fint = clk->parent->rate / (n + 1);
fint = clk->dpll_data->clk_ref->rate / (n + 1);

pr_debug("clock: fint is %lu\n", fint);

Expand Down Expand Up @@ -411,7 +409,7 @@ static int _omap3_noncore_dpll_lock(struct clk *clk)
}

/*
* 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
Expand Down Expand Up @@ -501,14 +499,25 @@ static int _omap3_noncore_dpll_stop(struct clk *clk)
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->clk_bypass->rate) {
WARN_ON(clk->parent != dd->clk_bypass);
r = _omap3_noncore_dpll_bypass(clk);
else
} else {
WARN_ON(clk->parent != dd->clk_ref);
r = _omap3_noncore_dpll_lock(clk);
}
/* FIXME: this is dubious - if clk->rate has changed, what about propagating? */
if (!r)
clk->rate = omap2_get_dpll_rate(clk);

return r;
}
Expand Down Expand Up @@ -583,13 +592,18 @@ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
* @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)
{
struct clk *new_parent = NULL;
u16 freqsel;
struct dpll_data *dd;
int ret;

if (!clk || !rate)
return -EINVAL;
Expand All @@ -601,18 +615,56 @@ static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
if (rate == omap2_get_dpll_rate(clk))
return 0;

if (dd->last_rounded_rate != rate)
omap2_dpll_round_rate(clk, rate);
/*
* Ensure both the bypass and ref clocks are enabled prior to
* doing anything; we need the bypass clock running to reprogram
* the DPLL.
*/
omap2_clk_enable(dd->clk_bypass);
omap2_clk_enable(dd->clk_ref);

if (dd->clk_bypass->rate == rate &&
(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);

if (dd->last_rounded_rate == 0)
return -EINVAL;
ret = _omap3_noncore_dpll_bypass(clk);
if (!ret)
new_parent = dd->clk_bypass;
} 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)
new_parent = dd->clk_ref;
}
if (!ret) {
/*
* Switch the parent clock in the heirarchy, and make sure
* that the new parent's usecount is correct. Note: we
* enable the new parent before disabling the old to avoid
* any unnecessary hardware disable->enable transitions.
*/
if (clk->usecount) {
omap2_clk_enable(new_parent);
omap2_clk_disable(clk->parent);
}
clk_reparent(clk, new_parent);
clk->rate = rate;
}
omap2_clk_disable(dd->clk_ref);
omap2_clk_disable(dd->clk_bypass);

return 0;
}
Expand Down Expand Up @@ -804,11 +856,11 @@ static unsigned long omap3_clkoutx2_recalc(struct clk *clk)

dd = pclk->dpll_data;

WARN_ON(!dd->control_reg || !dd->enable_mask);
WARN_ON(!dd->enable_mask);

v = __raw_readl(dd->control_reg) & dd->enable_mask;
v >>= __ffs(dd->enable_mask);
if (v != DPLL_LOCKED)
if (v != OMAP3XXX_EN_DPLL_LOCKED)
rate = clk->parent->rate;
else
rate = clk->parent->rate * 2;
Expand Down
Loading

0 comments on commit fe26d18

Please sign in to comment.