1 // SPDX-License-Identifier: GPL-2.0+
3 * SAM9X60's PLL clock support.
5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
9 * Based on drivers/clk/at91/clk-sam9x60-pll.c from Linux.
13 #include <asm/processor.h>
15 #include <clk-uclass.h>
18 #include <linux/clk-provider.h>
19 #include <linux/clk/at91_pmc.h>
20 #include <linux/delay.h>
24 #define UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL "at91-sam9x60-div-pll-clk"
25 #define UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL "at91-sam9x60-frac-pll-clk"
27 #define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0)
28 #define PMC_PLL_CTRL1_MUL_MSK GENMASK(31, 24)
29 #define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0)
31 #define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
33 #define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
35 #define FCORE_MIN (600000000)
36 #define FCORE_MAX (1200000000)
42 const struct clk_pll_characteristics *characteristics;
43 const struct clk_pll_layout *layout;
48 #define to_sam9x60_pll(_clk) container_of(_clk, struct sam9x60_pll, clk)
50 static inline bool sam9x60_pll_ready(void __iomem *base, int id)
54 pmc_read(base, AT91_PMC_PLL_ISR0, &status);
56 return !!(status & BIT(id));
59 static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate,
62 unsigned long tmprate, remainder;
63 unsigned long nmul = 0;
64 unsigned long nfrac = 0;
66 if (rate < FCORE_MIN || rate > FCORE_MAX)
70 * Calculate the multiplier associated with the current
71 * divider that provide the closest rate to the requested one.
73 nmul = mult_frac(rate, 1, parent_rate);
74 tmprate = mult_frac(parent_rate, nmul, 1);
75 remainder = rate - tmprate;
78 nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),
81 tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,
85 /* Check if resulted rate is valid. */
86 if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
95 static ulong sam9x60_frac_pll_set_rate(struct clk *clk, ulong rate)
97 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
98 void __iomem *base = pll->base;
99 ulong parent_rate = clk_get_parent_rate(clk);
100 u32 nmul, cmul, nfrac, cfrac, val;
101 bool ready = sam9x60_pll_ready(base, pll->id);
107 ret = sam9x60_frac_pll_compute_mul_frac(&nmul, &nfrac, rate,
112 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
114 pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
115 cmul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
116 cfrac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
118 /* Check against current values. */
119 if (sam9x60_pll_ready(base, pll->id) &&
120 nmul == cmul && nfrac == cfrac)
123 /* Update it to hardware. */
124 pmc_write(base, AT91_PMC_PLL_CTRL1,
125 (nmul << pll->layout->mul_shift) |
126 (nfrac << pll->layout->frac_shift));
128 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
129 AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
130 AT91_PMC_PLL_UPDT_UPDATE | pll->id);
132 while (ready && !sam9x60_pll_ready(base, pll->id)) {
133 debug("waiting for pll %u...\n", pll->id);
137 return parent_rate * (nmul + 1) + ((u64)parent_rate * nfrac >> 22);
140 static ulong sam9x60_frac_pll_get_rate(struct clk *clk)
142 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
143 void __iomem *base = pll->base;
144 ulong parent_rate = clk_get_parent_rate(clk);
150 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
152 pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
153 mul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
154 frac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
156 return (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22));
159 static int sam9x60_frac_pll_enable(struct clk *clk)
161 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
162 void __iomem *base = pll->base;
166 crate = sam9x60_frac_pll_get_rate(clk);
167 if (crate < FCORE_MIN || crate > FCORE_MAX)
170 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
172 pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
174 if (sam9x60_pll_ready(base, pll->id))
177 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
178 AT91_PMC_PMM_UPDT_STUPTIM_MSK |
179 AT91_PMC_PLL_UPDT_ID_MSK,
180 AT91_PMC_PLL_UPDT_STUPTIM(0x3f) | pll->id);
182 /* Recommended value for AT91_PMC_PLL_ACR */
183 if (pll->characteristics->upll)
184 val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
186 val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
187 pmc_write(base, AT91_PMC_PLL_ACR, val);
189 if (pll->characteristics->upll) {
190 /* Enable the UTMI internal bandgap */
191 val |= AT91_PMC_PLL_ACR_UTMIBG;
192 pmc_write(base, AT91_PMC_PLL_ACR, val);
196 /* Enable the UTMI internal regulator */
197 val |= AT91_PMC_PLL_ACR_UTMIVR;
198 pmc_write(base, AT91_PMC_PLL_ACR, val);
202 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
203 AT91_PMC_PLL_UPDT_UPDATE |
204 AT91_PMC_PLL_UPDT_ID_MSK,
205 AT91_PMC_PLL_UPDT_UPDATE | pll->id);
208 pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
209 AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
210 AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);
212 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
213 AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
214 AT91_PMC_PLL_UPDT_UPDATE | pll->id);
216 while (!sam9x60_pll_ready(base, pll->id)) {
217 debug("waiting for pll %u...\n", pll->id);
224 static int sam9x60_frac_pll_disable(struct clk *clk)
226 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
227 void __iomem *base = pll->base;
229 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
232 pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
233 AT91_PMC_PLL_CTRL0_ENPLL, 0);
235 if (pll->characteristics->upll)
236 pmc_update_bits(base, AT91_PMC_PLL_ACR,
237 AT91_PMC_PLL_ACR_UTMIBG |
238 AT91_PMC_PLL_ACR_UTMIVR, 0);
240 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
241 AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
242 AT91_PMC_PLL_UPDT_UPDATE | pll->id);
247 static const struct clk_ops sam9x60_frac_pll_ops = {
248 .enable = sam9x60_frac_pll_enable,
249 .disable = sam9x60_frac_pll_disable,
250 .set_rate = sam9x60_frac_pll_set_rate,
251 .get_rate = sam9x60_frac_pll_get_rate,
254 static int sam9x60_div_pll_enable(struct clk *clk)
256 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
257 void __iomem *base = pll->base;
260 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
262 pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
264 /* Stop if enabled. */
265 if (val & pll->layout->endiv_mask)
268 pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
269 pll->layout->endiv_mask,
270 (1 << pll->layout->endiv_shift));
272 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
273 AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
274 AT91_PMC_PLL_UPDT_UPDATE | pll->id);
276 while (!sam9x60_pll_ready(base, pll->id)) {
277 debug("waiting for pll %u...\n", pll->id);
284 static int sam9x60_div_pll_disable(struct clk *clk)
286 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
287 void __iomem *base = pll->base;
289 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
292 pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
293 pll->layout->endiv_mask, 0);
295 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
296 AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
297 AT91_PMC_PLL_UPDT_UPDATE | pll->id);
302 static ulong sam9x60_div_pll_set_rate(struct clk *clk, ulong rate)
304 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
305 void __iomem *base = pll->base;
306 const struct clk_pll_characteristics *characteristics =
307 pll->characteristics;
308 ulong parent_rate = clk_get_parent_rate(clk);
309 u8 div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate) - 1;
310 ulong req_rate = parent_rate / (div + 1);
311 bool ready = sam9x60_pll_ready(base, pll->id);
314 if (!parent_rate || div > pll->layout->div_mask ||
315 req_rate < characteristics->output[0].min ||
316 req_rate > characteristics->output[0].max)
319 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
321 pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
322 /* Compare against current value. */
323 if (div == ((val & pll->layout->div_mask) >> pll->layout->div_shift))
326 /* Update it to hardware. */
327 pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
328 pll->layout->div_mask,
329 div << pll->layout->div_shift);
331 pmc_update_bits(base, AT91_PMC_PLL_UPDT,
332 AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
333 AT91_PMC_PLL_UPDT_UPDATE | pll->id);
335 while (ready && !sam9x60_pll_ready(base, pll->id)) {
336 debug("waiting for pll %u...\n", pll->id);
343 static ulong sam9x60_div_pll_get_rate(struct clk *clk)
345 struct sam9x60_pll *pll = to_sam9x60_pll(clk);
346 void __iomem *base = pll->base;
347 ulong parent_rate = clk_get_parent_rate(clk);
354 pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
357 pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
359 div = (val & pll->layout->div_mask) >> pll->layout->div_shift;
361 return parent_rate / (div + 1);
364 static const struct clk_ops sam9x60_div_pll_ops = {
365 .enable = sam9x60_div_pll_enable,
366 .disable = sam9x60_div_pll_disable,
367 .set_rate = sam9x60_div_pll_set_rate,
368 .get_rate = sam9x60_div_pll_get_rate,
372 sam9x60_clk_register_pll(void __iomem *base, const char *type,
373 const char *name, const char *parent_name, u8 id,
374 const struct clk_pll_characteristics *characteristics,
375 const struct clk_pll_layout *layout, u32 flags)
377 struct sam9x60_pll *pll;
381 if (!base || !type || !name || !parent_name || !characteristics ||
382 !layout || id > PLL_MAX_ID)
383 return ERR_PTR(-EINVAL);
385 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
387 return ERR_PTR(-ENOMEM);
390 pll->characteristics = characteristics;
391 pll->layout = layout;
396 ret = clk_register(clk, type, name, parent_name);
406 sam9x60_clk_register_div_pll(void __iomem *base, const char *name,
407 const char *parent_name, u8 id,
408 const struct clk_pll_characteristics *characteristics,
409 const struct clk_pll_layout *layout, bool critical)
411 return sam9x60_clk_register_pll(base,
412 UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL, name, parent_name, id,
413 characteristics, layout,
414 CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
418 sam9x60_clk_register_frac_pll(void __iomem *base, const char *name,
419 const char *parent_name, u8 id,
420 const struct clk_pll_characteristics *characteristics,
421 const struct clk_pll_layout *layout, bool critical)
423 return sam9x60_clk_register_pll(base,
424 UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL, name, parent_name, id,
425 characteristics, layout,
426 CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
429 U_BOOT_DRIVER(at91_sam9x60_div_pll_clk) = {
430 .name = UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL,
432 .ops = &sam9x60_div_pll_ops,
433 .flags = DM_FLAG_PRE_RELOC,
436 U_BOOT_DRIVER(at91_sam9x60_frac_pll_clk) = {
437 .name = UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL,
439 .ops = &sam9x60_frac_pll_ops,
440 .flags = DM_FLAG_PRE_RELOC,