Hi Fabio,

Thanks for the patch.

On 12/2/2026 6:25 am, Fabio Estevam wrote:
[CAUTION: This email is from outside your organization. Unless you trust the 
sender, do not click on links or open attachments as it may be a fraudulent 
email attempting to steal your information and/or compromise your computer.]

From: Fabio Estevam <[email protected]>

Add support for loading the next stage from an MTD device in SPL.

Introduce CONFIG_SPL_MTD_LOAD and a generic SPL MTD loader
implementation that uses the MTD subsystem to read the U-Boot payload.

The loader works with any MTD-backed storage, including raw NAND and
SPI NAND, without being tied to a specific NAND type.

The payload offset defaults to CONFIG_SYS_MTD_U_BOOT_OFFS and can be
overridden via the device tree property:

     u-boot,spl-payload-offset

To support both raw NAND and SPI NAND boot flows, the loader is
registered for BOOT_DEVICE_NAND and BOOT_DEVICE_SPI. This allows it
to operate correctly on platforms where the ROM reports either NAND
or SPI as the boot source while using the same MTD-based loading
infrastructure.

The required NAND core and SPI NAND drivers are built for SPL when
CONFIG_SPL_MTD_LOAD is enabled.

This provides reusable infrastructure for boards that boot from MTD
devices without relying on SPI-specific or NAND-specific SPL loaders.

Signed-off-by: Fabio Estevam <[email protected]>
---
Dinesh,

Could you please test this approach on your boards?

Thanks

Sure, seems like the approach is quite robust.
Let me try the approach on my board and will update you

Thanks


  common/spl/Kconfig        | 15 +++++++
  common/spl/Makefile       |  1 +
  common/spl/spl_mtd.c      | 88 +++++++++++++++++++++++++++++++++++++++
  drivers/mtd/Makefile      |  1 +
  drivers/mtd/nand/Makefile | 12 +++++-
  5 files changed, 116 insertions(+), 1 deletion(-)
  create mode 100644 common/spl/spl_mtd.c

diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 2998b7acb75f..2aba6da73c10 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1576,8 +1576,23 @@ config SPL_SPI_LOAD
           Enable support for loading next stage, U-Boot or otherwise, from
           SPI NOR in U-Boot SPL.

+config SPL_MTD_LOAD
+       bool "Support loading from a generic MTD device"
+       depends on SPL
+       depends on MTD && DM_MTD
+       help
+         Enable support for loading next stage, U-Boot or otherwise, from
+         a generic MTD device (raw NAND, SPI NAND) in U-Boot SPL.
+
  endif # SPL_SPI_FLASH_SUPPORT

+config SYS_MTD_U_BOOT_OFFS
+       hex "address of u-boot payload in the MTD device"
+       default 0x0
+       help
+        Address within the MTD device where the u-boot payload is fetched
+        from.
+
  config SYS_SPI_U_BOOT_OFFS
         hex "address of u-boot payload in SPI flash"
         default 0x8000 if ARCH_SUNXI
diff --git a/common/spl/Makefile b/common/spl/Makefile
index 4c9482bd3096..9f5ddcad17af 100644
--- a/common/spl/Makefile
+++ b/common/spl/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_$(PHASE_)NVME) += spl_nvme.o
  obj-$(CONFIG_$(PHASE_)SEMIHOSTING) += spl_semihosting.o
  obj-$(CONFIG_$(PHASE_)DFU) += spl_dfu.o
  obj-$(CONFIG_$(PHASE_)SPI_LOAD) += spl_spi.o
+obj-$(CONFIG_$(PHASE_)MTD_LOAD) += spl_mtd.o
  obj-$(CONFIG_$(PHASE_)RAM_SUPPORT) += spl_ram.o
  obj-$(CONFIG_$(PHASE_)USB_SDP_SUPPORT) += spl_sdp.o
  endif
