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