]>
Commit | Line | Data |
---|---|---|
41e5ee54 | 1 | /* |
9c6d3b7b | 2 | * Copyright (C) 2014-2015 Stefan Roese <[email protected]> |
41e5ee54 SR |
3 | * |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <netdev.h> | |
4d991cb3 SR |
9 | #include <ahci.h> |
10 | #include <linux/mbus.h> | |
41e5ee54 | 11 | #include <asm/io.h> |
5730360e | 12 | #include <asm/pl310.h> |
41e5ee54 SR |
13 | #include <asm/arch/cpu.h> |
14 | #include <asm/arch/soc.h> | |
7f1adcd7 | 15 | #include <sdhci.h> |
41e5ee54 SR |
16 | |
17 | #define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3)) | |
18 | #define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3)) | |
19 | ||
20 | static struct mbus_win windows[] = { | |
21 | /* PCIE MEM address space */ | |
8ed20d65 SR |
22 | { MBUS_PCI_MEM_BASE, MBUS_PCI_MEM_SIZE, |
23 | CPU_TARGET_PCIE13, CPU_ATTR_PCIE_MEM }, | |
41e5ee54 SR |
24 | |
25 | /* PCIE IO address space */ | |
8ed20d65 SR |
26 | { MBUS_PCI_IO_BASE, MBUS_PCI_IO_SIZE, |
27 | CPU_TARGET_PCIE13, CPU_ATTR_PCIE_IO }, | |
41e5ee54 SR |
28 | |
29 | /* SPI */ | |
8ed20d65 SR |
30 | { MBUS_SPI_BASE, MBUS_SPI_SIZE, |
31 | CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_SPIFLASH }, | |
41e5ee54 SR |
32 | |
33 | /* NOR */ | |
8ed20d65 SR |
34 | { MBUS_BOOTROM_BASE, MBUS_BOOTROM_SIZE, |
35 | CPU_TARGET_DEVICEBUS_BOOTROM_SPI, CPU_ATTR_BOOTROM }, | |
41e5ee54 SR |
36 | }; |
37 | ||
38 | void reset_cpu(unsigned long ignored) | |
39 | { | |
40 | struct mvebu_system_registers *reg = | |
41 | (struct mvebu_system_registers *)MVEBU_SYSTEM_REG_BASE; | |
42 | ||
43 | writel(readl(®->rstoutn_mask) | 1, ®->rstoutn_mask); | |
44 | writel(readl(®->sys_soft_rst) | 1, ®->sys_soft_rst); | |
45 | while (1) | |
46 | ; | |
47 | } | |
48 | ||
9c6d3b7b SR |
49 | int mvebu_soc_family(void) |
50 | { | |
51 | u16 devid = (readl(MVEBU_REG_PCIE_DEVID) >> 16) & 0xffff; | |
52 | ||
53 | if (devid == SOC_MV78460_ID) | |
54 | return MVEBU_SOC_AXP; | |
55 | ||
56 | if (devid == SOC_88F6810_ID || devid == SOC_88F6820_ID || | |
57 | devid == SOC_88F6828_ID) | |
58 | return MVEBU_SOC_A38X; | |
59 | ||
60 | return MVEBU_SOC_UNKNOWN; | |
61 | } | |
62 | ||
41e5ee54 SR |
63 | #if defined(CONFIG_DISPLAY_CPUINFO) |
64 | int print_cpuinfo(void) | |
65 | { | |
66 | u16 devid = (readl(MVEBU_REG_PCIE_DEVID) >> 16) & 0xffff; | |
67 | u8 revid = readl(MVEBU_REG_PCIE_REVID) & 0xff; | |
68 | ||
69 | puts("SoC: "); | |
70 | ||
71 | switch (devid) { | |
72 | case SOC_MV78460_ID: | |
73 | puts("MV78460-"); | |
74 | break; | |
9c6d3b7b SR |
75 | case SOC_88F6810_ID: |
76 | puts("MV88F6810-"); | |
41e5ee54 | 77 | break; |
9c6d3b7b SR |
78 | case SOC_88F6820_ID: |
79 | puts("MV88F6820-"); | |
41e5ee54 | 80 | break; |
9c6d3b7b SR |
81 | case SOC_88F6828_ID: |
82 | puts("MV88F6828-"); | |
41e5ee54 SR |
83 | break; |
84 | default: | |
9c6d3b7b | 85 | puts("Unknown-"); |
41e5ee54 SR |
86 | break; |
87 | } | |
88 | ||
9c6d3b7b SR |
89 | if (mvebu_soc_family() == MVEBU_SOC_AXP) { |
90 | switch (revid) { | |
91 | case 1: | |
92 | puts("A0\n"); | |
93 | break; | |
94 | case 2: | |
95 | puts("B0\n"); | |
96 | break; | |
97 | default: | |
98 | printf("?? (%x)\n", revid); | |
99 | break; | |
100 | } | |
101 | } | |
102 | ||
103 | if (mvebu_soc_family() == MVEBU_SOC_A38X) { | |
104 | switch (revid) { | |
105 | case MV_88F68XX_Z1_ID: | |
106 | puts("Z1\n"); | |
107 | break; | |
108 | case MV_88F68XX_A0_ID: | |
109 | puts("A0\n"); | |
110 | break; | |
111 | default: | |
112 | printf("?? (%x)\n", revid); | |
113 | break; | |
114 | } | |
115 | } | |
116 | ||
41e5ee54 SR |
117 | return 0; |
118 | } | |
119 | #endif /* CONFIG_DISPLAY_CPUINFO */ | |
120 | ||
121 | /* | |
122 | * This function initialize Controller DRAM Fastpath windows. | |
123 | * It takes the CS size information from the 0x1500 scratch registers | |
124 | * and sets the correct windows sizes and base addresses accordingly. | |
125 | * | |
126 | * These values are set in the scratch registers by the Marvell | |
127 | * DDR3 training code, which is executed by the BootROM before the | |
128 | * main payload (U-Boot) is executed. This training code is currently | |
129 | * only available in the Marvell U-Boot version. It needs to be | |
130 | * ported to mainline U-Boot SPL at some point. | |
131 | */ | |
132 | static void update_sdram_window_sizes(void) | |
133 | { | |
134 | u64 base = 0; | |
135 | u32 size, temp; | |
136 | int i; | |
137 | ||
138 | for (i = 0; i < SDRAM_MAX_CS; i++) { | |
139 | size = readl((MVEBU_SDRAM_SCRATCH + (i * 8))) & SDRAM_ADDR_MASK; | |
140 | if (size != 0) { | |
141 | size |= ~(SDRAM_ADDR_MASK); | |
142 | ||
143 | /* Set Base Address */ | |
144 | temp = (base & 0xFF000000ll) | ((base >> 32) & 0xF); | |
145 | writel(temp, MVEBU_SDRAM_BASE + DDR_BASE_CS_OFF(i)); | |
146 | ||
147 | /* | |
148 | * Check if out of max window size and resize | |
149 | * the window | |
150 | */ | |
151 | temp = (readl(MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i)) & | |
152 | ~(SDRAM_ADDR_MASK)) | 1; | |
153 | temp |= (size & SDRAM_ADDR_MASK); | |
154 | writel(temp, MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i)); | |
155 | ||
156 | base += ((u64)size + 1); | |
157 | } else { | |
158 | /* | |
159 | * Disable window if not used, otherwise this | |
160 | * leads to overlapping enabled windows with | |
161 | * pretty strange results | |
162 | */ | |
163 | clrbits_le32(MVEBU_SDRAM_BASE + DDR_SIZE_CS_OFF(i), 1); | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
9f62b44e SR |
168 | void mmu_disable(void) |
169 | { | |
170 | asm volatile( | |
171 | "mrc p15, 0, r0, c1, c0, 0\n" | |
172 | "bic r0, #1\n" | |
173 | "mcr p15, 0, r0, c1, c0, 0\n"); | |
174 | } | |
175 | ||
41e5ee54 | 176 | #ifdef CONFIG_ARCH_CPU_INIT |
e1b078e0 KS |
177 | static void set_cbar(u32 addr) |
178 | { | |
179 | asm("mcr p15, 4, %0, c15, c0" : : "r" (addr)); | |
180 | } | |
181 | ||
182 | ||
41e5ee54 SR |
183 | int arch_cpu_init(void) |
184 | { | |
9f62b44e | 185 | #ifndef CONFIG_SPL_BUILD |
2b181b5b SR |
186 | if (mvebu_soc_family() == MVEBU_SOC_A38X) { |
187 | struct pl310_regs *const pl310 = | |
188 | (struct pl310_regs *)CONFIG_SYS_PL310_BASE; | |
189 | ||
190 | /* | |
191 | * Only with disabled MMU its possible to switch the base | |
192 | * register address on Armada 38x. Without this the SDRAM | |
193 | * located at >= 0x4000.0000 is also not accessible, as its | |
194 | * still locked to cache. | |
195 | * | |
196 | * So to fully release / unlock this area from cache, we need | |
197 | * to first flush all caches, then disable the MMU and | |
198 | * disable the L2 cache. | |
199 | */ | |
200 | icache_disable(); | |
201 | dcache_disable(); | |
202 | mmu_disable(); | |
203 | clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); | |
204 | } | |
9f62b44e SR |
205 | #endif |
206 | ||
41e5ee54 SR |
207 | /* Linux expects the internal registers to be at 0xf1000000 */ |
208 | writel(SOC_REGS_PHY_BASE, INTREG_BASE_ADDR_REG); | |
e1b078e0 | 209 | set_cbar(SOC_REGS_PHY_BASE + 0xC000); |
41e5ee54 SR |
210 | |
211 | /* | |
212 | * We need to call mvebu_mbus_probe() before calling | |
213 | * update_sdram_window_sizes() as it disables all previously | |
214 | * configured mbus windows and then configures them as | |
215 | * required for U-Boot. Calling update_sdram_window_sizes() | |
216 | * without this configuration will not work, as the internal | |
217 | * registers can't be accessed reliably because of potenial | |
218 | * double mapping. | |
219 | * After updating the SDRAM access windows we need to call | |
220 | * mvebu_mbus_probe() again, as this now correctly configures | |
221 | * the SDRAM areas that are later used by the MVEBU drivers | |
222 | * (e.g. USB, NETA). | |
223 | */ | |
224 | ||
225 | /* | |
226 | * First disable all windows | |
227 | */ | |
228 | mvebu_mbus_probe(NULL, 0); | |
229 | ||
9c6d3b7b SR |
230 | if (mvebu_soc_family() == MVEBU_SOC_AXP) { |
231 | /* | |
232 | * Now the SDRAM access windows can be reconfigured using | |
233 | * the information in the SDRAM scratch pad registers | |
234 | */ | |
235 | update_sdram_window_sizes(); | |
236 | } | |
41e5ee54 SR |
237 | |
238 | /* | |
239 | * Finally the mbus windows can be configured with the | |
240 | * updated SDRAM sizes | |
241 | */ | |
242 | mvebu_mbus_probe(windows, ARRAY_SIZE(windows)); | |
243 | ||
244 | return 0; | |
245 | } | |
246 | #endif /* CONFIG_ARCH_CPU_INIT */ | |
247 | ||
248 | /* | |
249 | * SOC specific misc init | |
250 | */ | |
251 | #if defined(CONFIG_ARCH_MISC_INIT) | |
252 | int arch_misc_init(void) | |
253 | { | |
254 | /* Nothing yet, perhaps we need something here later */ | |
255 | return 0; | |
256 | } | |
257 | #endif /* CONFIG_ARCH_MISC_INIT */ | |
258 | ||
259 | #ifdef CONFIG_MVNETA | |
260 | int cpu_eth_init(bd_t *bis) | |
261 | { | |
cae9008f SR |
262 | u32 enet_base[] = { MVEBU_EGIGA0_BASE, MVEBU_EGIGA1_BASE, |
263 | MVEBU_EGIGA2_BASE, MVEBU_EGIGA3_BASE }; | |
264 | u8 phy_addr[] = CONFIG_PHY_ADDR; | |
265 | int i; | |
266 | ||
267 | /* | |
268 | * Only Armada XP supports all 4 ethernet interfaces. A38x has | |
269 | * slightly different base addresses for its 2-3 interfaces. | |
270 | */ | |
271 | if (mvebu_soc_family() != MVEBU_SOC_AXP) { | |
272 | enet_base[1] = MVEBU_EGIGA2_BASE; | |
273 | enet_base[2] = MVEBU_EGIGA3_BASE; | |
274 | } | |
275 | ||
276 | for (i = 0; i < ARRAY_SIZE(phy_addr); i++) | |
277 | mvneta_initialize(bis, enet_base[i], i, phy_addr[i]); | |
41e5ee54 SR |
278 | |
279 | return 0; | |
280 | } | |
281 | #endif | |
282 | ||
7f1adcd7 SR |
283 | #ifdef CONFIG_MV_SDHCI |
284 | int board_mmc_init(bd_t *bis) | |
285 | { | |
286 | mv_sdh_init(MVEBU_SDIO_BASE, 0, 0, | |
287 | SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD); | |
288 | ||
289 | return 0; | |
290 | } | |
291 | #endif | |
292 | ||
4d991cb3 SR |
293 | #ifdef CONFIG_SCSI_AHCI_PLAT |
294 | #define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0 | |
295 | #define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4 | |
296 | ||
297 | #define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4)) | |
298 | #define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4)) | |
299 | #define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4)) | |
300 | ||
301 | static void ahci_mvebu_mbus_config(void __iomem *base) | |
302 | { | |
303 | const struct mbus_dram_target_info *dram; | |
304 | int i; | |
305 | ||
306 | dram = mvebu_mbus_dram_info(); | |
307 | ||
308 | for (i = 0; i < 4; i++) { | |
309 | writel(0, base + AHCI_WINDOW_CTRL(i)); | |
310 | writel(0, base + AHCI_WINDOW_BASE(i)); | |
311 | writel(0, base + AHCI_WINDOW_SIZE(i)); | |
312 | } | |
313 | ||
314 | for (i = 0; i < dram->num_cs; i++) { | |
315 | const struct mbus_dram_window *cs = dram->cs + i; | |
316 | ||
317 | writel((cs->mbus_attr << 8) | | |
318 | (dram->mbus_dram_target_id << 4) | 1, | |
319 | base + AHCI_WINDOW_CTRL(i)); | |
320 | writel(cs->base >> 16, base + AHCI_WINDOW_BASE(i)); | |
321 | writel(((cs->size - 1) & 0xffff0000), | |
322 | base + AHCI_WINDOW_SIZE(i)); | |
323 | } | |
324 | } | |
325 | ||
326 | static void ahci_mvebu_regret_option(void __iomem *base) | |
327 | { | |
328 | /* | |
329 | * Enable the regret bit to allow the SATA unit to regret a | |
330 | * request that didn't receive an acknowlegde and avoid a | |
331 | * deadlock | |
332 | */ | |
333 | writel(0x4, base + AHCI_VENDOR_SPECIFIC_0_ADDR); | |
334 | writel(0x80, base + AHCI_VENDOR_SPECIFIC_0_DATA); | |
335 | } | |
336 | ||
337 | void scsi_init(void) | |
338 | { | |
339 | printf("MVEBU SATA INIT\n"); | |
340 | ahci_mvebu_mbus_config((void __iomem *)MVEBU_SATA0_BASE); | |
341 | ahci_mvebu_regret_option((void __iomem *)MVEBU_SATA0_BASE); | |
342 | ahci_init((void __iomem *)MVEBU_SATA0_BASE); | |
343 | } | |
344 | #endif | |
345 | ||
41e5ee54 SR |
346 | #ifndef CONFIG_SYS_DCACHE_OFF |
347 | void enable_caches(void) | |
348 | { | |
5730360e SR |
349 | struct pl310_regs *const pl310 = |
350 | (struct pl310_regs *)CONFIG_SYS_PL310_BASE; | |
351 | ||
352 | /* First disable L2 cache - may still be enable from BootROM */ | |
353 | if (mvebu_soc_family() == MVEBU_SOC_A38X) | |
354 | clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); | |
355 | ||
60b75324 SR |
356 | /* Avoid problem with e.g. neta ethernet driver */ |
357 | invalidate_dcache_all(); | |
358 | ||
41e5ee54 SR |
359 | /* Enable D-cache. I-cache is already enabled in start.S */ |
360 | dcache_enable(); | |
361 | } | |
362 | #endif |