Browse Source

Merge tag 'fpga-for-v2018.11' of git://git.denx.de/u-boot-microblaze

FPGA changes for v2018.11

- add fpga tests to cover fpga commands
- fpga Kconfig cleanup
- fix cmd/fpga.c
- add support for missing fpga loadmk commands
- add fpga fragment to MAINTAINERS
Tom Rini 5 years ago
parent
commit
89aa19d092
4 changed files with 904 additions and 324 deletions
  1. 8 0
      MAINTAINERS
  2. 336 316
      cmd/fpga.c
  3. 8 8
      drivers/fpga/Kconfig
  4. 552 0
      test/py/tests/test_fpga.py

+ 8 - 0
MAINTAINERS

@@ -391,6 +391,14 @@ F:	test/py/tests/test_efi*
 F:	cmd/bootefi.c
 F:	tools/file2include.c
 
+FPGA
+M:	Michal Simek <michal.simek@xilinx.com>
+S:	Maintained
+T:	git git://git.denx.de/u-boot-microblaze.git
+F:	drivers/fpga/
+F:	cmd/fpga.c
+F:	include/fpga.h
+
 FLATTENED DEVICE TREE
 M:	Simon Glass <sjg@chromium.org>
 S:	Maintained

+ 336 - 316
cmd/fpga.c

@@ -13,388 +13,408 @@
 #include <fs.h>
 #include <malloc.h>
 
