]>
Commit | Line | Data |
---|---|---|
b940ca64 GR |
1 | /* |
2 | * Copyright (C) 2014 Freescale Semiconductor | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
21c69870 | 6 | #include <common.h> |
b940ca64 GR |
7 | #include <errno.h> |
8 | #include <asm/io.h> | |
21c69870 SY |
9 | #include <libfdt.h> |
10 | #include <fdt_support.h> | |
7b3bd9a7 GR |
11 | #include <fsl-mc/fsl_mc.h> |
12 | #include <fsl-mc/fsl_mc_sys.h> | |
a2a55e51 | 13 | #include <fsl-mc/fsl_mc_private.h> |
7b3bd9a7 | 14 | #include <fsl-mc/fsl_dpmng.h> |
a2a55e51 PK |
15 | #include <fsl-mc/fsl_dprc.h> |
16 | #include <fsl-mc/fsl_dpio.h> | |
17 | #include <fsl-mc/fsl_qbman_portal.h> | |
b940ca64 | 18 | |
125e2bc1 GR |
19 | #define MC_RAM_BASE_ADDR_ALIGNMENT (512UL * 1024 * 1024) |
20 | #define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1)) | |
21 | #define MC_RAM_SIZE_ALIGNMENT (256UL * 1024 * 1024) | |
22 | ||
23 | #define MC_MEM_SIZE_ENV_VAR "mcmemsize" | |
24 | #define MC_BOOT_TIMEOUT_ENV_VAR "mcboottimeout" | |
25 | ||
b940ca64 GR |
26 | DECLARE_GLOBAL_DATA_PTR; |
27 | static int mc_boot_status; | |
a2a55e51 PK |
28 | struct fsl_mc_io *dflt_mc_io = NULL; |
29 | uint16_t dflt_dprc_handle = 0; | |
30 | struct fsl_dpbp_obj *dflt_dpbp = NULL; | |
31 | struct fsl_dpio_obj *dflt_dpio = NULL; | |
125e2bc1 GR |
32 | uint16_t dflt_dpio_handle = 0; |
33 | ||
34 | #ifdef DEBUG | |
35 | void dump_ram_words(const char *title, void *addr) | |
36 | { | |
37 | int i; | |
38 | uint32_t *words = addr; | |
39 | ||
40 | printf("Dumping beginning of %s (%p):\n", title, addr); | |
41 | for (i = 0; i < 16; i++) | |
42 | printf("%#x ", words[i]); | |
43 | ||
44 | printf("\n"); | |
45 | } | |
b940ca64 | 46 | |
125e2bc1 GR |
47 | void dump_mc_ccsr_regs(struct mc_ccsr_registers __iomem *mc_ccsr_regs) |
48 | { | |
49 | printf("MC CCSR registers:\n" | |
50 | "reg_gcr1 %#x\n" | |
51 | "reg_gsr %#x\n" | |
52 | "reg_sicbalr %#x\n" | |
53 | "reg_sicbahr %#x\n" | |
54 | "reg_sicapr %#x\n" | |
55 | "reg_mcfbalr %#x\n" | |
56 | "reg_mcfbahr %#x\n" | |
57 | "reg_mcfapr %#x\n" | |
58 | "reg_psr %#x\n", | |
59 | mc_ccsr_regs->reg_gcr1, | |
60 | mc_ccsr_regs->reg_gsr, | |
61 | mc_ccsr_regs->reg_sicbalr, | |
62 | mc_ccsr_regs->reg_sicbahr, | |
63 | mc_ccsr_regs->reg_sicapr, | |
64 | mc_ccsr_regs->reg_mcfbalr, | |
65 | mc_ccsr_regs->reg_mcfbahr, | |
66 | mc_ccsr_regs->reg_mcfapr, | |
67 | mc_ccsr_regs->reg_psr); | |
68 | } | |
69 | #else | |
70 | ||
71 | #define dump_ram_words(title, addr) | |
72 | #define dump_mc_ccsr_regs(mc_ccsr_regs) | |
73 | ||
74 | #endif /* DEBUG */ | |
75 | ||
76 | #ifndef CONFIG_SYS_LS_MC_FW_IN_DDR | |
b940ca64 GR |
77 | /** |
78 | * Copying MC firmware or DPL image to DDR | |
79 | */ | |
80 | static int mc_copy_image(const char *title, | |
7b3bd9a7 | 81 | u64 image_addr, u32 image_size, u64 mc_ram_addr) |
b940ca64 GR |
82 | { |
83 | debug("%s copied to address %p\n", title, (void *)mc_ram_addr); | |
84 | memcpy((void *)mc_ram_addr, (void *)image_addr, image_size); | |
125e2bc1 | 85 | flush_dcache_range(mc_ram_addr, mc_ram_addr + image_size); |
b940ca64 GR |
86 | return 0; |
87 | } | |
88 | ||
89 | /** | |
90 | * MC firmware FIT image parser checks if the image is in FIT | |
91 | * format, verifies integrity of the image and calculates | |
92 | * raw image address and size values. | |
7b3bd9a7 | 93 | * Returns 0 on success and a negative errno on error. |
b940ca64 GR |
94 | * task fail. |
95 | **/ | |
b940ca64 GR |
96 | int parse_mc_firmware_fit_image(const void **raw_image_addr, |
97 | size_t *raw_image_size) | |
98 | { | |
99 | int format; | |
100 | void *fit_hdr; | |
101 | int node_offset; | |
102 | const void *data; | |
103 | size_t size; | |
104 | const char *uname = "firmware"; | |
105 | ||
7b3bd9a7 | 106 | /* Check if the image is in NOR flash */ |
b940ca64 GR |
107 | #ifdef CONFIG_SYS_LS_MC_FW_IN_NOR |
108 | fit_hdr = (void *)CONFIG_SYS_LS_MC_FW_ADDR; | |
109 | #else | |
110 | #error "No CONFIG_SYS_LS_MC_FW_IN_xxx defined" | |
111 | #endif | |
112 | ||
113 | /* Check if Image is in FIT format */ | |
114 | format = genimg_get_format(fit_hdr); | |
115 | ||
116 | if (format != IMAGE_FORMAT_FIT) { | |
7b3bd9a7 GR |
117 | printf("fsl-mc: ERROR: Bad firmware image (not a FIT image)\n"); |
118 | return -EINVAL; | |
b940ca64 GR |
119 | } |
120 | ||
121 | if (!fit_check_format(fit_hdr)) { | |
7b3bd9a7 GR |
122 | printf("fsl-mc: ERROR: Bad firmware image (bad FIT header)\n"); |
123 | return -EINVAL; | |
b940ca64 GR |
124 | } |
125 | ||
126 | node_offset = fit_image_get_node(fit_hdr, uname); | |
127 | ||
128 | if (node_offset < 0) { | |
7b3bd9a7 GR |
129 | printf("fsl-mc: ERROR: Bad firmware image (missing subimage)\n"); |
130 | return -ENOENT; | |
b940ca64 GR |
131 | } |
132 | ||
133 | /* Verify MC firmware image */ | |
134 | if (!(fit_image_verify(fit_hdr, node_offset))) { | |
7b3bd9a7 GR |
135 | printf("fsl-mc: ERROR: Bad firmware image (bad CRC)\n"); |
136 | return -EINVAL; | |
b940ca64 GR |
137 | } |
138 | ||
139 | /* Get address and size of raw image */ | |
140 | fit_image_get_data(fit_hdr, node_offset, &data, &size); | |
141 | ||
142 | *raw_image_addr = data; | |
143 | *raw_image_size = size; | |
144 | ||
145 | return 0; | |
146 | } | |
125e2bc1 GR |
147 | #endif |
148 | ||
149 | /* | |
150 | * Calculates the values to be used to specify the address range | |
151 | * for the MC private DRAM block, in the MCFBALR/MCFBAHR registers. | |
152 | * It returns the highest 512MB-aligned address within the given | |
153 | * address range, in '*aligned_base_addr', and the number of 256 MiB | |
154 | * blocks in it, in 'num_256mb_blocks'. | |
155 | */ | |
156 | static int calculate_mc_private_ram_params(u64 mc_private_ram_start_addr, | |
157 | size_t mc_ram_size, | |
158 | u64 *aligned_base_addr, | |
159 | u8 *num_256mb_blocks) | |
160 | { | |
161 | u64 addr; | |
162 | u16 num_blocks; | |
163 | ||
164 | if (mc_ram_size % MC_RAM_SIZE_ALIGNMENT != 0) { | |
165 | printf("fsl-mc: ERROR: invalid MC private RAM size (%lu)\n", | |
166 | mc_ram_size); | |
167 | return -EINVAL; | |
168 | } | |
169 | ||
170 | num_blocks = mc_ram_size / MC_RAM_SIZE_ALIGNMENT; | |
171 | if (num_blocks < 1 || num_blocks > 0xff) { | |
172 | printf("fsl-mc: ERROR: invalid MC private RAM size (%lu)\n", | |
173 | mc_ram_size); | |
174 | return -EINVAL; | |
175 | } | |
176 | ||
177 | addr = (mc_private_ram_start_addr + mc_ram_size - 1) & | |
178 | MC_RAM_BASE_ADDR_ALIGNMENT_MASK; | |
179 | ||
180 | if (addr < mc_private_ram_start_addr) { | |
181 | printf("fsl-mc: ERROR: bad start address %#llx\n", | |
182 | mc_private_ram_start_addr); | |
183 | return -EFAULT; | |
184 | } | |
185 | ||
186 | *aligned_base_addr = addr; | |
187 | *num_256mb_blocks = num_blocks; | |
188 | return 0; | |
189 | } | |
190 | ||
21c69870 SY |
191 | static int mc_fixup_dpc(u64 dpc_addr) |
192 | { | |
193 | void *blob = (void *)dpc_addr; | |
194 | int nodeoffset; | |
195 | ||
196 | /* delete any existing ICID pools */ | |
197 | nodeoffset = fdt_path_offset(blob, "/resources/icid_pools"); | |
198 | if (fdt_del_node(blob, nodeoffset) < 0) | |
199 | printf("\nfsl-mc: WARNING: could not delete ICID pool\n"); | |
200 | ||
201 | /* add a new pool */ | |
202 | nodeoffset = fdt_path_offset(blob, "/resources"); | |
203 | if (nodeoffset < 0) { | |
204 | printf("\nfsl-mc: ERROR: DPC is missing /resources\n"); | |
205 | return -EINVAL; | |
206 | } | |
207 | nodeoffset = fdt_add_subnode(blob, nodeoffset, "icid_pools"); | |
208 | nodeoffset = fdt_add_subnode(blob, nodeoffset, "icid_pool@0"); | |
209 | do_fixup_by_path_u32(blob, "/resources/icid_pools/icid_pool@0", | |
210 | "base_icid", FSL_DPAA2_STREAM_ID_START, 1); | |
211 | do_fixup_by_path_u32(blob, "/resources/icid_pools/icid_pool@0", | |
212 | "num", | |
213 | FSL_DPAA2_STREAM_ID_END - | |
214 | FSL_DPAA2_STREAM_ID_START + 1, 1); | |
215 | ||
216 | flush_dcache_range(dpc_addr, dpc_addr + fdt_totalsize(blob)); | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
125e2bc1 GR |
221 | static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size) |
222 | { | |
223 | u64 mc_dpc_offset; | |
224 | #ifndef CONFIG_SYS_LS_MC_DPC_IN_DDR | |
225 | int error; | |
226 | void *dpc_fdt_hdr; | |
227 | int dpc_size; | |
228 | #endif | |
229 | ||
230 | #ifdef CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET | |
231 | BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET & 0x3) != 0 || | |
232 | CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET > 0xffffffff); | |
233 | ||
234 | mc_dpc_offset = CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET; | |
235 | #else | |
236 | #error "CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET not defined" | |
237 | #endif | |
238 | ||
239 | /* | |
240 | * Load the MC DPC blob in the MC private DRAM block: | |
241 | */ | |
242 | #ifdef CONFIG_SYS_LS_MC_DPC_IN_DDR | |
243 | printf("MC DPC is preloaded to %#llx\n", mc_ram_addr + mc_dpc_offset); | |
244 | #else | |
245 | /* | |
246 | * Get address and size of the DPC blob stored in flash: | |
247 | */ | |
248 | #ifdef CONFIG_SYS_LS_MC_DPC_IN_NOR | |
249 | dpc_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPC_ADDR; | |
250 | #else | |
251 | #error "No CONFIG_SYS_LS_MC_DPC_IN_xxx defined" | |
252 | #endif | |
253 | ||
254 | error = fdt_check_header(dpc_fdt_hdr); | |
255 | if (error != 0) { | |
256 | /* | |
257 | * Don't return with error here, since the MC firmware can | |
258 | * still boot without a DPC | |
259 | */ | |
cc088c3a | 260 | printf("\nfsl-mc: WARNING: No DPC image found"); |
125e2bc1 GR |
261 | return 0; |
262 | } | |
263 | ||
264 | dpc_size = fdt_totalsize(dpc_fdt_hdr); | |
265 | if (dpc_size > CONFIG_SYS_LS_MC_DPC_MAX_LENGTH) { | |
cc088c3a | 266 | printf("\nfsl-mc: ERROR: Bad DPC image (too large: %d)\n", |
125e2bc1 GR |
267 | dpc_size); |
268 | return -EINVAL; | |
269 | } | |
270 | ||
271 | mc_copy_image("MC DPC blob", | |
272 | (u64)dpc_fdt_hdr, dpc_size, mc_ram_addr + mc_dpc_offset); | |
273 | #endif /* not defined CONFIG_SYS_LS_MC_DPC_IN_DDR */ | |
274 | ||
21c69870 SY |
275 | if (mc_fixup_dpc(mc_ram_addr + mc_dpc_offset)) |
276 | return -EINVAL; | |
277 | ||
125e2bc1 GR |
278 | dump_ram_words("DPC", (void *)(mc_ram_addr + mc_dpc_offset)); |
279 | return 0; | |
280 | } | |
281 | ||
282 | static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size) | |
283 | { | |
284 | u64 mc_dpl_offset; | |
285 | #ifndef CONFIG_SYS_LS_MC_DPL_IN_DDR | |
286 | int error; | |
287 | void *dpl_fdt_hdr; | |
288 | int dpl_size; | |
289 | #endif | |
290 | ||
291 | #ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET | |
292 | BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 || | |
293 | CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff); | |
294 | ||
295 | mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET; | |
296 | #else | |
297 | #error "CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET not defined" | |
298 | #endif | |
299 | ||
300 | /* | |
301 | * Load the MC DPL blob in the MC private DRAM block: | |
302 | */ | |
303 | #ifdef CONFIG_SYS_LS_MC_DPL_IN_DDR | |
304 | printf("MC DPL is preloaded to %#llx\n", mc_ram_addr + mc_dpl_offset); | |
305 | #else | |
306 | /* | |
307 | * Get address and size of the DPL blob stored in flash: | |
308 | */ | |
309 | #ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR | |
310 | dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR; | |
311 | #else | |
312 | #error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined" | |
313 | #endif | |
314 | ||
315 | error = fdt_check_header(dpl_fdt_hdr); | |
316 | if (error != 0) { | |
cc088c3a | 317 | printf("\nfsl-mc: ERROR: Bad DPL image (bad header)\n"); |
125e2bc1 GR |
318 | return error; |
319 | } | |
320 | ||
321 | dpl_size = fdt_totalsize(dpl_fdt_hdr); | |
322 | if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) { | |
cc088c3a | 323 | printf("\nfsl-mc: ERROR: Bad DPL image (too large: %d)\n", |
125e2bc1 GR |
324 | dpl_size); |
325 | return -EINVAL; | |
326 | } | |
327 | ||
328 | mc_copy_image("MC DPL blob", | |
329 | (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset); | |
330 | #endif /* not defined CONFIG_SYS_LS_MC_DPL_IN_DDR */ | |
331 | ||
332 | dump_ram_words("DPL", (void *)(mc_ram_addr + mc_dpl_offset)); | |
333 | return 0; | |
334 | } | |
335 | ||
336 | /** | |
337 | * Return the MC boot timeout value in milliseconds | |
338 | */ | |
339 | static unsigned long get_mc_boot_timeout_ms(void) | |
340 | { | |
341 | unsigned long timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS; | |
342 | ||
343 | char *timeout_ms_env_var = getenv(MC_BOOT_TIMEOUT_ENV_VAR); | |
344 | ||
345 | if (timeout_ms_env_var) { | |
346 | timeout_ms = simple_strtoul(timeout_ms_env_var, NULL, 10); | |
347 | if (timeout_ms == 0) { | |
348 | printf("fsl-mc: WARNING: Invalid value for \'" | |
349 | MC_BOOT_TIMEOUT_ENV_VAR | |
350 | "\' environment variable: %lu\n", | |
351 | timeout_ms); | |
352 | ||
353 | timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS; | |
354 | } | |
355 | } | |
356 | ||
357 | return timeout_ms; | |
358 | } | |
359 | ||
c1000c12 GR |
360 | #ifdef CONFIG_SYS_LS_MC_AIOP_IMG_IN_NOR |
361 | static int load_mc_aiop_img(u64 mc_ram_addr, size_t mc_ram_size) | |
362 | { | |
363 | void *aiop_img; | |
364 | ||
365 | /* | |
366 | * Load the MC AIOP image in the MC private DRAM block: | |
367 | */ | |
368 | ||
369 | aiop_img = (void *)CONFIG_SYS_LS_MC_AIOP_IMG_ADDR; | |
370 | mc_copy_image("MC AIOP image", | |
371 | (u64)aiop_img, CONFIG_SYS_LS_MC_AIOP_IMG_MAX_LENGTH, | |
372 | mc_ram_addr + CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET); | |
373 | ||
374 | return 0; | |
375 | } | |
376 | #endif | |
125e2bc1 GR |
377 | static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr) |
378 | { | |
379 | u32 reg_gsr; | |
380 | u32 mc_fw_boot_status; | |
381 | unsigned long timeout_ms = get_mc_boot_timeout_ms(); | |
382 | struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; | |
383 | ||
384 | dmb(); | |
125e2bc1 GR |
385 | assert(timeout_ms > 0); |
386 | for (;;) { | |
387 | udelay(1000); /* throttle polling */ | |
388 | reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr); | |
389 | mc_fw_boot_status = (reg_gsr & GSR_FS_MASK); | |
390 | if (mc_fw_boot_status & 0x1) | |
391 | break; | |
392 | ||
393 | timeout_ms--; | |
394 | if (timeout_ms == 0) | |
395 | break; | |
396 | } | |
397 | ||
398 | if (timeout_ms == 0) { | |
cc088c3a | 399 | printf("ERROR: timeout\n"); |
125e2bc1 GR |
400 | |
401 | /* TODO: Get an error status from an MC CCSR register */ | |
402 | return -ETIMEDOUT; | |
403 | } | |
404 | ||
405 | if (mc_fw_boot_status != 0x1) { | |
406 | /* | |
407 | * TODO: Identify critical errors from the GSR register's FS | |
408 | * field and for those errors, set error to -ENODEV or other | |
409 | * appropriate errno, so that the status property is set to | |
410 | * failure in the fsl,dprc device tree node. | |
411 | */ | |
cc088c3a GR |
412 | printf("WARNING: Firmware returned an error (GSR: %#x)\n", |
413 | reg_gsr); | |
414 | } else { | |
415 | printf("SUCCESS\n"); | |
125e2bc1 GR |
416 | } |
417 | ||
cc088c3a | 418 | |
125e2bc1 GR |
419 | *final_reg_gsr = reg_gsr; |
420 | return 0; | |
421 | } | |
b940ca64 | 422 | |
a2a55e51 | 423 | int mc_init(void) |
b940ca64 GR |
424 | { |
425 | int error = 0; | |
a2a55e51 | 426 | int portal_id = 0; |
b940ca64 GR |
427 | struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; |
428 | u64 mc_ram_addr; | |
b940ca64 | 429 | u32 reg_gsr; |
125e2bc1 GR |
430 | u32 reg_mcfbalr; |
431 | #ifndef CONFIG_SYS_LS_MC_FW_IN_DDR | |
b940ca64 GR |
432 | const void *raw_image_addr; |
433 | size_t raw_image_size = 0; | |
125e2bc1 | 434 | #endif |
7b3bd9a7 | 435 | struct mc_version mc_ver_info; |
125e2bc1 GR |
436 | u64 mc_ram_aligned_base_addr; |
437 | u8 mc_ram_num_256mb_blocks; | |
438 | size_t mc_ram_size = mc_get_dram_block_size(); | |
b940ca64 GR |
439 | |
440 | /* | |
441 | * The MC private DRAM block was already carved at the end of DRAM | |
442 | * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE: | |
443 | */ | |
444 | if (gd->bd->bi_dram[1].start) { | |
445 | mc_ram_addr = | |
446 | gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size; | |
447 | } else { | |
448 | mc_ram_addr = | |
449 | gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; | |
450 | } | |
451 | ||
125e2bc1 GR |
452 | error = calculate_mc_private_ram_params(mc_ram_addr, |
453 | mc_ram_size, | |
454 | &mc_ram_aligned_base_addr, | |
455 | &mc_ram_num_256mb_blocks); | |
456 | if (error != 0) | |
457 | goto out; | |
458 | ||
b940ca64 GR |
459 | /* |
460 | * Management Complex cores should be held at reset out of POR. | |
461 | * U-boot should be the first software to touch MC. To be safe, | |
462 | * we reset all cores again by setting GCR1 to 0. It doesn't do | |
463 | * anything if they are held at reset. After we setup the firmware | |
464 | * we kick off MC by deasserting the reset bit for core 0, and | |
465 | * deasserting the reset bits for Command Portal Managers. | |
466 | * The stop bits are not touched here. They are used to stop the | |
467 | * cores when they are active. Setting stop bits doesn't stop the | |
468 | * cores from fetching instructions when they are released from | |
469 | * reset. | |
470 | */ | |
471 | out_le32(&mc_ccsr_regs->reg_gcr1, 0); | |
472 | dmb(); | |
473 | ||
125e2bc1 GR |
474 | #ifdef CONFIG_SYS_LS_MC_FW_IN_DDR |
475 | printf("MC firmware is preloaded to %#llx\n", mc_ram_addr); | |
476 | #else | |
b940ca64 GR |
477 | error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size); |
478 | if (error != 0) | |
479 | goto out; | |
480 | /* | |
481 | * Load the MC FW at the beginning of the MC private DRAM block: | |
482 | */ | |
7b3bd9a7 GR |
483 | mc_copy_image("MC Firmware", |
484 | (u64)raw_image_addr, raw_image_size, mc_ram_addr); | |
7b3bd9a7 | 485 | #endif |
125e2bc1 | 486 | dump_ram_words("firmware", (void *)mc_ram_addr); |
7b3bd9a7 | 487 | |
125e2bc1 GR |
488 | error = load_mc_dpc(mc_ram_addr, mc_ram_size); |
489 | if (error != 0) | |
7b3bd9a7 | 490 | goto out; |
b940ca64 | 491 | |
125e2bc1 GR |
492 | error = load_mc_dpl(mc_ram_addr, mc_ram_size); |
493 | if (error != 0) | |
b940ca64 | 494 | goto out; |
b940ca64 | 495 | |
c1000c12 GR |
496 | #ifdef CONFIG_SYS_LS_MC_AIOP_IMG_IN_NOR |
497 | error = load_mc_aiop_img(mc_ram_addr, mc_ram_size); | |
498 | if (error != 0) | |
499 | goto out; | |
500 | #endif | |
501 | ||
b940ca64 | 502 | debug("mc_ccsr_regs %p\n", mc_ccsr_regs); |
125e2bc1 | 503 | dump_mc_ccsr_regs(mc_ccsr_regs); |
b940ca64 GR |
504 | |
505 | /* | |
125e2bc1 | 506 | * Tell MC what is the address range of the DRAM block assigned to it: |
b940ca64 | 507 | */ |
125e2bc1 GR |
508 | reg_mcfbalr = (u32)mc_ram_aligned_base_addr | |
509 | (mc_ram_num_256mb_blocks - 1); | |
510 | out_le32(&mc_ccsr_regs->reg_mcfbalr, reg_mcfbalr); | |
511 | out_le32(&mc_ccsr_regs->reg_mcfbahr, | |
512 | (u32)(mc_ram_aligned_base_addr >> 32)); | |
39da644e | 513 | out_le32(&mc_ccsr_regs->reg_mcfapr, FSL_BYPASS_AMQ); |
b940ca64 GR |
514 | |
515 | /* | |
125e2bc1 | 516 | * Tell the MC that we want delayed DPL deployment. |
b940ca64 | 517 | */ |
125e2bc1 | 518 | out_le32(&mc_ccsr_regs->reg_gsr, 0xDD00); |
b940ca64 | 519 | |
cc088c3a | 520 | printf("\nfsl-mc: Booting Management Complex ... "); |
7b3bd9a7 | 521 | |
b940ca64 GR |
522 | /* |
523 | * Deassert reset and release MC core 0 to run | |
524 | */ | |
525 | out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST); | |
125e2bc1 GR |
526 | error = wait_for_mc(true, ®_gsr); |
527 | if (error != 0) | |
b940ca64 | 528 | goto out; |
b940ca64 | 529 | |
7b3bd9a7 GR |
530 | /* |
531 | * TODO: need to obtain the portal_id for the root container from the | |
532 | * DPL | |
533 | */ | |
534 | portal_id = 0; | |
535 | ||
536 | /* | |
a2a55e51 PK |
537 | * Initialize the global default MC portal |
538 | * And check that the MC firmware is responding portal commands: | |
7b3bd9a7 | 539 | */ |
a2a55e51 PK |
540 | dflt_mc_io = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io)); |
541 | if (!dflt_mc_io) { | |
542 | printf(" No memory: malloc() failed\n"); | |
543 | return -ENOMEM; | |
544 | } | |
545 | ||
546 | dflt_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(portal_id); | |
7b3bd9a7 | 547 | debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n", |
a2a55e51 | 548 | portal_id, dflt_mc_io->mmio_regs); |
7b3bd9a7 | 549 | |
a2a55e51 | 550 | error = mc_get_version(dflt_mc_io, &mc_ver_info); |
7b3bd9a7 GR |
551 | if (error != 0) { |
552 | printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n", | |
553 | error); | |
554 | goto out; | |
555 | } | |
556 | ||
2b7c4a19 | 557 | if (MC_VER_MAJOR != mc_ver_info.major) { |
7b3bd9a7 GR |
558 | printf("fsl-mc: ERROR: Firmware major version mismatch (found: %d, expected: %d)\n", |
559 | mc_ver_info.major, MC_VER_MAJOR); | |
2b7c4a19 PK |
560 | printf("fsl-mc: Update the Management Complex firmware\n"); |
561 | ||
562 | error = -ENODEV; | |
563 | goto out; | |
564 | } | |
7b3bd9a7 GR |
565 | |
566 | if (MC_VER_MINOR != mc_ver_info.minor) | |
567 | printf("fsl-mc: WARNING: Firmware minor version mismatch (found: %d, expected: %d)\n", | |
568 | mc_ver_info.minor, MC_VER_MINOR); | |
569 | ||
570 | printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n", | |
571 | mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision, | |
125e2bc1 GR |
572 | reg_gsr & GSR_FS_MASK); |
573 | ||
574 | /* | |
575 | * Tell the MC to deploy the DPL: | |
576 | */ | |
577 | out_le32(&mc_ccsr_regs->reg_gsr, 0x0); | |
cc088c3a | 578 | printf("fsl-mc: Deploying data path layout ... "); |
125e2bc1 GR |
579 | error = wait_for_mc(false, ®_gsr); |
580 | if (error != 0) | |
581 | goto out; | |
cc088c3a | 582 | |
b940ca64 GR |
583 | out: |
584 | if (error != 0) | |
2b7c4a19 | 585 | mc_boot_status = error; |
b940ca64 GR |
586 | else |
587 | mc_boot_status = 0; | |
588 | ||
589 | return error; | |
590 | } | |
591 | ||
592 | int get_mc_boot_status(void) | |
593 | { | |
594 | return mc_boot_status; | |
595 | } | |
596 | ||
597 | /** | |
598 | * Return the actual size of the MC private DRAM block. | |
b940ca64 GR |
599 | */ |
600 | unsigned long mc_get_dram_block_size(void) | |
601 | { | |
125e2bc1 GR |
602 | unsigned long dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; |
603 | ||
604 | char *dram_block_size_env_var = getenv(MC_MEM_SIZE_ENV_VAR); | |
605 | ||
606 | if (dram_block_size_env_var) { | |
607 | dram_block_size = simple_strtoul(dram_block_size_env_var, NULL, | |
608 | 10); | |
609 | ||
610 | if (dram_block_size < CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE) { | |
611 | printf("fsl-mc: WARNING: Invalid value for \'" | |
612 | MC_MEM_SIZE_ENV_VAR | |
613 | "\' environment variable: %lu\n", | |
614 | dram_block_size); | |
615 | ||
616 | dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; | |
617 | } | |
618 | } | |
619 | ||
620 | return dram_block_size; | |
b940ca64 | 621 | } |
a2a55e51 PK |
622 | |
623 | int dpio_init(struct dprc_obj_desc obj_desc) | |
624 | { | |
625 | struct qbman_swp_desc p_des; | |
626 | struct dpio_attr attr; | |
627 | int err = 0; | |
628 | ||
629 | dflt_dpio = (struct fsl_dpio_obj *)malloc(sizeof(struct fsl_dpio_obj)); | |
630 | if (!dflt_dpio) { | |
631 | printf(" No memory: malloc() failed\n"); | |
632 | return -ENOMEM; | |
633 | } | |
634 | ||
635 | dflt_dpio->dpio_id = obj_desc.id; | |
636 | ||
637 | err = dpio_open(dflt_mc_io, obj_desc.id, &dflt_dpio_handle); | |
638 | if (err) { | |
639 | printf("dpio_open() failed\n"); | |
640 | goto err_open; | |
641 | } | |
642 | ||
643 | err = dpio_get_attributes(dflt_mc_io, dflt_dpio_handle, &attr); | |
644 | if (err) { | |
645 | printf("dpio_get_attributes() failed %d\n", err); | |
646 | goto err_get_attr; | |
647 | } | |
648 | ||
649 | err = dpio_enable(dflt_mc_io, dflt_dpio_handle); | |
650 | if (err) { | |
651 | printf("dpio_enable() failed %d\n", err); | |
652 | goto err_get_enable; | |
653 | } | |
1f1c25c7 PK |
654 | debug("ce_offset=0x%llx, ci_offset=0x%llx, portalid=%d, prios=%d\n", |
655 | attr.qbman_portal_ce_offset, | |
656 | attr.qbman_portal_ci_offset, | |
a2a55e51 PK |
657 | attr.qbman_portal_id, |
658 | attr.num_priorities); | |
659 | ||
1f1c25c7 PK |
660 | p_des.cena_bar = (void *)(SOC_QBMAN_PORTALS_BASE_ADDR |
661 | + attr.qbman_portal_ce_offset); | |
662 | p_des.cinh_bar = (void *)(SOC_QBMAN_PORTALS_BASE_ADDR | |
663 | + attr.qbman_portal_ci_offset); | |
a2a55e51 PK |
664 | |
665 | dflt_dpio->sw_portal = qbman_swp_init(&p_des); | |
666 | if (dflt_dpio->sw_portal == NULL) { | |
667 | printf("qbman_swp_init() failed\n"); | |
668 | goto err_get_swp_init; | |
669 | } | |
670 | return 0; | |
671 | ||
672 | err_get_swp_init: | |
673 | err_get_enable: | |
674 | dpio_disable(dflt_mc_io, dflt_dpio_handle); | |
675 | err_get_attr: | |
676 | dpio_close(dflt_mc_io, dflt_dpio_handle); | |
677 | err_open: | |
678 | free(dflt_dpio); | |
679 | return err; | |
680 | } | |
681 | ||
682 | int dpbp_init(struct dprc_obj_desc obj_desc) | |
683 | { | |
684 | dflt_dpbp = (struct fsl_dpbp_obj *)malloc(sizeof(struct fsl_dpbp_obj)); | |
685 | if (!dflt_dpbp) { | |
686 | printf(" No memory: malloc() failed\n"); | |
687 | return -ENOMEM; | |
688 | } | |
689 | dflt_dpbp->dpbp_attr.id = obj_desc.id; | |
690 | ||
691 | return 0; | |
692 | } | |
693 | ||
c517771a | 694 | int dprc_init_container_obj(struct dprc_obj_desc obj_desc, uint16_t dprc_handle) |
a2a55e51 | 695 | { |
c517771a PK |
696 | int error = 0, state = 0; |
697 | struct dprc_endpoint dpni_endpoint, dpmac_endpoint; | |
a2a55e51 PK |
698 | if (!strcmp(obj_desc.type, "dpbp")) { |
699 | if (!dflt_dpbp) { | |
700 | error = dpbp_init(obj_desc); | |
701 | if (error < 0) | |
702 | printf("dpbp_init failed\n"); | |
703 | } | |
704 | } else if (!strcmp(obj_desc.type, "dpio")) { | |
705 | if (!dflt_dpio) { | |
706 | error = dpio_init(obj_desc); | |
707 | if (error < 0) | |
708 | printf("dpio_init failed\n"); | |
709 | } | |
c517771a PK |
710 | } else if (!strcmp(obj_desc.type, "dpni")) { |
711 | strcpy(dpni_endpoint.type, obj_desc.type); | |
712 | dpni_endpoint.id = obj_desc.id; | |
713 | error = dprc_get_connection(dflt_mc_io, dprc_handle, | |
714 | &dpni_endpoint, &dpmac_endpoint, &state); | |
715 | if (!strcmp(dpmac_endpoint.type, "dpmac")) | |
716 | error = ldpaa_eth_init(obj_desc); | |
717 | if (error < 0) | |
718 | printf("ldpaa_eth_init failed\n"); | |
a2a55e51 PK |
719 | } |
720 | ||
721 | return error; | |
722 | } | |
723 | ||
724 | int dprc_scan_container_obj(uint16_t dprc_handle, char *obj_type, int i) | |
725 | { | |
726 | int error = 0; | |
727 | struct dprc_obj_desc obj_desc; | |
728 | ||
729 | memset((void *)&obj_desc, 0x00, sizeof(struct dprc_obj_desc)); | |
730 | ||
731 | error = dprc_get_obj(dflt_mc_io, dprc_handle, | |
732 | i, &obj_desc); | |
733 | if (error < 0) { | |
734 | printf("dprc_get_obj(i=%d) failed: %d\n", | |
735 | i, error); | |
736 | return error; | |
737 | } | |
738 | ||
739 | if (!strcmp(obj_desc.type, obj_type)) { | |
740 | debug("Discovered object: type %s, id %d, req %s\n", | |
741 | obj_desc.type, obj_desc.id, obj_type); | |
742 | ||
c517771a | 743 | error = dprc_init_container_obj(obj_desc, dprc_handle); |
a2a55e51 PK |
744 | if (error < 0) { |
745 | printf("dprc_init_container_obj(i=%d) failed: %d\n", | |
746 | i, error); | |
747 | return error; | |
748 | } | |
749 | } | |
750 | ||
751 | return error; | |
752 | } | |
753 | ||
754 | int fsl_mc_ldpaa_init(bd_t *bis) | |
755 | { | |
756 | int i, error = 0; | |
757 | int dprc_opened = 0, container_id; | |
758 | int num_child_objects = 0; | |
759 | ||
760 | error = mc_init(); | |
125e2bc1 GR |
761 | if (error < 0) |
762 | goto error; | |
a2a55e51 PK |
763 | |
764 | error = dprc_get_container_id(dflt_mc_io, &container_id); | |
765 | if (error < 0) { | |
766 | printf("dprc_get_container_id() failed: %d\n", error); | |
767 | goto error; | |
768 | } | |
769 | ||
770 | debug("fsl-mc: Container id=0x%x\n", container_id); | |
771 | ||
772 | error = dprc_open(dflt_mc_io, container_id, &dflt_dprc_handle); | |
773 | if (error < 0) { | |
774 | printf("dprc_open() failed: %d\n", error); | |
775 | goto error; | |
776 | } | |
777 | dprc_opened = true; | |
778 | ||
779 | error = dprc_get_obj_count(dflt_mc_io, | |
780 | dflt_dprc_handle, | |
781 | &num_child_objects); | |
782 | if (error < 0) { | |
783 | printf("dprc_get_obj_count() failed: %d\n", error); | |
784 | goto error; | |
785 | } | |
786 | debug("Total child in container %d = %d\n", container_id, | |
787 | num_child_objects); | |
788 | ||
789 | if (num_child_objects != 0) { | |
790 | /* | |
791 | * Discover objects currently in the DPRC container in the MC: | |
792 | */ | |
793 | for (i = 0; i < num_child_objects; i++) | |
794 | error = dprc_scan_container_obj(dflt_dprc_handle, | |
795 | "dpbp", i); | |
796 | ||
797 | for (i = 0; i < num_child_objects; i++) | |
798 | error = dprc_scan_container_obj(dflt_dprc_handle, | |
799 | "dpio", i); | |
800 | ||
801 | for (i = 0; i < num_child_objects; i++) | |
802 | error = dprc_scan_container_obj(dflt_dprc_handle, | |
803 | "dpni", i); | |
804 | } | |
805 | error: | |
806 | if (dprc_opened) | |
807 | dprc_close(dflt_mc_io, dflt_dprc_handle); | |
808 | ||
809 | return error; | |
810 | } | |
811 | ||
812 | void fsl_mc_ldpaa_exit(bd_t *bis) | |
813 | { | |
814 | int err; | |
815 | ||
125e2bc1 GR |
816 | if (get_mc_boot_status() == 0) { |
817 | err = dpio_disable(dflt_mc_io, dflt_dpio_handle); | |
818 | if (err < 0) { | |
819 | printf("dpio_disable() failed: %d\n", err); | |
820 | return; | |
821 | } | |
822 | err = dpio_reset(dflt_mc_io, dflt_dpio_handle); | |
823 | if (err < 0) { | |
824 | printf("dpio_reset() failed: %d\n", err); | |
825 | return; | |
826 | } | |
827 | err = dpio_close(dflt_mc_io, dflt_dpio_handle); | |
828 | if (err < 0) { | |
829 | printf("dpio_close() failed: %d\n", err); | |
830 | return; | |
831 | } | |
a2a55e51 | 832 | |
125e2bc1 GR |
833 | free(dflt_dpio); |
834 | free(dflt_dpbp); | |
a2a55e51 PK |
835 | } |
836 | ||
125e2bc1 GR |
837 | if (dflt_mc_io) |
838 | free(dflt_mc_io); | |
a2a55e51 | 839 | } |