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