Merge patch series "nand: Add sandbox tests"

To quote the author:

This series tests raw nand flash in sandbox and fixes various bugs discovered in
the process. I've tried to do things in a contemporary manner, avoiding the
(numerous) variations present on only a few boards. The test is pretty minimal.
Future work could test the rest of the nand API as well as the MTD API.

Bloat (for v1) at [1] (for boards with SPL_NAND_SUPPORT enabled). Almost
everything grows by a few bytes due to nand_page_size. A few boards grow more,
mostly those using nand_spl_loaders.c. CI at [2].

[1] https://gist.github.com/Forty-Bot/9694f3401893c9e706ccc374922de6c2
[2] https://source.denx.de/u-boot/custodians/u-boot-clk/-/pipelines/18443
diff --git a/README b/README
index 60c6b8a..00d4227 100644
--- a/README
+++ b/README
@@ -1191,11 +1191,10 @@
 		Support for a lightweight UBI (fastmap) scanner and
 		loader
 
-		CONFIG_SYS_NAND_5_ADDR_CYCLE, CONFIG_SYS_NAND_PAGE_COUNT,
-		CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE,
-		CONFIG_SYS_NAND_BLOCK_SIZE, CONFIG_SYS_NAND_BAD_BLOCK_POS,
-		CFG_SYS_NAND_ECCPOS, CFG_SYS_NAND_ECCSIZE,
-		CFG_SYS_NAND_ECCBYTES
+		CONFIG_SYS_NAND_5_ADDR_CYCLE, CONFIG_SYS_NAND_PAGE_SIZE,
+		CONFIG_SYS_NAND_OOBSIZE, CONFIG_SYS_NAND_BLOCK_SIZE,
+		CONFIG_SYS_NAND_BAD_BLOCK_POS, CFG_SYS_NAND_ECCPOS,
+		CFG_SYS_NAND_ECCSIZE, CFG_SYS_NAND_ECCBYTES
 		Defines the size and behavior of the NAND that SPL uses
 		to read U-Boot
 
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 85d0d6a..8847c4c 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -282,6 +282,23 @@
 	return 0;
 }
 
+int os_mktemp(char *fname, off_t size)
+{
+	int fd;
+
+	fd = mkostemp(fname, O_CLOEXEC);
+	if (fd < 0)
+		return -errno;
+
+	if (unlink(fname) < 0)
+		return -errno;
+
+	if (ftruncate(fd, size))
+		return -errno;
+
+	return fd;
+}
+
 /* Restore tty state when we exit */
 static struct termios orig_term;
 static bool term_setup;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 2887f6c..6fd62fc 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1913,6 +1913,71 @@
 				compatible = "sandbox,arm-ffa";
 		};
 	};
+
+	nand-controller {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "sandbox,nand";
+
+		nand@0 {
+			reg = <0>;
+			nand-ecc-mode = "soft";
+			sandbox,id = [00 e3];
+			sandbox,erasesize = <(8 * 1024)>;
+			sandbox,oobsize = <16>;
+			sandbox,pagesize = <512>;
+			sandbox,pages = <0x2000>;
+			sandbox,err-count = <1>;
+			sandbox,err-step-size = <512>;
+		};
+
+		/* MT29F64G08AKABA */
+		nand@1 {
+			reg = <1>;
+			nand-ecc-mode = "soft_bch";
+			sandbox,id = [2C 48 00 26 89 00 00 00];
+			sandbox,onfi = [
+				4f 4e 46 49 0e 00 5a 00
+				ff 01 00 00 00 00 03 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				4d 49 43 52 4f 4e 20 20
+				20 20 20 20 4d 54 32 39
+				46 36 34 47 30 38 41 4b
+				41 42 41 43 35 20 20 20
+				2c 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 10 00 00 e0 00 00 02
+				00 00 1c 00 80 00 00 00
+				00 10 00 00 02 23 01 50
+				00 01 05 01 00 00 04 00
+				04 01 1e 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				0e 1f 00 1f 00 f4 01 ac
+				0d 19 00 c8 00 00 00 00
+				00 00 00 00 00 00 0a 07
+				19 00 00 00 00 00 00 00
+				00 00 00 00 01 00 01 00
+				00 00 04 10 01 81 04 02
+				02 01 1e 90 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 00 00 00
+				00 00 00 00 00 03 20 7d
+			];
+			sandbox,erasesize = <(512 * 1024)>;
+			sandbox,oobsize = <224>;
+			sandbox,pagesize = <4096>;
+			sandbox,pages = <0x200000>;
+			sandbox,err-count = <3>;
+			sandbox,err-step-size = <512>;
+		};
+	};
 };
 
 #include "sandbox_pmic.dtsi"
diff --git a/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h
index f349ea1..4fab24c 100644
--- a/arch/sandbox/include/asm/spl.h
+++ b/arch/sandbox/include/asm/spl.h
@@ -15,6 +15,7 @@
 	BOOT_DEVICE_CPGMAC,
 	BOOT_DEVICE_NOR,
 	BOOT_DEVICE_SPI,
+	BOOT_DEVICE_NAND,
 };
 
 /**
diff --git a/cmd/nand.c b/cmd/nand.c
index 71b8f96..fe834c4 100644
--- a/cmd/nand.c
+++ b/cmd/nand.c
@@ -34,6 +34,7 @@
 #include <env.h>
 #include <watchdog.h>
 #include <malloc.h>
+#include <mapmem.h>
 #include <asm/byteorder.h>
 #include <jffs2/jffs2.h>
 #include <nand.h>
@@ -432,7 +433,7 @@
 	env_set_hex("nand_erasesize", mtd->erasesize);
 }
 
-static int raw_access(struct mtd_info *mtd, ulong addr, loff_t off,
+static int raw_access(struct mtd_info *mtd, void *buf, loff_t off,
 		      ulong count, int read, int no_verify)
 {
 	int ret = 0;
@@ -440,8 +441,8 @@
 	while (count--) {
 		/* Raw access */
 		mtd_oob_ops_t ops = {
-			.datbuf = (u8 *)addr,
-			.oobbuf = ((u8 *)addr) + mtd->writesize,
+			.datbuf = buf,
+			.oobbuf = buf + mtd->writesize,
 			.len = mtd->writesize,
 			.ooblen = mtd->oobsize,
 			.mode = MTD_OPS_RAW
@@ -461,7 +462,7 @@
 			break;
 		}
 
-		addr += mtd->writesize + mtd->oobsize;
+		buf += mtd->writesize + mtd->oobsize;
 		off += mtd->writesize;
 	}
 
@@ -675,6 +676,7 @@
 		int read;
 		int raw = 0;
 		int no_verify = 0;
+		void *buf;
 
 		if (argc < 4)
 			goto usage;
@@ -730,32 +732,32 @@
 		}
 
 		mtd = get_nand_dev_by_index(dev);
+		buf = map_sysmem(addr, maxsize);
 
 		if (!s || !strcmp(s, ".jffs2") ||
 		    !strcmp(s, ".e") || !strcmp(s, ".i")) {
 			if (read)
 				ret = nand_read_skip_bad(mtd, off, &rwsize,
-							 NULL, maxsize,
-							 (u_char *)addr);
+							 NULL, maxsize, buf);
 			else
 				ret = nand_write_skip_bad(mtd, off, &rwsize,
-							  NULL, maxsize,
-							  (u_char *)addr,
+							  NULL, maxsize, buf,
 							  WITH_WR_VERIFY);
 #ifdef CONFIG_CMD_NAND_TRIMFFS
 		} else if (!strcmp(s, ".trimffs")) {
 			if (read) {
 				printf("Unknown nand command suffix '%s'\n", s);
+				unmap_sysmem(buf);
 				return 1;
 			}
 			ret = nand_write_skip_bad(mtd, off, &rwsize, NULL,
-						maxsize, (u_char *)addr,
+						maxsize, buf,
 						WITH_DROP_FFS | WITH_WR_VERIFY);
 #endif
 		} else if (!strcmp(s, ".oob")) {
 			/* out-of-band data */
 			mtd_oob_ops_t ops = {
-				.oobbuf = (u8 *)addr,
+				.oobbuf = buf,
 				.ooblen = rwsize,
 				.mode = MTD_OPS_RAW
 			};
@@ -765,13 +767,15 @@
 			else
 				ret = mtd_write_oob(mtd, off, &ops);
 		} else if (raw) {
-			ret = raw_access(mtd, addr, off, pagecount, read,
+			ret = raw_access(mtd, buf, off, pagecount, read,
 					 no_verify);
 		} else {
 			printf("Unknown nand command suffix '%s'.\n", s);
+			unmap_sysmem(buf);
 			return 1;
 		}
 
+		unmap_sysmem(buf);
 		printf(" %zu bytes %s: %s\n", rwsize,
 		       read ? "read" : "written", ret ? "ERROR" : "OK");
 
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 25cd18a..00332cf 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -857,7 +857,7 @@
 	  allows DRAM to be set up before loading U-Boot into that DRAM,
 	  where it can run.
 
-config SPL_MTD_SUPPORT
+config SPL_MTD
 	bool "Support MTD drivers"
 	help
 	  Enable support for MTD (Memory Technology Device) within SPL. MTD
diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c
index 51656fb..9189576 100644
--- a/common/spl/spl_legacy.c
+++ b/common/spl/spl_legacy.c
@@ -133,25 +133,31 @@
 			   map_sysmem(spl_image->load_addr, spl_image->size));
 		break;
 
-	case IH_COMP_LZMA:
+	case IH_COMP_LZMA: {
+		ulong overhead, size;
+
 		lzma_len = LZMA_LEN;
 
 		/* dataptr points to compressed payload  */
-		dataptr = offset + sizeof(*hdr);
+		dataptr = ALIGN_DOWN(sizeof(*hdr), load->bl_len);
+		overhead = sizeof(*hdr) - dataptr;
+		size = ALIGN(spl_image->size + overhead, load->bl_len);
+		dataptr += offset;
 
 		debug("LZMA: Decompressing %08lx to %08lx\n",
 		      dataptr, spl_image->load_addr);
-		src = malloc(spl_image->size);
+		src = malloc(size);
 		if (!src) {
 			printf("Unable to allocate %d bytes for LZMA\n",
 			       spl_image->size);
 			return -ENOMEM;
 		}
 
-		load->read(load, dataptr, spl_image->size, src);
+		load->read(load, dataptr, size, src);
 		ret = lzmaBuffToBuffDecompress(map_sysmem(spl_image->load_addr,
 							  spl_image->size),
-					       &lzma_len, src, spl_image->size);
+					       &lzma_len, src + overhead,
+					       spl_image->size);
 		if (ret) {
 			printf("LZMA decompression error: %d\n", ret);
 			return ret;
@@ -159,7 +165,7 @@
 
 		spl_image->size = lzma_len;
 		break;
-
+	}
 	default:
 		debug("Compression method %s is not supported\n",
 		      genimg_get_comp_short_name(image_get_comp(hdr)));
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c
index 07916be..b8cd640 100644
--- a/common/spl/spl_nand.c
+++ b/common/spl/spl_nand.c
@@ -11,6 +11,7 @@
 #include <log.h>
 #include <spl.h>
 #include <asm/io.h>
+#include <mapmem.h>
 #include <nand.h>
 #include <linux/libfdt_env.h>
 #include <fdt.h>
@@ -32,7 +33,8 @@
 
 	nand_spl_load_image(spl_nand_get_uboot_raw_page(),
 			    CFG_SYS_NAND_U_BOOT_SIZE,
-			    (void *)CFG_SYS_NAND_U_BOOT_DST);
+			    map_sysmem(CFG_SYS_NAND_U_BOOT_DST,
+				       CFG_SYS_NAND_U_BOOT_SIZE));
 	spl_set_header_raw_uboot(spl_image);
 	nand_deselect();
 
@@ -72,23 +74,18 @@
 	return size;
 }
 
