]>
Commit | Line | Data |
---|---|---|
d1c559af LFT |
1 | /* |
2 | * Copyright (C) 2012-2017 Altera Corporation <www.altera.com> | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <asm/io.h> | |
9 | #include <errno.h> | |
10 | #include <fdtdec.h> | |
11 | #include <libfdt.h> | |
12 | #include <altera.h> | |
13 | #include <miiphy.h> | |
14 | #include <netdev.h> | |
15 | #include <watchdog.h> | |
16 | #include <asm/arch/misc.h> | |
17 | #include <asm/arch/reset_manager.h> | |
18 | #include <asm/arch/scan_manager.h> | |
19 | #include <asm/arch/sdram.h> | |
20 | #include <asm/arch/system_manager.h> | |
21 | #include <asm/arch/nic301.h> | |
22 | #include <asm/arch/scu.h> | |
23 | #include <asm/pl310.h> | |
24 | ||
25 | #include <dt-bindings/reset/altr,rst-mgr.h> | |
26 | ||
27 | DECLARE_GLOBAL_DATA_PTR; | |
28 | ||
29 | static struct pl310_regs *const pl310 = | |
30 | (struct pl310_regs *)CONFIG_SYS_PL310_BASE; | |
31 | static struct socfpga_system_manager *sysmgr_regs = | |
32 | (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; | |
d1c559af LFT |
33 | static struct nic301_registers *nic301_regs = |
34 | (struct nic301_registers *)SOCFPGA_L3REGS_ADDRESS; | |
35 | static struct scu_registers *scu_regs = | |
36 | (struct scu_registers *)SOCFPGA_MPUSCU_ADDRESS; | |
d1c559af LFT |
37 | |
38 | /* | |
39 | * DesignWare Ethernet initialization | |
40 | */ | |
41 | #ifdef CONFIG_ETH_DESIGNWARE | |
42 | void dwmac_deassert_reset(const unsigned int of_reset_id, | |
43 | const u32 phymode) | |
44 | { | |
45 | u32 physhift, reset; | |
46 | ||
47 | if (of_reset_id == EMAC0_RESET) { | |
48 | physhift = SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB; | |
49 | reset = SOCFPGA_RESET(EMAC0); | |
50 | } else if (of_reset_id == EMAC1_RESET) { | |
51 | physhift = SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB; | |
52 | reset = SOCFPGA_RESET(EMAC1); | |
53 | } else { | |
54 | printf("GMAC: Invalid reset ID (%i)!\n", of_reset_id); | |
55 | return; | |
56 | } | |
57 | ||
58 | /* configure to PHY interface select choosed */ | |
59 | clrsetbits_le32(&sysmgr_regs->emacgrp_ctrl, | |
60 | SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << physhift, | |
61 | phymode << physhift); | |
62 | ||
63 | /* Release the EMAC controller from reset */ | |
64 | socfpga_per_reset(reset, 0); | |
65 | } | |
66 | ||
67 | static u32 dwmac_phymode_to_modereg(const char *phymode, u32 *modereg) | |
68 | { | |
69 | if (!phymode) | |
70 | return -EINVAL; | |
71 | ||
72 | if (!strcmp(phymode, "mii") || !strcmp(phymode, "gmii")) { | |
73 | *modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; | |
74 | return 0; | |
75 | } | |
76 | ||
77 | if (!strcmp(phymode, "rgmii")) { | |
78 | *modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; | |
79 | return 0; | |
80 | } | |
81 | ||
82 | if (!strcmp(phymode, "rmii")) { | |
83 | *modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII; | |
84 | return 0; | |
85 | } | |
86 | ||
87 | return -EINVAL; | |
88 | } | |
89 | ||
90 | static int socfpga_eth_reset(void) | |
91 | { | |
92 | const void *fdt = gd->fdt_blob; | |
93 | struct fdtdec_phandle_args args; | |
94 | const char *phy_mode; | |
95 | u32 phy_modereg; | |
96 | int nodes[2]; /* Max. two GMACs */ | |
97 | int ret, count; | |
98 | int i, node; | |
99 | ||
100 | /* Put both GMACs into RESET state. */ | |
101 | socfpga_per_reset(SOCFPGA_RESET(EMAC0), 1); | |
102 | socfpga_per_reset(SOCFPGA_RESET(EMAC1), 1); | |
103 | ||
104 | count = fdtdec_find_aliases_for_id(fdt, "ethernet", | |
105 | COMPAT_ALTERA_SOCFPGA_DWMAC, | |
106 | nodes, ARRAY_SIZE(nodes)); | |
107 | for (i = 0; i < count; i++) { | |
108 | node = nodes[i]; | |
109 | if (node <= 0) | |
110 | continue; | |
111 | ||
112 | ret = fdtdec_parse_phandle_with_args(fdt, node, "resets", | |
113 | "#reset-cells", 1, 0, | |
114 | &args); | |
115 | if (ret || (args.args_count != 1)) { | |
116 | debug("GMAC%i: Failed to parse DT 'resets'!\n", i); | |
117 | continue; | |
118 | } | |
119 | ||
120 | phy_mode = fdt_getprop(fdt, node, "phy-mode", NULL); | |
121 | ret = dwmac_phymode_to_modereg(phy_mode, &phy_modereg); | |
122 | if (ret) { | |
123 | debug("GMAC%i: Failed to parse DT 'phy-mode'!\n", i); | |
124 | continue; | |
125 | } | |
126 | ||
127 | dwmac_deassert_reset(args.args[0], phy_modereg); | |
128 | } | |
129 | ||
130 | return 0; | |
131 | } | |
132 | #else | |
133 | static int socfpga_eth_reset(void) | |
134 | { | |
135 | return 0; | |
136 | }; | |
137 | #endif | |
138 | ||
139 | static const struct { | |
140 | const u16 pn; | |
141 | const char *name; | |
142 | const char *var; | |
5e8c39d4 | 143 | } socfpga_fpga_model[] = { |
d1c559af LFT |
144 | /* Cyclone V E */ |
145 | { 0x2b15, "Cyclone V, E/A2", "cv_e_a2" }, | |
146 | { 0x2b05, "Cyclone V, E/A4", "cv_e_a4" }, | |
147 | { 0x2b22, "Cyclone V, E/A5", "cv_e_a5" }, | |
148 | { 0x2b13, "Cyclone V, E/A7", "cv_e_a7" }, | |
149 | { 0x2b14, "Cyclone V, E/A9", "cv_e_a9" }, | |
150 | /* Cyclone V GX/GT */ | |
151 | { 0x2b01, "Cyclone V, GX/C3", "cv_gx_c3" }, | |
152 | { 0x2b12, "Cyclone V, GX/C4", "cv_gx_c4" }, | |
153 | { 0x2b02, "Cyclone V, GX/C5 or GT/D5", "cv_gx_c5" }, | |
154 | { 0x2b03, "Cyclone V, GX/C7 or GT/D7", "cv_gx_c7" }, | |
155 | { 0x2b04, "Cyclone V, GX/C9 or GT/D9", "cv_gx_c9" }, | |
156 | /* Cyclone V SE/SX/ST */ | |
157 | { 0x2d11, "Cyclone V, SE/A2 or SX/C2", "cv_se_a2" }, | |
158 | { 0x2d01, "Cyclone V, SE/A4 or SX/C4", "cv_se_a4" }, | |
159 | { 0x2d12, "Cyclone V, SE/A5 or SX/C5 or ST/D5", "cv_se_a5" }, | |
160 | { 0x2d02, "Cyclone V, SE/A6 or SX/C6 or ST/D6", "cv_se_a6" }, | |
161 | /* Arria V */ | |
162 | { 0x2d03, "Arria V, D5", "av_d5" }, | |
163 | }; | |
164 | ||
165 | static int socfpga_fpga_id(const bool print_id) | |
166 | { | |
167 | const u32 altera_mi = 0x6e; | |
168 | const u32 id = scan_mgr_get_fpga_id(); | |
169 | ||
170 | const u32 lsb = id & 0x00000001; | |
171 | const u32 mi = (id >> 1) & 0x000007ff; | |
172 | const u32 pn = (id >> 12) & 0x0000ffff; | |
173 | const u32 version = (id >> 28) & 0x0000000f; | |
174 | int i; | |
175 | ||
176 | if ((mi != altera_mi) || (lsb != 1)) { | |
177 | printf("FPGA: Not Altera chip ID\n"); | |
178 | return -EINVAL; | |
179 | } | |
180 | ||
181 | for (i = 0; i < ARRAY_SIZE(socfpga_fpga_model); i++) | |
182 | if (pn == socfpga_fpga_model[i].pn) | |
183 | break; | |
184 | ||
185 | if (i == ARRAY_SIZE(socfpga_fpga_model)) { | |
186 | printf("FPGA: Unknown Altera chip, ID 0x%08x\n", id); | |
187 | return -EINVAL; | |
188 | } | |
189 | ||
190 | if (print_id) | |
191 | printf("FPGA: Altera %s, version 0x%01x\n", | |
192 | socfpga_fpga_model[i].name, version); | |
193 | return i; | |
194 | } | |
195 | ||
196 | /* | |
197 | * Print CPU information | |
198 | */ | |
199 | #if defined(CONFIG_DISPLAY_CPUINFO) | |
200 | int print_cpuinfo(void) | |
201 | { | |
202 | const u32 bsel = | |
203 | SYSMGR_GET_BOOTINFO_BSEL(readl(&sysmgr_regs->bootinfo)); | |
204 | ||
205 | puts("CPU: Altera SoCFPGA Platform\n"); | |
206 | socfpga_fpga_id(1); | |
207 | ||
208 | printf("BOOT: %s\n", bsel_str[bsel].name); | |
209 | return 0; | |
210 | } | |
211 | #endif | |
212 | ||
213 | #ifdef CONFIG_ARCH_MISC_INIT | |
214 | int arch_misc_init(void) | |
215 | { | |
216 | const u32 bsel = readl(&sysmgr_regs->bootinfo) & 0x7; | |
217 | const int fpga_id = socfpga_fpga_id(0); | |
382bee57 | 218 | env_set("bootmode", bsel_str[bsel].mode); |
d1c559af | 219 | if (fpga_id >= 0) |
382bee57 | 220 | env_set("fpgatype", socfpga_fpga_model[fpga_id].var); |
d1c559af LFT |
221 | return socfpga_eth_reset(); |
222 | } | |
223 | #endif | |
224 | ||
225 | /* | |
226 | * Convert all NIC-301 AMBA slaves from secure to non-secure | |
227 | */ | |
228 | static void socfpga_nic301_slave_ns(void) | |
229 | { | |
230 | writel(0x1, &nic301_regs->lwhps2fpgaregs); | |
231 | writel(0x1, &nic301_regs->hps2fpgaregs); | |
232 | writel(0x1, &nic301_regs->acp); | |
233 | writel(0x1, &nic301_regs->rom); | |
234 | writel(0x1, &nic301_regs->ocram); | |
235 | writel(0x1, &nic301_regs->sdrdata); | |
236 | } | |
237 | ||
238 | static u32 iswgrp_handoff[8]; | |
239 | ||
240 | int arch_early_init_r(void) | |
241 | { | |
242 | int i; | |
243 | ||
244 | /* | |
245 | * Write magic value into magic register to unlock support for | |
246 | * issuing warm reset. The ancient kernel code expects this | |
247 | * value to be written into the register by the bootloader, so | |
248 | * to support that old code, we write it here instead of in the | |
249 | * reset_cpu() function just before resetting the CPU. | |
250 | */ | |
251 | writel(0xae9efebc, &sysmgr_regs->romcodegrp_warmramgrp_enable); | |
252 | ||
253 | for (i = 0; i < 8; i++) /* Cache initial SW setting regs */ | |
254 | iswgrp_handoff[i] = readl(&sysmgr_regs->iswgrp_handoff[i]); | |
255 | ||
256 | socfpga_bridges_reset(1); | |
257 | ||
258 | socfpga_nic301_slave_ns(); | |
259 | ||
260 | /* | |
261 | * Private components security: | |
262 | * U-Boot : configure private timer, global timer and cpu component | |
263 | * access as non secure for kernel stage (as required by Linux) | |
264 | */ | |
265 | setbits_le32(&scu_regs->sacr, 0xfff); | |
266 | ||
267 | /* Configure the L2 controller to make SDRAM start at 0 */ | |
268 | #ifdef CONFIG_SOCFPGA_VIRTUAL_TARGET | |
269 | writel(0x2, &nic301_regs->remap); | |
270 | #else | |
271 | writel(0x1, &nic301_regs->remap); /* remap.mpuzero */ | |
272 | writel(0x1, &pl310->pl310_addr_filter_start); | |
273 | #endif | |
274 | ||
275 | /* Add device descriptor to FPGA device table */ | |
276 | socfpga_fpga_add(); | |
277 | ||
278 | #ifdef CONFIG_DESIGNWARE_SPI | |
279 | /* Get Designware SPI controller out of reset */ | |
280 | socfpga_per_reset(SOCFPGA_RESET(SPIM0), 0); | |
281 | socfpga_per_reset(SOCFPGA_RESET(SPIM1), 0); | |
282 | #endif | |
283 | ||
284 | #ifdef CONFIG_NAND_DENALI | |
285 | socfpga_per_reset(SOCFPGA_RESET(NAND), 0); | |
286 | #endif | |
287 | ||
288 | return 0; | |
289 | } | |
290 | ||
b4b9814f TR |
291 | #ifndef CONFIG_SPL_BUILD |
292 | static struct socfpga_reset_manager *reset_manager_base = | |
293 | (struct socfpga_reset_manager *)SOCFPGA_RSTMGR_ADDRESS; | |
294 | static struct socfpga_sdr_ctrl *sdr_ctrl = | |
295 | (struct socfpga_sdr_ctrl *)SDR_CTRLGRP_ADDRESS; | |
296 | ||
d1c559af LFT |
297 | static void socfpga_sdram_apply_static_cfg(void) |
298 | { | |
299 | const u32 applymask = 0x8; | |
300 | u32 val = readl(&sdr_ctrl->static_cfg) | applymask; | |
301 | ||
302 | /* | |
303 | * SDRAM staticcfg register specific: | |
304 | * When applying the register setting, the CPU must not access | |
305 | * SDRAM. Luckily for us, we can abuse i-cache here to help us | |
306 | * circumvent the SDRAM access issue. The idea is to make sure | |
307 | * that the code is in one full i-cache line by branching past | |
308 | * it and back. Once it is in the i-cache, we execute the core | |
309 | * of the code and apply the register settings. | |
310 | * | |
311 | * The code below uses 7 instructions, while the Cortex-A9 has | |
312 | * 32-byte cachelines, thus the limit is 8 instructions total. | |
313 | */ | |
314 | asm volatile( | |
315 | ".align 5 \n" | |
316 | " b 2f \n" | |
317 | "1: str %0, [%1] \n" | |
318 | " dsb \n" | |
319 | " isb \n" | |
320 | " b 3f \n" | |
321 | "2: b 1b \n" | |
322 | "3: nop \n" | |
323 | : : "r"(val), "r"(&sdr_ctrl->static_cfg) : "memory", "cc"); | |
324 | } | |
325 | ||
b4b9814f | 326 | static int do_bridge(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
d1c559af LFT |
327 | { |
328 | if (argc != 2) | |
329 | return CMD_RET_USAGE; | |
330 | ||
331 | argv++; | |
332 | ||
333 | switch (*argv[0]) { | |
334 | case 'e': /* Enable */ | |
335 | writel(iswgrp_handoff[2], &sysmgr_regs->fpgaintfgrp_module); | |
336 | socfpga_sdram_apply_static_cfg(); | |
337 | writel(iswgrp_handoff[3], &sdr_ctrl->fpgaport_rst); | |
338 | writel(iswgrp_handoff[0], &reset_manager_base->brg_mod_reset); | |
339 | writel(iswgrp_handoff[1], &nic301_regs->remap); | |
340 | break; | |
341 | case 'd': /* Disable */ | |
342 | writel(0, &sysmgr_regs->fpgaintfgrp_module); | |
343 | writel(0, &sdr_ctrl->fpgaport_rst); | |
344 | socfpga_sdram_apply_static_cfg(); | |
345 | writel(0, &reset_manager_base->brg_mod_reset); | |
346 | writel(1, &nic301_regs->remap); | |
347 | break; | |
348 | default: | |
349 | return CMD_RET_USAGE; | |
350 | } | |
351 | ||
352 | return 0; | |
353 | } | |
354 | ||
355 | U_BOOT_CMD( | |
356 | bridge, 2, 1, do_bridge, | |
357 | "SoCFPGA HPS FPGA bridge control", | |
358 | "enable - Enable HPS-to-FPGA, FPGA-to-HPS, LWHPS-to-FPGA bridges\n" | |
359 | "bridge disable - Enable HPS-to-FPGA, FPGA-to-HPS, LWHPS-to-FPGA bridges\n" | |
360 | "" | |
361 | ); | |
b4b9814f | 362 | #endif |