1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2015 Endless Mobile, Inc. 4 * Author: Carlo Caione <carlo@endlessm.com> 5 * 6 * Copyright (c) 2018 Baylibre, SAS. 7 * Author: Jerome Brunet <jbrunet@baylibre.com> 8 */ 9 10 /* 11 * In the most basic form, a Meson PLL is composed as follows: 12 * 13 * PLL 14 * +--------------------------------+ 15 * | | 16 * | +--+ | 17 * in >>-----[ /N ]--->| | +-----+ | 18 * | | |------| DCO |---->> out 19 * | +--------->| | +--v--+ | 20 * | | +--+ | | 21 * | | | | 22 * | +--[ *(M + (F/Fmax) ]<--+ | 23 * | | 24 * +--------------------------------+ 25 * 26 * out = in * (m + frac / frac_max) / n 27 */ 28 29 #include <linux/clk-provider.h> 30 #include <linux/delay.h> 31 #include <linux/err.h> 32 #include <linux/io.h> 33 #include <linux/math64.h> 34 #include <linux/module.h> 35 #include <linux/rational.h> 36 37 #include "clk-regmap.h" 38 #include "clk-pll.h" 39 40 static inline struct meson_clk_pll_data * 41 meson_clk_pll_data(struct clk_regmap *clk) 42 { 43 return (struct meson_clk_pll_data *)clk->data; 44 } 45 46 static int __pll_round_closest_mult(struct meson_clk_pll_data *pll) 47 { 48 if ((pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) && 49 !MESON_PARM_APPLICABLE(&pll->frac)) 50 return 1; 51 52 return 0; 53 } 54 55 static unsigned long __pll_params_to_rate(unsigned long parent_rate, 56 unsigned int m, unsigned int n, 57 unsigned int frac, 58 struct meson_clk_pll_data *pll) 59 { 60 u64 rate = (u64)parent_rate * m; 61 62 if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { 63 u64 frac_rate = (u64)parent_rate * frac; 64 65 rate += DIV_ROUND_UP_ULL(frac_rate, 66 (1 << pll->frac.width)); 67 } 68 69 return DIV_ROUND_UP_ULL(rate, n); 70 } 71 72 static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, 73 unsigned long parent_rate) 74 { 75 struct clk_regmap *clk = to_clk_regmap(hw); 76 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 77 unsigned int m, n, frac; 78 79 n = meson_parm_read(clk->map, &pll->n); 80 m = meson_parm_read(clk->map, &pll->m); 81 82 frac = MESON_PARM_APPLICABLE(&pll->frac) ? 83 meson_parm_read(clk->map, &pll->frac) : 84 0; 85 86 return __pll_params_to_rate(parent_rate, m, n, frac, pll); 87 } 88 89 static unsigned int __pll_params_with_frac(unsigned long rate, 90 unsigned long parent_rate, 91 unsigned int m, 92 unsigned int n, 93 struct meson_clk_pll_data *pll) 94 { 95 unsigned int frac_max = (1 << pll->frac.width); 96 u64 val = (u64)rate * n; 97 98 /* Bail out if we are already over the requested rate */ 99 if (rate < parent_rate * m / n) 100 return 0; 101 102 if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) 103 val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); 104 else 105 val = div_u64(val * frac_max, parent_rate); 106 107 val -= m * frac_max; 108 109 return min((unsigned int)val, (frac_max - 1)); 110 } 111 112 static bool meson_clk_pll_is_better(unsigned long rate, 113 unsigned long best, 114 unsigned long now, 115 struct meson_clk_pll_data *pll) 116 { 117 if (__pll_round_closest_mult(pll)) { 118 /* Round Closest */ 119 if (abs(now - rate) < abs(best - rate)) 120 return true; 121 } else { 122 /* Round down */ 123 if (now < rate && best < now) 124 return true; 125 } 126 127 return false; 128 } 129 130 static int meson_clk_get_pll_table_index(unsigned int index, 131 unsigned int *m, 132 unsigned int *n, 133 struct meson_clk_pll_data *pll) 134 { 135 if (!pll->table[index].n) 136 return -EINVAL; 137 138 *m = pll->table[index].m; 139 *n = pll->table[index].n; 140 141 return 0; 142 } 143 144 static unsigned int meson_clk_get_pll_range_m(unsigned long rate, 145 unsigned long parent_rate, 146 unsigned int n, 147 struct meson_clk_pll_data *pll) 148 { 149 u64 val = (u64)rate * n; 150 151 if (__pll_round_closest_mult(pll)) 152 return DIV_ROUND_CLOSEST_ULL(val, parent_rate); 153 154 return div_u64(val, parent_rate); 155 } 156 157 static int meson_clk_get_pll_range_index(unsigned long rate, 158 unsigned long parent_rate, 159 unsigned int index, 160 unsigned int *m, 161 unsigned int *n, 162 struct meson_clk_pll_data *pll) 163 { 164 *n = index + 1; 165 166 /* Check the predivider range */ 167 if (*n >= (1 << pll->n.width)) 168 return -EINVAL; 169 170 if (*n == 1) { 171 /* Get the boundaries out the way */ 172 if (rate <= pll->range->min * parent_rate) { 173 *m = pll->range->min; 174 return -ENODATA; 175 } else if (rate >= pll->range->max * parent_rate) { 176 *m = pll->range->max; 177 return -ENODATA; 178 } 179 } 180 181 *m = meson_clk_get_pll_range_m(rate, parent_rate, *n, pll); 182 183 /* the pre-divider gives a multiplier too big - stop */ 184 if (*m >= (1 << pll->m.width)) 185 return -EINVAL; 186 187 return 0; 188 } 189 190 static int meson_clk_get_pll_get_index(unsigned long rate, 191 unsigned long parent_rate, 192 unsigned int index, 193 unsigned int *m, 194 unsigned int *n, 195 struct meson_clk_pll_data *pll) 196 { 197 if (pll->range) 198 return meson_clk_get_pll_range_index(rate, parent_rate, 199 index, m, n, pll); 200 else if (pll->table) 201 return meson_clk_get_pll_table_index(index, m, n, pll); 202 203 return -EINVAL; 204 } 205 206 static int meson_clk_get_pll_settings(unsigned long rate, 207 unsigned long parent_rate, 208 unsigned int *best_m, 209 unsigned int *best_n, 210 struct meson_clk_pll_data *pll) 211 { 212 unsigned long best = 0, now = 0; 213 unsigned int i, m, n; 214 int ret; 215 216 for (i = 0, ret = 0; !ret; i++) { 217 ret = meson_clk_get_pll_get_index(rate, parent_rate, 218 i, &m, &n, pll); 219 if (ret == -EINVAL) 220 break; 221 222 now = __pll_params_to_rate(parent_rate, m, n, 0, pll); 223 if (meson_clk_pll_is_better(rate, best, now, pll)) { 224 best = now; 225 *best_m = m; 226 *best_n = n; 227 228 if (now == rate) 229 break; 230 } 231 } 232 233 return best ? 0 : -EINVAL; 234 } 235 236 static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, 237 unsigned long *parent_rate) 238 { 239 struct clk_regmap *clk = to_clk_regmap(hw); 240 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 241 unsigned int m, n, frac; 242 unsigned long round; 243 int ret; 244 245 ret = meson_clk_get_pll_settings(rate, *parent_rate, &m, &n, pll); 246 if (ret) 247 return meson_clk_pll_recalc_rate(hw, *parent_rate); 248 249 round = __pll_params_to_rate(*parent_rate, m, n, 0, pll); 250 251 if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round) 252 return round; 253 254 /* 255 * The rate provided by the setting is not an exact match, let's 256 * try to improve the result using the fractional parameter 257 */ 258 frac = __pll_params_with_frac(rate, *parent_rate, m, n, pll); 259 260 return __pll_params_to_rate(*parent_rate, m, n, frac, pll); 261 } 262 263 static int meson_clk_pll_wait_lock(struct clk_hw *hw) 264 { 265 struct clk_regmap *clk = to_clk_regmap(hw); 266 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 267 int delay = 24000000; 268 269 do { 270 /* Is the clock locked now ? */ 271 if (meson_parm_read(clk->map, &pll->l)) 272 return 0; 273 274 delay--; 275 } while (delay > 0); 276 277 return -ETIMEDOUT; 278 } 279 280 static void meson_clk_pll_init(struct clk_hw *hw) 281 { 282 struct clk_regmap *clk = to_clk_regmap(hw); 283 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 284 285 if (pll->init_count) { 286 meson_parm_write(clk->map, &pll->rst, 1); 287 regmap_multi_reg_write(clk->map, pll->init_regs, 288 pll->init_count); 289 meson_parm_write(clk->map, &pll->rst, 0); 290 } 291 } 292 293 static int meson_clk_pll_is_enabled(struct clk_hw *hw) 294 { 295 struct clk_regmap *clk = to_clk_regmap(hw); 296 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 297 298 if (meson_parm_read(clk->map, &pll->rst) || 299 !meson_parm_read(clk->map, &pll->en) || 300 !meson_parm_read(clk->map, &pll->l)) 301 return 0; 302 303 return 1; 304 } 305 306 static int meson_clk_pll_enable(struct clk_hw *hw) 307 { 308 struct clk_regmap *clk = to_clk_regmap(hw); 309 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 310 311 /* do nothing if the PLL is already enabled */ 312 if (clk_hw_is_enabled(hw)) 313 return 0; 314 315 /* Make sure the pll is in reset */ 316 meson_parm_write(clk->map, &pll->rst, 1); 317 318 /* Enable the pll */ 319 meson_parm_write(clk->map, &pll->en, 1); 320 321 /* Take the pll out reset */ 322 meson_parm_write(clk->map, &pll->rst, 0); 323 324 if (meson_clk_pll_wait_lock(hw)) 325 return -EIO; 326 327 return 0; 328 } 329 330 static void meson_clk_pll_disable(struct clk_hw *hw) 331 { 332 struct clk_regmap *clk = to_clk_regmap(hw); 333 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 334 335 /* Put the pll is in reset */ 336 meson_parm_write(clk->map, &pll->rst, 1); 337 338 /* Disable the pll */ 339 meson_parm_write(clk->map, &pll->en, 0); 340 } 341 342 static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, 343 unsigned long parent_rate) 344 { 345 struct clk_regmap *clk = to_clk_regmap(hw); 346 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); 347 unsigned int enabled, m, n, frac = 0, ret; 348 unsigned long old_rate; 349 350 if (parent_rate == 0 || rate == 0) 351 return -EINVAL; 352 353 old_rate = rate; 354 355 ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll); 356 if (ret) 357 return ret; 358 359 enabled = meson_parm_read(clk->map, &pll->en); 360 if (enabled) 361 meson_clk_pll_disable(hw); 362 363 meson_parm_write(clk->map, &pll->n, n); 364 meson_parm_write(clk->map, &pll->m, m); 365 366 if (MESON_PARM_APPLICABLE(&pll->frac)) { 367 frac = __pll_params_with_frac(rate, parent_rate, m, n, pll); 368 meson_parm_write(clk->map, &pll->frac, frac); 369 } 370 371 /* If the pll is stopped, bail out now */ 372 if (!enabled) 373 return 0; 374 375 if (meson_clk_pll_enable(hw)) { 376 pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", 377 __func__, old_rate); 378 /* 379 * FIXME: Do we really need/want this HACK ? 380 * It looks unsafe. what happens if the clock gets into a 381 * broken state and we can't lock back on the old_rate ? Looks 382 * like an infinite recursion is possible 383 */ 384 meson_clk_pll_set_rate(hw, old_rate, parent_rate); 385 } 386 387 return 0; 388 } 389 390 const struct clk_ops meson_clk_pll_ops = { 391 .init = meson_clk_pll_init, 392 .recalc_rate = meson_clk_pll_recalc_rate, 393 .round_rate = meson_clk_pll_round_rate, 394 .set_rate = meson_clk_pll_set_rate, 395 .is_enabled = meson_clk_pll_is_enabled, 396 .enable = meson_clk_pll_enable, 397 .disable = meson_clk_pll_disable 398 }; 399 EXPORT_SYMBOL_GPL(meson_clk_pll_ops); 400 401 const struct clk_ops meson_clk_pll_ro_ops = { 402 .recalc_rate = meson_clk_pll_recalc_rate, 403 .is_enabled = meson_clk_pll_is_enabled, 404 }; 405 EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops); 406 407 MODULE_DESCRIPTION("Amlogic PLL driver"); 408 MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>"); 409 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 410 MODULE_LICENSE("GPL v2"); 411