xref: /openbmc/u-boot/cmd/fpga.c (revision 5cf22289)
12e192b24SSimon Glass /*
22e192b24SSimon Glass  * (C) Copyright 2000, 2001
32e192b24SSimon Glass  * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
42e192b24SSimon Glass  *
52e192b24SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
62e192b24SSimon Glass  */
72e192b24SSimon Glass 
82e192b24SSimon Glass /*
92e192b24SSimon Glass  *  FPGA support
102e192b24SSimon Glass  */
112e192b24SSimon Glass #include <common.h>
122e192b24SSimon Glass #include <command.h>
132e192b24SSimon Glass #include <fpga.h>
142e192b24SSimon Glass #include <fs.h>
152e192b24SSimon Glass #include <malloc.h>
162e192b24SSimon Glass 
172e192b24SSimon Glass /* Local functions */
182e192b24SSimon Glass static int fpga_get_op(char *opstr);
192e192b24SSimon Glass 
202e192b24SSimon Glass /* Local defines */
21*5cf22289SMichal Simek enum {
22*5cf22289SMichal Simek 	FPGA_NONE = -1,
23*5cf22289SMichal Simek 	FPGA_INFO,
24*5cf22289SMichal Simek 	FPGA_LOAD,
25*5cf22289SMichal Simek 	FPGA_LOADB,
26*5cf22289SMichal Simek 	FPGA_DUMP,
27*5cf22289SMichal Simek 	FPGA_LOADMK,
28*5cf22289SMichal Simek 	FPGA_LOADP,
29*5cf22289SMichal Simek 	FPGA_LOADBP,
30*5cf22289SMichal Simek 	FPGA_LOADFS,
31*5cf22289SMichal Simek };
322e192b24SSimon Glass 
332e192b24SSimon Glass /* ------------------------------------------------------------------------- */
342e192b24SSimon Glass /* command form:
352e192b24SSimon Glass  *   fpga <op> <device number> <data addr> <datasize>
362e192b24SSimon Glass  * where op is 'load', 'dump', or 'info'
372e192b24SSimon Glass  * If there is no device number field, the fpga environment variable is used.
382e192b24SSimon Glass  * If there is no data addr field, the fpgadata environment variable is used.
392e192b24SSimon Glass  * The info command requires no data address field.
402e192b24SSimon Glass  */
412e192b24SSimon Glass int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
422e192b24SSimon Glass {
432e192b24SSimon Glass 	int op, dev = FPGA_INVALID_DEVICE;
442e192b24SSimon Glass 	size_t data_size = 0;
452e192b24SSimon Glass 	void *fpga_data = NULL;
462e192b24SSimon Glass 	char *devstr = getenv("fpga");
472e192b24SSimon Glass 	char *datastr = getenv("fpgadata");
482e192b24SSimon Glass 	int rc = FPGA_FAIL;
492e192b24SSimon Glass 	int wrong_parms = 0;
502e192b24SSimon Glass #if defined(CONFIG_FIT)
512e192b24SSimon Glass 	const char *fit_uname = NULL;
522e192b24SSimon Glass 	ulong fit_addr;
532e192b24SSimon Glass #endif
542e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
552e192b24SSimon Glass 	fpga_fs_info fpga_fsinfo;
562e192b24SSimon Glass 	fpga_fsinfo.fstype = FS_TYPE_ANY;
572e192b24SSimon Glass #endif
582e192b24SSimon Glass 
592e192b24SSimon Glass 	if (devstr)
602e192b24SSimon Glass 		dev = (int) simple_strtoul(devstr, NULL, 16);
612e192b24SSimon Glass 	if (datastr)
622e192b24SSimon Glass 		fpga_data = (void *)simple_strtoul(datastr, NULL, 16);
632e192b24SSimon Glass 
642e192b24SSimon Glass 	switch (argc) {
652e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
662e192b24SSimon Glass 	case 9:
672e192b24SSimon Glass 		fpga_fsinfo.blocksize = (unsigned int)
682e192b24SSimon Glass 					     simple_strtoul(argv[5], NULL, 16);
692e192b24SSimon Glass 		fpga_fsinfo.interface = argv[6];
702e192b24SSimon Glass 		fpga_fsinfo.dev_part = argv[7];
712e192b24SSimon Glass 		fpga_fsinfo.filename = argv[8];
722e192b24SSimon Glass #endif
732e192b24SSimon Glass 	case 5:		/* fpga <op> <dev> <data> <datasize> */
742e192b24SSimon Glass 		data_size = simple_strtoul(argv[4], NULL, 16);
752e192b24SSimon Glass 
762e192b24SSimon Glass 	case 4:		/* fpga <op> <dev> <data> */
772e192b24SSimon Glass #if defined(CONFIG_FIT)
782e192b24SSimon Glass 		if (fit_parse_subimage(argv[3], (ulong)fpga_data,
792e192b24SSimon Glass 				       &fit_addr, &fit_uname)) {
802e192b24SSimon Glass 			fpga_data = (void *)fit_addr;
812e192b24SSimon Glass 			debug("*  fpga: subimage '%s' from FIT image ",
822e192b24SSimon Glass 			      fit_uname);
832e192b24SSimon Glass 			debug("at 0x%08lx\n", fit_addr);
842e192b24SSimon Glass 		} else
852e192b24SSimon Glass #endif
862e192b24SSimon Glass 		{
872e192b24SSimon Glass 			fpga_data = (void *)simple_strtoul(argv[3], NULL, 16);
882e192b24SSimon Glass 			debug("*  fpga: cmdline image address = 0x%08lx\n",
892e192b24SSimon Glass 			      (ulong)fpga_data);
902e192b24SSimon Glass 		}
91455ad585SMichal Simek 		debug("%s: fpga_data = 0x%lx\n", __func__, (ulong)fpga_data);
922e192b24SSimon Glass 
932e192b24SSimon Glass 	case 3:		/* fpga <op> <dev | data addr> */
942e192b24SSimon Glass 		dev = (int)simple_strtoul(argv[2], NULL, 16);
952e192b24SSimon Glass 		debug("%s: device = %d\n", __func__, dev);
962e192b24SSimon Glass 		/* FIXME - this is a really weak test */
972e192b24SSimon Glass 		if ((argc == 3) && (dev > fpga_count())) {
982e192b24SSimon Glass 			/* must be buffer ptr */
992e192b24SSimon Glass 			debug("%s: Assuming buffer pointer in arg 3\n",
1002e192b24SSimon Glass 			      __func__);
1012e192b24SSimon Glass 
1022e192b24SSimon Glass #if defined(CONFIG_FIT)
1032e192b24SSimon Glass 			if (fit_parse_subimage(argv[2], (ulong)fpga_data,
1042e192b24SSimon Glass 					       &fit_addr, &fit_uname)) {
1052e192b24SSimon Glass 				fpga_data = (void *)fit_addr;
1062e192b24SSimon Glass 				debug("*  fpga: subimage '%s' from FIT image ",
1072e192b24SSimon Glass 				      fit_uname);
1082e192b24SSimon Glass 				debug("at 0x%08lx\n", fit_addr);
1092e192b24SSimon Glass 			} else
1102e192b24SSimon Glass #endif
1112e192b24SSimon Glass 			{
112455ad585SMichal Simek 				fpga_data = (void *)(uintptr_t)dev;
1132e192b24SSimon Glass 				debug("*  fpga: cmdline image addr = 0x%08lx\n",
1142e192b24SSimon Glass 				      (ulong)fpga_data);
1152e192b24SSimon Glass 			}
1162e192b24SSimon Glass 
117455ad585SMichal Simek 			debug("%s: fpga_data = 0x%lx\n",
118455ad585SMichal Simek 			      __func__, (ulong)fpga_data);
1192e192b24SSimon Glass 			dev = FPGA_INVALID_DEVICE;	/* reset device num */
1202e192b24SSimon Glass 		}
1212e192b24SSimon Glass 
1222e192b24SSimon Glass 	case 2:		/* fpga <op> */
1232e192b24SSimon Glass 		op = (int)fpga_get_op(argv[1]);
1242e192b24SSimon Glass 		break;
1252e192b24SSimon Glass 
1262e192b24SSimon Glass 	default:
1272e192b24SSimon Glass 		debug("%s: Too many or too few args (%d)\n", __func__, argc);
1282e192b24SSimon Glass 		op = FPGA_NONE;	/* force usage display */
1292e192b24SSimon Glass 		break;
1302e192b24SSimon Glass 	}
1312e192b24SSimon Glass 
1322e192b24SSimon Glass 	if (dev == FPGA_INVALID_DEVICE) {
1332e192b24SSimon Glass 		puts("FPGA device not specified\n");
1342e192b24SSimon Glass 		op = FPGA_NONE;
1352e192b24SSimon Glass 	}
1362e192b24SSimon Glass 
1372e192b24SSimon Glass 	switch (op) {
1382e192b24SSimon Glass 	case FPGA_NONE:
1392e192b24SSimon Glass 	case FPGA_INFO:
1402e192b24SSimon Glass 		break;
1412e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
1422e192b24SSimon Glass 	case FPGA_LOADFS:
1432e192b24SSimon Glass 		/* Blocksize can be zero */
1442e192b24SSimon Glass 		if (!fpga_fsinfo.interface || !fpga_fsinfo.dev_part ||
1452e192b24SSimon Glass 		    !fpga_fsinfo.filename)
1462e192b24SSimon Glass 			wrong_parms = 1;
1472e192b24SSimon Glass #endif
1482e192b24SSimon Glass 	case FPGA_LOAD:
1492e192b24SSimon Glass 	case FPGA_LOADP:
1502e192b24SSimon Glass 	case FPGA_LOADB:
1512e192b24SSimon Glass 	case FPGA_LOADBP:
1522e192b24SSimon Glass 	case FPGA_DUMP:
1532e192b24SSimon Glass 		if (!fpga_data || !data_size)
1542e192b24SSimon Glass 			wrong_parms = 1;
1552e192b24SSimon Glass 		break;
1562e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
1572e192b24SSimon Glass 	case FPGA_LOADMK:
1582e192b24SSimon Glass 		if (!fpga_data)
1592e192b24SSimon Glass 			wrong_parms = 1;
1602e192b24SSimon Glass 		break;
1612e192b24SSimon Glass #endif
1622e192b24SSimon Glass 	}
1632e192b24SSimon Glass 
1642e192b24SSimon Glass 	if (wrong_parms) {
1652e192b24SSimon Glass 		puts("Wrong parameters for FPGA request\n");
1662e192b24SSimon Glass 		op = FPGA_NONE;
1672e192b24SSimon Glass 	}
1682e192b24SSimon Glass 
1692e192b24SSimon Glass 	switch (op) {
1702e192b24SSimon Glass 	case FPGA_NONE:
1712e192b24SSimon Glass 		return CMD_RET_USAGE;
1722e192b24SSimon Glass 
1732e192b24SSimon Glass 	case FPGA_INFO:
1742e192b24SSimon Glass 		rc = fpga_info(dev);
1752e192b24SSimon Glass 		break;
1762e192b24SSimon Glass 
1772e192b24SSimon Glass 	case FPGA_LOAD:
1782e192b24SSimon Glass 		rc = fpga_load(dev, fpga_data, data_size, BIT_FULL);
1792e192b24SSimon Glass 		break;
1802e192b24SSimon Glass 
1812e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADP)
1822e192b24SSimon Glass 	case FPGA_LOADP:
1832e192b24SSimon Glass 		rc = fpga_load(dev, fpga_data, data_size, BIT_PARTIAL);
1842e192b24SSimon Glass 		break;
1852e192b24SSimon Glass #endif
1862e192b24SSimon Glass 
1872e192b24SSimon Glass 	case FPGA_LOADB:
1882e192b24SSimon Glass 		rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_FULL);
1892e192b24SSimon Glass 		break;
1902e192b24SSimon Glass 
1912e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADBP)
1922e192b24SSimon Glass 	case FPGA_LOADBP:
1932e192b24SSimon Glass 		rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_PARTIAL);
1942e192b24SSimon Glass 		break;
1952e192b24SSimon Glass #endif
1962e192b24SSimon Glass 
1972e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
1982e192b24SSimon Glass 	case FPGA_LOADFS:
1992e192b24SSimon Glass 		rc = fpga_fsload(dev, fpga_data, data_size, &fpga_fsinfo);
2002e192b24SSimon Glass 		break;
2012e192b24SSimon Glass #endif
2022e192b24SSimon Glass 
2032e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
2042e192b24SSimon Glass 	case FPGA_LOADMK:
2052e192b24SSimon Glass 		switch (genimg_get_format(fpga_data)) {
2062e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
2072e192b24SSimon Glass 		case IMAGE_FORMAT_LEGACY:
2082e192b24SSimon Glass 			{
2092e192b24SSimon Glass 				image_header_t *hdr =
2102e192b24SSimon Glass 						(image_header_t *)fpga_data;
2112e192b24SSimon Glass 				ulong data;
2122e192b24SSimon Glass 				uint8_t comp;
2132e192b24SSimon Glass 
2142e192b24SSimon Glass 				comp = image_get_comp(hdr);
2152e192b24SSimon Glass 				if (comp == IH_COMP_GZIP) {
2162e192b24SSimon Glass #if defined(CONFIG_GZIP)
2172e192b24SSimon Glass 					ulong image_buf = image_get_data(hdr);
2182e192b24SSimon Glass 					data = image_get_load(hdr);
2192e192b24SSimon Glass 					ulong image_size = ~0UL;
2202e192b24SSimon Glass 
2212e192b24SSimon Glass 					if (gunzip((void *)data, ~0UL,
2222e192b24SSimon Glass 						   (void *)image_buf,
2232e192b24SSimon Glass 						   &image_size) != 0) {
2242e192b24SSimon Glass 						puts("GUNZIP: error\n");
2252e192b24SSimon Glass 						return 1;
2262e192b24SSimon Glass 					}
2272e192b24SSimon Glass 					data_size = image_size;
2282e192b24SSimon Glass #else
2292e192b24SSimon Glass 					puts("Gunzip image is not supported\n");
2302e192b24SSimon Glass 					return 1;
2312e192b24SSimon Glass #endif
2322e192b24SSimon Glass 				} else {
2332e192b24SSimon Glass 					data = (ulong)image_get_data(hdr);
2342e192b24SSimon Glass 					data_size = image_get_data_size(hdr);
2352e192b24SSimon Glass 				}
2362e192b24SSimon Glass 				rc = fpga_load(dev, (void *)data, data_size,
2372e192b24SSimon Glass 					       BIT_FULL);
2382e192b24SSimon Glass 			}
2392e192b24SSimon Glass 			break;
2402e192b24SSimon Glass #endif
2412e192b24SSimon Glass #if defined(CONFIG_FIT)
2422e192b24SSimon Glass 		case IMAGE_FORMAT_FIT:
2432e192b24SSimon Glass 			{
2442e192b24SSimon Glass 				const void *fit_hdr = (const void *)fpga_data;
2452e192b24SSimon Glass 				int noffset;
2462e192b24SSimon Glass 				const void *fit_data;
2472e192b24SSimon Glass 
2482e192b24SSimon Glass 				if (fit_uname == NULL) {
2492e192b24SSimon Glass 					puts("No FIT subimage unit name\n");
2502e192b24SSimon Glass 					return 1;
2512e192b24SSimon Glass 				}
2522e192b24SSimon Glass 
2532e192b24SSimon Glass 				if (!fit_check_format(fit_hdr)) {
2542e192b24SSimon Glass 					puts("Bad FIT image format\n");
2552e192b24SSimon Glass 					return 1;
2562e192b24SSimon Glass 				}
2572e192b24SSimon Glass 
2582e192b24SSimon Glass 				/* get fpga component image node offset */
2592e192b24SSimon Glass 				noffset = fit_image_get_node(fit_hdr,
2602e192b24SSimon Glass 							     fit_uname);
2612e192b24SSimon Glass 				if (noffset < 0) {
2622e192b24SSimon Glass 					printf("Can't find '%s' FIT subimage\n",
2632e192b24SSimon Glass 					       fit_uname);
2642e192b24SSimon Glass 					return 1;
2652e192b24SSimon Glass 				}
2662e192b24SSimon Glass 
2672e192b24SSimon Glass 				/* verify integrity */
2682e192b24SSimon Glass 				if (!fit_image_verify(fit_hdr, noffset)) {
2692e192b24SSimon Glass 					puts ("Bad Data Hash\n");
2702e192b24SSimon Glass 					return 1;
2712e192b24SSimon Glass 				}
2722e192b24SSimon Glass 
2732e192b24SSimon Glass 				/* get fpga subimage data address and length */
2742e192b24SSimon Glass 				if (fit_image_get_data(fit_hdr, noffset,
2752e192b24SSimon Glass 						       &fit_data, &data_size)) {
2762e192b24SSimon Glass 					puts("Fpga subimage data not found\n");
2772e192b24SSimon Glass 					return 1;
2782e192b24SSimon Glass 				}
2792e192b24SSimon Glass 
2802e192b24SSimon Glass 				rc = fpga_load(dev, fit_data, data_size,
2812e192b24SSimon Glass 					       BIT_FULL);
2822e192b24SSimon Glass 			}
2832e192b24SSimon Glass 			break;
2842e192b24SSimon Glass #endif
2852e192b24SSimon Glass 		default:
2862e192b24SSimon Glass 			puts("** Unknown image type\n");
2872e192b24SSimon Glass 			rc = FPGA_FAIL;
2882e192b24SSimon Glass 			break;
2892e192b24SSimon Glass 		}
2902e192b24SSimon Glass 		break;
2912e192b24SSimon Glass #endif
2922e192b24SSimon Glass 
2932e192b24SSimon Glass 	case FPGA_DUMP:
2942e192b24SSimon Glass 		rc = fpga_dump(dev, fpga_data, data_size);
2952e192b24SSimon Glass 		break;
2962e192b24SSimon Glass 
2972e192b24SSimon Glass 	default:
2982e192b24SSimon Glass 		printf("Unknown operation\n");
2992e192b24SSimon Glass 		return CMD_RET_USAGE;
3002e192b24SSimon Glass 	}
3012e192b24SSimon Glass 	return rc;
3022e192b24SSimon Glass }
3032e192b24SSimon Glass 
3042e192b24SSimon Glass /*
3052e192b24SSimon Glass  * Map op to supported operations.  We don't use a table since we
3062e192b24SSimon Glass  * would just have to relocate it from flash anyway.
3072e192b24SSimon Glass  */
3082e192b24SSimon Glass static int fpga_get_op(char *opstr)
3092e192b24SSimon Glass {
3102e192b24SSimon Glass 	int op = FPGA_NONE;
3112e192b24SSimon Glass 
3122e192b24SSimon Glass 	if (!strcmp("info", opstr))
3132e192b24SSimon Glass 		op = FPGA_INFO;
3142e192b24SSimon Glass 	else if (!strcmp("loadb", opstr))
3152e192b24SSimon Glass 		op = FPGA_LOADB;
3162e192b24SSimon Glass 	else if (!strcmp("load", opstr))
3172e192b24SSimon Glass 		op = FPGA_LOAD;
3182e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADP)
3192e192b24SSimon Glass 	else if (!strcmp("loadp", opstr))
3202e192b24SSimon Glass 		op = FPGA_LOADP;
3212e192b24SSimon Glass #endif
3222e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADBP)
3232e192b24SSimon Glass 	else if (!strcmp("loadbp", opstr))
3242e192b24SSimon Glass 		op = FPGA_LOADBP;
3252e192b24SSimon Glass #endif
3262e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
3272e192b24SSimon Glass 	else if (!strcmp("loadfs", opstr))
3282e192b24SSimon Glass 		op = FPGA_LOADFS;
3292e192b24SSimon Glass #endif
3302e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
3312e192b24SSimon Glass 	else if (!strcmp("loadmk", opstr))
3322e192b24SSimon Glass 		op = FPGA_LOADMK;
3332e192b24SSimon Glass #endif
3342e192b24SSimon Glass 	else if (!strcmp("dump", opstr))
3352e192b24SSimon Glass 		op = FPGA_DUMP;
3362e192b24SSimon Glass 
3372e192b24SSimon Glass 	if (op == FPGA_NONE)
3382e192b24SSimon Glass 		printf("Unknown fpga operation \"%s\"\n", opstr);
3392e192b24SSimon Glass 
3402e192b24SSimon Glass 	return op;
3412e192b24SSimon Glass }
3422e192b24SSimon Glass 
3432e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
3442e192b24SSimon Glass U_BOOT_CMD(fpga, 9, 1, do_fpga,
3452e192b24SSimon Glass #else
3462e192b24SSimon Glass U_BOOT_CMD(fpga, 6, 1, do_fpga,
3472e192b24SSimon Glass #endif
3482e192b24SSimon Glass 	   "loadable FPGA image support",
3492e192b24SSimon Glass 	   "[operation type] [device number] [image address] [image size]\n"
3502e192b24SSimon Glass 	   "fpga operations:\n"
3512e192b24SSimon Glass 	   "  dump\t[dev] [address] [size]\tLoad device to memory buffer\n"
3522e192b24SSimon Glass 	   "  info\t[dev]\t\t\tlist known device information\n"
3532e192b24SSimon Glass 	   "  load\t[dev] [address] [size]\tLoad device from memory buffer\n"
3542e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADP)
3552e192b24SSimon Glass 	   "  loadp\t[dev] [address] [size]\t"
3562e192b24SSimon Glass 	   "Load device from memory buffer with partial bitstream\n"
3572e192b24SSimon Glass #endif
3582e192b24SSimon Glass 	   "  loadb\t[dev] [address] [size]\t"
3592e192b24SSimon Glass 	   "Load device from bitstream buffer (Xilinx only)\n"
3602e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADBP)
3612e192b24SSimon Glass 	   "  loadbp\t[dev] [address] [size]\t"
3622e192b24SSimon Glass 	   "Load device from bitstream buffer with partial bitstream"
3632e192b24SSimon Glass 	   "(Xilinx only)\n"
3642e192b24SSimon Glass #endif
3652e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADFS)
3662e192b24SSimon Glass 	   "Load device from filesystem (FAT by default) (Xilinx only)\n"
3672e192b24SSimon Glass 	   "  loadfs [dev] [address] [image size] [blocksize] <interface>\n"
3682e192b24SSimon Glass 	   "        [<dev[:part]>] <filename>\n"
3692e192b24SSimon Glass #endif
3702e192b24SSimon Glass #if defined(CONFIG_CMD_FPGA_LOADMK)
3712e192b24SSimon Glass 	   "  loadmk [dev] [address]\tLoad device generated with mkimage"
3722e192b24SSimon Glass #if defined(CONFIG_FIT)
3732e192b24SSimon Glass 	   "\n"
3742e192b24SSimon Glass 	   "\tFor loadmk operating on FIT format uImage address must include\n"
3752e192b24SSimon Glass 	   "\tsubimage unit name in the form of addr:<subimg_uname>"
3762e192b24SSimon Glass #endif
3772e192b24SSimon Glass #endif
3782e192b24SSimon Glass );
379