forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb
kernel/drivers/clk/meson/clk-pll.c
....@@ -11,15 +11,19 @@
1111 * In the most basic form, a Meson PLL is composed as follows:
1212 *
1313 * PLL
14
- * +------------------------------+
15
- * | |
16
- * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
17
- * | ^ ^ |
18
- * +------------------------------+
19
- * | |
20
- * FREF VCO
14
+ * +--------------------------------+
15
+ * | |
16
+ * | +--+ |
17
+ * in >>-----[ /N ]--->| | +-----+ |
18
+ * | | |------| DCO |---->> out
19
+ * | +--------->| | +--v--+ |
20
+ * | | +--+ | |
21
+ * | | | |
22
+ * | +--[ *(M + (F/Fmax) ]<--+ |
23
+ * | |
24
+ * +--------------------------------+
2125 *
22
- * out = in * (m + frac / frac_max) / (n << sum(ods))
26
+ * out = in * (m + frac / frac_max) / n
2327 */
2428
2529 #include <linux/clk-provider.h>
....@@ -28,11 +32,10 @@
2832 #include <linux/io.h>
2933 #include <linux/math64.h>
3034 #include <linux/module.h>
31
-#include <linux/of_address.h>
32
-#include <linux/slab.h>
33
-#include <linux/string.h>
35
+#include <linux/rational.h>
3436
35
-#include "clkc.h"
37
+#include "clk-regmap.h"
38
+#include "clk-pll.h"
3639
3740 static inline struct meson_clk_pll_data *
3841 meson_clk_pll_data(struct clk_regmap *clk)
....@@ -40,13 +43,21 @@
4043 return (struct meson_clk_pll_data *)clk->data;
4144 }
4245
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
+
4355 static unsigned long __pll_params_to_rate(unsigned long parent_rate,
44
- const struct pll_rate_table *pllt,
45
- u16 frac,
56
+ unsigned int m, unsigned int n,
57
+ unsigned int frac,
4658 struct meson_clk_pll_data *pll)
4759 {
48
- u64 rate = (u64)parent_rate * pllt->m;
49
- unsigned int od = pllt->od + pllt->od2 + pllt->od3;
60
+ u64 rate = (u64)parent_rate * m;
5061
5162 if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
5263 u64 frac_rate = (u64)parent_rate * frac;
....@@ -55,7 +66,7 @@
5566 (1 << pll->frac.width));
5667 }
5768
58
- return DIV_ROUND_UP_ULL(rate, pllt->n << od);
69
+ return DIV_ROUND_UP_ULL(rate, n);
5970 }
6071
6172 static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
....@@ -63,71 +74,172 @@
6374 {
6475 struct clk_regmap *clk = to_clk_regmap(hw);
6576 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
66
- struct pll_rate_table pllt;
67
- u16 frac;
77
+ unsigned int m, n, frac;
6878
69
- pllt.n = meson_parm_read(clk->map, &pll->n);
70
- pllt.m = meson_parm_read(clk->map, &pll->m);
71
- pllt.od = meson_parm_read(clk->map, &pll->od);
79
+ n = meson_parm_read(clk->map, &pll->n);
7280
73
- pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ?
74
- meson_parm_read(clk->map, &pll->od2) :
75
- 0;
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;
7688
77
- pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ?
78
- meson_parm_read(clk->map, &pll->od3) :
79
- 0;
89
+ m = meson_parm_read(clk->map, &pll->m);
8090
8191 frac = MESON_PARM_APPLICABLE(&pll->frac) ?
8292 meson_parm_read(clk->map, &pll->frac) :
8393 0;
8494
85
- return __pll_params_to_rate(parent_rate, &pllt, frac, pll);
95
+ return __pll_params_to_rate(parent_rate, m, n, frac, pll);
8696 }
8797
88
-static u16 __pll_params_with_frac(unsigned long rate,
89
- unsigned long parent_rate,
90
- const struct pll_rate_table *pllt,
91
- struct meson_clk_pll_data *pll)
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)
92103 {
93
- u16 frac_max = (1 << pll->frac.width);
94
- u64 val = (u64)rate * pllt->n;
104
+ unsigned int frac_max = (1 << pll->frac.width);
105
+ u64 val = (u64)rate * n;
95106
96
- val <<= pllt->od + pllt->od2 + pllt->od3;
107
+ /* Bail out if we are already over the requested rate */
108
+ if (rate < parent_rate * m / n)
109
+ return 0;
97110
98111 if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
99112 val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
100113 else
101114 val = div_u64(val * frac_max, parent_rate);
102115
103
- val -= pllt->m * frac_max;
116
+ val -= m * frac_max;
104117
105
- return min((u16)val, (u16)(frac_max - 1));
118
+ return min((unsigned int)val, (frac_max - 1));
106119 }
107120
108
-static const struct pll_rate_table *
109
-meson_clk_get_pll_settings(unsigned long rate,
110
- struct meson_clk_pll_data *pll)
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)
111125 {
112
- const struct pll_rate_table *table = pll->table;
113
- unsigned int i = 0;
114
-
115
- if (!table)
116
- return NULL;
117
-
118
- /* Find the first table element exceeding rate */
119
- while (table[i].rate && table[i].rate <= rate)
120
- i++;
121
-
122
- if (i != 0) {
123
- if (MESON_PARM_APPLICABLE(&pll->frac) ||
124
- !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
125
- (abs(rate - table[i - 1].rate) <
126
- abs(rate - table[i].rate)))
127
- i--;
126
+ if (__pll_round_closest_mult(pll)) {
127
+ /* Round Closest */
128
+ if (abs(now - rate) < abs(best - rate))
129
+ return true;
130
+ } else {
131
+ /* Round down */
132
+ if (now <= rate && best < now)
133
+ return true;
128134 }
129135
130
- return (struct pll_rate_table *)&table[i];
136
+ return false;
137
+}
138
+
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)
143
+{
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);
162
+
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
+}
214
+
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;
230
+
231
+ now = __pll_params_to_rate(parent_rate, m, n, 0, pll);
232
+ if (meson_clk_pll_is_better(rate, best, now, pll)) {
233
+ best = now;
234
+ *best_m = m;
235
+ *best_n = n;
236
+
237
+ if (now == rate)
238
+ break;
239
+ }
240
+ }
241
+
242
+ return best ? 0 : -EINVAL;
131243 }
132244
133245 static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
....@@ -135,24 +247,26 @@
135247 {
136248 struct clk_regmap *clk = to_clk_regmap(hw);
137249 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
138
- const struct pll_rate_table *pllt =
139
- meson_clk_get_pll_settings(rate, pll);
140
- u16 frac;
250
+ unsigned int m, n, frac;
251
+ unsigned long round;
252
+ int ret;
141253
142
- if (!pllt)
254
+ ret = meson_clk_get_pll_settings(rate, *parent_rate, &m, &n, pll);
255
+ if (ret)
143256 return meson_clk_pll_recalc_rate(hw, *parent_rate);
144257
145
- if (!MESON_PARM_APPLICABLE(&pll->frac)
146
- || rate == pllt->rate)
147
- return pllt->rate;
258
+ round = __pll_params_to_rate(*parent_rate, m, n, 0, pll);
259
+
260
+ if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round)
261
+ return round;
148262
149263 /*
150264 * The rate provided by the setting is not an exact match, let's
151265 * try to improve the result using the fractional parameter
152266 */
153
- frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll);
267
+ frac = __pll_params_with_frac(rate, *parent_rate, m, n, pll);
154268
155
- return __pll_params_to_rate(*parent_rate, pllt, frac, pll);
269
+ return __pll_params_to_rate(*parent_rate, m, n, frac, pll);
156270 }
157271
158272 static int meson_clk_pll_wait_lock(struct clk_hw *hw)
....@@ -172,7 +286,7 @@
172286 return -ETIMEDOUT;
173287 }
174288
175
-static void meson_clk_pll_init(struct clk_hw *hw)
289
+static int meson_clk_pll_init(struct clk_hw *hw)
176290 {
177291 struct clk_regmap *clk = to_clk_regmap(hw);
178292 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
....@@ -183,6 +297,67 @@
183297 pll->init_count);
184298 meson_parm_write(clk->map, &pll->rst, 0);
185299 }
300
+
301
+ return 0;
302
+}
303
+
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
+
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
+
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
+
332
+ /* do nothing if the PLL is already enabled */
333
+ if (clk_hw_is_enabled(hw))
334
+ return 0;
335
+
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);
186361 }
187362
188363 static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
....@@ -190,41 +365,37 @@
190365 {
191366 struct clk_regmap *clk = to_clk_regmap(hw);
192367 struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
193
- const struct pll_rate_table *pllt;
368
+ unsigned int enabled, m, n, frac = 0;
194369 unsigned long old_rate;
195
- u16 frac = 0;
370
+ int ret;
196371
197372 if (parent_rate == 0 || rate == 0)
198373 return -EINVAL;
199374
200375 old_rate = clk_hw_get_rate(hw);
201376
202
- pllt = meson_clk_get_pll_settings(rate, pll);
203
- if (!pllt)
204
- return -EINVAL;
377
+ ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll);
378
+ if (ret)
379
+ return ret;
205380
206
- /* Put the pll in reset to write the params */
207
- meson_parm_write(clk->map, &pll->rst, 1);
381
+ enabled = meson_parm_read(clk->map, &pll->en);
382
+ if (enabled)
383
+ meson_clk_pll_disable(hw);
208384
209
- meson_parm_write(clk->map, &pll->n, pllt->n);
210
- meson_parm_write(clk->map, &pll->m, pllt->m);
211
- meson_parm_write(clk->map, &pll->od, pllt->od);
212
-
213
- if (MESON_PARM_APPLICABLE(&pll->od2))
214
- meson_parm_write(clk->map, &pll->od2, pllt->od2);
215
-
216
- if (MESON_PARM_APPLICABLE(&pll->od3))
217
- meson_parm_write(clk->map, &pll->od3, pllt->od3);
385
+ meson_parm_write(clk->map, &pll->n, n);
386
+ meson_parm_write(clk->map, &pll->m, m);
218387
219388 if (MESON_PARM_APPLICABLE(&pll->frac)) {
220
- frac = __pll_params_with_frac(rate, parent_rate, pllt, pll);
389
+ frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
221390 meson_parm_write(clk->map, &pll->frac, frac);
222391 }
223392
224
- /* make sure the reset is cleared at this point */
225
- meson_parm_write(clk->map, &pll->rst, 0);
393
+ /* If the pll is stopped, bail out now */
394
+ if (!enabled)
395
+ return 0;
226396
227
- if (meson_clk_pll_wait_lock(hw)) {
397
+ ret = meson_clk_pll_enable(hw);
398
+ if (ret) {
228399 pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
229400 __func__, old_rate);
230401 /*
....@@ -236,16 +407,43 @@
236407 meson_clk_pll_set_rate(hw, old_rate, parent_rate);
237408 }
238409
239
- return 0;
410
+ return ret;
240411 }
412
+
413
+/*
414
+ * The Meson G12A PCIE PLL is fined tuned to deliver a very precise
415
+ * 100MHz reference clock for the PCIe Analog PHY, and thus requires
416
+ * a strict register sequence to enable the PLL.
417
+ * To simplify, re-use the _init() op to enable the PLL and keep
418
+ * the other ops except set_rate since the rate is fixed.
419
+ */
420
+const struct clk_ops meson_clk_pcie_pll_ops = {
421
+ .recalc_rate = meson_clk_pll_recalc_rate,
422
+ .round_rate = meson_clk_pll_round_rate,
423
+ .is_enabled = meson_clk_pll_is_enabled,
424
+ .enable = meson_clk_pcie_pll_enable,
425
+ .disable = meson_clk_pll_disable
426
+};
427
+EXPORT_SYMBOL_GPL(meson_clk_pcie_pll_ops);
241428
242429 const struct clk_ops meson_clk_pll_ops = {
243430 .init = meson_clk_pll_init,
244431 .recalc_rate = meson_clk_pll_recalc_rate,
245432 .round_rate = meson_clk_pll_round_rate,
246433 .set_rate = meson_clk_pll_set_rate,
434
+ .is_enabled = meson_clk_pll_is_enabled,
435
+ .enable = meson_clk_pll_enable,
436
+ .disable = meson_clk_pll_disable
247437 };
438
+EXPORT_SYMBOL_GPL(meson_clk_pll_ops);
248439
249440 const struct clk_ops meson_clk_pll_ro_ops = {
250441 .recalc_rate = meson_clk_pll_recalc_rate,
442
+ .is_enabled = meson_clk_pll_is_enabled,
251443 };
444
+EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops);
445
+
446
+MODULE_DESCRIPTION("Amlogic PLL driver");
447
+MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
448
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
449
+MODULE_LICENSE("GPL v2");