blob: 7ec78dc3a80b79aa5c5f0fe5067dfa1d104e8c48 [file] [log] [blame]
Peng Fan134cf092019-08-19 07:53:58 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2017-2019 NXP.
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
7
Peng Fan134cf092019-08-19 07:53:58 +00008#include <asm/io.h>
9#include <malloc.h>
10#include <clk-uclass.h>
11#include <dm/device.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070012#include <dm/devres.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060013#include <linux/bitops.h>
Peng Fan134cf092019-08-19 07:53:58 +000014#include <linux/clk-provider.h>
Simon Glassdbd79542020-05-10 11:40:11 -060015#include <linux/delay.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070016#include <linux/err.h>
Peng Fan134cf092019-08-19 07:53:58 +000017#include <linux/iopoll.h>
18#include <clk.h>
19#include <div64.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060020#include <linux/printk.h>
Peng Fan134cf092019-08-19 07:53:58 +000021
22#include "clk.h"
23
24#define UBOOT_DM_CLK_IMX_PLL1443X "imx_clk_pll1443x"
25#define UBOOT_DM_CLK_IMX_PLL1416X "imx_clk_pll1416x"
26
27#define GNRL_CTL 0x0
28#define DIV_CTL 0x4
29#define LOCK_STATUS BIT(31)
30#define LOCK_SEL_MASK BIT(29)
31#define CLKE_MASK BIT(11)
32#define RST_MASK BIT(9)
33#define BYPASS_MASK BIT(4)
34#define MDIV_SHIFT 12
35#define MDIV_MASK GENMASK(21, 12)
36#define PDIV_SHIFT 4
37#define PDIV_MASK GENMASK(9, 4)
38#define SDIV_SHIFT 0
39#define SDIV_MASK GENMASK(2, 0)
40#define KDIV_SHIFT 0
41#define KDIV_MASK GENMASK(15, 0)
42
43#define LOCK_TIMEOUT_US 10000
44
45struct clk_pll14xx {
46 struct clk clk;
47 void __iomem *base;
48 enum imx_pll14xx_type type;
49 const struct imx_pll14xx_rate_table *rate_table;
50 int rate_count;
51};
52
53#define to_clk_pll14xx(_clk) container_of(_clk, struct clk_pll14xx, clk)
54
Angus Ainslie73d75ec2022-03-29 07:02:40 -070055#define PLL_1416X_RATE(_rate, _m, _p, _s) \
56 { \
57 .rate = (_rate), \
58 .mdiv = (_m), \
59 .pdiv = (_p), \
60 .sdiv = (_s), \
61 }
62
63#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \
64 { \
65 .rate = (_rate), \
66 .mdiv = (_m), \
67 .pdiv = (_p), \
68 .sdiv = (_s), \
69 .kdiv = (_k), \
70 }
71
72static const struct imx_pll14xx_rate_table imx_pll1416x_tbl[] = {
73 PLL_1416X_RATE(1800000000U, 225, 3, 0),
74 PLL_1416X_RATE(1600000000U, 200, 3, 0),
75 PLL_1416X_RATE(1500000000U, 375, 3, 1),
76 PLL_1416X_RATE(1400000000U, 350, 3, 1),
77 PLL_1416X_RATE(1200000000U, 300, 3, 1),
78 PLL_1416X_RATE(1000000000U, 250, 3, 1),
79 PLL_1416X_RATE(800000000U, 200, 3, 1),
80 PLL_1416X_RATE(750000000U, 250, 2, 2),
81 PLL_1416X_RATE(700000000U, 350, 3, 2),
82 PLL_1416X_RATE(600000000U, 300, 3, 2),
83};
84
85const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = {
86 PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384),
87 PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
88 PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
89 PLL_1443X_RATE(519750000U, 173, 2, 2, 16384),
90 PLL_1443X_RATE(393216000U, 262, 2, 3, 9437),
91 PLL_1443X_RATE(361267200U, 361, 3, 3, 17511),
92};
93
94struct imx_pll14xx_clk imx_1443x_pll __initdata = {
95 .type = PLL_1443X,
96 .rate_table = imx_pll1443x_tbl,
97 .rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
98};
99EXPORT_SYMBOL_GPL(imx_1443x_pll);
100
101struct imx_pll14xx_clk imx_1443x_dram_pll __initdata = {
102 .type = PLL_1443X,
103 .rate_table = imx_pll1443x_tbl,
104 .rate_count = ARRAY_SIZE(imx_pll1443x_tbl),
105 .flags = CLK_GET_RATE_NOCACHE,
106};
107EXPORT_SYMBOL_GPL(imx_1443x_dram_pll);
108
109struct imx_pll14xx_clk imx_1416x_pll __initdata = {
110 .type = PLL_1416X,
111 .rate_table = imx_pll1416x_tbl,
112 .rate_count = ARRAY_SIZE(imx_pll1416x_tbl),
113};
114EXPORT_SYMBOL_GPL(imx_1416x_pll);
115
Peng Fan134cf092019-08-19 07:53:58 +0000116static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
117 struct clk_pll14xx *pll, unsigned long rate)
118{
119 const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
120 int i;
121
122 for (i = 0; i < pll->rate_count; i++)
123 if (rate == rate_table[i].rate)
124 return &rate_table[i];
125
126 return NULL;
127}
128
129static unsigned long clk_pll1416x_recalc_rate(struct clk *clk)
130{
131 struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
132 u64 fvco = clk_get_parent_rate(clk);
133 u32 mdiv, pdiv, sdiv, pll_div;
134
135 pll_div = readl(pll->base + 4);
136 mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
137 pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
138 sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
139
140 fvco *= mdiv;
141 do_div(fvco, pdiv << sdiv);
142
143 return fvco;
144}
145
146static unsigned long clk_pll1443x_recalc_rate(struct clk *clk)
147{
148 struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
149 u64 fvco = clk_get_parent_rate(clk);
150 u32 mdiv, pdiv, sdiv, pll_div_ctl0, pll_div_ctl1;
151 short int kdiv;
152
153 pll_div_ctl0 = readl(pll->base + 4);
154 pll_div_ctl1 = readl(pll->base + 8);
155 mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
156 pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
157 sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
158 kdiv = pll_div_ctl1 & KDIV_MASK;
159
160 /* fvco = (m * 65536 + k) * Fin / (p * 65536) */
161 fvco *= (mdiv * 65536 + kdiv);
162 pdiv *= 65536;
163
164 do_div(fvco, pdiv << sdiv);
165
166 return fvco;
167}
168
169static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate,
170 u32 pll_div)
171{
172 u32 old_mdiv, old_pdiv;
173
174 old_mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
175 old_pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
176
177 return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
178}
179
180static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate,
181 u32 pll_div_ctl0, u32 pll_div_ctl1)
182{
183 u32 old_mdiv, old_pdiv, old_kdiv;
184
185 old_mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
186 old_pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
187 old_kdiv = (pll_div_ctl1 & KDIV_MASK) >> KDIV_SHIFT;
188
189 return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
190 rate->kdiv != old_kdiv;
191}
192
193static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate,
194 u32 pll_div_ctl0, u32 pll_div_ctl1)
195{
196 u32 old_mdiv, old_pdiv, old_kdiv;
197
198 old_mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
199 old_pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
200 old_kdiv = (pll_div_ctl1 & KDIV_MASK) >> KDIV_SHIFT;
201
202 return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
203 rate->kdiv != old_kdiv;
204}
205
206static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
207{
208 u32 val;
209
210 return readl_poll_timeout(pll->base, val, val & LOCK_TIMEOUT_US,
211 LOCK_TIMEOUT_US);
212}
213
214static ulong clk_pll1416x_set_rate(struct clk *clk, unsigned long drate)
215{
216 struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
217 const struct imx_pll14xx_rate_table *rate;
218 u32 tmp, div_val;
219 int ret;
220
221 rate = imx_get_pll_settings(pll, drate);
222 if (!rate) {
223 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
224 drate, "xxxx");
225 return -EINVAL;
226 }
227
228 tmp = readl(pll->base + 4);
229
230 if (!clk_pll1416x_mp_change(rate, tmp)) {
231 tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
232 tmp |= rate->sdiv << SDIV_SHIFT;
233 writel(tmp, pll->base + 4);
234
235 return clk_pll1416x_recalc_rate(clk);
236 }
237
238 /* Bypass clock and set lock to pll output lock */
239 tmp = readl(pll->base);
240 tmp |= LOCK_SEL_MASK;
241 writel(tmp, pll->base);
242
243 /* Enable RST */
244 tmp &= ~RST_MASK;
245 writel(tmp, pll->base);
246
247 /* Enable BYPASS */
248 tmp |= BYPASS_MASK;
249 writel(tmp, pll->base);
250
Peng Fan134cf092019-08-19 07:53:58 +0000251 div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
252 (rate->sdiv << SDIV_SHIFT);
253 writel(div_val, pll->base + 0x4);
254
255 /*
256 * According to SPEC, t3 - t2 need to be greater than
257 * 1us and 1/FREF, respectively.
258 * FREF is FIN / Prediv, the prediv is [1, 63], so choose
259 * 3us.
260 */
261 udelay(3);
262
263 /* Disable RST */
264 tmp |= RST_MASK;
265 writel(tmp, pll->base);
266
267 /* Wait Lock */
268 ret = clk_pll14xx_wait_lock(pll);
269 if (ret)
270 return ret;
271
272 /* Bypass */
273 tmp &= ~BYPASS_MASK;
274 writel(tmp, pll->base);
275
276 return clk_pll1416x_recalc_rate(clk);
277}
278
279static ulong clk_pll1443x_set_rate(struct clk *clk, unsigned long drate)
280{
281 struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
282 const struct imx_pll14xx_rate_table *rate;
283 u32 tmp, div_val;
284 int ret;
285
286 rate = imx_get_pll_settings(pll, drate);
287 if (!rate) {
288 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
289 drate, "===");
290 return -EINVAL;
291 }
292
293 tmp = readl(pll->base + 4);
294 div_val = readl(pll->base + 8);
295
296 if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) {
297 tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
298 tmp |= rate->sdiv << SDIV_SHIFT;
299 writel(tmp, pll->base + 4);
300
301 return clk_pll1443x_recalc_rate(clk);
302 }
303
304 tmp = readl(pll->base);
305
306 /* Enable RST */
307 tmp &= ~RST_MASK;
308 writel(tmp, pll->base);
309
310 /* Enable BYPASS */
311 tmp |= BYPASS_MASK;
312 writel(tmp, pll->base);
313
314 div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
315 (rate->sdiv << SDIV_SHIFT);
316 writel(div_val, pll->base + 0x4);
317 writel(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
318
319 /*
320 * According to SPEC, t3 - t2 need to be greater than
321 * 1us and 1/FREF, respectively.
322 * FREF is FIN / Prediv, the prediv is [1, 63], so choose
323 * 3us.
324 */
325 udelay(3);
326
327 /* Disable RST */
328 tmp |= RST_MASK;
329 writel(tmp, pll->base);
330
331 /* Wait Lock*/
332 ret = clk_pll14xx_wait_lock(pll);
333 if (ret)
334 return ret;
335
336 /* Bypass */
337 tmp &= ~BYPASS_MASK;
338 writel(tmp, pll->base);
339
340 return clk_pll1443x_recalc_rate(clk);
341}
342
343static int clk_pll14xx_prepare(struct clk *clk)
344{
345 struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
346 u32 val;
347
348 /*
349 * RESETB = 1 from 0, PLL starts its normal
350 * operation after lock time
351 */
352 val = readl(pll->base + GNRL_CTL);
353 val |= RST_MASK;
354 writel(val, pll->base + GNRL_CTL);
355
356 return clk_pll14xx_wait_lock(pll);
357}
358
359static int clk_pll14xx_unprepare(struct clk *clk)
360{
361 struct clk_pll14xx *pll = to_clk_pll14xx(dev_get_clk_ptr(clk->dev));
362 u32 val;
363
364 /*
365 * Set RST to 0, power down mode is enabled and
366 * every digital block is reset
367 */
368 val = readl(pll->base + GNRL_CTL);
369 val &= ~RST_MASK;
370 writel(val, pll->base + GNRL_CTL);
371
372 return 0;
373}
374
375static const struct clk_ops clk_pll1416x_ops = {
376 .enable = clk_pll14xx_prepare,
377 .disable = clk_pll14xx_unprepare,
378 .set_rate = clk_pll1416x_set_rate,
379 .get_rate = clk_pll1416x_recalc_rate,
380};
381
382static const struct clk_ops clk_pll1443x_ops = {
383 .enable = clk_pll14xx_prepare,
384 .disable = clk_pll14xx_unprepare,
385 .set_rate = clk_pll1443x_set_rate,
386 .get_rate = clk_pll1443x_recalc_rate,
387};
388
389struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
390 void __iomem *base,
391 const struct imx_pll14xx_clk *pll_clk)
392{
393 struct clk_pll14xx *pll;
394 struct clk *clk;
395 char *type_name;
396 int ret;
397
398 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
399 if (!pll)
400 return ERR_PTR(-ENOMEM);
401
402 switch (pll_clk->type) {
403 case PLL_1416X:
404 type_name = UBOOT_DM_CLK_IMX_PLL1416X;
405 break;
406 case PLL_1443X:
407 type_name = UBOOT_DM_CLK_IMX_PLL1443X;
408 break;
409 default:
410 pr_err("%s: Unknown pll type for pll clk %s\n",
411 __func__, name);
412 return ERR_PTR(-EINVAL);
413 };
414
415 pll->base = base;
416 pll->type = pll_clk->type;
417 pll->rate_table = pll_clk->rate_table;
418 pll->rate_count = pll_clk->rate_count;
419
420 clk = &pll->clk;
421
422 ret = clk_register(clk, type_name, name, parent_name);
423 if (ret) {
424 pr_err("%s: failed to register pll %s %d\n",
425 __func__, name, ret);
426 kfree(pll);
427 return ERR_PTR(ret);
428 }
429
430 return clk;
431}
432
433U_BOOT_DRIVER(clk_pll1443x) = {
434 .name = UBOOT_DM_CLK_IMX_PLL1443X,
435 .id = UCLASS_CLK,
436 .ops = &clk_pll1443x_ops,
437 .flags = DM_FLAG_PRE_RELOC,
438};
439
440U_BOOT_DRIVER(clk_pll1416x) = {
441 .name = UBOOT_DM_CLK_IMX_PLL1416X,
442 .id = UCLASS_CLK,
443 .ops = &clk_pll1416x_ops,
444 .flags = DM_FLAG_PRE_RELOC,
445};