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