| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (c) 2014 MundoReader S.L. | 
|  | 3 | * Author: Heiko Stuebner <heiko@sntech.de> | 
|  | 4 | * | 
|  | 5 | * Copyright (c) 2015 Rockchip Electronics Co. Ltd. | 
|  | 6 | * Author: Xing Zheng <zhengxing@rock-chips.com> | 
|  | 7 | * | 
|  | 8 | * This program is free software; you can redistribute it and/or modify | 
|  | 9 | * it under the terms of the GNU General Public License as published by | 
|  | 10 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 11 | * (at your option) any later version. | 
|  | 12 | * | 
|  | 13 | * This program is distributed in the hope that it will be useful, | 
|  | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 16 | * GNU General Public License for more details. | 
|  | 17 | */ | 
|  | 18 |  | 
|  | 19 | #include <asm/div64.h> | 
|  | 20 | #include <linux/slab.h> | 
|  | 21 | #include <linux/io.h> | 
|  | 22 | #include <linux/delay.h> | 
|  | 23 | #include <linux/clk-provider.h> | 
|  | 24 | #include <linux/regmap.h> | 
|  | 25 | #include <linux/clk.h> | 
|  | 26 | #include "clk.h" | 
|  | 27 |  | 
|  | 28 | #define PLL_MODE_MASK		0x3 | 
|  | 29 | #define PLL_MODE_SLOW		0x0 | 
|  | 30 | #define PLL_MODE_NORM		0x1 | 
|  | 31 | #define PLL_MODE_DEEP		0x2 | 
|  | 32 | #define PLL_RK3328_MODE_MASK	0x1 | 
|  | 33 |  | 
|  | 34 | struct rockchip_clk_pll { | 
|  | 35 | struct clk_hw		hw; | 
|  | 36 |  | 
|  | 37 | struct clk_mux		pll_mux; | 
|  | 38 | const struct clk_ops	*pll_mux_ops; | 
|  | 39 |  | 
|  | 40 | struct notifier_block	clk_nb; | 
|  | 41 |  | 
|  | 42 | void __iomem		*reg_base; | 
|  | 43 | int			lock_offset; | 
|  | 44 | unsigned int		lock_shift; | 
|  | 45 | enum rockchip_pll_type	type; | 
|  | 46 | u8			flags; | 
|  | 47 | const struct rockchip_pll_rate_table *rate_table; | 
|  | 48 | unsigned int		rate_count; | 
|  | 49 | spinlock_t		*lock; | 
|  | 50 |  | 
|  | 51 | struct rockchip_clk_provider *ctx; | 
|  | 52 | }; | 
|  | 53 |  | 
|  | 54 | #define to_rockchip_clk_pll(_hw) container_of(_hw, struct rockchip_clk_pll, hw) | 
|  | 55 | #define to_rockchip_clk_pll_nb(nb) \ | 
|  | 56 | container_of(nb, struct rockchip_clk_pll, clk_nb) | 
|  | 57 |  | 
|  | 58 | static const struct rockchip_pll_rate_table *rockchip_get_pll_settings( | 
|  | 59 | struct rockchip_clk_pll *pll, unsigned long rate) | 
|  | 60 | { | 
|  | 61 | const struct rockchip_pll_rate_table  *rate_table = pll->rate_table; | 
|  | 62 | int i; | 
|  | 63 |  | 
|  | 64 | for (i = 0; i < pll->rate_count; i++) { | 
|  | 65 | if (rate == rate_table[i].rate) | 
|  | 66 | return &rate_table[i]; | 
|  | 67 | } | 
|  | 68 |  | 
|  | 69 | return NULL; | 
|  | 70 | } | 
|  | 71 |  | 
|  | 72 | static long rockchip_pll_round_rate(struct clk_hw *hw, | 
|  | 73 | unsigned long drate, unsigned long *prate) | 
|  | 74 | { | 
|  | 75 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 76 | const struct rockchip_pll_rate_table *rate_table = pll->rate_table; | 
|  | 77 | int i; | 
|  | 78 |  | 
|  | 79 | /* Assumming rate_table is in descending order */ | 
|  | 80 | for (i = 0; i < pll->rate_count; i++) { | 
|  | 81 | if (drate >= rate_table[i].rate) | 
|  | 82 | return rate_table[i].rate; | 
|  | 83 | } | 
|  | 84 |  | 
|  | 85 | /* return minimum supported value */ | 
|  | 86 | return rate_table[i - 1].rate; | 
|  | 87 | } | 
|  | 88 |  | 
|  | 89 | /* | 
|  | 90 | * Wait for the pll to reach the locked state. | 
|  | 91 | * The calling set_rate function is responsible for making sure the | 
|  | 92 | * grf regmap is available. | 
|  | 93 | */ | 
|  | 94 | static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) | 
|  | 95 | { | 
|  | 96 | struct regmap *grf = pll->ctx->grf; | 
|  | 97 | unsigned int val; | 
|  | 98 | int delay = 24000000, ret; | 
|  | 99 |  | 
|  | 100 | while (delay > 0) { | 
|  | 101 | ret = regmap_read(grf, pll->lock_offset, &val); | 
|  | 102 | if (ret) { | 
|  | 103 | pr_err("%s: failed to read pll lock status: %d\n", | 
|  | 104 | __func__, ret); | 
|  | 105 | return ret; | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | if (val & BIT(pll->lock_shift)) | 
|  | 109 | return 0; | 
|  | 110 | delay--; | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | pr_err("%s: timeout waiting for pll to lock\n", __func__); | 
|  | 114 | return -ETIMEDOUT; | 
|  | 115 | } | 
|  | 116 |  | 
|  | 117 | /** | 
|  | 118 | * PLL used in RK3036 | 
|  | 119 | */ | 
|  | 120 |  | 
|  | 121 | #define RK3036_PLLCON(i)			(i * 0x4) | 
|  | 122 | #define RK3036_PLLCON0_FBDIV_MASK		0xfff | 
|  | 123 | #define RK3036_PLLCON0_FBDIV_SHIFT		0 | 
|  | 124 | #define RK3036_PLLCON0_POSTDIV1_MASK		0x7 | 
|  | 125 | #define RK3036_PLLCON0_POSTDIV1_SHIFT		12 | 
|  | 126 | #define RK3036_PLLCON1_REFDIV_MASK		0x3f | 
|  | 127 | #define RK3036_PLLCON1_REFDIV_SHIFT		0 | 
|  | 128 | #define RK3036_PLLCON1_POSTDIV2_MASK		0x7 | 
|  | 129 | #define RK3036_PLLCON1_POSTDIV2_SHIFT		6 | 
|  | 130 | #define RK3036_PLLCON1_DSMPD_MASK		0x1 | 
|  | 131 | #define RK3036_PLLCON1_DSMPD_SHIFT		12 | 
|  | 132 | #define RK3036_PLLCON2_FRAC_MASK		0xffffff | 
|  | 133 | #define RK3036_PLLCON2_FRAC_SHIFT		0 | 
|  | 134 |  | 
|  | 135 | #define RK3036_PLLCON1_PWRDOWN			(1 << 13) | 
|  | 136 |  | 
|  | 137 | static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll, | 
|  | 138 | struct rockchip_pll_rate_table *rate) | 
|  | 139 | { | 
|  | 140 | u32 pllcon; | 
|  | 141 |  | 
|  | 142 | pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(0)); | 
|  | 143 | rate->fbdiv = ((pllcon >> RK3036_PLLCON0_FBDIV_SHIFT) | 
|  | 144 | & RK3036_PLLCON0_FBDIV_MASK); | 
|  | 145 | rate->postdiv1 = ((pllcon >> RK3036_PLLCON0_POSTDIV1_SHIFT) | 
|  | 146 | & RK3036_PLLCON0_POSTDIV1_MASK); | 
|  | 147 |  | 
|  | 148 | pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(1)); | 
|  | 149 | rate->refdiv = ((pllcon >> RK3036_PLLCON1_REFDIV_SHIFT) | 
|  | 150 | & RK3036_PLLCON1_REFDIV_MASK); | 
|  | 151 | rate->postdiv2 = ((pllcon >> RK3036_PLLCON1_POSTDIV2_SHIFT) | 
|  | 152 | & RK3036_PLLCON1_POSTDIV2_MASK); | 
|  | 153 | rate->dsmpd = ((pllcon >> RK3036_PLLCON1_DSMPD_SHIFT) | 
|  | 154 | & RK3036_PLLCON1_DSMPD_MASK); | 
|  | 155 |  | 
|  | 156 | pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2)); | 
|  | 157 | rate->frac = ((pllcon >> RK3036_PLLCON2_FRAC_SHIFT) | 
|  | 158 | & RK3036_PLLCON2_FRAC_MASK); | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw, | 
|  | 162 | unsigned long prate) | 
|  | 163 | { | 
|  | 164 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 165 | struct rockchip_pll_rate_table cur; | 
|  | 166 | u64 rate64 = prate; | 
|  | 167 |  | 
|  | 168 | rockchip_rk3036_pll_get_params(pll, &cur); | 
|  | 169 |  | 
|  | 170 | rate64 *= cur.fbdiv; | 
|  | 171 | do_div(rate64, cur.refdiv); | 
|  | 172 |  | 
|  | 173 | if (cur.dsmpd == 0) { | 
|  | 174 | /* fractional mode */ | 
|  | 175 | u64 frac_rate64 = prate * cur.frac; | 
|  | 176 |  | 
|  | 177 | do_div(frac_rate64, cur.refdiv); | 
|  | 178 | rate64 += frac_rate64 >> 24; | 
|  | 179 | } | 
|  | 180 |  | 
|  | 181 | do_div(rate64, cur.postdiv1); | 
|  | 182 | do_div(rate64, cur.postdiv2); | 
|  | 183 |  | 
|  | 184 | return (unsigned long)rate64; | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll, | 
|  | 188 | const struct rockchip_pll_rate_table *rate) | 
|  | 189 | { | 
|  | 190 | const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; | 
|  | 191 | struct clk_mux *pll_mux = &pll->pll_mux; | 
|  | 192 | struct rockchip_pll_rate_table cur; | 
|  | 193 | u32 pllcon; | 
|  | 194 | int rate_change_remuxed = 0; | 
|  | 195 | int cur_parent; | 
|  | 196 | int ret; | 
|  | 197 |  | 
|  | 198 | pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", | 
|  | 199 | __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv, | 
|  | 200 | rate->postdiv2, rate->dsmpd, rate->frac); | 
|  | 201 |  | 
|  | 202 | rockchip_rk3036_pll_get_params(pll, &cur); | 
|  | 203 | cur.rate = 0; | 
|  | 204 |  | 
|  | 205 | cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); | 
|  | 206 | if (cur_parent == PLL_MODE_NORM) { | 
|  | 207 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); | 
|  | 208 | rate_change_remuxed = 1; | 
|  | 209 | } | 
|  | 210 |  | 
|  | 211 | /* update pll values */ | 
|  | 212 | writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK, | 
|  | 213 | RK3036_PLLCON0_FBDIV_SHIFT) | | 
|  | 214 | HIWORD_UPDATE(rate->postdiv1, RK3036_PLLCON0_POSTDIV1_MASK, | 
|  | 215 | RK3036_PLLCON0_POSTDIV1_SHIFT), | 
|  | 216 | pll->reg_base + RK3036_PLLCON(0)); | 
|  | 217 |  | 
|  | 218 | writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3036_PLLCON1_REFDIV_MASK, | 
|  | 219 | RK3036_PLLCON1_REFDIV_SHIFT) | | 
|  | 220 | HIWORD_UPDATE(rate->postdiv2, RK3036_PLLCON1_POSTDIV2_MASK, | 
|  | 221 | RK3036_PLLCON1_POSTDIV2_SHIFT) | | 
|  | 222 | HIWORD_UPDATE(rate->dsmpd, RK3036_PLLCON1_DSMPD_MASK, | 
|  | 223 | RK3036_PLLCON1_DSMPD_SHIFT), | 
|  | 224 | pll->reg_base + RK3036_PLLCON(1)); | 
|  | 225 |  | 
|  | 226 | /* GPLL CON2 is not HIWORD_MASK */ | 
|  | 227 | pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2)); | 
|  | 228 | pllcon &= ~(RK3036_PLLCON2_FRAC_MASK << RK3036_PLLCON2_FRAC_SHIFT); | 
|  | 229 | pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT; | 
|  | 230 | writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2)); | 
|  | 231 |  | 
|  | 232 | /* wait for the pll to lock */ | 
|  | 233 | ret = rockchip_pll_wait_lock(pll); | 
|  | 234 | if (ret) { | 
|  | 235 | pr_warn("%s: pll update unsuccessful, trying to restore old params\n", | 
|  | 236 | __func__); | 
|  | 237 | rockchip_rk3036_pll_set_params(pll, &cur); | 
|  | 238 | } | 
|  | 239 |  | 
|  | 240 | if (rate_change_remuxed) | 
|  | 241 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); | 
|  | 242 |  | 
|  | 243 | return ret; | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate, | 
|  | 247 | unsigned long prate) | 
|  | 248 | { | 
|  | 249 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 250 | const struct rockchip_pll_rate_table *rate; | 
|  | 251 |  | 
|  | 252 | pr_debug("%s: changing %s to %lu with a parent rate of %lu\n", | 
|  | 253 | __func__, __clk_get_name(hw->clk), drate, prate); | 
|  | 254 |  | 
|  | 255 | /* Get required rate settings from table */ | 
|  | 256 | rate = rockchip_get_pll_settings(pll, drate); | 
|  | 257 | if (!rate) { | 
|  | 258 | pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, | 
|  | 259 | drate, __clk_get_name(hw->clk)); | 
|  | 260 | return -EINVAL; | 
|  | 261 | } | 
|  | 262 |  | 
|  | 263 | return rockchip_rk3036_pll_set_params(pll, rate); | 
|  | 264 | } | 
|  | 265 |  | 
|  | 266 | static int rockchip_rk3036_pll_enable(struct clk_hw *hw) | 
|  | 267 | { | 
|  | 268 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 269 |  | 
|  | 270 | writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0), | 
|  | 271 | pll->reg_base + RK3036_PLLCON(1)); | 
|  | 272 | rockchip_pll_wait_lock(pll); | 
|  | 273 |  | 
|  | 274 | return 0; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | static void rockchip_rk3036_pll_disable(struct clk_hw *hw) | 
|  | 278 | { | 
|  | 279 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 280 |  | 
|  | 281 | writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN, | 
|  | 282 | RK3036_PLLCON1_PWRDOWN, 0), | 
|  | 283 | pll->reg_base + RK3036_PLLCON(1)); | 
|  | 284 | } | 
|  | 285 |  | 
|  | 286 | static int rockchip_rk3036_pll_is_enabled(struct clk_hw *hw) | 
|  | 287 | { | 
|  | 288 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 289 | u32 pllcon = readl(pll->reg_base + RK3036_PLLCON(1)); | 
|  | 290 |  | 
|  | 291 | return !(pllcon & RK3036_PLLCON1_PWRDOWN); | 
|  | 292 | } | 
|  | 293 |  | 
|  | 294 | static void rockchip_rk3036_pll_init(struct clk_hw *hw) | 
|  | 295 | { | 
|  | 296 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 297 | const struct rockchip_pll_rate_table *rate; | 
|  | 298 | struct rockchip_pll_rate_table cur; | 
|  | 299 | unsigned long drate; | 
|  | 300 |  | 
|  | 301 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) | 
|  | 302 | return; | 
|  | 303 |  | 
|  | 304 | drate = clk_hw_get_rate(hw); | 
|  | 305 | rate = rockchip_get_pll_settings(pll, drate); | 
|  | 306 |  | 
|  | 307 | /* when no rate setting for the current rate, rely on clk_set_rate */ | 
|  | 308 | if (!rate) | 
|  | 309 | return; | 
|  | 310 |  | 
|  | 311 | rockchip_rk3036_pll_get_params(pll, &cur); | 
|  | 312 |  | 
|  | 313 | pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk), | 
|  | 314 | drate); | 
|  | 315 | pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", | 
|  | 316 | cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2, | 
|  | 317 | cur.dsmpd, cur.frac); | 
|  | 318 | pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", | 
|  | 319 | rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2, | 
|  | 320 | rate->dsmpd, rate->frac); | 
|  | 321 |  | 
|  | 322 | if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 || | 
|  | 323 | rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 || | 
|  | 324 | rate->dsmpd != cur.dsmpd || | 
|  | 325 | (!cur.dsmpd && (rate->frac != cur.frac))) { | 
|  | 326 | struct clk *parent = clk_get_parent(hw->clk); | 
|  | 327 |  | 
|  | 328 | if (!parent) { | 
|  | 329 | pr_warn("%s: parent of %s not available\n", | 
|  | 330 | __func__, __clk_get_name(hw->clk)); | 
|  | 331 | return; | 
|  | 332 | } | 
|  | 333 |  | 
|  | 334 | pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", | 
|  | 335 | __func__, __clk_get_name(hw->clk)); | 
|  | 336 | rockchip_rk3036_pll_set_params(pll, rate); | 
|  | 337 | } | 
|  | 338 | } | 
|  | 339 |  | 
|  | 340 | static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = { | 
|  | 341 | .recalc_rate = rockchip_rk3036_pll_recalc_rate, | 
|  | 342 | .enable = rockchip_rk3036_pll_enable, | 
|  | 343 | .disable = rockchip_rk3036_pll_disable, | 
|  | 344 | .is_enabled = rockchip_rk3036_pll_is_enabled, | 
|  | 345 | }; | 
|  | 346 |  | 
|  | 347 | static const struct clk_ops rockchip_rk3036_pll_clk_ops = { | 
|  | 348 | .recalc_rate = rockchip_rk3036_pll_recalc_rate, | 
|  | 349 | .round_rate = rockchip_pll_round_rate, | 
|  | 350 | .set_rate = rockchip_rk3036_pll_set_rate, | 
|  | 351 | .enable = rockchip_rk3036_pll_enable, | 
|  | 352 | .disable = rockchip_rk3036_pll_disable, | 
|  | 353 | .is_enabled = rockchip_rk3036_pll_is_enabled, | 
|  | 354 | .init = rockchip_rk3036_pll_init, | 
|  | 355 | }; | 
|  | 356 |  | 
|  | 357 | /** | 
|  | 358 | * PLL used in RK3066, RK3188 and RK3288 | 
|  | 359 | */ | 
|  | 360 |  | 
|  | 361 | #define RK3066_PLL_RESET_DELAY(nr)	((nr * 500) / 24 + 1) | 
|  | 362 |  | 
|  | 363 | #define RK3066_PLLCON(i)		(i * 0x4) | 
|  | 364 | #define RK3066_PLLCON0_OD_MASK		0xf | 
|  | 365 | #define RK3066_PLLCON0_OD_SHIFT		0 | 
|  | 366 | #define RK3066_PLLCON0_NR_MASK		0x3f | 
|  | 367 | #define RK3066_PLLCON0_NR_SHIFT		8 | 
|  | 368 | #define RK3066_PLLCON1_NF_MASK		0x1fff | 
|  | 369 | #define RK3066_PLLCON1_NF_SHIFT		0 | 
|  | 370 | #define RK3066_PLLCON2_NB_MASK		0xfff | 
|  | 371 | #define RK3066_PLLCON2_NB_SHIFT		0 | 
|  | 372 | #define RK3066_PLLCON3_RESET		(1 << 5) | 
|  | 373 | #define RK3066_PLLCON3_PWRDOWN		(1 << 1) | 
|  | 374 | #define RK3066_PLLCON3_BYPASS		(1 << 0) | 
|  | 375 |  | 
|  | 376 | static void rockchip_rk3066_pll_get_params(struct rockchip_clk_pll *pll, | 
|  | 377 | struct rockchip_pll_rate_table *rate) | 
|  | 378 | { | 
|  | 379 | u32 pllcon; | 
|  | 380 |  | 
|  | 381 | pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(0)); | 
|  | 382 | rate->nr = ((pllcon >> RK3066_PLLCON0_NR_SHIFT) | 
|  | 383 | & RK3066_PLLCON0_NR_MASK) + 1; | 
|  | 384 | rate->no = ((pllcon >> RK3066_PLLCON0_OD_SHIFT) | 
|  | 385 | & RK3066_PLLCON0_OD_MASK) + 1; | 
|  | 386 |  | 
|  | 387 | pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(1)); | 
|  | 388 | rate->nf = ((pllcon >> RK3066_PLLCON1_NF_SHIFT) | 
|  | 389 | & RK3066_PLLCON1_NF_MASK) + 1; | 
|  | 390 |  | 
|  | 391 | pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(2)); | 
|  | 392 | rate->nb = ((pllcon >> RK3066_PLLCON2_NB_SHIFT) | 
|  | 393 | & RK3066_PLLCON2_NB_MASK) + 1; | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | static unsigned long rockchip_rk3066_pll_recalc_rate(struct clk_hw *hw, | 
|  | 397 | unsigned long prate) | 
|  | 398 | { | 
|  | 399 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 400 | struct rockchip_pll_rate_table cur; | 
|  | 401 | u64 rate64 = prate; | 
|  | 402 | u32 pllcon; | 
|  | 403 |  | 
|  | 404 | pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(3)); | 
|  | 405 | if (pllcon & RK3066_PLLCON3_BYPASS) { | 
|  | 406 | pr_debug("%s: pll %s is bypassed\n", __func__, | 
|  | 407 | clk_hw_get_name(hw)); | 
|  | 408 | return prate; | 
|  | 409 | } | 
|  | 410 |  | 
|  | 411 | rockchip_rk3066_pll_get_params(pll, &cur); | 
|  | 412 |  | 
|  | 413 | rate64 *= cur.nf; | 
|  | 414 | do_div(rate64, cur.nr); | 
|  | 415 | do_div(rate64, cur.no); | 
|  | 416 |  | 
|  | 417 | return (unsigned long)rate64; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 | static int rockchip_rk3066_pll_set_params(struct rockchip_clk_pll *pll, | 
|  | 421 | const struct rockchip_pll_rate_table *rate) | 
|  | 422 | { | 
|  | 423 | const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; | 
|  | 424 | struct clk_mux *pll_mux = &pll->pll_mux; | 
|  | 425 | struct rockchip_pll_rate_table cur; | 
|  | 426 | int rate_change_remuxed = 0; | 
|  | 427 | int cur_parent; | 
|  | 428 | int ret; | 
|  | 429 |  | 
|  | 430 | pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n", | 
|  | 431 | __func__, rate->rate, rate->nr, rate->no, rate->nf); | 
|  | 432 |  | 
|  | 433 | rockchip_rk3066_pll_get_params(pll, &cur); | 
|  | 434 | cur.rate = 0; | 
|  | 435 |  | 
|  | 436 | cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); | 
|  | 437 | if (cur_parent == PLL_MODE_NORM) { | 
|  | 438 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); | 
|  | 439 | rate_change_remuxed = 1; | 
|  | 440 | } | 
|  | 441 |  | 
|  | 442 | /* enter reset mode */ | 
|  | 443 | writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0), | 
|  | 444 | pll->reg_base + RK3066_PLLCON(3)); | 
|  | 445 |  | 
|  | 446 | /* update pll values */ | 
|  | 447 | writel(HIWORD_UPDATE(rate->nr - 1, RK3066_PLLCON0_NR_MASK, | 
|  | 448 | RK3066_PLLCON0_NR_SHIFT) | | 
|  | 449 | HIWORD_UPDATE(rate->no - 1, RK3066_PLLCON0_OD_MASK, | 
|  | 450 | RK3066_PLLCON0_OD_SHIFT), | 
|  | 451 | pll->reg_base + RK3066_PLLCON(0)); | 
|  | 452 |  | 
|  | 453 | writel_relaxed(HIWORD_UPDATE(rate->nf - 1, RK3066_PLLCON1_NF_MASK, | 
|  | 454 | RK3066_PLLCON1_NF_SHIFT), | 
|  | 455 | pll->reg_base + RK3066_PLLCON(1)); | 
|  | 456 | writel_relaxed(HIWORD_UPDATE(rate->nb - 1, RK3066_PLLCON2_NB_MASK, | 
|  | 457 | RK3066_PLLCON2_NB_SHIFT), | 
|  | 458 | pll->reg_base + RK3066_PLLCON(2)); | 
|  | 459 |  | 
|  | 460 | /* leave reset and wait the reset_delay */ | 
|  | 461 | writel(HIWORD_UPDATE(0, RK3066_PLLCON3_RESET, 0), | 
|  | 462 | pll->reg_base + RK3066_PLLCON(3)); | 
|  | 463 | udelay(RK3066_PLL_RESET_DELAY(rate->nr)); | 
|  | 464 |  | 
|  | 465 | /* wait for the pll to lock */ | 
|  | 466 | ret = rockchip_pll_wait_lock(pll); | 
|  | 467 | if (ret) { | 
|  | 468 | pr_warn("%s: pll update unsuccessful, trying to restore old params\n", | 
|  | 469 | __func__); | 
|  | 470 | rockchip_rk3066_pll_set_params(pll, &cur); | 
|  | 471 | } | 
|  | 472 |  | 
|  | 473 | if (rate_change_remuxed) | 
|  | 474 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); | 
|  | 475 |  | 
|  | 476 | return ret; | 
|  | 477 | } | 
|  | 478 |  | 
|  | 479 | static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, | 
|  | 480 | unsigned long prate) | 
|  | 481 | { | 
|  | 482 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 483 | const struct rockchip_pll_rate_table *rate; | 
|  | 484 |  | 
|  | 485 | pr_debug("%s: changing %s to %lu with a parent rate of %lu\n", | 
|  | 486 | __func__, clk_hw_get_name(hw), drate, prate); | 
|  | 487 |  | 
|  | 488 | /* Get required rate settings from table */ | 
|  | 489 | rate = rockchip_get_pll_settings(pll, drate); | 
|  | 490 | if (!rate) { | 
|  | 491 | pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, | 
|  | 492 | drate, clk_hw_get_name(hw)); | 
|  | 493 | return -EINVAL; | 
|  | 494 | } | 
|  | 495 |  | 
|  | 496 | return rockchip_rk3066_pll_set_params(pll, rate); | 
|  | 497 | } | 
|  | 498 |  | 
|  | 499 | static int rockchip_rk3066_pll_enable(struct clk_hw *hw) | 
|  | 500 | { | 
|  | 501 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 502 |  | 
|  | 503 | writel(HIWORD_UPDATE(0, RK3066_PLLCON3_PWRDOWN, 0), | 
|  | 504 | pll->reg_base + RK3066_PLLCON(3)); | 
|  | 505 | rockchip_pll_wait_lock(pll); | 
|  | 506 |  | 
|  | 507 | return 0; | 
|  | 508 | } | 
|  | 509 |  | 
|  | 510 | static void rockchip_rk3066_pll_disable(struct clk_hw *hw) | 
|  | 511 | { | 
|  | 512 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 513 |  | 
|  | 514 | writel(HIWORD_UPDATE(RK3066_PLLCON3_PWRDOWN, | 
|  | 515 | RK3066_PLLCON3_PWRDOWN, 0), | 
|  | 516 | pll->reg_base + RK3066_PLLCON(3)); | 
|  | 517 | } | 
|  | 518 |  | 
|  | 519 | static int rockchip_rk3066_pll_is_enabled(struct clk_hw *hw) | 
|  | 520 | { | 
|  | 521 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 522 | u32 pllcon = readl(pll->reg_base + RK3066_PLLCON(3)); | 
|  | 523 |  | 
|  | 524 | return !(pllcon & RK3066_PLLCON3_PWRDOWN); | 
|  | 525 | } | 
|  | 526 |  | 
|  | 527 | static void rockchip_rk3066_pll_init(struct clk_hw *hw) | 
|  | 528 | { | 
|  | 529 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 530 | const struct rockchip_pll_rate_table *rate; | 
|  | 531 | struct rockchip_pll_rate_table cur; | 
|  | 532 | unsigned long drate; | 
|  | 533 |  | 
|  | 534 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) | 
|  | 535 | return; | 
|  | 536 |  | 
|  | 537 | drate = clk_hw_get_rate(hw); | 
|  | 538 | rate = rockchip_get_pll_settings(pll, drate); | 
|  | 539 |  | 
|  | 540 | /* when no rate setting for the current rate, rely on clk_set_rate */ | 
|  | 541 | if (!rate) | 
|  | 542 | return; | 
|  | 543 |  | 
|  | 544 | rockchip_rk3066_pll_get_params(pll, &cur); | 
|  | 545 |  | 
|  | 546 | pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), nb(%d:%d)\n", | 
|  | 547 | __func__, clk_hw_get_name(hw), drate, rate->nr, cur.nr, | 
|  | 548 | rate->no, cur.no, rate->nf, cur.nf, rate->nb, cur.nb); | 
|  | 549 | if (rate->nr != cur.nr || rate->no != cur.no || rate->nf != cur.nf | 
|  | 550 | || rate->nb != cur.nb) { | 
|  | 551 | pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", | 
|  | 552 | __func__, clk_hw_get_name(hw)); | 
|  | 553 | rockchip_rk3066_pll_set_params(pll, rate); | 
|  | 554 | } | 
|  | 555 | } | 
|  | 556 |  | 
|  | 557 | static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = { | 
|  | 558 | .recalc_rate = rockchip_rk3066_pll_recalc_rate, | 
|  | 559 | .enable = rockchip_rk3066_pll_enable, | 
|  | 560 | .disable = rockchip_rk3066_pll_disable, | 
|  | 561 | .is_enabled = rockchip_rk3066_pll_is_enabled, | 
|  | 562 | }; | 
|  | 563 |  | 
|  | 564 | static const struct clk_ops rockchip_rk3066_pll_clk_ops = { | 
|  | 565 | .recalc_rate = rockchip_rk3066_pll_recalc_rate, | 
|  | 566 | .round_rate = rockchip_pll_round_rate, | 
|  | 567 | .set_rate = rockchip_rk3066_pll_set_rate, | 
|  | 568 | .enable = rockchip_rk3066_pll_enable, | 
|  | 569 | .disable = rockchip_rk3066_pll_disable, | 
|  | 570 | .is_enabled = rockchip_rk3066_pll_is_enabled, | 
|  | 571 | .init = rockchip_rk3066_pll_init, | 
|  | 572 | }; | 
|  | 573 |  | 
|  | 574 | /** | 
|  | 575 | * PLL used in RK3399 | 
|  | 576 | */ | 
|  | 577 |  | 
|  | 578 | #define RK3399_PLLCON(i)			(i * 0x4) | 
|  | 579 | #define RK3399_PLLCON0_FBDIV_MASK		0xfff | 
|  | 580 | #define RK3399_PLLCON0_FBDIV_SHIFT		0 | 
|  | 581 | #define RK3399_PLLCON1_REFDIV_MASK		0x3f | 
|  | 582 | #define RK3399_PLLCON1_REFDIV_SHIFT		0 | 
|  | 583 | #define RK3399_PLLCON1_POSTDIV1_MASK		0x7 | 
|  | 584 | #define RK3399_PLLCON1_POSTDIV1_SHIFT		8 | 
|  | 585 | #define RK3399_PLLCON1_POSTDIV2_MASK		0x7 | 
|  | 586 | #define RK3399_PLLCON1_POSTDIV2_SHIFT		12 | 
|  | 587 | #define RK3399_PLLCON2_FRAC_MASK		0xffffff | 
|  | 588 | #define RK3399_PLLCON2_FRAC_SHIFT		0 | 
|  | 589 | #define RK3399_PLLCON2_LOCK_STATUS		BIT(31) | 
|  | 590 | #define RK3399_PLLCON3_PWRDOWN			BIT(0) | 
|  | 591 | #define RK3399_PLLCON3_DSMPD_MASK		0x1 | 
|  | 592 | #define RK3399_PLLCON3_DSMPD_SHIFT		3 | 
|  | 593 |  | 
|  | 594 | static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll) | 
|  | 595 | { | 
|  | 596 | u32 pllcon; | 
|  | 597 | int delay = 24000000; | 
|  | 598 |  | 
|  | 599 | /* poll check the lock status in rk3399 xPLLCON2 */ | 
|  | 600 | while (delay > 0) { | 
|  | 601 | pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); | 
|  | 602 | if (pllcon & RK3399_PLLCON2_LOCK_STATUS) | 
|  | 603 | return 0; | 
|  | 604 |  | 
|  | 605 | delay--; | 
|  | 606 | } | 
|  | 607 |  | 
|  | 608 | pr_err("%s: timeout waiting for pll to lock\n", __func__); | 
|  | 609 | return -ETIMEDOUT; | 
|  | 610 | } | 
|  | 611 |  | 
|  | 612 | static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll, | 
|  | 613 | struct rockchip_pll_rate_table *rate) | 
|  | 614 | { | 
|  | 615 | u32 pllcon; | 
|  | 616 |  | 
|  | 617 | pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(0)); | 
|  | 618 | rate->fbdiv = ((pllcon >> RK3399_PLLCON0_FBDIV_SHIFT) | 
|  | 619 | & RK3399_PLLCON0_FBDIV_MASK); | 
|  | 620 |  | 
|  | 621 | pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(1)); | 
|  | 622 | rate->refdiv = ((pllcon >> RK3399_PLLCON1_REFDIV_SHIFT) | 
|  | 623 | & RK3399_PLLCON1_REFDIV_MASK); | 
|  | 624 | rate->postdiv1 = ((pllcon >> RK3399_PLLCON1_POSTDIV1_SHIFT) | 
|  | 625 | & RK3399_PLLCON1_POSTDIV1_MASK); | 
|  | 626 | rate->postdiv2 = ((pllcon >> RK3399_PLLCON1_POSTDIV2_SHIFT) | 
|  | 627 | & RK3399_PLLCON1_POSTDIV2_MASK); | 
|  | 628 |  | 
|  | 629 | pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); | 
|  | 630 | rate->frac = ((pllcon >> RK3399_PLLCON2_FRAC_SHIFT) | 
|  | 631 | & RK3399_PLLCON2_FRAC_MASK); | 
|  | 632 |  | 
|  | 633 | pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(3)); | 
|  | 634 | rate->dsmpd = ((pllcon >> RK3399_PLLCON3_DSMPD_SHIFT) | 
|  | 635 | & RK3399_PLLCON3_DSMPD_MASK); | 
|  | 636 | } | 
|  | 637 |  | 
|  | 638 | static unsigned long rockchip_rk3399_pll_recalc_rate(struct clk_hw *hw, | 
|  | 639 | unsigned long prate) | 
|  | 640 | { | 
|  | 641 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 642 | struct rockchip_pll_rate_table cur; | 
|  | 643 | u64 rate64 = prate; | 
|  | 644 |  | 
|  | 645 | rockchip_rk3399_pll_get_params(pll, &cur); | 
|  | 646 |  | 
|  | 647 | rate64 *= cur.fbdiv; | 
|  | 648 | do_div(rate64, cur.refdiv); | 
|  | 649 |  | 
|  | 650 | if (cur.dsmpd == 0) { | 
|  | 651 | /* fractional mode */ | 
|  | 652 | u64 frac_rate64 = prate * cur.frac; | 
|  | 653 |  | 
|  | 654 | do_div(frac_rate64, cur.refdiv); | 
|  | 655 | rate64 += frac_rate64 >> 24; | 
|  | 656 | } | 
|  | 657 |  | 
|  | 658 | do_div(rate64, cur.postdiv1); | 
|  | 659 | do_div(rate64, cur.postdiv2); | 
|  | 660 |  | 
|  | 661 | return (unsigned long)rate64; | 
|  | 662 | } | 
|  | 663 |  | 
|  | 664 | static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll, | 
|  | 665 | const struct rockchip_pll_rate_table *rate) | 
|  | 666 | { | 
|  | 667 | const struct clk_ops *pll_mux_ops = pll->pll_mux_ops; | 
|  | 668 | struct clk_mux *pll_mux = &pll->pll_mux; | 
|  | 669 | struct rockchip_pll_rate_table cur; | 
|  | 670 | u32 pllcon; | 
|  | 671 | int rate_change_remuxed = 0; | 
|  | 672 | int cur_parent; | 
|  | 673 | int ret; | 
|  | 674 |  | 
|  | 675 | pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", | 
|  | 676 | __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv, | 
|  | 677 | rate->postdiv2, rate->dsmpd, rate->frac); | 
|  | 678 |  | 
|  | 679 | rockchip_rk3399_pll_get_params(pll, &cur); | 
|  | 680 | cur.rate = 0; | 
|  | 681 |  | 
|  | 682 | cur_parent = pll_mux_ops->get_parent(&pll_mux->hw); | 
|  | 683 | if (cur_parent == PLL_MODE_NORM) { | 
|  | 684 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW); | 
|  | 685 | rate_change_remuxed = 1; | 
|  | 686 | } | 
|  | 687 |  | 
|  | 688 | /* update pll values */ | 
|  | 689 | writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3399_PLLCON0_FBDIV_MASK, | 
|  | 690 | RK3399_PLLCON0_FBDIV_SHIFT), | 
|  | 691 | pll->reg_base + RK3399_PLLCON(0)); | 
|  | 692 |  | 
|  | 693 | writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3399_PLLCON1_REFDIV_MASK, | 
|  | 694 | RK3399_PLLCON1_REFDIV_SHIFT) | | 
|  | 695 | HIWORD_UPDATE(rate->postdiv1, RK3399_PLLCON1_POSTDIV1_MASK, | 
|  | 696 | RK3399_PLLCON1_POSTDIV1_SHIFT) | | 
|  | 697 | HIWORD_UPDATE(rate->postdiv2, RK3399_PLLCON1_POSTDIV2_MASK, | 
|  | 698 | RK3399_PLLCON1_POSTDIV2_SHIFT), | 
|  | 699 | pll->reg_base + RK3399_PLLCON(1)); | 
|  | 700 |  | 
|  | 701 | /* xPLL CON2 is not HIWORD_MASK */ | 
|  | 702 | pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2)); | 
|  | 703 | pllcon &= ~(RK3399_PLLCON2_FRAC_MASK << RK3399_PLLCON2_FRAC_SHIFT); | 
|  | 704 | pllcon |= rate->frac << RK3399_PLLCON2_FRAC_SHIFT; | 
|  | 705 | writel_relaxed(pllcon, pll->reg_base + RK3399_PLLCON(2)); | 
|  | 706 |  | 
|  | 707 | writel_relaxed(HIWORD_UPDATE(rate->dsmpd, RK3399_PLLCON3_DSMPD_MASK, | 
|  | 708 | RK3399_PLLCON3_DSMPD_SHIFT), | 
|  | 709 | pll->reg_base + RK3399_PLLCON(3)); | 
|  | 710 |  | 
|  | 711 | /* wait for the pll to lock */ | 
|  | 712 | ret = rockchip_rk3399_pll_wait_lock(pll); | 
|  | 713 | if (ret) { | 
|  | 714 | pr_warn("%s: pll update unsuccessful, trying to restore old params\n", | 
|  | 715 | __func__); | 
|  | 716 | rockchip_rk3399_pll_set_params(pll, &cur); | 
|  | 717 | } | 
|  | 718 |  | 
|  | 719 | if (rate_change_remuxed) | 
|  | 720 | pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM); | 
|  | 721 |  | 
|  | 722 | return ret; | 
|  | 723 | } | 
|  | 724 |  | 
|  | 725 | static int rockchip_rk3399_pll_set_rate(struct clk_hw *hw, unsigned long drate, | 
|  | 726 | unsigned long prate) | 
|  | 727 | { | 
|  | 728 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 729 | const struct rockchip_pll_rate_table *rate; | 
|  | 730 |  | 
|  | 731 | pr_debug("%s: changing %s to %lu with a parent rate of %lu\n", | 
|  | 732 | __func__, __clk_get_name(hw->clk), drate, prate); | 
|  | 733 |  | 
|  | 734 | /* Get required rate settings from table */ | 
|  | 735 | rate = rockchip_get_pll_settings(pll, drate); | 
|  | 736 | if (!rate) { | 
|  | 737 | pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, | 
|  | 738 | drate, __clk_get_name(hw->clk)); | 
|  | 739 | return -EINVAL; | 
|  | 740 | } | 
|  | 741 |  | 
|  | 742 | return rockchip_rk3399_pll_set_params(pll, rate); | 
|  | 743 | } | 
|  | 744 |  | 
|  | 745 | static int rockchip_rk3399_pll_enable(struct clk_hw *hw) | 
|  | 746 | { | 
|  | 747 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 748 |  | 
|  | 749 | writel(HIWORD_UPDATE(0, RK3399_PLLCON3_PWRDOWN, 0), | 
|  | 750 | pll->reg_base + RK3399_PLLCON(3)); | 
|  | 751 | rockchip_rk3399_pll_wait_lock(pll); | 
|  | 752 |  | 
|  | 753 | return 0; | 
|  | 754 | } | 
|  | 755 |  | 
|  | 756 | static void rockchip_rk3399_pll_disable(struct clk_hw *hw) | 
|  | 757 | { | 
|  | 758 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 759 |  | 
|  | 760 | writel(HIWORD_UPDATE(RK3399_PLLCON3_PWRDOWN, | 
|  | 761 | RK3399_PLLCON3_PWRDOWN, 0), | 
|  | 762 | pll->reg_base + RK3399_PLLCON(3)); | 
|  | 763 | } | 
|  | 764 |  | 
|  | 765 | static int rockchip_rk3399_pll_is_enabled(struct clk_hw *hw) | 
|  | 766 | { | 
|  | 767 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 768 | u32 pllcon = readl(pll->reg_base + RK3399_PLLCON(3)); | 
|  | 769 |  | 
|  | 770 | return !(pllcon & RK3399_PLLCON3_PWRDOWN); | 
|  | 771 | } | 
|  | 772 |  | 
|  | 773 | static void rockchip_rk3399_pll_init(struct clk_hw *hw) | 
|  | 774 | { | 
|  | 775 | struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); | 
|  | 776 | const struct rockchip_pll_rate_table *rate; | 
|  | 777 | struct rockchip_pll_rate_table cur; | 
|  | 778 | unsigned long drate; | 
|  | 779 |  | 
|  | 780 | if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) | 
|  | 781 | return; | 
|  | 782 |  | 
|  | 783 | drate = clk_hw_get_rate(hw); | 
|  | 784 | rate = rockchip_get_pll_settings(pll, drate); | 
|  | 785 |  | 
|  | 786 | /* when no rate setting for the current rate, rely on clk_set_rate */ | 
|  | 787 | if (!rate) | 
|  | 788 | return; | 
|  | 789 |  | 
|  | 790 | rockchip_rk3399_pll_get_params(pll, &cur); | 
|  | 791 |  | 
|  | 792 | pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk), | 
|  | 793 | drate); | 
|  | 794 | pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", | 
|  | 795 | cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2, | 
|  | 796 | cur.dsmpd, cur.frac); | 
|  | 797 | pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n", | 
|  | 798 | rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2, | 
|  | 799 | rate->dsmpd, rate->frac); | 
|  | 800 |  | 
|  | 801 | if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 || | 
|  | 802 | rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 || | 
|  | 803 | rate->dsmpd != cur.dsmpd || | 
|  | 804 | (!cur.dsmpd && (rate->frac != cur.frac))) { | 
|  | 805 | struct clk *parent = clk_get_parent(hw->clk); | 
|  | 806 |  | 
|  | 807 | if (!parent) { | 
|  | 808 | pr_warn("%s: parent of %s not available\n", | 
|  | 809 | __func__, __clk_get_name(hw->clk)); | 
|  | 810 | return; | 
|  | 811 | } | 
|  | 812 |  | 
|  | 813 | pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", | 
|  | 814 | __func__, __clk_get_name(hw->clk)); | 
|  | 815 | rockchip_rk3399_pll_set_params(pll, rate); | 
|  | 816 | } | 
|  | 817 | } | 
|  | 818 |  | 
|  | 819 | static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = { | 
|  | 820 | .recalc_rate = rockchip_rk3399_pll_recalc_rate, | 
|  | 821 | .enable = rockchip_rk3399_pll_enable, | 
|  | 822 | .disable = rockchip_rk3399_pll_disable, | 
|  | 823 | .is_enabled = rockchip_rk3399_pll_is_enabled, | 
|  | 824 | }; | 
|  | 825 |  | 
|  | 826 | static const struct clk_ops rockchip_rk3399_pll_clk_ops = { | 
|  | 827 | .recalc_rate = rockchip_rk3399_pll_recalc_rate, | 
|  | 828 | .round_rate = rockchip_pll_round_rate, | 
|  | 829 | .set_rate = rockchip_rk3399_pll_set_rate, | 
|  | 830 | .enable = rockchip_rk3399_pll_enable, | 
|  | 831 | .disable = rockchip_rk3399_pll_disable, | 
|  | 832 | .is_enabled = rockchip_rk3399_pll_is_enabled, | 
|  | 833 | .init = rockchip_rk3399_pll_init, | 
|  | 834 | }; | 
|  | 835 |  | 
|  | 836 | /* | 
|  | 837 | * Common registering of pll clocks | 
|  | 838 | */ | 
|  | 839 |  | 
|  | 840 | struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, | 
|  | 841 | enum rockchip_pll_type pll_type, | 
|  | 842 | const char *name, const char *const *parent_names, | 
|  | 843 | u8 num_parents, int con_offset, int grf_lock_offset, | 
|  | 844 | int lock_shift, int mode_offset, int mode_shift, | 
|  | 845 | struct rockchip_pll_rate_table *rate_table, | 
|  | 846 | unsigned long flags, u8 clk_pll_flags) | 
|  | 847 | { | 
|  | 848 | const char *pll_parents[3]; | 
|  | 849 | struct clk_init_data init; | 
|  | 850 | struct rockchip_clk_pll *pll; | 
|  | 851 | struct clk_mux *pll_mux; | 
|  | 852 | struct clk *pll_clk, *mux_clk; | 
|  | 853 | char pll_name[20]; | 
|  | 854 |  | 
|  | 855 | if ((pll_type != pll_rk3328 && num_parents != 2) || | 
|  | 856 | (pll_type == pll_rk3328 && num_parents != 1)) { | 
|  | 857 | pr_err("%s: needs two parent clocks\n", __func__); | 
|  | 858 | return ERR_PTR(-EINVAL); | 
|  | 859 | } | 
|  | 860 |  | 
|  | 861 | /* name the actual pll */ | 
|  | 862 | snprintf(pll_name, sizeof(pll_name), "pll_%s", name); | 
|  | 863 |  | 
|  | 864 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | 
|  | 865 | if (!pll) | 
|  | 866 | return ERR_PTR(-ENOMEM); | 
|  | 867 |  | 
|  | 868 | /* create the mux on top of the real pll */ | 
|  | 869 | pll->pll_mux_ops = &clk_mux_ops; | 
|  | 870 | pll_mux = &pll->pll_mux; | 
|  | 871 | pll_mux->reg = ctx->reg_base + mode_offset; | 
|  | 872 | pll_mux->shift = mode_shift; | 
|  | 873 | if (pll_type == pll_rk3328) | 
|  | 874 | pll_mux->mask = PLL_RK3328_MODE_MASK; | 
|  | 875 | else | 
|  | 876 | pll_mux->mask = PLL_MODE_MASK; | 
|  | 877 | pll_mux->flags = 0; | 
|  | 878 | pll_mux->lock = &ctx->lock; | 
|  | 879 | pll_mux->hw.init = &init; | 
|  | 880 |  | 
|  | 881 | if (pll_type == pll_rk3036 || | 
|  | 882 | pll_type == pll_rk3066 || | 
|  | 883 | pll_type == pll_rk3328 || | 
|  | 884 | pll_type == pll_rk3399) | 
|  | 885 | pll_mux->flags |= CLK_MUX_HIWORD_MASK; | 
|  | 886 |  | 
|  | 887 | /* the actual muxing is xin24m, pll-output, xin32k */ | 
|  | 888 | pll_parents[0] = parent_names[0]; | 
|  | 889 | pll_parents[1] = pll_name; | 
|  | 890 | pll_parents[2] = parent_names[1]; | 
|  | 891 |  | 
|  | 892 | init.name = name; | 
|  | 893 | init.flags = CLK_SET_RATE_PARENT; | 
|  | 894 | init.ops = pll->pll_mux_ops; | 
|  | 895 | init.parent_names = pll_parents; | 
|  | 896 | if (pll_type == pll_rk3328) | 
|  | 897 | init.num_parents = 2; | 
|  | 898 | else | 
|  | 899 | init.num_parents = ARRAY_SIZE(pll_parents); | 
|  | 900 |  | 
|  | 901 | mux_clk = clk_register(NULL, &pll_mux->hw); | 
|  | 902 | if (IS_ERR(mux_clk)) | 
|  | 903 | goto err_mux; | 
|  | 904 |  | 
|  | 905 | /* now create the actual pll */ | 
|  | 906 | init.name = pll_name; | 
|  | 907 |  | 
|  | 908 | /* keep all plls untouched for now */ | 
|  | 909 | init.flags = flags | CLK_IGNORE_UNUSED; | 
|  | 910 |  | 
|  | 911 | init.parent_names = &parent_names[0]; | 
|  | 912 | init.num_parents = 1; | 
|  | 913 |  | 
|  | 914 | if (rate_table) { | 
|  | 915 | int len; | 
|  | 916 |  | 
|  | 917 | /* find count of rates in rate_table */ | 
|  | 918 | for (len = 0; rate_table[len].rate != 0; ) | 
|  | 919 | len++; | 
|  | 920 |  | 
|  | 921 | pll->rate_count = len; | 
|  | 922 | pll->rate_table = kmemdup(rate_table, | 
|  | 923 | pll->rate_count * | 
|  | 924 | sizeof(struct rockchip_pll_rate_table), | 
|  | 925 | GFP_KERNEL); | 
|  | 926 | WARN(!pll->rate_table, | 
|  | 927 | "%s: could not allocate rate table for %s\n", | 
|  | 928 | __func__, name); | 
|  | 929 | } | 
|  | 930 |  | 
|  | 931 | switch (pll_type) { | 
|  | 932 | case pll_rk3036: | 
|  | 933 | case pll_rk3328: | 
|  | 934 | if (!pll->rate_table || IS_ERR(ctx->grf)) | 
|  | 935 | init.ops = &rockchip_rk3036_pll_clk_norate_ops; | 
|  | 936 | else | 
|  | 937 | init.ops = &rockchip_rk3036_pll_clk_ops; | 
|  | 938 | break; | 
|  | 939 | case pll_rk3066: | 
|  | 940 | if (!pll->rate_table || IS_ERR(ctx->grf)) | 
|  | 941 | init.ops = &rockchip_rk3066_pll_clk_norate_ops; | 
|  | 942 | else | 
|  | 943 | init.ops = &rockchip_rk3066_pll_clk_ops; | 
|  | 944 | break; | 
|  | 945 | case pll_rk3399: | 
|  | 946 | if (!pll->rate_table) | 
|  | 947 | init.ops = &rockchip_rk3399_pll_clk_norate_ops; | 
|  | 948 | else | 
|  | 949 | init.ops = &rockchip_rk3399_pll_clk_ops; | 
|  | 950 | break; | 
|  | 951 | default: | 
|  | 952 | pr_warn("%s: Unknown pll type for pll clk %s\n", | 
|  | 953 | __func__, name); | 
|  | 954 | } | 
|  | 955 |  | 
|  | 956 | pll->hw.init = &init; | 
|  | 957 | pll->type = pll_type; | 
|  | 958 | pll->reg_base = ctx->reg_base + con_offset; | 
|  | 959 | pll->lock_offset = grf_lock_offset; | 
|  | 960 | pll->lock_shift = lock_shift; | 
|  | 961 | pll->flags = clk_pll_flags; | 
|  | 962 | pll->lock = &ctx->lock; | 
|  | 963 | pll->ctx = ctx; | 
|  | 964 |  | 
|  | 965 | pll_clk = clk_register(NULL, &pll->hw); | 
|  | 966 | if (IS_ERR(pll_clk)) { | 
|  | 967 | pr_err("%s: failed to register pll clock %s : %ld\n", | 
|  | 968 | __func__, name, PTR_ERR(pll_clk)); | 
|  | 969 | goto err_pll; | 
|  | 970 | } | 
|  | 971 |  | 
|  | 972 | return mux_clk; | 
|  | 973 |  | 
|  | 974 | err_pll: | 
|  | 975 | clk_unregister(mux_clk); | 
|  | 976 | mux_clk = pll_clk; | 
|  | 977 | err_mux: | 
|  | 978 | kfree(pll); | 
|  | 979 | return mux_clk; | 
|  | 980 | } |