mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
clk: rockchip: add clk_core ops support
This commit is contained in:
@@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user