1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
4  *
5  */
6 
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <div64.h>
11 #include <time.h>
12 #include <wait_bit.h>
13 #include <asm/global_data.h>
14 #include <dm/lists.h>
15 #include <asm/io.h>
16 #include <linux/bitops.h>
17 #include <linux/bug.h>
18 #include <mach/pic32.h>
19 #include <dt-bindings/clock/microchip,clock.h>
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
23 /* Primary oscillator */
24 #define SYS_POSC_CLK_HZ	24000000
25 
26 /* FRC clk rate */
27 #define SYS_FRC_CLK_HZ	8000000
28 
29 /* Clock Registers */
30 #define OSCCON		0x0000
31 #define OSCTUNE		0x0010
32 #define SPLLCON		0x0020
33 #define REFO1CON	0x0080
34 #define REFO1TRIM	0x0090
35 #define PB1DIV		0x0140
36 
37 /* SPLL */
38 #define ICLK_MASK	0x00000080
39 #define PLLIDIV_MASK	0x00000007
40 #define PLLODIV_MASK	0x00000007
41 #define CUROSC_MASK	0x00000007
42 #define PLLMUL_MASK	0x0000007F
43 #define FRCDIV_MASK	0x00000007
44 
45 /* PBCLK */
46 #define PBDIV_MASK	0x00000007
47 
48 /* SYSCLK MUX */
49 #define SCLK_SRC_FRC1	0
50 #define SCLK_SRC_SPLL	1
51 #define SCLK_SRC_POSC	2
52 #define SCLK_SRC_FRC2	7
53 
54 /* Reference Oscillator Control Reg fields */
55 #define REFO_SEL_MASK	0x0f
56 #define REFO_SEL_SHIFT	0
57 #define REFO_ACTIVE	BIT(8)
58 #define REFO_DIVSW_EN	BIT(9)
59 #define REFO_OE		BIT(12)
60 #define REFO_ON		BIT(15)
61 #define REFO_DIV_SHIFT	16
62 #define REFO_DIV_MASK	0x7fff
63 
64 /* Reference Oscillator Trim Register Fields */
65 #define REFO_TRIM_REG	0x10
66 #define REFO_TRIM_MASK	0x1ff
67 #define REFO_TRIM_SHIFT	23
68 #define REFO_TRIM_MAX	511
69 
70 #define ROCLK_SRC_SCLK		0x0
71 #define ROCLK_SRC_SPLL		0x7
72 #define ROCLK_SRC_ROCLKI	0x8
73 
74 /* Memory PLL */
75 #define MPLL_IDIV		0x3f
76 #define MPLL_MULT		0xff
77 #define MPLL_ODIV1		0x7
78 #define MPLL_ODIV2		0x7
79 #define MPLL_VREG_RDY		BIT(23)
80 #define MPLL_RDY		BIT(31)
81 #define MPLL_IDIV_SHIFT		0
82 #define MPLL_MULT_SHIFT		8
83 #define MPLL_ODIV1_SHIFT	24
84 #define MPLL_ODIV2_SHIFT	27
85 #define MPLL_IDIV_INIT		0x03
86 #define MPLL_MULT_INIT		0x32
87 #define MPLL_ODIV1_INIT		0x02
88 #define MPLL_ODIV2_INIT		0x01
89 
90 struct pic32_clk_priv {
91 	void __iomem *iobase;
92 	void __iomem *syscfg_base;
93 };
94 
pic32_get_pll_rate(struct pic32_clk_priv * priv)95 static ulong pic32_get_pll_rate(struct pic32_clk_priv *priv)
96 {
97 	u32 iclk, idiv, odiv, mult;
98 	ulong plliclk, v;
99 
100 	v = readl(priv->iobase + SPLLCON);
101 	iclk = (v & ICLK_MASK);
102 	idiv = ((v >> 8) & PLLIDIV_MASK) + 1;
103 	odiv = ((v >> 24) & PLLODIV_MASK);
104 	mult = ((v >> 16) & PLLMUL_MASK) + 1;
105 
106 	plliclk = iclk ? SYS_FRC_CLK_HZ : SYS_POSC_CLK_HZ;
107 
108 	if (odiv < 2)
109 		odiv = 2;
110 	else if (odiv < 5)
111 		odiv = (1 << odiv);
112 	else
113 		odiv = 32;
114 
115 	return ((plliclk / idiv) * mult) / odiv;
116 }
117 
pic32_get_sysclk(struct pic32_clk_priv * priv)118 static ulong pic32_get_sysclk(struct pic32_clk_priv *priv)
119 {
120 	ulong v;
121 	ulong hz;
122 	ulong div, frcdiv;
123 	ulong curr_osc;
124 
125 	/* get clk source */
126 	v = readl(priv->iobase + OSCCON);
127 	curr_osc = (v >> 12) & CUROSC_MASK;
128 	switch (curr_osc) {
129 	case SCLK_SRC_FRC1:
130 	case SCLK_SRC_FRC2:
131 		frcdiv = ((v >> 24) & FRCDIV_MASK);
132 		div = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7));
133 		hz = SYS_FRC_CLK_HZ / div;
134 		break;
135 
136 	case SCLK_SRC_SPLL:
137 		hz = pic32_get_pll_rate(priv);
138 		break;
139 
140 	case SCLK_SRC_POSC:
141 		hz = SYS_POSC_CLK_HZ;
142 		break;
143 
144 	default:
145 		hz = 0;
146 		printf("clk: unknown sclk_src.\n");
147 		break;
148 	}
149 
150 	return hz;
151 }
152 
pic32_get_pbclk(struct pic32_clk_priv * priv,int periph)153 static ulong pic32_get_pbclk(struct pic32_clk_priv *priv, int periph)
154 {
155 	void __iomem *reg;
156 	ulong div, clk_freq;
157 
158 	WARN_ON((periph < PB1CLK) || (periph > PB7CLK));
159 
160 	clk_freq = pic32_get_sysclk(priv);
161 
162 	reg = priv->iobase + PB1DIV + (periph - PB1CLK) * 0x10;
163 	div = (readl(reg) & PBDIV_MASK) + 1;
164 
165 	return clk_freq / div;
166 }
167 
pic32_get_cpuclk(struct pic32_clk_priv * priv)168 static ulong pic32_get_cpuclk(struct pic32_clk_priv *priv)
169 {
170 	return pic32_get_pbclk(priv, PB7CLK);
171 }
172 
pic32_set_refclk(struct pic32_clk_priv * priv,int periph,int parent_rate,int rate,int parent_id)173 static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int periph,
174 			      int parent_rate, int rate, int parent_id)
175 {
176 	void __iomem *reg;
177 	u32 div, trim, v;
178 	u64 frac;
179 
180 	WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
181 
182 	/* calculate dividers,
183 	 *   rate = parent_rate / [2 * (div + (trim / 512))]
184 	 */
185 	if (parent_rate <= rate) {
186 		div = 0;
187 		trim = 0;
188 	} else {
189 		div = parent_rate / (rate << 1);
190 		frac = parent_rate;
191 		frac <<= 8;
192 		do_div(frac, rate);
193 		frac -= (u64)(div << 9);
194 		trim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX : (u32)frac;
195 	}
196 
197 	reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
198 
199 	/* disable clk */
200 	writel(REFO_ON | REFO_OE, reg + _CLR_OFFSET);
201 
202 	/* wait till previous src change is active */
203 	wait_for_bit_le32(reg, REFO_DIVSW_EN | REFO_ACTIVE,
204 			  false, CONFIG_SYS_HZ, false);
205 
206 	/* parent_id */
207 	v = readl(reg);
208 	v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT);
209 	v |= (parent_id << REFO_SEL_SHIFT);
210 
211 	/* apply rodiv */
212 	v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT);
213 	v |= (div << REFO_DIV_SHIFT);
214 	writel(v, reg);
215 
216 	/* apply trim */
217 	v = readl(reg + REFO_TRIM_REG);
218 	v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT);
219 	v |= (trim << REFO_TRIM_SHIFT);
220 	writel(v, reg + REFO_TRIM_REG);
221 
222 	/* enable clk */
223 	writel(REFO_ON | REFO_OE, reg + _SET_OFFSET);
224 
225 	/* switch divider */
226 	writel(REFO_DIVSW_EN, reg + _SET_OFFSET);
227 
228 	/* wait for divider switching to complete */
229 	return wait_for_bit_le32(reg, REFO_DIVSW_EN, false,
230 				 CONFIG_SYS_HZ, false);
231 }
232 
pic32_get_refclk(struct pic32_clk_priv * priv,int periph)233 static ulong pic32_get_refclk(struct pic32_clk_priv *priv, int periph)
234 {
235 	u32 rodiv, rotrim, rosel, v, parent_rate;
236 	void __iomem *reg;
237 	u64 rate64;
238 
239 	WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
240 
241 	reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
242 	v = readl(reg);
243 	/* get rosel */
244 	rosel = (v >> REFO_SEL_SHIFT) & REFO_SEL_MASK;
245 	/* get div */
246 	rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK;
247 
248 	/* get trim */
249 	v = readl(reg + REFO_TRIM_REG);
250 	rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK;
251 
252 	if (!rodiv)
253 		return 0;
254 
255 	/* get parent rate */
256 	switch (rosel) {
257 	case ROCLK_SRC_SCLK:
258 		parent_rate = pic32_get_cpuclk(priv);
259 		break;
260 	case ROCLK_SRC_SPLL:
261 		parent_rate = pic32_get_pll_rate(priv);
262 		break;
263 	default:
264 		parent_rate = 0;
265 		break;
266 	}
267 
268 	/* Calculation
269 	 * rate = parent_rate / [2 * (div + (trim / 512))]
270 	 */
271 	if (rotrim) {
272 		rodiv <<= 9;
273 		rodiv += rotrim;
274 		rate64 = parent_rate;
275 		rate64 <<= 8;
276 		do_div(rate64, rodiv);
277 		v = (u32)rate64;
278 	} else {
279 		v = parent_rate / (rodiv << 1);
280 	}
281 	return v;
282 }
283 
pic32_get_mpll_rate(struct pic32_clk_priv * priv)284 static ulong pic32_get_mpll_rate(struct pic32_clk_priv *priv)
285 {
286 	u32 v, idiv, mul;
287 	u32 odiv1, odiv2;
288 	u64 rate;
289 
290 	v = readl(priv->syscfg_base + CFGMPLL);
291 	idiv = v & MPLL_IDIV;
292 	mul = (v >> MPLL_MULT_SHIFT) & MPLL_MULT;
293 	odiv1 = (v >> MPLL_ODIV1_SHIFT) & MPLL_ODIV1;
294 	odiv2 = (v >> MPLL_ODIV2_SHIFT) & MPLL_ODIV2;
295 
296 	rate = (SYS_POSC_CLK_HZ / idiv) * mul;
297 	do_div(rate, odiv1);
298 	do_div(rate, odiv2);
299 
300 	return (ulong)rate;
301 }
302 
pic32_mpll_init(struct pic32_clk_priv * priv)303 static int pic32_mpll_init(struct pic32_clk_priv *priv)
304 {
305 	u32 v, mask;
306 
307 	/* initialize */
308 	v = (MPLL_IDIV_INIT << MPLL_IDIV_SHIFT) |
309 	    (MPLL_MULT_INIT << MPLL_MULT_SHIFT) |
310 	    (MPLL_ODIV1_INIT << MPLL_ODIV1_SHIFT) |
311 	    (MPLL_ODIV2_INIT << MPLL_ODIV2_SHIFT);
312 
313 	writel(v, priv->syscfg_base + CFGMPLL);
314 
315 	/* Wait for ready */
316 	mask = MPLL_RDY | MPLL_VREG_RDY;
317 	return wait_for_bit_le32(priv->syscfg_base + CFGMPLL, mask,
318 				 true, get_tbclk(), false);
319 }
320 
pic32_clk_init(struct udevice * dev)321 static void pic32_clk_init(struct udevice *dev)
322 {
323 	const void *blob = gd->fdt_blob;
324 	struct pic32_clk_priv *priv;
325 	ulong rate, pll_hz;
326 	char propname[50];
327 	int i;
328 
329 	priv = dev_get_priv(dev);
330 	pll_hz = pic32_get_pll_rate(priv);
331 
332 	/* Initialize REFOs as not initialized and enabled on reset. */
333 	for (i = REF1CLK; i <= REF5CLK; i++) {
334 		snprintf(propname, sizeof(propname),
335 			 "microchip,refo%d-frequency", i - REF1CLK + 1);
336 		rate = fdtdec_get_int(blob, dev_of_offset(dev), propname, 0);
337 		if (rate)
338 			pic32_set_refclk(priv, i, pll_hz, rate, ROCLK_SRC_SPLL);
339 	}
340 
341 	/* Memory PLL */
342 	pic32_mpll_init(priv);
343 }
344 
pic32_get_rate(struct clk * clk)345 static ulong pic32_get_rate(struct clk *clk)
346 {
347 	struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
348 	ulong rate;
349 
350 	switch (clk->id) {
351 	case PB1CLK ... PB7CLK:
352 		rate = pic32_get_pbclk(priv, clk->id);
353 		break;
354 	case REF1CLK ... REF5CLK:
355 		rate = pic32_get_refclk(priv, clk->id);
356 		break;
357 	case PLLCLK:
358 		rate = pic32_get_pll_rate(priv);
359 		break;
360 	case MPLL:
361 		rate = pic32_get_mpll_rate(priv);
362 		break;
363 	default:
364 		rate = 0;
365 		break;
366 	}
367 
368 	return rate;
369 }
370 
pic32_set_rate(struct clk * clk,ulong rate)371 static ulong pic32_set_rate(struct clk *clk, ulong rate)
372 {
373 	struct pic32_clk_priv *priv = dev_get_priv(clk->dev);
374 	ulong pll_hz;
375 
376 	switch (clk->id) {
377 	case REF1CLK ... REF5CLK:
378 		pll_hz = pic32_get_pll_rate(priv);
379 		pic32_set_refclk(priv, clk->id, pll_hz, rate, ROCLK_SRC_SPLL);
380 		break;
381 	default:
382 		break;
383 	}
384 
385 	return rate;
386 }
387 
388 static struct clk_ops pic32_pic32_clk_ops = {
389 	.set_rate = pic32_set_rate,
390 	.get_rate = pic32_get_rate,
391 };
392 
pic32_clk_probe(struct udevice * dev)393 static int pic32_clk_probe(struct udevice *dev)
394 {
395 	struct pic32_clk_priv *priv = dev_get_priv(dev);
396 	fdt_addr_t addr;
397 	fdt_size_t size;
398 
399 	addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
400 				    &size);
401 	if (addr == FDT_ADDR_T_NONE)
402 		return -EINVAL;
403 
404 	priv->iobase = ioremap(addr, size);
405 	if (!priv->iobase)
406 		return -EINVAL;
407 
408 	priv->syscfg_base = pic32_get_syscfg_base();
409 
410 	/* initialize clocks */
411 	pic32_clk_init(dev);
412 
413 	return 0;
414 }
415 
416 static const struct udevice_id pic32_clk_ids[] = {
417 	{ .compatible = "microchip,pic32mzda-clk"},
418 	{}
419 };
420 
421 U_BOOT_DRIVER(pic32_clk) = {
422 	.name		= "pic32_clk",
423 	.id		= UCLASS_CLK,
424 	.of_match	= pic32_clk_ids,
425 	.ops		= &pic32_pic32_clk_ops,
426 	.probe		= pic32_clk_probe,
427 	.priv_auto	= sizeof(struct pic32_clk_priv),
428 };
429