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