1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2013-2016, Freescale Semiconductor, Inc.
4 */
5
6 #include <common.h>
7 #include <clock_legacy.h>
8 #include <cpu_func.h>
9 #include <init.h>
10 #include <net.h>
11 #include <asm/global_data.h>
12 #include <asm/io.h>
13 #include <asm/arch/imx-regs.h>
14 #include <asm/arch/clock.h>
15 #include <asm/arch/mc_cgm_regs.h>
16 #include <asm/arch/mc_me_regs.h>
17 #include <asm/arch/mc_rgm_regs.h>
18 #include <netdev.h>
19 #include <div64.h>
20 #include <errno.h>
21
get_cpu_rev(void)22 u32 get_cpu_rev(void)
23 {
24 struct mscm_ir *mscmir = (struct mscm_ir *)MSCM_BASE_ADDR;
25 u32 cpu = readl(&mscmir->cpxtype);
26
27 return cpu;
28 }
29
30 DECLARE_GLOBAL_DATA_PTR;
31
get_pllfreq(u32 pll,u32 refclk_freq,u32 plldv,u32 pllfd,u32 selected_output)32 static uintptr_t get_pllfreq(u32 pll, u32 refclk_freq, u32 plldv,
33 u32 pllfd, u32 selected_output)
34 {
35 u32 vco = 0, plldv_prediv = 0, plldv_mfd = 0, pllfd_mfn = 0;
36 u32 plldv_rfdphi_div = 0, fout = 0;
37 u32 dfs_portn = 0, dfs_mfn = 0, dfs_mfi = 0;
38
39 if (selected_output > DFS_MAXNUMBER) {
40 return -1;
41 }
42
43 plldv_prediv =
44 (plldv & PLLDIG_PLLDV_PREDIV_MASK) >> PLLDIG_PLLDV_PREDIV_OFFSET;
45 plldv_mfd = (plldv & PLLDIG_PLLDV_MFD_MASK);
46
47 pllfd_mfn = (pllfd & PLLDIG_PLLFD_MFN_MASK);
48
49 plldv_prediv = plldv_prediv == 0 ? 1 : plldv_prediv;
50
51 /* The formula for VCO is from TR manual, rev. D */
52 vco = refclk_freq / plldv_prediv * (plldv_mfd + pllfd_mfn / 20481);
53
54 if (selected_output != 0) {
55 /* Determine the RFDPHI for PHI1 */
56 plldv_rfdphi_div =
57 (plldv & PLLDIG_PLLDV_RFDPHI1_MASK) >>
58 PLLDIG_PLLDV_RFDPHI1_OFFSET;
59 plldv_rfdphi_div = plldv_rfdphi_div == 0 ? 1 : plldv_rfdphi_div;
60 if (pll == ARM_PLL || pll == ENET_PLL || pll == DDR_PLL) {
61 dfs_portn =
62 readl(DFS_DVPORTn(pll, selected_output - 1));
63 dfs_mfi =
64 (dfs_portn & DFS_DVPORTn_MFI_MASK) >>
65 DFS_DVPORTn_MFI_OFFSET;
66 dfs_mfn =
67 (dfs_portn & DFS_DVPORTn_MFI_MASK) >>
68 DFS_DVPORTn_MFI_OFFSET;
69 fout = vco / (dfs_mfi + (dfs_mfn / 256));
70 } else {
71 fout = vco / plldv_rfdphi_div;
72 }
73
74 } else {
75 /* Determine the RFDPHI for PHI0 */
76 plldv_rfdphi_div =
77 (plldv & PLLDIG_PLLDV_RFDPHI_MASK) >>
78 PLLDIG_PLLDV_RFDPHI_OFFSET;
79 fout = vco / plldv_rfdphi_div;
80 }
81
82 return fout;
83
84 }
85
86 /* Implemented for ARMPLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_LL */
decode_pll(enum pll_type pll,u32 refclk_freq,u32 selected_output)87 static uintptr_t decode_pll(enum pll_type pll, u32 refclk_freq,
88 u32 selected_output)
89 {
90 u32 plldv, pllfd;
91
92 plldv = readl(PLLDIG_PLLDV(pll));
93 pllfd = readl(PLLDIG_PLLFD(pll));
94
95 return get_pllfreq(pll, refclk_freq, plldv, pllfd, selected_output);
96 }
97
get_mcu_main_clk(void)98 static u32 get_mcu_main_clk(void)
99 {
100 u32 coreclk_div;
101 u32 sysclk_sel;
102 u32 freq = 0;
103
104 sysclk_sel = readl(CGM_SC_SS(MC_CGM1_BASE_ADDR)) & MC_CGM_SC_SEL_MASK;
105 sysclk_sel >>= MC_CGM_SC_SEL_OFFSET;
106
107 coreclk_div =
108 readl(CGM_SC_DCn(MC_CGM1_BASE_ADDR, 0)) & MC_CGM_SC_DCn_PREDIV_MASK;
109 coreclk_div >>= MC_CGM_SC_DCn_PREDIV_OFFSET;
110 coreclk_div += 1;
111
112 switch (sysclk_sel) {
113 case MC_CGM_SC_SEL_FIRC:
114 freq = FIRC_CLK_FREQ;
115 break;
116 case MC_CGM_SC_SEL_XOSC:
117 freq = XOSC_CLK_FREQ;
118 break;
119 case MC_CGM_SC_SEL_ARMPLL:
120 /* ARMPLL has as source XOSC and CORE_CLK has as input PHI0 */
121 freq = decode_pll(ARM_PLL, XOSC_CLK_FREQ, 0);
122 break;
123 case MC_CGM_SC_SEL_CLKDISABLE:
124 printf("Sysclk is disabled\n");
125 break;
126 default:
127 printf("unsupported system clock select\n");
128 }
129
130 return freq / coreclk_div;
131 }
132
get_sys_clk(u32 number)133 static u32 get_sys_clk(u32 number)
134 {
135 u32 sysclk_div, sysclk_div_number;
136 u32 sysclk_sel;
137 u32 freq = 0;
138
139 switch (number) {
140 case 3:
141 sysclk_div_number = 0;
142 break;
143 case 6:
144 sysclk_div_number = 1;
145 break;
146 default:
147 printf("unsupported system clock \n");
148 return -1;
149 }
150 sysclk_sel = readl(CGM_SC_SS(MC_CGM0_BASE_ADDR)) & MC_CGM_SC_SEL_MASK;
151 sysclk_sel >>= MC_CGM_SC_SEL_OFFSET;
152
153 sysclk_div =
154 readl(CGM_SC_DCn(MC_CGM1_BASE_ADDR, sysclk_div_number)) &
155 MC_CGM_SC_DCn_PREDIV_MASK;
156 sysclk_div >>= MC_CGM_SC_DCn_PREDIV_OFFSET;
157 sysclk_div += 1;
158
159 switch (sysclk_sel) {
160 case MC_CGM_SC_SEL_FIRC:
161 freq = FIRC_CLK_FREQ;
162 break;
163 case MC_CGM_SC_SEL_XOSC:
164 freq = XOSC_CLK_FREQ;
165 break;
166 case MC_CGM_SC_SEL_ARMPLL:
167 /* ARMPLL has as source XOSC and SYSn_CLK has as input DFS1 */
168 freq = decode_pll(ARM_PLL, XOSC_CLK_FREQ, 1);
169 break;
170 case MC_CGM_SC_SEL_CLKDISABLE:
171 printf("Sysclk is disabled\n");
172 break;
173 default:
174 printf("unsupported system clock select\n");
175 }
176
177 return freq / sysclk_div;
178 }
179
get_peripherals_clk(void)180 static u32 get_peripherals_clk(void)
181 {
182 u32 aux5clk_div;
183 u32 freq = 0;
184
185 aux5clk_div =
186 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 5, 0)) &
187 MC_CGM_ACn_DCm_PREDIV_MASK;
188 aux5clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
189 aux5clk_div += 1;
190
191 freq = decode_pll(PERIPH_PLL, XOSC_CLK_FREQ, 0);
192
193 return freq / aux5clk_div;
194
195 }
196
get_uart_clk(void)197 static u32 get_uart_clk(void)
198 {
199 u32 auxclk3_div, auxclk3_sel, freq = 0;
200
201 auxclk3_sel =
202 readl(CGM_ACn_SS(MC_CGM0_BASE_ADDR, 3)) & MC_CGM_ACn_SEL_MASK;
203 auxclk3_sel >>= MC_CGM_ACn_SEL_OFFSET;
204
205 auxclk3_div =
206 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 3, 0)) &
207 MC_CGM_ACn_DCm_PREDIV_MASK;
208 auxclk3_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
209 auxclk3_div += 1;
210
211 switch (auxclk3_sel) {
212 case MC_CGM_ACn_SEL_FIRC:
213 freq = FIRC_CLK_FREQ;
214 break;
215 case MC_CGM_ACn_SEL_XOSC:
216 freq = XOSC_CLK_FREQ;
217 break;
218 case MC_CGM_ACn_SEL_PERPLLDIVX:
219 freq = get_peripherals_clk() / 3;
220 break;
221 case MC_CGM_ACn_SEL_SYSCLK:
222 freq = get_sys_clk(6);
223 break;
224 default:
225 printf("unsupported system clock select\n");
226 }
227
228 return freq / auxclk3_div;
229 }
230
get_fec_clk(void)231 static u32 get_fec_clk(void)
232 {
233 u32 aux2clk_div;
234 u32 freq = 0;
235
236 aux2clk_div =
237 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 2, 0)) &
238 MC_CGM_ACn_DCm_PREDIV_MASK;
239 aux2clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
240 aux2clk_div += 1;
241
242 freq = decode_pll(ENET_PLL, XOSC_CLK_FREQ, 0);
243
244 return freq / aux2clk_div;
245 }
246
get_usdhc_clk(void)247 static u32 get_usdhc_clk(void)
248 {
249 u32 aux15clk_div;
250 u32 freq = 0;
251
252 aux15clk_div =
253 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 15, 0)) &
254 MC_CGM_ACn_DCm_PREDIV_MASK;
255 aux15clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET;
256 aux15clk_div += 1;
257
258 freq = decode_pll(ENET_PLL, XOSC_CLK_FREQ, 4);
259
260 return freq / aux15clk_div;
261 }
262
get_i2c_clk(void)263 static u32 get_i2c_clk(void)
264 {
265 return get_peripherals_clk();
266 }
267
268 /* return clocks in Hz */
mxc_get_clock(enum mxc_clock clk)269 unsigned int mxc_get_clock(enum mxc_clock clk)
270 {
271 switch (clk) {
272 case MXC_ARM_CLK:
273 return get_mcu_main_clk();
274 case MXC_PERIPHERALS_CLK:
275 return get_peripherals_clk();
276 case MXC_UART_CLK:
277 return get_uart_clk();
278 case MXC_FEC_CLK:
279 return get_fec_clk();
280 case MXC_I2C_CLK:
281 return get_i2c_clk();
282 case MXC_USDHC_CLK:
283 return get_usdhc_clk();
284 default:
285 break;
286 }
287 printf("Error: Unsupported function to read the frequency! \
288 Please define it correctly!");
289 return -1;
290 }
291
292 /* Not yet implemented - int soc_clk_dump(); */
293
294 #if defined(CONFIG_DISPLAY_CPUINFO)
get_reset_cause(void)295 static char *get_reset_cause(void)
296 {
297 u32 cause = readl(MC_RGM_BASE_ADDR + 0x300);
298
299 switch (cause) {
300 case F_SWT4:
301 return "WDOG";
302 case F_JTAG:
303 return "JTAG";
304 case F_FCCU_SOFT:
305 return "FCCU soft reaction";
306 case F_FCCU_HARD:
307 return "FCCU hard reaction";
308 case F_SOFT_FUNC:
309 return "Software Functional reset";
310 case F_ST_DONE:
311 return "Self Test done reset";
312 case F_EXT_RST:
313 return "External reset";
314 default:
315 return "unknown reset";
316 }
317
318 }
319
320 #define SRC_SCR_SW_RST (1<<12)
321
reset_cpu(ulong addr)322 void reset_cpu(ulong addr)
323 {
324 printf("Feature not supported.\n");
325 };
326
print_cpuinfo(void)327 int print_cpuinfo(void)
328 {
329 printf("CPU: Freescale Treerunner S32V234 at %d MHz\n",
330 mxc_get_clock(MXC_ARM_CLK) / 1000000);
331 printf("Reset cause: %s\n", get_reset_cause());
332
333 return 0;
334 }
335 #endif
336
cpu_eth_init(struct bd_info * bis)337 int cpu_eth_init(struct bd_info * bis)
338 {
339 int rc = -ENODEV;
340
341 #if defined(CONFIG_FEC_MXC)
342 rc = fecmxc_initialize(bis);
343 #endif
344
345 return rc;
346 }
347
get_clocks(void)348 int get_clocks(void)
349 {
350 #ifdef CONFIG_FSL_ESDHC_IMX
351 gd->arch.sdhc_clk = mxc_get_clock(MXC_USDHC_CLK);
352 #endif
353 return 0;
354 }
355