blob: 47219957b58c028ba46f438cd3fa966832636544 [file] [log] [blame]
Peng Fan99878462019-08-27 06:25:51 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018-2019 NXP
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
7
8#include <common.h>
9#include <asm/arch/clock.h>
10#include <asm/arch/imx-regs.h>
11#include <asm/arch/sys_proto.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060012#include <asm/global_data.h>
Peng Fan99878462019-08-27 06:25:51 +000013#include <asm/io.h>
Peng Fan99878462019-08-27 06:25:51 +000014#include <div64.h>
15#include <errno.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060017#include <linux/delay.h>
Marek Vasute6576952023-03-06 15:53:49 +010018#include <phy.h>
Peng Fan99878462019-08-27 06:25:51 +000019
20DECLARE_GLOBAL_DATA_PTR;
21
22static struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR;
23
Peng Fan4e36e332020-07-09 11:06:24 +080024static u32 get_root_clk(enum clk_root_index clock_id);
Ye Liebabd8d2021-03-25 17:30:17 +080025
26#ifdef CONFIG_IMX_HAB
27void hab_caam_clock_enable(unsigned char enable)
28{
29 /* The CAAM clock is always on for iMX8M */
30}
31#endif
32
Peng Fan99878462019-08-27 06:25:51 +000033void enable_ocotp_clk(unsigned char enable)
34{
Peng Fan60c29bb2019-12-30 16:52:30 +080035 clock_enable(CCGR_OCOTP, !!enable);
Peng Fan99878462019-08-27 06:25:51 +000036}
37
38int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
39{
Rasmus Villemoes791c43d2023-03-22 15:42:05 +010040 u8 i2c_ccgr[] = {
Martyn Welchc445dc42022-10-25 10:54:59 +010041 CCGR_I2C1, CCGR_I2C2, CCGR_I2C3, CCGR_I2C4,
42#if (IS_ENABLED(CONFIG_IMX8MP))
43 CCGR_I2C5_8MP, CCGR_I2C6_8MP
44#endif
45 };
46
Rasmus Villemoes791c43d2023-03-22 15:42:05 +010047 if (i2c_num >= ARRAY_SIZE(i2c_ccgr))
Peng Fan60c29bb2019-12-30 16:52:30 +080048 return -EINVAL;
Peng Fan99878462019-08-27 06:25:51 +000049
Martyn Welchc445dc42022-10-25 10:54:59 +010050 clock_enable(i2c_ccgr[i2c_num], !!enable);
Peng Fan99878462019-08-27 06:25:51 +000051
Peng Fan60c29bb2019-12-30 16:52:30 +080052 return 0;
Peng Fan99878462019-08-27 06:25:51 +000053}
54
55#ifdef CONFIG_SPL_BUILD
56static struct imx_int_pll_rate_table imx8mm_fracpll_tbl[] = {
Peng Fand29bf222019-12-27 11:40:55 +080057 PLL_1443X_RATE(1000000000U, 250, 3, 1, 0),
Marek Vasutc5eab902022-02-26 04:37:41 +010058 PLL_1443X_RATE(933000000U, 311, 4, 1, 0),
Marek Vasut471211e2023-12-02 02:48:40 +010059 PLL_1443X_RATE(900000000U, 300, 8, 0, 0),
Peng Fan99878462019-08-27 06:25:51 +000060 PLL_1443X_RATE(800000000U, 300, 9, 0, 0),
61 PLL_1443X_RATE(750000000U, 250, 8, 0, 0),
62 PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
63 PLL_1443X_RATE(600000000U, 300, 3, 2, 0),
64 PLL_1443X_RATE(594000000U, 99, 1, 2, 0),
65 PLL_1443X_RATE(400000000U, 300, 9, 1, 0),
Andrey Zhizhikin09786cd2021-05-03 09:59:17 +020066 PLL_1443X_RATE(266000000U, 400, 9, 2, 0),
Peng Fan99878462019-08-27 06:25:51 +000067 PLL_1443X_RATE(167000000U, 334, 3, 4, 0),
68 PLL_1443X_RATE(100000000U, 300, 9, 3, 0),
69};
70
Alifer Moraes39931102020-01-14 15:54:59 -030071static int fracpll_configure(enum pll_clocks pll, u32 freq)
Peng Fan99878462019-08-27 06:25:51 +000072{
73 int i;
74 u32 tmp, div_val;
75 void *pll_base;
76 struct imx_int_pll_rate_table *rate;
77
78 for (i = 0; i < ARRAY_SIZE(imx8mm_fracpll_tbl); i++) {
79 if (freq == imx8mm_fracpll_tbl[i].rate)
80 break;
81 }
82
83 if (i == ARRAY_SIZE(imx8mm_fracpll_tbl)) {
Andrey Zhizhikin367ca322021-05-03 10:02:10 +020084 printf("%s: No matched freq table %u\n", __func__, freq);
Peng Fan99878462019-08-27 06:25:51 +000085 return -EINVAL;
86 }
87
88 rate = &imx8mm_fracpll_tbl[i];
89
90 switch (pll) {
91 case ANATOP_DRAM_PLL:
92 setbits_le32(GPC_BASE_ADDR + 0xEC, 1 << 7);
93 setbits_le32(GPC_BASE_ADDR + 0xF8, 1 << 5);
Peng Fan99878462019-08-27 06:25:51 +000094
95 pll_base = &ana_pll->dram_pll_gnrl_ctl;
96 break;
97 case ANATOP_VIDEO_PLL:
98 pll_base = &ana_pll->video_pll1_gnrl_ctl;
99 break;
100 default:
101 return 0;
102 }
103 /* Bypass clock and set lock to pll output lock */
104 tmp = readl(pll_base);
105 tmp |= BYPASS_MASK;
106 writel(tmp, pll_base);
107
108 /* Enable RST */
109 tmp &= ~RST_MASK;
110 writel(tmp, pll_base);
111
112 div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
113 (rate->sdiv << SDIV_SHIFT);
114 writel(div_val, pll_base + 4);
115 writel(rate->kdiv << KDIV_SHIFT, pll_base + 8);
116
117 __udelay(100);
118
119 /* Disable RST */
120 tmp |= RST_MASK;
121 writel(tmp, pll_base);
122
123 /* Wait Lock*/
124 while (!(readl(pll_base) & LOCK_STATUS))
125 ;
126
127 /* Bypass */
128 tmp &= ~BYPASS_MASK;
129 writel(tmp, pll_base);
130
131 return 0;
132}
133
134void dram_pll_init(ulong pll_val)
135{
136 fracpll_configure(ANATOP_DRAM_PLL, pll_val);
137}
138
139static struct dram_bypass_clk_setting imx8mm_dram_bypass_tbl[] = {
140 DRAM_BYPASS_ROOT_CONFIG(MHZ(100), 2, CLK_ROOT_PRE_DIV1, 2,
141 CLK_ROOT_PRE_DIV2),
142 DRAM_BYPASS_ROOT_CONFIG(MHZ(250), 3, CLK_ROOT_PRE_DIV2, 2,
143 CLK_ROOT_PRE_DIV2),
144 DRAM_BYPASS_ROOT_CONFIG(MHZ(400), 1, CLK_ROOT_PRE_DIV2, 3,
145 CLK_ROOT_PRE_DIV2),
146};
147
148void dram_enable_bypass(ulong clk_val)
149{
150 int i;
151 struct dram_bypass_clk_setting *config;
152
153 for (i = 0; i < ARRAY_SIZE(imx8mm_dram_bypass_tbl); i++) {
154 if (clk_val == imx8mm_dram_bypass_tbl[i].clk)
155 break;
156 }
157
158 if (i == ARRAY_SIZE(imx8mm_dram_bypass_tbl)) {
Andrey Zhizhikin367ca322021-05-03 10:02:10 +0200159 printf("%s: No matched freq table %lu\n", __func__, clk_val);
Peng Fan99878462019-08-27 06:25:51 +0000160 return;
161 }
162
163 config = &imx8mm_dram_bypass_tbl[i];
164
165 clock_set_target_val(DRAM_ALT_CLK_ROOT, CLK_ROOT_ON |
166 CLK_ROOT_SOURCE_SEL(config->alt_root_sel) |
167 CLK_ROOT_PRE_DIV(config->alt_pre_div));
168 clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
169 CLK_ROOT_SOURCE_SEL(config->apb_root_sel) |
170 CLK_ROOT_PRE_DIV(config->apb_pre_div));
171 clock_set_target_val(DRAM_SEL_CFG, CLK_ROOT_ON |
172 CLK_ROOT_SOURCE_SEL(1));
173}
174
175void dram_disable_bypass(void)
176{
177 clock_set_target_val(DRAM_SEL_CFG, CLK_ROOT_ON |
178 CLK_ROOT_SOURCE_SEL(0));
179 clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
180 CLK_ROOT_SOURCE_SEL(4) |
181 CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV5));
182}
183#endif
184
Peng Fan4e36e332020-07-09 11:06:24 +0800185int intpll_configure(enum pll_clocks pll, ulong freq)
186{
187 void __iomem *pll_gnrl_ctl, __iomem *pll_div_ctl;
188 u32 pll_div_ctl_val, pll_clke_masks;
189
190 switch (pll) {
191 case ANATOP_SYSTEM_PLL1:
192 pll_gnrl_ctl = &ana_pll->sys_pll1_gnrl_ctl;
193 pll_div_ctl = &ana_pll->sys_pll1_div_ctl;
194 pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
195 INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
196 INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
197 INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
198 INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
199 break;
200 case ANATOP_SYSTEM_PLL2:
201 pll_gnrl_ctl = &ana_pll->sys_pll2_gnrl_ctl;
202 pll_div_ctl = &ana_pll->sys_pll2_div_ctl;
203 pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
204 INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
205 INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
206 INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
207 INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
208 break;
209 case ANATOP_SYSTEM_PLL3:
210 pll_gnrl_ctl = &ana_pll->sys_pll3_gnrl_ctl;
211 pll_div_ctl = &ana_pll->sys_pll3_div_ctl;
212 pll_clke_masks = INTPLL_CLKE_MASK;
213 break;
214 case ANATOP_ARM_PLL:
215 pll_gnrl_ctl = &ana_pll->arm_pll_gnrl_ctl;
216 pll_div_ctl = &ana_pll->arm_pll_div_ctl;
217 pll_clke_masks = INTPLL_CLKE_MASK;
218 break;
219 case ANATOP_GPU_PLL:
220 pll_gnrl_ctl = &ana_pll->gpu_pll_gnrl_ctl;
221 pll_div_ctl = &ana_pll->gpu_pll_div_ctl;
222 pll_clke_masks = INTPLL_CLKE_MASK;
223 break;
224 case ANATOP_VPU_PLL:
225 pll_gnrl_ctl = &ana_pll->vpu_pll_gnrl_ctl;
226 pll_div_ctl = &ana_pll->vpu_pll_div_ctl;
227 pll_clke_masks = INTPLL_CLKE_MASK;
228 break;
229 default:
230 return -EINVAL;
231 };
232
233 switch (freq) {
234 case MHZ(600):
235 /* 24 * 0x12c / 3 / 2 ^ 2 */
236 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x12c) |
237 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(2);
238 break;
239 case MHZ(750):
240 /* 24 * 0xfa / 2 / 2 ^ 2 */
241 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
242 INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(2);
243 break;
244 case MHZ(800):
245 /* 24 * 0x190 / 3 / 2 ^ 2 */
246 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x190) |
247 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(2);
248 break;
249 case MHZ(1000):
250 /* 24 * 0xfa / 3 / 2 ^ 1 */
251 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
252 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1);
253 break;
254 case MHZ(1200):
Marek Vasutd2578f22022-01-25 03:48:05 +0100255 /* 24 * 0x12c / 3 / 2 ^ 1 */
256 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x12c) |
257 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1);
Peng Fan4e36e332020-07-09 11:06:24 +0800258 break;
Marek Vasutd376a502022-01-25 03:48:06 +0100259 case MHZ(1400):
260 /* 24 * 0x15e / 3 / 2 ^ 1 */
261 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x15e) |
262 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1);
263 break;
264 case MHZ(1500):
265 /* 24 * 0x177 / 3 / 2 ^ 1 */
266 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x177) |
267 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1);
268 break;
269 case MHZ(1600):
270 /* 24 * 0xc8 / 3 / 2 ^ 0 */
271 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xc8) |
272 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0);
273 break;
274 case MHZ(1800):
275 /* 24 * 0xe1 / 3 / 2 ^ 0 */
276 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xe1) |
277 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0);
278 break;
Peng Fan4e36e332020-07-09 11:06:24 +0800279 case MHZ(2000):
280 /* 24 * 0xfa / 3 / 2 ^ 0 */
281 pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
282 INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0);
283 break;
284 default:
285 return -EINVAL;
286 };
287 /* Bypass clock and set lock to pll output lock */
288 setbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK | INTPLL_LOCK_SEL_MASK);
289 /* Enable reset */
290 clrbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
291 /* Configure */
292 writel(pll_div_ctl_val, pll_div_ctl);
293
294 __udelay(100);
295
296 /* Disable reset */
297 setbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
298 /* Wait Lock */
299 while (!(readl(pll_gnrl_ctl) & INTPLL_LOCK_MASK))
300 ;
301 /* Clear bypass */
302 clrbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK);
303 setbits_le32(pll_gnrl_ctl, pll_clke_masks);
304
305 return 0;
306}
307
Peng Fan99878462019-08-27 06:25:51 +0000308void init_uart_clk(u32 index)
309{
310 /*
311 * set uart clock root
312 * 24M OSC
313 */
314 switch (index) {
315 case 0:
316 clock_enable(CCGR_UART1, 0);
317 clock_set_target_val(UART1_CLK_ROOT, CLK_ROOT_ON |
318 CLK_ROOT_SOURCE_SEL(0));
319 clock_enable(CCGR_UART1, 1);
320 return;
321 case 1:
322 clock_enable(CCGR_UART2, 0);
323 clock_set_target_val(UART2_CLK_ROOT, CLK_ROOT_ON |
324 CLK_ROOT_SOURCE_SEL(0));
325 clock_enable(CCGR_UART2, 1);
326 return;
327 case 2:
328 clock_enable(CCGR_UART3, 0);
329 clock_set_target_val(UART3_CLK_ROOT, CLK_ROOT_ON |
330 CLK_ROOT_SOURCE_SEL(0));
331 clock_enable(CCGR_UART3, 1);
332 return;
333 case 3:
334 clock_enable(CCGR_UART4, 0);
335 clock_set_target_val(UART4_CLK_ROOT, CLK_ROOT_ON |
336 CLK_ROOT_SOURCE_SEL(0));
337 clock_enable(CCGR_UART4, 1);
338 return;
339 default:
340 printf("Invalid uart index\n");
341 return;
342 }
343}
344
345void init_wdog_clk(void)
346{
347 clock_enable(CCGR_WDOG1, 0);
348 clock_enable(CCGR_WDOG2, 0);
349 clock_enable(CCGR_WDOG3, 0);
350 clock_set_target_val(WDOG_CLK_ROOT, CLK_ROOT_ON |
351 CLK_ROOT_SOURCE_SEL(0));
352 clock_enable(CCGR_WDOG1, 1);
353 clock_enable(CCGR_WDOG2, 1);
354 clock_enable(CCGR_WDOG3, 1);
355}
356
Peng Fanc61ec9b2020-07-09 11:35:15 +0800357void init_clk_usdhc(u32 index)
358{
359 /*
360 * set usdhc clock root
361 * sys pll1 400M
362 */
363 switch (index) {
364 case 0:
365 clock_enable(CCGR_USDHC1, 0);
366 clock_set_target_val(USDHC1_CLK_ROOT, CLK_ROOT_ON |
367 CLK_ROOT_SOURCE_SEL(1));
368 clock_enable(CCGR_USDHC1, 1);
369 return;
370 case 1:
371 clock_enable(CCGR_USDHC2, 0);
372 clock_set_target_val(USDHC2_CLK_ROOT, CLK_ROOT_ON |
373 CLK_ROOT_SOURCE_SEL(1));
374 clock_enable(CCGR_USDHC2, 1);
375 return;
376 case 2:
377 clock_enable(CCGR_USDHC3, 0);
378 clock_set_target_val(USDHC3_CLK_ROOT, CLK_ROOT_ON |
379 CLK_ROOT_SOURCE_SEL(1));
380 clock_enable(CCGR_USDHC3, 1);
381 return;
382 default:
383 printf("Invalid usdhc index\n");
384 return;
385 }
386}
387
388void init_clk_ecspi(u32 index)
389{
390 switch (index) {
391 case 0:
392 clock_enable(CCGR_ECSPI1, 0);
393 clock_set_target_val(ECSPI1_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(0));
394 clock_enable(CCGR_ECSPI1, 1);
395 return;
396 case 1:
397 clock_enable(CCGR_ECSPI2, 0);
398 clock_set_target_val(ECSPI2_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(0));
399 clock_enable(CCGR_ECSPI2, 1);
Peng Fan016c2512020-09-16 15:17:21 +0800400 return;
Peng Fanc61ec9b2020-07-09 11:35:15 +0800401 case 2:
402 clock_enable(CCGR_ECSPI3, 0);
403 clock_set_target_val(ECSPI3_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(0));
404 clock_enable(CCGR_ECSPI3, 1);
405 return;
406 default:
407 printf("Invalid ecspi index\n");
408 return;
409 }
410}
411
412void init_nand_clk(void)
413{
414 /*
415 * set rawnand root
416 * sys pll1 400M
417 */
418 clock_enable(CCGR_RAWNAND, 0);
419 clock_set_target_val(NAND_CLK_ROOT, CLK_ROOT_ON |
420 CLK_ROOT_SOURCE_SEL(3) | CLK_ROOT_POST_DIV(CLK_ROOT_POST_DIV4)); /* 100M */
421 clock_enable(CCGR_RAWNAND, 1);
422}
423
Peng Fan99878462019-08-27 06:25:51 +0000424int clock_init(void)
425{
426 u32 val_cfg0;
427
428 /*
429 * The gate is not exported to clk tree, so configure them here.
430 * According to ANAMIX SPEC
431 * sys pll1 fixed at 800MHz
432 * sys pll2 fixed at 1GHz
433 * Here we only enable the outputs.
434 */
435 val_cfg0 = readl(&ana_pll->sys_pll1_gnrl_ctl);
436 val_cfg0 |= INTPLL_CLKE_MASK | INTPLL_DIV2_CLKE_MASK |
437 INTPLL_DIV3_CLKE_MASK | INTPLL_DIV4_CLKE_MASK |
438 INTPLL_DIV5_CLKE_MASK | INTPLL_DIV6_CLKE_MASK |
439 INTPLL_DIV8_CLKE_MASK | INTPLL_DIV10_CLKE_MASK |
440 INTPLL_DIV20_CLKE_MASK;
441 writel(val_cfg0, &ana_pll->sys_pll1_gnrl_ctl);
442
443 val_cfg0 = readl(&ana_pll->sys_pll2_gnrl_ctl);
444 val_cfg0 |= INTPLL_CLKE_MASK | INTPLL_DIV2_CLKE_MASK |
445 INTPLL_DIV3_CLKE_MASK | INTPLL_DIV4_CLKE_MASK |
446 INTPLL_DIV5_CLKE_MASK | INTPLL_DIV6_CLKE_MASK |
447 INTPLL_DIV8_CLKE_MASK | INTPLL_DIV10_CLKE_MASK |
448 INTPLL_DIV20_CLKE_MASK;
449 writel(val_cfg0, &ana_pll->sys_pll2_gnrl_ctl);
450
Peng Fan4e36e332020-07-09 11:06:24 +0800451 /* Configure ARM at 1.2GHz */
452 clock_set_target_val(ARM_A53_CLK_ROOT, CLK_ROOT_ON |
453 CLK_ROOT_SOURCE_SEL(2));
454
455 intpll_configure(ANATOP_ARM_PLL, MHZ(1200));
456
457 /* Bypass CCM A53 ROOT, Switch to ARM PLL -> MUX-> CPU */
458 clock_set_target_val(CORE_SEL_CFG, CLK_ROOT_SOURCE_SEL(1));
459
Peng Fane5653932020-07-09 11:18:50 +0800460 if (is_imx8mn() || is_imx8mp())
461 intpll_configure(ANATOP_SYSTEM_PLL3, MHZ(600));
462 else
463 intpll_configure(ANATOP_SYSTEM_PLL3, MHZ(750));
464
465#ifdef CONFIG_IMX8MP
466 /* 8MP ROM already set NOC to 800Mhz, only need to configure NOC_IO clk to 600Mhz */
467 /* 8MP ROM already set GIC to 400Mhz, system_pll1_800m with div = 2 */
468 clock_set_target_val(NOC_IO_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(2));
469#else
470 clock_set_target_val(NOC_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(2));
471
Peng Fan99878462019-08-27 06:25:51 +0000472 /* config GIC to sys_pll2_100m */
473 clock_enable(CCGR_GIC, 0);
474 clock_set_target_val(GIC_CLK_ROOT, CLK_ROOT_ON |
475 CLK_ROOT_SOURCE_SEL(3));
476 clock_enable(CCGR_GIC, 1);
Peng Fane5653932020-07-09 11:18:50 +0800477#endif
Peng Fan99878462019-08-27 06:25:51 +0000478
479 clock_set_target_val(NAND_USDHC_BUS_CLK_ROOT, CLK_ROOT_ON |
480 CLK_ROOT_SOURCE_SEL(1));
481
482 clock_enable(CCGR_DDR1, 0);
483 clock_set_target_val(DRAM_ALT_CLK_ROOT, CLK_ROOT_ON |
484 CLK_ROOT_SOURCE_SEL(1));
485 clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
486 CLK_ROOT_SOURCE_SEL(1));
487 clock_enable(CCGR_DDR1, 1);
488
489 init_wdog_clk();
490
491 clock_enable(CCGR_TEMP_SENSOR, 1);
492
493 clock_enable(CCGR_SEC_DEBUG, 1);
494
495 return 0;
496};
497
498u32 imx_get_uartclk(void)
499{
500 return 24000000U;
501}
502
Alifer Moraes39931102020-01-14 15:54:59 -0300503static u32 decode_intpll(enum clk_root_src intpll)
Peng Fan60c29bb2019-12-30 16:52:30 +0800504{
505 u32 pll_gnrl_ctl, pll_div_ctl, pll_clke_mask;
506 u32 main_div, pre_div, post_div, div;
507 u64 freq;
508
509 switch (intpll) {
510 case ARM_PLL_CLK:
511 pll_gnrl_ctl = readl(&ana_pll->arm_pll_gnrl_ctl);
512 pll_div_ctl = readl(&ana_pll->arm_pll_div_ctl);
513 break;
514 case GPU_PLL_CLK:
515 pll_gnrl_ctl = readl(&ana_pll->gpu_pll_gnrl_ctl);
516 pll_div_ctl = readl(&ana_pll->gpu_pll_div_ctl);
517 break;
518 case VPU_PLL_CLK:
519 pll_gnrl_ctl = readl(&ana_pll->vpu_pll_gnrl_ctl);
520 pll_div_ctl = readl(&ana_pll->vpu_pll_div_ctl);
521 break;
522 case SYSTEM_PLL1_800M_CLK:
523 case SYSTEM_PLL1_400M_CLK:
524 case SYSTEM_PLL1_266M_CLK:
525 case SYSTEM_PLL1_200M_CLK:
526 case SYSTEM_PLL1_160M_CLK:
527 case SYSTEM_PLL1_133M_CLK:
528 case SYSTEM_PLL1_100M_CLK:
529 case SYSTEM_PLL1_80M_CLK:
530 case SYSTEM_PLL1_40M_CLK:
531 pll_gnrl_ctl = readl(&ana_pll->sys_pll1_gnrl_ctl);
532 pll_div_ctl = readl(&ana_pll->sys_pll1_div_ctl);
533 break;
534 case SYSTEM_PLL2_1000M_CLK:
535 case SYSTEM_PLL2_500M_CLK:
536 case SYSTEM_PLL2_333M_CLK:
537 case SYSTEM_PLL2_250M_CLK:
538 case SYSTEM_PLL2_200M_CLK:
539 case SYSTEM_PLL2_166M_CLK:
540 case SYSTEM_PLL2_125M_CLK:
541 case SYSTEM_PLL2_100M_CLK:
542 case SYSTEM_PLL2_50M_CLK:
543 pll_gnrl_ctl = readl(&ana_pll->sys_pll2_gnrl_ctl);
544 pll_div_ctl = readl(&ana_pll->sys_pll2_div_ctl);
545 break;
546 case SYSTEM_PLL3_CLK:
547 pll_gnrl_ctl = readl(&ana_pll->sys_pll3_gnrl_ctl);
548 pll_div_ctl = readl(&ana_pll->sys_pll3_div_ctl);
549 break;
550 default:
551 return -EINVAL;
552 }
553
554 /* Only support SYS_XTAL 24M, PAD_CLK not take into consideration */
555 if ((pll_gnrl_ctl & INTPLL_REF_CLK_SEL_MASK) != 0)
556 return 0;
557
558 if ((pll_gnrl_ctl & INTPLL_RST_MASK) == 0)
559 return 0;
560
561 /*
562 * When BYPASS is equal to 1, PLL enters the bypass mode
563 * regardless of the values of RESETB
564 */
565 if (pll_gnrl_ctl & INTPLL_BYPASS_MASK)
566 return 24000000u;
567
568 if (!(pll_gnrl_ctl & INTPLL_LOCK_MASK)) {
569 puts("pll not locked\n");
570 return 0;
571 }
572
573 switch (intpll) {
574 case ARM_PLL_CLK:
575 case GPU_PLL_CLK:
576 case VPU_PLL_CLK:
577 case SYSTEM_PLL3_CLK:
578 case SYSTEM_PLL1_800M_CLK:
579 case SYSTEM_PLL2_1000M_CLK:
580 pll_clke_mask = INTPLL_CLKE_MASK;
581 div = 1;
582 break;
583
584 case SYSTEM_PLL1_400M_CLK:
585 case SYSTEM_PLL2_500M_CLK:
586 pll_clke_mask = INTPLL_DIV2_CLKE_MASK;
587 div = 2;
588 break;
589
590 case SYSTEM_PLL1_266M_CLK:
591 case SYSTEM_PLL2_333M_CLK:
592 pll_clke_mask = INTPLL_DIV3_CLKE_MASK;
593 div = 3;
594 break;
595
596 case SYSTEM_PLL1_200M_CLK:
597 case SYSTEM_PLL2_250M_CLK:
598 pll_clke_mask = INTPLL_DIV4_CLKE_MASK;
599 div = 4;
600 break;
601
602 case SYSTEM_PLL1_160M_CLK:
603 case SYSTEM_PLL2_200M_CLK:
604 pll_clke_mask = INTPLL_DIV5_CLKE_MASK;
605 div = 5;
606 break;
607
608 case SYSTEM_PLL1_133M_CLK:
609 case SYSTEM_PLL2_166M_CLK:
610 pll_clke_mask = INTPLL_DIV6_CLKE_MASK;
611 div = 6;
612 break;
613
614 case SYSTEM_PLL1_100M_CLK:
615 case SYSTEM_PLL2_125M_CLK:
616 pll_clke_mask = INTPLL_DIV8_CLKE_MASK;
617 div = 8;
618 break;
619
620 case SYSTEM_PLL1_80M_CLK:
621 case SYSTEM_PLL2_100M_CLK:
622 pll_clke_mask = INTPLL_DIV10_CLKE_MASK;
623 div = 10;
624 break;
625
626 case SYSTEM_PLL1_40M_CLK:
627 case SYSTEM_PLL2_50M_CLK:
628 pll_clke_mask = INTPLL_DIV20_CLKE_MASK;
629 div = 20;
630 break;
631 default:
632 return -EINVAL;
633 }
634
635 if ((pll_gnrl_ctl & pll_clke_mask) == 0)
636 return 0;
637
638 main_div = (pll_div_ctl & INTPLL_MAIN_DIV_MASK) >>
639 INTPLL_MAIN_DIV_SHIFT;
640 pre_div = (pll_div_ctl & INTPLL_PRE_DIV_MASK) >>
641 INTPLL_PRE_DIV_SHIFT;
642 post_div = (pll_div_ctl & INTPLL_POST_DIV_MASK) >>
643 INTPLL_POST_DIV_SHIFT;
644
645 /* FFVCO = (m * FFIN) / p, FFOUT = (m * FFIN) / (p * 2^s) */
646 freq = 24000000ULL * main_div;
647 return lldiv(freq, pre_div * (1 << post_div) * div);
648}
649
Alifer Moraes39931102020-01-14 15:54:59 -0300650static u32 decode_fracpll(enum clk_root_src frac_pll)
Peng Fan60c29bb2019-12-30 16:52:30 +0800651{
652 u32 pll_gnrl_ctl, pll_fdiv_ctl0, pll_fdiv_ctl1;
653 u32 main_div, pre_div, post_div, k;
654
655 switch (frac_pll) {
656 case DRAM_PLL1_CLK:
657 pll_gnrl_ctl = readl(&ana_pll->dram_pll_gnrl_ctl);
658 pll_fdiv_ctl0 = readl(&ana_pll->dram_pll_fdiv_ctl0);
659 pll_fdiv_ctl1 = readl(&ana_pll->dram_pll_fdiv_ctl1);
660 break;
661 case AUDIO_PLL1_CLK:
662 pll_gnrl_ctl = readl(&ana_pll->audio_pll1_gnrl_ctl);
663 pll_fdiv_ctl0 = readl(&ana_pll->audio_pll1_fdiv_ctl0);
664 pll_fdiv_ctl1 = readl(&ana_pll->audio_pll1_fdiv_ctl1);
665 break;
666 case AUDIO_PLL2_CLK:
667 pll_gnrl_ctl = readl(&ana_pll->audio_pll2_gnrl_ctl);
668 pll_fdiv_ctl0 = readl(&ana_pll->audio_pll2_fdiv_ctl0);
669 pll_fdiv_ctl1 = readl(&ana_pll->audio_pll2_fdiv_ctl1);
670 break;
671 case VIDEO_PLL_CLK:
672 pll_gnrl_ctl = readl(&ana_pll->video_pll1_gnrl_ctl);
673 pll_fdiv_ctl0 = readl(&ana_pll->video_pll1_fdiv_ctl0);
674 pll_fdiv_ctl1 = readl(&ana_pll->video_pll1_fdiv_ctl1);
675 break;
676 default:
Andrey Zhizhikin367ca322021-05-03 10:02:10 +0200677 printf("Unsupported clk_root_src %d\n", frac_pll);
Peng Fan60c29bb2019-12-30 16:52:30 +0800678 return 0;
679 }
680
681 /* Only support SYS_XTAL 24M, PAD_CLK not take into consideration */
Ye Licc643ea2020-03-23 19:54:29 -0700682 if ((pll_gnrl_ctl & GENMASK(1, 0)) != 0)
Peng Fan60c29bb2019-12-30 16:52:30 +0800683 return 0;
684
Ye Licc643ea2020-03-23 19:54:29 -0700685 if ((pll_gnrl_ctl & RST_MASK) == 0)
Peng Fan60c29bb2019-12-30 16:52:30 +0800686 return 0;
687 /*
688 * When BYPASS is equal to 1, PLL enters the bypass mode
689 * regardless of the values of RESETB
690 */
Ye Licc643ea2020-03-23 19:54:29 -0700691 if (pll_gnrl_ctl & BYPASS_MASK)
Peng Fan60c29bb2019-12-30 16:52:30 +0800692 return 24000000u;
693
Ye Licc643ea2020-03-23 19:54:29 -0700694 if (!(pll_gnrl_ctl & LOCK_STATUS)) {
Peng Fan60c29bb2019-12-30 16:52:30 +0800695 puts("pll not locked\n");
696 return 0;
697 }
698
Ye Licc643ea2020-03-23 19:54:29 -0700699 if (!(pll_gnrl_ctl & CLKE_MASK))
Peng Fan60c29bb2019-12-30 16:52:30 +0800700 return 0;
701
Ye Licc643ea2020-03-23 19:54:29 -0700702 main_div = (pll_fdiv_ctl0 & MDIV_MASK) >>
703 MDIV_SHIFT;
704 pre_div = (pll_fdiv_ctl0 & PDIV_MASK) >>
705 PDIV_SHIFT;
706 post_div = (pll_fdiv_ctl0 & SDIV_MASK) >>
707 SDIV_SHIFT;
Peng Fan60c29bb2019-12-30 16:52:30 +0800708
Ye Licc643ea2020-03-23 19:54:29 -0700709 k = pll_fdiv_ctl1 & KDIV_MASK;
Peng Fan60c29bb2019-12-30 16:52:30 +0800710
711 return lldiv((main_div * 65536 + k) * 24000000ULL,
712 65536 * pre_div * (1 << post_div));
713}
714
Alifer Moraes39931102020-01-14 15:54:59 -0300715static u32 get_root_src_clk(enum clk_root_src root_src)
Peng Fan60c29bb2019-12-30 16:52:30 +0800716{
717 switch (root_src) {
718 case OSC_24M_CLK:
719 return 24000000u;
720 case OSC_HDMI_CLK:
721 return 26000000u;
722 case OSC_32K_CLK:
723 return 32000u;
724 case ARM_PLL_CLK:
725 case GPU_PLL_CLK:
726 case VPU_PLL_CLK:
727 case SYSTEM_PLL1_800M_CLK:
728 case SYSTEM_PLL1_400M_CLK:
729 case SYSTEM_PLL1_266M_CLK:
730 case SYSTEM_PLL1_200M_CLK:
731 case SYSTEM_PLL1_160M_CLK:
732 case SYSTEM_PLL1_133M_CLK:
733 case SYSTEM_PLL1_100M_CLK:
734 case SYSTEM_PLL1_80M_CLK:
735 case SYSTEM_PLL1_40M_CLK:
736 case SYSTEM_PLL2_1000M_CLK:
737 case SYSTEM_PLL2_500M_CLK:
738 case SYSTEM_PLL2_333M_CLK:
739 case SYSTEM_PLL2_250M_CLK:
740 case SYSTEM_PLL2_200M_CLK:
741 case SYSTEM_PLL2_166M_CLK:
742 case SYSTEM_PLL2_125M_CLK:
743 case SYSTEM_PLL2_100M_CLK:
744 case SYSTEM_PLL2_50M_CLK:
745 case SYSTEM_PLL3_CLK:
746 return decode_intpll(root_src);
747 case DRAM_PLL1_CLK:
748 case AUDIO_PLL1_CLK:
749 case AUDIO_PLL2_CLK:
750 case VIDEO_PLL_CLK:
751 return decode_fracpll(root_src);
Peng Fan4e36e332020-07-09 11:06:24 +0800752 case ARM_A53_ALT_CLK:
753 return get_root_clk(ARM_A53_CLK_ROOT);
Peng Fan60c29bb2019-12-30 16:52:30 +0800754 default:
755 return 0;
756 }
757
758 return 0;
759}
760
Alifer Moraes39931102020-01-14 15:54:59 -0300761static u32 get_root_clk(enum clk_root_index clock_id)
Peng Fan60c29bb2019-12-30 16:52:30 +0800762{
763 enum clk_root_src root_src;
764 u32 post_podf, pre_podf, root_src_clk;
765
766 if (clock_root_enabled(clock_id) <= 0)
767 return 0;
768
769 if (clock_get_prediv(clock_id, &pre_podf) < 0)
770 return 0;
771
772 if (clock_get_postdiv(clock_id, &post_podf) < 0)
773 return 0;
774
775 if (clock_get_src(clock_id, &root_src) < 0)
776 return 0;
777
778 root_src_clk = get_root_src_clk(root_src);
779
780 return root_src_clk / (post_podf + 1) / (pre_podf + 1);
781}
782
Peng Fan4e36e332020-07-09 11:06:24 +0800783u32 get_arm_core_clk(void)
784{
785 enum clk_root_src root_src;
786 u32 root_src_clk;
787
788 if (clock_get_src(CORE_SEL_CFG, &root_src) < 0)
789 return 0;
790
791 root_src_clk = get_root_src_clk(root_src);
792
793 return root_src_clk;
794}
795
Peng Fan99878462019-08-27 06:25:51 +0000796u32 mxc_get_clock(enum mxc_clock clk)
797{
Peng Fan60c29bb2019-12-30 16:52:30 +0800798 u32 val;
Peng Fan99878462019-08-27 06:25:51 +0000799
800 switch (clk) {
Peng Fan99878462019-08-27 06:25:51 +0000801 case MXC_ARM_CLK:
Peng Fan4e36e332020-07-09 11:06:24 +0800802 return get_arm_core_clk();
Peng Fan60c29bb2019-12-30 16:52:30 +0800803 case MXC_IPG_CLK:
804 clock_get_target_val(IPG_CLK_ROOT, &val);
805 val = val & 0x3;
806 return get_root_clk(AHB_CLK_ROOT) / 2 / (val + 1);
807 case MXC_CSPI_CLK:
808 return get_root_clk(ECSPI1_CLK_ROOT);
809 case MXC_ESDHC_CLK:
810 return get_root_clk(USDHC1_CLK_ROOT);
811 case MXC_ESDHC2_CLK:
812 return get_root_clk(USDHC2_CLK_ROOT);
813 case MXC_ESDHC3_CLK:
814 return get_root_clk(USDHC3_CLK_ROOT);
815 case MXC_I2C_CLK:
816 return get_root_clk(I2C1_CLK_ROOT);
817 case MXC_UART_CLK:
818 return get_root_clk(UART1_CLK_ROOT);
819 case MXC_QSPI_CLK:
820 return get_root_clk(QSPI_CLK_ROOT);
Peng Fan99878462019-08-27 06:25:51 +0000821 default:
Peng Fan60c29bb2019-12-30 16:52:30 +0800822 printf("Unsupported mxc_clock %d\n", clk);
823 break;
Peng Fan99878462019-08-27 06:25:51 +0000824 }
825
826 return 0;
827}
Marek Vasut363725d2020-04-24 21:37:26 +0200828
Marek Vasute6576952023-03-06 15:53:49 +0100829#if defined(CONFIG_IMX8MP) && defined(CONFIG_DWC_ETH_QOS)
Marek Vasute6576952023-03-06 15:53:49 +0100830static int imx8mp_eqos_interface_init(struct udevice *dev,
831 phy_interface_t interface_type)
832{
833 struct iomuxc_gpr_base_regs *gpr =
834 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
835
836 clrbits_le32(&gpr->gpr[1],
837 IOMUXC_GPR_GPR1_GPR_ENET_QOS_INTF_SEL_MASK |
838 IOMUXC_GPR_GPR1_GPR_ENET_QOS_RGMII_EN |
839 IOMUXC_GPR_GPR1_GPR_ENET_QOS_CLK_TX_CLK_SEL |
840 IOMUXC_GPR_GPR1_GPR_ENET_QOS_CLK_GEN_EN);
841
842 switch (interface_type) {
843 case PHY_INTERFACE_MODE_MII:
844 setbits_le32(&gpr->gpr[1],
845 IOMUXC_GPR_GPR1_GPR_ENET_QOS_CLK_GEN_EN |
846 IOMUXC_GPR_GPR1_GPR_ENET_QOS_INTF_SEL_MII);
847 break;
848 case PHY_INTERFACE_MODE_RMII:
849 setbits_le32(&gpr->gpr[1],
850 IOMUXC_GPR_GPR1_GPR_ENET_QOS_CLK_TX_CLK_SEL |
851 IOMUXC_GPR_GPR1_GPR_ENET_QOS_CLK_GEN_EN |
852 IOMUXC_GPR_GPR1_GPR_ENET_QOS_INTF_SEL_RMII);
853 break;
854 case PHY_INTERFACE_MODE_RGMII:
855 case PHY_INTERFACE_MODE_RGMII_ID:
856 case PHY_INTERFACE_MODE_RGMII_RXID:
857 case PHY_INTERFACE_MODE_RGMII_TXID:
858 setbits_le32(&gpr->gpr[1],
859 IOMUXC_GPR_GPR1_GPR_ENET_QOS_RGMII_EN |
860 IOMUXC_GPR_GPR1_GPR_ENET_QOS_CLK_GEN_EN |
861 IOMUXC_GPR_GPR1_GPR_ENET_QOS_INTF_SEL_RGMII);
862 break;
863 default:
864 return -EINVAL;
865 }
866
867 return 0;
868}
869#else
870static int imx8mp_eqos_interface_init(struct udevice *dev,
871 phy_interface_t interface_type)
872{
873 return 0;
874}
Peng Fan1dd259c2020-07-09 13:14:20 +0800875#endif
876
Marek Vasut363725d2020-04-24 21:37:26 +0200877#ifdef CONFIG_FEC_MXC
Marek Vasutebef0642023-03-06 15:53:51 +0100878static int imx8mp_fec_interface_init(struct udevice *dev,
879 phy_interface_t interface_type,
880 bool mx8mp)
881{
882 /* i.MX8MP has extra RGMII_EN bit in IOMUXC GPR1 register */
883 const u32 rgmii_en = mx8mp ? IOMUXC_GPR_GPR1_GPR_ENET1_RGMII_EN : 0;
884 struct iomuxc_gpr_base_regs *gpr =
885 (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
886
887 clrbits_le32(&gpr->gpr[1],
888 rgmii_en |
889 IOMUXC_GPR_GPR1_GPR_ENET1_TX_CLK_SEL);
890
891 switch (interface_type) {
892 case PHY_INTERFACE_MODE_MII:
893 case PHY_INTERFACE_MODE_RMII:
894 setbits_le32(&gpr->gpr[1], IOMUXC_GPR_GPR1_GPR_ENET1_TX_CLK_SEL);
895 break;
896 case PHY_INTERFACE_MODE_RGMII:
897 case PHY_INTERFACE_MODE_RGMII_ID:
898 case PHY_INTERFACE_MODE_RGMII_RXID:
899 case PHY_INTERFACE_MODE_RGMII_TXID:
900 setbits_le32(&gpr->gpr[1], rgmii_en);
901 break;
902 default:
903 return -EINVAL;
904 }
905
906 return 0;
907}
Fabio Estevamc9da5842023-10-19 21:47:35 -0300908#else
909static int imx8mp_fec_interface_init(struct udevice *dev,
910 phy_interface_t interface_type,
911 bool mx8mp)
912{
913 return 0;
914}
Marek Vasut363725d2020-04-24 21:37:26 +0200915#endif
Marek Vasute6576952023-03-06 15:53:49 +0100916
917int board_interface_eth_init(struct udevice *dev, phy_interface_t interface_type)
918{
Marek Vasutebef0642023-03-06 15:53:51 +0100919 if (IS_ENABLED(CONFIG_IMX8MM) &&
920 IS_ENABLED(CONFIG_FEC_MXC) &&
921 device_is_compatible(dev, "fsl,imx8mm-fec"))
922 return imx8mp_fec_interface_init(dev, interface_type, false);
923
924 if (IS_ENABLED(CONFIG_IMX8MN) &&
925 IS_ENABLED(CONFIG_FEC_MXC) &&
926 device_is_compatible(dev, "fsl,imx8mn-fec"))
927 return imx8mp_fec_interface_init(dev, interface_type, false);
928
929 if (IS_ENABLED(CONFIG_IMX8MP) &&
930 IS_ENABLED(CONFIG_FEC_MXC) &&
931 device_is_compatible(dev, "fsl,imx8mp-fec"))
932 return imx8mp_fec_interface_init(dev, interface_type, true);
933
Marek Vasute6576952023-03-06 15:53:49 +0100934 if (IS_ENABLED(CONFIG_IMX8MP) &&
935 IS_ENABLED(CONFIG_DWC_ETH_QOS) &&
936 device_is_compatible(dev, "nxp,imx8mp-dwmac-eqos"))
937 return imx8mp_eqos_interface_init(dev, interface_type);
938
939 return -EINVAL;
940}