-struct mtd_info * __weak nand_get_mtd(void)
-{
-	return NULL;
-}
-
 static int spl_nand_load_element(struct spl_image_info *spl_image,
 				 struct spl_boot_device *bootdev,
 				 int offset, struct legacy_img_hdr *header)
 {
-	struct mtd_info *mtd = nand_get_mtd();
-	int bl_len = mtd ? mtd->writesize : 1;
+	int bl_len;
 	int err;
 
 	err = nand_spl_load_image(offset, sizeof(*header), (void *)header);
 	if (err)
 		return err;
 
+	bl_len = nand_page_size();
 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
 	    image_get_magic(header) == FDT_MAGIC) {
 		struct spl_load_info load;
@@ -105,7 +102,7 @@
 		struct spl_load_info load;
 
 		load.dev = NULL;
-		load.priv = NULL;
+		load.priv = &offset;
 		load.filename = NULL;
 		load.bl_len = bl_len;
 		load.read = spl_nand_fit_read;
@@ -118,7 +115,7 @@
 		load.dev = NULL;
 		load.priv = NULL;
 		load.filename = NULL;
-		load.bl_len = 1;
+		load.bl_len = IS_ENABLED(CONFIG_SPL_LZMA) ? bl_len : 1;
 		load.read = spl_nand_legacy_read;
 
 		return spl_load_legacy_img(spl_image, bootdev, &load, offset, header);
@@ -127,7 +124,8 @@
 		if (err)
 			return err;
 		return nand_spl_load_image(offset, spl_image->size,
-					   (void *)(ulong)spl_image->load_addr);
+					   map_sysmem(spl_image->load_addr,
+						      spl_image->size));
 	}
 }
 
diff --git a/configs/am335x_baltos_defconfig b/configs/am335x_baltos_defconfig
index 16993ef..0599ae2 100644
--- a/configs/am335x_baltos_defconfig
+++ b/configs/am335x_baltos_defconfig
@@ -22,7 +22,7 @@
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -67,7 +67,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig
index f048e60..5d38dad 100644
--- a/configs/am335x_evm_defconfig
+++ b/configs/am335x_evm_defconfig
@@ -26,7 +26,7 @@
 CONFIG_SPL_ETH=y
 # CONFIG_SPL_FS_EXT4 is not set
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_MUSB_NEW=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
@@ -84,7 +84,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/am335x_evm_spiboot_defconfig b/configs/am335x_evm_spiboot_defconfig
index 9866246..b5b11fb 100644
--- a/configs/am335x_evm_spiboot_defconfig
+++ b/configs/am335x_evm_spiboot_defconfig
@@ -28,7 +28,7 @@
 CONFIG_SPL_FIT_IMAGE_TINY=y
 # CONFIG_SPL_FS_EXT4 is not set
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 # CONFIG_SPL_NAND_SUPPORT is not set
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_SPI_LOAD=y
diff --git a/configs/am335x_guardian_defconfig b/configs/am335x_guardian_defconfig
index 01d848c..5369e46 100644
--- a/configs/am335x_guardian_defconfig
+++ b/configs/am335x_guardian_defconfig
@@ -99,7 +99,6 @@
 CONFIG_NAND_OMAP_ECCSCHEME_BCH16_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x40000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0x100
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/am335x_hs_evm_defconfig b/configs/am335x_hs_evm_defconfig
index b961b6c..ea46e58 100644
--- a/configs/am335x_hs_evm_defconfig
+++ b/configs/am335x_hs_evm_defconfig
@@ -27,7 +27,7 @@
 # CONFIG_SPL_ENV_SUPPORT is not set
 # CONFIG_SPL_FS_EXT4 is not set
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 # CONFIG_SPL_NAND_SUPPORT is not set
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
diff --git a/configs/am335x_hs_evm_uart_defconfig b/configs/am335x_hs_evm_uart_defconfig
index b5d8eac..7886557 100644
--- a/configs/am335x_hs_evm_uart_defconfig
+++ b/configs/am335x_hs_evm_uart_defconfig
@@ -29,7 +29,7 @@
 CONFIG_SPL_FIT_IMAGE_TINY=y
 # CONFIG_SPL_ENV_SUPPORT is not set
 # CONFIG_SPL_FS_EXT4 is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 # CONFIG_SPL_NAND_SUPPORT is not set
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
diff --git a/configs/am335x_igep003x_defconfig b/configs/am335x_igep003x_defconfig
index 4dd6366..e2c5b70 100644
--- a/configs/am335x_igep003x_defconfig
+++ b/configs/am335x_igep003x_defconfig
@@ -24,7 +24,7 @@
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -85,7 +85,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_MTD_UBI_FASTMAP=y
diff --git a/configs/am335x_sl50_defconfig b/configs/am335x_sl50_defconfig
index 9ba376f..fb61dd7 100644
--- a/configs/am335x_sl50_defconfig
+++ b/configs/am335x_sl50_defconfig
@@ -28,7 +28,7 @@
 CONFIG_SPL_ENV_SUPPORT=y
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 # CONFIG_SPL_NAND_SUPPORT is not set
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
diff --git a/configs/am3517_evm_defconfig b/configs/am3517_evm_defconfig
index 0a83ac9..a96936c 100644
--- a/configs/am3517_evm_defconfig
+++ b/configs/am3517_evm_defconfig
@@ -26,7 +26,7 @@
 # CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
 # CONFIG_SPL_FS_EXT4 is not set
 # CONFIG_SPL_I2C is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -75,7 +75,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_BCH8_CODE_HW_DETECTION_SW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/am43xx_evm_defconfig b/configs/am43xx_evm_defconfig
index 6571afd..d5ce299 100644
--- a/configs/am43xx_evm_defconfig
+++ b/configs/am43xx_evm_defconfig
@@ -22,7 +22,7 @@
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_ETH=y
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -72,7 +72,6 @@
 CONFIG_NAND_OMAP_ECCSCHEME_BCH16_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x40000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0xe0
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/am43xx_evm_rtconly_defconfig b/configs/am43xx_evm_rtconly_defconfig
index e84aed4..a0a9e8a 100644
--- a/configs/am43xx_evm_rtconly_defconfig
+++ b/configs/am43xx_evm_rtconly_defconfig
@@ -21,7 +21,7 @@
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -62,7 +62,6 @@
 CONFIG_NAND_OMAP_ECCSCHEME_BCH16_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x40000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0xe0
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/am43xx_evm_usbhost_boot_defconfig b/configs/am43xx_evm_usbhost_boot_defconfig
index 0cae324..cd47806 100644
--- a/configs/am43xx_evm_usbhost_boot_defconfig
+++ b/configs/am43xx_evm_usbhost_boot_defconfig
@@ -20,7 +20,7 @@
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -75,7 +75,6 @@
 CONFIG_NAND_OMAP_ECCSCHEME_BCH16_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x40000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0xe0
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/am43xx_hs_evm_defconfig b/configs/am43xx_hs_evm_defconfig
index 370ee96..d721664 100644
--- a/configs/am43xx_hs_evm_defconfig
+++ b/configs/am43xx_hs_evm_defconfig
@@ -28,7 +28,7 @@
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_ETH=y
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -68,7 +68,6 @@
 CONFIG_NAND_OMAP_ECCSCHEME_BCH16_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x40000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0xe0
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/am62ax_evm_r5_defconfig b/configs/am62ax_evm_r5_defconfig
index d52de8b..4070415 100644
--- a/configs/am62ax_evm_r5_defconfig
+++ b/configs/am62ax_evm_r5_defconfig
@@ -43,7 +43,7 @@
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400
 CONFIG_SPL_DMA=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index f436986..55289b9 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -52,7 +52,7 @@
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
diff --git a/configs/axm_defconfig b/configs/axm_defconfig
index f9c0214..e1a01b2 100644
--- a/configs/axm_defconfig
+++ b/configs/axm_defconfig
@@ -86,7 +86,6 @@
 # CONFIG_SYS_NAND_USE_FLASH_BBT is not set
 CONFIG_NAND_ATMEL=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/chiliboard_defconfig b/configs/chiliboard_defconfig
index 06642d2..0cd649d 100644
--- a/configs/chiliboard_defconfig
+++ b/configs/chiliboard_defconfig
@@ -63,7 +63,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/cm_t43_defconfig b/configs/cm_t43_defconfig
index 73ccefd..1a558b0 100644
--- a/configs/cm_t43_defconfig
+++ b/configs/cm_t43_defconfig
@@ -37,7 +37,7 @@
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x480
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 # CONFIG_SPL_NAND_SUPPORT is not set
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
diff --git a/configs/corvus_defconfig b/configs/corvus_defconfig
index ecf61f0..5eaa6db 100644
--- a/configs/corvus_defconfig
+++ b/configs/corvus_defconfig
@@ -81,7 +81,6 @@
 # CONFIG_SYS_NAND_USE_FLASH_BBT is not set
 CONFIG_NAND_ATMEL=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/da850evm_nand_defconfig b/configs/da850evm_nand_defconfig
index 5f6f5d7..62b8edd 100644
--- a/configs/da850evm_nand_defconfig
+++ b/configs/da850evm_nand_defconfig
@@ -88,7 +88,6 @@
 CONFIG_SYS_NAND_USE_FLASH_BBT=y
 CONFIG_NAND_DAVINCI=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/devkit3250_defconfig b/configs/devkit3250_defconfig
index ec4031d..569b156 100644
--- a/configs/devkit3250_defconfig
+++ b/configs/devkit3250_defconfig
@@ -73,7 +73,6 @@
 CONFIG_SYS_NAND_USE_FLASH_BBT=y
 CONFIG_NAND_LPC32XX_SLC=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 # CONFIG_SYS_NAND_5_ADDR_CYCLE is not set
diff --git a/configs/devkit8000_defconfig b/configs/devkit8000_defconfig
index ef16da1..a7f8244 100644
--- a/configs/devkit8000_defconfig
+++ b/configs/devkit8000_defconfig
@@ -77,7 +77,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_HAM1_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/dra7xx_evm_defconfig b/configs/dra7xx_evm_defconfig
index 19ca89f..c3a3ec2 100644
--- a/configs/dra7xx_evm_defconfig
+++ b/configs/dra7xx_evm_defconfig
@@ -104,7 +104,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/draco_defconfig b/configs/draco_defconfig
index ee19920..2a82087 100644
--- a/configs/draco_defconfig
+++ b/configs/draco_defconfig
@@ -100,7 +100,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/etamin_defconfig b/configs/etamin_defconfig
index c0ce7a3..4ac0abc 100644
--- a/configs/etamin_defconfig
+++ b/configs/etamin_defconfig
@@ -104,7 +104,6 @@
 CONFIG_NAND_OMAP_ECCSCHEME_BCH16_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x80000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x80
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0xe0
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/gardena-smart-gateway-at91sam_defconfig b/configs/gardena-smart-gateway-at91sam_defconfig
index 439fcc0..0fb92ff 100644
--- a/configs/gardena-smart-gateway-at91sam_defconfig
+++ b/configs/gardena-smart-gateway-at91sam_defconfig
@@ -99,7 +99,6 @@
 CONFIG_NAND_ATMEL=y
 CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/igep00x0_defconfig b/configs/igep00x0_defconfig
index 993bbe2..34439cf 100644
--- a/configs/igep00x0_defconfig
+++ b/configs/igep00x0_defconfig
@@ -24,7 +24,7 @@
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 # CONFIG_SPL_FS_EXT4 is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -78,7 +78,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_BCH8_CODE_HW_DETECTION_SW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/imx6ulz_smm_m2_defconfig b/configs/imx6ulz_smm_m2_defconfig
index d6edc71..c471e04 100644
--- a/configs/imx6ulz_smm_m2_defconfig
+++ b/configs/imx6ulz_smm_m2_defconfig
@@ -25,7 +25,7 @@
 CONFIG_SPL_BSS_START_ADDR=0x84100000
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_DMA=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_SUPPORT=y
 CONFIG_SPL_WATCHDOG=y
 CONFIG_CMD_DM=y
