]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
24e8bee5 AW |
2 | /* |
3 | * Copyright 2013 Freescale Semiconductor, Inc. | |
24e8bee5 AW |
4 | */ |
5 | ||
6 | #include <common.h> | |
d96c2604 | 7 | #include <clock_legacy.h> |
9edefc27 | 8 | #include <cpu_func.h> |
691d719d | 9 | #include <init.h> |
90526e9f SG |
10 | #include <net.h> |
11 | #include <asm/cache.h> | |
24e8bee5 AW |
12 | #include <asm/io.h> |
13 | #include <asm/arch/imx-regs.h> | |
14 | #include <asm/arch/clock.h> | |
15 | #include <asm/arch/crm_regs.h> | |
552a848e | 16 | #include <asm/mach-imx/sys_proto.h> |
9fb625ce | 17 | #include <env.h> |
24e8bee5 | 18 | #include <netdev.h> |
e37ac717 YL |
19 | #ifdef CONFIG_FSL_ESDHC_IMX |
20 | #include <fsl_esdhc_imx.h> | |
24e8bee5 AW |
21 | #endif |
22 | ||
e37ac717 | 23 | #ifdef CONFIG_FSL_ESDHC_IMX |
24e8bee5 AW |
24 | DECLARE_GLOBAL_DATA_PTR; |
25 | #endif | |
26 | ||
1db503c4 SM |
27 | static char soc_type[] = "xx0"; |
28 | ||
24e8bee5 AW |
29 | #ifdef CONFIG_MXC_OCOTP |
30 | void enable_ocotp_clk(unsigned char enable) | |
31 | { | |
32 | struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; | |
33 | u32 reg; | |
34 | ||
35 | reg = readl(&ccm->ccgr6); | |
36 | if (enable) | |
37 | reg |= CCM_CCGR6_OCOTP_CTRL_MASK; | |
38 | else | |
39 | reg &= ~CCM_CCGR6_OCOTP_CTRL_MASK; | |
40 | writel(reg, &ccm->ccgr6); | |
41 | } | |
42 | #endif | |
43 | ||
44 | static u32 get_mcu_main_clk(void) | |
45 | { | |
46 | struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; | |
47 | u32 ccm_ccsr, ccm_cacrr, armclk_div; | |
48 | u32 sysclk_sel, pll_pfd_sel = 0; | |
49 | u32 freq = 0; | |
50 | ||
51 | ccm_ccsr = readl(&ccm->ccsr); | |
52 | sysclk_sel = ccm_ccsr & CCM_CCSR_SYS_CLK_SEL_MASK; | |
53 | sysclk_sel >>= CCM_CCSR_SYS_CLK_SEL_OFFSET; | |
54 | ||
55 | ccm_cacrr = readl(&ccm->cacrr); | |
56 | armclk_div = ccm_cacrr & CCM_CACRR_ARM_CLK_DIV_MASK; | |
57 | armclk_div >>= CCM_CACRR_ARM_CLK_DIV_OFFSET; | |
58 | armclk_div += 1; | |
59 | ||
60 | switch (sysclk_sel) { | |
61 | case 0: | |
62 | freq = FASE_CLK_FREQ; | |
63 | break; | |
64 | case 1: | |
65 | freq = SLOW_CLK_FREQ; | |
66 | break; | |
67 | case 2: | |
68 | pll_pfd_sel = ccm_ccsr & CCM_CCSR_PLL2_PFD_CLK_SEL_MASK; | |
69 | pll_pfd_sel >>= CCM_CCSR_PLL2_PFD_CLK_SEL_OFFSET; | |
70 | if (pll_pfd_sel == 0) | |
71 | freq = PLL2_MAIN_FREQ; | |
72 | else if (pll_pfd_sel == 1) | |
73 | freq = PLL2_PFD1_FREQ; | |
74 | else if (pll_pfd_sel == 2) | |
75 | freq = PLL2_PFD2_FREQ; | |
76 | else if (pll_pfd_sel == 3) | |
77 | freq = PLL2_PFD3_FREQ; | |
78 | else if (pll_pfd_sel == 4) | |
79 | freq = PLL2_PFD4_FREQ; | |
80 | break; | |
81 | case 3: | |
82 | freq = PLL2_MAIN_FREQ; | |
83 | break; | |
84 | case 4: | |
85 | pll_pfd_sel = ccm_ccsr & CCM_CCSR_PLL1_PFD_CLK_SEL_MASK; | |
86 | pll_pfd_sel >>= CCM_CCSR_PLL1_PFD_CLK_SEL_OFFSET; | |
87 | if (pll_pfd_sel == 0) | |
88 | freq = PLL1_MAIN_FREQ; | |
89 | else if (pll_pfd_sel == 1) | |
90 | freq = PLL1_PFD1_FREQ; | |
91 | else if (pll_pfd_sel == 2) | |
92 | freq = PLL1_PFD2_FREQ; | |
93 | else if (pll_pfd_sel == 3) | |
94 | freq = PLL1_PFD3_FREQ; | |
95 | else if (pll_pfd_sel == 4) | |
96 | freq = PLL1_PFD4_FREQ; | |
97 | break; | |
98 | case 5: | |
99 | freq = PLL3_MAIN_FREQ; | |
100 | break; | |
101 | default: | |
102 | printf("unsupported system clock select\n"); | |
103 | } | |
104 | ||
105 | return freq / armclk_div; | |
106 | } | |
107 | ||
108 | static u32 get_bus_clk(void) | |
109 | { | |
110 | struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; | |
111 | u32 ccm_cacrr, busclk_div; | |
112 | ||
113 | ccm_cacrr = readl(&ccm->cacrr); | |
114 | ||
115 | busclk_div = ccm_cacrr & CCM_CACRR_BUS_CLK_DIV_MASK; | |
116 | busclk_div >>= CCM_CACRR_BUS_CLK_DIV_OFFSET; | |
117 | busclk_div += 1; | |
118 | ||
119 | return get_mcu_main_clk() / busclk_div; | |
120 | } | |
121 | ||
122 | static u32 get_ipg_clk(void) | |
123 | { | |
124 | struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; | |
125 | u32 ccm_cacrr, ipgclk_div; | |
126 | ||
127 | ccm_cacrr = readl(&ccm->cacrr); | |
128 | ||
129 | ipgclk_div = ccm_cacrr & CCM_CACRR_IPG_CLK_DIV_MASK; | |
130 | ipgclk_div >>= CCM_CACRR_IPG_CLK_DIV_OFFSET; | |
131 | ipgclk_div += 1; | |
132 | ||
133 | return get_bus_clk() / ipgclk_div; | |
134 | } | |
135 | ||
136 | static u32 get_uart_clk(void) | |
137 | { | |
138 | return get_ipg_clk(); | |
139 | } | |
140 | ||
141 | static u32 get_sdhc_clk(void) | |
142 | { | |
143 | struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; | |
144 | u32 ccm_cscmr1, ccm_cscdr2, sdhc_clk_sel, sdhc_clk_div; | |
145 | u32 freq = 0; | |
146 | ||
147 | ccm_cscmr1 = readl(&ccm->cscmr1); | |
148 | sdhc_clk_sel = ccm_cscmr1 & CCM_CSCMR1_ESDHC1_CLK_SEL_MASK; | |
149 | sdhc_clk_sel >>= CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET; | |
150 | ||
151 | ccm_cscdr2 = readl(&ccm->cscdr2); | |
152 | sdhc_clk_div = ccm_cscdr2 & CCM_CSCDR2_ESDHC1_CLK_DIV_MASK; | |
153 | sdhc_clk_div >>= CCM_CSCDR2_ESDHC1_CLK_DIV_OFFSET; | |
154 | sdhc_clk_div += 1; | |
155 | ||
156 | switch (sdhc_clk_sel) { | |
157 | case 0: | |
158 | freq = PLL3_MAIN_FREQ; | |
159 | break; | |
160 | case 1: | |
161 | freq = PLL3_PFD3_FREQ; | |
162 | break; | |
163 | case 2: | |
164 | freq = PLL1_PFD3_FREQ; | |
165 | break; | |
166 | case 3: | |
167 | freq = get_bus_clk(); | |
168 | break; | |
169 | } | |
170 | ||
171 | return freq / sdhc_clk_div; | |
172 | } | |
173 | ||
174 | u32 get_fec_clk(void) | |
175 | { | |
176 | struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; | |
177 | u32 ccm_cscmr2, rmii_clk_sel; | |
178 | u32 freq = 0; | |
179 | ||
180 | ccm_cscmr2 = readl(&ccm->cscmr2); | |
181 | rmii_clk_sel = ccm_cscmr2 & CCM_CSCMR2_RMII_CLK_SEL_MASK; | |
182 | rmii_clk_sel >>= CCM_CSCMR2_RMII_CLK_SEL_OFFSET; | |
183 | ||
184 | switch (rmii_clk_sel) { | |
185 | case 0: | |
186 | freq = ENET_EXTERNAL_CLK; | |
187 | break; | |
188 | case 1: | |
189 | freq = AUDIO_EXTERNAL_CLK; | |
190 | break; | |
191 | case 2: | |
192 | freq = PLL5_MAIN_FREQ; | |
193 | break; | |
194 | case 3: | |
195 | freq = PLL5_MAIN_FREQ / 2; | |
196 | break; | |
197 | } | |
198 | ||
199 | return freq; | |
200 | } | |
201 | ||
1221b3d7 AW |
202 | static u32 get_i2c_clk(void) |
203 | { | |
204 | return get_ipg_clk(); | |
205 | } | |
206 | ||
098d8584 BD |
207 | static u32 get_dspi_clk(void) |
208 | { | |
209 | return get_ipg_clk(); | |
210 | } | |
211 | ||
c40d612b PF |
212 | u32 get_lpuart_clk(void) |
213 | { | |
214 | return get_uart_clk(); | |
215 | } | |
216 | ||
24e8bee5 AW |
217 | unsigned int mxc_get_clock(enum mxc_clock clk) |
218 | { | |
219 | switch (clk) { | |
220 | case MXC_ARM_CLK: | |
221 | return get_mcu_main_clk(); | |
222 | case MXC_BUS_CLK: | |
223 | return get_bus_clk(); | |
224 | case MXC_IPG_CLK: | |
225 | return get_ipg_clk(); | |
226 | case MXC_UART_CLK: | |
227 | return get_uart_clk(); | |
228 | case MXC_ESDHC_CLK: | |
229 | return get_sdhc_clk(); | |
230 | case MXC_FEC_CLK: | |
231 | return get_fec_clk(); | |
1221b3d7 AW |
232 | case MXC_I2C_CLK: |
233 | return get_i2c_clk(); | |
098d8584 BD |
234 | case MXC_DSPI_CLK: |
235 | return get_dspi_clk(); | |
24e8bee5 AW |
236 | default: |
237 | break; | |
238 | } | |
239 | return -1; | |
240 | } | |
241 | ||
242 | /* Dump some core clocks */ | |
243 | int do_vf610_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, | |
244 | char * const argv[]) | |
245 | { | |
246 | printf("\n"); | |
247 | printf("cpu clock : %8d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); | |
248 | printf("bus clock : %8d MHz\n", mxc_get_clock(MXC_BUS_CLK) / 1000000); | |
249 | printf("ipg clock : %8d MHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000000); | |
250 | ||
251 | return 0; | |
252 | } | |
253 | ||
254 | U_BOOT_CMD( | |
255 | clocks, CONFIG_SYS_MAXARGS, 1, do_vf610_showclocks, | |
256 | "display clocks", | |
257 | "" | |
258 | ); | |
259 | ||
260 | #ifdef CONFIG_FEC_MXC | |
a01cc0ac | 261 | __weak void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) |
24e8bee5 AW |
262 | { |
263 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | |
264 | struct fuse_bank *bank = &ocotp->bank[4]; | |
265 | struct fuse_bank4_regs *fuse = | |
266 | (struct fuse_bank4_regs *)bank->fuse_regs; | |
267 | ||
268 | u32 value = readl(&fuse->mac_addr0); | |
269 | mac[0] = (value >> 8); | |
270 | mac[1] = value; | |
271 | ||
272 | value = readl(&fuse->mac_addr1); | |
273 | mac[2] = value >> 24; | |
274 | mac[3] = value >> 16; | |
275 | mac[4] = value >> 8; | |
276 | mac[5] = value; | |
277 | } | |
278 | #endif | |
279 | ||
37cf2152 PF |
280 | u32 get_cpu_rev(void) |
281 | { | |
282 | return MXC_CPU_VF610 << 12; | |
283 | } | |
284 | ||
24e8bee5 AW |
285 | #if defined(CONFIG_DISPLAY_CPUINFO) |
286 | static char *get_reset_cause(void) | |
287 | { | |
288 | u32 cause; | |
289 | struct src *src_regs = (struct src *)SRC_BASE_ADDR; | |
290 | ||
291 | cause = readl(&src_regs->srsr); | |
292 | writel(cause, &src_regs->srsr); | |
24e8bee5 | 293 | |
9e89a64f SA |
294 | if (cause & SRC_SRSR_POR_RST) |
295 | return "POWER ON RESET"; | |
296 | else if (cause & SRC_SRSR_WDOG_A5) | |
297 | return "WDOG A5"; | |
298 | else if (cause & SRC_SRSR_WDOG_M4) | |
299 | return "WDOG M4"; | |
300 | else if (cause & SRC_SRSR_JTAG_RST) | |
24e8bee5 | 301 | return "JTAG HIGH-Z"; |
9e89a64f SA |
302 | else if (cause & SRC_SRSR_SW_RST) |
303 | return "SW RESET"; | |
304 | else if (cause & SRC_SRSR_RESETB) | |
24e8bee5 | 305 | return "EXTERNAL RESET"; |
9e89a64f | 306 | else |
24e8bee5 | 307 | return "unknown reset"; |
24e8bee5 AW |
308 | } |
309 | ||
310 | int print_cpuinfo(void) | |
311 | { | |
1db503c4 SM |
312 | printf("CPU: Freescale Vybrid VF%s at %d MHz\n", |
313 | soc_type, mxc_get_clock(MXC_ARM_CLK) / 1000000); | |
24e8bee5 AW |
314 | printf("Reset cause: %s\n", get_reset_cause()); |
315 | ||
316 | return 0; | |
317 | } | |
318 | #endif | |
319 | ||
1db503c4 SM |
320 | int arch_cpu_init(void) |
321 | { | |
322 | struct mscm *mscm = (struct mscm *)MSCM_BASE_ADDR; | |
323 | ||
324 | soc_type[0] = mscm->cpxcount ? '6' : '5'; /*Dual Core => VF6x0 */ | |
325 | soc_type[1] = mscm->cpxcfg1 ? '1' : '0'; /* L2 Cache => VFx10 */ | |
326 | ||
327 | return 0; | |
328 | } | |
329 | ||
330 | #ifdef CONFIG_ARCH_MISC_INIT | |
331 | int arch_misc_init(void) | |
332 | { | |
333 | char soc[6]; | |
334 | ||
d7255e8d | 335 | strcpy(soc, "vf"); |
1db503c4 | 336 | strcat(soc, soc_type); |
382bee57 | 337 | env_set("soc", soc); |
1db503c4 SM |
338 | |
339 | return 0; | |
340 | } | |
341 | #endif | |
342 | ||
24e8bee5 AW |
343 | int cpu_eth_init(bd_t *bis) |
344 | { | |
345 | int rc = -ENODEV; | |
346 | ||
347 | #if defined(CONFIG_FEC_MXC) | |
348 | rc = fecmxc_initialize(bis); | |
349 | #endif | |
350 | ||
351 | return rc; | |
352 | } | |
353 | ||
e37ac717 | 354 | #ifdef CONFIG_FSL_ESDHC_IMX |
24e8bee5 AW |
355 | int cpu_mmc_init(bd_t *bis) |
356 | { | |
357 | return fsl_esdhc_mmc_init(bis); | |
358 | } | |
359 | #endif | |
360 | ||
361 | int get_clocks(void) | |
362 | { | |
e37ac717 | 363 | #ifdef CONFIG_FSL_ESDHC_IMX |
24e8bee5 AW |
364 | gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); |
365 | #endif | |
366 | return 0; | |
367 | } | |
7a90a1f2 | 368 | |
10015025 | 369 | #if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) |
7a90a1f2 SA |
370 | void enable_caches(void) |
371 | { | |
372 | #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) | |
373 | enum dcache_option option = DCACHE_WRITETHROUGH; | |
374 | #else | |
375 | enum dcache_option option = DCACHE_WRITEBACK; | |
376 | #endif | |
377 | dcache_enable(); | |
378 | icache_enable(); | |
379 | ||
380 | /* Enable caching on OCRAM */ | |
381 | mmu_set_region_dcache_behaviour(IRAM_BASE_ADDR, IRAM_SIZE, option); | |
382 | } | |
383 | #endif | |
7db8b854 LM |
384 | |
385 | #ifdef CONFIG_SYS_I2C_MXC | |
386 | /* i2c_num can be from 0 - 3 */ | |
387 | int enable_i2c_clk(unsigned char enable, unsigned int i2c_num) | |
388 | { | |
389 | struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; | |
390 | ||
391 | switch (i2c_num) { | |
392 | case 0: | |
393 | clrsetbits_le32(&ccm->ccgr4, CCM_CCGR4_I2C0_CTRL_MASK, | |
394 | CCM_CCGR4_I2C0_CTRL_MASK); | |
395 | case 2: | |
396 | clrsetbits_le32(&ccm->ccgr10, CCM_CCGR10_I2C2_CTRL_MASK, | |
397 | CCM_CCGR10_I2C2_CTRL_MASK); | |
398 | break; | |
399 | default: | |
400 | return -EINVAL; | |
401 | } | |
402 | ||
403 | return 0; | |
404 | } | |
405 | #endif |