Commit de381a91 authored by Sekhar Nori's avatar Sekhar Nori Committed by Kevin Hilman

davinci: make clock rate re-calculation easy

Make clock rate recalculation easy by having a re-calculate
function for each clock.

The existing functions for calculation of output rates of PLL
and PLL-derived sysclks have been convered to the new
re-calculate API.

A new function is introduced to take care of rate
(re)calculation for leaf clocks.
Signed-off-by: default avatarSekhar Nori <nsekhar@ti.com>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent f02bf3b3
...@@ -135,8 +135,12 @@ int clk_register(struct clk *clk) ...@@ -135,8 +135,12 @@ int clk_register(struct clk *clk)
if (clk->rate) if (clk->rate)
return 0; return 0;
/* Else, see if there is a way to calculate it */
if (clk->recalc)
clk->rate = clk->recalc(clk);
/* Otherwise, default to parent rate */ /* Otherwise, default to parent rate */
if (clk->parent) else if (clk->parent)
clk->rate = clk->parent->rate; clk->rate = clk->parent->rate;
return 0; return 0;
...@@ -184,50 +188,62 @@ static int __init clk_disable_unused(void) ...@@ -184,50 +188,62 @@ static int __init clk_disable_unused(void)
late_initcall(clk_disable_unused); late_initcall(clk_disable_unused);
#endif #endif
static void clk_sysclk_recalc(struct clk *clk) static unsigned long clk_sysclk_recalc(struct clk *clk)
{ {
u32 v, plldiv; u32 v, plldiv;
struct pll_data *pll; struct pll_data *pll;
unsigned long rate = clk->rate;
/* If this is the PLL base clock, no more calculations needed */ /* If this is the PLL base clock, no more calculations needed */
if (clk->pll_data) if (clk->pll_data)
return; return rate;
if (WARN_ON(!clk->parent)) if (WARN_ON(!clk->parent))
return; return rate;
clk->rate = clk->parent->rate; rate = clk->parent->rate;
/* Otherwise, the parent must be a PLL */ /* Otherwise, the parent must be a PLL */
if (WARN_ON(!clk->parent->pll_data)) if (WARN_ON(!clk->parent->pll_data))
return; return rate;
pll = clk->parent->pll_data; pll = clk->parent->pll_data;
/* If pre-PLL, source clock is before the multiplier and divider(s) */ /* If pre-PLL, source clock is before the multiplier and divider(s) */
if (clk->flags & PRE_PLL) if (clk->flags & PRE_PLL)
clk->rate = pll->input_rate; rate = pll->input_rate;
if (!clk->div_reg) if (!clk->div_reg)
return; return rate;
v = __raw_readl(pll->base + clk->div_reg); v = __raw_readl(pll->base + clk->div_reg);
if (v & PLLDIV_EN) { if (v & PLLDIV_EN) {
plldiv = (v & PLLDIV_RATIO_MASK) + 1; plldiv = (v & PLLDIV_RATIO_MASK) + 1;
if (plldiv) if (plldiv)
clk->rate /= plldiv; rate /= plldiv;
} }
return rate;
} }
static void __init clk_pll_init(struct clk *clk) static unsigned long clk_leafclk_recalc(struct clk *clk)
{
if (WARN_ON(!clk->parent))
return clk->rate;
return clk->parent->rate;
}
static unsigned long clk_pllclk_recalc(struct clk *clk)
{ {
u32 ctrl, mult = 1, prediv = 1, postdiv = 1; u32 ctrl, mult = 1, prediv = 1, postdiv = 1;
u8 bypass; u8 bypass;
struct pll_data *pll = clk->pll_data; struct pll_data *pll = clk->pll_data;
unsigned long rate = clk->rate;
pll->base = IO_ADDRESS(pll->phys_base); pll->base = IO_ADDRESS(pll->phys_base);
ctrl = __raw_readl(pll->base + PLLCTL); ctrl = __raw_readl(pll->base + PLLCTL);
clk->rate = pll->input_rate = clk->parent->rate; rate = pll->input_rate = clk->parent->rate;
if (ctrl & PLLCTL_PLLEN) { if (ctrl & PLLCTL_PLLEN) {
bypass = 0; bypass = 0;
...@@ -260,9 +276,9 @@ static void __init clk_pll_init(struct clk *clk) ...@@ -260,9 +276,9 @@ static void __init clk_pll_init(struct clk *clk)
} }
if (!bypass) { if (!bypass) {
clk->rate /= prediv; rate /= prediv;
clk->rate *= mult; rate *= mult;
clk->rate /= postdiv; rate /= postdiv;
} }
pr_debug("PLL%d: input = %lu MHz [ ", pr_debug("PLL%d: input = %lu MHz [ ",
...@@ -275,7 +291,9 @@ static void __init clk_pll_init(struct clk *clk) ...@@ -275,7 +291,9 @@ static void __init clk_pll_init(struct clk *clk)
pr_debug("* %d ", mult); pr_debug("* %d ", mult);
if (postdiv > 1) if (postdiv > 1)
pr_debug("/ %d ", postdiv); pr_debug("/ %d ", postdiv);
pr_debug("] --> %lu MHz output.\n", clk->rate / 1000000); pr_debug("] --> %lu MHz output.\n", rate / 1000000);
return rate;
} }
int __init davinci_clk_init(struct davinci_clk *clocks) int __init davinci_clk_init(struct davinci_clk *clocks)
...@@ -286,12 +304,23 @@ int __init davinci_clk_init(struct davinci_clk *clocks) ...@@ -286,12 +304,23 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
for (c = clocks; c->lk.clk; c++) { for (c = clocks; c->lk.clk; c++) {
clk = c->lk.clk; clk = c->lk.clk;
if (!clk->recalc) {
/* Check if clock is a PLL */
if (clk->pll_data) if (clk->pll_data)
clk_pll_init(clk); clk->recalc = clk_pllclk_recalc;
/* Calculate rates for PLL-derived clocks */ /* Else, if it is a PLL-derived clock */
else if (clk->flags & CLK_PLL) else if (clk->flags & CLK_PLL)
clk_sysclk_recalc(clk); clk->recalc = clk_sysclk_recalc;
/* Otherwise, it is a leaf clock (PSC clock) */
else if (clk->parent)
clk->recalc = clk_leafclk_recalc;
}
if (clk->recalc)
clk->rate = clk->recalc(clk);
if (clk->lpsc) if (clk->lpsc)
clk->flags |= CLK_PSC; clk->flags |= CLK_PSC;
......
...@@ -73,6 +73,7 @@ struct clk { ...@@ -73,6 +73,7 @@ struct clk {
struct list_head childnode; /* parent's child list node */ struct list_head childnode; /* parent's child list node */
struct pll_data *pll_data; struct pll_data *pll_data;
u32 div_reg; u32 div_reg;
unsigned long (*recalc) (struct clk *);
}; };
/* Clock flags */ /* Clock flags */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment