clk: rockchip: add clk_core ops support

This commit is contained in:
dkl
2014-01-21 16:55:26 +08:00
parent a713b86ca3
commit 46b5245015
4 changed files with 91 additions and 10 deletions

View File

@@ -145,7 +145,7 @@
rockchip,bits = <5 1>;
clocks = <&clk_apll>, <&clk_gpll>;
clock-output-names = "aclk_cpu";
#clock-cells = <0>;
#clock-cells = <0>;
#clock-init-cells = <1>;
};
@@ -155,6 +155,7 @@
clocks = <&clk_core>;
clock-output-names = "clk_core_peri";
rockchip,div-type = <CLK_DIVIDER_USER_DEFINE>;
rockchip,clkops-idx = <CLKOPS_RATE_CORE_PERI>;
#clock-cells = <0>;
rockchip,div-relations = <0x0 2
0x1 4
@@ -168,6 +169,8 @@
clocks = <&clk_apll>,
<&clk_gates0 1>;
clock-output-names = "clk_core";
rockchip,flags = <(CLK_GET_RATE_NOCACHE |
CLK_SET_RATE_NO_REPARENT)>;
#clock-cells = <0>;
};
@@ -176,6 +179,7 @@
rockchip,bits = <9 5>;
clocks = <&clk_core>;
rockchip,div-type = <CLK_DIVIDER_PLUS_ONE>;
rockchip,clkops-idx = <CLKOPS_RATE_CORE>;
};
/* reg[15:14]: reserved */
@@ -197,6 +201,7 @@
clock-output-names = "aclk_core";
#clock-cells = <0>;
rockchip,div-type = <CLK_DIVIDER_USER_DEFINE>;
rockchip,clkops-idx = <CLKOPS_RATE_CORE_PERI>;
rockchip,div-relations = <0x0 1
0x1 2
0x2 3
@@ -398,7 +403,7 @@
rockchip,bits = <15 1>;
clocks = <&clk_cpll>, <&clk_gpll>;
clock-output-names = "aclk_peri_mux";
#clock-cells = <0>;
#clock-cells = <0>;
#clock-init-cells = <1>;
};
};

View File

@@ -310,12 +310,81 @@ const struct clk_ops clkops_rate_i2s_frac = {
.set_rate = clk_fracdiv_set_rate,
};
static unsigned long clk_core_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
/* As parent rate could be changed in clk_core.set_rate
* ops, the passing_in parent_rate may not be the newest
* and we should use the parent->rate instead. As a side
* effect, we should NOT directly set clk_core's parent
* (apll) rate, otherwise we will get a wrong recalc rate
* with clk_core_recalc_rate.
*/
struct clk *parent = __clk_get_parent(hw->clk);
return clk_divider_recalc_rate(hw, __clk_get_rate(parent));
}
static long clk_core_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *parent = __clk_get_parent(hw->clk);
if (IS_ERR_OR_NULL(parent)) {
clk_err("fail to get parent!\n");
return 0;
}
return clk_round_rate(parent, rate);
}
static long clk_core_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
return clk_core_determine_rate(hw, rate, prate, NULL);
}
static int clk_core_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk *parent = __clk_get_parent(hw->clk);
struct clk *grand_p = __clk_get_parent(parent);
int ret;
if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
clk_err("fail to get parent or grand_parent!\n");
return -EINVAL;
}
ret = parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
parent->rate = parent->ops->recalc_rate(parent->hw,
__clk_get_rate(grand_p));
return ret;
}
const struct clk_ops clkops_rate_core = {
.recalc_rate = clk_core_recalc_rate,
.round_rate = clk_core_round_rate,
.set_rate = clk_core_set_rate,
.determine_rate = clk_core_determine_rate,
};
const struct clk_ops clkops_rate_core_peri = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_divider_round_rate,
.set_rate = NULL,
};
struct clk_ops_table rk_clkops_rate_table[] = {
{.index = CLKOPS_RATE_MUX_DIV, .clk_ops = &clkops_rate_auto_parent},
{.index = CLKOPS_RATE_EVENDIV, .clk_ops = &clkops_rate_evendiv},
{.index = CLKOPS_RATE_DCLK_LCDC, .clk_ops = &clkops_rate_dclk_lcdc},
{.index = CLKOPS_RATE_I2S_FRAC, .clk_ops = &clkops_rate_i2s_frac},
{.index = CLKOPS_RATE_FRAC, .clk_ops = &clkops_rate_frac},
{.index = CLKOPS_RATE_CORE, .clk_ops = &clkops_rate_core},
{.index = CLKOPS_RATE_CORE_PERI, .clk_ops = &clkops_rate_core_peri},
{.index = CLKOPS_RATE_I2S, .clk_ops = NULL},
{.index = CLKOPS_RATE_CIFOUT, .clk_ops = NULL},
{.index = CLKOPS_RATE_UART, .clk_ops = NULL},

View File

@@ -154,7 +154,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
rate = rate64;
} else {
rate = parent_rate;
clk_debug("pll id=%d by pass mode\n", pll_id);
clk_debug("pll id=%d slow mode\n", pll_id);
}
clk_debug("pll id=%d, recalc rate =%lu\n", pll->id, rate);
@@ -284,8 +284,10 @@ static int _pll_clk_set_rate(struct pll_clk_set *clk_set, u8 pll_id,
if (lock)
spin_unlock_irqrestore(lock, flags);
clk_debug("pll id=%d, dump reg:\n con0=%x,con1=%x,mode=%x\n", pll_id,
cru_readl(PLL_CONS(pll_id,0)),(PLL_CONS(pll_id,1)),
clk_debug("pll id=%d, dump reg: con0=0x%08x, con1=0x%08x, mode=0x%08x\n",
pll_id,
cru_readl(PLL_CONS(pll_id,0)),
cru_readl(PLL_CONS(pll_id,1)),
cru_readl(CRU_MODE_CON));
clk_debug("_pll_clk_set_rate end!\n");
@@ -412,8 +414,9 @@ static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
CHANGE_APLL:
ps = apll_get_best_set(rate, apll_table);
clk_debug("apll will set rate(%lu) table con(%x,%x,%x),sel(%x,%x)\n",
ps->rate, ps->pllcon0, ps->pllcon1, ps->pllcon2,
clk_debug("apll will set rate %lu\n", ps->rate);
clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n",
ps->pllcon0, ps->pllcon1, ps->pllcon2,
ps->clksel0, ps->clksel1);
local_irq_save(flags);
@@ -421,8 +424,9 @@ CHANGE_APLL:
/* If core src don't select gpll, apll need to enter slow mode
* before power down
*/
//FIXME
//if(!sel_gpll)
cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON);
cru_writel(PLL_MODE_SLOW(pll->id), CRU_MODE_CON);
/* PLL power down */
cru_writel((0x1<<(16+1))|(0x1<<1), PLL_CONS(pll->id, 3));
@@ -451,8 +455,9 @@ CHANGE_APLL:
}
/* PLL return from slow mode */
//if (!sel_gpll)
cru_writel(PLL_MODE_NORM(APLL_ID), CRU_MODE_CON);
//FIXME
//if(!sel_gpll)
cru_writel(PLL_MODE_NORM(pll->id), CRU_MODE_CON);
/* reparent to apll, and set div to 1 */
if (sel_gpll) {

View File

@@ -20,6 +20,8 @@
#define CLKOPS_RATE_UART 7
#define CLKOPS_RATE_HSADC 8
#define CLKOPS_RATE_MAC_REF 9
#define CLKOPS_RATE_CORE 10
#define CLKOPS_RATE_CORE_PERI 11
#define CLKOPS_TABLE_END (~0)