blob: 2beacbceb02a5cbd68ebb8cacbe1a3bfd8abd962 [file] [log] [blame]
Peng Fanb15705a2021-08-07 16:00:35 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2020 NXP
4 */
5
6#include <common.h>
Peng Fan690eea12021-08-07 16:00:45 +08007#include <command.h>
Peng Fanb15705a2021-08-07 16:00:35 +08008#include <div64.h>
Peng Fan690eea12021-08-07 16:00:45 +08009#include <asm/arch/imx-regs.h>
Peng Fanb15705a2021-08-07 16:00:35 +080010#include <asm/io.h>
11#include <errno.h>
12#include <asm/arch/clock.h>
Peng Fan690eea12021-08-07 16:00:45 +080013#include <asm/arch/pcc.h>
14#include <asm/arch/cgc.h>
Peng Fanb15705a2021-08-07 16:00:35 +080015#include <asm/arch/sys_proto.h>
Peng Fan690eea12021-08-07 16:00:45 +080016#include <asm/global_data.h>
17#include <linux/delay.h>
Peng Fanb15705a2021-08-07 16:00:35 +080018
19DECLARE_GLOBAL_DATA_PTR;
20
Peng Fan690eea12021-08-07 16:00:45 +080021#define PLL_USB_EN_USB_CLKS_MASK (0x01 << 6)
22#define PLL_USB_PWR_MASK (0x01 << 12)
23#define PLL_USB_ENABLE_MASK (0x01 << 13)
24#define PLL_USB_BYPASS_MASK (0x01 << 16)
25#define PLL_USB_REG_ENABLE_MASK (0x01 << 21)
26#define PLL_USB_DIV_SEL_MASK (0x07 << 22)
27#define PLL_USB_LOCK_MASK (0x01 << 31)
28#define PCC5_LPDDR4_ADDR 0x2da70108
29
Ye Lida0469d2021-10-29 09:46:18 +080030static void lpuart_set_clk(u32 index, enum cgc_clk clk)
Peng Fan690eea12021-08-07 16:00:45 +080031{
32 const u32 lpuart_pcc_slots[] = {
33 LPUART4_PCC3_SLOT,
34 LPUART5_PCC3_SLOT,
35 LPUART6_PCC4_SLOT,
36 LPUART7_PCC4_SLOT,
37 };
38
39 const u32 lpuart_pcc[] = {
40 3, 3, 4, 4,
41 };
42
43 if (index > 3)
44 return;
45
46 pcc_clock_enable(lpuart_pcc[index], lpuart_pcc_slots[index], false);
47 pcc_clock_sel(lpuart_pcc[index], lpuart_pcc_slots[index], clk);
48 pcc_clock_enable(lpuart_pcc[index], lpuart_pcc_slots[index], true);
49
50 pcc_reset_peripheral(lpuart_pcc[index], lpuart_pcc_slots[index], false);
51}
52
53static void init_clk_lpuart(void)
54{
55 u32 index = 0, i;
56
57 const u32 lpuart_array[] = {
58 LPUART4_RBASE,
59 LPUART5_RBASE,
60 LPUART6_RBASE,
61 LPUART7_RBASE,
62 };
63
64 for (i = 0; i < 4; i++) {
65 if (lpuart_array[i] == LPUART_BASE) {
66 index = i;
67 break;
68 }
69 }
70
71 lpuart_set_clk(index, SOSC_DIV2);
72}
73
74void init_clk_fspi(int index)
75{
76 pcc_clock_enable(4, FLEXSPI2_PCC4_SLOT, false);
77 pcc_clock_sel(4, FLEXSPI2_PCC4_SLOT, PLL3_PFD2_DIV1);
78 pcc_clock_div_config(4, FLEXSPI2_PCC4_SLOT, false, 8);
79 pcc_clock_enable(4, FLEXSPI2_PCC4_SLOT, true);
80 pcc_reset_peripheral(4, FLEXSPI2_PCC4_SLOT, false);
81}
82
83void setclkout_ddr(void)
84{
85 writel(0x12800000, 0x2DA60020);
86 writel(0xa00, 0x298C0000); /* PTD0 */
87}
88
89void ddrphy_pll_lock(void)
90{
91 writel(0x00011542, 0x2E065964);
92 writel(0x00011542, 0x2E06586C);
93
94 writel(0x00000B01, 0x2E062000);
95 writel(0x00000B01, 0x2E060000);
96}
97
98void init_clk_ddr(void)
99{
100 /* enable pll4 and ddrclk*/
101 cgc2_pll4_init();
102 cgc2_ddrclk_config(1, 1);
103
104 /* enable ddr pcc */
105 writel(0xd0000000, PCC5_LPDDR4_ADDR);
106
107 /* for debug */
108 /* setclkout_ddr(); */
109}
110
111int set_ddr_clk(u32 phy_freq_mhz)
112{
113 debug("%s %u\n", __func__, phy_freq_mhz);
114
115 if (phy_freq_mhz == 48) {
116 writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */
117 cgc2_ddrclk_config(2, 0); /* 24Mhz DDR clock */
118 writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */
119 } else if (phy_freq_mhz == 384) {
120 writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */
121 cgc2_ddrclk_config(0, 0); /* 192Mhz DDR clock */
122 writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */
123 } else if (phy_freq_mhz == 528) {
124 writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */
125 cgc2_ddrclk_config(4, 1); /* 264Mhz DDR clock */
126 writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */
127 } else if (phy_freq_mhz == 264) {
128 writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */
129 cgc2_ddrclk_config(4, 3); /* 132Mhz DDR clock */
130 writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */
131 } else if (phy_freq_mhz == 192) {
132 writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */
133 cgc2_ddrclk_config(0, 1); /* 96Mhz DDR clock */
134 writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */
135 } else if (phy_freq_mhz == 96) {
136 writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */
137 cgc2_ddrclk_config(0, 3); /* 48Mhz DDR clock */
138 writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */
139 } else {
140 printf("ddr phy clk %uMhz is not supported\n", phy_freq_mhz);
141 return -EINVAL;
142 }
143
144 return 0;
145}
146
Peng Fanb15705a2021-08-07 16:00:35 +0800147void clock_init(void)
148{
Peng Fan690eea12021-08-07 16:00:45 +0800149 cgc1_soscdiv_init();
150 cgc1_init_core_clk();
151
152 init_clk_lpuart();
153
154 pcc_clock_enable(4, SDHC0_PCC4_SLOT, false);
155 pcc_clock_sel(4, SDHC0_PCC4_SLOT, PLL3_PFD1_DIV2);
156 pcc_clock_enable(4, SDHC0_PCC4_SLOT, true);
157 pcc_reset_peripheral(4, SDHC0_PCC4_SLOT, false);
158
159 pcc_clock_enable(4, SDHC1_PCC4_SLOT, false);
160 pcc_clock_sel(4, SDHC1_PCC4_SLOT, PLL3_PFD2_DIV1);
161 pcc_clock_enable(4, SDHC1_PCC4_SLOT, true);
162 pcc_reset_peripheral(4, SDHC1_PCC4_SLOT, false);
163
164 pcc_clock_enable(4, SDHC2_PCC4_SLOT, false);
165 pcc_clock_sel(4, SDHC2_PCC4_SLOT, PLL3_PFD2_DIV1);
166 pcc_clock_enable(4, SDHC2_PCC4_SLOT, true);
167 pcc_reset_peripheral(4, SDHC2_PCC4_SLOT, false);
168
169 /* Enable upower mu1 clk */
170 pcc_clock_enable(3, UPOWER_PCC3_SLOT, true);
171
172 /*
173 * Enable clock division
174 * TODO: may not needed after ROM ready.
175 */
176}
177
178#if IS_ENABLED(CONFIG_SYS_I2C_IMX_LPI2C)
179int enable_i2c_clk(unsigned char enable, u32 i2c_num)
180{
181 /* Set parent to FIRC DIV2 clock */
182 const u32 lpi2c_pcc_clks[] = {
183 LPI2C4_PCC3_SLOT << 8 | 3,
184 LPI2C5_PCC3_SLOT << 8 | 3,
185 LPI2C6_PCC4_SLOT << 8 | 4,
186 LPI2C7_PCC4_SLOT << 8 | 4,
187 };
188
189 if (i2c_num < 4 || i2c_num > 7)
190 return -EINVAL;
191
192 if (enable) {
193 pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4] & 0xff,
194 lpi2c_pcc_clks[i2c_num - 4] >> 8, false);
195 pcc_clock_sel(lpi2c_pcc_clks[i2c_num - 4] & 0xff,
196 lpi2c_pcc_clks[i2c_num - 4] >> 8, SOSC_DIV2);
197 pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4] & 0xff,
198 lpi2c_pcc_clks[i2c_num - 4] >> 8, true);
199 pcc_reset_peripheral(lpi2c_pcc_clks[i2c_num - 4] & 0xff,
200 lpi2c_pcc_clks[i2c_num - 4] >> 8, false);
201 } else {
202 pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4] & 0xff,
203 lpi2c_pcc_clks[i2c_num - 4] >> 8, false);
204 }
205 return 0;
206}
207
208u32 imx_get_i2cclk(u32 i2c_num)
209{
210 const u32 lpi2c_pcc_clks[] = {
211 LPI2C4_PCC3_SLOT << 8 | 3,
212 LPI2C5_PCC3_SLOT << 8 | 3,
213 LPI2C6_PCC4_SLOT << 8 | 4,
214 LPI2C7_PCC4_SLOT << 8 | 4,
215 };
216
217 if (i2c_num < 4 || i2c_num > 7)
218 return 0;
219
220 return pcc_clock_get_rate(lpi2c_pcc_clks[i2c_num - 4] & 0xff,
221 lpi2c_pcc_clks[i2c_num - 4] >> 8);
222}
223#endif
224
225void enable_usboh3_clk(unsigned char enable)
226{
227 if (enable) {
228 pcc_clock_enable(4, USB0_PCC4_SLOT, true);
229 pcc_clock_enable(4, USBPHY_PCC4_SLOT, true);
230 pcc_reset_peripheral(4, USB0_PCC4_SLOT, false);
231 pcc_reset_peripheral(4, USBPHY_PCC4_SLOT, false);
232
233#ifdef CONFIG_USB_MAX_CONTROLLER_COUNT
234 if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1) {
235 pcc_clock_enable(4, USB1_PCC4_SLOT, true);
236 pcc_clock_enable(4, USB1PHY_PCC4_SLOT, true);
237 pcc_reset_peripheral(4, USB1_PCC4_SLOT, false);
238 pcc_reset_peripheral(4, USB1PHY_PCC4_SLOT, false);
239 }
240#endif
241
242 pcc_clock_enable(4, USB_XBAR_PCC4_SLOT, true);
243 } else {
244 pcc_clock_enable(4, USB0_PCC4_SLOT, false);
245 pcc_clock_enable(4, USB1_PCC4_SLOT, false);
246 pcc_clock_enable(4, USBPHY_PCC4_SLOT, false);
247 pcc_clock_enable(4, USB1PHY_PCC4_SLOT, false);
248 pcc_clock_enable(4, USB_XBAR_PCC4_SLOT, false);
249 }
Peng Fanb15705a2021-08-07 16:00:35 +0800250}
251
Peng Fan690eea12021-08-07 16:00:45 +0800252int enable_usb_pll(ulong usb_phy_base)
Peng Fanb15705a2021-08-07 16:00:35 +0800253{
Peng Fan690eea12021-08-07 16:00:45 +0800254 u32 sosc_rate;
255 s32 timeout = 1000000;
256
257 struct usbphy_regs *usbphy =
258 (struct usbphy_regs *)usb_phy_base;
259
260 sosc_rate = cgc1_sosc_div(SOSC);
261 if (!sosc_rate)
262 return -EPERM;
263
264 if (!(readl(&usbphy->usb1_pll_480_ctrl) & PLL_USB_LOCK_MASK)) {
265 writel(0x1c00000, &usbphy->usb1_pll_480_ctrl_clr);
266
267 switch (sosc_rate) {
268 case 24000000:
269 writel(0xc00000, &usbphy->usb1_pll_480_ctrl_set);
270 break;
271
272 case 30000000:
273 writel(0x800000, &usbphy->usb1_pll_480_ctrl_set);
274 break;
275
276 case 19200000:
277 writel(0x1400000, &usbphy->usb1_pll_480_ctrl_set);
278 break;
279
280 default:
281 writel(0xc00000, &usbphy->usb1_pll_480_ctrl_set);
282 break;
283 }
284
285 /* Enable the regulator first */
286 writel(PLL_USB_REG_ENABLE_MASK,
287 &usbphy->usb1_pll_480_ctrl_set);
288
289 /* Wait at least 15us */
290 udelay(15);
291
292 /* Enable the power */
293 writel(PLL_USB_PWR_MASK, &usbphy->usb1_pll_480_ctrl_set);
294
295 /* Wait lock */
296 while (timeout--) {
297 if (readl(&usbphy->usb1_pll_480_ctrl) &
298 PLL_USB_LOCK_MASK)
299 break;
300 }
301
302 if (timeout <= 0) {
303 /* If timeout, we power down the pll */
304 writel(PLL_USB_PWR_MASK,
305 &usbphy->usb1_pll_480_ctrl_clr);
306 return -ETIME;
307 }
308 }
309
310 /* Clear the bypass */
311 writel(PLL_USB_BYPASS_MASK, &usbphy->usb1_pll_480_ctrl_clr);
312
313 /* Enable the PLL clock out to USB */
314 writel((PLL_USB_EN_USB_CLKS_MASK | PLL_USB_ENABLE_MASK),
315 &usbphy->usb1_pll_480_ctrl_set);
316
Peng Fanb15705a2021-08-07 16:00:35 +0800317 return 0;
318}
319
Peng Fan690eea12021-08-07 16:00:45 +0800320u32 mxc_get_clock(enum mxc_clock clk)
321{
322 switch (clk) {
323 case MXC_ESDHC_CLK:
324 return pcc_clock_get_rate(4, SDHC0_PCC4_SLOT);
325 case MXC_ESDHC2_CLK:
326 return pcc_clock_get_rate(4, SDHC1_PCC4_SLOT);
327 case MXC_ESDHC3_CLK:
328 return pcc_clock_get_rate(4, SDHC2_PCC4_SLOT);
329 case MXC_ARM_CLK:
Ye Lida0469d2021-10-29 09:46:18 +0800330 return cgc_clk_get_rate(PLL2);
Peng Fan690eea12021-08-07 16:00:45 +0800331 default:
332 return 0;
333 }
334}
335
Peng Fanb15705a2021-08-07 16:00:35 +0800336u32 get_lpuart_clk(void)
337{
Peng Fan690eea12021-08-07 16:00:45 +0800338 int index = 0;
339
340 const u32 lpuart_array[] = {
341 LPUART4_RBASE,
342 LPUART5_RBASE,
343 LPUART6_RBASE,
344 LPUART7_RBASE,
345 };
346
347 const u32 lpuart_pcc_slots[] = {
348 LPUART4_PCC3_SLOT,
349 LPUART5_PCC3_SLOT,
350 LPUART6_PCC4_SLOT,
351 LPUART7_PCC4_SLOT,
352 };
353
354 const u32 lpuart_pcc[] = {
355 3, 3, 4, 4,
356 };
357
358 for (index = 0; index < 4; index++) {
359 if (lpuart_array[index] == LPUART_BASE)
360 break;
361 }
362
363 if (index > 3)
364 return 0;
365
366 return pcc_clock_get_rate(lpuart_pcc[index], lpuart_pcc_slots[index]);
367}
368
369#ifndef CONFIG_SPL_BUILD
370/*
371 * Dump some core clockes.
372 */
373int do_mx8ulp_showclocks(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
374{
375 printf("SDHC0 %8d MHz\n", pcc_clock_get_rate(4, SDHC0_PCC4_SLOT) / 1000000);
376 printf("SDHC1 %8d MHz\n", pcc_clock_get_rate(4, SDHC1_PCC4_SLOT) / 1000000);
377 printf("SDHC2 %8d MHz\n", pcc_clock_get_rate(4, SDHC2_PCC4_SLOT) / 1000000);
378
Ye Lida0469d2021-10-29 09:46:18 +0800379 printf("SOSC %8d MHz\n", cgc_clk_get_rate(SOSC) / 1000000);
380 printf("FRO %8d MHz\n", cgc_clk_get_rate(FRO) / 1000000);
381 printf("PLL2 %8d MHz\n", cgc_clk_get_rate(PLL2) / 1000000);
382 printf("PLL3 %8d MHz\n", cgc_clk_get_rate(PLL3) / 1000000);
383 printf("PLL3_VCODIV %8d MHz\n", cgc_clk_get_rate(PLL3_VCODIV) / 1000000);
384 printf("PLL3_PFD0 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD0) / 1000000);
385 printf("PLL3_PFD1 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD1) / 1000000);
386 printf("PLL3_PFD2 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD2) / 1000000);
387 printf("PLL3_PFD3 %8d MHz\n", cgc_clk_get_rate(PLL3_PFD3) / 1000000);
388
389 printf("PLL4_PFD0 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD0) / 1000000);
390 printf("PLL4_PFD1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD1) / 1000000);
391 printf("PLL4_PFD2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD2) / 1000000);
392 printf("PLL4_PFD3 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD3) / 1000000);
393
394 printf("PLL4_PFD0_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD0_DIV1) / 1000000);
395 printf("PLL4_PFD0_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD0_DIV2) / 1000000);
396 printf("PLL4_PFD1_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD1_DIV1) / 1000000);
397 printf("PLL4_PFD1_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD1_DIV2) / 1000000);
398
399 printf("PLL4_PFD2_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD2_DIV1) / 1000000);
400 printf("PLL4_PFD2_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD2_DIV2) / 1000000);
401 printf("PLL4_PFD3_DIV1 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD3_DIV1) / 1000000);
402 printf("PLL4_PFD3_DIV2 %8d MHz\n", cgc_clk_get_rate(PLL4_PFD3_DIV2) / 1000000);
403
404 printf("LPAV_AXICLK %8d MHz\n", cgc_clk_get_rate(LPAV_AXICLK) / 1000000);
405 printf("LPAV_AHBCLK %8d MHz\n", cgc_clk_get_rate(LPAV_AHBCLK) / 1000000);
406 printf("LPAV_BUSCLK %8d MHz\n", cgc_clk_get_rate(LPAV_BUSCLK) / 1000000);
407 printf("NIC_APCLK %8d MHz\n", cgc_clk_get_rate(NIC_APCLK) / 1000000);
Peng Fan690eea12021-08-07 16:00:45 +0800408
Ye Lida0469d2021-10-29 09:46:18 +0800409 printf("NIC_PERCLK %8d MHz\n", cgc_clk_get_rate(NIC_PERCLK) / 1000000);
410 printf("XBAR_APCLK %8d MHz\n", cgc_clk_get_rate(XBAR_APCLK) / 1000000);
411 printf("XBAR_BUSCLK %8d MHz\n", cgc_clk_get_rate(XBAR_BUSCLK) / 1000000);
412 printf("AD_SLOWCLK %8d MHz\n", cgc_clk_get_rate(AD_SLOWCLK) / 1000000);
Peng Fan690eea12021-08-07 16:00:45 +0800413 return 0;
Peng Fanb15705a2021-08-07 16:00:35 +0800414}
Peng Fan690eea12021-08-07 16:00:45 +0800415
416U_BOOT_CMD(
417 clocks, CONFIG_SYS_MAXARGS, 1, do_mx8ulp_showclocks,
418 "display clocks",
419 ""
420);
421#endif