diff --git a/configs/imx8mn_bsh_smm_s2_defconfig b/configs/imx8mn_bsh_smm_s2_defconfig
index 657eb35..a9c0297 100644
--- a/configs/imx8mn_bsh_smm_s2_defconfig
+++ b/configs/imx8mn_bsh_smm_s2_defconfig
@@ -43,7 +43,7 @@
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x300
 CONFIG_SPL_DMA=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_SUPPORT=y
 CONFIG_SPL_NAND_BASE=y
 CONFIG_SPL_NAND_IDENT=y
diff --git a/configs/j7200_evm_a72_defconfig b/configs/j7200_evm_a72_defconfig
index cb4a141..01f1957 100644
--- a/configs/j7200_evm_a72_defconfig
+++ b/configs/j7200_evm_a72_defconfig
@@ -50,7 +50,7 @@
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_NOR_SUPPORT=y
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/j7200_evm_r5_defconfig b/configs/j7200_evm_r5_defconfig
index d25dd81..10b7205 100644
--- a/configs/j7200_evm_r5_defconfig
+++ b/configs/j7200_evm_r5_defconfig
@@ -48,7 +48,7 @@
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_NOR_SUPPORT=y
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig
index 99e0e16..1d043f2 100644
--- a/configs/j721e_evm_a72_defconfig
+++ b/configs/j721e_evm_a72_defconfig
@@ -50,7 +50,7 @@
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_NOR_SUPPORT=y
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/j721e_evm_r5_defconfig b/configs/j721e_evm_r5_defconfig
index e76ab59..55169bb 100644
--- a/configs/j721e_evm_r5_defconfig
+++ b/configs/j721e_evm_r5_defconfig
@@ -53,7 +53,7 @@
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_NOR_SUPPORT=y
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/j721s2_evm_a72_defconfig b/configs/j721s2_evm_a72_defconfig
index 876f078..a7adb92 100644
--- a/configs/j721s2_evm_a72_defconfig
+++ b/configs/j721s2_evm_a72_defconfig
@@ -49,7 +49,7 @@
 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME="u-boot.img"
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_NOR_SUPPORT=y
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/j721s2_evm_r5_defconfig b/configs/j721s2_evm_r5_defconfig
index 4990e27..c0fdd86 100644
--- a/configs/j721s2_evm_r5_defconfig
+++ b/configs/j721s2_evm_r5_defconfig
@@ -55,7 +55,7 @@
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_MAILBOX=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_NOR_SUPPORT=y
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/m53menlo_defconfig b/configs/m53menlo_defconfig
index ef9e15d..e1ddc0a 100644
--- a/configs/m53menlo_defconfig
+++ b/configs/m53menlo_defconfig
@@ -90,7 +90,6 @@
 CONFIG_NAND_MXC=y
 CONFIG_MXC_NAND_HWECC=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/omap35_logic_defconfig b/configs/omap35_logic_defconfig
index 539b0cf..5040af0 100644
--- a/configs/omap35_logic_defconfig
+++ b/configs/omap35_logic_defconfig
@@ -30,7 +30,7 @@
 # CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
 # CONFIG_SPL_FS_EXT4 is not set
 # CONFIG_SPL_I2C is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -74,7 +74,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_BCH8_CODE_HW_DETECTION_SW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/omap35_logic_somlv_defconfig b/configs/omap35_logic_somlv_defconfig
index f14ce3d..1ea35c7 100644
--- a/configs/omap35_logic_somlv_defconfig
+++ b/configs/omap35_logic_somlv_defconfig
@@ -31,7 +31,7 @@
 # CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
 # CONFIG_SPL_FS_EXT4 is not set
 # CONFIG_SPL_I2C is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -83,7 +83,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_BCH8_CODE_HW_DETECTION_SW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/omap3_beagle_defconfig b/configs/omap3_beagle_defconfig
index cabd365..c8c9ae0 100644
--- a/configs/omap3_beagle_defconfig
+++ b/configs/omap3_beagle_defconfig
@@ -22,7 +22,7 @@
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 # CONFIG_SPL_FS_EXT4 is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -83,7 +83,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_HAM1_CODE_HW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/omap3_evm_defconfig b/configs/omap3_evm_defconfig
index 33ff39f..93427f3 100644
--- a/configs/omap3_evm_defconfig
+++ b/configs/omap3_evm_defconfig
@@ -22,7 +22,7 @@
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 # CONFIG_SPL_FS_EXT4 is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -74,7 +74,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_BCH8_CODE_HW_DETECTION_SW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/omap3_logic_defconfig b/configs/omap3_logic_defconfig
index 7d3d602..729586b 100644
--- a/configs/omap3_logic_defconfig
+++ b/configs/omap3_logic_defconfig
@@ -29,7 +29,7 @@
 # CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
 # CONFIG_SPL_FS_EXT4 is not set
 # CONFIG_SPL_I2C is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -73,7 +73,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_BCH8_CODE_HW_DETECTION_SW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/omap3_logic_somlv_defconfig b/configs/omap3_logic_somlv_defconfig
index 0141a42..f0f326d 100644
--- a/configs/omap3_logic_somlv_defconfig
+++ b/configs/omap3_logic_somlv_defconfig
@@ -31,7 +31,7 @@
 # CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
 # CONFIG_SPL_FS_EXT4 is not set
 # CONFIG_SPL_I2C is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_SIMPLE=y
@@ -84,7 +84,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_NAND_OMAP_ECCSCHEME_BCH8_CODE_HW_DETECTION_SW=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/omapl138_lcdk_defconfig b/configs/omapl138_lcdk_defconfig
index 47feff2..63554d5 100644
--- a/configs/omapl138_lcdk_defconfig
+++ b/configs/omapl138_lcdk_defconfig
@@ -84,7 +84,6 @@
 CONFIG_SYS_NAND_USE_FLASH_BBT=y
 CONFIG_NAND_DAVINCI=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
diff --git a/configs/phycore-am335x-r2-regor_defconfig b/configs/phycore-am335x-r2-regor_defconfig
index 4bdf882..cbfe1cf 100644
--- a/configs/phycore-am335x-r2-regor_defconfig
+++ b/configs/phycore-am335x-r2-regor_defconfig
@@ -28,7 +28,7 @@
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -76,7 +76,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/phycore-am335x-r2-wega_defconfig b/configs/phycore-am335x-r2-wega_defconfig
index 7644fbe..b91b966 100644
--- a/configs/phycore-am335x-r2-wega_defconfig
+++ b/configs/phycore-am335x-r2-wega_defconfig
@@ -28,7 +28,7 @@
 CONFIG_SPL_SYS_MALLOC=y
 CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_DRIVERS=y
 CONFIG_SPL_NAND_ECC=y
 CONFIG_SPL_NAND_BASE=y
@@ -76,7 +76,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/pxm2_defconfig b/configs/pxm2_defconfig
index 2ea007d..e1d1066 100644
--- a/configs/pxm2_defconfig
+++ b/configs/pxm2_defconfig
@@ -99,7 +99,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/rastaban_defconfig b/configs/rastaban_defconfig
index 9f538a2..2149534 100644
--- a/configs/rastaban_defconfig
+++ b/configs/rastaban_defconfig
@@ -100,7 +100,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/rut_defconfig b/configs/rut_defconfig
index ccf2566..248073b 100644
--- a/configs/rut_defconfig
+++ b/configs/rut_defconfig
@@ -99,7 +99,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/sama5d3_xplained_nandflash_defconfig b/configs/sama5d3_xplained_nandflash_defconfig
index a1b6122..a0802f9 100644
--- a/configs/sama5d3_xplained_nandflash_defconfig
+++ b/configs/sama5d3_xplained_nandflash_defconfig
@@ -86,7 +86,6 @@
 CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/sama5d3xek_nandflash_defconfig b/configs/sama5d3xek_nandflash_defconfig
index 6278a6c..d96bb91 100644
--- a/configs/sama5d3xek_nandflash_defconfig
+++ b/configs/sama5d3xek_nandflash_defconfig
@@ -90,7 +90,6 @@
 CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/sama5d4_xplained_nandflash_defconfig b/configs/sama5d4_xplained_nandflash_defconfig
index d12f749..68101a1 100644
--- a/configs/sama5d4_xplained_nandflash_defconfig
+++ b/configs/sama5d4_xplained_nandflash_defconfig
@@ -84,7 +84,6 @@
 CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x40000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0xe0
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/sama5d4ek_nandflash_defconfig b/configs/sama5d4ek_nandflash_defconfig
index 27bfcdf..b8062db 100644
--- a/configs/sama5d4ek_nandflash_defconfig
+++ b/configs/sama5d4ek_nandflash_defconfig
@@ -81,7 +81,6 @@
 CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x40000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x1000
 CONFIG_SYS_NAND_OOBSIZE=0xe0
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 6e80780..e3f7f11 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -1,4 +1,5 @@
 CONFIG_TEXT_BASE=0
+CONFIG_SYS_MALLOC_LEN=0x6000000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x2000
 CONFIG_DEFAULT_DEVICE_TREE="sandbox64"
@@ -49,6 +50,7 @@
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_LOADM=y
+CONFIG_CMD_MTD=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_READ=y
@@ -166,6 +168,13 @@
 CONFIG_I2C_EEPROM=y
 CONFIG_MMC_SANDBOX=y
 CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_SYS_MAX_NAND_DEVICE=8
+CONFIG_SYS_NAND_USE_FLASH_BBT=y
+CONFIG_NAND_SANDBOX=y
+CONFIG_SYS_NAND_ONFI_DETECTION=y
+CONFIG_SYS_NAND_PAGE_SIZE=0x200
 CONFIG_SPI_FLASH_SANDBOX=y
 CONFIG_BOOTDEV_SPI_FLASH=y
 CONFIG_SPI_FLASH_ATMEL=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index e615656..b7ae1f0 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,4 +1,5 @@
 CONFIG_TEXT_BASE=0
+CONFIG_SYS_MALLOC_LEN=0x6000000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x2000
 CONFIG_DEFAULT_DEVICE_TREE="sandbox"
@@ -73,6 +74,7 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_LOADM=y
 CONFIG_CMD_LSBLK=y
+CONFIG_CMD_MTD=y
 CONFIG_CMD_MUX=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
@@ -215,6 +217,13 @@
 CONFIG_MMC_SANDBOX=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_SYS_MAX_NAND_DEVICE=8
+CONFIG_SYS_NAND_USE_FLASH_BBT=y
+CONFIG_NAND_SANDBOX=y
+CONFIG_SYS_NAND_ONFI_DETECTION=y
+CONFIG_SYS_NAND_PAGE_SIZE=0x200
 CONFIG_SPI_FLASH_SANDBOX=y
 CONFIG_BOOTDEV_SPI_FLASH=y
 CONFIG_SPI_FLASH_ATMEL=y
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig
index 1fd074b..8cfe30b 100644
--- a/configs/sandbox_noinst_defconfig
+++ b/configs/sandbox_noinst_defconfig
@@ -50,6 +50,13 @@
 CONFIG_SPL_FS_EXT4=y
 CONFIG_SPL_I2C=y
 CONFIG_SPL_MMC_WRITE=y
+CONFIG_SPL_MTD=y
+CONFIG_SPL_NAND_SUPPORT=y
+CONFIG_SPL_NAND_DRIVERS=y
+CONFIG_SPL_NAND_ECC=y
+CONFIG_SPL_NAND_SOFTECC=y
+CONFIG_SPL_NAND_BASE=y
+CONFIG_SPL_NAND_IDENT=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_NET=y
 CONFIG_SPL_NOR_SUPPORT=y
