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