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