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