-/* Local functions */
-static int fpga_get_op(char *opstr);
-
-/* Local defines */
-enum {
-	FPGA_NONE = -1,
-	FPGA_INFO,
-	FPGA_LOAD,
-	FPGA_LOADB,
-	FPGA_DUMP,
-	FPGA_LOADMK,
-	FPGA_LOADP,
-	FPGA_LOADBP,
-	FPGA_LOADFS,
-	FPGA_LOADS,
-};
-
-/* ------------------------------------------------------------------------- */
-/* command form:
- *   fpga <op> <device number> <data addr> <datasize>
- * where op is 'load', 'dump', or 'info'
- * If there is no device number field, the fpga environment variable is used.
- * If there is no data addr field, the fpgadata environment variable is used.
- * The info command requires no data address field.
- */
-int do_fpga(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+static long do_fpga_get_device(char *arg)
 {
-	int op, dev = FPGA_INVALID_DEVICE;
-	size_t data_size = 0;
-	void *fpga_data = NULL;
+	long dev = FPGA_INVALID_DEVICE;
 	char *devstr = env_get("fpga");
-	char *datastr = env_get("fpgadata");
-	int rc = FPGA_FAIL;
-	int wrong_parms = 0;
-#if defined(CONFIG_FIT)
-	const char *fit_uname = NULL;
-	ulong fit_addr;
-#endif
-#if defined(CONFIG_CMD_FPGA_LOADFS)
-	fpga_fs_info fpga_fsinfo;
-	fpga_fsinfo.fstype = FS_TYPE_ANY;
-#endif
-#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
-	struct fpga_secure_info fpga_sec_info;
-
-	memset(&fpga_sec_info, 0, sizeof(fpga_sec_info));
-#endif
 
 	if (devstr)
-		dev = (int) simple_strtoul(devstr, NULL, 16);
-	if (datastr)
-		fpga_data = (void *)simple_strtoul(datastr, NULL, 16);
+		/* Should be strtol to handle -1 cases */
+		dev = simple_strtol(devstr, NULL, 16);
+
+	if (dev == FPGA_INVALID_DEVICE && arg)
+		dev = simple_strtol(arg, NULL, 16);
 
-	if (argc > 9 || argc < 2) {
-		debug("%s: Too many or too few args (%d)\n", __func__, argc);
+	debug("%s: device = %ld\n", __func__, dev);
+
+	return dev;
+}
+
+static int do_fpga_check_params(long *dev, long *fpga_data, size_t *data_size,
+				cmd_tbl_t *cmdtp, int argc, char *const argv[])
+{
+	size_t local_data_size;
+	long local_fpga_data;
+
+	debug("%s %d, %d\n", __func__, argc, cmdtp->maxargs);
+
+	if (argc != cmdtp->maxargs) {
+		debug("fpga: incorrect parameters passed\n");
 		return CMD_RET_USAGE;
 	}
 
-	op = (int)fpga_get_op(argv[1]);
+	*dev = do_fpga_get_device(argv[0]);
 
-	switch (op) {
-#if defined(CONFIG_CMD_FPGA_LOADFS)
-	case FPGA_LOADFS:
-		if (argc < 9)
-			return CMD_RET_USAGE;
-		fpga_fsinfo.blocksize = (unsigned int)
-					simple_strtoul(argv[5], NULL, 16);
-		fpga_fsinfo.interface = argv[6];
-		fpga_fsinfo.dev_part = argv[7];
-		fpga_fsinfo.filename = argv[8];
-		argc = 5;
-		break;
-#endif
-#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
-	case FPGA_LOADS:
-		if (argc < 7)
-			return CMD_RET_USAGE;
-		if (argc == 8)
-			fpga_sec_info.userkey_addr = (u8 *)(uintptr_t)
-						     simple_strtoull(argv[7],
-								     NULL, 16);
-		fpga_sec_info.encflag = (u8)simple_strtoul(argv[6], NULL, 16);
-		fpga_sec_info.authflag = (u8)simple_strtoul(argv[5], NULL, 16);
-		argc = 5;
-		break;
-#endif
-	default:
-		break;
+	local_fpga_data = simple_strtol(argv[1], NULL, 16);
+	if (!local_fpga_data) {
+		debug("fpga: zero fpga_data address\n");
+		return CMD_RET_USAGE;
 	}
+	*fpga_data = local_fpga_data;
 
-	switch (argc) {
-	case 5:		/* fpga <op> <dev> <data> <datasize> */
-		data_size = simple_strtoul(argv[4], NULL, 16);
+	local_data_size = simple_strtoul(argv[2], NULL, 16);
+	if (!local_data_size) {
+		debug("fpga: zero size\n");
+		return CMD_RET_USAGE;
+	}
+	*data_size = local_data_size;
 
-	case 4:		/* fpga <op> <dev> <data> */
-#if defined(CONFIG_FIT)
-		if (fit_parse_subimage(argv[3], (ulong)fpga_data,
-				       &fit_addr, &fit_uname)) {
-			fpga_data = (void *)fit_addr;
-			debug("*  fpga: subimage '%s' from FIT image ",
-			      fit_uname);
-			debug("at 0x%08lx\n", fit_addr);
-		} else
-#endif
-		{
-			fpga_data = (void *)simple_strtoul(argv[3], NULL, 16);
-			debug("*  fpga: cmdline image address = 0x%08lx\n",
-			      (ulong)fpga_data);
-		}
-		debug("%s: fpga_data = 0x%lx\n", __func__, (ulong)fpga_data);
+	return 0;
+}
+
+#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
+int do_fpga_loads(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	size_t data_size = 0;
+	long fpga_data, dev;
+	int ret;
+	struct fpga_secure_info fpga_sec_info;
 
-	case 3:		/* fpga <op> <dev | data addr> */
-		dev = (int)simple_strtoul(argv[2], NULL, 16);
-		debug("%s: device = %d\n", __func__, dev);
-		/* FIXME - this is a really weak test */
-		if ((argc == 3) && (dev > fpga_count())) {
-			/* must be buffer ptr */
-			debug("%s: Assuming buffer pointer in arg 3\n",
-			      __func__);
+	memset(&fpga_sec_info, 0, sizeof(fpga_sec_info));
 
-#if defined(CONFIG_FIT)
-			if (fit_parse_subimage(argv[2], (ulong)fpga_data,
-					       &fit_addr, &fit_uname)) {
-				fpga_data = (void *)fit_addr;
-				debug("*  fpga: subimage '%s' from FIT image ",
-				      fit_uname);
-				debug("at 0x%08lx\n", fit_addr);
-			} else
-#endif
-			{
-				fpga_data = (void *)(uintptr_t)dev;
-				debug("*  fpga: cmdline image addr = 0x%08lx\n",
-				      (ulong)fpga_data);
-			}
+	if (argc < 5) {
+		debug("fpga: incorrect parameters passed\n");
+		return CMD_RET_USAGE;
+	}
 
-			debug("%s: fpga_data = 0x%lx\n",
-			      __func__, (ulong)fpga_data);
-			dev = FPGA_INVALID_DEVICE;	/* reset device num */
-		}
+	if (argc == 6)
+		fpga_sec_info.userkey_addr = (u8 *)(uintptr_t)
+					      simple_strtoull(argv[5],
+							      NULL, 16);
+	else
+		/*
+		 * If 6th parameter is not passed then do_fpga_check_params
+		 * will get 5 instead of expected 6 which means that function
+		 * return CMD_RET_USAGE. Increase number of params +1 to pass
+		 * this.
+		 */
+		argc++;
+
+	fpga_sec_info.encflag = (u8)simple_strtoul(argv[4], NULL, 16);
+	fpga_sec_info.authflag = (u8)simple_strtoul(argv[3], NULL, 16);
+
+	if (fpga_sec_info.authflag >= FPGA_NO_ENC_OR_NO_AUTH &&
+	    fpga_sec_info.encflag >= FPGA_NO_ENC_OR_NO_AUTH) {
+		debug("fpga: Use <fpga load> for NonSecure bitstream\n");
+		return CMD_RET_USAGE;
 	}
 
-	if (dev == FPGA_INVALID_DEVICE) {
-		puts("FPGA device not specified\n");
-		op = FPGA_NONE;
+	if (fpga_sec_info.encflag == FPGA_ENC_USR_KEY &&
+	    !fpga_sec_info.userkey_addr) {
+		debug("fpga: User key not provided\n");
+		return CMD_RET_USAGE;
 	}
 
-	switch (op) {
-	case FPGA_NONE:
-	case FPGA_INFO:
-		break;
-#if defined(CONFIG_CMD_FPGA_LOADFS)
-	case FPGA_LOADFS:
-		/* Blocksize can be zero */
-		if (!fpga_fsinfo.interface || !fpga_fsinfo.dev_part ||
-		    !fpga_fsinfo.filename)
-			wrong_parms = 1;
-		break;
-#endif
-#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
-	case FPGA_LOADS:
-		if (fpga_sec_info.authflag >= FPGA_NO_ENC_OR_NO_AUTH &&
-		    fpga_sec_info.encflag >= FPGA_NO_ENC_OR_NO_AUTH) {
-			puts("ERR: use <fpga load> for NonSecure bitstream\n");
-			wrong_parms = 1;
-		}
+	ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
+				   cmdtp, argc, argv);
+	if (ret)
+		return ret;
 
-		if (fpga_sec_info.encflag == FPGA_ENC_USR_KEY &&
-		    !fpga_sec_info.userkey_addr) {
-			wrong_parms = 1;
-			puts("ERR:User key not provided\n");
-		}
-		break;
+	return fpga_loads(dev, (void *)fpga_data, data_size, &fpga_sec_info);
+}
 #endif
-	case FPGA_LOAD:
-	case FPGA_LOADP:
-	case FPGA_LOADB:
-	case FPGA_LOADBP:
-	case FPGA_DUMP:
-		if (!fpga_data || !data_size)
-			wrong_parms = 1;
-		break;
-#if defined(CONFIG_CMD_FPGA_LOADMK)
-	case FPGA_LOADMK:
-		if (!fpga_data)
-			wrong_parms = 1;
-		break;
+
+#if defined(CONFIG_CMD_FPGA_LOADFS)
+static int do_fpga_loadfs(cmd_tbl_t *cmdtp, int flag, int argc,
+			  char *const argv[])
+{
+	size_t data_size = 0;
+	long fpga_data, dev;
+	int ret;
+	fpga_fs_info fpga_fsinfo;
+
+	ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
+				   cmdtp, argc, argv);
+	if (ret)
+		return ret;
+
+	fpga_fsinfo.fstype = FS_TYPE_ANY;
+	fpga_fsinfo.blocksize = (unsigned int)simple_strtoul(argv[3], NULL, 16);
+	fpga_fsinfo.interface = argv[4];
+	fpga_fsinfo.dev_part = argv[5];
+	fpga_fsinfo.filename = argv[6];
+
+	return fpga_fsload(dev, (void *)fpga_data, data_size, &fpga_fsinfo);
+}
 #endif
-	}
 
-	if (wrong_parms) {
-		puts("Wrong parameters for FPGA request\n");
-		op = FPGA_NONE;
-	}
+static int do_fpga_info(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	long dev = do_fpga_get_device(argv[0]);
 
-	switch (op) {
-	case FPGA_NONE:
-		return CMD_RET_USAGE;
+	return fpga_info(dev);
+}
+
+static int do_fpga_dump(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	size_t data_size = 0;
+	long fpga_data, dev;
+	int ret;
+
+	ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
+				   cmdtp, argc, argv);
+	if (ret)
+		return ret;
+
+	return fpga_dump(dev, (void *)fpga_data, data_size);
+}
 
-	case FPGA_INFO:
-		rc = fpga_info(dev);
-		break;
+static int do_fpga_load(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	size_t data_size = 0;
+	long fpga_data, dev;
+	int ret;
+
+	ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
+				   cmdtp, argc, argv);
+	if (ret)
+		return ret;
 
-	case FPGA_LOAD:
-		rc = fpga_load(dev, fpga_data, data_size, BIT_FULL);
-		break;
+	return fpga_load(dev, (void *)fpga_data, data_size, BIT_FULL);
+}
+
+static int do_fpga_loadb(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char * const argv[])
+{
+	size_t data_size = 0;
+	long fpga_data, dev;
+	int ret;
+
+	ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
+				   cmdtp, argc, argv);
+	if (ret)
+		return ret;
+
+	return fpga_loadbitstream(dev, (void *)fpga_data, data_size, BIT_FULL);
+}
 
 #if defined(CONFIG_CMD_FPGA_LOADP)
-	case FPGA_LOADP:
-		rc = fpga_load(dev, fpga_data, data_size, BIT_PARTIAL);
-		break;
-#endif
+static int do_fpga_loadp(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char * const argv[])
+{
+	size_t data_size = 0;
+	long fpga_data, dev;
+	int ret;
+
+	ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
+				   cmdtp, argc, argv);
+	if (ret)
+		return ret;
 
-	case FPGA_LOADB:
-		rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_FULL);
-		break;
+	return fpga_load(dev, (void *)fpga_data, data_size, BIT_PARTIAL);
+}
+#endif
 
 #if defined(CONFIG_CMD_FPGA_LOADBP)
