blob: a987ff22dfd535b1172fa4acff97fc701aba09e6 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Peng Fan684ccd92017-02-22 16:21:42 +08002/*
3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
Peng Fan684ccd92017-02-22 16:21:42 +08004 */
5
6#include <common.h>
Simon Glass85d65312019-12-28 10:44:58 -07007#include <clock_legacy.h>
Simon Glassed38aef2020-05-10 11:40:03 -06008#include <command.h>
Peng Fan684ccd92017-02-22 16:21:42 +08009#include <div64.h>
10#include <asm/io.h>
11#include <errno.h>
12#include <asm/arch/clock.h>
13#include <asm/arch/sys_proto.h>
14
15DECLARE_GLOBAL_DATA_PTR;
16
17int get_clocks(void)
18{
Yangbo Lu73340382019-06-21 11:42:28 +080019#ifdef CONFIG_FSL_ESDHC_IMX
Peng Fan684ccd92017-02-22 16:21:42 +080020#if CONFIG_SYS_FSL_ESDHC_ADDR == USDHC0_RBASE
21 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
22#elif CONFIG_SYS_FSL_ESDHC_ADDR == USDHC1_RBASE
23 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
24#endif
25#endif
26 return 0;
27}
28
29static u32 get_fast_plat_clk(void)
30{
31 return scg_clk_get_rate(SCG_NIC0_CLK);
32}
33
34static u32 get_slow_plat_clk(void)
35{
36 return scg_clk_get_rate(SCG_NIC1_CLK);
37}
38
39static u32 get_ipg_clk(void)
40{
41 return scg_clk_get_rate(SCG_NIC1_BUS_CLK);
42}
43
44u32 get_lpuart_clk(void)
45{
46 int index = 0;
47
48 const u32 lpuart_array[] = {
49 LPUART0_RBASE,
50 LPUART1_RBASE,
51 LPUART2_RBASE,
52 LPUART3_RBASE,
53 LPUART4_RBASE,
54 LPUART5_RBASE,
55 LPUART6_RBASE,
56 LPUART7_RBASE,
57 };
58
59 const enum pcc_clk lpuart_pcc_clks[] = {
60 PER_CLK_LPUART4,
61 PER_CLK_LPUART5,
62 PER_CLK_LPUART6,
63 PER_CLK_LPUART7,
64 };
65
66 for (index = 0; index < 8; index++) {
67 if (lpuart_array[index] == LPUART_BASE)
68 break;
69 }
70
71 if (index < 4 || index > 7)
72 return 0;
73
74 return pcc_clock_get_rate(lpuart_pcc_clks[index - 4]);
75}
76
Ye Li3edefd52019-07-22 01:24:53 +000077#ifdef CONFIG_SYS_I2C_IMX_LPI2C
Ye Lib7f9c3e2017-02-22 16:21:44 +080078int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
79{
80 /* Set parent to FIRC DIV2 clock */
81 const enum pcc_clk lpi2c_pcc_clks[] = {
82 PER_CLK_LPI2C4,
83 PER_CLK_LPI2C5,
84 PER_CLK_LPI2C6,
85 PER_CLK_LPI2C7,
86 };
87
88 if (i2c_num < 4 || i2c_num > 7)
89 return -EINVAL;
90
91 if (enable) {
92 pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4], false);
93 pcc_clock_sel(lpi2c_pcc_clks[i2c_num - 4], SCG_FIRC_DIV2_CLK);
94 pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4], true);
95 } else {
96 pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4], false);
97 }
98 return 0;
99}
100
101u32 imx_get_i2cclk(unsigned i2c_num)
102{
103 const enum pcc_clk lpi2c_pcc_clks[] = {
104 PER_CLK_LPI2C4,
105 PER_CLK_LPI2C5,
106 PER_CLK_LPI2C6,
107 PER_CLK_LPI2C7,
108 };
109
110 if (i2c_num < 4 || i2c_num > 7)
111 return 0;
112
113 return pcc_clock_get_rate(lpi2c_pcc_clks[i2c_num - 4]);
114}
115#endif
116
Peng Fan684ccd92017-02-22 16:21:42 +0800117unsigned int mxc_get_clock(enum mxc_clock clk)
118{
119 switch (clk) {
120 case MXC_ARM_CLK:
121 return scg_clk_get_rate(SCG_CORE_CLK);
122 case MXC_AXI_CLK:
123 return get_fast_plat_clk();
124 case MXC_AHB_CLK:
125 return get_slow_plat_clk();
126 case MXC_IPG_CLK:
127 return get_ipg_clk();
128 case MXC_I2C_CLK:
129 return pcc_clock_get_rate(PER_CLK_LPI2C4);
130 case MXC_UART_CLK:
131 return get_lpuart_clk();
132 case MXC_ESDHC_CLK:
133 return pcc_clock_get_rate(PER_CLK_USDHC0);
134 case MXC_ESDHC2_CLK:
135 return pcc_clock_get_rate(PER_CLK_USDHC1);
136 case MXC_DDR_CLK:
137 return scg_clk_get_rate(SCG_DDR_CLK);
138 default:
139 printf("Unsupported mxc_clock %d\n", clk);
140 break;
141 }
142
143 return 0;
144}
145
146void init_clk_usdhc(u32 index)
147{
148 switch (index) {
149 case 0:
150 /*Disable the clock before configure it */
151 pcc_clock_enable(PER_CLK_USDHC0, false);
152
153 /* 158MHz / 1 = 158MHz */
154 pcc_clock_sel(PER_CLK_USDHC0, SCG_NIC1_CLK);
155 pcc_clock_div_config(PER_CLK_USDHC0, false, 1);
156 pcc_clock_enable(PER_CLK_USDHC0, true);
157 break;
158 case 1:
159 /*Disable the clock before configure it */
160 pcc_clock_enable(PER_CLK_USDHC1, false);
161
162 /* 158MHz / 1 = 158MHz */
163 pcc_clock_sel(PER_CLK_USDHC1, SCG_NIC1_CLK);
164 pcc_clock_div_config(PER_CLK_USDHC1, false, 1);
165 pcc_clock_enable(PER_CLK_USDHC1, true);
166 break;
167 default:
168 printf("Invalid index for USDHC %d\n", index);
169 break;
170 }
171}
172
173#ifdef CONFIG_MXC_OCOTP
174
175#define OCOTP_CTRL_PCC1_SLOT (38)
176#define OCOTP_CTRL_HIGH4K_PCC1_SLOT (39)
177
178void enable_ocotp_clk(unsigned char enable)
179{
180 u32 val;
181
182 /*
183 * Seems the OCOTP CLOCKs have been enabled at default,
184 * check its inuse flag
185 */
186
187 val = readl(PCC1_RBASE + 4 * OCOTP_CTRL_PCC1_SLOT);
188 if (!(val & PCC_INUSE_MASK))
189 writel(PCC_CGC_MASK, (PCC1_RBASE + 4 * OCOTP_CTRL_PCC1_SLOT));
190
191 val = readl(PCC1_RBASE + 4 * OCOTP_CTRL_HIGH4K_PCC1_SLOT);
192 if (!(val & PCC_INUSE_MASK))
193 writel(PCC_CGC_MASK,
194 (PCC1_RBASE + 4 * OCOTP_CTRL_HIGH4K_PCC1_SLOT));
195}
196#endif
197
198void enable_usboh3_clk(unsigned char enable)
199{
200 if (enable) {
201 pcc_clock_enable(PER_CLK_USB0, false);
202 pcc_clock_sel(PER_CLK_USB0, SCG_NIC1_BUS_CLK);
203 pcc_clock_enable(PER_CLK_USB0, true);
204
205#ifdef CONFIG_USB_MAX_CONTROLLER_COUNT
206 if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1) {
207 pcc_clock_enable(PER_CLK_USB1, false);
208 pcc_clock_sel(PER_CLK_USB1, SCG_NIC1_BUS_CLK);
209 pcc_clock_enable(PER_CLK_USB1, true);
210 }
211#endif
212
213 pcc_clock_enable(PER_CLK_USB_PHY, true);
214 pcc_clock_enable(PER_CLK_USB_PL301, true);
215 } else {
216 pcc_clock_enable(PER_CLK_USB0, false);
217 pcc_clock_enable(PER_CLK_USB1, false);
218 pcc_clock_enable(PER_CLK_USB_PHY, false);
219 pcc_clock_enable(PER_CLK_USB_PL301, false);
220 }
221}
222
223static void lpuart_set_clk(uint32_t index, enum scg_clk clk)
224{
225 const enum pcc_clk lpuart_pcc_clks[] = {
226 PER_CLK_LPUART4,
227 PER_CLK_LPUART5,
228 PER_CLK_LPUART6,
229 PER_CLK_LPUART7,
230 };
231
232 if (index < 4 || index > 7)
233 return;
234
235#ifndef CONFIG_CLK_DEBUG
236 pcc_clock_enable(lpuart_pcc_clks[index - 4], false);
237#endif
238 pcc_clock_sel(lpuart_pcc_clks[index - 4], clk);
239 pcc_clock_enable(lpuart_pcc_clks[index - 4], true);
240}
241
242static void init_clk_lpuart(void)
243{
244 u32 index = 0, i;
245
246 const u32 lpuart_array[] = {
247 LPUART0_RBASE,
248 LPUART1_RBASE,
249 LPUART2_RBASE,
250 LPUART3_RBASE,
251 LPUART4_RBASE,
252 LPUART5_RBASE,
253 LPUART6_RBASE,
254 LPUART7_RBASE,
255 };
256
257 for (i = 0; i < 8; i++) {
258 if (lpuart_array[i] == LPUART_BASE) {
259 index = i;
260 break;
261 }
262 }
263
264 lpuart_set_clk(index, SCG_SOSC_DIV2_CLK);
265}
266
267static void init_clk_rgpio2p(void)
268{
269 /*Enable RGPIO2P1 clock */
270 pcc_clock_enable(PER_CLK_RGPIO2P1, true);
271
272 /*
273 * Hard code to enable RGPIO2P0 clock since it is not
274 * in clock frame for A7 domain
275 */
276 writel(PCC_CGC_MASK, (PCC0_RBASE + 0x3C));
277}
278
279/* Configure PLL/PFD freq */
280void clock_init(void)
281{
282 /*
283 * ROM has enabled clocks:
284 * A4 side: SIRC 16Mhz (DIV1-3 off), FIRC 48Mhz (DIV1-2 on),
285 * Non-LP-boot: SOSC, SPLL PFD0 (scs selected)
286 * A7 side: SPLL PFD0 (scs selected, 413Mhz),
287 * APLL PFD0 (352Mhz), DDRCLK, all NIC clocks
288 * A7 Plat0 (NIC0) = 176Mhz, Plat1 (NIC1) = 176Mhz,
289 * IP BUS (NIC1_BUS) = 58.6Mhz
290 *
291 * In u-boot:
292 * 1. Enable PFD1-3 of APLL for A7 side. Enable FIRC and DIVs.
293 * 2. Enable USB PLL
294 * 3. Init the clocks of peripherals used in u-boot bu
295 * without set rate interface.The clocks for these
296 * peripherals are enabled in this intialization.
297 * 4.Other peripherals with set clock rate interface
298 * does not be set in this function.
299 */
300
301 scg_a7_firc_init();
302
303 scg_a7_soscdiv_init();
304
Ye Li73df56a2019-07-22 01:25:08 +0000305 scg_a7_init_core_clk();
306
Ye Lib2e7c2b2019-07-22 01:25:03 +0000307 /* APLL PFD1 = 270Mhz, PFD2=345.6Mhz, PFD3=800Mhz */
Peng Fan684ccd92017-02-22 16:21:42 +0800308 scg_enable_pll_pfd(SCG_APLL_PFD1_CLK, 35);
Ye Lib2e7c2b2019-07-22 01:25:03 +0000309 scg_enable_pll_pfd(SCG_APLL_PFD2_CLK, 28);
Peng Fan684ccd92017-02-22 16:21:42 +0800310 scg_enable_pll_pfd(SCG_APLL_PFD3_CLK, 12);
311
312 init_clk_lpuart();
313
314 init_clk_rgpio2p();
315
316 enable_usboh3_clk(1);
317}
318
Stefano Babicf8b509b2019-09-20 08:47:53 +0200319#ifdef CONFIG_IMX_HAB
Peng Fana26ba6d2017-02-22 16:21:53 +0800320void hab_caam_clock_enable(unsigned char enable)
321{
322 if (enable)
323 pcc_clock_enable(PER_CLK_CAAM, true);
324 else
325 pcc_clock_enable(PER_CLK_CAAM, false);
326}
327#endif
328
Tom Rini2f218872018-01-03 08:52:39 -0500329#ifndef CONFIG_SPL_BUILD
Peng Fan684ccd92017-02-22 16:21:42 +0800330/*
331 * Dump some core clockes.
332 */
Simon Glassed38aef2020-05-10 11:40:03 -0600333int do_mx7_showclocks(struct cmd_tbl *cmdtp, int flag, int argc,
334 char *const argv[])
Peng Fan684ccd92017-02-22 16:21:42 +0800335{
336 u32 addr = 0;
337 u32 freq;
338 freq = decode_pll(PLL_A7_SPLL);
339 printf("PLL_A7_SPLL %8d MHz\n", freq / 1000000);
340
341 freq = decode_pll(PLL_A7_APLL);
342 printf("PLL_A7_APLL %8d MHz\n", freq / 1000000);
343
344 freq = decode_pll(PLL_USB);
345 printf("PLL_USB %8d MHz\n", freq / 1000000);
346
347 printf("\n");
348
349 printf("CORE %8d kHz\n", scg_clk_get_rate(SCG_CORE_CLK) / 1000);
350 printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
351 printf("UART %8d kHz\n", mxc_get_clock(MXC_UART_CLK) / 1000);
352 printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
353 printf("AXI %8d kHz\n", mxc_get_clock(MXC_AXI_CLK) / 1000);
354 printf("DDR %8d kHz\n", mxc_get_clock(MXC_DDR_CLK) / 1000);
355 printf("USDHC1 %8d kHz\n", mxc_get_clock(MXC_ESDHC_CLK) / 1000);
356 printf("USDHC2 %8d kHz\n", mxc_get_clock(MXC_ESDHC2_CLK) / 1000);
357 printf("I2C4 %8d kHz\n", mxc_get_clock(MXC_I2C_CLK) / 1000);
358
359 addr = (u32) clock_init;
360 printf("[%s] addr = 0x%08X\r\n", __func__, addr);
361 scg_a7_info();
362
363 return 0;
364}
365
366U_BOOT_CMD(
367 clocks, CONFIG_SYS_MAXARGS, 1, do_mx7_showclocks,
368 "display clocks",
369 ""
370);
Tom Rini2f218872018-01-03 08:52:39 -0500371#endif