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