summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFinley Xiao <finley.xiao@rock-chips.com>2018-02-22 10:52:05 +0800
committerTao Huang <huangtao@rock-chips.com>2018-02-22 15:30:40 +0800
commit14aba8d3783b8a3d24ee486982dc730a478e0e2a (patch)
treed4c30f0c834a80e89671347cb03597b26603528c
parent2c1c86dca03672433064faf67976c01a3b25e7f1 (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.c42
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)