@@ -79,6 +86,7 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
+CONFIG_CMD_MTD=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_REMOTEPROC=y
@@ -179,6 +187,18 @@
 CONFIG_SPL_PWRSEQ=y
 CONFIG_FS_LOADER=y
 CONFIG_MMC_SANDBOX=y
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_SYS_MAX_NAND_DEVICE=8
+CONFIG_SYS_NAND_USE_FLASH_BBT=y
+CONFIG_NAND_SANDBOX=y
+CONFIG_SYS_NAND_BLOCK_SIZE=0x2000
+CONFIG_SYS_NAND_ONFI_DETECTION=y
+CONFIG_SYS_NAND_PAGE_SIZE=0x200
+CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
+CONFIG_SYS_NAND_U_BOOT_OFFS=0x0
 CONFIG_SPI_FLASH_SANDBOX=y
 CONFIG_SPI_FLASH_ATMEL=y
 CONFIG_SPI_FLASH_EON=y
diff --git a/configs/smartweb_defconfig b/configs/smartweb_defconfig
index 10cbccb..80d2c0f 100644
--- a/configs/smartweb_defconfig
+++ b/configs/smartweb_defconfig
@@ -84,7 +84,6 @@
 # CONFIG_SYS_NAND_USE_FLASH_BBT is not set
 CONFIG_NAND_ATMEL=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/socfpga_secu1_defconfig b/configs/socfpga_secu1_defconfig
index b8052f1..6a4106a 100644
--- a/configs/socfpga_secu1_defconfig
+++ b/configs/socfpga_secu1_defconfig
@@ -43,7 +43,7 @@
 # CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR is not set
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=0x1
 # CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE is not set
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_NAND_SUPPORT=y
 CONFIG_SYS_MAXARGS=32
 CONFIG_SYS_BOOTM_LEN=0x4000000
diff --git a/configs/stm32746g-eval_spl_defconfig b/configs/stm32746g-eval_spl_defconfig
index 3864e21..f9711be 100644
--- a/configs/stm32746g-eval_spl_defconfig
+++ b/configs/stm32746g-eval_spl_defconfig
@@ -34,7 +34,7 @@
 CONFIG_SPL_NO_BSS_LIMIT=y
 CONFIG_SPL_BOARD_INIT=y
 CONFIG_SPL_SYS_MALLOC_SIMPLE=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_XIP_SUPPORT=y
 CONFIG_SPL_PAYLOAD_ARGS_ADDR=0x80c0000
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/stm32f746-disco_spl_defconfig b/configs/stm32f746-disco_spl_defconfig
index b2a7861..a2b740c 100644
--- a/configs/stm32f746-disco_spl_defconfig
+++ b/configs/stm32f746-disco_spl_defconfig
@@ -34,7 +34,7 @@
 CONFIG_SPL_NO_BSS_LIMIT=y
 CONFIG_SPL_BOARD_INIT=y
 CONFIG_SPL_SYS_MALLOC_SIMPLE=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_XIP_SUPPORT=y
 CONFIG_SPL_PAYLOAD_ARGS_ADDR=0x80c0000
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/stm32f769-disco_spl_defconfig b/configs/stm32f769-disco_spl_defconfig
index 3462203..37d22f8 100644
--- a/configs/stm32f769-disco_spl_defconfig
+++ b/configs/stm32f769-disco_spl_defconfig
@@ -33,7 +33,7 @@
 CONFIG_SPL_NO_BSS_LIMIT=y
 CONFIG_SPL_BOARD_INIT=y
 CONFIG_SPL_SYS_MALLOC_SIMPLE=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_XIP_SUPPORT=y
 CONFIG_SPL_PAYLOAD_ARGS_ADDR=0x81c0000
 CONFIG_SPL_DM_RESET=y
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index 6df0935..be553ad 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -40,7 +40,7 @@
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3
 CONFIG_SPL_ENV_SUPPORT=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_POWER=y
 CONFIG_SPL_SPI_FLASH_MTD=y
diff --git a/configs/stm32mp15_dhcom_basic_defconfig b/configs/stm32mp15_dhcom_basic_defconfig
index b6cd0a4..3d5df30 100644
--- a/configs/stm32mp15_dhcom_basic_defconfig
+++ b/configs/stm32mp15_dhcom_basic_defconfig
@@ -47,7 +47,7 @@
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3
 CONFIG_SPL_ENV_SUPPORT=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_POWER=y
 CONFIG_SPL_RAM_SUPPORT=y
diff --git a/configs/stm32mp15_dhcor_basic_defconfig b/configs/stm32mp15_dhcor_basic_defconfig
index d1acf9c..50a8882 100644
--- a/configs/stm32mp15_dhcor_basic_defconfig
+++ b/configs/stm32mp15_dhcor_basic_defconfig
@@ -45,7 +45,7 @@
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=3
 CONFIG_SPL_ENV_SUPPORT=y
 CONFIG_SPL_I2C=y
-CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_MTD=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_POWER=y
 CONFIG_SPL_RAM_SUPPORT=y
diff --git a/configs/taurus_defconfig b/configs/taurus_defconfig
index cc57551..9be30c8 100644
--- a/configs/taurus_defconfig
+++ b/configs/taurus_defconfig
@@ -94,7 +94,6 @@
 # CONFIG_SYS_NAND_USE_FLASH_BBT is not set
 CONFIG_NAND_ATMEL=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/configs/thuban_defconfig b/configs/thuban_defconfig
index 116700e..1134624 100644
--- a/configs/thuban_defconfig
+++ b/configs/thuban_defconfig
@@ -100,7 +100,6 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_SYS_NAND_BLOCK_SIZE=0x20000
 CONFIG_SYS_NAND_ONFI_DETECTION=y
-CONFIG_SYS_NAND_PAGE_COUNT=0x40
 CONFIG_SYS_NAND_PAGE_SIZE=0x800
 CONFIG_SYS_NAND_OOBSIZE=0x40
 CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y
diff --git a/doc/device-tree-bindings/nand/sandbox,nand.txt b/doc/device-tree-bindings/nand/sandbox,nand.txt
new file mode 100644
index 0000000..0a723d7
--- /dev/null
+++ b/doc/device-tree-bindings/nand/sandbox,nand.txt
@@ -0,0 +1,57 @@
+Sandbox NAND
+============
+
+The sandbox NAND controller emulates a NAND controller and attached devices.
+
+Required properties:
+- compatible: "sandbox,nand"
+- #address-cells: Must be 1
+- #size-cells: Must be 0
+
+Any number of child nodes may be present, each representing a NAND device:
+
+Required Properties:
+- reg: The chip-select(s) to use. Only single-die devices are supported for now.
+- sandbox,id: An array of bytes to be reported by the READID (0x90) command
+- sandbox,erasesize: The block size (erase size) of the device, in bytes. Must
+                     be a power-of-two multiple of the page size.
+- sandbox,oobsize: The size of the OOB area per page, in bytes.
+- sandbox,pagesize: The page size (write size) of the device, in bytes. Must be
+                    a power of two.
+- sandbox,pages: The total number of pages in the device.
+- sandbox,err-count: Number of bit errors to inject per step.
+- sandbox,err-step-size: Size of the step to use when injecting errors, in
+                         bytes. Must evenly divide the page size.
+
+Optional properties:
+- sandbox,onfi: The complete ONFI parameter page, including the CRC. Should be
+                exactly 256 bytes.
+- Any common NAND chip properties as documented by Linux's
+  Documentation/devicetree/bindings/mtd/raw-nand-chip.yaml
+
+To match U-Boot's error correction capabilities, errors are only injected into
+the data area and the ECC codes. Other data in the OOB area is never corrupted.
+Generally, sandbox,err-step-size should be the same as the ECC step size, and
+sandbox,err-count should be less than the number of correctable bit errors (the
+ECC strength).
+
+Example
+-------
+
+nand-controller {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "sandbox,nand";
+
+	nand@0 {
+		reg = <0>;
+		nand-ecc-mode = "soft";
+		sandbox,id = [00 e3];
+		sandbox,erasesize = <(8 * 1024)>;
+		sandbox,oobsize = <16>;
+		sandbox,pagesize = <512>;
+		sandbox,pages = <0x2000>;
+		sandbox,err-count = <1>;
+		sandbox,err-step-size = <512>;
+	};
+};
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index c638980..c2fc80b 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -31,7 +31,7 @@
 else
 
 ifneq ($(mtd-y),)
-obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd.o
+obj-$(CONFIG_SPL_MTD) += mtd.o
 endif
 obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += nand/
 obj-$(CONFIG_SPL_ONENAND_SUPPORT) += onenand/
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index a13e6f5..bb9994b 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -447,6 +447,22 @@
 	  This enables the driver for the NAND flash device found on
 	  PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
 
+config NAND_SANDBOX
+	bool "Support for NAND in sandbox"
+	depends on SANDBOX
+	select SYS_NAND_SELF_INIT
+	select SPL_SYS_NAND_SELF_INIT
+	select SPL_NAND_INIT
+	select SYS_NAND_SOFT_ECC
+	select BCH
+	select NAND_ECC_BCH
+	imply CMD_NAND
+	help
+	  Enable a dummy NAND driver for sandbox. It simulates any number of
+	  arbitrary NAND chips with a RAM buffer. It will also inject errors to
+	  test ECC. At the moment, only 8-bit busses and single-chip devices are
+	  supported.
+
 config NAND_SUNXI
 	bool "Support for NAND on Allwinner SoCs"
 	default ARCH_SUNXI
@@ -659,20 +675,13 @@
 	  And fetching device parameters flashed on device, by parsing
 	  ONFI parameter page.
 
-config SYS_NAND_PAGE_COUNT
-	hex "NAND chip page count"
-	depends on SPL_NAND_SUPPORT && (NAND_ATMEL || NAND_MXC || \
-		SPL_NAND_AM33XX_BCH || SPL_NAND_LOAD || SPL_NAND_SIMPLE || \
-		NAND_OMAP_GPMC)
-	help
-	  Number of pages in the NAND chip.
-
 config SYS_NAND_PAGE_SIZE
 	hex "NAND chip page size"
 	depends on ARCH_SUNXI || NAND_OMAP_GPMC || NAND_LPC32XX_SLC || \
 		SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \
 		MVEBU_SPL_BOOT_DEVICE_NAND || \
-		(NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER
+		(NAND_ATMEL && SPL_NAND_SUPPORT) || \
+		SPL_GENERATE_ATMEL_PMECC_HEADER || NAND_SANDBOX
 	depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621
 	help
 	  Number of data bytes in one page for the NAND chip on the
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index add2b4c..ddbba89 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -70,6 +70,7 @@
 obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
 obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
 obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
+obj-$(CONFIG_NAND_SANDBOX) += sand_nand.o
 obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o
 obj-$(CONFIG_NAND_MXIC) += mxic_nand.o
 obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o
diff --git a/drivers/mtd/nand/raw/am335x_spl_bch.c b/drivers/mtd/nand/raw/am335x_spl_bch.c
index 6ab3f1f..6831af9 100644
--- a/drivers/mtd/nand/raw/am335x_spl_bch.c
+++ b/drivers/mtd/nand/raw/am335x_spl_bch.c
@@ -11,6 +11,7 @@
 
 #include <common.h>
 #include <nand.h>
+#include <system-constants.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/mtd/nand_ecc.h>
@@ -32,7 +33,7 @@
 	u8 cmd)
 {
 	struct nand_chip *this = mtd_to_nand(mtd);
-	int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+	int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
 	void (*hwctrl)(struct mtd_info *mtd, int cmd,
 			unsigned int ctrl) = this->cmd_ctrl;
 
@@ -217,6 +218,11 @@
 	nand_command(0, 0, 0, NAND_CMD_RESET);
 }
 
