xref: /openbmc/u-boot/drivers/net/fsl-mc/mc.c (revision 66869f955417b89dbf6b7cbb72738b2205a26bf8)
1 /*
2  * Copyright (C) 2014 Freescale Semiconductor
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <errno.h>
8 #include <asm/io.h>
9 #include <fsl-mc/fsl_mc.h>
10 #include <fsl-mc/fsl_mc_sys.h>
11 #include <fsl-mc/fsl_mc_private.h>
12 #include <fsl-mc/fsl_dpmng.h>
13 #include <fsl_debug_server.h>
14 #include <fsl-mc/fsl_dprc.h>
15 #include <fsl-mc/fsl_dpio.h>
16 #include <fsl-mc/fsl_qbman_portal.h>
17 
18 DECLARE_GLOBAL_DATA_PTR;
19 static int mc_boot_status;
20 struct fsl_mc_io *dflt_mc_io = NULL;
21 uint16_t dflt_dprc_handle = 0;
22 struct fsl_dpbp_obj *dflt_dpbp = NULL;
23 struct fsl_dpio_obj *dflt_dpio = NULL;
24 uint16_t dflt_dpio_handle = NULL;
25 
26 /**
27  * Copying MC firmware or DPL image to DDR
28  */
29 static int mc_copy_image(const char *title,
30 			 u64 image_addr, u32 image_size, u64 mc_ram_addr)
31 {
32 	debug("%s copied to address %p\n", title, (void *)mc_ram_addr);
33 	memcpy((void *)mc_ram_addr, (void *)image_addr, image_size);
34 	return 0;
35 }
36 
37 /**
38  * MC firmware FIT image parser checks if the image is in FIT
39  * format, verifies integrity of the image and calculates
40  * raw image address and size values.
41  * Returns 0 on success and a negative errno on error.
42  * task fail.
43  **/
44 int parse_mc_firmware_fit_image(const void **raw_image_addr,
45 				size_t *raw_image_size)
46 {
47 	int format;
48 	void *fit_hdr;
49 	int node_offset;
50 	const void *data;
51 	size_t size;
52 	const char *uname = "firmware";
53 
54 	/* Check if the image is in NOR flash */
55 #ifdef CONFIG_SYS_LS_MC_FW_IN_NOR
56 	fit_hdr = (void *)CONFIG_SYS_LS_MC_FW_ADDR;
57 #else
58 #error "No CONFIG_SYS_LS_MC_FW_IN_xxx defined"
59 #endif
60 
61 	/* Check if Image is in FIT format */
62 	format = genimg_get_format(fit_hdr);
63 
64 	if (format != IMAGE_FORMAT_FIT) {
65 		printf("fsl-mc: ERROR: Bad firmware image (not a FIT image)\n");
66 		return -EINVAL;
67 	}
68 
69 	if (!fit_check_format(fit_hdr)) {
70 		printf("fsl-mc: ERROR: Bad firmware image (bad FIT header)\n");
71 		return -EINVAL;
72 	}
73 
74 	node_offset = fit_image_get_node(fit_hdr, uname);
75 
76 	if (node_offset < 0) {
77 		printf("fsl-mc: ERROR: Bad firmware image (missing subimage)\n");
78 		return -ENOENT;
79 	}
80 
81 	/* Verify MC firmware image */
82 	if (!(fit_image_verify(fit_hdr, node_offset))) {
83 		printf("fsl-mc: ERROR: Bad firmware image (bad CRC)\n");
84 		return -EINVAL;
85 	}
86 
87 	/* Get address and size of raw image */
88 	fit_image_get_data(fit_hdr, node_offset, &data, &size);
89 
90 	*raw_image_addr = data;
91 	*raw_image_size = size;
92 
93 	return 0;
94 }
95 
96 int mc_init(void)
97 {
98 	int error = 0;
99 	int timeout = 200000;
100 	int portal_id = 0;
101 	struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
102 	u64 mc_ram_addr;
103 	u64 mc_dpl_offset;
104 	u32 reg_gsr;
105 	u32 mc_fw_boot_status;
106 	void *dpl_fdt_hdr;
107 	int dpl_size;
108 	const void *raw_image_addr;
109 	size_t raw_image_size = 0;
110 	struct mc_version mc_ver_info;
111 
112 	/*
113 	 * The MC private DRAM block was already carved at the end of DRAM
114 	 * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE:
115 	 */
116 	if (gd->bd->bi_dram[1].start) {
117 		mc_ram_addr =
118 			gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size;
119 	} else {
120 		mc_ram_addr =
121 			gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size;
122 	}
123 
124 #ifdef CONFIG_FSL_DEBUG_SERVER
125 		mc_ram_addr -= debug_server_get_dram_block_size();
126 #endif
127 	/*
128 	 * Management Complex cores should be held at reset out of POR.
129 	 * U-boot should be the first software to touch MC. To be safe,
130 	 * we reset all cores again by setting GCR1 to 0. It doesn't do
131 	 * anything if they are held at reset. After we setup the firmware
132 	 * we kick off MC by deasserting the reset bit for core 0, and
133 	 * deasserting the reset bits for Command Portal Managers.
134 	 * The stop bits are not touched here. They are used to stop the
135 	 * cores when they are active. Setting stop bits doesn't stop the
136 	 * cores from fetching instructions when they are released from
137 	 * reset.
138 	 */
139 	out_le32(&mc_ccsr_regs->reg_gcr1, 0);
140 	dmb();
141 
142 	error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size);
143 	if (error != 0)
144 		goto out;
145 	/*
146 	 * Load the MC FW at the beginning of the MC private DRAM block:
147 	 */
148 	mc_copy_image("MC Firmware",
149 		      (u64)raw_image_addr, raw_image_size, mc_ram_addr);
150 
151 	/*
152 	 * Get address and size of the DPL blob stored in flash:
153 	 */
154 #ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR
155 	dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR;
156 #else
157 #error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined"
158 #endif
159 
160 	error = fdt_check_header(dpl_fdt_hdr);
161 	if (error != 0) {
162 		printf("fsl-mc: ERROR: Bad DPL image (bad header)\n");
163 		goto out;
164 	}
165 
166 	dpl_size = fdt_totalsize(dpl_fdt_hdr);
167 	if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) {
168 		printf("fsl-mc: ERROR: Bad DPL image (too large: %d)\n",
169 		       dpl_size);
170 		error = -EINVAL;
171 		goto out;
172 	}
173 
174 	/*
175 	 * Calculate offset in the MC private DRAM block at which the MC DPL
176 	 * blob is to be placed:
177 	 */
178 #ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET
179 	BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 ||
180 		     CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff);
181 
182 	mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET;
183 #else
184 	mc_dpl_offset = mc_get_dram_block_size() -
185 			roundup(CONFIG_SYS_LS_MC_DPL_MAX_LENGTH, 4096);
186 
187 	if ((mc_dpl_offset & 0x3) != 0 || mc_dpl_offset > 0xffffffff) {
188 		printf("%s: Invalid MC DPL offset: %llu\n",
189 		       __func__, mc_dpl_offset);
190 		error = -EINVAL;
191 		goto out;
192 	}
193 #endif
194 
195 	/*
196 	 * Load the MC DPL blob at the far end of the MC private DRAM block:
197 	 *
198 	 * TODO: Should we place the DPL at a different location to match
199 	 * assumptions of MC firmware about its memory layout?
200 	 */
201 	mc_copy_image("MC DPL blob",
202 		      (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset);
203 
204 	debug("mc_ccsr_regs %p\n", mc_ccsr_regs);
205 
206 	/*
207 	 * Tell MC where the MC Firmware image was loaded in DDR:
208 	 */
209 	out_le32(&mc_ccsr_regs->reg_mcfbalr, (u32)mc_ram_addr);
210 	out_le32(&mc_ccsr_regs->reg_mcfbahr, (u32)((u64)mc_ram_addr >> 32));
211 	out_le32(&mc_ccsr_regs->reg_mcfapr, MCFAPR_BYPASS_ICID_MASK);
212 
213 	/*
214 	 * Tell MC where the DPL blob was loaded in DDR, by indicating
215 	 * its offset relative to the beginning of the DDR block
216 	 * allocated to the MC firmware. The MC firmware is responsible
217 	 * for checking that there is no overlap between the DPL blob
218 	 * and the runtime heap and stack of the MC firmware itself.
219 	 *
220 	 * NOTE: bits [31:2] of this offset need to be stored in bits [29:0] of
221 	 * the GSR MC CCSR register. So, this offset is assumed to be 4-byte
222 	 * aligned.
223 	 * Care must be taken not to write 1s into bits 31 and 30 of the GSR in
224 	 * this case as the SoC COP or PIC will be signaled.
225 	 */
226 	out_le32(&mc_ccsr_regs->reg_gsr, (u32)(mc_dpl_offset >> 2));
227 
228 	printf("\nfsl-mc: Booting Management Complex ...\n");
229 
230 	/*
231 	 * Deassert reset and release MC core 0 to run
232 	 */
233 	out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST);
234 	dmb();
235 	debug("Polling mc_ccsr_regs->reg_gsr ...\n");
236 
237 	for (;;) {
238 		reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr);
239 		mc_fw_boot_status = (reg_gsr & GSR_FS_MASK);
240 		if (mc_fw_boot_status & 0x1)
241 			break;
242 
243 		udelay(1000);	/* throttle polling */
244 		if (timeout-- <= 0)
245 			break;
246 	}
247 
248 	if (timeout <= 0) {
249 		printf("fsl-mc: timeout booting management complex firmware\n");
250 
251 		/* TODO: Get an error status from an MC CCSR register */
252 		error = -ETIMEDOUT;
253 		goto out;
254 	}
255 
256 	if (mc_fw_boot_status != 0x1) {
257 		/*
258 		 * TODO: Identify critical errors from the GSR register's FS
259 		 * field and for those errors, set error to -ENODEV or other
260 		 * appropriate errno, so that the status property is set to
261 		 * failure in the fsl,dprc device tree node.
262 		 */
263 		printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n",
264 		       reg_gsr);
265 	}
266 
267 	/*
268 	 * TODO: need to obtain the portal_id for the root container from the
269 	 * DPL
270 	 */
271 	portal_id = 0;
272 
273 	/*
274 	 * Initialize the global default MC portal
275 	 * And check that the MC firmware is responding portal commands:
276 	 */
277 	dflt_mc_io = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io));
278 	if (!dflt_mc_io) {
279 		printf(" No memory: malloc() failed\n");
280 		return -ENOMEM;
281 	}
282 
283 	dflt_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(portal_id);
284 	debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n",
285 	      portal_id, dflt_mc_io->mmio_regs);
286 
287 	error = mc_get_version(dflt_mc_io, &mc_ver_info);
288 	if (error != 0) {
289 		printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n",
290 		       error);
291 		goto out;
292 	}
293 
294 	if (MC_VER_MAJOR != mc_ver_info.major)
295 		printf("fsl-mc: ERROR: Firmware major version mismatch (found: %d, expected: %d)\n",
296 		       mc_ver_info.major, MC_VER_MAJOR);
297 
298 	if (MC_VER_MINOR != mc_ver_info.minor)
299 		printf("fsl-mc: WARNING: Firmware minor version mismatch (found: %d, expected: %d)\n",
300 		       mc_ver_info.minor, MC_VER_MINOR);
301 
302 	printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n",
303 	       mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision,
304 	       mc_fw_boot_status);
305 out:
306 	if (error != 0)
307 		mc_boot_status = -error;
308 	else
309 		mc_boot_status = 0;
310 
311 	return error;
312 }
313 
314 int get_mc_boot_status(void)
315 {
316 	return mc_boot_status;
317 }
318 
319 /**
320  * Return the actual size of the MC private DRAM block.
321  *
322  * NOTE: For now this function always returns the minimum required size,
323  * However, in the future, the actual size may be obtained from an environment
324  * variable.
325  */
326 unsigned long mc_get_dram_block_size(void)
327 {
328 	return CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE;
329 }
330 
331 int dpio_init(struct dprc_obj_desc obj_desc)
332 {
333 	struct qbman_swp_desc p_des;
334 	struct dpio_attr attr;
335 	int err = 0;
336 
337 	dflt_dpio = (struct fsl_dpio_obj *)malloc(sizeof(struct fsl_dpio_obj));
338 	if (!dflt_dpio) {
339 		printf(" No memory: malloc() failed\n");
340 		return -ENOMEM;
341 	}
342 
343 	dflt_dpio->dpio_id = obj_desc.id;
344 
345 	err = dpio_open(dflt_mc_io, obj_desc.id, &dflt_dpio_handle);
346 	if (err) {
347 		printf("dpio_open() failed\n");
348 		goto err_open;
349 	}
350 
351 	err = dpio_get_attributes(dflt_mc_io, dflt_dpio_handle, &attr);
352 	if (err) {
353 		printf("dpio_get_attributes() failed %d\n", err);
354 		goto err_get_attr;
355 	}
356 
357 	err = dpio_enable(dflt_mc_io, dflt_dpio_handle);
358 	if (err) {
359 		printf("dpio_enable() failed %d\n", err);
360 		goto err_get_enable;
361 	}
362 	debug("ce_paddr=0x%llx, ci_paddr=0x%llx, portalid=%d, prios=%d\n",
363 	      attr.qbman_portal_ce_paddr,
364 	      attr.qbman_portal_ci_paddr,
365 	      attr.qbman_portal_id,
366 	      attr.num_priorities);
367 
368 	p_des.cena_bar = (void *)attr.qbman_portal_ce_paddr;
369 	p_des.cinh_bar = (void *)attr.qbman_portal_ci_paddr;
370 
371 	dflt_dpio->sw_portal = qbman_swp_init(&p_des);
372 	if (dflt_dpio->sw_portal == NULL) {
373 		printf("qbman_swp_init() failed\n");
374 		goto err_get_swp_init;
375 	}
376 	return 0;
377 
378 err_get_swp_init:
379 err_get_enable:
380 	dpio_disable(dflt_mc_io, dflt_dpio_handle);
381 err_get_attr:
382 	dpio_close(dflt_mc_io, dflt_dpio_handle);
383 err_open:
384 	free(dflt_dpio);
385 	return err;
386 }
387 
388 int dpbp_init(struct dprc_obj_desc obj_desc)
389 {
390 	dflt_dpbp = (struct fsl_dpbp_obj *)malloc(sizeof(struct fsl_dpbp_obj));
391 	if (!dflt_dpbp) {
392 		printf(" No memory: malloc() failed\n");
393 		return -ENOMEM;
394 	}
395 	dflt_dpbp->dpbp_attr.id = obj_desc.id;
396 
397 	return 0;
398 }
399 
400 int dprc_init_container_obj(struct dprc_obj_desc obj_desc, uint16_t dprc_handle)
401 {
402 	int error = 0, state = 0;
403 	struct dprc_endpoint dpni_endpoint, dpmac_endpoint;
404 	if (!strcmp(obj_desc.type, "dpbp")) {
405 		if (!dflt_dpbp) {
406 			error = dpbp_init(obj_desc);
407 			if (error < 0)
408 				printf("dpbp_init failed\n");
409 		}
410 	} else if (!strcmp(obj_desc.type, "dpio")) {
411 		if (!dflt_dpio) {
412 			error = dpio_init(obj_desc);
413 			if (error < 0)
414 				printf("dpio_init failed\n");
415 		}
416 	} else if (!strcmp(obj_desc.type, "dpni")) {
417 		strcpy(dpni_endpoint.type, obj_desc.type);
418 		dpni_endpoint.id = obj_desc.id;
419 		error = dprc_get_connection(dflt_mc_io, dprc_handle,
420 				     &dpni_endpoint, &dpmac_endpoint, &state);
421 		if (!strcmp(dpmac_endpoint.type, "dpmac"))
422 			error = ldpaa_eth_init(obj_desc);
423 		if (error < 0)
424 			printf("ldpaa_eth_init failed\n");
425 	}
426 
427 	return error;
428 }
429 
430 int dprc_scan_container_obj(uint16_t dprc_handle, char *obj_type, int i)
431 {
432 	int error = 0;
433 	struct dprc_obj_desc obj_desc;
434 
435 	memset((void *)&obj_desc, 0x00, sizeof(struct dprc_obj_desc));
436 
437 	error = dprc_get_obj(dflt_mc_io, dprc_handle,
438 			     i, &obj_desc);
439 	if (error < 0) {
440 		printf("dprc_get_obj(i=%d) failed: %d\n",
441 		       i, error);
442 		return error;
443 	}
444 
445 	if (!strcmp(obj_desc.type, obj_type)) {
446 		debug("Discovered object: type %s, id %d, req %s\n",
447 		      obj_desc.type, obj_desc.id, obj_type);
448 
449 		error = dprc_init_container_obj(obj_desc, dprc_handle);
450 		if (error < 0) {
451 			printf("dprc_init_container_obj(i=%d) failed: %d\n",
452 			       i, error);
453 			return error;
454 		}
455 	}
456 
457 	return error;
458 }
459 
460 int fsl_mc_ldpaa_init(bd_t *bis)
461 {
462 	int i, error = 0;
463 	int dprc_opened = 0, container_id;
464 	int num_child_objects = 0;
465 
466 	error = mc_init();
467 
468 	error = dprc_get_container_id(dflt_mc_io, &container_id);
469 	if (error < 0) {
470 		printf("dprc_get_container_id() failed: %d\n", error);
471 		goto error;
472 	}
473 
474 	debug("fsl-mc: Container id=0x%x\n", container_id);
475 
476 	error = dprc_open(dflt_mc_io, container_id, &dflt_dprc_handle);
477 	if (error < 0) {
478 		printf("dprc_open() failed: %d\n", error);
479 		goto error;
480 	}
481 	dprc_opened = true;
482 
483 	error = dprc_get_obj_count(dflt_mc_io,
484 				   dflt_dprc_handle,
485 				   &num_child_objects);
486 	if (error < 0) {
487 		printf("dprc_get_obj_count() failed: %d\n", error);
488 		goto error;
489 	}
490 	debug("Total child in container %d = %d\n", container_id,
491 	      num_child_objects);
492 
493 	if (num_child_objects != 0) {
494 		/*
495 		 * Discover objects currently in the DPRC container in the MC:
496 		 */
497 		for (i = 0; i < num_child_objects; i++)
498 			error = dprc_scan_container_obj(dflt_dprc_handle,
499 							"dpbp", i);
500 
501 		for (i = 0; i < num_child_objects; i++)
502 			error = dprc_scan_container_obj(dflt_dprc_handle,
503 							"dpio", i);
504 
505 		for (i = 0; i < num_child_objects; i++)
506 			error = dprc_scan_container_obj(dflt_dprc_handle,
507 							"dpni", i);
508 	}
509 error:
510 	if (dprc_opened)
511 		dprc_close(dflt_mc_io, dflt_dprc_handle);
512 
513 	return error;
514 }
515 
516 void fsl_mc_ldpaa_exit(bd_t *bis)
517 {
518 	int err;
519 
520 
521 	err = dpio_disable(dflt_mc_io, dflt_dpio_handle);
522 	if (err < 0) {
523 		printf("dpio_disable() failed: %d\n", err);
524 		return;
525 	}
526 	err = dpio_reset(dflt_mc_io, dflt_dpio_handle);
527 	if (err < 0) {
528 		printf("dpio_reset() failed: %d\n", err);
529 		return;
530 	}
531 	err = dpio_close(dflt_mc_io, dflt_dpio_handle);
532 	if (err < 0) {
533 		printf("dpio_close() failed: %d\n", err);
534 		return;
535 	}
536 
537 	free(dflt_dpio);
538 	free(dflt_dpbp);
539 	free(dflt_mc_io);
540 }
541