blob: 92c41e9a67bf7b67cd7a3dbf8f38178c60d0f021 [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
8#include <common.h>
9#include <command.h>
10#include <asm/arch/clock.h>
11#include <asm/arch/imx-regs.h>
Peng Fan28b5cb52022-07-26 16:40:43 +080012#include <asm/arch/ccm_regs.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080013#include <asm/arch/sys_proto.h>
14#include <asm/global_data.h>
15#include <asm/io.h>
16#include <div64.h>
17#include <errno.h>
18#include <linux/bitops.h>
19#include <linux/delay.h>
20#include <log.h>
Sébastien Szymanski459dd942023-10-17 11:44:59 +020021#include <phy.h>
Peng Fanbbcd2c42022-07-26 16:40:39 +080022
23DECLARE_GLOBAL_DATA_PTR;
24
Peng Fan28b5cb52022-07-26 16:40:43 +080025static struct anatop_reg *ana_regs = (struct anatop_reg *)ANATOP_BASE_ADDR;
26
27static struct imx_intpll_rate_table imx9_intpll_tbl[] = {
28 INT_PLL_RATE(1800000000U, 1, 150, 2), /* 1.8Ghz */
29 INT_PLL_RATE(1700000000U, 1, 141, 2), /* 1.7Ghz */
Peng Fan205286f2023-04-28 12:08:16 +080030 INT_PLL_RATE(1500000000U, 1, 125, 2), /* 1.5Ghz */
Peng Fan28b5cb52022-07-26 16:40:43 +080031 INT_PLL_RATE(1400000000U, 1, 175, 3), /* 1.4Ghz */
32 INT_PLL_RATE(1000000000U, 1, 166, 4), /* 1000Mhz */
33 INT_PLL_RATE(900000000U, 1, 150, 4), /* 900Mhz */
34};
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 */
39 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),
Peng Fan28b5cb52022-07-26 16:40:43 +080045};
46
47/* return in khz */
48static u32 decode_pll_vco(struct ana_pll_reg *reg, bool fracpll)
49{
50 u32 ctrl;
51 u32 pll_status;
52 u32 div;
53 int rdiv, mfi, mfn, mfd;
54 int clk = 24000;
55
56 ctrl = readl(&reg->ctrl.reg);
57 pll_status = readl(&reg->pll_status);
58 div = readl(&reg->div.reg);
59
60 if (!(ctrl & PLL_CTRL_POWERUP))
61 return 0;
62
63 if (!(pll_status & PLL_STATUS_PLL_LOCK))
64 return 0;
65
66 mfi = (div & GENMASK(24, 16)) >> 16;
67 rdiv = (div & GENMASK(15, 13)) >> 13;
68
69 if (rdiv == 0)
70 rdiv = 1;
71
72 if (fracpll) {
73 mfn = (int)readl(&reg->num.reg);
74 mfn >>= 2;
75 mfd = (int)(readl(&reg->denom.reg) & GENMASK(29, 0));
76
77 clk = clk * (mfi * mfd + mfn) / mfd / rdiv;
78 } else {
79 clk = clk * mfi / rdiv;
80 }
81
82 return (u32)clk;
83}
84
85/* return in khz */
86static u32 decode_pll_out(struct ana_pll_reg *reg, bool fracpll)
87{
88 u32 ctrl = readl(&reg->ctrl.reg);
89 u32 div;
90
91 if (ctrl & PLL_CTRL_CLKMUX_BYPASS)
92 return 24000;
93
94 if (!(ctrl & PLL_CTRL_CLKMUX_EN))
95 return 0;
96
97 div = readl(&reg->div.reg);
98 div &= 0xff; /* odiv */
99
100 if (div == 0)
101 div = 2;
102 else if (div == 1)
103 div = 3;
104
105 return decode_pll_vco(reg, fracpll) / div;
106}
107
108/* return in khz */
109static u32 decode_pll_pfd(struct ana_pll_reg *reg, struct ana_pll_dfs *dfs_reg,
110 bool div2, bool fracpll)
111{
112 u32 pllvco = decode_pll_vco(reg, fracpll);
113 u32 dfs_ctrl = readl(&dfs_reg->dfs_ctrl.reg);
114 u32 dfs_div = readl(&dfs_reg->dfs_div.reg);
115 u32 mfn, mfi;
116 u32 output;
117
118 if (dfs_ctrl & PLL_DFS_CTRL_BYPASS)
119 return pllvco;
120
121 if (!(dfs_ctrl & PLL_DFS_CTRL_ENABLE) ||
122 (div2 && !(dfs_ctrl & PLL_DFS_CTRL_CLKOUT_DIV2)) ||
123 (!div2 && !(dfs_ctrl & PLL_DFS_CTRL_CLKOUT)))
124 return 0;
125
126 mfn = dfs_div & GENMASK(2, 0);
127 mfi = (dfs_div & GENMASK(15, 8)) >> 8;
128
129 if (mfn > 3)
130 return 0; /* valid mfn 0-3 */
131
132 if (mfi == 0 || mfi == 1)
133 return 0; /* valid mfi 2-255 */
134
135 output = (pllvco * 5) / (mfi * 5 + mfn);
136
137 if (div2)
138 return output >> 1;
139
140 return output;
141}
142
143static u32 decode_pll(enum ccm_clk_src pll)
144{
145 switch (pll) {
146 case ARM_PLL_CLK:
147 return decode_pll_out(&ana_regs->arm_pll, false);
148 case SYS_PLL_PG:
149 return decode_pll_out(&ana_regs->sys_pll, false);
150 case SYS_PLL_PFD0:
151 return decode_pll_pfd(&ana_regs->sys_pll,
152 &ana_regs->sys_pll.dfs[0], false, true);
153 case SYS_PLL_PFD0_DIV2:
154 return decode_pll_pfd(&ana_regs->sys_pll,
155 &ana_regs->sys_pll.dfs[0], true, true);
156 case SYS_PLL_PFD1:
157 return decode_pll_pfd(&ana_regs->sys_pll,
158 &ana_regs->sys_pll.dfs[1], false, true);
159 case SYS_PLL_PFD1_DIV2:
160 return decode_pll_pfd(&ana_regs->sys_pll,
161 &ana_regs->sys_pll.dfs[1], true, true);
162 case SYS_PLL_PFD2:
163 return decode_pll_pfd(&ana_regs->sys_pll,
164 &ana_regs->sys_pll.dfs[2], false, true);
165 case SYS_PLL_PFD2_DIV2:
166 return decode_pll_pfd(&ana_regs->sys_pll,
167 &ana_regs->sys_pll.dfs[2], true, true);
168 case AUDIO_PLL_CLK:
169 return decode_pll_out(&ana_regs->audio_pll, true);
170 case DRAM_PLL_CLK:
171 return decode_pll_out(&ana_regs->dram_pll, true);
172 case VIDEO_PLL_CLK:
173 return decode_pll_out(&ana_regs->video_pll, true);
174 default:
175 printf("Invalid clock source to decode\n");
176 break;
177 }
178
179 return 0;
180}
181
182int configure_intpll(enum ccm_clk_src pll, u32 freq)
183{
184 int i;
185 struct imx_intpll_rate_table *rate;
186 struct ana_pll_reg *reg;
187 u32 pll_status;
188
189 for (i = 0; i < ARRAY_SIZE(imx9_intpll_tbl); i++) {
190 if (freq == imx9_intpll_tbl[i].rate)
191 break;
192 }
193
194 if (i == ARRAY_SIZE(imx9_intpll_tbl)) {
195 debug("No matched freq table %u\n", freq);
196 return -EINVAL;
197 }
198
199 rate = &imx9_intpll_tbl[i];
200
201 /* ROM has configured SYS PLL and PFD, no need for it */
202 switch (pll) {
203 case ARM_PLL_CLK:
204 reg = &ana_regs->arm_pll;
205 break;
206 default:
207 return -EPERM;
208 }
209
Peng Fane3fe0502023-04-28 12:08:29 +0800210 /* Clear PLL HW CTRL SEL */
211 setbits_le32(&reg->ctrl.reg_clr, PLL_CTRL_HW_CTRL_SEL);
212
Peng Fan28b5cb52022-07-26 16:40:43 +0800213 /* Bypass the PLL to ref */
214 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_set);
215
216 /* disable pll and output */
217 writel(PLL_CTRL_CLKMUX_EN | PLL_CTRL_POWERUP, &reg->ctrl.reg_clr);
218
219 /* Program the ODIV, RDIV, MFI */
220 writel((rate->odiv & GENMASK(7, 0)) | ((rate->rdiv << 13) & GENMASK(15, 13)) |
221 ((rate->mfi << 16) & GENMASK(24, 16)), &reg->div.reg);
222
223 /* wait 5us */
224 udelay(5);
225
226 /* power up the PLL and wait lock (max wait time 100 us) */
227 writel(PLL_CTRL_POWERUP, &reg->ctrl.reg_set);
228
229 udelay(100);
230
231 pll_status = readl(&reg->pll_status);
232 if (pll_status & PLL_STATUS_PLL_LOCK) {
233 writel(PLL_CTRL_CLKMUX_EN, &reg->ctrl.reg_set);
234
235 /* clear bypass */
236 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_clr);
237
238 } else {
239 debug("Fail to lock PLL %u\n", pll);
240 return -EIO;
241 }
242
243 return 0;
244}
245
246int configure_fracpll(enum ccm_clk_src pll, u32 freq)
247{
248 struct imx_fracpll_rate_table *rate;
249 struct ana_pll_reg *reg;
250 u32 pll_status;
251 int i;
252
253 for (i = 0; i < ARRAY_SIZE(imx9_fracpll_tbl); i++) {
254 if (freq == imx9_fracpll_tbl[i].rate)
255 break;
256 }
257
258 if (i == ARRAY_SIZE(imx9_fracpll_tbl)) {
259 debug("No matched freq table %u\n", freq);
260 return -EINVAL;
261 }
262
263 rate = &imx9_fracpll_tbl[i];
264
265 switch (pll) {
266 case SYS_PLL_PG:
267 reg = &ana_regs->sys_pll;
268 break;
269 case DRAM_PLL_CLK:
270 reg = &ana_regs->dram_pll;
271 break;
272 case VIDEO_PLL_CLK:
273 reg = &ana_regs->video_pll;
274 break;
275 default:
276 return -EPERM;
277 }
278
279 /* Bypass the PLL to ref */
280 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_set);
281
282 /* disable pll and output */
283 writel(PLL_CTRL_CLKMUX_EN | PLL_CTRL_POWERUP, &reg->ctrl.reg_clr);
284
285 /* Program the ODIV, RDIV, MFI */
286 writel((rate->odiv & GENMASK(7, 0)) | ((rate->rdiv << 13) & GENMASK(15, 13)) |
287 ((rate->mfi << 16) & GENMASK(24, 16)), &reg->div.reg);
288
289 /* Set SPREAD_SPECRUM enable to 0 */
290 writel(PLL_SS_EN, &reg->ss.reg_clr);
291
292 /* Program NUMERATOR and DENOMINATOR */
293 writel((rate->mfn << 2), &reg->num.reg);
294 writel((rate->mfd & GENMASK(29, 0)), &reg->denom.reg);
295
296 /* wait 5us */
297 udelay(5);
298
299 /* power up the PLL and wait lock (max wait time 100 us) */
300 writel(PLL_CTRL_POWERUP, &reg->ctrl.reg_set);
301
302 udelay(100);
303
304 pll_status = readl(&reg->pll_status);
305 if (pll_status & PLL_STATUS_PLL_LOCK) {
306 writel(PLL_CTRL_CLKMUX_EN, &reg->ctrl.reg_set);
307
308 /* check the MFN is updated */
309 pll_status = readl(&reg->pll_status);
310 if ((pll_status & ~0x3) != (rate->mfn << 2)) {
311 debug("MFN update not matched, pll_status 0x%x, mfn 0x%x\n",
312 pll_status, rate->mfn);
313 return -EIO;
314 }
315
316 /* clear bypass */
317 writel(PLL_CTRL_CLKMUX_BYPASS, &reg->ctrl.reg_clr);
318
319 } else {
320 debug("Fail to lock PLL %u\n", pll);
321 return -EIO;
322 }
323
324 return 0;
325}
326
327int configure_pll_pfd(enum ccm_clk_src pll_pfg, u32 mfi, u32 mfn, bool div2_en)
328{
329 struct ana_pll_dfs *dfs;
330 struct ana_pll_reg *reg;
331 u32 dfs_status;
332 u32 index;
333
334 if (mfn > 3)
335 return -EINVAL; /* valid mfn 0-3 */
336
337 if (mfi < 2 || mfi > 255)
338 return -EINVAL; /* valid mfi 2-255 */
339
340 switch (pll_pfg) {
341 case SYS_PLL_PFD0:
342 reg = &ana_regs->sys_pll;
343 index = 0;
344 break;
345 case SYS_PLL_PFD1:
346 reg = &ana_regs->sys_pll;
347 index = 1;
348 break;
349 case SYS_PLL_PFD2:
350 reg = &ana_regs->sys_pll;
351 index = 2;
352 break;
353 default:
354 return -EPERM;
355 }
356
357 dfs = &reg->dfs[index];
358
359 /* Bypass the DFS to PLL VCO */
360 writel(PLL_DFS_CTRL_BYPASS, &dfs->dfs_ctrl.reg_set);
361
362 /* disable DFS and output */
363 writel(PLL_DFS_CTRL_ENABLE | PLL_DFS_CTRL_CLKOUT |
364 PLL_DFS_CTRL_CLKOUT_DIV2, &dfs->dfs_ctrl.reg_clr);
365
366 writel(((mfi << 8) & GENMASK(15, 8)) | (mfn & GENMASK(2, 0)), &dfs->dfs_div.reg);
367
368 writel(PLL_DFS_CTRL_CLKOUT, &dfs->dfs_ctrl.reg_set);
369 if (div2_en)
370 writel(PLL_DFS_CTRL_CLKOUT_DIV2, &dfs->dfs_ctrl.reg_set);
371 writel(PLL_DFS_CTRL_ENABLE, &dfs->dfs_ctrl.reg_set);
372
373 /*
374 * As HW expert said: after enabling the DFS, clock will start
375 * coming after 6 cycles output clock period.
376 * 5us is much bigger than expected, so it will be safe
377 */
378 udelay(5);
379
380 dfs_status = readl(&reg->dfs_status);
381
382 if (!(dfs_status & (1 << index))) {
383 debug("DFS lock failed\n");
384 return -EIO;
385 }
386
387 /* Bypass the DFS to PLL VCO */
388 writel(PLL_DFS_CTRL_BYPASS, &dfs->dfs_ctrl.reg_clr);
389
390 return 0;
391}
392
393int update_fracpll_mfn(enum ccm_clk_src pll, int mfn)
394{
395 struct ana_pll_reg *reg;
396 bool repoll = false;
397 u32 pll_status;
398 int count = 20;
399
400 switch (pll) {
401 case AUDIO_PLL_CLK:
402 reg = &ana_regs->audio_pll;
403 break;
404 case DRAM_PLL_CLK:
405 reg = &ana_regs->dram_pll;
406 break;
407 case VIDEO_PLL_CLK:
408 reg = &ana_regs->video_pll;
409 break;
410 default:
411 printf("Invalid pll %u for update FRAC PLL MFN\n", pll);
412 return -EINVAL;
413 }
414
415 if (readl(&reg->pll_status) & PLL_STATUS_PLL_LOCK)
416 repoll = true;
417
418 mfn <<= 2;
419 writel(mfn, &reg->num);
420
421 if (repoll) {
422 do {
423 pll_status = readl(&reg->pll_status);
424 udelay(5);
425 count--;
426 } while (((pll_status & ~0x3) != (u32)mfn) && count > 0);
427
428 if (count <= 0) {
429 printf("update MFN timeout, pll_status 0x%x, mfn 0x%x\n", pll_status, mfn);
430 return -EIO;
431 }
432 }
433
434 return 0;
435}
436
437int update_pll_pfd_mfn(enum ccm_clk_src pll_pfd, u32 mfn)
438{
439 struct ana_pll_dfs *dfs;
440 u32 val;
441 u32 index;
442
443 switch (pll_pfd) {
444 case SYS_PLL_PFD0:
445 case SYS_PLL_PFD0_DIV2:
446 index = 0;
447 break;
448 case SYS_PLL_PFD1:
449 case SYS_PLL_PFD1_DIV2:
450 index = 1;
451 break;
452 case SYS_PLL_PFD2:
453 case SYS_PLL_PFD2_DIV2:
454 index = 2;
455 break;
456 default:
457 printf("Invalid pfd %u for update PLL PFD MFN\n", pll_pfd);
458 return -EINVAL;
459 }
460
461 dfs = &ana_regs->sys_pll.dfs[index];
462
463 val = readl(&dfs->dfs_div.reg);
464 val &= ~0x3;
465 val |= mfn & 0x3;
466 writel(val, &dfs->dfs_div.reg);
467
468 return 0;
469}
470
471/* return in khz */
472u32 get_clk_src_rate(enum ccm_clk_src source)
473{
474 u32 ctrl;
475 bool clk_on;
476
477 switch (source) {
478 case ARM_PLL_CLK:
479 ctrl = readl(&ana_regs->arm_pll.ctrl.reg);
480 case AUDIO_PLL_CLK:
481 ctrl = readl(&ana_regs->audio_pll.ctrl.reg);
482 break;
483 case DRAM_PLL_CLK:
484 ctrl = readl(&ana_regs->dram_pll.ctrl.reg);
485 break;
486 case VIDEO_PLL_CLK:
487 ctrl = readl(&ana_regs->video_pll.ctrl.reg);
488 break;
489 case SYS_PLL_PFD0:
490 case SYS_PLL_PFD0_DIV2:
491 ctrl = readl(&ana_regs->sys_pll.dfs[0].dfs_ctrl.reg);
492 break;
493 case SYS_PLL_PFD1:
494 case SYS_PLL_PFD1_DIV2:
495 ctrl = readl(&ana_regs->sys_pll.dfs[1].dfs_ctrl.reg);
496 break;
497 case SYS_PLL_PFD2:
498 case SYS_PLL_PFD2_DIV2:
499 ctrl = readl(&ana_regs->sys_pll.dfs[2].dfs_ctrl.reg);
500 break;
501 case OSC_24M_CLK:
502 return 24000;
503 default:
504 printf("Invalid clock source to get rate\n");
505 return 0;
506 }
507
508 if (ctrl & PLL_CTRL_HW_CTRL_SEL) {
509 /* When using HW ctrl, check OSCPLL */
510 clk_on = ccm_clk_src_is_clk_on(source);
511 if (clk_on)
512 return decode_pll(source);
513 else
514 return 0;
515 } else {
516 /* controlled by pll registers */
517 return decode_pll(source);
518 }
519}
520
521u32 get_arm_core_clk(void)
522{
523 u32 val;
524
525 ccm_shared_gpr_get(SHARED_GPR_A55_CLK, &val);
526
527 if (val & SHARED_GPR_A55_CLK_SEL_PLL)
528 return decode_pll(ARM_PLL_CLK) * 1000;
529
530 return ccm_clk_root_get_rate(ARM_A55_CLK_ROOT);
531}
532
533unsigned int mxc_get_clock(enum mxc_clock clk)
534{
535 switch (clk) {
536 case MXC_ARM_CLK:
537 return get_arm_core_clk();
538 case MXC_IPG_CLK:
539 return ccm_clk_root_get_rate(BUS_WAKEUP_CLK_ROOT);
540 case MXC_CSPI_CLK:
541 return ccm_clk_root_get_rate(LPSPI1_CLK_ROOT);
542 case MXC_ESDHC_CLK:
543 return ccm_clk_root_get_rate(USDHC1_CLK_ROOT);
544 case MXC_ESDHC2_CLK:
545 return ccm_clk_root_get_rate(USDHC2_CLK_ROOT);
546 case MXC_ESDHC3_CLK:
547 return ccm_clk_root_get_rate(USDHC3_CLK_ROOT);
548 case MXC_UART_CLK:
549 return ccm_clk_root_get_rate(LPUART1_CLK_ROOT);
550 case MXC_FLEXSPI_CLK:
551 return ccm_clk_root_get_rate(FLEXSPI1_CLK_ROOT);
552 default:
553 return -1;
554 };
555
556 return -1;
557};
558
559int enable_i2c_clk(unsigned char enable, u32 i2c_num)
560{
561 if (i2c_num > 7)
562 return -EINVAL;
563
564 if (enable) {
565 /* 24M */
566 ccm_lpcg_on(CCGR_I2C1 + i2c_num, false);
567 ccm_clk_root_cfg(LPI2C1_CLK_ROOT + i2c_num, OSC_24M_CLK, 1);
568 ccm_lpcg_on(CCGR_I2C1 + i2c_num, true);
569 } else {
570 ccm_lpcg_on(CCGR_I2C1 + i2c_num, false);
571 }
572
573 return 0;
574}
575
576u32 imx_get_i2cclk(u32 i2c_num)
577{
578 if (i2c_num > 7)
579 return -EINVAL;
580
Peng Fana050ede2023-04-28 12:08:18 +0800581 return ccm_clk_root_get_rate(LPI2C1_CLK_ROOT + i2c_num);
Peng Fan28b5cb52022-07-26 16:40:43 +0800582}
583
Peng Fanbbcd2c42022-07-26 16:40:39 +0800584u32 get_lpuart_clk(void)
585{
Peng Fan28b5cb52022-07-26 16:40:43 +0800586 return mxc_get_clock(MXC_UART_CLK);
587}
588
589void init_uart_clk(u32 index)
590{
591 switch (index) {
592 case LPUART1_CLK_ROOT:
593 /* 24M */
594 ccm_lpcg_on(CCGR_URT1, false);
595 ccm_clk_root_cfg(LPUART1_CLK_ROOT, OSC_24M_CLK, 1);
596 ccm_lpcg_on(CCGR_URT1, true);
597 break;
598 default:
599 break;
600 }
601}
602
603void init_clk_usdhc(u32 index)
604{
Peng Fan14e66962023-04-28 12:08:30 +0800605 u32 div;
606
607 if (IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE))
608 div = 3; /* 266.67 Mhz */
609 else
610 div = 2; /* 400 Mhz */
611
Peng Fan28b5cb52022-07-26 16:40:43 +0800612 switch (index) {
613 case 0:
614 ccm_lpcg_on(CCGR_USDHC1, 0);
Peng Fan14e66962023-04-28 12:08:30 +0800615 ccm_clk_root_cfg(USDHC1_CLK_ROOT, SYS_PLL_PFD1, div);
Peng Fan28b5cb52022-07-26 16:40:43 +0800616 ccm_lpcg_on(CCGR_USDHC1, 1);
617 break;
618 case 1:
619 ccm_lpcg_on(CCGR_USDHC2, 0);
Peng Fan14e66962023-04-28 12:08:30 +0800620 ccm_clk_root_cfg(USDHC2_CLK_ROOT, SYS_PLL_PFD1, div);
Peng Fan28b5cb52022-07-26 16:40:43 +0800621 ccm_lpcg_on(CCGR_USDHC2, 1);
622 break;
623 case 2:
624 ccm_lpcg_on(CCGR_USDHC3, 0);
Peng Fan14e66962023-04-28 12:08:30 +0800625 ccm_clk_root_cfg(USDHC3_CLK_ROOT, SYS_PLL_PFD1, div);
Peng Fan28b5cb52022-07-26 16:40:43 +0800626 ccm_lpcg_on(CCGR_USDHC3, 1);
627 break;
628 default:
629 return;
630 };
631}
632
633void enable_usboh3_clk(unsigned char enable)
634{
635 if (enable) {
636 ccm_clk_root_cfg(HSIO_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3);
637 ccm_lpcg_on(CCGR_USBC, 1);
638 } else {
639 ccm_lpcg_on(CCGR_USBC, 0);
640 }
641}
642
Ye Li327ecf92022-07-26 16:41:06 +0800643#ifdef CONFIG_SPL_BUILD
644void dram_pll_init(ulong pll_val)
645{
646 configure_fracpll(DRAM_PLL_CLK, pll_val);
647}
648
649void dram_enable_bypass(ulong clk_val)
650{
651 switch (clk_val) {
Jacky Baie747f9f2023-04-28 12:08:42 +0800652 case MHZ(625):
653 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD2, 1);
654 break;
Ye Li327ecf92022-07-26 16:41:06 +0800655 case MHZ(400):
656 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD1, 2);
657 break;
658 case MHZ(333):
659 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD0, 3);
660 break;
661 case MHZ(200):
662 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD1, 4);
663 break;
664 case MHZ(100):
665 ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD1, 8);
666 break;
667 default:
668 printf("No matched freq table %lu\n", clk_val);
669 return;
670 }
671
672 /* Set DRAM APB to 133Mhz */
673 ccm_clk_root_cfg(DRAM_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3);
674 /* Switch from DRAM clock root from PLL to CCM */
675 ccm_shared_gpr_set(SHARED_GPR_DRAM_CLK, SHARED_GPR_DRAM_CLK_SEL_CCM);
676}
677
678void dram_disable_bypass(void)
679{
680 /* Set DRAM APB to 133Mhz */
681 ccm_clk_root_cfg(DRAM_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3);
682 /* Switch from DRAM clock root from CCM to PLL */
683 ccm_shared_gpr_set(SHARED_GPR_DRAM_CLK, SHARED_GPR_DRAM_CLK_SEL_PLL);
684}
Peng Fan10fde4e2022-07-26 16:41:11 +0800685
686void set_arm_clk(ulong freq)
687{
688 /* Increase ARM clock to 1.7Ghz */
689 ccm_shared_gpr_set(SHARED_GPR_A55_CLK, SHARED_GPR_A55_CLK_SEL_CCM);
Peng Fan0f30f0c2023-04-28 12:08:17 +0800690 configure_intpll(ARM_PLL_CLK, freq);
Peng Fan10fde4e2022-07-26 16:41:11 +0800691 ccm_shared_gpr_set(SHARED_GPR_A55_CLK, SHARED_GPR_A55_CLK_SEL_PLL);
692}
693
Peng Fan14e66962023-04-28 12:08:30 +0800694void set_arm_core_max_clk(void)
695{
696 /* Increase ARM clock to max rate according to speed grade */
697 u32 speed = get_cpu_speed_grade_hz();
698
699 set_arm_clk(speed);
700}
701
Ye Li327ecf92022-07-26 16:41:06 +0800702#endif
703
Peng Fan14e66962023-04-28 12:08:30 +0800704#if IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE)
705struct imx_clk_setting imx_clk_settings[] = {
706 /* 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};
732#else
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};
Peng Fan14e66962023-04-28 12:08:30 +0800766#endif
Peng Fan7a78c922023-04-28 12:08:19 +0800767
768int clock_init(void)
769{
770 int i;
771
772 for (i = 0; i < ARRAY_SIZE(imx_clk_settings); i++) {
773 ccm_clk_root_cfg(imx_clk_settings[i].clk_root,
774 imx_clk_settings[i].src, imx_clk_settings[i].div);
775 }
Peng Fan28b5cb52022-07-26 16:40:43 +0800776
Peng Fan14e66962023-04-28 12:08:30 +0800777 if (IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE))
778 set_arm_clk(MHZ(900));
779
Peng Fan28b5cb52022-07-26 16:40:43 +0800780 /* allow for non-secure access */
781 for (i = 0; i < OSCPLL_END; i++)
782 ccm_clk_src_tz_access(i, true, false, false);
783
784 for (i = 0; i < CLK_ROOT_NUM; i++)
785 ccm_clk_root_tz_access(i, true, false, false);
786
787 for (i = 0; i < CCGR_NUM; i++)
788 ccm_lpcg_tz_access(i, true, false, false);
789
790 for (i = 0; i < SHARED_GPR_NUM; i++)
791 ccm_shared_gpr_tz_access(i, true, false, false);
792
793 return 0;
794}
795
796int set_clk_eqos(enum enet_freq type)
797{
798 u32 eqos_post_div;
799
800 switch (type) {
801 case ENET_125MHZ:
802 eqos_post_div = 2; /* 250M clock */
803 break;
804 case ENET_50MHZ:
805 eqos_post_div = 5; /* 100M clock */
806 break;
807 case ENET_25MHZ:
808 eqos_post_div = 10; /* 50M clock*/
809 break;
810 default:
811 return -EINVAL;
812 }
813
814 /* disable the clock first */
815 ccm_lpcg_on(CCGR_ENETQOS, false);
816
817 ccm_clk_root_cfg(ENET_CLK_ROOT, SYS_PLL_PFD0_DIV2, eqos_post_div);
818 ccm_clk_root_cfg(ENET_TIMER2_CLK_ROOT, SYS_PLL_PFD0_DIV2, 5);
819
820 /* enable clock */
821 ccm_lpcg_on(CCGR_ENETQOS, true);
822
823 return 0;
824}
825
826u32 imx_get_eqos_csr_clk(void)
827{
828 return ccm_clk_root_get_rate(WAKEUP_AXI_CLK_ROOT);
829}
830
831u32 imx_get_fecclk(void)
832{
833 return ccm_clk_root_get_rate(WAKEUP_AXI_CLK_ROOT);
834}
835
Sébastien Szymanski459dd942023-10-17 11:44:59 +0200836#if defined(CONFIG_IMX93) && defined(CONFIG_DWC_ETH_QOS)
837static int imx93_eqos_interface_init(struct udevice *dev, phy_interface_t interface_type)
838{
839 struct blk_ctrl_wakeupmix_regs *bctrl =
840 (struct blk_ctrl_wakeupmix_regs *)BLK_CTRL_WAKEUPMIX_BASE_ADDR;
841
842 clrbits_le32(&bctrl->eqos_gpr,
843 BCTRL_GPR_ENET_QOS_INTF_MODE_MASK |
844 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
845
846 switch (interface_type) {
847 case PHY_INTERFACE_MODE_MII:
848 setbits_le32(&bctrl->eqos_gpr,
849 BCTRL_GPR_ENET_QOS_INTF_SEL_MII |
850 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
851 break;
852 case PHY_INTERFACE_MODE_RMII:
853 setbits_le32(&bctrl->eqos_gpr,
854 BCTRL_GPR_ENET_QOS_INTF_SEL_RMII |
855 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
856 break;
857 case PHY_INTERFACE_MODE_RGMII:
858 case PHY_INTERFACE_MODE_RGMII_ID:
859 case PHY_INTERFACE_MODE_RGMII_RXID:
860 case PHY_INTERFACE_MODE_RGMII_TXID:
861 setbits_le32(&bctrl->eqos_gpr,
862 BCTRL_GPR_ENET_QOS_INTF_SEL_RGMII |
863 BCTRL_GPR_ENET_QOS_CLK_GEN_EN);
864 break;
865 default:
866 return -EINVAL;
867 }
868
869 return 0;
870}
871#else
872static int imx93_eqos_interface_init(struct udevice *dev, phy_interface_t interface_type)
873{
874 return 0;
875}
876#endif
877
878int board_interface_eth_init(struct udevice *dev, phy_interface_t interface_type)
879{
880 if (IS_ENABLED(CONFIG_IMX93) &&
881 IS_ENABLED(CONFIG_DWC_ETH_QOS) &&
882 device_is_compatible(dev, "nxp,imx93-dwmac-eqos"))
883 return imx93_eqos_interface_init(dev, interface_type);
884
885 return -EINVAL;
886}
887
Peng Fan28b5cb52022-07-26 16:40:43 +0800888int set_clk_enet(enum enet_freq type)
889{
890 u32 div;
891
892 /* disable the clock first */
893 ccm_lpcg_on(CCGR_ENET1, false);
894
895 switch (type) {
896 case ENET_125MHZ:
897 div = 2; /* 250Mhz */
898 break;
899 case ENET_50MHZ:
900 div = 5; /* 100Mhz */
901 break;
902 case ENET_25MHZ:
903 div = 10; /* 50Mhz */
904 break;
905 default:
906 return -EINVAL;
907 }
908
909 ccm_clk_root_cfg(ENET_REF_CLK_ROOT, SYS_PLL_PFD0_DIV2, div);
910 ccm_clk_root_cfg(ENET_TIMER1_CLK_ROOT, SYS_PLL_PFD0_DIV2, 5);
911
912#ifdef CONFIG_FEC_MXC_25M_REF_CLK
913 ccm_clk_root_cfg(ENET_REF_PHY_CLK_ROOT, SYS_PLL_PFD0_DIV2, 20);
914#endif
915
916 /* enable clock */
917 ccm_lpcg_on(CCGR_ENET1, true);
918
919 return 0;
920}
921
922/*
923 * Dump some clockes.
924 */
925#ifndef CONFIG_SPL_BUILD
926int do_showclocks(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
927{
928 u32 freq;
929
930 freq = decode_pll(ARM_PLL_CLK);
931 printf("ARM_PLL %8d MHz\n", freq / 1000);
932 freq = decode_pll(DRAM_PLL_CLK);
933 printf("DRAM_PLL %8d MHz\n", freq / 1000);
934 freq = decode_pll(SYS_PLL_PFD0);
935 printf("SYS_PLL_PFD0 %8d MHz\n", freq / 1000);
936 freq = decode_pll(SYS_PLL_PFD0_DIV2);
937 printf("SYS_PLL_PFD0_DIV2 %8d MHz\n", freq / 1000);
938 freq = decode_pll(SYS_PLL_PFD1);
939 printf("SYS_PLL_PFD1 %8d MHz\n", freq / 1000);
940 freq = decode_pll(SYS_PLL_PFD1_DIV2);
941 printf("SYS_PLL_PFD1_DIV2 %8d MHz\n", freq / 1000);
942 freq = decode_pll(SYS_PLL_PFD2);
943 printf("SYS_PLL_PFD2 %8d MHz\n", freq / 1000);
944 freq = decode_pll(SYS_PLL_PFD2_DIV2);
945 printf("SYS_PLL_PFD2_DIV2 %8d MHz\n", freq / 1000);
946 freq = mxc_get_clock(MXC_ARM_CLK);
947 printf("ARM CORE %8d MHz\n", freq / 1000000);
948 freq = mxc_get_clock(MXC_IPG_CLK);
949 printf("IPG %8d MHz\n", freq / 1000000);
950 freq = mxc_get_clock(MXC_UART_CLK);
951 printf("UART3 %8d MHz\n", freq / 1000000);
952 freq = mxc_get_clock(MXC_ESDHC_CLK);
953 printf("USDHC1 %8d MHz\n", freq / 1000000);
954 freq = mxc_get_clock(MXC_FLEXSPI_CLK);
955 printf("FLEXSPI %8d MHz\n", freq / 1000000);
956
957 return 0;
Peng Fanbbcd2c42022-07-26 16:40:39 +0800958}
Peng Fan28b5cb52022-07-26 16:40:43 +0800959
960U_BOOT_CMD(
961 clocks, CONFIG_SYS_MAXARGS, 1, do_showclocks,
962 "display clocks",
963 ""
964);
965#endif