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