blob: e65cabef2c96a3e707112ba07a646fd5babbbe6a [file] [log] [blame]
Peng Fanbbcd2c42022-07-26 16:40:39 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 NXP
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
7
Peng Fanbbcd2c42022-07-26 16:40:39 +08008#include <command.h>
9#include <asm/arch/clock.h>
10#include <asm/arch/imx-regs.h>
Peng Fan28b5cb52022-07-26 16:40:43 +080011#include <asm/arch/ccm_regs.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080012#include <asm/arch/sys_proto.h>
13#include <asm/global_data.h>
14#include <asm/io.h>
15#include <div64.h>
16#include <errno.h>
17#include <linux/bitops.h>
18#include <linux/delay.h>
19#include <log.h>
Sébastien Szymanski459dd942023-10-17 11:44:59 +020020#include <phy.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080021
22DECLARE_GLOBAL_DATA_PTR;
23
Peng Fan28b5cb52022-07-26 16:40:43 +080024static struct anatop_reg *ana_regs = (struct anatop_reg *)ANATOP_BASE_ADDR;
25
26static struct imx_intpll_rate_table imx9_intpll_tbl[] = {
27 INT_PLL_RATE(1800000000U, 1, 150, 2), /* 1.8Ghz */
28 INT_PLL_RATE(1700000000U, 1, 141, 2), /* 1.7Ghz */
Peng Fan205286f2023-04-28 12:08:16 +080029 INT_PLL_RATE(1500000000U, 1, 125, 2), /* 1.5Ghz */
Peng Fan28b5cb52022-07-26 16:40:43 +080030 INT_PLL_RATE(1400000000U, 1, 175, 3), /* 1.4Ghz */
31 INT_PLL_RATE(1000000000U, 1, 166, 4), /* 1000Mhz */
32 INT_PLL_RATE(900000000U, 1, 150, 4), /* 900Mhz */
Peng Fan0ce300f2024-12-03 23:42:48 +080033 INT_PLL_RATE(800000000U, 1, 200, 6), /* 800Mhz */
Peng Fan28b5cb52022-07-26 16:40:43 +080034};
35
36static struct imx_fracpll_rate_table imx9_fracpll_tbl[] = {
37 FRAC_PLL_RATE(1000000000U, 1, 166, 4, 2, 3), /* 1000Mhz */
38 FRAC_PLL_RATE(933000000U, 1, 155, 4, 1, 2), /* 933Mhz */
Peng Fan657d45e2024-10-23 12:03:16 +080039 FRAC_PLL_RATE(800000000U, 1, 200, 6, 0, 1), /* 800Mhz */
Peng Fan28b5cb52022-07-26 16:40:43 +080040 FRAC_PLL_RATE(700000000U, 1, 145, 5, 5, 6), /* 700Mhz */
Peng Fan0ce300f2024-12-03 23:42:48 +080041 FRAC_PLL_RATE(600000000U, 1, 200, 8, 0, 1), /* 600Mhz */
Peng Fan205286f2023-04-28 12:08:16 +080042 FRAC_PLL_RATE(484000000U, 1, 121, 6, 0, 1),
43 FRAC_PLL_RATE(445333333U, 1, 167, 9, 0, 1),
Peng Fan28b5cb52022-07-26 16:40:43 +080044 FRAC_PLL_RATE(466000000U, 1, 155, 8, 1, 3), /* 466Mhz */
45 FRAC_PLL_RATE(400000000U, 1, 200, 12, 0, 1), /* 400Mhz */
Peng Fan205286f2023-04-28 12:08:16 +080046 FRAC_PLL_RATE(300000000U, 1, 150, 12, 0, 1),
Ye Lifa83dc82024-09-19 12:01:29 +080047 FRAC_PLL_RATE(233000000U, 1, 174, 18, 3, 4), /* 233Mhz */
Peng Fan0ce300f2024-12-03 23:42:48 +080048 FRAC_PLL_RATE(200000000U, 1, 200, 24, 0, 1), /* 200Mhz */
Peng Fan28b5cb52022-07-26 16:40:43 +080049};
50
51/* return in khz */
52static u32 decode_pll_vco(struct ana_pll_reg *reg, bool fracpll)
53{
54 u32 ctrl;
55 u32 pll_status;
56 u32 div;
57 int rdiv, mfi, mfn, mfd;
58 int clk = 24000;
59
60 ctrl = readl(&reg->ctrl.reg);
61 pll_status = readl(&reg->pll_status);
62 div = readl(&reg->div.reg);
63
64 if (!(ctrl & PLL_CTRL_POWERUP))
65 return 0;
66
67 if (!(pll_status & PLL_STATUS_PLL_LOCK))
68 return 0;
69
70 mfi = (div & GENMASK(24, 16)) >> 16;
71 rdiv = (div & GENMASK(15, 13)) >> 13;
72
73 if (rdiv == 0)
74 rdiv = 1;
75
76 if (fracpll) {
77 mfn = (int)readl(&reg->num.reg);
78 mfn >>= 2;
79 mfd = (int)(readl(&reg->denom.reg) & GENMASK(29, 0));
80
81 clk = clk * (mfi * mfd + mfn) / mfd / rdiv;
82 } else {
83 clk = clk * mfi / rdiv;
84 }
85
86 return (u32)clk;
87}
88
89/* return in khz */
90static u32 decode_pll_out(struct ana_pll_reg *reg, bool fracpll)
91{
92 u32 ctrl = readl(&reg->ctrl.reg);
93 u32 div;
94
95 if (ctrl & PLL_CTRL_CLKMUX_BYPASS)
96 return 24000;
97
98 if (!(ctrl & PLL_CTRL_CLKMUX_EN))
99 return 0;
100
101 div = readl(&reg->div.reg);
102 div &= 0xff; /* odiv */
103
104 if (div == 0)
105 div = 2;
106 else if (div == 1)
107 div = 3;
108
109 return decode_pll_vco(reg, fracpll) / div;
110}
111
112/* return in khz */
113static u32 decode_pll_pfd(struct ana_pll_reg *reg, struct ana_pll_dfs *dfs_reg,
114 bool div2, bool fracpll)
115{
116 u32 pllvco = decode_pll_vco(reg, fracpll);
117 u32 dfs_ctrl = readl(&dfs_reg->dfs_ctrl.reg);
118 u32 dfs_div = readl(&dfs_reg->dfs_div.reg);
119 u32 mfn, mfi;
120 u32 output;
121
122 if (dfs_ctrl & PLL_DFS_CTRL_BYPASS)
123 return pllvco;
124
125 if (!(dfs_ctrl & PLL_DFS_CTRL_ENABLE) ||
126 (div2 && !(dfs_ctrl & PLL_DFS_CTRL_CLKOUT_DIV2)) ||
127 (!div2 && !(dfs_ctrl & PLL_DFS_CTRL_CLKOUT)))
128 return 0;
129
130 mfn = dfs_div & GENMASK(2, 0);
131 mfi = (dfs_div & GENMASK(15, 8)) >> 8;
132
133 if (mfn > 3)
134 return 0; /* valid mfn 0-3 */
135
136 if (mfi == 0 || mfi == 1)
137 return 0; /* valid mfi 2-255 */
138
139 output = (pllvco * 5) / (mfi * 5 + mfn);
140
141 if (div2)
142 return output >> 1;
143
144 return output;
145}
146
147static u32 decode_pll(enum ccm_clk_src pll)
148{
149 switch (pll) {
150 case ARM_PLL_CLK:
151 return decode_pll_out(&ana_regs->arm_pll, false);
152 case SYS_PLL_PG:
153 return decode_pll_out(&ana_regs->sys_pll, false);
154 case SYS_PLL_PFD0:
155 return decode_pll_pfd(&ana_regs->sys_pll,
156 &ana_regs->sys_pll.dfs[0], false, true);
157 case SYS_PLL_PFD0_DIV2:
158 return decode_pll_pfd(&ana_regs->sys_pll,
159 &ana_regs->sys_pll.dfs[0], true, true);
160 case SYS_PLL_PFD1:
161 return decode_pll_pfd(&ana_regs->sys_pll,
162 &ana_regs->sys_pll.dfs[1], false, true);
163 case SYS_PLL_PFD1_DIV2:
164 return decode_pll_pfd(&ana_regs->sys_pll,
165 &ana_regs->sys_pll.dfs[1], true, true);
166 case SYS_PLL_PFD2:
167 return decode_pll_pfd(&ana_regs->sys_pll,
168 &ana_regs->sys_pll.dfs[2], false, true);
169 case SYS_PLL_PFD2_DIV2:
170 return decode_pll_pfd(&ana_regs->sys_pll,
171 &ana_regs->sys_pll.dfs[2], true, true);
172 case AUDIO_PLL_CLK:
173 return decode_pll_out(&ana_regs->audio_pll, true);
174 case DRAM_PLL_CLK:
175 return decode_pll_out(&ana_regs->dram_pll, true);
176 case VIDEO_PLL_CLK:
177 return decode_pll_out(&ana_regs->video_pll, true);
178 default:
179 printf("Invalid clock source to decode\n");
180 break;
181 }
182
183 return 0;
184}
185
186int configure_intpll(enum ccm_clk_src pll, u32 freq)
187{
188 int i;
189 struct imx_intpll_rate_table *rate;
190 struct ana_pll_reg *reg;
191 u32 pll_status;
192
193 for (i = 0; i < ARRAY_SIZE(imx9_intpll_tbl); i++) {
194 if (freq == imx9_intpll_tbl[i].rate)
195 break;
196 }
197
198 if (i == ARRAY_SIZE(imx9_intpll_tbl)) {
199 debug("No matched freq table %u\n", freq);
200 return -EINVAL;
201 }
202
203 rate = &imx9_intpll_tbl[i];
204
205 /* ROM has configured SYS PLL and PFD, no need for it */
206 switch (pll) {
207 case ARM_PLL_CLK:
208 reg = &ana_regs->arm_pll;
209 break;
210 default:
211 return -EPERM;
212 }
213
Peng Fane3fe0502023-04-28 12:08:29 +0800214 /* Clear PLL HW CTRL SEL */
215 setbits_le32(&reg->ctrl.reg_clr, PLL_CTRL_HW_CTRL_SEL);
216
Peng Fan28b5cb52022-07-26 16:40:43 +0800217 /* Bypass the PLL to ref */
218 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_set);
219
220 /* disable pll and output */
221 writel(PLL_CTRL_CLKMUX_EN | PLL_CTRL_POWERUP, &reg->ctrl.reg_clr);
222
223 /* Program the ODIV, RDIV, MFI */
224 writel((rate->odiv & GENMASK(7, 0)) | ((rate->rdiv << 13) & GENMASK(15, 13)) |
225 ((rate->mfi << 16) & GENMASK(24, 16)), &reg->div.reg);
226
227 /* wait 5us */
228 udelay(5);
229
230 /* power up the PLL and wait lock (max wait time 100 us) */
231 writel(PLL_CTRL_POWERUP, &reg->ctrl.reg_set);
232
233 udelay(100);
234
235 pll_status = readl(&reg->pll_status);
236 if (pll_status & PLL_STATUS_PLL_LOCK) {
237 writel(PLL_CTRL_CLKMUX_EN, &reg->ctrl.reg_set);
238
239 /* clear bypass */
240 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_clr);
241
242 } else {
243 debug("Fail to lock PLL %u\n", pll);
244 return -EIO;
245 }
246
247 return 0;
248}
249
250int configure_fracpll(enum ccm_clk_src pll, u32 freq)
251{
252 struct imx_fracpll_rate_table *rate;
253 struct ana_pll_reg *reg;
254 u32 pll_status;
255 int i;
256
257 for (i = 0; i < ARRAY_SIZE(imx9_fracpll_tbl); i++) {
258 if (freq == imx9_fracpll_tbl[i].rate)
259 break;
260 }
261
262 if (i == ARRAY_SIZE(imx9_fracpll_tbl)) {
263 debug("No matched freq table %u\n", freq);
264 return -EINVAL;
265 }
266
267 rate = &imx9_fracpll_tbl[i];
268
269 switch (pll) {
270 case SYS_PLL_PG:
271 reg = &ana_regs->sys_pll;
272 break;
273 case DRAM_PLL_CLK:
274 reg = &ana_regs->dram_pll;
275 break;
276 case VIDEO_PLL_CLK:
277 reg = &ana_regs->video_pll;
278 break;
279 default:
280 return -EPERM;
281 }
282
283 /* Bypass the PLL to ref */
284 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_set);
285
286 /* disable pll and output */
287 writel(PLL_CTRL_CLKMUX_EN | PLL_CTRL_POWERUP, &reg->ctrl.reg_clr);
288
289 /* Program the ODIV, RDIV, MFI */
290 writel((rate->odiv & GENMASK(7, 0)) | ((rate->rdiv << 13) & GENMASK(15, 13)) |
291 ((rate->mfi << 16) & GENMASK(24, 16)), &reg->div.reg);
292
293 /* Set SPREAD_SPECRUM enable to 0 */
294 writel(PLL_SS_EN, &reg->ss.reg_clr);
295
296 /* Program NUMERATOR and DENOMINATOR */
297 writel((rate->mfn << 2), &reg->num.reg);
298 writel((rate->mfd & GENMASK(29, 0)), &reg->denom.reg);
299
300 /* wait 5us */
301 udelay(5);
302
303 /* power up the PLL and wait lock (max wait time 100 us) */
304 writel(PLL_CTRL_POWERUP, &reg->ctrl.reg_set);
305
306 udelay(100);
307
308 pll_status = readl(&reg->pll_status);
309 if (pll_status & PLL_STATUS_PLL_LOCK) {
310 writel(PLL_CTRL_CLKMUX_EN, &reg->ctrl.reg_set);
311
312 /* check the MFN is updated */
313 pll_status = readl(&reg->pll_status);
314 if ((pll_status & ~0x3) != (rate->mfn << 2)) {
315 debug("MFN update not matched, pll_status 0x%x, mfn 0x%x\n",
316 pll_status, rate->mfn);
317 return -EIO;
318 }
319
320 /* clear bypass */
321 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_clr);
322
323 } else {
324 debug("Fail to lock PLL %u\n", pll);
325 return -EIO;
326 }
327
328 return 0;
329}
330
331int configure_pll_pfd(enum ccm_clk_src pll_pfg, u32 mfi, u32 mfn, bool div2_en)
332{
333 struct ana_pll_dfs *dfs;
334 struct ana_pll_reg *reg;
335 u32 dfs_status;
336 u32 index;
337
338 if (mfn > 3)
339 return -EINVAL; /* valid mfn 0-3 */
340
341 if (mfi < 2 || mfi > 255)
342 return -EINVAL; /* valid mfi 2-255 */
343
344 switch (pll_pfg) {
345 case SYS_PLL_PFD0:
346 reg = &ana_regs->sys_pll;
347 index = 0;
348 break;
349 case SYS_PLL_PFD1:
350 reg = &ana_regs->sys_pll;
351 index = 1;
352 break;
353 case SYS_PLL_PFD2:
354 reg = &ana_regs->sys_pll;
355 index = 2;
356 break;
357 default:
358 return -EPERM;
359 }
360
361 dfs = &reg->dfs[index];
362
363 /* Bypass the DFS to PLL VCO */
364 writel(PLL_DFS_CTRL_BYPASS, &dfs->dfs_ctrl.reg_set);
365
366 /* disable DFS and output */
367 writel(PLL_DFS_CTRL_ENABLE | PLL_DFS_CTRL_CLKOUT |
368 PLL_DFS_CTRL_CLKOUT_DIV2, &dfs->dfs_ctrl.reg_clr);
369
370 writel(((mfi << 8) & GENMASK(15, 8)) | (mfn & GENMASK(2, 0)), &dfs->dfs_div.reg);
371
372 writel(PLL_DFS_CTRL_CLKOUT, &dfs->dfs_ctrl.reg_set);
373 if (div2_en)
374 writel(PLL_DFS_CTRL_CLKOUT_DIV2, &dfs->dfs_ctrl.reg_set);
375 writel(PLL_DFS_CTRL_ENABLE, &dfs->dfs_ctrl.reg_set);
376
377 /*
378 * As HW expert said: after enabling the DFS, clock will start
379 * coming after 6 cycles output clock period.
380 * 5us is much bigger than expected, so it will be safe
381 */
382 udelay(5);
383
384 dfs_status = readl(&reg->dfs_status);
385
386 if (!(dfs_status & (1 << index))) {
387 debug("DFS lock failed\n");
388 return -EIO;
389 }
390
391 /* Bypass the DFS to PLL VCO */
392 writel(PLL_DFS_CTRL_BYPASS, &dfs->dfs_ctrl.reg_clr);
393
394 return 0;
395}
396
397int update_fracpll_mfn(enum ccm_clk_src pll, int mfn)
398{
399 struct ana_pll_reg *reg;
400 bool repoll = false;
401 u32 pll_status;
402 int count = 20;
403
404 switch (pll) {
405 case AUDIO_PLL_CLK:
406 reg = &ana_regs->audio_pll;
407 break;
408 case DRAM_PLL_CLK:
409 reg = &ana_regs->dram_pll;
410 break;
411 case VIDEO_PLL_CLK:
412 reg = &ana_regs->video_pll;
413 break;
414 default:
415 printf("Invalid pll %u for update FRAC PLL MFN\n", pll);
416 return -EINVAL;
417 }
418
419 if (readl(&reg->pll_status) & PLL_STATUS_PLL_LOCK)
420 repoll = true;
421
422 mfn <<= 2;
423 writel(mfn, &reg->num);
424
425 if (repoll) {
426 do {
427 pll_status = readl(&reg->pll_status);
428 udelay(5);
429 count--;
430 } while (((pll_status & ~0x3) != (u32)mfn) && count > 0);
431
432 if (count <= 0) {
433 printf("update MFN timeout, pll_status 0x%x, mfn 0x%x\n", pll_status, mfn);
434 return -EIO;
435 }
436 }
437
438 return 0;
439}
440
441int update_pll_pfd_mfn(enum ccm_clk_src pll_pfd, u32 mfn)
442{
443 struct ana_pll_dfs *dfs;
444 u32 val;
445 u32 index;
446
447 switch (pll_pfd) {
448 case SYS_PLL_PFD0:
449 case SYS_PLL_PFD0_DIV2:
450 index = 0;
451 break;
452 case SYS_PLL_PFD1:
453 case SYS_PLL_PFD1_DIV2:
454 index = 1;
455 break;
456 case SYS_PLL_PFD2:
457 case SYS_PLL_PFD2_DIV2:
458 index = 2;
459 break;
460 default:
461 printf("Invalid pfd %u for update PLL PFD MFN\n", pll_pfd);
462 return -EINVAL;
463 }
464
465 dfs = &ana_regs->sys_pll.dfs[index];
466
467 val = readl(&dfs->dfs_div.reg);
468 val &= ~0x3;
469 val |= mfn & 0x3;
470 writel(val, &dfs->dfs_div.reg);
471
472 return 0;
473}
474
475/* return in khz */
476u32 get_clk_src_rate(enum ccm_clk_src source)
477{
478 u32 ctrl;
479 bool clk_on;
480
481 switch (source) {
482 case ARM_PLL_CLK:
483 ctrl = readl(&ana_regs->arm_pll.ctrl.reg);
484 case AUDIO_PLL_CLK:
485 ctrl = readl(&ana_regs->audio_pll.ctrl.reg);
486 break;
487 case DRAM_PLL_CLK:
488 ctrl = readl(&ana_regs->dram_pll.ctrl.reg);
489 break;
490 case VIDEO_PLL_CLK:
491 ctrl = readl(&ana_regs->video_pll.ctrl.reg);
492 break;
493 case SYS_PLL_PFD0:
494 case SYS_PLL_PFD0_DIV2:
495 ctrl = readl(&ana_regs->sys_pll.dfs[0].dfs_ctrl.reg);
496 break;
497 case SYS_PLL_PFD1:
498 case SYS_PLL_PFD1_DIV2:
499 ctrl = readl(&ana_regs->sys_pll.dfs[1].dfs_ctrl.reg);
500 break;
501 case SYS_PLL_PFD2:
502 case SYS_PLL_PFD2_DIV2:
503 ctrl = readl(&ana_regs->sys_pll.dfs[2].dfs_ctrl.reg);
504 break;
505 case OSC_24M_CLK:
506 return 24000;
507 default:
508 printf("Invalid clock source to get rate\n");
509 return 0;
510 }
511
512 if (ctrl & PLL_CTRL_HW_CTRL_SEL) {
513 /* When using HW ctrl, check OSCPLL */
514 clk_on = ccm_clk_src_is_clk_on(source);
515 if (clk_on)
516 return decode_pll(source);
517 else
518 return 0;
519 } else {
520 /* controlled by pll registers */
521 return decode_pll(source);
522 }
523}
524
525u32 get_arm_core_clk(void)
526{
527 u32 val;
528
529 ccm_shared_gpr_get(SHARED_GPR_A55_CLK, &val);
530
531 if (val & SHARED_GPR_A55_CLK_SEL_PLL)
532 return decode_pll(ARM_PLL_CLK) * 1000;
533
534 return ccm_clk_root_get_rate(ARM_A55_CLK_ROOT);
535}
536
537unsigned int mxc_get_clock(enum mxc_clock clk)
538{
539 switch (clk) {
540 case MXC_ARM_CLK:
541 return get_arm_core_clk();
542 case MXC_IPG_CLK:
543 return ccm_clk_root_get_rate(BUS_WAKEUP_CLK_ROOT);
544 case MXC_CSPI_CLK:
545 return ccm_clk_root_get_rate(LPSPI1_CLK_ROOT);
546 case MXC_ESDHC_CLK:
547 return ccm_clk_root_get_rate(USDHC1_CLK_ROOT);
548 case MXC_ESDHC2_CLK:
549 return ccm_clk_root_get_rate(USDHC2_CLK_ROOT);
550 case MXC_ESDHC3_CLK:
551 return ccm_clk_root_get_rate(USDHC3_CLK_ROOT);
552 case MXC_UART_CLK:
553 return ccm_clk_root_get_rate(LPUART1_CLK_ROOT);
554 case MXC_FLEXSPI_CLK:
555 return ccm_clk_root_get_rate(FLEXSPI1_CLK_ROOT);
556 default:
557 return -1;
558 };
559
560 return -1;
561};
562
563int enable_i2c_clk(unsigned char enable, u32 i2c_num)
564{
565 if (i2c_num > 7)
566 return -EINVAL;
567
568 if (enable) {
569 /* 24M */
570 ccm_lpcg_on(CCGR_I2C1 + i2c_num, false);
571 ccm_clk_root_cfg(LPI2C1_CLK_ROOT + i2c_num, OSC_24M_CLK, 1);
572 ccm_lpcg_on(CCGR_I2C1 + i2c_num, true);
573 } else {
574 ccm_lpcg_on(CCGR_I2C1 + i2c_num, false);
575 }
576
577 return 0;
578}
579
580u32 imx_get_i2cclk(u32 i2c_num)
581{
582 if (i2c_num > 7)
583 return -EINVAL;
584
Peng Fana050ede2023-04-28 12:08:18 +0800585 return ccm_clk_root_get_rate(LPI2C1_CLK_ROOT + i2c_num);
Peng Fan28b5cb52022-07-26 16:40:43 +0800586}
587
Peng Fanbbcd2c42022-07-26 16:40:39 +0800588u32 get_lpuart_clk(void)
589{
Peng Fan28b5cb52022-07-26 16:40:43 +0800590 return mxc_get_clock(MXC_UART_CLK);
591}
592
593void init_uart_clk(u32 index)
594{
595 switch (index) {
596 case LPUART1_CLK_ROOT:
597 /* 24M */
598 ccm_lpcg_on(CCGR_URT1, false);
599 ccm_clk_root_cfg(LPUART1_CLK_ROOT, OSC_24M_CLK, 1);
600 ccm_lpcg_on(CCGR_URT1, true);
601 break;
602 default:
603 break;
604 }
605}
606
607void init_clk_usdhc(u32 index)
608{
Peng Fan14e66962023-04-28 12:08:30 +0800609 u32 div;
610
Ye Li7b248152024-09-19 12:01:26 +0800611 if (is_voltage_mode(VOLT_LOW_DRIVE))
Peng Fan14e66962023-04-28 12:08:30 +0800612 div = 3; /* 266.67 Mhz */
613 else
614 div = 2; /* 400 Mhz */
615
Peng Fan28b5cb52022-07-26 16:40:43 +0800616 switch (index) {
617 case 0:
618 ccm_lpcg_on(CCGR_USDHC1, 0);
Peng Fan14e66962023-04-28 12:08:30 +0800619 ccm_clk_root_cfg(USDHC1_CLK_ROOT, SYS_PLL_PFD1, div);
Peng Fan28b5cb52022-07-26 16:40:43 +0800620 ccm_lpcg_on(CCGR_USDHC1, 1);
621 break;
622 case 1:
623 ccm_lpcg_on(CCGR_USDHC2, 0);
Peng Fan14e66962023-04-28 12:08:30 +0800624 ccm_clk_root_cfg(USDHC2_CLK_ROOT, SYS_PLL_PFD1, div);
Peng Fan28b5cb52022-07-26 16:40:43 +0800625 ccm_lpcg_on(CCGR_USDHC2, 1);
626 break;
627 case 2:
628 ccm_lpcg_on(CCGR_USDHC3, 0);
Peng Fan14e66962023-04-28 12:08:30 +0800629 ccm_clk_root_cfg(USDHC3_CLK_ROOT, SYS_PLL_PFD1, div);
Peng Fan28b5cb52022-07-26 16:40:43 +0800630 ccm_lpcg_on(CCGR_USDHC3, 1);
631 break;
632 default:
633 return;
634 };
635}
636
637void enable_usboh3_clk(unsigned char enable)
638{
639 if (enable) {
640 ccm_clk_root_cfg(HSIO_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3);
641 ccm_lpcg_on(CCGR_USBC, 1);
642 } else {
643 ccm_lpcg_on(CCGR_USBC, 0);
644 }
645}
646
Simon Glass85ed77d2024-09-29 19:49:46 -0600647#ifdef CONFIG_XPL_BUILD
Ye Li327ecf92022-07-26 16:41:06 +0800648void dram_pll_init(ulong pll_val)
649{
650 configure_fracpll(DRAM_PLL_CLK, pll_val);
651}
652
653void dram_enable_bypass(ulong clk_val)
654{
655 switch (clk_val) {
Jacky Baie747f9f2023-04-28 12:08:42 +0800656 case MHZ(625):
657 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD2, 1);
658 break;
Ye Li327ecf92022-07-26 16:41:06 +0800659 case MHZ(400):
660 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD1, 2);
661 break;
662 case MHZ(333):
663 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD0, 3);
664 break;
665 case MHZ(200):
666 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD1, 4);
667 break;
668 case MHZ(100):
669 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD1, 8);
670 break;
671 default:
672 printf("No matched freq table %lu\n", clk_val);
673 return;
674 }
675
676 /* Set DRAM APB to 133Mhz */
677 ccm_clk_root_cfg(DRAM_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3);
678 /* Switch from DRAM clock root from PLL to CCM */
679 ccm_shared_gpr_set(SHARED_GPR_DRAM_CLK, SHARED_GPR_DRAM_CLK_SEL_CCM);
680}
681
682void dram_disable_bypass(void)
683{
684 /* Set DRAM APB to 133Mhz */
685 ccm_clk_root_cfg(DRAM_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3);
686 /* Switch from DRAM clock root from CCM to PLL */
687 ccm_shared_gpr_set(SHARED_GPR_DRAM_CLK, SHARED_GPR_DRAM_CLK_SEL_PLL);
688}
Peng Fan10fde4e2022-07-26 16:41:11 +0800689
690void set_arm_clk(ulong freq)
691{
692 /* Increase ARM clock to 1.7Ghz */
693 ccm_shared_gpr_set(SHARED_GPR_A55_CLK, SHARED_GPR_A55_CLK_SEL_CCM);
Peng Fan0f30f0c2023-04-28 12:08:17 +0800694 configure_intpll(ARM_PLL_CLK, freq);
Peng Fan10fde4e2022-07-26 16:41:11 +0800695 ccm_shared_gpr_set(SHARED_GPR_A55_CLK, SHARED_GPR_A55_CLK_SEL_PLL);
696}
697
Peng Fan14e66962023-04-28 12:08:30 +0800698void set_arm_core_max_clk(void)
699{
700 /* Increase ARM clock to max rate according to speed grade */
701 u32 speed = get_cpu_speed_grade_hz();
702
703 set_arm_clk(speed);
704}
705
Ye Li327ecf92022-07-26 16:41:06 +0800706#endif
707
Ye Li7b248152024-09-19 12:01:26 +0800708struct imx_clk_setting imx_clk_ld_settings[] = {
Peng Fan14e66962023-04-28 12:08:30 +0800709 /* Set A55 clk to 500M */
710 {ARM_A55_CLK_ROOT, SYS_PLL_PFD0, 2},
711 /* Set A55 periphal to 200M */
712 {ARM_A55_PERIPH_CLK_ROOT, SYS_PLL_PFD1, 4},
713 /* Set A55 mtr bus to 133M */
714 {ARM_A55_MTR_BUS_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
715
Peng Fand5c31832023-06-15 18:09:05 +0800716 /* ELE to 133M */
717 {ELE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
Peng Fan14e66962023-04-28 12:08:30 +0800718 /* Bus_wakeup to 133M */
719 {BUS_WAKEUP_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
720 /* Bus_AON to 133M */
721 {BUS_AON_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
722 /* M33 to 133M */
723 {M33_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
724 /* WAKEUP_AXI to 200M */
725 {WAKEUP_AXI_CLK_ROOT, SYS_PLL_PFD1, 4},
726 /* SWO TRACE to 133M */
727 {SWO_TRACE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
728 /* M33 systetick to 24M */
Peng Fan0ce300f2024-12-03 23:42:48 +0800729 {M33_SYSTICK_CLK_ROOT, OSC_24M_CLK, 1, CLK_SOC_IMX93},
Peng Fan14e66962023-04-28 12:08:30 +0800730 /* NIC to 250M */
731 {NIC_CLK_ROOT, SYS_PLL_PFD0, 4},
732 /* NIC_APB to 133M */
733 {NIC_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3}
734};
Ye Li7b248152024-09-19 12:01:26 +0800735
Peng Fan7a78c922023-04-28 12:08:19 +0800736struct imx_clk_setting imx_clk_settings[] = {
Peng Fan6d65d2c2023-04-28 12:08:31 +0800737 /*
738 * Set A55 clk to 500M. This clock root is normally used as intermediate
739 * clock source for A55 core/DSU when doing ARM PLL reconfig. set it to
740 * 500MHz(LD mode frequency) should be ok.
741 */
742 {ARM_A55_CLK_ROOT, SYS_PLL_PFD0, 2},
Peng Fan28b5cb52022-07-26 16:40:43 +0800743 /* Set A55 periphal to 333M */
Peng Fan7a78c922023-04-28 12:08:19 +0800744 {ARM_A55_PERIPH_CLK_ROOT, SYS_PLL_PFD0, 3},
Peng Fan28b5cb52022-07-26 16:40:43 +0800745 /* Set A55 mtr bus to 133M */
Peng Fan7a78c922023-04-28 12:08:19 +0800746 {ARM_A55_MTR_BUS_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
Peng Fand5c31832023-06-15 18:09:05 +0800747 /* ELE to 200M */
748 {ELE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 2},
Peng Fan28b5cb52022-07-26 16:40:43 +0800749 /* Bus_wakeup to 133M */
Peng Fan7a78c922023-04-28 12:08:19 +0800750 {BUS_WAKEUP_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
Peng Fan28b5cb52022-07-26 16:40:43 +0800751 /* Bus_AON to 133M */
Peng Fan7a78c922023-04-28 12:08:19 +0800752 {BUS_AON_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
Peng Fan28b5cb52022-07-26 16:40:43 +0800753 /* M33 to 200M */
Peng Fan7a78c922023-04-28 12:08:19 +0800754 {M33_CLK_ROOT, SYS_PLL_PFD1_DIV2, 2},
Peng Fan28b5cb52022-07-26 16:40:43 +0800755 /*
756 * WAKEUP_AXI to 312.5M, because of FEC only can support to 320M for
757 * generating MII clock at 2.5M
758 */
Peng Fan0ce300f2024-12-03 23:42:48 +0800759 {WAKEUP_AXI_CLK_ROOT, SYS_PLL_PFD2, 2, CLK_SOC_IMX93},
760 /* Wakeup AXI 250M*/
761 {WAKEUP_AXI_CLK_ROOT, SYS_PLL_PFD0, 4, CLK_SOC_IMX91},
Peng Fan28b5cb52022-07-26 16:40:43 +0800762 /* SWO TRACE to 133M */
Peng Fan7a78c922023-04-28 12:08:19 +0800763 {SWO_TRACE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
Peng Fan44b6f6b2023-04-28 12:08:15 +0800764 /* M33 systetick to 24M */
Peng Fan0ce300f2024-12-03 23:42:48 +0800765 {M33_SYSTICK_CLK_ROOT, OSC_24M_CLK, 1, CLK_SOC_IMX93},
Peng Fan28b5cb52022-07-26 16:40:43 +0800766 /* NIC to 400M */
Peng Fan0ce300f2024-12-03 23:42:48 +0800767 {NIC_CLK_ROOT, SYS_PLL_PFD1, 2, CLK_SOC_IMX93},
768 /* NIC to 333M */
769 {NIC_CLK_ROOT, SYS_PLL_PFD0, 3, CLK_SOC_IMX91},
Peng Fan28b5cb52022-07-26 16:40:43 +0800770 /* NIC_APB to 133M */
Peng Fan7a78c922023-04-28 12:08:19 +0800771 {NIC_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3}
772};
773
Ye Li7b248152024-09-19 12:01:26 +0800774void bus_clock_init_low_drive(void)
Peng Fan7a78c922023-04-28 12:08:19 +0800775{
776 int i;
777
Ye Li7b248152024-09-19 12:01:26 +0800778 for (i = 0; i < ARRAY_SIZE(imx_clk_ld_settings); i++) {
Peng Fan0ce300f2024-12-03 23:42:48 +0800779 if (imx_clk_ld_settings[i].soc == CLK_SOC_ALL ||
780 (is_imx91() && imx_clk_ld_settings[i].soc == CLK_SOC_IMX91) ||
781 (is_imx93() && imx_clk_ld_settings[i].soc == CLK_SOC_IMX93)) {
782 ccm_clk_root_cfg(imx_clk_ld_settings[i].clk_root,
783 imx_clk_ld_settings[i].src, imx_clk_ld_settings[i].div);
784 }
Ye Li7b248152024-09-19 12:01:26 +0800785 }
786}
787
788void bus_clock_init(void)
789{
790 int i;
791
Peng Fan7a78c922023-04-28 12:08:19 +0800792 for (i = 0; i < ARRAY_SIZE(imx_clk_settings); i++) {
Peng Fan0ce300f2024-12-03 23:42:48 +0800793 if (imx_clk_settings[i].soc == CLK_SOC_ALL ||
794 (is_imx91() && imx_clk_settings[i].soc == CLK_SOC_IMX91) ||
795 (is_imx93() && imx_clk_settings[i].soc == CLK_SOC_IMX93)) {
796 ccm_clk_root_cfg(imx_clk_settings[i].clk_root,
797 imx_clk_settings[i].src, imx_clk_settings[i].div);
798 }
Peng Fan7a78c922023-04-28 12:08:19 +0800799 }
Ye Li7b248152024-09-19 12:01:26 +0800800}
801
Ye Li66af10a2024-09-19 12:01:27 +0800802int clock_init_early(void)
Ye Li7b248152024-09-19 12:01:26 +0800803{
804 int i;
Peng Fan28b5cb52022-07-26 16:40:43 +0800805
806 /* allow for non-secure access */
807 for (i = 0; i < OSCPLL_END; i++)
808 ccm_clk_src_tz_access(i, true, false, false);
809
810 for (i = 0; i < CLK_ROOT_NUM; i++)
811 ccm_clk_root_tz_access(i, true, false, false);
812
813 for (i = 0; i < CCGR_NUM; i++)
814 ccm_lpcg_tz_access(i, true, false, false);
815
816 for (i = 0; i < SHARED_GPR_NUM; i++)
817 ccm_shared_gpr_tz_access(i, true, false, false);
818
819 return 0;
820}
821
Ye Li66af10a2024-09-19 12:01:27 +0800822/* Set bus and A55 core clock per voltage mode */
823int clock_init_late(void)
824{
825 if (is_voltage_mode(VOLT_LOW_DRIVE)) {
826 bus_clock_init_low_drive();
827 set_arm_core_max_clk();
828 } else {
829 bus_clock_init();
830 }
831
832 return 0;
833}
834
Peng Fan28b5cb52022-07-26 16:40:43 +0800835int set_clk_eqos(enum enet_freq type)
836{
837 u32 eqos_post_div;
838
839 switch (type) {
840 case ENET_125MHZ:
841 eqos_post_div = 2; /* 250M clock */
842 break;
843 case ENET_50MHZ:
844 eqos_post_div = 5; /* 100M clock */
845 break;
846 case ENET_25MHZ:
847 eqos_post_div = 10; /* 50M clock*/
848 break;
849 default:
850 return -EINVAL;
851 }
852
853 /* disable the clock first */
854 ccm_lpcg_on(CCGR_ENETQOS, false);
855
856 ccm_clk_root_cfg(ENET_CLK_ROOT, SYS_PLL_PFD0_DIV2, eqos_post_div);
857 ccm_clk_root_cfg(ENET_TIMER2_CLK_ROOT, SYS_PLL_PFD0_DIV2, 5);
858
859 /* enable clock */
860 ccm_lpcg_on(CCGR_ENETQOS, true);
861
862 return 0;
863}
864
865u32 imx_get_eqos_csr_clk(void)
866{
867 return ccm_clk_root_get_rate(WAKEUP_AXI_CLK_ROOT);
868}
869
870u32 imx_get_fecclk(void)
871{
872 return ccm_clk_root_get_rate(WAKEUP_AXI_CLK_ROOT);
873}
874
Peng Fan0ce300f2024-12-03 23:42:48 +0800875#if (CONFIG_IS_ENABLED(IMX93) || CONFIG_IS_ENABLED(IMX91)) && CONFIG_IS_ENABLED(DWC_ETH_QOS)
Sébastien Szymanski459dd942023-10-17 11:44:59 +0200876static int imx93_eqos_interface_init(struct udevice *dev, phy_interface_t interface_type)
877{
878 struct blk_ctrl_wakeupmix_regs *bctrl =
879 (struct blk_ctrl_wakeupmix_regs *)BLK_CTRL_WAKEUPMIX_BASE_ADDR;
880
881 clrbits_le32(&bctrl->eqos_gpr,
882 BCTRL_GPR_ENET_QOS_INTF_MODE_MASK |
883 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
884
885 switch (interface_type) {
886 case PHY_INTERFACE_MODE_MII:
887 setbits_le32(&bctrl->eqos_gpr,
888 BCTRL_GPR_ENET_QOS_INTF_SEL_MII |
889 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
890 break;
891 case PHY_INTERFACE_MODE_RMII:
892 setbits_le32(&bctrl->eqos_gpr,
893 BCTRL_GPR_ENET_QOS_INTF_SEL_RMII |
894 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
895 break;
896 case PHY_INTERFACE_MODE_RGMII:
897 case PHY_INTERFACE_MODE_RGMII_ID:
898 case PHY_INTERFACE_MODE_RGMII_RXID:
899 case PHY_INTERFACE_MODE_RGMII_TXID:
900 setbits_le32(&bctrl->eqos_gpr,
901 BCTRL_GPR_ENET_QOS_INTF_SEL_RGMII |
902 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
903 break;
904 default:
905 return -EINVAL;
906 }
907
908 return 0;
909}
910#else
911static int imx93_eqos_interface_init(struct udevice *dev, phy_interface_t interface_type)
912{
913 return 0;
914}
915#endif
916
917int board_interface_eth_init(struct udevice *dev, phy_interface_t interface_type)
918{
Peng Fan0ce300f2024-12-03 23:42:48 +0800919 if ((IS_ENABLED(CONFIG_IMX93) || IS_ENABLED(CONFIG_IMX91)) &&
Sébastien Szymanski459dd942023-10-17 11:44:59 +0200920 IS_ENABLED(CONFIG_DWC_ETH_QOS) &&
921 device_is_compatible(dev, "nxp,imx93-dwmac-eqos"))
922 return imx93_eqos_interface_init(dev, interface_type);
923
Peng Fan0ce300f2024-12-03 23:42:48 +0800924 if ((IS_ENABLED(CONFIG_IMX93) || IS_ENABLED(CONFIG_IMX91)) &&
Primoz Fiser848b9042024-01-30 13:43:37 +0100925 IS_ENABLED(CONFIG_FEC_MXC) &&
926 device_is_compatible(dev, "fsl,imx93-fec"))
927 return 0;
928
Sébastien Szymanski459dd942023-10-17 11:44:59 +0200929 return -EINVAL;
930}
931
Peng Fan28b5cb52022-07-26 16:40:43 +0800932int set_clk_enet(enum enet_freq type)
933{
934 u32 div;
935
936 /* disable the clock first */
937 ccm_lpcg_on(CCGR_ENET1, false);
938
939 switch (type) {
940 case ENET_125MHZ:
941 div = 2; /* 250Mhz */
942 break;
943 case ENET_50MHZ:
944 div = 5; /* 100Mhz */
945 break;
946 case ENET_25MHZ:
947 div = 10; /* 50Mhz */
948 break;
949 default:
950 return -EINVAL;
951 }
952
953 ccm_clk_root_cfg(ENET_REF_CLK_ROOT, SYS_PLL_PFD0_DIV2, div);
954 ccm_clk_root_cfg(ENET_TIMER1_CLK_ROOT, SYS_PLL_PFD0_DIV2, 5);
955
956#ifdef CONFIG_FEC_MXC_25M_REF_CLK
957 ccm_clk_root_cfg(ENET_REF_PHY_CLK_ROOT, SYS_PLL_PFD0_DIV2, 20);
958#endif
959
960 /* enable clock */
961 ccm_lpcg_on(CCGR_ENET1, true);
962
963 return 0;
964}
965
966/*
967 * Dump some clockes.
968 */
Simon Glass85ed77d2024-09-29 19:49:46 -0600969#ifndef CONFIG_XPL_BUILD
Peng Fan28b5cb52022-07-26 16:40:43 +0800970int do_showclocks(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
971{
972 u32 freq;
973
974 freq = decode_pll(ARM_PLL_CLK);
975 printf("ARM_PLL %8d MHz\n", freq / 1000);
976 freq = decode_pll(DRAM_PLL_CLK);
977 printf("DRAM_PLL %8d MHz\n", freq / 1000);
978 freq = decode_pll(SYS_PLL_PFD0);
979 printf("SYS_PLL_PFD0 %8d MHz\n", freq / 1000);
980 freq = decode_pll(SYS_PLL_PFD0_DIV2);
981 printf("SYS_PLL_PFD0_DIV2 %8d MHz\n", freq / 1000);
982 freq = decode_pll(SYS_PLL_PFD1);
983 printf("SYS_PLL_PFD1 %8d MHz\n", freq / 1000);
984 freq = decode_pll(SYS_PLL_PFD1_DIV2);
985 printf("SYS_PLL_PFD1_DIV2 %8d MHz\n", freq / 1000);
986 freq = decode_pll(SYS_PLL_PFD2);
987 printf("SYS_PLL_PFD2 %8d MHz\n", freq / 1000);
988 freq = decode_pll(SYS_PLL_PFD2_DIV2);
989 printf("SYS_PLL_PFD2_DIV2 %8d MHz\n", freq / 1000);
990 freq = mxc_get_clock(MXC_ARM_CLK);
991 printf("ARM CORE %8d MHz\n", freq / 1000000);
992 freq = mxc_get_clock(MXC_IPG_CLK);
993 printf("IPG %8d MHz\n", freq / 1000000);
994 freq = mxc_get_clock(MXC_UART_CLK);
995 printf("UART3 %8d MHz\n", freq / 1000000);
996 freq = mxc_get_clock(MXC_ESDHC_CLK);
997 printf("USDHC1 %8d MHz\n", freq / 1000000);
998 freq = mxc_get_clock(MXC_FLEXSPI_CLK);
999 printf("FLEXSPI %8d MHz\n", freq / 1000000);
1000
1001 return 0;
Peng Fanbbcd2c42022-07-26 16:40:39 +08001002}
Peng Fan28b5cb52022-07-26 16:40:43 +08001003
1004U_BOOT_CMD(
1005 clocks, CONFIG_SYS_MAXARGS, 1, do_showclocks,
1006 "display clocks",
1007 ""
1008);
1009#endif