+unsigned int nand_page_size(void)
+{
+	return nand_to_mtd(&nand_chip)->writesize;
+}
+
 /* Unselect after operation */
 void nand_deselect(void)
 {
diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c
index 6b17e74..6d94e7a 100644
--- a/drivers/mtd/nand/raw/atmel_nand.c
+++ b/drivers/mtd/nand/raw/atmel_nand.c
@@ -12,6 +12,7 @@
 
 #include <common.h>
 #include <log.h>
+#include <system-constants.h>
 #include <asm/gpio.h>
 #include <asm/arch/gpio.h>
 #include <dm/device_compat.h>
@@ -1258,7 +1259,7 @@
 static int nand_command(int block, int page, uint32_t offs, u8 cmd)
 {
 	struct nand_chip *this = mtd_to_nand(mtd);
-	int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+	int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
 	void (*hwctrl)(struct mtd_info *mtd, int cmd,
 			unsigned int ctrl) = this->cmd_ctrl;
 
@@ -1359,7 +1360,7 @@
 	if (nand_chip.select_chip)
 		nand_chip.select_chip(mtd, 0);
 
-	page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+	page_addr = page + block * SYS_NAND_BLOCK_PAGES;
 	hwctrl(mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE);
 	/* Row address */
 	hwctrl(mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE);
@@ -1451,6 +1452,11 @@
 		nand_chip.select_chip(mtd, 0);
 }
 
+unsigned int nand_page_size(void)
+{
+	return nand_to_mtd(&nand_chip)->writesize;
+}
+
 void nand_deselect(void)
 {
 	if (nand_chip.select_chip)
diff --git a/drivers/mtd/nand/raw/denali_spl.c b/drivers/mtd/nand/raw/denali_spl.c
index 690279c..165a233 100644
--- a/drivers/mtd/nand/raw/denali_spl.c
+++ b/drivers/mtd/nand/raw/denali_spl.c
@@ -234,4 +234,9 @@
 	return 0;
 }
 
+unsigned int nand_page_size(void)
+{
+	return page_size;
+}
+
 void nand_deselect(void) {}
diff --git a/drivers/mtd/nand/raw/fsl_ifc_spl.c b/drivers/mtd/nand/raw/fsl_ifc_spl.c
index c67065e..69d26f1 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_spl.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_spl.c
@@ -106,6 +106,8 @@
 		return __raw_readw((u16 *)marker) != 0xffff;
 }
 
+static int saved_page_size;
+
 int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst)
 {
 	struct fsl_ifc_fcm *gregs = (void *)CFG_SYS_IFC_ADDR;
@@ -150,6 +152,7 @@
 		if (port_size == 8)
 			bad_marker = 5;
 	}
+	saved_page_size = page_size;
 
 	ver = ifc_in32(&gregs->ifc_rev);
 	if (ver >= FSL_IFC_V2_0_0)
@@ -302,6 +305,11 @@
 {
 }
 
+unsigned int nand_page_size(void)
+{
+	return saved_page_size;
+}
+
 void nand_deselect(void)
 {
 }
diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
index ac2e669..f8ae216 100644
--- a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c
@@ -765,4 +765,9 @@
 	return 0;
 }
 
+unsigned int nand_page_size(void)
+{
+	return BYTES_PER_PAGE;
+}
+
 #endif /* CONFIG_SPL_BUILD */
diff --git a/drivers/mtd/nand/raw/mt7621_nand_spl.c b/drivers/mtd/nand/raw/mt7621_nand_spl.c
index 114fc8b..a2be9ba 100644
--- a/drivers/mtd/nand/raw/mt7621_nand_spl.c
+++ b/drivers/mtd/nand/raw/mt7621_nand_spl.c
@@ -203,6 +203,11 @@
 	return SZ_2G;
 }
 
+unsigned int nand_page_size(void)
+{
+	return nfc_dev.nand.mtd.writesize;
+}
+
 void nand_deselect(void)
 {
 }
diff --git a/drivers/mtd/nand/raw/mxc_nand_spl.c b/drivers/mtd/nand/raw/mxc_nand_spl.c
index 309e75d..a855c99 100644
--- a/drivers/mtd/nand/raw/mxc_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxc_nand_spl.c
@@ -13,6 +13,7 @@
 #include <common.h>
 #include <hang.h>
 #include <nand.h>
+#include <system-constants.h>
 #include <linux/mtd/rawnand.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/io.h>
@@ -304,13 +305,13 @@
 		 * Check if we have crossed a block boundary, and if so
 		 * check for bad block.
 		 */
-		if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) {
+		if (!(page % SYS_NAND_BLOCK_PAGES)) {
 			/*
 			 * Yes, new block. See if this block is good. If not,
 			 * loop until we find a good block.
 			 */
 			while (is_badblock(page)) {
-				page = page + CONFIG_SYS_NAND_PAGE_COUNT;
+				page = page + SYS_NAND_BLOCK_PAGES;
 				/* Check i we've reached the end of flash. */
 				if (page >= maxpages)
 					return -1;
@@ -350,3 +351,8 @@
 
 void nand_init(void) {}
 void nand_deselect(void) {}
+
+unsigned int nand_page_size(void)
+{
+	return CONFIG_SYS_NAND_PAGE_SIZE;
+}
diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c
index 3006629..f7d3f02 100644
--- a/drivers/mtd/nand/raw/mxs_nand_spl.c
+++ b/drivers/mtd/nand/raw/mxs_nand_spl.c
@@ -295,6 +295,11 @@
 	return 0;
 }
 
+unsigned int nand_page_size(void)
+{
+	return nand_to_mtd(&nand_chip)->writesize;
+}
+
 void nand_deselect(void)
 {
 }
diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c
index eacd99c..4c18861 100644
--- a/drivers/mtd/nand/raw/nand.c
+++ b/drivers/mtd/nand/raw/nand.c
@@ -60,13 +60,11 @@
 	sprintf(dev_name[devnum], "nand%d", devnum);
 	mtd->name = dev_name[devnum];
 
-#ifdef CONFIG_MTD
 	/*
 	 * Add MTD device so that we can reference it later
 	 * via the mtdcore infrastructure (e.g. ubi).
 	 */
 	add_mtd_device(mtd);
-#endif
 
 	total_nand_size += mtd->size / 1024;
 
@@ -76,6 +74,23 @@
 	return 0;
 }
 
+void nand_unregister(struct mtd_info *mtd)
+{
+	int devnum = nand_mtd_to_devnum(mtd);
+
+	if (devnum < 0)
+		return;
+
+	if (nand_curr_device == devnum)
+		nand_curr_device = -1;
+
+	total_nand_size -= mtd->size / 1024;
+
+	del_mtd_device(nand_info[devnum]);
+
+	nand_info[devnum] = NULL;
+}
+
 #if !CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
 static void nand_init_chip(int i)
 {
@@ -100,6 +115,8 @@
 #endif
 
 #ifdef CONFIG_MTD_CONCAT
+struct mtd_info *concat_mtd;
+
 static void create_mtd_concat(void)
 {
 	struct mtd_info *nand_info_list[CONFIG_SYS_MAX_NAND_DEVICE];
@@ -114,28 +131,40 @@
 		}
 	}
 	if (nand_devices_found > 1) {
-		struct mtd_info *mtd;
 		char c_mtd_name[16];
 
 		/*
 		 * We detected multiple devices. Concatenate them together.
 		 */
 		sprintf(c_mtd_name, "nand%d", nand_devices_found);
-		mtd = mtd_concat_create(nand_info_list, nand_devices_found,
-					c_mtd_name);
+		concat_mtd = mtd_concat_create(nand_info_list,
+					       nand_devices_found, c_mtd_name);
 
-		if (mtd == NULL)
+		if (!concat_mtd)
 			return;
 
-		nand_register(nand_devices_found, mtd);
+		nand_register(nand_devices_found, concat_mtd);
 	}
 
 	return;
 }
+
+static void destroy_mtd_concat(void)
+{
+	if (!concat_mtd)
+		return;
+
+	mtd_concat_destroy(concat_mtd);
+	concat_mtd = NULL;
+}
 #else
 static void create_mtd_concat(void)
 {
 }
+
+static void destroy_mtd_concat(void)
+{
+}
 #endif
 
 unsigned long nand_size(void)
@@ -143,10 +172,10 @@
 	return total_nand_size;
 }
 
