diff options
author | Finley Xiao <finley.xiao@rock-chips.com> | 2018-02-22 10:52:05 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-02-22 15:30:40 +0800 |
commit | 14aba8d3783b8a3d24ee486982dc730a478e0e2a (patch) | |
tree | d4c30f0c834a80e89671347cb03597b26603528c | |
parent | 2c1c86dca03672433064faf67976c01a3b25e7f1 (diff) |
clk: rockchip: Fix cpu frequency overflowing
If change parent to alternate parent and the old parent clock speed is less
than the clock speed of the alternate parent, add dividers first and then
select alternate parent.
If change parent to primary parent, select primary parent first and then
remove dividers.
Change-Id: Ib82de9a936effe5c885639799f3bb5629dc89f8d
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
-rw-r--r-- | drivers/clk/rockchip/clk-cpu.c | 42 |
1 files changed, 15 insertions, 27 deletions
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c index 4d9f38de342b..675f10cc0ed4 100644 --- a/drivers/clk/rockchip/clk-cpu.c +++ b/drivers/clk/rockchip/clk-cpu.c @@ -158,30 +158,21 @@ static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk, alt_div = reg_data->div_core_mask; } - /* - * Change parents and add dividers in a single transaction. - * - * NOTE: we do this in a single transaction so we're never - * dividing the primary parent by the extra dividers that were - * needed for the alt. - */ pr_debug("%s: setting div %lu as alt-rate %lu > old-rate %lu\n", __func__, alt_div, alt_prate, ndata->old_rate); + /* add dividers */ writel(HIWORD_UPDATE(alt_div, reg_data->div_core_mask, - reg_data->div_core_shift) | - HIWORD_UPDATE(reg_data->mux_core_alt, - reg_data->mux_core_mask, - reg_data->mux_core_shift), - cpuclk->reg_base + reg_data->core_reg); - } else { - /* select alternate parent */ - writel(HIWORD_UPDATE(reg_data->mux_core_alt, - reg_data->mux_core_mask, - reg_data->mux_core_shift), + reg_data->div_core_shift), cpuclk->reg_base + reg_data->core_reg); } + /* select alternate parent */ + writel(HIWORD_UPDATE(reg_data->mux_core_alt, + reg_data->mux_core_mask, + reg_data->mux_core_shift), + cpuclk->reg_base + reg_data->core_reg); + spin_unlock_irqrestore(cpuclk->lock, flags); return 0; } @@ -206,18 +197,15 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk, if (ndata->old_rate < ndata->new_rate) rockchip_cpuclk_set_dividers(cpuclk, rate); - /* - * post-rate change event, re-mux to primary parent and remove dividers. - * - * NOTE: we do this in a single transaction so we're never dividing the - * primary parent by the extra dividers that were needed for the alt. - */ + /* re-mux to primary parent */ + writel(HIWORD_UPDATE(reg_data->mux_core_main, + reg_data->mux_core_mask, + reg_data->mux_core_shift), + cpuclk->reg_base + reg_data->core_reg); + /* remove dividers */ writel(HIWORD_UPDATE(0, reg_data->div_core_mask, - reg_data->div_core_shift) | - HIWORD_UPDATE(reg_data->mux_core_main, - reg_data->mux_core_mask, - reg_data->mux_core_shift), + reg_data->div_core_shift), cpuclk->reg_base + reg_data->core_reg); if (ndata->old_rate > ndata->new_rate) |