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