blob: d240abaee46fab6db1dc870655a494cb9be96537 [file] [log] [blame]
Peng Fan690eea12021-08-07 16:00:45 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2021 NXP
4 */
5
6#include <common.h>
7#include <div64.h>
8#include <asm/io.h>
9#include <errno.h>
10#include <asm/arch/imx-regs.h>
11#include <asm/arch/cgc.h>
Peng Fan4cdb3a32022-04-06 14:30:12 +080012#include <asm/arch/clock.h>
Peng Fan690eea12021-08-07 16:00:45 +080013#include <asm/arch/sys_proto.h>
14#include <asm/global_data.h>
15#include <linux/delay.h>
Peng Fan4cdb3a32022-04-06 14:30:12 +080016#include <hang.h>
Peng Fan690eea12021-08-07 16:00:45 +080017
18DECLARE_GLOBAL_DATA_PTR;
19
20static struct cgc1_regs *cgc1_regs = (struct cgc1_regs *)0x292C0000UL;
21static struct cgc2_regs *cgc2_regs = (struct cgc2_regs *)0x2da60000UL;
22
23void cgc1_soscdiv_init(void)
24{
25 /* Configure SOSC/FRO DIV1 ~ DIV3 */
26 clrbits_le32(&cgc1_regs->soscdiv, BIT(7));
27 clrbits_le32(&cgc1_regs->soscdiv, BIT(15));
28 clrbits_le32(&cgc1_regs->soscdiv, BIT(23));
29 clrbits_le32(&cgc1_regs->soscdiv, BIT(31));
30
31 clrbits_le32(&cgc1_regs->frodiv, BIT(7));
32}
33
Peng Fan4cdb3a32022-04-06 14:30:12 +080034void cgc1_pll2_init(ulong freq)
Peng Fan690eea12021-08-07 16:00:45 +080035{
36 u32 reg;
37
38 if (readl(&cgc1_regs->pll2csr) & BIT(23))
39 clrbits_le32(&cgc1_regs->pll2csr, BIT(23));
40
41 /* Disable PLL2 */
42 clrbits_le32(&cgc1_regs->pll2csr, BIT(0));
43 mdelay(1);
44
45 /* wait valid bit false */
46 while ((readl(&cgc1_regs->pll2csr) & BIT(24)))
47 ;
48
Peng Fan4cdb3a32022-04-06 14:30:12 +080049 /* Select SOSC as source */
50 reg = (freq / MHZ(24)) << 16;
Peng Fan690eea12021-08-07 16:00:45 +080051 writel(reg, &cgc1_regs->pll2cfg);
52
53 /* Enable PLL2 */
54 setbits_le32(&cgc1_regs->pll2csr, BIT(0));
55
56 /* Wait for PLL2 clock ready */
57 while (!(readl(&cgc1_regs->pll2csr) & BIT(24)))
58 ;
59}
60
61static void cgc1_set_a35_clk(u32 clk_src, u32 div_core)
62{
63 u32 reg;
64
65 /* ulock */
66 if (readl(&cgc1_regs->ca35clk) & BIT(31))
67 clrbits_le32(&cgc1_regs->ca35clk, BIT(31));
68
69 reg = readl(&cgc1_regs->ca35clk);
70 reg &= ~GENMASK(29, 21);
71 reg |= ((clk_src & 0x3) << 28);
72 reg |= (((div_core - 1) & 0x3f) << 21);
73 writel(reg, &cgc1_regs->ca35clk);
74
75 while (!(readl(&cgc1_regs->ca35clk) & BIT(27)))
76 ;
77}
78
Peng Fan4cdb3a32022-04-06 14:30:12 +080079void cgc1_init_core_clk(ulong freq)
Peng Fan690eea12021-08-07 16:00:45 +080080{
81 u32 reg = readl(&cgc1_regs->ca35clk);
82
83 /* if already selected to PLL2, switch to FRO firstly */
84 if (((reg >> 28) & 0x3) == 0x1)
85 cgc1_set_a35_clk(0, 1);
86
Peng Fan4cdb3a32022-04-06 14:30:12 +080087 cgc1_pll2_init(freq);
Peng Fan690eea12021-08-07 16:00:45 +080088
89 /* Set A35 clock to pll2 */
90 cgc1_set_a35_clk(1, 1);
91}
92
93void cgc1_enet_stamp_sel(u32 clk_src)
94{
95 writel((clk_src & 0x7) << 24, &cgc1_regs->enetstamp);
96}
97
Peng Fan4cdb3a32022-04-06 14:30:12 +080098void cgc1_pll3_init(ulong freq)
Peng Fan690eea12021-08-07 16:00:45 +080099{
100 /* Gate off VCO */
101 setbits_le32(&cgc1_regs->pll3div_vco, BIT(7));
102
103 /* Disable PLL3 */
104 clrbits_le32(&cgc1_regs->pll3csr, BIT(0));
105
106 /* Gate off PFDxDIV */
107 setbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31));
108 setbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31));
109
110 /* Gate off PFDx */
111 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7));
112 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15));
113 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23));
114 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31));
115
116 /* Select SOSC as source */
117 clrbits_le32(&cgc1_regs->pll3cfg, BIT(0));
118
Peng Fan4cdb3a32022-04-06 14:30:12 +0800119 switch (freq) {
120 case 540672000:
121 writel(0x16 << 16, &cgc1_regs->pll3cfg);
122 writel(0x16e3600, &cgc1_regs->pll3denom);
123 writel(0xc15c00, &cgc1_regs->pll3num);
124 break;
125 default:
126 hang();
127 }
Peng Fan690eea12021-08-07 16:00:45 +0800128
129 /* Enable PLL3 */
130 setbits_le32(&cgc1_regs->pll3csr, BIT(0));
131
132 /* Wait for PLL3 clock ready */
133 while (!(readl(&cgc1_regs->pll3csr) & BIT(24)))
134 ;
135 /* Gate on VCO */
136 clrbits_le32(&cgc1_regs->pll3div_vco, BIT(7));
137
Peng Fan690eea12021-08-07 16:00:45 +0800138 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F);
Peng Fan4cdb3a32022-04-06 14:30:12 +0800139
140 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
141 setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 0);
142 clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21), 3 << 21); /* 195M */
143 } else if (IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
144 setbits_le32(&cgc1_regs->pll3pfdcfg, 21 << 0);
145 clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21), 1 << 21); /* 231M */
146 } else {
147 setbits_le32(&cgc1_regs->pll3pfdcfg, 30 << 0); /* 324M */
148 }
149
Peng Fan690eea12021-08-07 16:00:45 +0800150 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7));
151 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(6)))
152 ;
153
154 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 8);
Peng Fan4cdb3a32022-04-06 14:30:12 +0800155 setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 8);
Peng Fan690eea12021-08-07 16:00:45 +0800156 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15));
157 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(14)))
158 ;
159
160 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 16);
Peng Fan4cdb3a32022-04-06 14:30:12 +0800161 setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 16);
Peng Fan690eea12021-08-07 16:00:45 +0800162 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23));
163 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(22)))
164 ;
165
166 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 24);
167 setbits_le32(&cgc1_regs->pll3pfdcfg, 29 << 24);
168 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31));
169 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(30)))
170 ;
171
172 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7));
173 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(15));
174 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(23));
175 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(31));
176
177 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7));
178 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(15));
179 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(23));
180 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(31));
Peng Fan4cdb3a32022-04-06 14:30:12 +0800181
182 if (!IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) && !IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
183 /* nicclk select pll3 pfd0 */
184 clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(29, 28), BIT(28));
185 while (!(readl(&cgc1_regs->nicclk) & BIT(27)))
186 ;
187 }
Peng Fan690eea12021-08-07 16:00:45 +0800188}
189
Ye Li8c0c8d02022-04-06 14:30:13 +0800190void cgc2_pll4_init(bool pll4_reset)
Peng Fan690eea12021-08-07 16:00:45 +0800191{
Ye Li0471ea12022-04-06 14:30:14 +0800192 /* Check the NICLPAV first to ensure not from PLL4 PFD1 clock */
193 if ((readl(&cgc2_regs->niclpavclk) & GENMASK(29, 28)) == BIT(28)) {
194 /* switch to FRO 192 first */
195 clrbits_le32(&cgc2_regs->niclpavclk, GENMASK(29, 28));
196 while (!(readl(&cgc2_regs->niclpavclk) & BIT(27)))
197 ;
198 }
199
Peng Fan690eea12021-08-07 16:00:45 +0800200 /* Disable PFD DIV and clear DIV */
201 writel(0x80808080, &cgc2_regs->pll4div_pfd0);
202 writel(0x80808080, &cgc2_regs->pll4div_pfd1);
203
204 /* Gate off and clear PFD */
205 writel(0x80808080, &cgc2_regs->pll4pfdcfg);
206
Ye Li8c0c8d02022-04-06 14:30:13 +0800207 if (pll4_reset) {
208 /* Disable PLL4 */
209 writel(0x0, &cgc2_regs->pll4csr);
Peng Fan690eea12021-08-07 16:00:45 +0800210
Ye Li8c0c8d02022-04-06 14:30:13 +0800211 /* Configure PLL4 to 528Mhz and clock source from SOSC */
212 writel(22 << 16, &cgc2_regs->pll4cfg);
213 writel(0x1, &cgc2_regs->pll4csr);
Peng Fan690eea12021-08-07 16:00:45 +0800214
Ye Li8c0c8d02022-04-06 14:30:13 +0800215 /* wait for PLL4 output valid */
216 while (!(readl(&cgc2_regs->pll4csr) & BIT(24)))
217 ;
218 }
Peng Fan690eea12021-08-07 16:00:45 +0800219
220 /* Enable all 4 PFDs */
Peng Fan4cdb3a32022-04-06 14:30:12 +0800221 setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 0); /* 528 */
222 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
223 setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 8);
224 /* 99Mhz for NIC_LPAV */
225 clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21), 3 << 21);
226 } else if (IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
227 setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 8);
228 /* 198Mhz for NIC_LPAV */
229 clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21), 1 << 21);
230 } else {
231 setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 8); /* 316.8Mhz for NIC_LPAV */
232 clrbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21));
233 }
234 setbits_le32(&cgc2_regs->pll4pfdcfg, 12 << 16); /* 792 */
235 setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24); /* 396 */
Peng Fan690eea12021-08-07 16:00:45 +0800236
237 clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) | BIT(15) | BIT(23) | BIT(31));
238
239 while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(30) | BIT(22) | BIT(14) | BIT(6)))
240 != (BIT(30) | BIT(22) | BIT(14) | BIT(6)))
241 ;
242
243 /* Enable PFD DIV */
244 clrbits_le32(&cgc2_regs->pll4div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31));
245 clrbits_le32(&cgc2_regs->pll4div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31));
Peng Fan4cdb3a32022-04-06 14:30:12 +0800246
247 clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(29, 28), BIT(28));
248 while (!(readl(&cgc2_regs->niclpavclk) & BIT(27)))
249 ;
Peng Fan690eea12021-08-07 16:00:45 +0800250}
251
Ye Lida0469d2021-10-29 09:46:18 +0800252void cgc2_pll4_pfd_config(enum cgc_clk pllpfd, u32 pfd)
253{
254 void __iomem *reg = &cgc2_regs->pll4div_pfd0;
255 u32 halt_mask = BIT(7) | BIT(15);
256 u32 pfd_shift = (pllpfd - PLL4_PFD0) * 8;
257 u32 val;
258
259 if (pllpfd < PLL4_PFD0 || pllpfd > PLL4_PFD3)
260 return;
261
262 if ((pllpfd - PLL4_PFD0) >> 1)
263 reg = &cgc2_regs->pll4div_pfd1;
264
265 halt_mask = halt_mask << (((pllpfd - PLL4_PFD0) & 0x1) * 16);
266
267 /* halt pfd div */
268 setbits_le32(reg, halt_mask);
269
270 /* gate pfd */
271 setbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift);
272
273 val = readl(&cgc2_regs->pll4pfdcfg);
274 val &= ~(0x3f << pfd_shift);
275 val |= (pfd << pfd_shift);
276 writel(val, &cgc2_regs->pll4pfdcfg);
277
278 /* ungate */
279 clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift);
280
281 /* Wait stable */
282 while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(6) << pfd_shift))
283 != (BIT(6) << pfd_shift))
284 ;
285
286 /* enable pfd div */
287 clrbits_le32(reg, halt_mask);
288}
289
290void cgc2_pll4_pfddiv_config(enum cgc_clk pllpfddiv, u32 div)
291{
292 void __iomem *reg = &cgc2_regs->pll4div_pfd0;
293 u32 shift = ((pllpfddiv - PLL4_PFD0_DIV1) & 0x3) * 8;
294
295 if (pllpfddiv < PLL4_PFD0_DIV1 || pllpfddiv > PLL4_PFD3_DIV2)
296 return;
297
298 if ((pllpfddiv - PLL4_PFD0_DIV1) >> 2)
299 reg = &cgc2_regs->pll4div_pfd1;
300
301 /* Halt pfd div */
302 setbits_le32(reg, BIT(7) << shift);
303
304 /* Clear div */
305 clrbits_le32(reg, 0x3f << shift);
306
307 /* Set div*/
308 setbits_le32(reg, div << shift);
309
310 /* Enable pfd div */
311 clrbits_le32(reg, BIT(7) << shift);
312}
313
Peng Fan690eea12021-08-07 16:00:45 +0800314void cgc2_ddrclk_config(u32 src, u32 div)
315{
Ye Li88408302021-10-29 09:46:30 +0800316 /* If reg lock is set, wait until unlock by HW */
317 /* This lock is triggered by div updating and ddrclk halt status change, */
318 while ((readl(&cgc2_regs->ddrclk) & BIT(31)))
319 ;
320
Peng Fan690eea12021-08-07 16:00:45 +0800321 writel((src << 28) | (div << 21), &cgc2_regs->ddrclk);
322 /* wait for DDRCLK switching done */
323 while (!(readl(&cgc2_regs->ddrclk) & BIT(27)))
324 ;
325}
326
Ye Li88408302021-10-29 09:46:30 +0800327void cgc2_ddrclk_wait_unlock(void)
328{
329 while ((readl(&cgc2_regs->ddrclk) & BIT(31)))
330 ;
331}
332
Ye Lida0469d2021-10-29 09:46:18 +0800333void cgc2_lpav_init(enum cgc_clk clk)
334{
335 u32 i, scs, reg;
336 const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS};
337
338 reg = readl(&cgc2_regs->niclpavclk);
339 scs = (reg >> 28) & 0x3;
340
341 for (i = 0; i < 4; i++) {
342 if (clk == src[i]) {
343 if (scs == i)
344 return;
345
346 reg &= ~(0x3 << 28);
347 reg |= (i << 28);
348
349 writel(reg, &cgc2_regs->niclpavclk);
350 break;
351 }
352 }
353
354 if (i == 4)
355 printf("Invalid clock source [%u] for LPAV\n", clk);
356}
357
358u32 cgc2_nic_get_rate(enum cgc_clk clk)
359{
360 u32 reg, rate;
361 u32 scs, lpav_axi_clk, lpav_ahb_clk, lpav_bus_clk;
362 const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS};
363
364 reg = readl(&cgc2_regs->niclpavclk);
365 scs = (reg >> 28) & 0x3;
366 lpav_axi_clk = ((reg >> 21) & 0x3f) + 1;
367 lpav_ahb_clk = ((reg >> 14) & 0x3f) + 1;
368 lpav_bus_clk = ((reg >> 7) & 0x3f) + 1;
369
370 rate = cgc_clk_get_rate(src[scs]);
371
372 switch (clk) {
373 case LPAV_AXICLK:
374 rate = rate / lpav_axi_clk;
375 break;
376 case LPAV_AHBCLK:
377 rate = rate / (lpav_axi_clk * lpav_ahb_clk);
378 break;
379 case LPAV_BUSCLK:
380 rate = rate / (lpav_axi_clk * lpav_bus_clk);
381 break;
382 default:
383 return 0;
384 }
385
386 return rate;
387}
388
389u32 decode_pll(enum cgc_clk pll)
Peng Fan690eea12021-08-07 16:00:45 +0800390{
391 u32 reg, infreq, mult;
392 u32 num, denom;
393
394 infreq = 24000000U;
395 /*
396 * Alought there are four choices for the bypass src,
397 * we choose SOSC 24M which is the default set in ROM.
398 * TODO: check more the comments
399 */
400 switch (pll) {
401 case PLL2:
402 reg = readl(&cgc1_regs->pll2csr);
403 if (!(reg & BIT(24)))
404 return 0;
405
406 reg = readl(&cgc1_regs->pll2cfg);
407 mult = (reg >> 16) & 0x7F;
408 denom = readl(&cgc1_regs->pll2denom) & 0x3FFFFFFF;
409 num = readl(&cgc1_regs->pll2num) & 0x3FFFFFFF;
410
411 return (u64)infreq * mult + (u64)infreq * num / denom;
412 case PLL3:
413 reg = readl(&cgc1_regs->pll3csr);
414 if (!(reg & BIT(24)))
415 return 0;
416
417 reg = readl(&cgc1_regs->pll3cfg);
418 mult = (reg >> 16) & 0x7F;
419 denom = readl(&cgc1_regs->pll3denom) & 0x3FFFFFFF;
420 num = readl(&cgc1_regs->pll3num) & 0x3FFFFFFF;
421
422 return (u64)infreq * mult + (u64)infreq * num / denom;
Ye Lida0469d2021-10-29 09:46:18 +0800423 case PLL4:
424 reg = readl(&cgc2_regs->pll4csr);
425 if (!(reg & BIT(24)))
426 return 0;
427
428 reg = readl(&cgc2_regs->pll4cfg);
429 mult = (reg >> 16) & 0x7F;
430 denom = readl(&cgc2_regs->pll4denom) & 0x3FFFFFFF;
431 num = readl(&cgc2_regs->pll4num) & 0x3FFFFFFF;
432
433 return (u64)infreq * mult + (u64)infreq * num / denom;
Peng Fan690eea12021-08-07 16:00:45 +0800434 default:
435 printf("Unsupported pll clocks %d\n", pll);
436 break;
437 }
438
439 return 0;
440}
441
Ye Lida0469d2021-10-29 09:46:18 +0800442u32 cgc_pll_vcodiv_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800443{
444 u32 reg, gate, div;
Ye Lida0469d2021-10-29 09:46:18 +0800445 void __iomem *plldiv_vco;
446 enum cgc_clk pll;
447
448 if (clk == PLL3_VCODIV) {
449 plldiv_vco = &cgc1_regs->pll3div_vco;
450 pll = PLL3;
451 } else {
452 plldiv_vco = &cgc2_regs->pll4div_vco;
453 pll = PLL4;
454 }
Peng Fan690eea12021-08-07 16:00:45 +0800455
Ye Lida0469d2021-10-29 09:46:18 +0800456 reg = readl(plldiv_vco);
Peng Fan690eea12021-08-07 16:00:45 +0800457 gate = BIT(7) & reg;
458 div = reg & 0x3F;
459
Ye Lida0469d2021-10-29 09:46:18 +0800460 return gate ? 0 : decode_pll(pll) / (div + 1);
Peng Fan690eea12021-08-07 16:00:45 +0800461}
462
Ye Lida0469d2021-10-29 09:46:18 +0800463u32 cgc_pll_pfd_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800464{
465 u32 index, gate, vld, reg;
Ye Lida0469d2021-10-29 09:46:18 +0800466 void __iomem *pllpfdcfg;
467 enum cgc_clk pll;
Peng Fan690eea12021-08-07 16:00:45 +0800468
469 switch (clk) {
470 case PLL3_PFD0:
Peng Fan690eea12021-08-07 16:00:45 +0800471 case PLL3_PFD1:
Peng Fan690eea12021-08-07 16:00:45 +0800472 case PLL3_PFD2:
Peng Fan690eea12021-08-07 16:00:45 +0800473 case PLL3_PFD3:
Ye Lida0469d2021-10-29 09:46:18 +0800474 index = clk - PLL3_PFD0;
475 pllpfdcfg = &cgc1_regs->pll3pfdcfg;
476 pll = PLL3;
477 break;
478 case PLL4_PFD0:
479 case PLL4_PFD1:
480 case PLL4_PFD2:
481 case PLL4_PFD3:
482 index = clk - PLL4_PFD0;
483 pllpfdcfg = &cgc2_regs->pll4pfdcfg;
484 pll = PLL4;
Peng Fan690eea12021-08-07 16:00:45 +0800485 break;
486 default:
487 return 0;
488 }
489
Ye Lida0469d2021-10-29 09:46:18 +0800490 reg = readl(pllpfdcfg);
Peng Fan690eea12021-08-07 16:00:45 +0800491 gate = reg & (BIT(7) << (index * 8));
492 vld = reg & (BIT(6) << (index * 8));
493
494 if (gate || !vld)
495 return 0;
496
Ye Lida0469d2021-10-29 09:46:18 +0800497 return (u64)decode_pll(pll) * 18 / ((reg >> (index * 8)) & 0x3F);
Peng Fan690eea12021-08-07 16:00:45 +0800498}
499
Ye Lida0469d2021-10-29 09:46:18 +0800500u32 cgc_pll_pfd_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800501{
502 void __iomem *base;
503 u32 pfd, index, gate, reg;
504
505 switch (clk) {
506 case PLL3_PFD0_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800507 case PLL3_PFD0_DIV2:
508 base = &cgc1_regs->pll3div_pfd0;
509 pfd = PLL3_PFD0;
Ye Lida0469d2021-10-29 09:46:18 +0800510 index = clk - PLL3_PFD0_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800511 break;
512 case PLL3_PFD1_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800513 case PLL3_PFD1_DIV2:
514 base = &cgc1_regs->pll3div_pfd0;
515 pfd = PLL3_PFD1;
Ye Lida0469d2021-10-29 09:46:18 +0800516 index = clk - PLL3_PFD0_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800517 break;
518 case PLL3_PFD2_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800519 case PLL3_PFD2_DIV2:
520 base = &cgc1_regs->pll3div_pfd1;
521 pfd = PLL3_PFD2;
Ye Lida0469d2021-10-29 09:46:18 +0800522 index = clk - PLL3_PFD2_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800523 break;
524 case PLL3_PFD3_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800525 case PLL3_PFD3_DIV2:
526 base = &cgc1_regs->pll3div_pfd1;
527 pfd = PLL3_PFD3;
Ye Lida0469d2021-10-29 09:46:18 +0800528 index = clk - PLL3_PFD2_DIV1;
529 break;
530 case PLL4_PFD0_DIV1:
531 case PLL4_PFD0_DIV2:
532 base = &cgc2_regs->pll4div_pfd0;
533 pfd = PLL4_PFD0;
534 index = clk - PLL4_PFD0_DIV1;
535 break;
536 case PLL4_PFD1_DIV1:
537 case PLL4_PFD1_DIV2:
538 base = &cgc2_regs->pll4div_pfd0;
539 pfd = PLL4_PFD1;
540 index = clk - PLL4_PFD0_DIV1;
541 break;
542 case PLL4_PFD2_DIV1:
543 case PLL4_PFD2_DIV2:
544 base = &cgc2_regs->pll4div_pfd1;
545 pfd = PLL4_PFD2;
546 index = clk - PLL4_PFD2_DIV1;
547 break;
548 case PLL4_PFD3_DIV1:
549 case PLL4_PFD3_DIV2:
550 base = &cgc2_regs->pll4div_pfd1;
551 pfd = PLL4_PFD3;
552 index = clk - PLL4_PFD2_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800553 break;
554 default:
555 return 0;
556 }
557
558 reg = readl(base);
559 gate = reg & (BIT(7) << (index * 8));
560
561 if (gate)
562 return 0;
Ye Lida0469d2021-10-29 09:46:18 +0800563
564 return cgc_pll_pfd_rate(pfd) / (((reg >> (index * 8)) & 0x3F) + 1);
565}
566
567u32 cgc1_nic_get_rate(enum cgc_clk clk)
568{
569 u32 reg, rate;
570 u32 scs, nic_ad_divplat, nic_per_divplat;
571 u32 xbar_ad_divplat, xbar_divbus, ad_slow;
572 const enum cgc_clk src[] = {FRO, PLL3_PFD0, SOSC, LVDS};
573
574 reg = readl(&cgc1_regs->nicclk);
575 scs = (reg >> 28) & 0x3;
576 nic_ad_divplat = ((reg >> 21) & 0x3f) + 1;
577 nic_per_divplat = ((reg >> 14) & 0x3f) + 1;
578
579 reg = readl(&cgc1_regs->xbarclk);
580 xbar_ad_divplat = ((reg >> 14) & 0x3f) + 1;
581 xbar_divbus = ((reg >> 7) & 0x3f) + 1;
582 ad_slow = (reg & 0x3f) + 1;
583
584 rate = cgc_clk_get_rate(src[scs]);
585
586 switch (clk) {
587 case NIC_APCLK:
588 rate = rate / nic_ad_divplat;
589 break;
590 case NIC_PERCLK:
591 rate = rate / (nic_ad_divplat * nic_per_divplat);
592 break;
593 case XBAR_APCLK:
594 rate = rate / (nic_ad_divplat * xbar_ad_divplat);
595 break;
596 case XBAR_BUSCLK:
597 rate = rate / (nic_ad_divplat * xbar_ad_divplat * xbar_divbus);
598 break;
599 case AD_SLOWCLK:
600 rate = rate / (nic_ad_divplat * xbar_ad_divplat * ad_slow);
601 break;
602 default:
603 return 0;
604 }
Peng Fan690eea12021-08-07 16:00:45 +0800605
Ye Lida0469d2021-10-29 09:46:18 +0800606 return rate;
Peng Fan690eea12021-08-07 16:00:45 +0800607}
608
Ye Lida0469d2021-10-29 09:46:18 +0800609u32 cgc1_sosc_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800610{
611 u32 reg, gate, index;
612
613 switch (clk) {
614 case SOSC:
615 return 24000000;
616 case SOSC_DIV1:
617 index = 0;
618 break;
619 case SOSC_DIV2:
620 index = 1;
621 break;
622 case SOSC_DIV3:
623 index = 2;
624 break;
625 default:
626 return 0;
627 }
628
629 reg = readl(&cgc1_regs->soscdiv);
630 gate = reg & (BIT(7) << (index * 8));
631
632 if (gate)
633 return 0;
634
635 return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1);
636}
637
Ye Lida0469d2021-10-29 09:46:18 +0800638u32 cgc1_fro_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800639{
640 u32 reg, gate, vld, index;
641
642 switch (clk) {
643 case FRO:
644 return 192000000;
645 case FRO_DIV1:
646 index = 0;
647 break;
648 case FRO_DIV2:
649 index = 1;
650 break;
651 case FRO_DIV3:
652 index = 2;
653 break;
654 default:
655 return 0;
656 }
657
658 reg = readl(&cgc1_regs->frodiv);
659 gate = reg & (BIT(7) << (index * 8));
660 vld = reg & (BIT(6) << (index * 8));
661
662 if (gate || !vld)
663 return 0;
664
665 return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1);
666}
667
Ye Lida0469d2021-10-29 09:46:18 +0800668u32 cgc_clk_get_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800669{
670 switch (clk) {
Ye Lida0469d2021-10-29 09:46:18 +0800671 case LVDS:
672 return 0; /* No external LVDS clock used */
Peng Fan690eea12021-08-07 16:00:45 +0800673 case SOSC:
674 case SOSC_DIV1:
675 case SOSC_DIV2:
676 case SOSC_DIV3:
677 return cgc1_sosc_div(clk);
678 case FRO:
679 case FRO_DIV1:
680 case FRO_DIV2:
681 case FRO_DIV3:
682 return cgc1_fro_div(clk);
683 case PLL2:
Peng Fan690eea12021-08-07 16:00:45 +0800684 case PLL3:
Ye Lida0469d2021-10-29 09:46:18 +0800685 case PLL4:
686 return decode_pll(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800687 case PLL3_VCODIV:
Ye Lida0469d2021-10-29 09:46:18 +0800688 case PLL4_VCODIV:
689 return cgc_pll_vcodiv_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800690 case PLL3_PFD0:
691 case PLL3_PFD1:
692 case PLL3_PFD2:
693 case PLL3_PFD3:
Ye Lida0469d2021-10-29 09:46:18 +0800694 case PLL4_PFD0:
695 case PLL4_PFD1:
696 case PLL4_PFD2:
697 case PLL4_PFD3:
698 return cgc_pll_pfd_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800699 case PLL3_PFD0_DIV1:
700 case PLL3_PFD0_DIV2:
701 case PLL3_PFD1_DIV1:
702 case PLL3_PFD1_DIV2:
703 case PLL3_PFD2_DIV1:
704 case PLL3_PFD2_DIV2:
705 case PLL3_PFD3_DIV1:
706 case PLL3_PFD3_DIV2:
Ye Lida0469d2021-10-29 09:46:18 +0800707 case PLL4_PFD0_DIV1:
708 case PLL4_PFD0_DIV2:
709 case PLL4_PFD1_DIV1:
710 case PLL4_PFD1_DIV2:
711 case PLL4_PFD2_DIV1:
712 case PLL4_PFD2_DIV2:
713 case PLL4_PFD3_DIV1:
714 case PLL4_PFD3_DIV2:
715 return cgc_pll_pfd_div(clk);
716 case NIC_APCLK:
717 case NIC_PERCLK:
718 case XBAR_APCLK:
719 case XBAR_BUSCLK:
720 case AD_SLOWCLK:
721 return cgc1_nic_get_rate(clk);
722 case LPAV_AXICLK:
723 case LPAV_AHBCLK:
724 case LPAV_BUSCLK:
725 return cgc2_nic_get_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800726 default:
Ye Lida0469d2021-10-29 09:46:18 +0800727 printf("Unsupported cgc clock: %d\n", clk);
Peng Fan690eea12021-08-07 16:00:45 +0800728 return 0;
729 }
730}