aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Stuebner <heiko@sntech.de>2014-11-20 14:38:52 -0500
committerHeiko Stuebner <heiko@sntech.de>2014-11-25 03:57:18 -0500
commit0bb66d3b6e78168f8f49c7a41060508707f04d1d (patch)
tree812b8a0face8604c03d472bbb75b7066b092687e
parentd0e7a0ca4b57483e424334c453818529148baafd (diff)
clk: rockchip: add optional sync to pll rate parameters
In some cases firmware brings up plls with different parameters than the ones noted in the rate table for the specific frequency. These firmware-selected parameters are worse than the tested ones in the pll rate tables but cannot be changed by a simple clk_set_rate call when the rate stays the same. Therefore add a ROCKCHIP_PLL_SYNC_RATE flag and implement an init callback that checks the runtime-parameters against the matching rate table entry and adjusts them to the table-ones if necessary. If no rate table is set or the current rate does not match any rate-table entry no changes are made. Being able to limit this adjustment to specific plls is necessary to not touch the ones supplying core components like the apll and dpll supplying the armcores and dram. Signed-off-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Kever Yang <kever.yang@rock-chips.com> Tested-by: Kever Yang <kever.yang@rock-chips.com>
-rw-r--r--drivers/clk/rockchip/clk-pll.c50
-rw-r--r--drivers/clk/rockchip/clk.h6
2 files changed, 56 insertions, 0 deletions
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 1bb68910a76b..f8d3baf275b2 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -258,6 +258,55 @@ static int rockchip_rk3066_pll_is_enabled(struct clk_hw *hw)
258 return !(pllcon & RK3066_PLLCON3_PWRDOWN); 258 return !(pllcon & RK3066_PLLCON3_PWRDOWN);
259} 259}
260 260
261static void rockchip_rk3066_pll_init(struct clk_hw *hw)
262{
263 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
264 const struct rockchip_pll_rate_table *rate;
265 unsigned int nf, nr, no, bwadj;
266 unsigned long drate;
267 u32 pllcon;
268
269 if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
270 return;
271
272 drate = __clk_get_rate(hw->clk);
273 rate = rockchip_get_pll_settings(pll, drate);
274
275 /* when no rate setting for the current rate, rely on clk_set_rate */
276 if (!rate)
277 return;
278
279 pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(0));
280 nr = ((pllcon >> RK3066_PLLCON0_NR_SHIFT) & RK3066_PLLCON0_NR_MASK) + 1;
281 no = ((pllcon >> RK3066_PLLCON0_OD_SHIFT) & RK3066_PLLCON0_OD_MASK) + 1;
282
283 pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(1));
284 nf = ((pllcon >> RK3066_PLLCON1_NF_SHIFT) & RK3066_PLLCON1_NF_MASK) + 1;
285
286 pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(2));
287 bwadj = (pllcon >> RK3066_PLLCON2_BWADJ_SHIFT) & RK3066_PLLCON2_BWADJ_MASK;
288
289 pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), bwadj(%d:%d)\n",
290 __func__, __clk_get_name(hw->clk), drate, rate->nr, nr,
291 rate->no, no, rate->nf, nf, rate->bwadj, bwadj);
292 if (rate->nr != nr || rate->no != no || rate->nf != nf
293 || rate->bwadj != bwadj) {
294 struct clk *parent = __clk_get_parent(hw->clk);
295 unsigned long prate;
296
297 if (!parent) {
298 pr_warn("%s: parent of %s not available\n",
299 __func__, __clk_get_name(hw->clk));
300 return;
301 }
302
303 pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
304 __func__, __clk_get_name(hw->clk));
305 prate = __clk_get_rate(parent);
306 rockchip_rk3066_pll_set_rate(hw, drate, prate);
307 }
308}
309
261static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = { 310static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = {
262 .recalc_rate = rockchip_rk3066_pll_recalc_rate, 311 .recalc_rate = rockchip_rk3066_pll_recalc_rate,
263 .enable = rockchip_rk3066_pll_enable, 312 .enable = rockchip_rk3066_pll_enable,
@@ -272,6 +321,7 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = {
272 .enable = rockchip_rk3066_pll_enable, 321 .enable = rockchip_rk3066_pll_enable,
273 .disable = rockchip_rk3066_pll_disable, 322 .disable = rockchip_rk3066_pll_disable,
274 .is_enabled = rockchip_rk3066_pll_is_enabled, 323 .is_enabled = rockchip_rk3066_pll_is_enabled,
324 .init = rockchip_rk3066_pll_init,
275}; 325};
276 326
277/* 327/*
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index eefd39a3820b..dc9468132ef1 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -92,6 +92,10 @@ struct rockchip_pll_rate_table {
92 * @type: Type of PLL to be registered. 92 * @type: Type of PLL to be registered.
93 * @pll_flags: hardware-specific flags 93 * @pll_flags: hardware-specific flags
94 * @rate_table: Table of usable pll rates 94 * @rate_table: Table of usable pll rates
95 *
96 * Flags:
97 * ROCKCHIP_PLL_SYNC_RATE - check rate parameters to match against the
98 * rate_table parameters and ajust them if necessary.
95 */ 99 */
96struct rockchip_pll_clock { 100struct rockchip_pll_clock {
97 unsigned int id; 101 unsigned int id;
@@ -108,6 +112,8 @@ struct rockchip_pll_clock {
108 struct rockchip_pll_rate_table *rate_table; 112 struct rockchip_pll_rate_table *rate_table;
109}; 113};
110 114
115#define ROCKCHIP_PLL_SYNC_RATE BIT(0)
116
111#define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift, \ 117#define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift, \
112 _lshift, _pflags, _rtable) \ 118 _lshift, _pflags, _rtable) \
113 { \ 119 { \