-	case FPGA_LOADBP:
-		rc = fpga_loadbitstream(dev, fpga_data, data_size, BIT_PARTIAL);
-		break;
+static int do_fpga_loadbp(cmd_tbl_t *cmdtp, int flag, int argc,
+			  char * const argv[])
+{
+	size_t data_size = 0;
+	long fpga_data, dev;
+	int ret;
+
+	ret = do_fpga_check_params(&dev, &fpga_data, &data_size,
+				   cmdtp, argc, argv);
+	if (ret)
+		return ret;
+
+	return fpga_loadbitstream(dev, (void *)fpga_data, data_size,
+				  BIT_PARTIAL);
+}
 #endif
 
-#if defined(CONFIG_CMD_FPGA_LOADFS)
-	case FPGA_LOADFS:
-		rc = fpga_fsload(dev, fpga_data, data_size, &fpga_fsinfo);
-		break;
+#if defined(CONFIG_CMD_FPGA_LOADMK)
+static int do_fpga_loadmk(cmd_tbl_t *cmdtp, int flag, int argc,
+			  char * const argv[])
+{
+	size_t data_size = 0;
+	void *fpga_data = NULL;
+#if defined(CONFIG_FIT)
+	const char *fit_uname = NULL;
+	ulong fit_addr;
 #endif
+	ulong dev = do_fpga_get_device(argv[0]);
+	char *datastr = env_get("fpgadata");
 
-#if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
-	case FPGA_LOADS:
-		rc = fpga_loads(dev, fpga_data, data_size, &fpga_sec_info);
-		break;
+	debug("fpga: argc %x, dev %lx, datastr %s\n", argc, dev, datastr);
+
+	if (dev == FPGA_INVALID_DEVICE) {
+		debug("fpga: Invalid fpga device\n");
+		return CMD_RET_USAGE;
+	}
+
+	if (argc == 0 && !datastr) {
+		debug("fpga: No datastr passed\n");
+		return CMD_RET_USAGE;
+	}
+
+	if (argc == 2) {
+		datastr = argv[1];
+		debug("fpga: Full command with two args\n");
+	} else if (argc == 1 && !datastr) {
+		debug("fpga: Dev is setup - fpgadata passed\n");
+		datastr = argv[0];
+	}
+
+#if defined(CONFIG_FIT)
+	if (fit_parse_subimage(datastr, (ulong)fpga_data,
+			       &fit_addr, &fit_uname)) {
+		fpga_data = (void *)fit_addr;
+		debug("*  fpga: subimage '%s' from FIT image ",
+		      fit_uname);
+		debug("at 0x%08lx\n", fit_addr);
+	} else
 #endif
+	{
+		fpga_data = (void *)simple_strtoul(datastr, NULL, 16);
+		debug("*  fpga: cmdline image address = 0x%08lx\n",
+		      (ulong)fpga_data);
+	}
+	debug("%s: fpga_data = 0x%lx\n", __func__, (ulong)fpga_data);
+	if (!fpga_data) {
+		puts("Zero fpga_data address\n");
+		return CMD_RET_USAGE;
+	}
 
-#if defined(CONFIG_CMD_FPGA_LOADMK)
-	case FPGA_LOADMK:
-		switch (genimg_get_format(fpga_data)) {
+	switch (genimg_get_format(fpga_data)) {
 #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
-		case IMAGE_FORMAT_LEGACY:
-			{
-				image_header_t *hdr =
-						(image_header_t *)fpga_data;
-				ulong data;
-				uint8_t comp;
-
-				comp = image_get_comp(hdr);
-				if (comp == IH_COMP_GZIP) {
+	case IMAGE_FORMAT_LEGACY:
+	{
+		image_header_t *hdr = (image_header_t *)fpga_data;
+		ulong data;
+		u8 comp;
+
+		comp = image_get_comp(hdr);
+		if (comp == IH_COMP_GZIP) {
 #if defined(CONFIG_GZIP)
-					ulong image_buf = image_get_data(hdr);
-					data = image_get_load(hdr);
-					ulong image_size = ~0UL;
-
-					if (gunzip((void *)data, ~0UL,
-						   (void *)image_buf,
-						   &image_size) != 0) {
-						puts("GUNZIP: error\n");
-						return 1;
-					}
-					data_size = image_size;
+			ulong image_buf = image_get_data(hdr);
+			ulong image_size = ~0UL;
+
+			data = image_get_load(hdr);
+
+			if (gunzip((void *)data, ~0UL, (void *)image_buf,
+				   &image_size) != 0) {
+				puts("GUNZIP: error\n");
+				return CMD_RET_FAILURE;
+			}
+			data_size = image_size;
 #else
-					puts("Gunzip image is not supported\n");
-					return 1;
+			puts("Gunzip image is not supported\n");
+			return 1;
 #endif
-				} else {
-					data = (ulong)image_get_data(hdr);
-					data_size = image_get_data_size(hdr);
-				}
-				rc = fpga_load(dev, (void *)data, data_size,
-					       BIT_FULL);
-			}
-			break;
+		} else {
+			data = (ulong)image_get_data(hdr);
+			data_size = image_get_data_size(hdr);
+		}
+		return fpga_load(dev, (void *)data, data_size,
+				  BIT_FULL);
+	}
 #endif
 #if defined(CONFIG_FIT)
-		case IMAGE_FORMAT_FIT:
-			{
-				const void *fit_hdr = (const void *)fpga_data;
-				int noffset;
-				const void *fit_data;
-
-				if (fit_uname == NULL) {
-					puts("No FIT subimage unit name\n");
-					return 1;
-				}
-
-				if (!fit_check_format(fit_hdr)) {
-					puts("Bad FIT image format\n");
-					return 1;
-				}
-
-				/* get fpga component image node offset */
-				noffset = fit_image_get_node(fit_hdr,
-							     fit_uname);
-				if (noffset < 0) {
-					printf("Can't find '%s' FIT subimage\n",
-					       fit_uname);
-					return 1;
-				}
-
-				/* verify integrity */
-				if (!fit_image_verify(fit_hdr, noffset)) {
-					puts ("Bad Data Hash\n");
-					return 1;
-				}
-
-				/* get fpga subimage data address and length */
-				if (fit_image_get_data(fit_hdr, noffset,
-						       &fit_data, &data_size)) {
-					puts("Fpga subimage data not found\n");
-					return 1;
-				}
-
-				rc = fpga_load(dev, fit_data, data_size,
-					       BIT_FULL);
-			}
-			break;
-#endif
-		default:
-			puts("** Unknown image type\n");
-			rc = FPGA_FAIL;
-			break;
+	case IMAGE_FORMAT_FIT:
+	{
+		const void *fit_hdr = (const void *)fpga_data;
+		int noffset;
+		const void *fit_data;
+
+		if (!fit_uname) {
+			puts("No FIT subimage unit name\n");
+			return CMD_RET_FAILURE;
+		}
+
+		if (!fit_check_format(fit_hdr)) {
+			puts("Bad FIT image format\n");
+			return CMD_RET_FAILURE;
 		}
-		break;
-#endif
 
-	case FPGA_DUMP:
-		rc = fpga_dump(dev, fpga_data, data_size);
-		break;
+		/* get fpga component image node offset */
+		noffset = fit_image_get_node(fit_hdr, fit_uname);
+		if (noffset < 0) {
+			printf("Can't find '%s' FIT subimage\n", fit_uname);
+			return CMD_RET_FAILURE;
+		}
 
+		/* verify integrity */
+		if (!fit_image_verify(fit_hdr, noffset)) {
+			puts("Bad Data Hash\n");
+			return CMD_RET_FAILURE;
+		}
+
+		/* get fpga subimage data address and length */
+		if (fit_image_get_data(fit_hdr, noffset, &fit_data,
+				       &data_size)) {
+			puts("Fpga subimage data not found\n");
+			return CMD_RET_FAILURE;
+		}
+
+		return fpga_load(dev, fit_data, data_size, BIT_FULL);
+	}
+#endif
 	default:
-		printf("Unknown operation\n");
-		return CMD_RET_USAGE;
+		puts("** Unknown image type\n");
+		return CMD_RET_FAILURE;
 	}
-	return rc;
 }
+#endif
 
-/*
- * Map op to supported operations.  We don't use a table since we
- * would just have to relocate it from flash anyway.
- */
-static int fpga_get_op(char *opstr)
-{
-	int op = FPGA_NONE;
-
-	if (!strcmp("info", opstr))
-		op = FPGA_INFO;
-	else if (!strcmp("loadb", opstr))
-		op = FPGA_LOADB;
-	else if (!strcmp("load", opstr))
-		op = FPGA_LOAD;
+static cmd_tbl_t fpga_commands[] = {
+	U_BOOT_CMD_MKENT(info, 1, 1, do_fpga_info, "", ""),
+	U_BOOT_CMD_MKENT(dump, 3, 1, do_fpga_dump, "", ""),
+	U_BOOT_CMD_MKENT(load, 3, 1, do_fpga_load, "", ""),
+	U_BOOT_CMD_MKENT(loadb, 3, 1, do_fpga_loadb, "", ""),
 #if defined(CONFIG_CMD_FPGA_LOADP)
-	else if (!strcmp("loadp", opstr))
-		op = FPGA_LOADP;
+	U_BOOT_CMD_MKENT(loadp, 3, 1, do_fpga_loadp, "", ""),
 #endif
 #if defined(CONFIG_CMD_FPGA_LOADBP)
-	else if (!strcmp("loadbp", opstr))
-		op = FPGA_LOADBP;
+	U_BOOT_CMD_MKENT(loadbp, 3, 1, do_fpga_loadbp, "", ""),
 #endif
 #if defined(CONFIG_CMD_FPGA_LOADFS)
-	else if (!strcmp("loadfs", opstr))
-		op = FPGA_LOADFS;
+	U_BOOT_CMD_MKENT(loadfs, 7, 1, do_fpga_loadfs, "", ""),
 #endif
 #if defined(CONFIG_CMD_FPGA_LOADMK)
-	else if (!strcmp("loadmk", opstr))
-		op = FPGA_LOADMK;
+	U_BOOT_CMD_MKENT(loadmk, 2, 1, do_fpga_loadmk, "", ""),
 #endif
-	else if (!strcmp("dump", opstr))
-		op = FPGA_DUMP;
 #if defined(CONFIG_CMD_FPGA_LOAD_SECURE)
-	else if (!strcmp("loads", opstr))
-		op = FPGA_LOADS;
+	U_BOOT_CMD_MKENT(loads, 6, 1, do_fpga_loads, "", ""),
 #endif
+};
+
+static int do_fpga_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	cmd_tbl_t *fpga_cmd;
+	int ret;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	fpga_cmd = find_cmd_tbl(argv[1], fpga_commands,
+				ARRAY_SIZE(fpga_commands));
+	if (!fpga_cmd) {
+		debug("fpga: non existing command\n");
+		return CMD_RET_USAGE;
+	}
+
+	argc -= 2;
+	argv += 2;
+
+	if (argc > fpga_cmd->maxargs) {
+		debug("fpga: more parameters passed\n");
+		return CMD_RET_USAGE;
+	}
 
-	if (op == FPGA_NONE)
-		printf("Unknown fpga operation \"%s\"\n", opstr);
+	ret = fpga_cmd->cmd(fpga_cmd, flag, argc, argv);
 
-	return op;
+	return cmd_process_error(fpga_cmd, ret);
 }
 
 #if defined(CONFIG_CMD_FPGA_LOADFS) || defined(CONFIG_CMD_FPGA_LOAD_SECURE)
-U_BOOT_CMD(fpga, 9, 1, do_fpga,
+U_BOOT_CMD(fpga, 9, 1, do_fpga_wrapper,
 #else
-U_BOOT_CMD(fpga, 6, 1, do_fpga,
+U_BOOT_CMD(fpga, 6, 1, do_fpga_wrapper,
 #endif
 	   "loadable FPGA image support",
 	   "[operation type] [device number] [image address] [image size]\n"

+ 8 - 8
drivers/fpga/Kconfig

@@ -46,15 +46,15 @@ config FPGA_ZYNQMPPL
 	  on Xilinx Zynq UltraScale+ (ZynqMP) device.
 
 config FPGA_SPARTAN3
-       bool "Enable Spartan3 FPGA driver"
-       help
-         Enable Spartan3 FPGA driver for loading in BIT format.
+	bool "Enable Spartan3 FPGA driver"
+	help
+	  Enable Spartan3 FPGA driver for loading in BIT format.
 
 config FPGA_ZYNQPL
-       bool "Enable Xilinx FPGA for Zynq"
-       depends on ARCH_ZYNQ
-       help
-         Enable FPGA driver for loading bitstream in BIT and BIN format
-         on Xilinx Zynq devices.
+	bool "Enable Xilinx FPGA for Zynq"
+	depends on ARCH_ZYNQ
+	help
+	  Enable FPGA driver for loading bitstream in BIT and BIN format
+	  on Xilinx Zynq devices.
 
 endmenu

+ 552 - 0
test/py/tests/test_fpga.py

@@ -0,0 +1,552 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2018, Xilinx Inc.
+#
+# Michal Simek
+# Siva Durga Prasad Paladugu
+
+import pytest
+import re
+import random
+import u_boot_utils
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+the network available and files to be used for testing. Without this, this test
+will be automatically skipped.
+
+For example:
+
+# True if a DHCP server is attached to the network, and should be tested.
+env__net_dhcp_server = True
+
+# A list of environment variables that should be set in order to configure a
+# static IP. In this test case we atleast need serverip for performing tftpb
+# to get required files.
+env__net_static_env_vars = [
+    ("ipaddr", "10.0.0.100"),
+    ("netmask", "255.255.255.0"),
+    ("serverip", "10.0.0.1"),
+]
+
+# Details regarding the files that may be read from a TFTP server. .
+env__fpga_secure_readable_file = {
+    "fn": "auth_bhdr_ppk1_bit.bin",
+    "enckupfn": "auth_bhdr_enc_kup_load_bit.bin",
+    "addr": 0x1000000,
+    "keyaddr": 0x100000,
+    "keyfn": "key.txt",
+}
+
+env__fpga_under_test = {
+    "dev": 0,
+    "addr" : 0x1000000,
+    "bitstream_load": "compress.bin",
+    "bitstream_load_size": 1831960,
+    "bitstream_loadp": "compress_pr.bin",
+    "bitstream_loadp_size": 423352,
+    "bitstream_loadb": "compress.bit",
+    "bitstream_loadb_size": 1832086,
+    "bitstream_loadbp": "compress_pr.bit",
+    "bitstream_loadbp_size": 423491,
+    "mkimage_legacy": "download.ub",
+    "mkimage_legacy_size": 13321468,
+    "mkimage_legacy_gz": "download.gz.ub",
+    "mkimage_legacy_gz_size": 53632,
+    "mkimage_fit": "download-fit.ub",
+    "mkimage_fit_size": 13322784,
+    "loadfs": "mmc 0 compress.bin",
+    "loadfs_size": 1831960,
+    "loadfs_block_size": 0x10000,
+}
+"""
+
+import test_net
+
+def check_dev(u_boot_console):
+    f = u_boot_console.config.env.get('env__fpga_under_test', None)
+    if not f:
+        pytest.skip('No FPGA to test')
+
+    dev = f.get('dev', -1)
+    if dev < 0:
+        pytest.fail('No dev specified via env__fpga_under_test')
+
+    return dev, f
+
+def load_file_from_var(u_boot_console, name):
+    dev, f = check_dev(u_boot_console)
+
+    addr = f.get('addr', -1)
+    if addr < 0:
+        pytest.fail('No address specified via env__fpga_under_test')
+
+    test_net.test_net_dhcp(u_boot_console)
+    test_net.test_net_setup_static(u_boot_console)
+    bit = f['%s' % (name)]
+    bit_size = f['%s_size' % (name)]
+
+    expected_tftp = 'Bytes transferred = %d' % bit_size
+    output = u_boot_console.run_command('tftpboot %x %s' % (addr, bit))
+    assert expected_tftp in output
+
+    return f, dev, addr, bit, bit_size
+
+###### FPGA FAIL test ######
+expected_usage = 'fpga - loadable FPGA image support'
+
+@pytest.mark.xfail
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_fail(u_boot_console):
+    # Test non valid fpga subcommand
+    expected = 'fpga: non existing command'
+    output = u_boot_console.run_command('fpga broken 0')
+    #assert expected in output
+    assert expected_usage in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_help(u_boot_console):
+    # Just show help
+    output = u_boot_console.run_command('fpga')
+    assert expected_usage in output
+
+
+###### FPGA DUMP tests ######
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_dump(u_boot_console):
+    pytest.skip('Not implemented now')
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_dump_variable(u_boot_console):
+    # Same as above but via "fpga" variable
+    pytest.skip('Not implemented now')
+
+###### FPGA INFO tests ######
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_info_fail(u_boot_console):
+    # Maybe this can be skipped completely
+    dev, f = check_dev(u_boot_console)
+
+    # Multiple parameters to fpga info should fail
+    expected = 'fpga: more parameters passed'
+    output = u_boot_console.run_command('fpga info 0 0')
+    #assert expected in output
+    assert expected_usage in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_info_list(u_boot_console):
+    # Maybe this can be skipped completely
+    dev, f = check_dev(u_boot_console)
+
+    # Code is design in a way that if fpga dev is not passed it should
+    # return list of all fpga devices in the system
+    u_boot_console.run_command('setenv fpga')
+    output = u_boot_console.run_command('fpga info')
+    assert expected_usage not in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_info(u_boot_console):
+    dev, f = check_dev(u_boot_console)
+
+    output = u_boot_console.run_command('fpga info %x' % (dev))
+    assert expected_usage not in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_info_variable(u_boot_console):
+    dev, f = check_dev(u_boot_console)
+
+    #
+    # fpga variable is storing device number which doesn't need to be passed
+    #
+    u_boot_console.run_command('setenv fpga %x' % (dev))
+
+    output = u_boot_console.run_command('fpga info')
+    # Variable cleanup
+    u_boot_console.run_command('setenv fpga')
+    assert expected_usage not in output
+
+###### FPGA LOAD tests ######
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_load_fail(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_load')
+
+    for cmd in ['dump', 'load', 'loadb']:
+	# missing dev parameter
+	expected = 'fpga: incorrect parameters passed'
+	output = u_boot_console.run_command('fpga %s %x $filesize' % (cmd, addr))
+	#assert expected in output
+	assert expected_usage in output
+
+	# more parameters - 0 at the end
+	expected = 'fpga: more parameters passed'
+	output = u_boot_console.run_command('fpga %s %x %x $filesize 0' % (cmd, dev, addr))
+	#assert expected in output
+	assert expected_usage in output
+
+	# 0 address
+	expected = 'fpga: zero fpga_data address'
+	output = u_boot_console.run_command('fpga %s %x 0 $filesize' % (cmd, dev))
+	#assert expected in output
+	assert expected_usage in output
+
+	# 0 filesize
+	expected = 'fpga: zero size'
+	output = u_boot_console.run_command('fpga %s %x %x 0' % (cmd, dev, addr))
+	#assert expected in output
+	assert expected_usage in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_load(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_load')
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga load %x %x $filesize && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadp')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadp(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_load')
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga load %x %x $filesize && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+    # And load also partial bistream
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_loadp')
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadp %x %x $filesize && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadb(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_loadb')
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadb %x %x $filesize && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadbp')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadbp(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_loadb')
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadb %x %x $filesize && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+    # And load also partial bistream in bit format
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_loadbp')
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadbp %x %x $filesize && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+###### FPGA LOADMK tests ######
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('cmd_echo')
+@pytest.mark.buildconfigspec('image_format_legacy')
+def test_fpga_loadmk_fail(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_legacy')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    # load image but pass incorrect address to show error message
+    expected = 'Unknown image type'
+    output = u_boot_console.run_command('fpga loadmk %x %x' % (dev, addr + 0x10))
+    assert expected in output
+
+    # Pass more parameters then command expects - 0 at the end
+    output = u_boot_console.run_command('fpga loadmk %x %x 0' % (dev, addr))
+    #assert expected in output
+    assert expected_usage in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('cmd_echo')
+@pytest.mark.buildconfigspec('image_format_legacy')
+def test_fpga_loadmk_legacy(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_legacy')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk %x %x && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+@pytest.mark.xfail
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('cmd_echo')
+@pytest.mark.buildconfigspec('image_format_legacy')
+def test_fpga_loadmk_legacy_variable_fpga(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_legacy')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    u_boot_console.run_command('setenv fpga %x' % (dev))
+
+    # this testcase should cover case which looks like it is supported but dev pointer is broken by loading mkimage address
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk %x && echo %s' % (addr, expected_text))
+    u_boot_console.run_command('setenv fpga')
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('cmd_echo')
+@pytest.mark.buildconfigspec('image_format_legacy')
+def test_fpga_loadmk_legacy_variable_fpgadata(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_legacy')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    u_boot_console.run_command('setenv fpgadata %x' % (addr))
+
+    # this testcase should cover case which looks like it is supported but dev pointer is broken by loading mkimage address
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk %x && echo %s' % (dev, expected_text))
+    u_boot_console.run_command('setenv fpgadata')
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('cmd_echo')
+@pytest.mark.buildconfigspec('image_format_legacy')
+def test_fpga_loadmk_legacy_variable(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_legacy')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    u_boot_console.run_command('setenv fpga %x' % (dev))
+    u_boot_console.run_command('setenv fpgadata %x' % (addr))
+
+    # this testcase should cover case which looks like it is supported but dev pointer is broken by loading mkimage address
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk && echo %s' % (expected_text))
+    u_boot_console.run_command('setenv fpga')
+    u_boot_console.run_command('setenv fpgadata')
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('cmd_echo')
+@pytest.mark.buildconfigspec('image_format_legacy')
+@pytest.mark.buildconfigspec('gzip')
+def test_fpga_loadmk_legacy_gz(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_legacy_gz')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk %x %x && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('fit')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadmk_fit(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_fit')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk %x %x:fpga && echo %s' % (dev, addr, expected_text))
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('fit')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadmk_fit_variable_fpga(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_fit')
+
+    u_boot_console.run_command('imi %x' % (addr))
+    # FIXME this should fail - broken support in past
+    u_boot_console.run_command('setenv fpga %x' % (dev))
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk %x:fpga && echo %s' % (addr, expected_text))
+    u_boot_console.run_command('setenv fpga')
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('fit')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadmk_fit_variable_fpgadata(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_fit')
+
+    u_boot_console.run_command('imi %x' % (addr))
+    # FIXME this should fail - broken support in past
+    u_boot_console.run_command('setenv fpgadata %x:fpga' % (addr))
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk %x && echo %s' % (dev, expected_text))
+    u_boot_console.run_command('setenv fpgadata')
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_loadmk')
+@pytest.mark.buildconfigspec('fit')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadmk_fit_variable(u_boot_console):
+    f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'mkimage_fit')
+
+    u_boot_console.run_command('imi %x' % (addr))
+
+    u_boot_console.run_command('setenv fpga %x' % (dev))
+    u_boot_console.run_command('setenv fpgadata %x:fpga' % (addr))
+
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadmk && echo %s' % (expected_text))
+    u_boot_console.run_command('setenv fpga')
+    u_boot_console.run_command('setenv fpgadata')
+    assert expected_text in output
+
+###### FPGA LOAD tests ######
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+def test_fpga_loadfs_fail(u_boot_console):
+    dev, f = check_dev(u_boot_console)
+
+    addr = f.get('addr', -1)
+    if addr < 0:
+        pytest.fail('No address specified via env__fpga_under_test')
+
+    bit = f['loadfs']
+    bit_size = f['loadfs_size']
+    block_size = f['loadfs_block_size']
+
+    # less params - dev number removed
+    expected = 'fpga: incorrect parameters passed'
+    output = u_boot_console.run_command('fpga loadfs %x %x %x %s' % (addr, bit_size, block_size, bit))
+    #assert expected in output
+    assert expected_usage in output
+
+    # one more param - 0 at the end
+    # This is the longest command that's why there is no message from cmd/fpga.c
+    output = u_boot_console.run_command('fpga loadfs %x %x %x %x %s 0' % (dev, addr, bit_size, block_size, bit))
+    assert expected_usage in output
+
+    # zero address 0
+    expected = 'fpga: zero fpga_data address'
+    output = u_boot_console.run_command('fpga loadfs %x %x %x %x %s' % (dev, 0, bit_size, block_size, bit))
+    #assert expected in output
+    assert expected_usage in output
+
+    # bit_size 0
+    expected = 'fpga: zero size'
+    output = u_boot_console.run_command('fpga loadfs %x %x %x %x %s' % (dev, addr, 0, block_size, bit))
+    #assert expected in output
+    assert expected_usage in output
+
+    # block size 0
+    # FIXME this should pass but it failing too
+    output = u_boot_console.run_command('fpga loadfs %x %x %x %x %s' % (dev, addr, bit_size, 0, bit))
+    assert expected_usage in output
+
+    # non existing bitstream name
+    expected = 'Unable to read file noname'
+    output = u_boot_console.run_command('fpga loadfs %x %x %x %x mmc 0 noname' % (dev, addr, bit_size, block_size))
+    assert expected in output
+    assert expected_usage in output
+
+    # -1 dev number
+    expected = 'fpga_fsload: Invalid device number -1'
+    output = u_boot_console.run_command('fpga loadfs %d %x %x %x mmc 0 noname' % (-1, addr, bit_size, block_size))
+    assert expected in output
+    assert expected_usage in output
+
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_echo')
+def test_fpga_loadfs(u_boot_console):
+    dev, f = check_dev(u_boot_console)
+
+    addr = f.get('addr', -1)
+    if addr < 0:
+        pytest.fail('No address specified via env__fpga_under_test')
+
+    bit = f['loadfs']
+    bit_size = f['loadfs_size']
+    block_size = f['loadfs_block_size']
+
+    # This should be done better
+    expected_text = 'FPGA loaded successfully'
+    output = u_boot_console.run_command('fpga loadfs %x %x %x %x %s && echo %s' % (dev, addr, bit_size, block_size, bit, expected_text))
+    assert expected_text in output
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_load_secure')
+@pytest.mark.buildconfigspec('cmd_net')
+@pytest.mark.buildconfigspec('cmd_dhcp')
+@pytest.mark.buildconfigspec('net')
+def test_fpga_secure_bit_auth(u_boot_console):
+
+    test_net.test_net_dhcp(u_boot_console)
+    test_net.test_net_setup_static(u_boot_console)
+
+    f = u_boot_console.config.env.get('env__fpga_secure_readable_file', None)
+    if not f:
+        pytest.skip('No TFTP readable file to read')
+
+    addr = f.get('addr', None)
+    if not addr:
+      addr = u_boot_utils.find_ram_base(u_boot_console)
+
+    expected_tftp = 'Bytes transferred = '
+    fn = f['fn']
+    output = u_boot_console.run_command('tftpboot %x %s' % (addr, fn))
+    assert expected_tftp in output
+
+    expected_zynqmpsecure = 'Bitstream successfully loaded'
+    output = u_boot_console.run_command('fpga loads 0 %x $filesize 0 2' % (addr))
+    assert expected_zynqmpsecure in output
+
+
+@pytest.mark.buildconfigspec('cmd_fpga')
+@pytest.mark.buildconfigspec('cmd_fpga_load_secure')
+@pytest.mark.buildconfigspec('cmd_net')
+@pytest.mark.buildconfigspec('cmd_dhcp')
+@pytest.mark.buildconfigspec('net')
+def test_fpga_secure_bit_img_auth_kup(u_boot_console):
+
+    test_net.test_net_dhcp(u_boot_console)
+    test_net.test_net_setup_static(u_boot_console)
+
+    f = u_boot_console.config.env.get('env__fpga_secure_readable_file', None)
+    if not f:
+        pytest.skip('No TFTP readable file to read')
+
+    keyaddr = f.get('keyaddr', None)
+    if not keyaddr:
+      addr = u_boot_utils.find_ram_base(u_boot_console)
+    expected_tftp = 'Bytes transferred = '
+    keyfn = f['keyfn']
+    output = u_boot_console.run_command('tftpboot %x %s' % (keyaddr, keyfn))
+    assert expected_tftp in output
+
+    addr = f.get('addr', None)
+    if not addr:
+      addr = u_boot_utils.find_ram_base(u_boot_console)
+    expected_tftp = 'Bytes transferred = '
+    fn = f['enckupfn']
+    output = u_boot_console.run_command('tftpboot %x %s' % (addr, fn))
+    assert expected_tftp in output
+
+    expected_zynqmpsecure = 'Bitstream successfully loaded'
+    output = u_boot_console.run_command('fpga loads 0 %x $filesize 0 1 %x' % (addr, keyaddr))
+    assert expected_zynqmpsecure in output