1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * SAM9X60's PLL clock support.
4  *
5  * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
6  *
7  * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
8  *
9  * Based on drivers/clk/at91/clk-sam9x60-pll.c from Linux.
10  *
11  */
12 
13 #include <asm/processor.h>
14 #include <common.h>
15 #include <clk-uclass.h>
16 #include <div64.h>
17 #include <dm.h>
18 #include <linux/clk-provider.h>
19 #include <linux/clk/at91_pmc.h>
20 #include <linux/delay.h>
21 
22 #include "pmc.h"
23 
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"
26 
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)
30 
31 #define PLL_DIV_MAX		(FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
32 #define UPLL_DIV		2
33 #define PLL_MUL_MAX		(FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
34 
35 #define FCORE_MIN		(600000000)
36 #define FCORE_MAX		(1200000000)
37 
38 #define PLL_MAX_ID		7
39 
40 struct sam9x60_pll {
41 	void __iomem *base;
42 	const struct clk_pll_characteristics *characteristics;
43 	const struct clk_pll_layout *layout;
44 	struct clk clk;
45 	u8 id;
46 };
47 
48 #define to_sam9x60_pll(_clk)	container_of(_clk, struct sam9x60_pll, clk)
49 
sam9x60_pll_ready(void __iomem * base,int id)50 static inline bool sam9x60_pll_ready(void __iomem *base, int id)
51 {
52 	unsigned int status;
53 
54 	pmc_read(base, AT91_PMC_PLL_ISR0, &status);
55 
56 	return !!(status & BIT(id));
57 }
58 
sam9x60_frac_pll_compute_mul_frac(u32 * mul,u32 * frac,ulong rate,ulong parent_rate)59 static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate,
60 					      ulong parent_rate)
61 {
62 	unsigned long tmprate, remainder;
63 	unsigned long nmul = 0;
64 	unsigned long nfrac = 0;
65 
66 	if (rate < FCORE_MIN || rate > FCORE_MAX)
67 		return -ERANGE;
68 
69 	/*
70 	 * Calculate the multiplier associated with the current
71 	 * divider that provide the closest rate to the requested one.
72 	 */
73 	nmul = mult_frac(rate, 1, parent_rate);
74 	tmprate = mult_frac(parent_rate, nmul, 1);
75 	remainder = rate - tmprate;
76 
77 	if (remainder) {
78 		nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),
79 					      parent_rate);
80 
81 		tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,
82 						 (1 << 22));
83 	}
84 
85 	/* Check if resulted rate is valid.  */
86 	if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
87 		return -ERANGE;
88 
89 	*mul = nmul - 1;
90 	*frac = nfrac;
91 
92 	return tmprate;
93 }
94 
sam9x60_frac_pll_set_rate(struct clk * clk,ulong rate)95 static ulong sam9x60_frac_pll_set_rate(struct clk *clk, ulong rate)
96 {
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);
102 	long ret;
103 
104 	if (!parent_rate)
105 		return 0;
106 
107 	ret = sam9x60_frac_pll_compute_mul_frac(&nmul, &nfrac, rate,
108 						parent_rate);
109 	if (ret < 0)
110 		return 0;
111 
112 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
113 			pll->id);
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;
117 
118 	/* Check against current values. */
119 	if (sam9x60_pll_ready(base, pll->id) &&
120 	    nmul == cmul && nfrac == cfrac)
121 		return 0;
122 
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));
127 
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);
131 
132 	while (ready && !sam9x60_pll_ready(base, pll->id)) {
133 		debug("waiting for pll %u...\n", pll->id);
134 		cpu_relax();
135 	}
136 
137 	return parent_rate * (nmul + 1) + ((u64)parent_rate * nfrac >> 22);
138 }
139 
sam9x60_frac_pll_get_rate(struct clk * clk)140 static ulong sam9x60_frac_pll_get_rate(struct clk *clk)
141 {
142 	struct sam9x60_pll *pll = to_sam9x60_pll(clk);
143 	void __iomem *base = pll->base;
144 	ulong parent_rate = clk_get_parent_rate(clk);
145 	u32 mul, frac, val;
146 
147 	if (!parent_rate)
148 		return 0;
149 
150 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
151 			pll->id);
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;
155 
156 	return (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22));
157 }
158 
sam9x60_frac_pll_enable(struct clk * clk)159 static int sam9x60_frac_pll_enable(struct clk *clk)
160 {
161 	struct sam9x60_pll *pll = to_sam9x60_pll(clk);
162 	void __iomem *base = pll->base;
163 	unsigned int val;
164 	ulong crate;
165 
166 	crate = sam9x60_frac_pll_get_rate(clk);
167 	if (crate < FCORE_MIN || crate > FCORE_MAX)
168 		return -ERANGE;
169 
170 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
171 			pll->id);
172 	pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
173 
174 	if (sam9x60_pll_ready(base, pll->id))
175 		return 0;
176 
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);
181 
182 	/* Recommended value for AT91_PMC_PLL_ACR */
183 	if (pll->characteristics->upll)
184 		val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
185 	else
186 		val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
187 	pmc_write(base, AT91_PMC_PLL_ACR, val);
188 
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);
193 
194 		udelay(10);
195 
196 		/* Enable the UTMI internal regulator */
197 		val |= AT91_PMC_PLL_ACR_UTMIVR;
198 		pmc_write(base, AT91_PMC_PLL_ACR, val);
199 
200 		udelay(10);
201 
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);
206 	}
207 
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);
211 
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);
215 
216 	while (!sam9x60_pll_ready(base, pll->id)) {
217 		debug("waiting for pll %u...\n", pll->id);
218 		cpu_relax();
219 	}
220 
221 	return 0;
222 }
223 
sam9x60_frac_pll_disable(struct clk * clk)224 static int sam9x60_frac_pll_disable(struct clk *clk)
225 {
226 	struct sam9x60_pll *pll = to_sam9x60_pll(clk);
227 	void __iomem *base = pll->base;
228 
229 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
230 			pll->id);
231 
232 	pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
233 			AT91_PMC_PLL_CTRL0_ENPLL, 0);
234 
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);
239 
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);
243 
244 	return 0;
245 }
246 
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,
252 };
253 
sam9x60_div_pll_enable(struct clk * clk)254 static int sam9x60_div_pll_enable(struct clk *clk)
255 {
256 	struct sam9x60_pll *pll = to_sam9x60_pll(clk);
257 	void __iomem *base = pll->base;
258 	unsigned int val;
259 
260 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
261 			pll->id);
262 	pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
263 
264 	/* Stop if enabled. */
265 	if (val & pll->layout->endiv_mask)
266 		return 0;
267 
268 	pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
269 			pll->layout->endiv_mask,
270 			(1 << pll->layout->endiv_shift));
271 
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);
275 
276 	while (!sam9x60_pll_ready(base, pll->id)) {
277 		debug("waiting for pll %u...\n", pll->id);
278 		cpu_relax();
279 	}
280 
281 	return 0;
282 }
283 
sam9x60_div_pll_disable(struct clk * clk)284 static int sam9x60_div_pll_disable(struct clk *clk)
285 {
286 	struct sam9x60_pll *pll = to_sam9x60_pll(clk);
287 	void __iomem *base = pll->base;
288 
289 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
290 			pll->id);
291 
292 	pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
293 			pll->layout->endiv_mask, 0);
294 
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);
298 
299 	return 0;
300 }
301 
sam9x60_div_pll_set_rate(struct clk * clk,ulong rate)302 static ulong sam9x60_div_pll_set_rate(struct clk *clk, ulong rate)
303 {
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);
312 	u32 val;
313 
314 	if (!parent_rate || div > pll->layout->div_mask ||
315 	    req_rate < characteristics->output[0].min ||
316 	    req_rate > characteristics->output[0].max)
317 		return 0;
318 
319 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
320 			pll->id);
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))
324 		return 0;
325 
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);
330 
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);
334 
335 	while (ready && !sam9x60_pll_ready(base, pll->id)) {
336 		debug("waiting for pll %u...\n", pll->id);
337 		cpu_relax();
338 	}
339 
340 	return req_rate;
341 }
342 
sam9x60_div_pll_get_rate(struct clk * clk)343 static ulong sam9x60_div_pll_get_rate(struct clk *clk)
344 {
345 	struct sam9x60_pll *pll = to_sam9x60_pll(clk);
346 	void __iomem *base = pll->base;
347 	ulong parent_rate = clk_get_parent_rate(clk);
348 	u32 val;
349 	u8 div;
350 
351 	if (!parent_rate)
352 		return 0;
353 
354 	pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
355 			pll->id);
356 
357 	pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
358 
359 	div = (val & pll->layout->div_mask) >> pll->layout->div_shift;
360 
361 	return parent_rate / (div + 1);
362 }
363 
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,
369 };
370 
371 static struct clk *
sam9x60_clk_register_pll(void __iomem * base,const char * type,const char * name,const char * parent_name,u8 id,const struct clk_pll_characteristics * characteristics,const struct clk_pll_layout * layout,u32 flags)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)
376 {
377 	struct sam9x60_pll *pll;
378 	struct clk *clk;
379 	int ret;
380 
381 	if (!base || !type || !name || !parent_name || !characteristics ||
382 	    !layout || id > PLL_MAX_ID)
383 		return ERR_PTR(-EINVAL);
384 
385 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
386 	if (!pll)
387 		return ERR_PTR(-ENOMEM);
388 
389 	pll->id = id;
390 	pll->characteristics = characteristics;
391 	pll->layout = layout;
392 	pll->base = base;
393 	clk = &pll->clk;
394 	clk->flags = flags;
395 
396 	ret = clk_register(clk, type, name, parent_name);
397 	if (ret) {
398 		kfree(pll);
399 		clk = ERR_PTR(ret);
400 	}
401 
402 	return clk;
403 }
404 
405 struct clk *
sam9x60_clk_register_div_pll(void __iomem * base,const char * name,const char * parent_name,u8 id,const struct clk_pll_characteristics * characteristics,const struct clk_pll_layout * layout,bool critical)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)
410 {
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));
415 }
416 
417 struct clk *
sam9x60_clk_register_frac_pll(void __iomem * base,const char * name,const char * parent_name,u8 id,const struct clk_pll_characteristics * characteristics,const struct clk_pll_layout * layout,bool critical)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)
422 {
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));
427 }
428 
429 U_BOOT_DRIVER(at91_sam9x60_div_pll_clk) = {
430 	.name = UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL,
431 	.id = UCLASS_CLK,
432 	.ops = &sam9x60_div_pll_ops,
433 	.flags = DM_FLAG_PRE_RELOC,
434 };
435 
436 U_BOOT_DRIVER(at91_sam9x60_frac_pll_clk) = {
437 	.name = UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL,
438 	.id = UCLASS_CLK,
439 	.ops = &sam9x60_frac_pll_ops,
440 	.flags = DM_FLAG_PRE_RELOC,
441 };
442 
443