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