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