+static int initialized;
+
 void nand_init(void)
 {
-	static int initialized;
-
 	/*
 	 * Avoid initializing NAND Flash multiple times,
 	 * otherwise it will calculate a wrong total size.
@@ -174,3 +203,22 @@
 
 	create_mtd_concat();
 }
+
+void nand_reinit(void)
+{
+	int i;
+
+	destroy_mtd_concat();
+	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+		assert(!nand_info[i]);
+
+	initialized = 0;
+	nand_init();
+}
+
+unsigned int nand_page_size(void)
+{
+	struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
+
+	return mtd ? mtd->writesize : 1;
+}
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 6b4adcf..44b6cb6 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4462,17 +4462,14 @@
 	else if (chip->jedec_version)
 		pr_info("%s %s\n", manufacturer_desc->name,
 			chip->jedec_params.model);
-	else
+	else if (manufacturer_desc)
 		pr_info("%s %s\n", manufacturer_desc->name, type->name);
 #else
 	if (chip->jedec_version)
 		pr_info("%s %s\n", manufacturer_desc->name,
 			chip->jedec_params.model);
-	else
+	else if (manufacturer_desc)
 		pr_info("%s %s\n", manufacturer_desc->name, type->name);
-
-	pr_info("%s %s\n", manufacturer_desc->name,
-		type->name);
 #endif
 
 	pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
diff --git a/drivers/mtd/nand/raw/nand_spl_loaders.c b/drivers/mtd/nand/raw/nand_spl_loaders.c
index 156b44d..db4213e 100644
--- a/drivers/mtd/nand/raw/nand_spl_loaders.c
+++ b/drivers/mtd/nand/raw/nand_spl_loaders.c
@@ -12,8 +12,11 @@
 	while (block <= lastblock) {
 		if (!nand_is_bad_block(block)) {
 			/* Skip bad blocks */
-			while (page < CONFIG_SYS_NAND_PAGE_COUNT) {
+			while (size && page < SYS_NAND_BLOCK_PAGES) {
 				nand_read_page(block, page, dst);
+
+				size -= min(size, CONFIG_SYS_NAND_PAGE_SIZE -
+						  page_offset);
 				/*
 				 * When offs is not aligned to page address the
 				 * extra offset is copied to dst as well. Copy
diff --git a/drivers/mtd/nand/raw/nand_spl_simple.c b/drivers/mtd/nand/raw/nand_spl_simple.c
index 2f3af9e..80d6e0e 100644
--- a/drivers/mtd/nand/raw/nand_spl_simple.c
+++ b/drivers/mtd/nand/raw/nand_spl_simple.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <nand.h>
+#include <system-constants.h>
 #include <asm/io.h>
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/rawnand.h>
@@ -27,7 +28,7 @@
 	u8 cmd)
 {
 	struct nand_chip *this = mtd_to_nand(mtd);
-	int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+	int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
 
 	while (!this->dev_ready(mtd))
 		;
@@ -59,7 +60,7 @@
 	u8 cmd)
 {
 	struct nand_chip *this = mtd_to_nand(mtd);
-	int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT;
+	int page_addr = page + block * SYS_NAND_BLOCK_PAGES;
 	void (*hwctrl)(struct mtd_info *mtd, int cmd,
 			unsigned int ctrl) = this->cmd_ctrl;
 
@@ -226,6 +227,11 @@
 		nand_chip.select_chip(mtd, 0);
 }
 
+unsigned int nand_page_size(void)
+{
+	return nand_to_mtd(&nand_chip)->writesize;
+}
+
 /* Unselect after operation */
 void nand_deselect(void)
 {
diff --git a/drivers/mtd/nand/raw/omap_gpmc.c b/drivers/mtd/nand/raw/omap_gpmc.c
index 1a5ed0d..0e25bd5 100644
--- a/drivers/mtd/nand/raw/omap_gpmc.c
+++ b/drivers/mtd/nand/raw/omap_gpmc.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <log.h>
+#include <system-constants.h>
 #include <asm/io.h>
 #include <dm/uclass.h>
 #include <linux/errno.h>
@@ -1298,7 +1299,7 @@
 
 static int nand_read_page(int block, int page, uchar *dst)
 {
-	int page_addr = block * CONFIG_SYS_NAND_PAGE_COUNT + page;
+	int page_addr = block * SYS_NAND_BLOCK_PAGES + page;
 	loff_t ofs = page_addr * CONFIG_SYS_NAND_PAGE_SIZE;
 	int ret;
 	size_t len = CONFIG_SYS_NAND_PAGE_SIZE;
diff --git a/drivers/mtd/nand/raw/sand_nand.c b/drivers/mtd/nand/raw/sand_nand.c
new file mode 100644
index 0000000..229d7b5
--- /dev/null
+++ b/drivers/mtd/nand/raw/sand_nand.c
@@ -0,0 +1,707 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Sean Anderson <seanga2@gmail.com>
+ */
+
+#define LOG_CATEGORY UCLASS_MTD
+#include <errno.h>
+#include <hexdump.h>
+#include <log.h>
+#include <nand.h>
+#include <os.h>
+#include <rand.h>
+#include <spl.h>
+#include <system-constants.h>
+#include <dm/device_compat.h>
+#include <dm/read.h>
+#include <dm/uclass.h>
+#include <asm/bitops.h>
+#include <linux/bitmap.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/sizes.h>
+
+enum sand_nand_state {
+	STATE_READY,
+	STATE_IDLE,
+	STATE_READ,
+	STATE_READ_ID,
+	STATE_READ_ONFI,
+	STATE_PARAM_ONFI,
+	STATE_STATUS,
+	STATE_PROG,
+	STATE_ERASE,
+};
+
+static const char *const state_name[] = {
+	[STATE_READY] = "READY",
+	[STATE_IDLE] = "IDLE",
+	[STATE_READ] = "READ",
+	[STATE_READ_ID] = "READ_ID",
+	[STATE_READ_ONFI] = "READ_ONFI",
+	[STATE_PARAM_ONFI] = "PARAM_ONFI",
+	[STATE_STATUS] = "STATUS",
+	[STATE_PROG] = "PROG",
+	[STATE_ERASE] = "ERASE",
+};
+
+/**
+ * struct sand_nand_chip - Per-device private data
+ * @nand: The nand chip
+ * @node: The next device in this controller
+ * @programmed: Bitmap of whether sectors are programmed
+ * @id: ID to report for NAND_CMD_READID
+ * @id_len: Length of @id
+ * @onfi: Three copies of ONFI parameter page
+ * @status: Status to report for NAND_CMD_STATUS
+ * @chunksize: Size of one "chunk" (page + oob) in bytes
+ * @pageize: Size of one page in bytes
+ * @pages: Total number of pages
+ * @pages_per_erase: Number of pages per eraseblock
+ * @err_count: Number of errors to inject per @err_step_bits of data
+ * @err_step_bits: Number of data bits per error "step"
+ * @err_steps: Number of err steps in a page
+ * @cs: Chip select for this device
+ * @state: Current state of the device
+ * @column: Column of the most-recent command
+ * @page_addr: Page address of the most-recent command
+ * @fd: File descriptor for the backing data
+ * @fd_page_addr: Page address that @fd is seek'd to
+ * @selected: Whether this device is selected
+ * @tmp: "Cache" buffer used to store transferred data before committing it
+ * @tmp_dirty: Whether @tmp is dirty (modified) or clean (all ones)
+ *
+ * Data is stored with the OOB area in-line. For example, with 512-byte pages
+ * and and 16-byte OOB areas, the first page would start at offset 0, the second
+ * at offset 528, the third at offset 1056, and so on
+ */
+struct sand_nand_chip {
+	struct nand_chip nand;
+	struct list_head node;
+	long *programmed;
+	const u8 *id;
+	u32 chunksize, pagesize, pages, pages_per_erase;
+	u32 err_count, err_step_bits, err_steps, ecc_bits;
+	unsigned int cs;
+	enum sand_nand_state state;
+	int column, page_addr, fd, fd_page_addr;
+	bool selected, tmp_dirty;
+	u8 status;
+	u8 id_len;
+	u8 tmp[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
+	u8 onfi[sizeof(struct nand_onfi_params) * 3];
+};
+
+#define SAND_DEBUG(chip, fmt, ...) \
+	dev_dbg((chip)->nand.mtd.dev, "%u (%s): " fmt, (chip)->cs, \
+		state_name[(chip)->state], ##__VA_ARGS__)
+
+static inline void to_state(struct sand_nand_chip *chip,
+			    enum sand_nand_state new_state)
+{
+	if (new_state != chip->state)
+		SAND_DEBUG(chip, "to state %s\n", state_name[new_state]);
+	chip->state = new_state;
+}
+
+static inline struct sand_nand_chip *to_sand_nand(struct nand_chip *nand)
+{
+	return container_of(nand, struct sand_nand_chip, nand);
+}
+
+struct sand_nand_priv {
+	struct list_head chips;
+};
+
+static int sand_nand_dev_ready(struct mtd_info *mtd)
+{
+	return 1;
+}
+
+static int sand_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	u8 status;
+
+	return nand_status_op(chip, &status) ?: status;
+}
+
+static int sand_nand_seek(struct sand_nand_chip *chip)
+{
+	if (chip->fd_page_addr == chip->page_addr)
+		return 0;
+
+	if (os_lseek(chip->fd, (off_t)chip->page_addr * chip->chunksize,
+		     OS_SEEK_SET) < 0) {
+		SAND_DEBUG(chip, "could not seek: %d\n", errno);
+		return -EIO;
+	}
+
+	chip->fd_page_addr = chip->page_addr;
+	return 0;
+}
+
+static void sand_nand_inject_error(struct sand_nand_chip *chip,
+				   unsigned int step, unsigned int pos)
+{
+	int byte, index;
+
+	if (pos < chip->err_step_bits) {
+		__change_bit(step * chip->err_step_bits + pos, chip->tmp);
+		return;
+	}
+
+	/*
+	 * Only ECC bytes are covered in the OOB area, so
+	 * pretend that those are the only bytes which can have
+	 * errors.
+	 */
+	byte = (pos - chip->err_step_bits + step * chip->ecc_bits) / 8;
+	index = chip->nand.ecc.layout->eccpos[byte];
+	/* Avoid endianness issues by working with bytes */
+	chip->tmp[chip->pagesize + index] ^= BIT(pos & 0x7);
+}
+
+static int sand_nand_read(struct sand_nand_chip *chip)
+{
+	unsigned int i, stop = 0;
+
+	if (chip->column == chip->pagesize)
+		stop = chip->err_step_bits;
+
+	if (test_bit(chip->page_addr, chip->programmed)) {
+		if (sand_nand_seek(chip))
+			return -EIO;
+
+		if (os_read(chip->fd, chip->tmp, chip->chunksize) !=
+		    chip->chunksize) {
+			SAND_DEBUG(chip, "could not read: %d\n", errno);
+			return -EIO;
+		}
+		chip->fd_page_addr++;
+	} else if (chip->tmp_dirty) {
+		memset(chip->tmp + chip->column, 0xff,
+		       chip->chunksize - chip->column);
+	}
+
+	/*
+	 * Inject some errors; this is Method A from "An Efficient Algorithm for
+	 * Sequential Random Sampling" (Vitter 87). This is still slow when
+	 * generating a lot (dozens) of ECC errors.
+	 *
+	 * To avoid generating too many errors in any one ECC step, we separate
+	 * our error generation by ECC step.
+	 */
+	chip->tmp_dirty = true;
+	for (i = 0; i < chip->err_steps; i++) {
+		u32 bit_errors = chip->err_count;
+		unsigned int j = chip->err_step_bits + chip->ecc_bits;
+
+		while (bit_errors) {
+			unsigned int u = rand();
+			float quot = 1ULL << 32;
+
+			do {
+				quot *= j - bit_errors;
+				quot /= j;
+				j--;
+
+				if (j < stop)
+					goto next;
+			} while (u < quot);
+
+			sand_nand_inject_error(chip, i, j);
+			bit_errors--;
+		}
+next:
+		;
+	}
+
+	return 0;
+}
+
+static void sand_nand_command(struct mtd_info *mtd, unsigned int command,
+			      int column, int page_addr)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sand_nand_chip *chip = to_sand_nand(nand);
+	enum sand_nand_state new_state = chip->state;
+
+	SAND_DEBUG(chip, "command=%02x column=%d page_addr=%d\n", command,
+		   column, page_addr);
+
+	if (!chip->selected)
+		return;
+
+	switch (chip->state) {
+	case STATE_READY:
+		if (command == NAND_CMD_RESET)
+			goto reset;
+		break;
+	case STATE_PROG:
+		new_state = STATE_IDLE;
+		if (command != NAND_CMD_PAGEPROG ||
+		    test_and_set_bit(chip->page_addr, chip->programmed)) {
+			chip->status |= NAND_STATUS_FAIL;
+			break;
+		}
+
+		if (sand_nand_seek(chip)) {
+			chip->status |= NAND_STATUS_FAIL;
+			break;
+		}
+
+		if (os_write(chip->fd, chip->tmp, chip->chunksize) !=
+		    chip->chunksize) {
+			SAND_DEBUG(chip, "could not write: %d\n", errno);
+			chip->status |= NAND_STATUS_FAIL;
+			break;
+		}
+
+		chip->fd_page_addr++;
+		break;
+	case STATE_ERASE:
+		new_state = STATE_IDLE;
+		if (command != NAND_CMD_ERASE2) {
+			chip->status |= NAND_STATUS_FAIL;
+			break;
+		}
+
+		if (chip->page_addr < 0 ||
+		    chip->page_addr >= chip->pages ||
+		    chip->page_addr % chip->pages_per_erase)
+			chip->status |= NAND_STATUS_FAIL;
+		else
+			bitmap_clear(chip->programmed, chip->page_addr,
+				     chip->pages_per_erase);
+		break;
+	default:
+		chip->column = column;
+		chip->page_addr = page_addr;
+		switch (command) {
+		case NAND_CMD_READOOB:
+			if (column >= 0)
+				chip->column += chip->pagesize;
+			fallthrough;
+		case NAND_CMD_READ0:
+			new_state = STATE_IDLE;
+			if (page_addr < 0 || page_addr >= chip->pages)
+				break;
+
+			if (chip->column < 0 || chip->column >= chip->chunksize)
+				break;
+
+			if (sand_nand_read(chip))
+				break;
+
+			chip->page_addr = page_addr;
+			new_state = STATE_READ;
+			break;
+		case NAND_CMD_ERASE1:
+			new_state = STATE_ERASE;
+			chip->status = ~NAND_STATUS_FAIL;
+			break;
+		case NAND_CMD_STATUS:
+			new_state = STATE_STATUS;
+			chip->column = 0;
+			break;
+		case NAND_CMD_SEQIN:
+			new_state = STATE_PROG;
+			chip->status = ~NAND_STATUS_FAIL;
+			if (page_addr < 0 || page_addr >= chip->pages ||
+			    chip->column < 0 ||
+			    chip->column >= chip->chunksize) {
+				chip->status |= NAND_STATUS_FAIL;
+			} else if (chip->tmp_dirty) {
+				memset(chip->tmp, 0xff, chip->chunksize);
+				chip->tmp_dirty = false;
+			}
+			break;
+		case NAND_CMD_READID:
+			if (chip->onfi[0] && column == 0x20)
+				new_state = STATE_READ_ONFI;
+			else
+				new_state = STATE_READ_ID;
+			chip->column = 0;
+			break;
+		case NAND_CMD_PARAM:
+			if (chip->onfi[0] && !column)
+				new_state = STATE_PARAM_ONFI;
+			else
+				new_state = STATE_IDLE;
+			break;
+		case NAND_CMD_RESET:
+reset:
+			new_state = STATE_IDLE;
+			chip->column = -1;
+			chip->page_addr = -1;
+			chip->status = ~NAND_STATUS_FAIL;
+			break;
+		default:
+			new_state = STATE_IDLE;
+			SAND_DEBUG(chip, "Unsupported command %02x\n", command);
+		}
+	}
+
+	to_state(chip, new_state);
+}
+
+static void sand_nand_select_chip(struct mtd_info *mtd, int n)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sand_nand_chip *chip = to_sand_nand(nand);
+
+	chip->selected = !n;
+}
+
+static void sand_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sand_nand_chip *chip = to_sand_nand(nand);
+	unsigned int to_copy;
+	int src_len = 0;
+	const u8 *src = NULL;
+
+	if (!chip->selected)
+		goto copy;
+
+	switch (chip->state) {
+	case STATE_READ:
+		src = chip->tmp;
+		src_len = chip->chunksize;
+		break;
+	case STATE_READ_ID:
+		src = chip->id;
+		src_len = chip->id_len;
+		break;
+	case STATE_READ_ONFI:
+		src = "ONFI";
+		src_len = 4;
+		break;
+	case STATE_PARAM_ONFI:
+		src = chip->onfi;
+		src_len = sizeof(chip->onfi);
+		break;
+	case STATE_STATUS:
+		src = &chip->status;
+		src_len = 1;
+		break;
+	default:
+		break;
+	}
+
+copy:
+	if (chip->column >= 0)
+		to_copy = max(min(len, src_len - chip->column), 0);
+	else
+		to_copy = 0;
+	memcpy(buf, src + chip->column, to_copy);
+	memset(buf + to_copy, 0xff, len - to_copy);
+	chip->column += to_copy;
+
+	if (len == 1) {
+		SAND_DEBUG(chip, "read [ %02x ]\n", buf[0]);
+	} else if (src_len) {
+		SAND_DEBUG(chip, "read %d bytes\n", len);
+#ifdef VERBOSE_DEBUG
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
+#endif
+	}
+
+	if (src_len && chip->column == src_len)
+		to_state(chip, STATE_IDLE);
+}
+
+static u8 sand_nand_read_byte(struct mtd_info *mtd)
+{
+	u8 ret;
+
+	sand_nand_read_buf(mtd, &ret, 1);
+	return ret;
+}
+
+static u16 sand_nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sand_nand_chip *chip = to_sand_nand(nand);
+
+	SAND_DEBUG(chip, "16-bit access unsupported\n");
+	return sand_nand_read_byte(mtd) | 0xff00;
+}
+
+static void sand_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct sand_nand_chip *chip = to_sand_nand(nand);
+
+	SAND_DEBUG(chip, "write %d bytes\n", len);
+#ifdef VERBOSE_DEBUG
+	print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
+#endif
+
+	if (chip->state != STATE_PROG || chip->status & NAND_STATUS_FAIL)
+		return;
+
+	chip->tmp_dirty = true;
+	len = min((unsigned int)len, chip->chunksize - chip->column);
+	memcpy(chip->tmp + chip->column, buf, len);
+	chip->column += len;
+}
+
+static struct nand_chip *nand_chip;
+
+int sand_nand_remove(struct udevice *dev)
+{
+	struct sand_nand_priv *priv = dev_get_priv(dev);
+	struct sand_nand_chip *chip;
+
+	list_for_each_entry(chip, &priv->chips, node) {
+		struct nand_chip *nand = &chip->nand;
+
+		if (nand_chip == nand)
+			nand_chip = NULL;
+
+		nand_unregister(nand_to_mtd(nand));
+		free(chip->programmed);
+		os_close(chip->fd);
+		free(chip);
+	}
+
+	return 0;
+}
+
+static int sand_nand_probe(struct udevice *dev)
+{
+	struct sand_nand_priv *priv = dev_get_priv(dev);
+	struct sand_nand_chip *chip;
+	int ret, devnum = 0;
+	ofnode np;
+
+	INIT_LIST_HEAD(&priv->chips);
+
+	dev_for_each_subnode(np, dev) {
+		struct nand_chip *nand;
+		struct mtd_info *mtd;
+		u32 erasesize, oobsize, pagesize, pages;
+		u32 err_count, err_step_size;
+		off_t expected_size;
+		char filename[30];
+		fdt_addr_t cs;
+		const u8 *id, *onfi;
+		int id_len, onfi_len;
+
+		cs = ofnode_get_addr_size_index_notrans(np, 0, NULL);
+		if (cs == FDT_ADDR_T_NONE) {
+			dev_dbg(dev, "Invalid cs for chip %s\n",
+				ofnode_get_name(np));
+			ret = -ENOENT;
+			goto err;
+		}
+
+		id = ofnode_read_prop(np, "sandbox,id", &id_len);
+		if (!id) {
+			dev_dbg(dev, "No sandbox,id property for chip %s\n",
+				ofnode_get_name(np));
+			ret = -EINVAL;
+			goto err;
+		}
+
+		onfi = ofnode_read_prop(np, "sandbox,onfi", &onfi_len);
+		if (onfi && onfi_len != sizeof(struct nand_onfi_params)) {
+			dev_dbg(dev, "Invalid length %d for onfi params\n",
+				onfi_len);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ret = ofnode_read_u32(np, "sandbox,erasesize", &erasesize);
+		if (ret) {
+			dev_dbg(dev, "No sandbox,erasesize property for chip %s",
+				ofnode_get_name(np));
+			goto err;
+		}
+
+		ret = ofnode_read_u32(np, "sandbox,oobsize", &oobsize);
+		if (ret) {
+			dev_dbg(dev, "No sandbox,oobsize property for chip %s",
+				ofnode_get_name(np));
+			goto err;
+		}
+
+		ret = ofnode_read_u32(np, "sandbox,pagesize", &pagesize);
+		if (ret) {
+			dev_dbg(dev, "No sandbox,pagesize property for chip %s",
+				ofnode_get_name(np));
+			goto err;
+		}
+
+		ret = ofnode_read_u32(np, "sandbox,pages", &pages);
+		if (ret) {
+			dev_dbg(dev, "No sandbox,pages property for chip %s",
+				ofnode_get_name(np));
+			goto err;
+		}
+
+		ret = ofnode_read_u32(np, "sandbox,err-count", &err_count);
+		if (ret) {
+			dev_dbg(dev,
+				"No sandbox,err-count property for chip %s",
+				ofnode_get_name(np));
+			goto err;
+		}
+
+		ret = ofnode_read_u32(np, "sandbox,err-step-size",
+				      &err_step_size);
+		if (ret) {
+			dev_dbg(dev,
+				"No sandbox,err-step-size property for chip %s",
+				ofnode_get_name(np));
+			goto err;
+		}
+
+		chip = calloc(sizeof(*chip), 1);
+		if (!chip) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		chip->cs = cs;
+		chip->id = id;
+		chip->id_len = id_len;
+		chip->chunksize = pagesize + oobsize;
+		chip->pagesize = pagesize;
+		chip->pages = pages;
+		chip->pages_per_erase = erasesize / pagesize;
+		memset(chip->tmp, 0xff, chip->chunksize);
+
+		chip->err_count = err_count;
+		chip->err_step_bits = err_step_size * 8;
+		chip->err_steps = pagesize / err_step_size;
+
+		expected_size = (off_t)pages * chip->chunksize;
+		snprintf(filename, sizeof(filename),
+			 "/tmp/u-boot.nand%d.XXXXXX", devnum);
+		chip->fd = os_mktemp(filename, expected_size);
+		if (chip->fd < 0) {
+			dev_dbg(dev, "Could not create temp file %s\n",
+				filename);
+			ret = chip->fd;
+			goto err_chip;
+		}
+
+		chip->programmed = calloc(sizeof(long),
+					  BITS_TO_LONGS(pages));
+		if (!chip->programmed) {
+			ret = -ENOMEM;
+			goto err_fd;
+		}
+
+		if (onfi) {
+			memcpy(chip->onfi, onfi, onfi_len);
+			memcpy(chip->onfi + onfi_len, onfi, onfi_len);
+			memcpy(chip->onfi + 2 * onfi_len, onfi, onfi_len);
+		}
+
+		nand = &chip->nand;
+		nand->options = spl_in_proper() ? 0 : NAND_SKIP_BBTSCAN;
+		nand->flash_node = np;
+		nand->dev_ready = sand_nand_dev_ready;
+		nand->cmdfunc = sand_nand_command;
+		nand->waitfunc = sand_nand_wait;
+		nand->select_chip = sand_nand_select_chip;
+		nand->read_byte = sand_nand_read_byte;
+		nand->read_word = sand_nand_read_word;
+		nand->read_buf = sand_nand_read_buf;
+		nand->write_buf = sand_nand_write_buf;
+		nand->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
+
+		mtd = nand_to_mtd(nand);
+		mtd->dev = dev;
+
+		ret = nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS);
+		if (ret) {
+			dev_dbg(dev, "Could not scan chip %s: %d\n",
+				ofnode_get_name(np), ret);
+			goto err_prog;
+		}
+		chip->ecc_bits = nand->ecc.layout->eccbytes * 8 /
+				 chip->err_steps;
+
+		ret = nand_register(devnum, mtd);
+		if (ret) {
+			dev_dbg(dev, "Could not register nand %d: %d\n", devnum,
+				ret);
+			goto err_prog;
+		}
+
+		if (!nand_chip)
+			nand_chip = nand;
+
+		list_add_tail(&chip->node, &priv->chips);
+		devnum++;
+		continue;
+
+err_prog:
+		free(chip->programmed);
+err_fd:
+		os_close(chip->fd);
+err_chip:
+		free(chip);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	sand_nand_remove(dev);
+	return ret;
+}
+
+static const struct udevice_id sand_nand_ids[] = {
+	{ .compatible = "sandbox,nand" },
+	{ }
+};
+
+U_BOOT_DRIVER(sand_nand) = {
+	.name           = "sand-nand",
+	.id             = UCLASS_MTD,
+	.of_match       = sand_nand_ids,
+	.probe          = sand_nand_probe,
+	.remove		= sand_nand_remove,
+	.priv_auto	= sizeof(struct sand_nand_priv),
+};
+
+void board_nand_init(void)
+{
+	struct udevice *dev;
+	int err;
+
+	err = uclass_get_device_by_driver(UCLASS_MTD, DM_DRIVER_REF(sand_nand),
+					  &dev);
+	if (err && err != -ENODEV)
+		log_info("Failed to get sandbox NAND: %d\n", err);
+}
+
+#if IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_SPL_NAND_INIT)
+void nand_deselect(void)
+{
+	nand_chip->select_chip(nand_to_mtd(nand_chip), -1);
+}
+
+static int nand_is_bad_block(int block)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand_chip);
+
+	return mtd_block_isbad(mtd, block << mtd->erasesize_shift);
+}
+
+static int nand_read_page(int block, int page, uchar *dst)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand_chip);
+	loff_t ofs = ((loff_t)block << mtd->erasesize_shift) +
+		     ((loff_t)page << mtd->writesize_shift);
+	size_t len = mtd->writesize;
+
+	return nand_read(mtd, ofs, &len, dst);
+}
+
+#include "nand_spl_loaders.c"
+#endif /* CONFIG_SPL_NAND_INIT */
diff --git a/drivers/mtd/nand/raw/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c
index 6de0b0a..c9b8c78 100644
--- a/drivers/mtd/nand/raw/sunxi_nand_spl.c
+++ b/drivers/mtd/nand/raw/sunxi_nand_spl.c
@@ -524,9 +524,10 @@
 	return 0;
 }
 
