test: spl: Add a test for the MMC load method

Add a test for the MMC load method. This shows the general shape of tests
to come: The main test function calls do_spl_test_load with an appropriate
callback to write the image to the medium.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
diff --git a/test/image/Kconfig b/test/image/Kconfig
index a52766b..e6be1b8 100644
--- a/test/image/Kconfig
+++ b/test/image/Kconfig
@@ -18,6 +18,7 @@
 	depends on SPL_FS_FAT
 	depends on SPL_FS_EXT4
 	depends on SPL_MMC_WRITE
+	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
 	default y
 	help
 	  Test filesystems and the various load methods which use them.
diff --git a/test/image/spl_load.c b/test/image/spl_load.c
index de2fdda..d2ce660 100644
--- a/test/image/spl_load.c
+++ b/test/image/spl_load.c
@@ -365,3 +365,39 @@
 SPL_IMG_TEST(spl_test_image, IMX8, 0);
 SPL_IMG_TEST(spl_test_image, FIT_INTERNAL, 0);
 SPL_IMG_TEST(spl_test_image, FIT_EXTERNAL, 0);
+
+int do_spl_test_load(struct unit_test_state *uts, const char *test_name,
+		     enum spl_test_image type, struct spl_image_loader *loader,
+		     int (*write_image)(struct unit_test_state *, void *, size_t))
+{
+	size_t img_size, img_data, plain_size = SPL_TEST_DATA_SIZE;
+	struct spl_image_info info_write = {
+		.name = test_name,
+		.size = plain_size,
+	}, info_read = { };
+	struct spl_boot_device bootdev = {
+		.boot_device = loader->boot_device,
+	};
+	char *plain;
+	void *img;
+
+	img_size = create_image(NULL, type, &info_write, &img_data);
+	ut_assert(img_size);
+	img = calloc(img_size, 1);
+	ut_assertnonnull(img);
+
+	plain = img + img_data;
+	generate_data(plain, plain_size, test_name);
+	ut_asserteq(img_size, create_image(img, type, &info_write, NULL));
+
+	if (write_image(uts, img, img_size))
+		return CMD_RET_FAILURE;
+
+	ut_assertok(loader->load_image(&info_read, &bootdev));
+	if (check_image_info(uts, &info_write, &info_read))
+		return CMD_RET_FAILURE;
+	ut_asserteq_mem(plain, phys_to_virt(info_write.load_addr), plain_size);
+
+	free(img);
+	return 0;
+}
diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c
index a8b45bd..297ab08 100644
--- a/test/image/spl_load_fs.c
+++ b/test/image/spl_load_fs.c
@@ -306,8 +306,16 @@
 }
 SPL_TEST(spl_test_fat, DM_FLAGS);
 
+static bool spl_mmc_raw;
+
+u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)
+{
+	return spl_mmc_raw ? MMCSD_MODE_RAW : MMCSD_MODE_FS;
+}
+
 static int spl_test_mmc_fs(struct unit_test_state *uts, const char *test_name,
-			   enum spl_test_image type, create_fs_t create_fs)
+			   enum spl_test_image type, create_fs_t create_fs,
+			   bool blk_mode)
 {
 	const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME;
 	struct blk_desc *dev_desc;
@@ -321,7 +329,11 @@
 		.start = 1,
 		.sys_ind = 0x83,
 	};
-	struct spl_boot_device bootdev = { };
+	struct spl_image_loader *loader =
+		SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_MMC1, spl_mmc_load_image);
+	struct spl_boot_device bootdev = {
+		.boot_device = loader->boot_device,
+	};
 	void *fs;
 	char *data;
 
@@ -346,7 +358,12 @@
 	ut_assertok(write_mbr_partitions(dev_desc, &part, 1, 0));
 	ut_asserteq(part.size, blk_dwrite(dev_desc, part.start, part.size, fs));
 
-	ut_assertok(spl_blk_load_image(&info_read, &bootdev, UCLASS_MMC, 0, 1));
+	spl_mmc_raw = false;
+	if (blk_mode)
+		ut_assertok(spl_blk_load_image(&info_read, &bootdev, UCLASS_MMC,
+					       0, 1));
+	else
+		ut_assertok(loader->load_image(&info_read, &bootdev));
 	if (check_image_info(uts, &info_write, &info_read))
 		return CMD_RET_FAILURE;
 	ut_asserteq_mem(data, phys_to_virt(info_write.load_addr), data_size);
@@ -359,11 +376,53 @@
 			enum spl_test_image type)
 {
 	spl_fat_force_reregister();
-	if (spl_test_mmc_fs(uts, test_name, type, create_fat))
+	if (spl_test_mmc_fs(uts, test_name, type, create_fat, true))
 		return CMD_RET_FAILURE;
 
-	return spl_test_mmc_fs(uts, test_name, type, create_ext2);
+	return spl_test_mmc_fs(uts, test_name, type, create_ext2, true);
 }
 SPL_IMG_TEST(spl_test_blk, LEGACY, DM_FLAGS);
 SPL_IMG_TEST(spl_test_blk, FIT_EXTERNAL, DM_FLAGS);
 SPL_IMG_TEST(spl_test_blk, FIT_INTERNAL, DM_FLAGS);
+
+static int spl_test_mmc_write_image(struct unit_test_state *uts, void *img,
+				    size_t img_size)
+{
+	struct blk_desc *dev_desc;
+	size_t img_blocks;
+
+	dev_desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0);
+	ut_assertnonnull(dev_desc);
+
+	img_blocks = DIV_ROUND_UP(img_size, dev_desc->blksz);
+	ut_asserteq(img_blocks, blk_dwrite(dev_desc,
+					   CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
+					   img_blocks, img));
+
+	spl_mmc_raw = true;
+	return 0;
+}
+
+static int spl_test_mmc(struct unit_test_state *uts, const char *test_name,
+			enum spl_test_image type)
+{
+	spl_mmc_clear_cache();
+	spl_fat_force_reregister();
+
+	if (type == LEGACY &&
+	    spl_test_mmc_fs(uts, test_name, type, create_ext2, false))
+		return CMD_RET_FAILURE;
+
+	if (type != IMX8 &&
+	    spl_test_mmc_fs(uts, test_name, type, create_fat, false))
+		return CMD_RET_FAILURE;
+
+	return do_spl_test_load(uts, test_name, type,
+				SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_MMC1,
+						   spl_mmc_load_image),
+				spl_test_mmc_write_image);
+}
+SPL_IMG_TEST(spl_test_mmc, LEGACY, DM_FLAGS);
+SPL_IMG_TEST(spl_test_mmc, IMX8, DM_FLAGS);
+SPL_IMG_TEST(spl_test_mmc, FIT_EXTERNAL, DM_FLAGS);
+SPL_IMG_TEST(spl_test_mmc, FIT_INTERNAL, DM_FLAGS);