From: dkl Date: Wed, 28 May 2014 09:45:06 +0000 (+0800) Subject: clk: rk3288: when apll change rate, adjust div to make rate change more gently X-Git-Tag: firefly_0821_release~5209 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0a450169ab44b143c49164ececdfc5b53afe3573;p=firefly-linux-kernel-4.4.55.git clk: rk3288: when apll change rate, adjust div to make rate change more gently --- diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 56005494fd33..4045fad75d7e 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -1135,7 +1135,7 @@ static int clk_pll_set_rate_3288_apll(struct clk_hw *hw, unsigned long rate, struct clk_pll *pll = to_clk_pll(hw); struct clk *clk = hw->clk; struct clk *arm_gpll = __clk_lookup("clk_arm_gpll"); - unsigned long arm_gpll_rate; + unsigned long arm_gpll_rate, temp_rate, old_rate; const struct apll_clk_set *ps; // u32 old_aclk_div = 0, new_aclk_div = 0; u32 temp_div; @@ -1168,8 +1168,11 @@ static int clk_pll_set_rate_3288_apll(struct clk_hw *hw, unsigned long rate, } arm_gpll_rate = __clk_get_rate(arm_gpll); - temp_div = DIV_ROUND_UP(arm_gpll_rate, __clk_get_rate(clk)); - temp_div = (temp_div == 0) ? 1 : temp_div; + old_rate = __clk_get_rate(clk); + + temp_rate = (old_rate > rate) ? old_rate : rate; + temp_div = DIV_ROUND_UP(arm_gpll_rate, temp_rate); + if (temp_div > RK3288_CORE_CLK_MAX_DIV) { clk_debug("temp_div %d > max_div %d\n", temp_div, RK3288_CORE_CLK_MAX_DIV); @@ -1195,10 +1198,30 @@ static int clk_pll_set_rate_3288_apll(struct clk_hw *hw, unsigned long rate, local_irq_save(flags); - /* firstly set div, then select arm_gpll path */ - cru_writel(RK3288_CORE_CLK_DIV(temp_div), RK3288_CRU_CLKSELS_CON(0)); - cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_GPLL, - RK3288_CRU_CLKSELS_CON(0)); + /* select gpll */ + if (temp_div == 1) { + /* when old_rate/2 < (old_rate-arm_gpll_rate), + we can set div to make rate change more gently */ + if (old_rate > (2*arm_gpll_rate)) { + cru_writel(RK3288_CORE_CLK_DIV(2), RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_CLK_DIV(3), RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_GPLL, + RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_CLK_DIV(2), RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_CLK_DIV(1), RK3288_CRU_CLKSELS_CON(0)); + } else { + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_GPLL, + RK3288_CRU_CLKSELS_CON(0)); + } + } else { + cru_writel(RK3288_CORE_CLK_DIV(temp_div), RK3288_CRU_CLKSELS_CON(0)); + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_GPLL, + RK3288_CRU_CLKSELS_CON(0)); + } sel_gpll = 1; //loops_per_jiffy = CLK_LOOPS_RECALC(arm_gpll_rate) / temp_div; @@ -1255,9 +1278,29 @@ CHANGE_APLL: /* reparent to apll, and set div to 1 */ if (sel_gpll) { - cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_APLL, - RK3288_CRU_CLKSELS_CON(0)); - cru_writel(RK3288_CORE_CLK_DIV(1), RK3288_CRU_CLKSELS_CON(0)); + if (temp_div == 1) { + /* when rate/2 < (old_rate-arm_gpll_rate), + we can set div to make rate change more gently */ + if (rate > (2*arm_gpll_rate)) { + cru_writel(RK3288_CORE_CLK_DIV(2), RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_CLK_DIV(3), RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_APLL, + RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_CLK_DIV(2), RK3288_CRU_CLKSELS_CON(0)); + udelay(10); + cru_writel(RK3288_CORE_CLK_DIV(1), RK3288_CRU_CLKSELS_CON(0)); + } else { + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_APLL, + RK3288_CRU_CLKSELS_CON(0)); + } + } else { + cru_writel(RK3288_CORE_SEL_PLL_W_MSK|RK3288_CORE_SEL_APLL, + RK3288_CRU_CLKSELS_CON(0)); + cru_writel(RK3288_CORE_CLK_DIV(1), RK3288_CRU_CLKSELS_CON(0)); + } } if (rate < __clk_get_rate(hw->clk)) {