+static struct nfc_config conf;
+
 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
 {
-	static struct nfc_config conf = { };
 	int ret;
 
 	ret = nand_detect_config(&conf, offs, dest);
@@ -536,6 +537,11 @@
 	return nand_read_buffer(&conf, offs, size, dest);
 }
 
+unsigned int nand_page_size(void)
+{
+	return conf.page_size;
+}
+
 void nand_deselect(void)
 {
 	struct sunxi_ccm_reg *const ccm =
diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c
index 04791df..ecacabe 100644
--- a/drivers/mtd/onenand/onenand_uboot.c
+++ b/drivers/mtd/onenand/onenand_uboot.c
@@ -44,14 +44,12 @@
 			puts("Flex-");
 		puts("OneNAND: ");
 
-#ifdef CONFIG_MTD
 		/*
 		 * Add MTD device so that we can reference it later
 		 * via the mtdcore infrastructure (e.g. ubi).
 		 */
 		onenand_mtd.name = dev_name;
 		add_mtd_device(&onenand_mtd);
-#endif
 	}
 	print_size(onenand_chip.chipsize, "\n");
 }
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 09f5269..7a66c7a 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -552,8 +552,20 @@
 
 #ifdef __UBOOT__
 /* drivers/mtd/mtdcore.h */
+#if CONFIG_IS_ENABLED(MTD)
 int add_mtd_device(struct mtd_info *mtd);
 int del_mtd_device(struct mtd_info *mtd);
