]>
Commit | Line | Data |
---|---|---|
881df6ed PF |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2022 NXP | |
4 | * | |
5 | * Peng Fan <peng.fan@nxp.com> | |
6 | */ | |
7 | ||
d678a59d | 8 | #include <common.h> |
881df6ed PF |
9 | #include <command.h> |
10 | #include <asm/arch/clock.h> | |
11 | #include <asm/arch/imx-regs.h> | |
f79c1626 | 12 | #include <asm/arch/ccm_regs.h> |
881df6ed PF |
13 | #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> | |
d5eae216 | 21 | #include <phy.h> |
881df6ed PF |
22 | |
23 | DECLARE_GLOBAL_DATA_PTR; | |
24 | ||
f79c1626 PF |
25 | static struct anatop_reg *ana_regs = (struct anatop_reg *)ANATOP_BASE_ADDR; |
26 | ||
27 | static 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 */ | |
a6b36e99 | 30 | INT_PLL_RATE(1500000000U, 1, 125, 2), /* 1.5Ghz */ |
f79c1626 PF |
31 | 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 | ||
36 | static 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 */ | |
a6b36e99 PF |
40 | FRAC_PLL_RATE(484000000U, 1, 121, 6, 0, 1), |
41 | FRAC_PLL_RATE(445333333U, 1, 167, 9, 0, 1), | |
f79c1626 PF |
42 | FRAC_PLL_RATE(466000000U, 1, 155, 8, 1, 3), /* 466Mhz */ |
43 | FRAC_PLL_RATE(400000000U, 1, 200, 12, 0, 1), /* 400Mhz */ | |
a6b36e99 | 44 | FRAC_PLL_RATE(300000000U, 1, 150, 12, 0, 1), |
f79c1626 PF |
45 | }; |
46 | ||
47 | /* return in khz */ | |
48 | static 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(®->ctrl.reg); | |
57 | pll_status = readl(®->pll_status); | |
58 | div = readl(®->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(®->num.reg); | |
74 | mfn >>= 2; | |
75 | mfd = (int)(readl(®->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 */ | |
86 | static u32 decode_pll_out(struct ana_pll_reg *reg, bool fracpll) | |
87 | { | |
88 | u32 ctrl = readl(®->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(®->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 */ | |
109 | static 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 | ||
143 | static 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 | ||
182 | int 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 | ||
59ecc85b PF |
210 | /* Clear PLL HW CTRL SEL */ |
211 | setbits_le32(®->ctrl.reg_clr, PLL_CTRL_HW_CTRL_SEL); | |
212 | ||
f79c1626 PF |
213 | /* Bypass the PLL to ref */ |
214 | writel(PLL_CTRL_CLKMUX_BYPASS, ®->ctrl.reg_set); | |
215 | ||
216 | /* disable pll and output */ | |
217 | writel(PLL_CTRL_CLKMUX_EN | PLL_CTRL_POWERUP, ®->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)), ®->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, ®->ctrl.reg_set); | |
228 | ||
229 | udelay(100); | |
230 | ||
231 | pll_status = readl(®->pll_status); | |
232 | if (pll_status & PLL_STATUS_PLL_LOCK) { | |
233 | writel(PLL_CTRL_CLKMUX_EN, ®->ctrl.reg_set); | |
234 | ||
235 | /* clear bypass */ | |
236 | writel(PLL_CTRL_CLKMUX_BYPASS, ®->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 | ||
246 | int 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, ®->ctrl.reg_set); | |
281 | ||
282 | /* disable pll and output */ | |
283 | writel(PLL_CTRL_CLKMUX_EN | PLL_CTRL_POWERUP, ®->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)), ®->div.reg); | |
288 | ||
289 | /* Set SPREAD_SPECRUM enable to 0 */ | |
290 | writel(PLL_SS_EN, ®->ss.reg_clr); | |
291 | ||
292 | /* Program NUMERATOR and DENOMINATOR */ | |
293 | writel((rate->mfn << 2), ®->num.reg); | |
294 | writel((rate->mfd & GENMASK(29, 0)), ®->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, ®->ctrl.reg_set); | |
301 | ||
302 | udelay(100); | |
303 | ||
304 | pll_status = readl(®->pll_status); | |
305 | if (pll_status & PLL_STATUS_PLL_LOCK) { | |
306 | writel(PLL_CTRL_CLKMUX_EN, ®->ctrl.reg_set); | |
307 | ||
308 | /* check the MFN is updated */ | |
309 | pll_status = readl(®->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, ®->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 | ||
327 | int 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 = ®->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(®->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 | ||
393 | int 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(®->pll_status) & PLL_STATUS_PLL_LOCK) | |
416 | repoll = true; | |
417 | ||
418 | mfn <<= 2; | |
419 | writel(mfn, ®->num); | |
420 | ||
421 | if (repoll) { | |
422 | do { | |
423 | pll_status = readl(®->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 | ||
437 | int 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 */ | |
472 | u32 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 | ||
521 | u32 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 | ||
533 | unsigned 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 | ||
559 | int 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 | ||
576 | u32 imx_get_i2cclk(u32 i2c_num) | |
577 | { | |
578 | if (i2c_num > 7) | |
579 | return -EINVAL; | |
580 | ||
532e73fd | 581 | return ccm_clk_root_get_rate(LPI2C1_CLK_ROOT + i2c_num); |
f79c1626 PF |
582 | } |
583 | ||
881df6ed PF |
584 | u32 get_lpuart_clk(void) |
585 | { | |
f79c1626 PF |
586 | return mxc_get_clock(MXC_UART_CLK); |
587 | } | |
588 | ||
589 | void 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 | ||
603 | void init_clk_usdhc(u32 index) | |
604 | { | |
3c5dcec7 PF |
605 | 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 | ||
f79c1626 PF |
612 | switch (index) { |
613 | case 0: | |
614 | ccm_lpcg_on(CCGR_USDHC1, 0); | |
3c5dcec7 | 615 | ccm_clk_root_cfg(USDHC1_CLK_ROOT, SYS_PLL_PFD1, div); |
f79c1626 PF |
616 | ccm_lpcg_on(CCGR_USDHC1, 1); |
617 | break; | |
618 | case 1: | |
619 | ccm_lpcg_on(CCGR_USDHC2, 0); | |
3c5dcec7 | 620 | ccm_clk_root_cfg(USDHC2_CLK_ROOT, SYS_PLL_PFD1, div); |
f79c1626 PF |
621 | ccm_lpcg_on(CCGR_USDHC2, 1); |
622 | break; | |
623 | case 2: | |
624 | ccm_lpcg_on(CCGR_USDHC3, 0); | |
3c5dcec7 | 625 | ccm_clk_root_cfg(USDHC3_CLK_ROOT, SYS_PLL_PFD1, div); |
f79c1626 PF |
626 | ccm_lpcg_on(CCGR_USDHC3, 1); |
627 | break; | |
628 | default: | |
629 | return; | |
630 | }; | |
881df6ed | 631 | } |
f79c1626 PF |
632 | |
633 | void 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 | ||
e631185a YL |
643 | #ifdef CONFIG_SPL_BUILD |
644 | void dram_pll_init(ulong pll_val) | |
645 | { | |
646 | configure_fracpll(DRAM_PLL_CLK, pll_val); | |
647 | } | |
648 | ||
649 | void dram_enable_bypass(ulong clk_val) | |
650 | { | |
651 | switch (clk_val) { | |
37eb821e JB |
652 | case MHZ(625): |
653 | ccm_clk_root_cfg(DRAM_ALT_CLK_ROOT, SYS_PLL_PFD2, 1); | |
654 | break; | |
e631185a YL |
655 | 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 | ||
678 | void 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 | } | |
feaf8e0c PF |
685 | |
686 | void 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); | |
5f2953eb | 690 | configure_intpll(ARM_PLL_CLK, freq); |
feaf8e0c PF |
691 | ccm_shared_gpr_set(SHARED_GPR_A55_CLK, SHARED_GPR_A55_CLK_SEL_PLL); |
692 | } | |
693 | ||
3c5dcec7 PF |
694 | void 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 | ||
e631185a YL |
702 | #endif |
703 | ||
3c5dcec7 PF |
704 | #if IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE) |
705 | struct 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 | ||
d3ee9dbd PF |
713 | /* ELE to 133M */ |
714 | {ELE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3}, | |
3c5dcec7 PF |
715 | /* 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 | |
5d09fcf2 | 733 | struct imx_clk_setting imx_clk_settings[] = { |
4a5c5d56 PF |
734 | /* |
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}, | |
f79c1626 | 740 | /* Set A55 periphal to 333M */ |
5d09fcf2 | 741 | {ARM_A55_PERIPH_CLK_ROOT, SYS_PLL_PFD0, 3}, |
f79c1626 | 742 | /* Set A55 mtr bus to 133M */ |
5d09fcf2 | 743 | {ARM_A55_MTR_BUS_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3}, |
d3ee9dbd PF |
744 | /* ELE to 200M */ |
745 | {ELE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 2}, | |
f79c1626 | 746 | /* Bus_wakeup to 133M */ |
5d09fcf2 | 747 | {BUS_WAKEUP_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3}, |
f79c1626 | 748 | /* Bus_AON to 133M */ |
5d09fcf2 | 749 | {BUS_AON_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3}, |
f79c1626 | 750 | /* M33 to 200M */ |
5d09fcf2 | 751 | {M33_CLK_ROOT, SYS_PLL_PFD1_DIV2, 2}, |
f79c1626 PF |
752 | /* |
753 | * WAKEUP_AXI to 312.5M, because of FEC only can support to 320M for | |
754 | * generating MII clock at 2.5M | |
755 | */ | |
5d09fcf2 | 756 | {WAKEUP_AXI_CLK_ROOT, SYS_PLL_PFD2, 2}, |
f79c1626 | 757 | /* SWO TRACE to 133M */ |
5d09fcf2 | 758 | {SWO_TRACE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3}, |
69326a7f | 759 | /* M33 systetick to 24M */ |
5d09fcf2 | 760 | {M33_SYSTICK_CLK_ROOT, OSC_24M_CLK, 1}, |
f79c1626 | 761 | /* NIC to 400M */ |
5d09fcf2 | 762 | {NIC_CLK_ROOT, SYS_PLL_PFD1, 2}, |
f79c1626 | 763 | /* NIC_APB to 133M */ |
5d09fcf2 PF |
764 | {NIC_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3} |
765 | }; | |
3c5dcec7 | 766 | #endif |
5d09fcf2 PF |
767 | |
768 | int 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 | } | |
f79c1626 | 776 | |
3c5dcec7 PF |
777 | if (IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE)) |
778 | set_arm_clk(MHZ(900)); | |
779 | ||
f79c1626 PF |
780 | /* 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 | ||
796 | int 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 | ||
826 | u32 imx_get_eqos_csr_clk(void) | |
827 | { | |
828 | return ccm_clk_root_get_rate(WAKEUP_AXI_CLK_ROOT); | |
829 | } | |
830 | ||
831 | u32 imx_get_fecclk(void) | |
832 | { | |
833 | return ccm_clk_root_get_rate(WAKEUP_AXI_CLK_ROOT); | |
834 | } | |
835 | ||
d5eae216 SS |
836 | #if defined(CONFIG_IMX93) && defined(CONFIG_DWC_ETH_QOS) |
837 | static 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 | |
872 | static int imx93_eqos_interface_init(struct udevice *dev, phy_interface_t interface_type) | |
873 | { | |
874 | return 0; | |
875 | } | |
876 | #endif | |
877 | ||
878 | int 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); | |
259e1012 PF |
884 | |
885 | if (IS_ENABLED(CONFIG_IMX93) && | |
886 | IS_ENABLED(CONFIG_FEC_MXC) && | |
887 | device_is_compatible(dev, "fsl,imx93-fec")) | |
888 | return 0; | |
d5eae216 SS |
889 | |
890 | return -EINVAL; | |
891 | } | |
892 | ||
f79c1626 PF |
893 | int set_clk_enet(enum enet_freq type) |
894 | { | |
895 | u32 div; | |
896 | ||
897 | /* disable the clock first */ | |
898 | ccm_lpcg_on(CCGR_ENET1, false); | |
899 | ||
900 | switch (type) { | |
901 | case ENET_125MHZ: | |
902 | div = 2; /* 250Mhz */ | |
903 | break; | |
904 | case ENET_50MHZ: | |
905 | div = 5; /* 100Mhz */ | |
906 | break; | |
907 | case ENET_25MHZ: | |
908 | div = 10; /* 50Mhz */ | |
909 | break; | |
910 | default: | |
911 | return -EINVAL; | |
912 | } | |
913 | ||
914 | ccm_clk_root_cfg(ENET_REF_CLK_ROOT, SYS_PLL_PFD0_DIV2, div); | |
915 | ccm_clk_root_cfg(ENET_TIMER1_CLK_ROOT, SYS_PLL_PFD0_DIV2, 5); | |
916 | ||
917 | #ifdef CONFIG_FEC_MXC_25M_REF_CLK | |
918 | ccm_clk_root_cfg(ENET_REF_PHY_CLK_ROOT, SYS_PLL_PFD0_DIV2, 20); | |
919 | #endif | |
920 | ||
921 | /* enable clock */ | |
922 | ccm_lpcg_on(CCGR_ENET1, true); | |
923 | ||
924 | return 0; | |
925 | } | |
926 | ||
927 | /* | |
928 | * Dump some clockes. | |
929 | */ | |
930 | #ifndef CONFIG_SPL_BUILD | |
931 | int do_showclocks(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) | |
932 | { | |
933 | u32 freq; | |
934 | ||
935 | freq = decode_pll(ARM_PLL_CLK); | |
936 | printf("ARM_PLL %8d MHz\n", freq / 1000); | |
937 | freq = decode_pll(DRAM_PLL_CLK); | |
938 | printf("DRAM_PLL %8d MHz\n", freq / 1000); | |
939 | freq = decode_pll(SYS_PLL_PFD0); | |
940 | printf("SYS_PLL_PFD0 %8d MHz\n", freq / 1000); | |
941 | freq = decode_pll(SYS_PLL_PFD0_DIV2); | |
942 | printf("SYS_PLL_PFD0_DIV2 %8d MHz\n", freq / 1000); | |
943 | freq = decode_pll(SYS_PLL_PFD1); | |
944 | printf("SYS_PLL_PFD1 %8d MHz\n", freq / 1000); | |
945 | freq = decode_pll(SYS_PLL_PFD1_DIV2); | |
946 | printf("SYS_PLL_PFD1_DIV2 %8d MHz\n", freq / 1000); | |
947 | freq = decode_pll(SYS_PLL_PFD2); | |
948 | printf("SYS_PLL_PFD2 %8d MHz\n", freq / 1000); | |
949 | freq = decode_pll(SYS_PLL_PFD2_DIV2); | |
950 | printf("SYS_PLL_PFD2_DIV2 %8d MHz\n", freq / 1000); | |
951 | freq = mxc_get_clock(MXC_ARM_CLK); | |
952 | printf("ARM CORE %8d MHz\n", freq / 1000000); | |
953 | freq = mxc_get_clock(MXC_IPG_CLK); | |
954 | printf("IPG %8d MHz\n", freq / 1000000); | |
955 | freq = mxc_get_clock(MXC_UART_CLK); | |
956 | printf("UART3 %8d MHz\n", freq / 1000000); | |
957 | freq = mxc_get_clock(MXC_ESDHC_CLK); | |
958 | printf("USDHC1 %8d MHz\n", freq / 1000000); | |
959 | freq = mxc_get_clock(MXC_FLEXSPI_CLK); | |
960 | printf("FLEXSPI %8d MHz\n", freq / 1000000); | |
961 | ||
962 | return 0; | |
963 | } | |
964 | ||
965 | U_BOOT_CMD( | |
966 | clocks, CONFIG_SYS_MAXARGS, 1, do_showclocks, | |
967 | "display clocks", | |
968 | "" | |
969 | ); | |
970 | #endif |