1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright 2021 NXP |
4 | */ |
5 | |
6 | #include <linux/bitfield.h> |
7 | #include <linux/clk-provider.h> |
8 | #include <linux/err.h> |
9 | #include <linux/export.h> |
10 | #include <linux/io.h> |
11 | #include <linux/iopoll.h> |
12 | #include <linux/slab.h> |
13 | #include <asm/div64.h> |
14 | |
15 | #include "clk.h" |
16 | |
17 | #define PLL_CTRL 0x0 |
18 | #define HW_CTRL_SEL BIT(16) |
19 | #define CLKMUX_BYPASS BIT(2) |
20 | #define CLKMUX_EN BIT(1) |
21 | #define POWERUP_MASK BIT(0) |
22 | |
23 | #define PLL_ANA_PRG 0x10 |
24 | #define PLL_SPREAD_SPECTRUM 0x30 |
25 | |
26 | #define PLL_NUMERATOR 0x40 |
27 | #define PLL_MFN_MASK GENMASK(31, 2) |
28 | |
29 | #define PLL_DENOMINATOR 0x50 |
30 | #define PLL_MFD_MASK GENMASK(29, 0) |
31 | |
32 | #define PLL_DIV 0x60 |
33 | #define PLL_MFI_MASK GENMASK(24, 16) |
34 | #define PLL_RDIV_MASK GENMASK(15, 13) |
35 | #define PLL_ODIV_MASK GENMASK(7, 0) |
36 | |
37 | #define PLL_DFS_CTRL(x) (0x70 + (x) * 0x10) |
38 | |
39 | #define PLL_STATUS 0xF0 |
40 | #define LOCK_STATUS BIT(0) |
41 | |
42 | #define DFS_STATUS 0xF4 |
43 | |
44 | #define LOCK_TIMEOUT_US 200 |
45 | |
46 | #define PLL_FRACN_GP(_rate, _mfi, _mfn, _mfd, _rdiv, _odiv) \ |
47 | { \ |
48 | .rate = (_rate), \ |
49 | .mfi = (_mfi), \ |
50 | .mfn = (_mfn), \ |
51 | .mfd = (_mfd), \ |
52 | .rdiv = (_rdiv), \ |
53 | .odiv = (_odiv), \ |
54 | } |
55 | |
56 | #define PLL_FRACN_GP_INTEGER(_rate, _mfi, _rdiv, _odiv) \ |
57 | { \ |
58 | .rate = (_rate), \ |
59 | .mfi = (_mfi), \ |
60 | .mfn = 0, \ |
61 | .mfd = 0, \ |
62 | .rdiv = (_rdiv), \ |
63 | .odiv = (_odiv), \ |
64 | } |
65 | |
66 | struct clk_fracn_gppll { |
67 | struct clk_hw hw; |
68 | void __iomem *base; |
69 | const struct imx_fracn_gppll_rate_table *rate_table; |
70 | int rate_count; |
71 | u32 flags; |
72 | }; |
73 | |
74 | /* |
75 | * Fvco = (Fref / rdiv) * (MFI + MFN / MFD) |
76 | * Fout = Fvco / odiv |
77 | * The (Fref / rdiv) should be in range 20MHz to 40MHz |
78 | * The Fvco should be in range 2.5Ghz to 5Ghz |
79 | */ |
80 | static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { |
81 | PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6), |
82 | PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8), |
83 | PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6), |
84 | PLL_FRACN_GP(519750000U, 173, 25, 100, 1, 8), |
85 | PLL_FRACN_GP(498000000U, 166, 0, 1, 0, 8), |
86 | PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6), |
87 | PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9), |
88 | PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12), |
89 | PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10), |
90 | PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12) |
91 | }; |
92 | |
93 | struct imx_fracn_gppll_clk imx_fracn_gppll = { |
94 | .rate_table = fracn_tbl, |
95 | .rate_count = ARRAY_SIZE(fracn_tbl), |
96 | }; |
97 | EXPORT_SYMBOL_GPL(imx_fracn_gppll); |
98 | |
99 | /* |
100 | * Fvco = (Fref / rdiv) * MFI |
101 | * Fout = Fvco / odiv |
102 | * The (Fref / rdiv) should be in range 20MHz to 40MHz |
103 | * The Fvco should be in range 2.5Ghz to 5Ghz |
104 | */ |
105 | static const struct imx_fracn_gppll_rate_table int_tbl[] = { |
106 | PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2), |
107 | PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3), |
108 | PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4), |
109 | }; |
110 | |
111 | struct imx_fracn_gppll_clk imx_fracn_gppll_integer = { |
112 | .rate_table = int_tbl, |
113 | .rate_count = ARRAY_SIZE(int_tbl), |
114 | }; |
115 | EXPORT_SYMBOL_GPL(imx_fracn_gppll_integer); |
116 | |
117 | static inline struct clk_fracn_gppll *to_clk_fracn_gppll(struct clk_hw *hw) |
118 | { |
119 | return container_of(hw, struct clk_fracn_gppll, hw); |
120 | } |
121 | |
122 | static const struct imx_fracn_gppll_rate_table * |
123 | imx_get_pll_settings(struct clk_fracn_gppll *pll, unsigned long rate) |
124 | { |
125 | const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; |
126 | int i; |
127 | |
128 | for (i = 0; i < pll->rate_count; i++) |
129 | if (rate == rate_table[i].rate) |
130 | return &rate_table[i]; |
131 | |
132 | return NULL; |
133 | } |
134 | |
135 | static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate, |
136 | unsigned long *prate) |
137 | { |
138 | struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); |
139 | const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; |
140 | int i; |
141 | |
142 | /* Assuming rate_table is in descending order */ |
143 | for (i = 0; i < pll->rate_count; i++) |
144 | if (rate >= rate_table[i].rate) |
145 | return rate_table[i].rate; |
146 | |
147 | /* return minimum supported value */ |
148 | return rate_table[pll->rate_count - 1].rate; |
149 | } |
150 | |
151 | static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) |
152 | { |
153 | struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); |
154 | const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table; |
155 | u32 pll_numerator, pll_denominator, pll_div; |
156 | u32 mfi, mfn, mfd, rdiv, odiv; |
157 | u64 fvco = parent_rate; |
158 | long rate = 0; |
159 | int i; |
160 | |
161 | pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR); |
162 | mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator); |
163 | |
164 | pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR); |
165 | mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator); |
166 | |
167 | pll_div = readl_relaxed(pll->base + PLL_DIV); |
168 | mfi = FIELD_GET(PLL_MFI_MASK, pll_div); |
169 | |
170 | rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div); |
171 | odiv = FIELD_GET(PLL_ODIV_MASK, pll_div); |
172 | |
173 | /* |
174 | * Sometimes, the recalculated rate has deviation due to |
175 | * the frac part. So find the accurate pll rate from the table |
176 | * first, if no match rate in the table, use the rate calculated |
177 | * from the equation below. |
178 | */ |
179 | for (i = 0; i < pll->rate_count; i++) { |
180 | if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi && |
181 | rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv && |
182 | rate_table[i].odiv == odiv) |
183 | rate = rate_table[i].rate; |
184 | } |
185 | |
186 | if (rate) |
187 | return (unsigned long)rate; |
188 | |
189 | if (!rdiv) |
190 | rdiv = rdiv + 1; |
191 | |
192 | switch (odiv) { |
193 | case 0: |
194 | odiv = 2; |
195 | break; |
196 | case 1: |
197 | odiv = 3; |
198 | break; |
199 | default: |
200 | break; |
201 | } |
202 | |
203 | if (pll->flags & CLK_FRACN_GPPLL_INTEGER) { |
204 | /* Fvco = (Fref / rdiv) * MFI */ |
205 | fvco = fvco * mfi; |
206 | do_div(fvco, rdiv * odiv); |
207 | } else { |
208 | /* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */ |
209 | fvco = fvco * mfi * mfd + fvco * mfn; |
210 | do_div(fvco, mfd * rdiv * odiv); |
211 | } |
212 | |
213 | return (unsigned long)fvco; |
214 | } |
215 | |
216 | static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll) |
217 | { |
218 | u32 val; |
219 | |
220 | return readl_poll_timeout(pll->base + PLL_STATUS, val, |
221 | val & LOCK_STATUS, 0, LOCK_TIMEOUT_US); |
222 | } |
223 | |
224 | static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, |
225 | unsigned long prate) |
226 | { |
227 | struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); |
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, rate: 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 | |
284 | static int clk_fracn_gppll_prepare(struct clk_hw *hw) |
285 | { |
286 | struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); |
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 | |
313 | static int clk_fracn_gppll_is_prepared(struct clk_hw *hw) |
314 | { |
315 | struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); |
316 | u32 val; |
317 | |
318 | val = readl_relaxed(pll->base + PLL_CTRL); |
319 | |
320 | return (val & POWERUP_MASK) ? 1 : 0; |
321 | } |
322 | |
323 | static void clk_fracn_gppll_unprepare(struct clk_hw *hw) |
324 | { |
325 | struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw); |
326 | u32 val; |
327 | |
328 | val = readl_relaxed(pll->base + PLL_CTRL); |
329 | val &= ~POWERUP_MASK; |
330 | writel_relaxed(val, pll->base + PLL_CTRL); |
331 | } |
332 | |
333 | static const struct clk_ops clk_fracn_gppll_ops = { |
334 | .prepare = clk_fracn_gppll_prepare, |
335 | .unprepare = clk_fracn_gppll_unprepare, |
336 | .is_prepared = clk_fracn_gppll_is_prepared, |
337 | .recalc_rate = clk_fracn_gppll_recalc_rate, |
338 | .round_rate = clk_fracn_gppll_round_rate, |
339 | .set_rate = clk_fracn_gppll_set_rate, |
340 | }; |
341 | |
342 | static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name, |
343 | void __iomem *base, |
344 | const struct imx_fracn_gppll_clk *pll_clk, |
345 | u32 pll_flags) |
346 | { |
347 | struct clk_fracn_gppll *pll; |
348 | struct clk_hw *hw; |
349 | struct clk_init_data init; |
350 | int ret; |
351 | |
352 | pll = kzalloc(size: sizeof(*pll), GFP_KERNEL); |
353 | if (!pll) |
354 | return ERR_PTR(error: -ENOMEM); |
355 | |
356 | init.name = name; |
357 | init.flags = pll_clk->flags; |
358 | init.parent_names = &parent_name; |
359 | init.num_parents = 1; |
360 | init.ops = &clk_fracn_gppll_ops; |
361 | |
362 | pll->base = base; |
363 | pll->hw.init = &init; |
364 | pll->rate_table = pll_clk->rate_table; |
365 | pll->rate_count = pll_clk->rate_count; |
366 | pll->flags = pll_flags; |
367 | |
368 | hw = &pll->hw; |
369 | |
370 | ret = clk_hw_register(NULL, hw); |
371 | if (ret) { |
372 | pr_err("%s: failed to register pll %s %d\n" , __func__, name, ret); |
373 | kfree(objp: pll); |
374 | return ERR_PTR(error: ret); |
375 | } |
376 | |
377 | return hw; |
378 | } |
379 | |
380 | struct clk_hw *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, |
381 | const struct imx_fracn_gppll_clk *pll_clk) |
382 | { |
383 | return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_FRACN); |
384 | } |
385 | EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll); |
386 | |
387 | struct clk_hw *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, |
388 | void __iomem *base, |
389 | const struct imx_fracn_gppll_clk *pll_clk) |
390 | { |
391 | return _imx_clk_fracn_gppll(name, parent_name, base, pll_clk, CLK_FRACN_GPPLL_INTEGER); |
392 | } |
393 | EXPORT_SYMBOL_GPL(imx_clk_fracn_gppll_integer); |
394 | |