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