From: dkl Date: Tue, 21 Jan 2014 08:55:26 +0000 (+0800) Subject: clk: rockchip: add clk_core ops support X-Git-Tag: firefly_0821_release~6376 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=46b52450158fedc727dd5877c381ef0d3d8e2c38;p=firefly-linux-kernel-4.4.55.git clk: rockchip: add clk_core ops support --- diff --git a/arch/arm/boot/dts/rk3188-clocks.dtsi b/arch/arm/boot/dts/rk3188-clocks.dtsi index 0097acce16f7..807503d41ae7 100755 --- a/arch/arm/boot/dts/rk3188-clocks.dtsi +++ b/arch/arm/boot/dts/rk3188-clocks.dtsi @@ -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 = ; + rockchip,clkops-idx = ; #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 = ; + rockchip,clkops-idx = ; }; /* reg[15:14]: reserved */ @@ -197,6 +201,7 @@ clock-output-names = "aclk_core"; #clock-cells = <0>; rockchip,div-type = ; + rockchip,clkops-idx = ; 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>; }; }; diff --git a/drivers/clk/rockchip/clk-ops.c b/drivers/clk/rockchip/clk-ops.c index 8527f1aa6130..e895f55fda7c 100644 --- a/drivers/clk/rockchip/clk-ops.c +++ b/drivers/clk/rockchip/clk-ops.c @@ -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}, diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 8bd252ad43f8..eafc7cec0d28 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -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) { diff --git a/drivers/clk/rockchip/clkops-dtsi.h b/drivers/clk/rockchip/clkops-dtsi.h index 578e5bd81896..07af92b37570 100644 --- a/drivers/clk/rockchip/clkops-dtsi.h +++ b/drivers/clk/rockchip/clkops-dtsi.h @@ -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)