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