blob: d2fadb4877c95466c9580ec33845f9c4762bcf88 [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);
Ye Lie9e068f2023-01-31 16:42:25 +0800139 setbits_le32(&cgc1_regs->pll3pfdcfg, 30 << 0); /* PFD0 324M */
Peng Fan690eea12021-08-07 16:00:45 +0800140 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7));
141 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(6)))
142 ;
143
144 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 8);
Ye Lie9e068f2023-01-31 16:42:25 +0800145 setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 8); /* PFD1 389M */
Peng Fan690eea12021-08-07 16:00:45 +0800146 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15));
147 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(14)))
148 ;
149
150 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 16);
Ye Lie9e068f2023-01-31 16:42:25 +0800151 setbits_le32(&cgc1_regs->pll3pfdcfg, 30 << 16); /* PFD2 324M */
Peng Fan690eea12021-08-07 16:00:45 +0800152 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23));
153 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(22)))
154 ;
155
156 clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 24);
Ye Lie9e068f2023-01-31 16:42:25 +0800157 setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 24); /* PFD3 389M */
Peng Fan690eea12021-08-07 16:00:45 +0800158 clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31));
159 while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(30)))
160 ;
161
Ye Lid459ca72023-01-31 16:42:21 +0800162 clrbits_le32(&cgc1_regs->pll3div_pfd0, 0x3f3f3f3f);
Ye Lie9e068f2023-01-31 16:42:25 +0800163 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) || IS_ENABLED(CONFIG_IMX8ULP_ND_MODE))
164 clrsetbits_le32(&cgc1_regs->pll3div_pfd1, 0x3f3f3f3f, 0x03010000); /* Set PFD3 DIV1 to 194M, PFD3 DIV2 to 97M */
165 else
166 clrsetbits_le32(&cgc1_regs->pll3div_pfd1, 0x3f3f3f3f, 0x01000000); /* Set PFD3 DIV1 to 389M, PFD3 DIV2 to 194M */
Peng Fan690eea12021-08-07 16:00:45 +0800167 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7));
168 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(15));
169 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(23));
170 clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(31));
171
172 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7));
173 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(15));
174 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(23));
175 clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(31));
Peng Fan4cdb3a32022-04-06 14:30:12 +0800176
Ye Lie9e068f2023-01-31 16:42:25 +0800177 /* NIC_AP:
178 * OD source PLL3 PFD0, 324M
179 * ND source FRO192, 192M
180 * LD source FRO192, 96M
181 */
182 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
183 clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21), 1 << 21);
184 } else {
185 clrbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21));
186 }
187
Peng Fan4cdb3a32022-04-06 14:30:12 +0800188 if (!IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) && !IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
189 /* nicclk select pll3 pfd0 */
190 clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(29, 28), BIT(28));
191 while (!(readl(&cgc1_regs->nicclk) & BIT(27)))
192 ;
193 }
Peng Fan690eea12021-08-07 16:00:45 +0800194}
195
Ye Li8c0c8d02022-04-06 14:30:13 +0800196void cgc2_pll4_init(bool pll4_reset)
Peng Fan690eea12021-08-07 16:00:45 +0800197{
Ye Li0471ea12022-04-06 14:30:14 +0800198 /* Check the NICLPAV first to ensure not from PLL4 PFD1 clock */
199 if ((readl(&cgc2_regs->niclpavclk) & GENMASK(29, 28)) == BIT(28)) {
200 /* switch to FRO 192 first */
201 clrbits_le32(&cgc2_regs->niclpavclk, GENMASK(29, 28));
202 while (!(readl(&cgc2_regs->niclpavclk) & BIT(27)))
203 ;
204 }
205
Peng Fan690eea12021-08-07 16:00:45 +0800206 /* Disable PFD DIV and clear DIV */
207 writel(0x80808080, &cgc2_regs->pll4div_pfd0);
208 writel(0x80808080, &cgc2_regs->pll4div_pfd1);
209
210 /* Gate off and clear PFD */
211 writel(0x80808080, &cgc2_regs->pll4pfdcfg);
212
Ye Li8c0c8d02022-04-06 14:30:13 +0800213 if (pll4_reset) {
214 /* Disable PLL4 */
215 writel(0x0, &cgc2_regs->pll4csr);
Peng Fan690eea12021-08-07 16:00:45 +0800216
Ye Li8c0c8d02022-04-06 14:30:13 +0800217 /* Configure PLL4 to 528Mhz and clock source from SOSC */
218 writel(22 << 16, &cgc2_regs->pll4cfg);
219 writel(0x1, &cgc2_regs->pll4csr);
Peng Fan690eea12021-08-07 16:00:45 +0800220
Ye Li8c0c8d02022-04-06 14:30:13 +0800221 /* wait for PLL4 output valid */
222 while (!(readl(&cgc2_regs->pll4csr) & BIT(24)))
223 ;
224 }
Peng Fan690eea12021-08-07 16:00:45 +0800225
226 /* Enable all 4 PFDs */
Peng Fan4cdb3a32022-04-06 14:30:12 +0800227 setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 0); /* 528 */
Ye Lie9e068f2023-01-31 16:42:25 +0800228 setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 8); /* 316.8Mhz for NIC_LPAV */
229 setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 16); /* 316.8Mhz */
230 setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24); /* 396Mhz */
Peng Fan690eea12021-08-07 16:00:45 +0800231
232 clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) | BIT(15) | BIT(23) | BIT(31));
233
234 while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(30) | BIT(22) | BIT(14) | BIT(6)))
235 != (BIT(30) | BIT(22) | BIT(14) | BIT(6)))
236 ;
237
238 /* Enable PFD DIV */
239 clrbits_le32(&cgc2_regs->pll4div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31));
240 clrbits_le32(&cgc2_regs->pll4div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31));
Peng Fan4cdb3a32022-04-06 14:30:12 +0800241
Ye Lie9e068f2023-01-31 16:42:25 +0800242 /* NIC_LPAV:
243 * OD source PLL4 PFD1, 316.8M
244 * ND source FRO192, 192M
245 * LD source FRO192, 96M
246 */
247 if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
248 clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21), 1 << 21);
249 } else {
250 clrbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21));
251 }
252
253 if (!IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) && !IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
254 clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(29, 28), BIT(28));
255 while (!(readl(&cgc2_regs->niclpavclk) & BIT(27)))
256 ;
257 }
Peng Fan690eea12021-08-07 16:00:45 +0800258}
259
Ye Lida0469d2021-10-29 09:46:18 +0800260void cgc2_pll4_pfd_config(enum cgc_clk pllpfd, u32 pfd)
261{
262 void __iomem *reg = &cgc2_regs->pll4div_pfd0;
263 u32 halt_mask = BIT(7) | BIT(15);
264 u32 pfd_shift = (pllpfd - PLL4_PFD0) * 8;
265 u32 val;
266
267 if (pllpfd < PLL4_PFD0 || pllpfd > PLL4_PFD3)
268 return;
269
270 if ((pllpfd - PLL4_PFD0) >> 1)
271 reg = &cgc2_regs->pll4div_pfd1;
272
273 halt_mask = halt_mask << (((pllpfd - PLL4_PFD0) & 0x1) * 16);
274
275 /* halt pfd div */
276 setbits_le32(reg, halt_mask);
277
278 /* gate pfd */
279 setbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift);
280
281 val = readl(&cgc2_regs->pll4pfdcfg);
282 val &= ~(0x3f << pfd_shift);
283 val |= (pfd << pfd_shift);
284 writel(val, &cgc2_regs->pll4pfdcfg);
285
286 /* ungate */
287 clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) << pfd_shift);
288
289 /* Wait stable */
290 while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(6) << pfd_shift))
291 != (BIT(6) << pfd_shift))
292 ;
293
294 /* enable pfd div */
295 clrbits_le32(reg, halt_mask);
296}
297
298void cgc2_pll4_pfddiv_config(enum cgc_clk pllpfddiv, u32 div)
299{
300 void __iomem *reg = &cgc2_regs->pll4div_pfd0;
301 u32 shift = ((pllpfddiv - PLL4_PFD0_DIV1) & 0x3) * 8;
302
303 if (pllpfddiv < PLL4_PFD0_DIV1 || pllpfddiv > PLL4_PFD3_DIV2)
304 return;
305
306 if ((pllpfddiv - PLL4_PFD0_DIV1) >> 2)
307 reg = &cgc2_regs->pll4div_pfd1;
308
309 /* Halt pfd div */
310 setbits_le32(reg, BIT(7) << shift);
311
312 /* Clear div */
313 clrbits_le32(reg, 0x3f << shift);
314
315 /* Set div*/
316 setbits_le32(reg, div << shift);
317
318 /* Enable pfd div */
319 clrbits_le32(reg, BIT(7) << shift);
320}
321
Peng Fan690eea12021-08-07 16:00:45 +0800322void cgc2_ddrclk_config(u32 src, u32 div)
323{
Ye Li88408302021-10-29 09:46:30 +0800324 /* If reg lock is set, wait until unlock by HW */
325 /* This lock is triggered by div updating and ddrclk halt status change, */
326 while ((readl(&cgc2_regs->ddrclk) & BIT(31)))
327 ;
328
Peng Fan690eea12021-08-07 16:00:45 +0800329 writel((src << 28) | (div << 21), &cgc2_regs->ddrclk);
330 /* wait for DDRCLK switching done */
331 while (!(readl(&cgc2_regs->ddrclk) & BIT(27)))
332 ;
333}
334
Ye Li88408302021-10-29 09:46:30 +0800335void cgc2_ddrclk_wait_unlock(void)
336{
337 while ((readl(&cgc2_regs->ddrclk) & BIT(31)))
338 ;
339}
340
Ye Lida0469d2021-10-29 09:46:18 +0800341void cgc2_lpav_init(enum cgc_clk clk)
342{
343 u32 i, scs, reg;
344 const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS};
345
346 reg = readl(&cgc2_regs->niclpavclk);
347 scs = (reg >> 28) & 0x3;
348
349 for (i = 0; i < 4; i++) {
350 if (clk == src[i]) {
351 if (scs == i)
352 return;
353
354 reg &= ~(0x3 << 28);
355 reg |= (i << 28);
356
357 writel(reg, &cgc2_regs->niclpavclk);
358 break;
359 }
360 }
361
362 if (i == 4)
363 printf("Invalid clock source [%u] for LPAV\n", clk);
364}
365
366u32 cgc2_nic_get_rate(enum cgc_clk clk)
367{
368 u32 reg, rate;
369 u32 scs, lpav_axi_clk, lpav_ahb_clk, lpav_bus_clk;
370 const enum cgc_clk src[] = {FRO, PLL4_PFD1, SOSC, LVDS};
371
372 reg = readl(&cgc2_regs->niclpavclk);
373 scs = (reg >> 28) & 0x3;
374 lpav_axi_clk = ((reg >> 21) & 0x3f) + 1;
375 lpav_ahb_clk = ((reg >> 14) & 0x3f) + 1;
376 lpav_bus_clk = ((reg >> 7) & 0x3f) + 1;
377
378 rate = cgc_clk_get_rate(src[scs]);
379
380 switch (clk) {
381 case LPAV_AXICLK:
382 rate = rate / lpav_axi_clk;
383 break;
384 case LPAV_AHBCLK:
385 rate = rate / (lpav_axi_clk * lpav_ahb_clk);
386 break;
387 case LPAV_BUSCLK:
388 rate = rate / (lpav_axi_clk * lpav_bus_clk);
389 break;
390 default:
391 return 0;
392 }
393
394 return rate;
395}
396
397u32 decode_pll(enum cgc_clk pll)
Peng Fan690eea12021-08-07 16:00:45 +0800398{
399 u32 reg, infreq, mult;
400 u32 num, denom;
401
402 infreq = 24000000U;
403 /*
404 * Alought there are four choices for the bypass src,
405 * we choose SOSC 24M which is the default set in ROM.
406 * TODO: check more the comments
407 */
408 switch (pll) {
409 case PLL2:
410 reg = readl(&cgc1_regs->pll2csr);
411 if (!(reg & BIT(24)))
412 return 0;
413
414 reg = readl(&cgc1_regs->pll2cfg);
415 mult = (reg >> 16) & 0x7F;
416 denom = readl(&cgc1_regs->pll2denom) & 0x3FFFFFFF;
417 num = readl(&cgc1_regs->pll2num) & 0x3FFFFFFF;
418
419 return (u64)infreq * mult + (u64)infreq * num / denom;
420 case PLL3:
421 reg = readl(&cgc1_regs->pll3csr);
422 if (!(reg & BIT(24)))
423 return 0;
424
425 reg = readl(&cgc1_regs->pll3cfg);
426 mult = (reg >> 16) & 0x7F;
427 denom = readl(&cgc1_regs->pll3denom) & 0x3FFFFFFF;
428 num = readl(&cgc1_regs->pll3num) & 0x3FFFFFFF;
429
430 return (u64)infreq * mult + (u64)infreq * num / denom;
Ye Lida0469d2021-10-29 09:46:18 +0800431 case PLL4:
432 reg = readl(&cgc2_regs->pll4csr);
433 if (!(reg & BIT(24)))
434 return 0;
435
436 reg = readl(&cgc2_regs->pll4cfg);
437 mult = (reg >> 16) & 0x7F;
438 denom = readl(&cgc2_regs->pll4denom) & 0x3FFFFFFF;
439 num = readl(&cgc2_regs->pll4num) & 0x3FFFFFFF;
440
441 return (u64)infreq * mult + (u64)infreq * num / denom;
Peng Fan690eea12021-08-07 16:00:45 +0800442 default:
443 printf("Unsupported pll clocks %d\n", pll);
444 break;
445 }
446
447 return 0;
448}
449
Ye Lida0469d2021-10-29 09:46:18 +0800450u32 cgc_pll_vcodiv_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800451{
452 u32 reg, gate, div;
Ye Lida0469d2021-10-29 09:46:18 +0800453 void __iomem *plldiv_vco;
454 enum cgc_clk pll;
455
456 if (clk == PLL3_VCODIV) {
457 plldiv_vco = &cgc1_regs->pll3div_vco;
458 pll = PLL3;
459 } else {
460 plldiv_vco = &cgc2_regs->pll4div_vco;
461 pll = PLL4;
462 }
Peng Fan690eea12021-08-07 16:00:45 +0800463
Ye Lida0469d2021-10-29 09:46:18 +0800464 reg = readl(plldiv_vco);
Peng Fan690eea12021-08-07 16:00:45 +0800465 gate = BIT(7) & reg;
466 div = reg & 0x3F;
467
Ye Lida0469d2021-10-29 09:46:18 +0800468 return gate ? 0 : decode_pll(pll) / (div + 1);
Peng Fan690eea12021-08-07 16:00:45 +0800469}
470
Ye Lida0469d2021-10-29 09:46:18 +0800471u32 cgc_pll_pfd_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800472{
473 u32 index, gate, vld, reg;
Ye Lida0469d2021-10-29 09:46:18 +0800474 void __iomem *pllpfdcfg;
475 enum cgc_clk pll;
Peng Fan690eea12021-08-07 16:00:45 +0800476
477 switch (clk) {
478 case PLL3_PFD0:
Peng Fan690eea12021-08-07 16:00:45 +0800479 case PLL3_PFD1:
Peng Fan690eea12021-08-07 16:00:45 +0800480 case PLL3_PFD2:
Peng Fan690eea12021-08-07 16:00:45 +0800481 case PLL3_PFD3:
Ye Lida0469d2021-10-29 09:46:18 +0800482 index = clk - PLL3_PFD0;
483 pllpfdcfg = &cgc1_regs->pll3pfdcfg;
484 pll = PLL3;
485 break;
486 case PLL4_PFD0:
487 case PLL4_PFD1:
488 case PLL4_PFD2:
489 case PLL4_PFD3:
490 index = clk - PLL4_PFD0;
491 pllpfdcfg = &cgc2_regs->pll4pfdcfg;
492 pll = PLL4;
Peng Fan690eea12021-08-07 16:00:45 +0800493 break;
494 default:
495 return 0;
496 }
497
Ye Lida0469d2021-10-29 09:46:18 +0800498 reg = readl(pllpfdcfg);
Peng Fan690eea12021-08-07 16:00:45 +0800499 gate = reg & (BIT(7) << (index * 8));
500 vld = reg & (BIT(6) << (index * 8));
501
502 if (gate || !vld)
503 return 0;
504
Ye Lida0469d2021-10-29 09:46:18 +0800505 return (u64)decode_pll(pll) * 18 / ((reg >> (index * 8)) & 0x3F);
Peng Fan690eea12021-08-07 16:00:45 +0800506}
507
Ye Lida0469d2021-10-29 09:46:18 +0800508u32 cgc_pll_pfd_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800509{
510 void __iomem *base;
511 u32 pfd, index, gate, reg;
512
513 switch (clk) {
514 case PLL3_PFD0_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800515 case PLL3_PFD0_DIV2:
516 base = &cgc1_regs->pll3div_pfd0;
517 pfd = PLL3_PFD0;
Ye Lida0469d2021-10-29 09:46:18 +0800518 index = clk - PLL3_PFD0_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800519 break;
520 case PLL3_PFD1_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800521 case PLL3_PFD1_DIV2:
522 base = &cgc1_regs->pll3div_pfd0;
523 pfd = PLL3_PFD1;
Ye Lida0469d2021-10-29 09:46:18 +0800524 index = clk - PLL3_PFD0_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800525 break;
526 case PLL3_PFD2_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800527 case PLL3_PFD2_DIV2:
528 base = &cgc1_regs->pll3div_pfd1;
529 pfd = PLL3_PFD2;
Ye Lida0469d2021-10-29 09:46:18 +0800530 index = clk - PLL3_PFD2_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800531 break;
532 case PLL3_PFD3_DIV1:
Peng Fan690eea12021-08-07 16:00:45 +0800533 case PLL3_PFD3_DIV2:
534 base = &cgc1_regs->pll3div_pfd1;
535 pfd = PLL3_PFD3;
Ye Lida0469d2021-10-29 09:46:18 +0800536 index = clk - PLL3_PFD2_DIV1;
537 break;
538 case PLL4_PFD0_DIV1:
539 case PLL4_PFD0_DIV2:
540 base = &cgc2_regs->pll4div_pfd0;
541 pfd = PLL4_PFD0;
542 index = clk - PLL4_PFD0_DIV1;
543 break;
544 case PLL4_PFD1_DIV1:
545 case PLL4_PFD1_DIV2:
546 base = &cgc2_regs->pll4div_pfd0;
547 pfd = PLL4_PFD1;
548 index = clk - PLL4_PFD0_DIV1;
549 break;
550 case PLL4_PFD2_DIV1:
551 case PLL4_PFD2_DIV2:
552 base = &cgc2_regs->pll4div_pfd1;
553 pfd = PLL4_PFD2;
554 index = clk - PLL4_PFD2_DIV1;
555 break;
556 case PLL4_PFD3_DIV1:
557 case PLL4_PFD3_DIV2:
558 base = &cgc2_regs->pll4div_pfd1;
559 pfd = PLL4_PFD3;
560 index = clk - PLL4_PFD2_DIV1;
Peng Fan690eea12021-08-07 16:00:45 +0800561 break;
562 default:
563 return 0;
564 }
565
566 reg = readl(base);
567 gate = reg & (BIT(7) << (index * 8));
568
569 if (gate)
570 return 0;
Ye Lida0469d2021-10-29 09:46:18 +0800571
572 return cgc_pll_pfd_rate(pfd) / (((reg >> (index * 8)) & 0x3F) + 1);
573}
574
575u32 cgc1_nic_get_rate(enum cgc_clk clk)
576{
577 u32 reg, rate;
578 u32 scs, nic_ad_divplat, nic_per_divplat;
579 u32 xbar_ad_divplat, xbar_divbus, ad_slow;
580 const enum cgc_clk src[] = {FRO, PLL3_PFD0, SOSC, LVDS};
581
582 reg = readl(&cgc1_regs->nicclk);
583 scs = (reg >> 28) & 0x3;
584 nic_ad_divplat = ((reg >> 21) & 0x3f) + 1;
585 nic_per_divplat = ((reg >> 14) & 0x3f) + 1;
586
587 reg = readl(&cgc1_regs->xbarclk);
588 xbar_ad_divplat = ((reg >> 14) & 0x3f) + 1;
589 xbar_divbus = ((reg >> 7) & 0x3f) + 1;
590 ad_slow = (reg & 0x3f) + 1;
591
592 rate = cgc_clk_get_rate(src[scs]);
593
594 switch (clk) {
595 case NIC_APCLK:
596 rate = rate / nic_ad_divplat;
597 break;
598 case NIC_PERCLK:
599 rate = rate / (nic_ad_divplat * nic_per_divplat);
600 break;
601 case XBAR_APCLK:
602 rate = rate / (nic_ad_divplat * xbar_ad_divplat);
603 break;
604 case XBAR_BUSCLK:
605 rate = rate / (nic_ad_divplat * xbar_ad_divplat * xbar_divbus);
606 break;
607 case AD_SLOWCLK:
608 rate = rate / (nic_ad_divplat * xbar_ad_divplat * ad_slow);
609 break;
610 default:
611 return 0;
612 }
Peng Fan690eea12021-08-07 16:00:45 +0800613
Ye Lida0469d2021-10-29 09:46:18 +0800614 return rate;
Peng Fan690eea12021-08-07 16:00:45 +0800615}
616
Ye Lida0469d2021-10-29 09:46:18 +0800617u32 cgc1_sosc_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800618{
619 u32 reg, gate, index;
620
621 switch (clk) {
622 case SOSC:
623 return 24000000;
624 case SOSC_DIV1:
625 index = 0;
626 break;
627 case SOSC_DIV2:
628 index = 1;
629 break;
630 case SOSC_DIV3:
631 index = 2;
632 break;
633 default:
634 return 0;
635 }
636
637 reg = readl(&cgc1_regs->soscdiv);
638 gate = reg & (BIT(7) << (index * 8));
639
640 if (gate)
641 return 0;
642
643 return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1);
644}
645
Ye Lida0469d2021-10-29 09:46:18 +0800646u32 cgc1_fro_div(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800647{
648 u32 reg, gate, vld, index;
649
650 switch (clk) {
651 case FRO:
652 return 192000000;
653 case FRO_DIV1:
654 index = 0;
655 break;
656 case FRO_DIV2:
657 index = 1;
658 break;
659 case FRO_DIV3:
660 index = 2;
661 break;
662 default:
663 return 0;
664 }
665
666 reg = readl(&cgc1_regs->frodiv);
667 gate = reg & (BIT(7) << (index * 8));
668 vld = reg & (BIT(6) << (index * 8));
669
670 if (gate || !vld)
671 return 0;
672
673 return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1);
674}
675
Ye Lida0469d2021-10-29 09:46:18 +0800676u32 cgc_clk_get_rate(enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +0800677{
678 switch (clk) {
Ye Lida0469d2021-10-29 09:46:18 +0800679 case LVDS:
680 return 0; /* No external LVDS clock used */
Peng Fan690eea12021-08-07 16:00:45 +0800681 case SOSC:
682 case SOSC_DIV1:
683 case SOSC_DIV2:
684 case SOSC_DIV3:
685 return cgc1_sosc_div(clk);
686 case FRO:
687 case FRO_DIV1:
688 case FRO_DIV2:
689 case FRO_DIV3:
690 return cgc1_fro_div(clk);
691 case PLL2:
Peng Fan690eea12021-08-07 16:00:45 +0800692 case PLL3:
Ye Lida0469d2021-10-29 09:46:18 +0800693 case PLL4:
694 return decode_pll(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800695 case PLL3_VCODIV:
Ye Lida0469d2021-10-29 09:46:18 +0800696 case PLL4_VCODIV:
697 return cgc_pll_vcodiv_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800698 case PLL3_PFD0:
699 case PLL3_PFD1:
700 case PLL3_PFD2:
701 case PLL3_PFD3:
Ye Lida0469d2021-10-29 09:46:18 +0800702 case PLL4_PFD0:
703 case PLL4_PFD1:
704 case PLL4_PFD2:
705 case PLL4_PFD3:
706 return cgc_pll_pfd_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800707 case PLL3_PFD0_DIV1:
708 case PLL3_PFD0_DIV2:
709 case PLL3_PFD1_DIV1:
710 case PLL3_PFD1_DIV2:
711 case PLL3_PFD2_DIV1:
712 case PLL3_PFD2_DIV2:
713 case PLL3_PFD3_DIV1:
714 case PLL3_PFD3_DIV2:
Ye Lida0469d2021-10-29 09:46:18 +0800715 case PLL4_PFD0_DIV1:
716 case PLL4_PFD0_DIV2:
717 case PLL4_PFD1_DIV1:
718 case PLL4_PFD1_DIV2:
719 case PLL4_PFD2_DIV1:
720 case PLL4_PFD2_DIV2:
721 case PLL4_PFD3_DIV1:
722 case PLL4_PFD3_DIV2:
723 return cgc_pll_pfd_div(clk);
724 case NIC_APCLK:
725 case NIC_PERCLK:
726 case XBAR_APCLK:
727 case XBAR_BUSCLK:
728 case AD_SLOWCLK:
729 return cgc1_nic_get_rate(clk);
730 case LPAV_AXICLK:
731 case LPAV_AHBCLK:
732 case LPAV_BUSCLK:
733 return cgc2_nic_get_rate(clk);
Peng Fan690eea12021-08-07 16:00:45 +0800734 default:
Ye Lida0469d2021-10-29 09:46:18 +0800735 printf("Unsupported cgc clock: %d\n", clk);
Peng Fan690eea12021-08-07 16:00:45 +0800736 return 0;
737 }
738}