blob: 9228f279e27d75bc4fff40b34bd0e03f9854af04 [file] [log] [blame]
Sébastien Szymanski9c153e462023-07-25 10:08:53 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2021 NXP
4 */
5
6#include <common.h>
7#include <asm/io.h>
8#include <malloc.h>
9#include <clk-uclass.h>
10#include <dm/device.h>
11#include <dm/devres.h>
12#include <linux/bitfield.h>
13#include <linux/bitops.h>
14#include <linux/clk-provider.h>
15#include <linux/delay.h>
16#include <linux/err.h>
17#include <linux/iopoll.h>
18#include <clk.h>
19#include <div64.h>
20
21#include "clk.h"
22
23#define UBOOT_DM_CLK_IMX_FRACN_GPPLL "imx_clk_fracn_gppll"
24
25#define PLL_CTRL 0x0
26#define HW_CTRL_SEL BIT(16)
27#define CLKMUX_BYPASS BIT(2)
28#define CLKMUX_EN BIT(1)
29#define POWERUP_MASK BIT(0)
30
31#define PLL_ANA_PRG 0x10
32#define PLL_SPREAD_SPECTRUM 0x30
33
34#define PLL_NUMERATOR 0x40
35#define PLL_MFN_MASK GENMASK(31, 2)
36
37#define PLL_DENOMINATOR 0x50
38#define PLL_MFD_MASK GENMASK(29, 0)
39
40#define PLL_DIV 0x60
41#define PLL_MFI_MASK GENMASK(24, 16)
42#define PLL_RDIV_MASK GENMASK(15, 13)
43#define PLL_ODIV_MASK GENMASK(7, 0)
44
45#define PLL_DFS_CTRL(x) (0x70 + (x) * 0x10)
46
47#define PLL_STATUS 0xF0
48#define LOCK_STATUS BIT(0)
49
50#define DFS_STATUS 0xF4
51
52#define LOCK_TIMEOUT_US 200
53
54#define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv) \
55 { \
56 .rate = (_rate), \
57 .mfi = (_mfi), \
58 .mfn = (_mfn), \
59 .mfd = (_mfd), \
60 .rdiv = (_rdiv), \
61 .odiv = (_odiv), \
62 }
63
64#define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv) \
65 { \
66 .rate = (_rate), \
67 .mfi = (_mfi), \
68 .mfn = 0, \
69 .mfd = 0, \
70 .rdiv = (_rdiv), \
71 .odiv = (_odiv), \
72 }
73
74struct clk_fracn_gppll {
75 struct clk clk;
76 void __iomem *base;
77 const struct imx_fracn_gppll_rate_table *rate_table;
78 int rate_count;
79 u32 flags;
80};
81
82/*
83 * Fvco = (Fref / rdiv) * (MFI + MFN / MFD)
84 * Fout = Fvco / odiv
85 * The (Fref / rdiv) should be in range 20MHz to 40MHz
86 * The Fvco should be in range 2.5Ghz to 5Ghz
87 */
88static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
89 PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6),
90 PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8),
91 PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6),
92 PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8),
93 PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6),
94 PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
95 PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
96 PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
97 PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
98};
99
100struct imx_fracn_gppll_clk imx_fracn_gppll = {
101 .rate_table = fracn_tbl,
102 .rate_count = ARRAY_SIZE(fracn_tbl),
103};
104
105/*
106 * Fvco = (Fref / rdiv) * MFI
107 * Fout = Fvco / odiv
108 * The (Fref / rdiv) should be in range 20MHz to 40MHz
109 * The Fvco should be in range 2.5Ghz to 5Ghz
110 */
111static const struct imx_fracn_gppll_rate_table int_tbl[] = {
112 PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2),
113 PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3),
114 PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4),
115};
116
117struct imx_fracn_gppll_clk imx_fracn_gppll_integer = {
118 .rate_table = int_tbl,
119 .rate_count = ARRAY_SIZE(int_tbl),
120};
121
122#define to_clk_fracn_gppll(_clk) container_of(_clk, struct clk_fracn_gppll, clk)
123
124static const struct imx_fracn_gppll_rate_table *
125imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate)
126{
127 const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
128 int i;
129
130 for (i = 0; i < pll->rate_count; i++)
131 if (rate == rate_table[i].rate)
132 return &rate_table[i];
133
134 return NULL;
135}
136
137static unsigned long clk_fracn_gppll_round_rate(struct clk *clk, unsigned long rate)
138{
139 struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
140 const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
141 int i;
142
143 /* Assuming rate_table is in descending order */
144 for (i = 0; i < pll->rate_count; i++)
145 if (rate >= rate_table[i].rate)
146 return rate_table[i].rate;
147
148 /* return minimum supported value */
149 return rate_table[pll->rate_count - 1].rate;
150}
151
152static unsigned long clk_fracn_gppll_recalc_rate(struct clk *clk)
153{
154 struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
155 const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
156 u32 pll_numerator, pll_denominator, pll_div;
157 u32 mfi, mfn, mfd, rdiv, odiv;
158 u64 fvco = clk_get_parent_rate(clk);
159 long rate = 0;
160 int i;
161
162 pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
163 mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
164
165 pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
166 mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
167
168 pll_div = readl_relaxed(pll->base + PLL_DIV);
169 mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
170
171 rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
172 odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
173
174 /*
175 * Sometimes, the recalculated rate has deviation due to
176 * the frac part. So find the accurate pll rate from the table
177 * first, if no match rate in the table, use the rate calculated
178 * from the equation below.
179 */
180 for (i = 0; i < pll->rate_count; i++) {
181 if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi &&
182 rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv &&
183 rate_table[i].odiv == odiv)
184 rate = rate_table[i].rate;
185 }
186
187 if (rate)
188 return (unsigned long)rate;
189
190 if (!rdiv)
191 rdiv = rdiv + 1;
192
193 switch (odiv) {
194 case 0:
195 odiv = 2;
196 break;
197 case 1:
198 odiv = 3;
199 break;
200 default:
201 break;
202 }
203
204 if (pll->flags & CLK_FRACN_GPPLL_INTEGER) {
205 /* Fvco = (Fref / rdiv) * MFI */
206 fvco = fvco * mfi;
207 do_div(fvco, rdiv * odiv);
208 } else {
209 /* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */
210 fvco = fvco * mfi * mfd + fvco * mfn;
211 do_div(fvco, mfd * rdiv * odiv);
212 }
213
214 return (unsigned long)fvco;
215}
216
217static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll)
218{
219 u32 val;
220
221 return readl_poll_timeout(pll->base + PLL_STATUS, val,
222 val & LOCK_STATUS, LOCK_TIMEOUT_US);
223}
224
225static ulong clk_fracn_gppll_set_rate(struct clk *clk, unsigned long drate)
226{
227 struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
228 const struct imx_fracn_gppll_rate_table *rate;
229 u32 tmp, pll_div, ana_mfn;
230 int ret;
231
232 rate = imx_get_pll_settings(pll, drate);
233
234 /* Hardware control select disable. PLL is control by register */
235 tmp = readl_relaxed(pll->base + PLL_CTRL);
236 tmp &= ~HW_CTRL_SEL;
237 writel_relaxed(tmp, pll->base + PLL_CTRL);
238
239 /* Disable output */
240 tmp = readl_relaxed(pll->base + PLL_CTRL);
241 tmp &= ~CLKMUX_EN;
242 writel_relaxed(tmp, pll->base + PLL_CTRL);
243
244 /* Power Down */
245 tmp &= ~POWERUP_MASK;
246 writel_relaxed(tmp, pll->base + PLL_CTRL);
247
248 /* Disable BYPASS */
249 tmp &= ~CLKMUX_BYPASS;
250 writel_relaxed(tmp, pll->base + PLL_CTRL);
251
252 pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
253 FIELD_PREP(PLL_MFI_MASK, rate->mfi);
254 writel_relaxed(pll_div, pll->base + PLL_DIV);
255 if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
256 writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
257 writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
258 }
259
260 /* Wait for 5us according to fracn mode pll doc */
261 udelay(5);
262
263 /* Enable Powerup */
264 tmp |= POWERUP_MASK;
265 writel_relaxed(tmp, pll->base + PLL_CTRL);
266
267 /* Wait Lock */
268 ret = clk_fracn_gppll_wait_lock(pll);
269 if (ret)
270 return ret;
271
272 /* Enable output */
273 tmp |= CLKMUX_EN;
274 writel_relaxed(tmp, pll->base + PLL_CTRL);
275
276 ana_mfn = readl_relaxed(pll->base + PLL_STATUS);
277 ana_mfn = FIELD_GET(PLL_MFN_MASK, ana_mfn);
278
279 WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n");
280
281 return 0;
282}
283
284static int clk_fracn_gppll_prepare(struct clk *clk)
285{
286 struct clk_fracn_gppll *pll = to_clk_fracn_gppll(clk);
287 u32 val;
288 int ret;
289
290 val = readl_relaxed(pll->base + PLL_CTRL);
291 if (val & POWERUP_MASK)
292 return 0;
293
294 val |= CLKMUX_BYPASS;
295 writel_relaxed(val, pll->base + PLL_CTRL);
296
297 val |= POWERUP_MASK;
298 writel_relaxed(val, pll->base + PLL_CTRL);
299
300 val |= CLKMUX_EN;
301 writel_relaxed(val, pll->base + PLL_CTRL);
302
303 ret = clk_fracn_gppll_wait_lock(pll);
304 if (ret)
305 return ret;
306
307 val &= ~CLKMUX_BYPASS;
308 writel_relaxed(val, pll->base + PLL_CTRL);
309
310 return 0;
311}
312
313static int clk_fracn_gppll_unprepare(struct clk *clk)
314{
315 struct clk_fracn_gppll *pll = to_clk_fracn_gppll(dev_get_clk_ptr(clk->dev));
316 u32 val;
317
318 val = readl_relaxed(pll->base + PLL_CTRL);
319 val &= ~POWERUP_MASK;
320 writel_relaxed(val, pll->base + PLL_CTRL);
321
322 return 0;
323}
324
325static const struct clk_ops clk_fracn_gppll_ops = {
326 .enable = clk_fracn_gppll_prepare,
327 .disable = clk_fracn_gppll_unprepare,
328 .get_rate = clk_fracn_gppll_recalc_rate,
329 .set_rate = clk_fracn_gppll_set_rate,
330 .round_rate = clk_fracn_gppll_round_rate,
331};
332
333static struct clk *_imx_clk_fracn_gppll(const char *name, const char *parent_name,
334 void __iomem *base,
335 const struct imx_fracn_gppll_clk *pll_clk,
336 u32 pll_flags)
337{
338 struct clk_fracn_gppll *pll;
339 struct clk *clk;
340 int ret;
341
342 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
343 if (!pll)
344 return ERR_PTR(-ENOMEM);
345
346 pll->base = base;
347 pll->rate_table = pll_clk->rate_table;
348 pll->rate_count = pll_clk->rate_count;
349 pll->flags = pll_flags;
350
351 clk = &pll->clk;
352
353 ret = clk_register(clk, UBOOT_DM_CLK_IMX_FRACN_GPPLL,
354 name, parent_name);
355 if (ret) {
356 pr_err("%s: failed to register pll %s %d\n", __func__, name, ret);
357 kfree(pll);
358 return ERR_PTR(ret);
359 }
360
361 return clk;
362}
363
364struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base,
365 const struct imx_fracn_gppll_clk *pll_clk)
366{
367 return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN);
368}
369
370struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name,
371 void __iomem *base,
372 const struct imx_fracn_gppll_clk *pll_clk)
373{
374 return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER);
375}
376
377U_BOOT_DRIVER(clk_fracn_gppll) = {
378 .name = UBOOT_DM_CLK_IMX_FRACN_GPPLL,
379 .id = UCLASS_CLK,
380 .ops = &clk_fracn_gppll_ops,
381 .flags = DM_FLAG_PRE_RELOC,
382};