blob: f9d8ed5b048b616cac1b1398f906444beed09ae2 [file] [log] [blame]
Peng Fan690eea12021-08-07 16:00:45 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2021 NXP
4 */
5
Peng Fan690eea12021-08-07 16:00:45 +08006#include <div64.h>
7#include <asm/io.h>
8#include <errno.h>
9#include <asm/arch/imx-regs.h>
10#include <asm/arch/cgc.h>
Peng Fan4cdb3a32022-04-06 14:30:12 +080011#include <asm/arch/clock.h>
Peng Fan690eea12021-08-07 16:00:45 +080012#include <asm/arch/sys_proto.h>
13#include <asm/global_data.h>
14#include <linux/delay.h>
Peng Fan4cdb3a32022-04-06 14:30:12 +080015#include <hang.h>
Peng Fan690eea12021-08-07 16:00:45 +080016
17DECLARE_GLOBAL_DATA_PTR;
18
19static struct cgc1_regs *cgc1_regs = (struct cgc1_regs *)0x292C0000UL;
20static struct cgc2_regs *cgc2_regs = (struct cgc2_regs *)0x2da60000UL;
21
22void cgc1_soscdiv_init(void)
23{
24 /* Configure SOSC/FRO DIV1 ~ DIV3 */
25 clrbits_le32(&cgc1_regs->soscdiv, BIT(7));
26 clrbits_le32(&cgc1_regs->soscdiv, BIT(15));
27 clrbits_le32(&cgc1_regs->soscdiv, BIT(23));
28 clrbits_le32(&cgc1_regs->soscdiv, BIT(31));
29
30 clrbits_le32(&cgc1_regs->frodiv, BIT(7));
31}
32
Peng Fan4cdb3a32022-04-06 14:30:12 +080033void cgc1_pll2_init(ulong freq)
Peng Fan690eea12021-08-07 16:00:45 +080034{
35 u32 reg;
36
37 if (readl(&cgc1_regs->pll2csr) & BIT(23))
38 clrbits_le32(&cgc1_regs->pll2csr, BIT(23));
39
40 /* Disable PLL2 */
41 clrbits_le32(&cgc1_regs->pll2csr, BIT(0));
42 mdelay(1);
43
44 /* wait valid bit false */
45 while ((readl(&cgc1_regs->pll2csr) & BIT(24)))
46 ;
47
Peng Fan4cdb3a32022-04-06 14:30:12 +080048 /* Select SOSC as source */
49 reg = (freq / MHZ(24)) << 16;
Peng Fan690eea12021-08-07 16:00:45 +080050 writel(reg, &cgc1_regs->pll2cfg);
51
52 /* Enable PLL2 */
53 setbits_le32(&cgc1_regs->pll2csr, BIT(0));
54
55 /* Wait for PLL2 clock ready */
56 while (!(readl(&cgc1_regs->pll2csr) & BIT(24)))
57 ;
58}
59
60static void cgc1_set_a35_clk(u32 clk_src, u32 div_core)
61{
62 u32 reg;
63
64 /* ulock */
65 if (readl(&cgc1_regs->ca35clk) & BIT(31))
66 clrbits_le32(&cgc1_regs->ca35clk, BIT(31));
67
68 reg = readl(&cgc1_regs->ca35clk);
69 reg &= ~GENMASK(29, 21);
70 reg |= ((clk_src & 0x3) << 28);
71 reg |= (((div_core - 1) & 0x3f) << 21);
72 writel(reg, &cgc1_regs->ca35clk);
73
74 while (!(readl(&cgc1_regs->ca35clk) & BIT(27)))
75 ;
76}
77
Peng Fan4cdb3a32022-04-06 14:30:12 +080078void cgc1_init_core_clk(ulong freq)
Peng Fan690eea12021-08-07 16:00:45 +080079{
80 u32 reg = readl(&cgc1_regs->ca35clk);
81
82 /* if already selected to PLL2, switch to FRO firstly */
83 if (((reg >> 28) & 0x3) == 0x1)
84 cgc1_set_a35_clk(0, 1);
85
Peng Fan4cdb3a32022-04-06 14:30:12 +080086 cgc1_pll2_init(freq);
Peng Fan690eea12021-08-07 16:00:45 +080087
88 /* Set A35 clock to pll2 */
89 cgc1_set_a35_clk(1, 1);
90}
91
92void cgc1_enet_stamp_sel(u32 clk_src)
93{
94 writel((clk_src & 0x7) << 24, &cgc1_regs->enetstamp);
95}
96
Peng Fan4cdb3a32022-04-06 14:30:12 +080097void cgc1_pll3_init(ulong freq)
Peng Fan690eea12021-08-07 16:00:45 +080098{
99 /* Gate off VCO */
100 setbits_le32(&cgc1_regs->pll3div_vco, BIT(7));
101
102 /* Disable PLL3 */
103 clrbits_le32(&cgc1_regs->pll3csr, BIT(0));
104
105 /* Gate off PFDxDIV */
106 setbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31));
107 setbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31));
108
109 /* Gate off PFDx */
110 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7));
111 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15));
112 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23));
113 setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31));
114
115 /* Select SOSC as source */
116 clrbits_le32(&cgc1_regs->pll3cfg, BIT(0));
117
Peng Fan4cdb3a32022-04-06 14:30:12 +0800118 switch (freq) {
119 case 540672000:
120 writel(0x16 << 16, &cgc1_regs->pll3cfg);
121 writel(0x16e3600, &cgc1_regs->pll3denom);
122 writel(0xc15c00, &cgc1_regs->pll3num);
123 break;
124 default:
125 hang();
126 }
Peng Fan690eea12021-08-07 16:00:45 +0800127
128 /* Enable PLL3 */
129 setbits_le32(&cgc1_regs->pll3csr, BIT(0));
130
131 /* Wait for PLL3 clock ready */
132 while (!(readl(&cgc1_regs->pll3csr) & BIT(24)))
133 ;
134 /* Gate on VCO */
135 clrbits_le32(&cgc1_regs->pll3div_vco, BIT(7));
136
Peng Fan690eea12021-08-07 16:00:45 +0800137 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F);
Ye Lie9e068f2023-01-31 16:42:25 +0800138 setbits_le32(&cgc1_regs->pll3pfdcfg, 30 << 0); /* PFD0 324M */
Peng Fan690eea12021-08-07 16:00:45 +0800139 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7));
140 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(6)))
141 ;
142
143 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 8);
Ye Lie9e068f2023-01-31 16:42:25 +0800144 setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 8); /* PFD1 389M */
Peng Fan690eea12021-08-07 16:00:45 +0800145 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15));
146 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(14)))
147 ;
148
149 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 16);
Ye Lie9e068f2023-01-31 16:42:25 +0800150 setbits_le32(&cgc1_regs->pll3pfdcfg, 30 << 16); /* PFD2 324M */
Peng Fan690eea12021-08-07 16:00:45 +0800151 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23));
152 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(22)))
153 ;
154
155 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 24);
Ye Lie9e068f2023-01-31 16:42:25 +0800156 setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 24); /* PFD3 389M */
Peng Fan690eea12021-08-07 16:00:45 +0800157 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31));
158 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(30)))
159 ;
160
Ye Lid459ca72023-01-31 16:42:21 +0800161 clrbits_le32(&cgc1_regs->pll3div_pfd0, 0x3f3f3f3f);
Ye Lie9e068f2023-01-31 16:42:25 +0800162 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) || IS_ENABLED(CONFIG_IMX8ULP_ND_MODE))
163 clrsetbits_le32(&cgc1_regs->pll3div_pfd1, 0x3f3f3f3f, 0x03010000); /* Set PFD3 DIV1 to 194M, PFD3 DIV2 to 97M */
164 else
165 clrsetbits_le32(&cgc1_regs->pll3div_pfd1, 0x3f3f3f3f, 0x01000000); /* Set PFD3 DIV1 to 389M, PFD3 DIV2 to 194M */
Peng Fan690eea12021-08-07 16:00:45 +0800166 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7));
167 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(15));
168 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(23));
169 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(31));
170
171 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7));
172 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(15));
173 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(23));
174 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(31));
Peng Fan4cdb3a32022-04-06 14:30:12 +0800175
Ye Lie9e068f2023-01-31 16:42:25 +0800176 /* NIC_AP:
177 * OD source PLL3 PFD0, 324M
178 * ND source FRO192, 192M
179 * LD source FRO192, 96M
180 */
181 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
182 clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21), 1 << 21);
183 } else {
184 clrbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21));
185 }
186
Peng Fan4cdb3a32022-04-06 14:30:12 +0800187 if (!IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) && !IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
188 /* nicclk select pll3 pfd0 */
189 clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(29, 28), BIT(28));
190 while (!(readl(&cgc1_regs->nicclk) & BIT(27)))
191 ;
192 }
Peng Fan690eea12021-08-07 16:00:45 +0800193}
194
Ye Li8c0c8d02022-04-06 14:30:13 +0800195void cgc2_pll4_init(bool pll4_reset)
Peng Fan690eea12021-08-07 16:00:45 +0800196{
Ye Li0471ea12022-04-06 14:30:14 +0800197 /* Check the NICLPAV first to ensure not from PLL4 PFD1 clock */
198 if ((readl(&cgc2_regs->niclpavclk) & GENMASK(29, 28)) == BIT(28)) {
199 /* switch to FRO 192 first */
200 clrbits_le32(&cgc2_regs->niclpavclk, GENMASK(29, 28));
201 while (!(readl(&cgc2_regs->niclpavclk) & BIT(27)))
202 ;
203 }
204
Peng Fan690eea12021-08-07 16:00:45 +0800205 /* Disable PFD DIV and clear DIV */
206 writel(0x80808080, &cgc2_regs->pll4div_pfd0);
207 writel(0x80808080, &cgc2_regs->pll4div_pfd1);
208
209 /* Gate off and clear PFD */
210 writel(0x80808080, &cgc2_regs->pll4pfdcfg);
211
Ye Li8c0c8d02022-04-06 14:30:13 +0800212 if (pll4_reset) {
213 /* Disable PLL4 */
214 writel(0x0, &cgc2_regs->pll4csr);
Peng Fan690eea12021-08-07 16:00:45 +0800215
Ye Li8c0c8d02022-04-06 14:30:13 +0800216 /* Configure PLL4 to 528Mhz and clock source from SOSC */
217 writel(22 << 16, &cgc2_regs->pll4cfg);
218 writel(0x1, &cgc2_regs->pll4csr);
Peng Fan690eea12021-08-07 16:00:45 +0800219
Ye Li8c0c8d02022-04-06 14:30:13 +0800220 /* wait for PLL4 output valid */
221 while (!(readl(&cgc2_regs->pll4csr) & BIT(24)))
222 ;
223 }
Peng Fan690eea12021-08-07 16:00:45 +0800224
225 /* Enable all 4 PFDs */
Peng Fan4cdb3a32022-04-06 14:30:12 +0800226 setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 0); /* 528 */
Ye Lie9e068f2023-01-31 16:42:25 +0800227 setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 8); /* 316.8Mhz for NIC_LPAV */
228 setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 16); /* 316.8Mhz */
229 setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24); /* 396Mhz */
Peng Fan690eea12021-08-07 16:00:45 +0800230
231 clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) | BIT(15) | BIT(23) | BIT(31));
232
233 while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(30) | BIT(22) | BIT(14) | BIT(6)))
234 != (BIT(30) | BIT(22) | BIT(14) | BIT(6)))
235 ;
236
237 /* Enable PFD DIV */
238 clrbits_le32(&cgc2_regs->pll4div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31));
239 clrbits_le32(&cgc2_regs->pll4div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31));
Peng Fan4cdb3a32022-04-06 14:30:12 +0800240
Ye Lie9e068f2023-01-31 16:42:25 +0800241 /* NIC_LPAV:
242 * OD source PLL4 PFD1, 316.8M
243 * ND source FRO192, 192M
244 * LD source FRO192, 96M
245 */
246 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
247 clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21), 1 << 21);
248 } else {
249 clrbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21));
250 }
251
252 if (!IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) && !IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
253 clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(29, 28), BIT(28));
254 while (!(readl(&cgc2_regs->niclpavclk) & BIT(27)))
255 ;
256 }
Peng Fan690eea12021-08-07 16:00:45 +0800257}
258
Ye Lida0469d2021-10-29 09:46:18 +0800259void cgc2_pll4_pfd_config(enum cgc_clk pllpfd, u32 pfd)
260{
261 void __iomem *reg = &cgc2_regs->pll4div_pfd0;
262 u32 halt_mask = BIT(7) | BIT(15);
263 u32 pfd_shift = (pllpfd - PLL4_PFD0) * 8;
264 u32 val;
265
266 if (pllpfd < PLL4_PFD0 || pllpfd > PLL4_PFD3)
267 return;
268
269 if ((pllpfd - PLL4_PFD0) >> 1)
270 reg = &cgc2_regs->pll4div_pfd1;
271
272 halt_mask = halt_mask << (((pllpfd - PLL4_PFD0) & 0x1) * 16);
273
274 /* halt pfd div */
275 setbits_le32(reg, halt_mask);
276
277 /* gate pfd */
278 setbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift);
279
280 val = readl(&cgc2_regs->pll4pfdcfg);
281 val &= ~(0x3f << pfd_shift);
282 val |= (pfd << pfd_shift);
283 writel(val, &cgc2_regs->pll4pfdcfg);
284
285 /* ungate */
286 clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift);
287
288 /* Wait stable */
289 while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(6) << pfd_shift))
290 != (BIT(6) << pfd_shift))
291 ;
292
293 /* enable pfd div */
294 clrbits_le32(reg, halt_mask);
295}
296
297void cgc2_pll4_pfddiv_config(enum cgc_clk pllpfddiv, u32 div)
298{
299 void __iomem *reg = &cgc2_regs->pll4div_pfd0;
300 u32 shift = ((pllpfddiv - PLL4_PFD0_DIV1) & 0x3) * 8;
301
302 if (pllpfddiv < PLL4_PFD0_DIV1 || pllpfddiv > PLL4_PFD3_DIV2)
303 return;
304
305 if ((pllpfddiv - PLL4_PFD0_DIV1) >> 2)
306 reg = &cgc2_regs->pll4div_pfd1;
307
308 /* Halt pfd div */
309 setbits_le32(reg, BIT(7) << shift);
310
311 /* Clear div */
312 clrbits_le32(reg, 0x3f << shift);
313
314 /* Set div*/
315 setbits_le32(reg, div << shift);
316
317 /* Enable pfd div */
318 clrbits_le32(reg, BIT(7) << shift);
319}
320
Peng Fan690eea12021-08-07 16:00:45 +0800321void cgc2_ddrclk_config(u32 src, u32 div)
322{
Ye Li88408302021-10-29 09:46:30 +0800323 /* If reg lock is set, wait until unlock by HW */
324 /* This lock is triggered by div updating and ddrclk halt status change, */
325 while ((readl(&cgc2_regs->ddrclk) & BIT(31)))
326 ;
327
Peng Fan690eea12021-08-07 16:00:45 +0800328 writel((src << 28) | (div << 21), &cgc2_regs->ddrclk);
329 /* wait for DDRCLK switching done */
330 while (!(readl(&cgc2_regs->ddrclk) & BIT(27)))
331 ;
332}
333
Ye Li88408302021-10-29 09:46:30 +0800334void cgc2_ddrclk_wait_unlock(void)
335{
336 while ((readl(&cgc2_regs->ddrclk) & BIT(31)))
337 ;
338}
339
Ye Lida0469d2021-10-29 09:46:18 +0800340void cgc2_lpav_init(enum cgc_clk clk)
341{
342 u32 i, scs, reg;
343 const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS};
344
345 reg = readl(&cgc2_regs->niclpavclk);
346 scs = (reg >> 28) & 0x3;
347
348 for (i = 0; i < 4; i++) {
349 if (clk == src[i]) {
350 if (scs == i)
351 return;
352
353 reg &= ~(0x3 << 28);
354 reg |= (i << 28);
355
356 writel(reg, &cgc2_regs->niclpavclk);
357 break;
358 }
359 }
360
361 if (i == 4)
362 printf("Invalid clock source [%u] for LPAV\n", clk);
363}
364
365u32 cgc2_nic_get_rate(enum cgc_clk clk)
366{
367 u32 reg, rate;
368 u32 scs, lpav_axi_clk, lpav_ahb_clk, lpav_bus_clk;
369 const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS};
370
371 reg = readl(&cgc2_regs->niclpavclk);
372 scs = (reg >> 28) & 0x3;
373 lpav_axi_clk = ((reg >> 21) & 0x3f) + 1;
374 lpav_ahb_clk = ((reg >> 14) & 0x3f) + 1;
375 lpav_bus_clk = ((reg >> 7) & 0x3f) + 1;
376
377 rate = cgc_clk_get_rate(src[scs]);
378
379 switch (clk) {
380 case LPAV_AXICLK:
381 rate = rate / lpav_axi_clk;
382 break;
383 case LPAV_AHBCLK:
384 rate = rate / (lpav_axi_clk * lpav_ahb_clk);
385 break;
386 case LPAV_BUSCLK:
387 rate = rate / (lpav_axi_clk * lpav_bus_clk);
388 break;
389 default:
390 return 0;
391 }
392
393 return rate;
394}
395
396u32 decode_pll(enum cgc_clk pll)
Peng Fan690eea12021-08-07 16:00:45 +0800397{
398 u32 reg, infreq, mult;
399 u32 num, denom;
400
401 infreq = 24000000U;
402 /*
403 * Alought there are four choices for the bypass src,
404 * we choose SOSC 24M which is the default set in ROM.
405 * TODO: check more the comments
406 */
407 switch (pll) {
408 case PLL2:
409 reg = readl(&cgc1_regs->pll2csr);
410 if (!(reg & BIT(24)))
411 return 0;
412
413 reg = readl(&cgc1_regs->pll2cfg);
414 mult = (reg >> 16) & 0x7F;
415 denom = readl(&cgc1_regs->pll2denom) & 0x3FFFFFFF;
416 num = readl(&cgc1_regs->pll2num) & 0x3FFFFFFF;
417
418 return (u64)infreq * mult + (u64)infreq * num / denom;
419 case PLL3:
420 reg = readl(&cgc1_regs->pll3csr);
421 if (!(reg & BIT(24)))
422 return 0;
423
424 reg = readl(&cgc1_regs->pll3cfg);
425 mult = (reg >> 16) & 0x7F;
426 denom = readl(&cgc1_regs->pll3denom) & 0x3FFFFFFF;
427 num = readl(&cgc1_regs->pll3num) & 0x3FFFFFFF;
428
429 return (u64)infreq * mult + (u64)infreq * num / denom;
Ye Lida0469d2021-10-29 09:46:18 +0800430 case PLL4:
431 reg = readl(&cgc2_regs->pll4csr);
432 if (!(reg & BIT(24)))
433 return 0;
434
435 reg = readl(&cgc2_regs->pll4cfg);
436 mult = (reg >> 16) & 0x7F;
437 denom = readl(&cgc2_regs->pll4denom) & 0x3FFFFFFF;
438 num = readl(&cgc2_regs->pll4num) & 0x3FFFFFFF;
439
440 return (u64)infreq * mult + (u64)infreq * num / denom;
Peng Fan690eea12021-08-07 16:00:45 +0800441 default:
442 printf("Unsupported pll clocks %d\n", pll);
443 break;
444 }
445
446 return 0;
447}
448
Ye Lida0469d2021-10-29 09:46:18 +0800449u32 cgc_pll_vcodiv_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800450{
451 u32 reg, gate, div;
Ye Lida0469d2021-10-29 09:46:18 +0800452 void __iomem *plldiv_vco;
453 enum cgc_clk pll;
454
455 if (clk == PLL3_VCODIV) {
456 plldiv_vco = &cgc1_regs->pll3div_vco;
457 pll = PLL3;
458 } else {
459 plldiv_vco = &cgc2_regs->pll4div_vco;
460 pll = PLL4;
461 }
Peng Fan690eea12021-08-07 16:00:45 +0800462
Ye Lida0469d2021-10-29 09:46:18 +0800463 reg = readl(plldiv_vco);
Peng Fan690eea12021-08-07 16:00:45 +0800464 gate = BIT(7) & reg;
465 div = reg & 0x3F;
466
Ye Lida0469d2021-10-29 09:46:18 +0800467 return gate ? 0 : decode_pll(pll) / (div + 1);
Peng Fan690eea12021-08-07 16:00:45 +0800468}
469
Ye Lida0469d2021-10-29 09:46:18 +0800470u32 cgc_pll_pfd_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800471{
472 u32 index, gate, vld, reg;
Ye Lida0469d2021-10-29 09:46:18 +0800473 void __iomem *pllpfdcfg;
474 enum cgc_clk pll;
Peng Fan690eea12021-08-07 16:00:45 +0800475
476 switch (clk) {
477 case PLL3_PFD0:
Peng Fan690eea12021-08-07 16:00:45 +0800478 case PLL3_PFD1:
Peng Fan690eea12021-08-07 16:00:45 +0800479 case PLL3_PFD2:
Peng Fan690eea12021-08-07 16:00:45 +0800480 case PLL3_PFD3:
Ye Lida0469d2021-10-29 09:46:18 +0800481 index = clk - PLL3_PFD0;
482 pllpfdcfg = &cgc1_regs->pll3pfdcfg;
483 pll = PLL3;
484 break;
485 case PLL4_PFD0:
486 case PLL4_PFD1:
487 case PLL4_PFD2:
488 case PLL4_PFD3:
489 index = clk - PLL4_PFD0;
490 pllpfdcfg = &cgc2_regs->pll4pfdcfg;
491 pll = PLL4;
Peng Fan690eea12021-08-07 16:00:45 +0800492 break;
493 default:
494 return 0;
495 }
496
Ye Lida0469d2021-10-29 09:46:18 +0800497 reg = readl(pllpfdcfg);
Peng Fan690eea12021-08-07 16:00:45 +0800498 gate = reg & (BIT(7) << (index * 8));
499 vld = reg & (BIT(6) << (index * 8));
500
501 if (gate || !vld)
502 return 0;
503
Ye Lida0469d2021-10-29 09:46:18 +0800504 return (u64)decode_pll(pll) * 18 / ((reg >> (index * 8)) & 0x3F);
Peng Fan690eea12021-08-07 16:00:45 +0800505}
506
Ye Lida0469d2021-10-29 09:46:18 +0800507u32 cgc_pll_pfd_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800508{
509 void __iomem *base;
510 u32 pfd, index, gate, reg;
511
512 switch (clk) {
513 case PLL3_PFD0_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800514 case PLL3_PFD0_DIV2:
515 base = &cgc1_regs->pll3div_pfd0;
516 pfd = PLL3_PFD0;
Ye Lida0469d2021-10-29 09:46:18 +0800517 index = clk - PLL3_PFD0_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800518 break;
519 case PLL3_PFD1_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800520 case PLL3_PFD1_DIV2:
521 base = &cgc1_regs->pll3div_pfd0;
522 pfd = PLL3_PFD1;
Ye Lida0469d2021-10-29 09:46:18 +0800523 index = clk - PLL3_PFD0_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800524 break;
525 case PLL3_PFD2_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800526 case PLL3_PFD2_DIV2:
527 base = &cgc1_regs->pll3div_pfd1;
528 pfd = PLL3_PFD2;
Ye Lida0469d2021-10-29 09:46:18 +0800529 index = clk - PLL3_PFD2_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800530 break;
531 case PLL3_PFD3_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800532 case PLL3_PFD3_DIV2:
533 base = &cgc1_regs->pll3div_pfd1;
534 pfd = PLL3_PFD3;
Ye Lida0469d2021-10-29 09:46:18 +0800535 index = clk - PLL3_PFD2_DIV1;
536 break;
537 case PLL4_PFD0_DIV1:
538 case PLL4_PFD0_DIV2:
539 base = &cgc2_regs->pll4div_pfd0;
540 pfd = PLL4_PFD0;
541 index = clk - PLL4_PFD0_DIV1;
542 break;
543 case PLL4_PFD1_DIV1:
544 case PLL4_PFD1_DIV2:
545 base = &cgc2_regs->pll4div_pfd0;
546 pfd = PLL4_PFD1;
547 index = clk - PLL4_PFD0_DIV1;
548 break;
549 case PLL4_PFD2_DIV1:
550 case PLL4_PFD2_DIV2:
551 base = &cgc2_regs->pll4div_pfd1;
552 pfd = PLL4_PFD2;
553 index = clk - PLL4_PFD2_DIV1;
554 break;
555 case PLL4_PFD3_DIV1:
556 case PLL4_PFD3_DIV2:
557 base = &cgc2_regs->pll4div_pfd1;
558 pfd = PLL4_PFD3;
559 index = clk - PLL4_PFD2_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800560 break;
561 default:
562 return 0;
563 }
564
565 reg = readl(base);
566 gate = reg & (BIT(7) << (index * 8));
567
568 if (gate)
569 return 0;
Ye Lida0469d2021-10-29 09:46:18 +0800570
571 return cgc_pll_pfd_rate(pfd) / (((reg >> (index * 8)) & 0x3F) + 1);
572}
573
574u32 cgc1_nic_get_rate(enum cgc_clk clk)
575{
576 u32 reg, rate;
577 u32 scs, nic_ad_divplat, nic_per_divplat;
578 u32 xbar_ad_divplat, xbar_divbus, ad_slow;
579 const enum cgc_clk src[] = {FRO, PLL3_PFD0, SOSC, LVDS};
580
581 reg = readl(&cgc1_regs->nicclk);
582 scs = (reg >> 28) & 0x3;
583 nic_ad_divplat = ((reg >> 21) & 0x3f) + 1;
584 nic_per_divplat = ((reg >> 14) & 0x3f) + 1;
585
586 reg = readl(&cgc1_regs->xbarclk);
587 xbar_ad_divplat = ((reg >> 14) & 0x3f) + 1;
588 xbar_divbus = ((reg >> 7) & 0x3f) + 1;
589 ad_slow = (reg & 0x3f) + 1;
590
591 rate = cgc_clk_get_rate(src[scs]);
592
593 switch (clk) {
594 case NIC_APCLK:
595 rate = rate / nic_ad_divplat;
596 break;
597 case NIC_PERCLK:
598 rate = rate / (nic_ad_divplat * nic_per_divplat);
599 break;
600 case XBAR_APCLK:
601 rate = rate / (nic_ad_divplat * xbar_ad_divplat);
602 break;
603 case XBAR_BUSCLK:
604 rate = rate / (nic_ad_divplat * xbar_ad_divplat * xbar_divbus);
605 break;
606 case AD_SLOWCLK:
607 rate = rate / (nic_ad_divplat * xbar_ad_divplat * ad_slow);
608 break;
609 default:
610 return 0;
611 }
Peng Fan690eea12021-08-07 16:00:45 +0800612
Ye Lida0469d2021-10-29 09:46:18 +0800613 return rate;
Peng Fan690eea12021-08-07 16:00:45 +0800614}
615
Ye Lida0469d2021-10-29 09:46:18 +0800616u32 cgc1_sosc_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800617{
618 u32 reg, gate, index;
619
620 switch (clk) {
621 case SOSC:
622 return 24000000;
623 case SOSC_DIV1:
624 index = 0;
625 break;
626 case SOSC_DIV2:
627 index = 1;
628 break;
629 case SOSC_DIV3:
630 index = 2;
631 break;
632 default:
633 return 0;
634 }
635
636 reg = readl(&cgc1_regs->soscdiv);
637 gate = reg & (BIT(7) << (index * 8));
638
639 if (gate)
640 return 0;
641
642 return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1);
643}
644
Ye Lida0469d2021-10-29 09:46:18 +0800645u32 cgc1_fro_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800646{
647 u32 reg, gate, vld, index;
648
649 switch (clk) {
650 case FRO:
651 return 192000000;
652 case FRO_DIV1:
653 index = 0;
654 break;
655 case FRO_DIV2:
656 index = 1;
657 break;
658 case FRO_DIV3:
659 index = 2;
660 break;
661 default:
662 return 0;
663 }
664
665 reg = readl(&cgc1_regs->frodiv);
666 gate = reg & (BIT(7) << (index * 8));
667 vld = reg & (BIT(6) << (index * 8));
668
669 if (gate || !vld)
670 return 0;
671
672 return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1);
673}
674
Ye Lida0469d2021-10-29 09:46:18 +0800675u32 cgc_clk_get_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800676{
677 switch (clk) {
Ye Lida0469d2021-10-29 09:46:18 +0800678 case LVDS:
679 return 0; /* No external LVDS clock used */
Peng Fan690eea12021-08-07 16:00:45 +0800680 case SOSC:
681 case SOSC_DIV1:
682 case SOSC_DIV2:
683 case SOSC_DIV3:
684 return cgc1_sosc_div(clk);
685 case FRO:
686 case FRO_DIV1:
687 case FRO_DIV2:
688 case FRO_DIV3:
689 return cgc1_fro_div(clk);
690 case PLL2:
Peng Fan690eea12021-08-07 16:00:45 +0800691 case PLL3:
Ye Lida0469d2021-10-29 09:46:18 +0800692 case PLL4:
693 return decode_pll(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800694 case PLL3_VCODIV:
Ye Lida0469d2021-10-29 09:46:18 +0800695 case PLL4_VCODIV:
696 return cgc_pll_vcodiv_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800697 case PLL3_PFD0:
698 case PLL3_PFD1:
699 case PLL3_PFD2:
700 case PLL3_PFD3:
Ye Lida0469d2021-10-29 09:46:18 +0800701 case PLL4_PFD0:
702 case PLL4_PFD1:
703 case PLL4_PFD2:
704 case PLL4_PFD3:
705 return cgc_pll_pfd_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800706 case PLL3_PFD0_DIV1:
707 case PLL3_PFD0_DIV2:
708 case PLL3_PFD1_DIV1:
709 case PLL3_PFD1_DIV2:
710 case PLL3_PFD2_DIV1:
711 case PLL3_PFD2_DIV2:
712 case PLL3_PFD3_DIV1:
713 case PLL3_PFD3_DIV2:
Ye Lida0469d2021-10-29 09:46:18 +0800714 case PLL4_PFD0_DIV1:
715 case PLL4_PFD0_DIV2:
716 case PLL4_PFD1_DIV1:
717 case PLL4_PFD1_DIV2:
718 case PLL4_PFD2_DIV1:
719 case PLL4_PFD2_DIV2:
720 case PLL4_PFD3_DIV1:
721 case PLL4_PFD3_DIV2:
722 return cgc_pll_pfd_div(clk);
723 case NIC_APCLK:
724 case NIC_PERCLK:
725 case XBAR_APCLK:
726 case XBAR_BUSCLK:
727 case AD_SLOWCLK:
728 return cgc1_nic_get_rate(clk);
729 case LPAV_AXICLK:
730 case LPAV_AHBCLK:
731 case LPAV_BUSCLK:
732 return cgc2_nic_get_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800733 default:
Ye Lida0469d2021-10-29 09:46:18 +0800734 printf("Unsupported cgc clock: %d\n", clk);
Peng Fan690eea12021-08-07 16:00:45 +0800735 return 0;
736 }
737}