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