+#else
+static inline int add_mtd_device(struct mtd_info *mtd)
+{
+	return -ENOSYS;
+}
+
+static inline int del_mtd_device(struct mtd_info *mtd)
+{
+	return -ENOSYS;
+}
+#endif
 
 #ifdef CONFIG_MTD_PARTITIONS
 int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
diff --git a/include/mtd/cfi_flash.h b/include/mtd/cfi_flash.h
index 52cd1c4..f4aecaa 100644
--- a/include/mtd/cfi_flash.h
+++ b/include/mtd/cfi_flash.h
@@ -163,7 +163,7 @@
 #if defined(CONFIG_SYS_MAX_FLASH_BANKS_DETECT)
 /* map to cfi_flash_num_flash_banks only when supported */
 #if IS_ENABLED(CONFIG_FLASH_CFI_DRIVER) && \
-    (!IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_SPL_MTD_SUPPORT))
+    (!IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_SPL_MTD))
 #define CFI_FLASH_BANKS		(cfi_flash_num_flash_banks)
 /* board code can update this variable before CFI detection */
 extern int cfi_flash_num_flash_banks;
diff --git a/include/nand.h b/include/nand.h
index 70c1286..220ffa2 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -11,7 +11,9 @@
 #include <config.h>
 
 extern void nand_init(void);
+void nand_reinit(void);
 unsigned long nand_size(void);
+unsigned int nand_page_size(void);
 
 #include <linux/compat.h>
 #include <linux/mtd/mtd.h>
@@ -21,6 +23,7 @@
 #if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
 void board_nand_init(void);
 int nand_register(int devnum, struct mtd_info *mtd);
+void nand_unregister(struct mtd_info *mtd);
 #else
 struct nand_chip;
 
diff --git a/include/os.h b/include/os.h
index fc8a1b1..877404a 100644
--- a/include/os.h
+++ b/include/os.h
@@ -109,6 +109,19 @@
 int os_persistent_file(char *buf, int maxsize, const char *fname);
 
 /**
+ * os_mktemp() - Create a temporary file
+ * @fname: The template to use for the file name. This must end with 6 Xs. It
+ *         will be modified to the opened filename on success.
+ * @size: The size of the file
+ *
+ * Create a temporary file using @fname as a template, unlink it, and truncate
+ * it to @size.
+ *
+ * Return: A file descriptor, or negative errno on error
+ */
+int os_mktemp(char *fname, off_t size);
+
+/**
  * os_exit() - access to the OS exit() system call
  *
  * This exits with the supplied return code, which should be 0 to indicate
diff --git a/include/system-constants.h b/include/system-constants.h
index 5937156..d688629 100644
--- a/include/system-constants.h
+++ b/include/system-constants.h
@@ -41,4 +41,8 @@
 #define SPL_PAYLOAD_ARGS_ADDR	0
 #endif
 
+/* Number of pages per block */
+#define SYS_NAND_BLOCK_PAGES \
+	(CONFIG_SYS_NAND_BLOCK_SIZE / CONFIG_SYS_NAND_PAGE_SIZE)
+
 #endif
diff --git a/test/dm/Makefile b/test/dm/Makefile
index cb82d83..a3ce7b3 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -73,6 +73,7 @@
 obj-$(CONFIG_MULTIPLEXER) += mux-emul.o
 obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
 obj-y += fdtdec.o
+obj-$(CONFIG_MTD_RAW_NAND) += nand.o
 obj-$(CONFIG_UT_DM) += nop.o
 obj-y += ofnode.o
 obj-y += ofread.o
diff --git a/test/dm/nand.c b/test/dm/nand.c
new file mode 100644
index 0000000..0b992fd
--- /dev/null
+++ b/test/dm/nand.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
+ */
+
+#include <nand.h>
+#include <part.h>
+#include <rand.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+
+static int dm_test_nand(struct unit_test_state *uts, int dev, bool end)
+{
+	nand_erase_options_t opts = { };
+	struct mtd_info *mtd;
+	size_t length;
+	loff_t size;
+	char *buf;
+	int *gold;
+	u8 oob[NAND_MAX_OOBSIZE];
+	int i;
+	loff_t off = 0;
+	mtd_oob_ops_t ops = { };
+
+	/* Seed RNG for bit errors */
+	srand((off >> 32) ^ off ^ ~dev);
+
+	mtd = get_nand_dev_by_index(dev);
+	ut_assertnonnull(mtd);
+	size = mtd->erasesize * 4;
+	length = size;
+
+	buf = malloc(size);
+	ut_assertnonnull(buf);
+	gold = malloc(size);
+	ut_assertnonnull(gold);
+
+	/* Mark a block as bad */
+	ut_assertok(mtd_block_markbad(mtd, off + mtd->erasesize));
+
+	/* Erase some stuff */
+	if (end)
+		off = mtd->size - size - mtd->erasesize;
+	opts.offset = off;
+	opts.length = size;
+	opts.spread = 1;
+	opts.lim = U32_MAX;
+	ut_assertok(nand_erase_opts(mtd, &opts));
+
+	/* Make sure everything is erased */
+	memset(gold, 0xff, size);
+	ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf));
+	ut_asserteq(size, length);
+	ut_asserteq_mem(gold, buf, size);
+
+	/* ...but our bad block marker is still there */
+	ops.oobbuf = oob;
+	ops.ooblen = mtd->oobsize;
+	ut_assertok(mtd_read_oob(mtd, mtd->erasesize, &ops));
+	ut_asserteq(0, oob[mtd_to_nand(mtd)->badblockpos]);
+
+	/* Generate some data and write it */
+	for (i = 0; i < size / sizeof(int); i++)
+		gold[i] = rand();
+	ut_assertok(nand_write_skip_bad(mtd, off, &length, NULL, U64_MAX,
+					(void *)gold, 0));
+	ut_asserteq(size, length);
+
+	/* Verify */
+	ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf));
+	ut_asserteq(size, length);
+	ut_asserteq_mem(gold, buf, size);
+
+	/* Erase some blocks */
+	memset(((char *)gold) + mtd->erasesize, 0xff, mtd->erasesize * 2);
+	opts.offset = off + mtd->erasesize;
+	opts.length = mtd->erasesize * 2;
+	ut_assertok(nand_erase_opts(mtd, &opts));
+
+	/* Verify */
+	ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf));
+	ut_asserteq(size, length);
+	ut_asserteq_mem(gold, buf, size);
+
+	return 0;
+}
+
+#define DM_NAND_TEST(dev) \
+static int dm_test_nand##dev##_start(struct unit_test_state *uts) \
+{ \
+	return dm_test_nand(uts, dev, false); \
+} \
+DM_TEST(dm_test_nand##dev##_start, UT_TESTF_SCAN_FDT); \
+static int dm_test_nand##dev##_end(struct unit_test_state *uts) \
+{ \
+	return dm_test_nand(uts, dev, true); \
+} \
+DM_TEST(dm_test_nand##dev##_end, UT_TESTF_SCAN_FDT)
+
+DM_NAND_TEST(0);
+DM_NAND_TEST(1);
diff --git a/test/image/Kconfig b/test/image/Kconfig
index 8f9e6ae..6f0bb81 100644
--- a/test/image/Kconfig
+++ b/test/image/Kconfig
@@ -23,6 +23,15 @@
 	help
 	  Test filesystems and the various load methods which use them.
 
+config SPL_UT_LOAD_NAND
+	bool "Test loading from NAND flash"
+	depends on SANDBOX && SPL_OF_REAL
+	depends on SPL_NAND_SUPPORT
+	depends on SPL_MTD
+	default y
+	help
+	  Test the NAND flash load method.
+
 config SPL_UT_LOAD_NET
 	bool "Test loading over TFTP"
 	depends on SANDBOX && SPL_OF_REAL
diff --git a/test/image/Makefile b/test/image/Makefile
index b302101..11ed257 100644
--- a/test/image/Makefile
+++ b/test/image/Makefile
@@ -4,6 +4,7 @@
 
 obj-y += spl_load.o
 obj-$(CONFIG_SPL_UT_LOAD_FS) += spl_load_fs.o
+obj-$(CONFIG_SPL_UT_LOAD_NAND) += spl_load_nand.o
 obj-$(CONFIG_SPL_UT_LOAD_NET) += spl_load_net.o
 obj-$(CONFIG_SPL_NOR_SUPPORT) += spl_load_nor.o
 obj-$(CONFIG_SPL_UT_LOAD_OS) += spl_load_os.o
diff --git a/test/image/spl_load_nand.c b/test/image/spl_load_nand.c
new file mode 100644
index 0000000..30179de
--- /dev/null
+++ b/test/image/spl_load_nand.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com>
+ */
+
+#include <nand.h>
+#include <spl.h>
+#include <test/spl.h>
+#include <test/ut.h>
+
+uint32_t spl_nand_get_uboot_raw_page(void);
+
+static int spl_test_nand_write_image(struct unit_test_state *uts, void *img,
+				     size_t img_size)
+{
+	uint32_t off = spl_nand_get_uboot_raw_page();
+	struct mtd_info *mtd;
+	struct erase_info erase = { };
+	size_t length;
+
+	nand_reinit();
+	mtd = get_nand_dev_by_index(0);
+	ut_assertnonnull(mtd);
+
+	/* Mark the first block as bad to test that it gets skipped */
+	ut_assertok(mtd_block_markbad(mtd, off & ~mtd->erasesize_mask));
+	off += mtd->erasesize;
+
+	erase.mtd = mtd;
+	erase.len = img_size + (off & mtd->erasesize_mask);
+	erase.len += mtd->erasesize_mask;
+	erase.len &= ~mtd->erasesize_mask;
+	erase.addr = off & ~mtd->erasesize_mask;
+	erase.scrub = 1;
+	ut_assertok(mtd_erase(mtd, &erase));
+
+	ut_assertok(mtd_write(mtd, off, img_size, &length, img));
+
+	return 0;
+}
+
+static int spl_test_nand(struct unit_test_state *uts, const char *test_name,
+			 enum spl_test_image type)
+{
+	return do_spl_test_load(uts, test_name, type,
+				SPL_LOAD_IMAGE_GET(1, BOOT_DEVICE_NAND,
+						   spl_nand_load_image),
+				spl_test_nand_write_image);
+}
+SPL_IMG_TEST(spl_test_nand, LEGACY, DM_FLAGS);
+SPL_IMG_TEST(spl_test_nand, LEGACY_LZMA, DM_FLAGS);
+SPL_IMG_TEST(spl_test_nand, IMX8, DM_FLAGS);
+SPL_IMG_TEST(spl_test_nand, FIT_INTERNAL, DM_FLAGS);
+SPL_IMG_TEST(spl_test_nand, FIT_EXTERNAL, DM_FLAGS);