diff --git a/common/spl/spl_mtd.c b/common/spl/spl_mtd.c
new file mode 100644
index 000000000000..8c6c94e592d0
--- /dev/null
+++ b/common/spl/spl_mtd.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Generic SPL loader for MTD devices.
+ *
+ * Based on spl_spi.c, which is:
+ *
+ * Copyright (C) 2011 OMICRON electronics GmbH
+ *
+ * based on drivers/mtd/nand/raw/nand_spl_load.c
+ *
+ * Copyright (C) 2011
+ * Heiko Schocher, DENX Software Engineering, [email protected].
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <image.h>
+#include <log.h>
+#include <spl.h>
+#include <spl_load.h>
+
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <dm/uclass.h>
+#include <mtd.h>
+
+static struct mtd_info *spl_mtd_get_device(void)
+{
+       struct udevice *dev;
+       int ret;
+
+       for (ret = uclass_first_device_err(UCLASS_MTD, &dev);
+            dev;
+            ret = uclass_next_device_err(&dev)) {
+               if (ret)
+                       continue;
+
+               return dev_get_uclass_priv(dev);
+       }
+
+       return NULL;
+}
+
+static ulong spl_mtd_read(struct spl_load_info *load,
+                         ulong offs, ulong size, void *buf)
+{
+       struct mtd_info *mtd = load->priv;
+       size_t retlen;
+       int ret;
+
+       ret = mtd_read(mtd, offs, size, &retlen, buf);
+       if (ret && !mtd_is_bitflip(ret))
+               return 0;
+
+       if (retlen != size)
+               return 0;
+
+       return retlen;
+}
+
+static int spl_mtd_load_image(struct spl_image_info *spl_image,
+                             struct spl_boot_device *bootdev)
+{
+       struct spl_load_info load;
+       struct mtd_info *mtd;
+       ulong offset;
+
+       mtd = spl_mtd_get_device();
+       if (!mtd) {
+               debug("No MTD device found\n");
+               return -ENODEV;
+       }
+
+       spl_load_init(&load, spl_mtd_read, mtd, mtd->writesize);
+
+       offset = CONFIG_SYS_MTD_U_BOOT_OFFS;
+
+       if (CONFIG_IS_ENABLED(OF_REAL))
+               offset = ofnode_conf_read_int("u-boot,spl-payload-offset",
+                                             offset);
+
+       return spl_load(spl_image, bootdev, &load, 0, offset);
+}
+
+/* Priority 1 so boards may override */
+SPL_LOAD_IMAGE_METHOD("MTD-NAND", 1, BOOT_DEVICE_NAND, spl_mtd_load_image);
+SPL_LOAD_IMAGE_METHOD("MTD-SPI-NAND", 1, BOOT_DEVICE_SPI, spl_mtd_load_image);
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index ce05e206073d..0856a8f68732 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -34,6 +34,7 @@ else
  ifneq ($(mtd-y),)
  obj-$(CONFIG_SPL_MTD) += mtd.o
  endif
+obj-$(CONFIG_SPL_MTD_LOAD) += nand/
  obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += nand/
  obj-$(CONFIG_SPL_ONENAND_SUPPORT) += onenand/
  obj-$(CONFIG_$(PHASE_)SPI_FLASH_SUPPORT) += spi/
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index c8169cf73902..cd6eaa87739c 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,10 +1,20 @@
  # SPDX-License-Identifier: GPL-2.0+

-ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
  nandcore-objs := core.o bbt.o
+
+ifeq ($(CONFIG_XPL_BUILD),)
+
+# U-Boot proper
  obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
  obj-$(CONFIG_MTD_RAW_NAND) += raw/
  obj-$(CONFIG_MTD_SPI_NAND) += spi/
+
  else
+
+# XPL
+obj-$(CONFIG_SPL_MTD_LOAD) += nandcore.o
+obj-$(CONFIG_SPL_MTD_LOAD) += spi/
+
+# raw NAND still follows the normal SPL rule
  obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += raw/
  endif
--
2.34.1

Reply via email to