blob: bc07dae318b5946ea39209d04d1be0aeea3ae44c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Eddy Petrișor5178dc12016-06-05 03:43:00 +03002/*
3 * (C) Copyright 2013-2016, Freescale Semiconductor, Inc.
Eddy Petrișor5178dc12016-06-05 03:43:00 +03004 */
5
6#include <common.h>
Simon Glass85d65312019-12-28 10:44:58 -07007#include <clock_legacy.h>
Simon Glassafb02152019-12-28 10:45:01 -07008#include <cpu_func.h>
Simon Glass97589732020-05-10 11:40:02 -06009#include <init.h>
Simon Glass274e0b02020-05-10 11:39:56 -060010#include <net.h>
Eddy Petrișor5178dc12016-06-05 03:43:00 +030011#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
21u32 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
29DECLARE_GLOBAL_DATA_PTR;
30
31static 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 */
86static 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
97static 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
132static 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
179static 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
196static 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
230static 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
246static 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
262static u32 get_i2c_clk(void)
263{
264 return get_peripherals_clk();
265}
266
267/* return clocks in Hz */
268unsigned 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)
294static 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
321void reset_cpu(ulong addr)
322{
323 printf("Feature not supported.\n");
324};
325
326int 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
336int 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
347int get_clocks(void)
348{
Yangbo Lu73340382019-06-21 11:42:28 +0800349#ifdef CONFIG_FSL_ESDHC_IMX
Eddy Petrișor5178dc12016-06-05 03:43:00 +0300350 gd->arch.sdhc_clk = mxc_get_clock(MXC_USDHC_CLK);
351#endif
352 return 0;
353}