* [PATCH v2] spl: Add generic SPL MTD loader support
@ 2026-02-20 3:12 Fabio Estevam
2026-02-20 3:52 ` Sean Anderson
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Fabio Estevam @ 2026-02-20 3:12 UTC (permalink / raw)
To: michael
Cc: u-boot, trini, seanga2, dinesh.maniyam, a-dutta, a-nandan, jonas,
Fabio Estevam
From: Fabio Estevam <festevam@nabladev.com>
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 <festevam@nabladev.com>
---
Changes since v1:
- Use uclass_get_device_by_seq().
- Use puts() instead of debug() for error.
- Include the new loader to include/spl_load.h.
- Introduce SPL_MTD_SPI_NAND.
common/spl/Kconfig | 30 ++++++++++++++
common/spl/Makefile | 1 +
common/spl/spl_mtd.c | 83 +++++++++++++++++++++++++++++++++++++++
drivers/mtd/Makefile | 1 +
drivers/mtd/nand/Makefile | 4 +-
include/spl_load.h | 1 +
6 files changed, 119 insertions(+), 1 deletion(-)
create mode 100644 common/spl/spl_mtd.c
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 2998b7acb75f..16dbc5b54324 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -933,6 +933,12 @@ config SYS_MMCSD_FS_BOOT_PARTITION
used in fs mode.
Use -1 as a special value to use the first bootable partition.
+config SYS_SPL_MTD_SEQ
+ int "MTD device number for the SPL load"
+ default 0
+ help
+ MTD device number used for the SPL load.
+
config SPL_MMC_TINY
bool "Tiny MMC framework in SPL"
depends on SPL_MMC
@@ -1578,6 +1584,30 @@ config SPL_SPI_LOAD
endif # SPL_SPI_FLASH_SUPPORT
+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 the next stage from an MTD device
+ using the MTD subsystem in SPL.
+
+ This supports raw NAND and SPI NAND devices.
+
+config SPL_MTD_SPI_NAND
+ bool "Enable SPI NAND support in SPL"
+ depends on SPL_MTD_LOAD
+ select MTD_SPI_NAND
+ help
+ Build SPI NAND support for SPL.
+
+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..67fc1cd1b396 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_SPL_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..904f1fbad834
--- /dev/null
+++ b/common/spl/spl_mtd.c
@@ -0,0 +1,83 @@
+// 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, hs@denx.de.
+ */
+
+#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;
+
+ ret = uclass_get_device_by_seq(UCLASS_MTD, CONFIG_SYS_SPL_MTD_SEQ, &dev);
+ if (ret)
+ return NULL;
+
+ return dev_get_uclass_priv(dev);
+}
+
+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) {
+ puts("SPL: 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..4bc11054ad74 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,10 +1,12 @@
# SPDX-License-Identifier: GPL-2.0+
-ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
nandcore-objs := core.o bbt.o
+ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
obj-$(CONFIG_MTD_RAW_NAND) += raw/
obj-$(CONFIG_MTD_SPI_NAND) += spi/
else
+obj-$(CONFIG_SPL_MTD_LOAD) += nandcore.o
+obj-$(CONFIG_SPL_MTD_SPI_NAND) += spi/
obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += raw/
endif
diff --git a/include/spl_load.h b/include/spl_load.h
index 525e0c9e86c6..5b06fa419dbf 100644
--- a/include/spl_load.h
+++ b/include/spl_load.h
@@ -113,6 +113,7 @@ static inline int _spl_load(struct spl_image_info *spl_image,
IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) + \
IS_ENABLED(CONFIG_SPL_SEMIHOSTING) + \
IS_ENABLED(CONFIG_SPL_SPI_LOAD) + \
+ IS_ENABLED(CONFIG_SPL_MTD_LOAD) + \
0
#if SPL_LOAD_USERS > 1
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-20 3:12 [PATCH v2] spl: Add generic SPL MTD loader support Fabio Estevam
@ 2026-02-20 3:52 ` Sean Anderson
2026-02-20 14:35 ` Tom Rini
2026-02-25 19:45 ` Sean Anderson
2026-02-20 7:20 ` Santhosh Kumar K
2026-02-25 15:46 ` Quentin Schulz
2 siblings, 2 replies; 10+ messages in thread
From: Sean Anderson @ 2026-02-20 3:52 UTC (permalink / raw)
To: Fabio Estevam, michael
Cc: u-boot, trini, dinesh.maniyam, a-dutta, a-nandan, jonas,
Fabio Estevam
On 2/19/26 22:12, Fabio Estevam wrote:
> From: Fabio Estevam <festevam@nabladev.com>
>
> 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 <festevam@nabladev.com>
> ---
> Changes since v1:
> - Use uclass_get_device_by_seq().
> - Use puts() instead of debug() for error.
> - Include the new loader to include/spl_load.h.
> - Introduce SPL_MTD_SPI_NAND.
>
> common/spl/Kconfig | 30 ++++++++++++++
> common/spl/Makefile | 1 +
> common/spl/spl_mtd.c | 83 +++++++++++++++++++++++++++++++++++++++
> drivers/mtd/Makefile | 1 +
> drivers/mtd/nand/Makefile | 4 +-
> include/spl_load.h | 1 +
> 6 files changed, 119 insertions(+), 1 deletion(-)
> create mode 100644 common/spl/spl_mtd.c
>
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index 2998b7acb75f..16dbc5b54324 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -933,6 +933,12 @@ config SYS_MMCSD_FS_BOOT_PARTITION
> used in fs mode.
> Use -1 as a special value to use the first bootable partition.
>
> +config SYS_SPL_MTD_SEQ
> + int "MTD device number for the SPL load"
> + default 0
> + help
> + MTD device number used for the SPL load.
> +
> config SPL_MMC_TINY
> bool "Tiny MMC framework in SPL"
> depends on SPL_MMC
> @@ -1578,6 +1584,30 @@ config SPL_SPI_LOAD
>
> endif # SPL_SPI_FLASH_SUPPORT
>
> +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 the next stage from an MTD device
> + using the MTD subsystem in SPL.
> +
> + This supports raw NAND and SPI NAND devices.
> +
> +config SPL_MTD_SPI_NAND
> + bool "Enable SPI NAND support in SPL"
> + depends on SPL_MTD_LOAD
> + select MTD_SPI_NAND
> + help
> + Build SPI NAND support for SPL.
> +
> +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.
> +
Maybe default to SYS_SPI_U_BOOT_OFFS? or CONFIG_SYS_NAND_U_BOOT_OFFS?
> 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..67fc1cd1b396 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_SPL_MTD_LOAD) += spl_mtd.o
Does this need a $(PHASE_)? (I don't know, but the others have it)
> 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..904f1fbad834
> --- /dev/null
> +++ b/common/spl/spl_mtd.c
> @@ -0,0 +1,83 @@
> +// 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, hs@denx.de.
> + */
> +
> +#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;
> +
> + ret = uclass_get_device_by_seq(UCLASS_MTD, CONFIG_SYS_SPL_MTD_SEQ, &dev);
> + if (ret)
> + return NULL;
> +
> + return dev_get_uclass_priv(dev);
> +}
> +
> +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;
You can just return retlen here. We check it against size in spl_load.
> +
> + 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) {
> + puts("SPL: 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);
Should these be a different priority than the "native" loaders? Does it make sense
to have both enabled or should we disable native loaders in Kconfig so we don't have
to consider this?
Actually, if CONFIG_SPL_NAND_SUPPORT is enabled then the native nand loader is compiled.
Maybe we should add a separate Kconfig for it (CONFIG_SPL_NAND_LOAD) defaulting to
SPL_NAND_SUPPORT. Then users can disable the "native" load method if they want to use MTD.
> 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/
Is this necessary? Shouldn't the user just enable CONFIG_SPL_NAND_SUPPORT?
> 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..4bc11054ad74 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -1,10 +1,12 @@
> # SPDX-License-Identifier: GPL-2.0+
>
> -ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
> nandcore-objs := core.o bbt.o
> +ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
> obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
> obj-$(CONFIG_MTD_RAW_NAND) += raw/
> obj-$(CONFIG_MTD_SPI_NAND) += spi/
> else
> +obj-$(CONFIG_SPL_MTD_LOAD) += nandcore.o
Shouldn't this be CONFIG_SPL_MTD_SPI_NAND too?
> +obj-$(CONFIG_SPL_MTD_SPI_NAND) += spi/
> obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += raw/
> endif
> diff --git a/include/spl_load.h b/include/spl_load.h
> index 525e0c9e86c6..5b06fa419dbf 100644
> --- a/include/spl_load.h
> +++ b/include/spl_load.h
> @@ -113,6 +113,7 @@ static inline int _spl_load(struct spl_image_info *spl_image,
> IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) + \
> IS_ENABLED(CONFIG_SPL_SEMIHOSTING) + \
> IS_ENABLED(CONFIG_SPL_SPI_LOAD) + \
> + IS_ENABLED(CONFIG_SPL_MTD_LOAD) + \
Please keep this alphabetical.
And still needs tests, but hopefully those should be simple to implement based
on my reply to v1.
--Sean
> 0
>
> #if SPL_LOAD_USERS > 1
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-20 3:52 ` Sean Anderson
@ 2026-02-20 14:35 ` Tom Rini
2026-02-25 19:45 ` Sean Anderson
1 sibling, 0 replies; 10+ messages in thread
From: Tom Rini @ 2026-02-20 14:35 UTC (permalink / raw)
To: Sean Anderson
Cc: Fabio Estevam, michael, u-boot, dinesh.maniyam, a-dutta, a-nandan,
jonas, Fabio Estevam
[-- Attachment #1: Type: text/plain, Size: 1936 bytes --]
On Thu, Feb 19, 2026 at 10:52:20PM -0500, Sean Anderson wrote:
> On 2/19/26 22:12, Fabio Estevam wrote:
> > From: Fabio Estevam <festevam@nabladev.com>
> >
> > 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 <festevam@nabladev.com>
[snip]
> > diff --git a/common/spl/Makefile b/common/spl/Makefile
> > index 4c9482bd3096..67fc1cd1b396 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_SPL_MTD_LOAD) += spl_mtd.o
>
> Does this need a $(PHASE_)? (I don't know, but the others have it)
For consistency yes, even if we're unlikely to need this in TPL too.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-20 3:52 ` Sean Anderson
2026-02-20 14:35 ` Tom Rini
@ 2026-02-25 19:45 ` Sean Anderson
2026-02-26 0:08 ` Fabio Estevam
1 sibling, 1 reply; 10+ messages in thread
From: Sean Anderson @ 2026-02-25 19:45 UTC (permalink / raw)
To: Fabio Estevam, michael
Cc: u-boot, trini, dinesh.maniyam, a-dutta, a-nandan, jonas,
Fabio Estevam
On 2/19/26 22:52, Sean Anderson wrote:
> On 2/19/26 22:12, Fabio Estevam wrote:
>> From: Fabio Estevam <festevam@nabladev.com>
>>
>> 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 <festevam@nabladev.com>
>> ---
>> Changes since v1:
>> - Use uclass_get_device_by_seq().
>> - Use puts() instead of debug() for error.
>> - Include the new loader to include/spl_load.h.
>> - Introduce SPL_MTD_SPI_NAND.
>>
>> common/spl/Kconfig | 30 ++++++++++++++
>> common/spl/Makefile | 1 +
>> common/spl/spl_mtd.c | 83 +++++++++++++++++++++++++++++++++++++++
>> drivers/mtd/Makefile | 1 +
>> drivers/mtd/nand/Makefile | 4 +-
>> include/spl_load.h | 1 +
>> 6 files changed, 119 insertions(+), 1 deletion(-)
>> create mode 100644 common/spl/spl_mtd.c
>>
>> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
>> index 2998b7acb75f..16dbc5b54324 100644
>> --- a/common/spl/Kconfig
>> +++ b/common/spl/Kconfig
>> @@ -933,6 +933,12 @@ config SYS_MMCSD_FS_BOOT_PARTITION
>> used in fs mode.
>> Use -1 as a special value to use the first bootable partition.
>> +config SYS_SPL_MTD_SEQ
>> + int "MTD device number for the SPL load"
>> + default 0
>> + help
>> + MTD device number used for the SPL load.
>> +
>> config SPL_MMC_TINY
>> bool "Tiny MMC framework in SPL"
>> depends on SPL_MMC
>> @@ -1578,6 +1584,30 @@ config SPL_SPI_LOAD
>> endif # SPL_SPI_FLASH_SUPPORT
>> +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 the next stage from an MTD device
>> + using the MTD subsystem in SPL.
>> +
>> + This supports raw NAND and SPI NAND devices.
>> +
>> +config SPL_MTD_SPI_NAND
>> + bool "Enable SPI NAND support in SPL"
>> + depends on SPL_MTD_LOAD
>> + select MTD_SPI_NAND
>> + help
>> + Build SPI NAND support for SPL.
>> +
>> +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.
>> +
>
> Maybe default to SYS_SPI_U_BOOT_OFFS? or CONFIG_SYS_NAND_U_BOOT_OFFS?
>
>> 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..67fc1cd1b396 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_SPL_MTD_LOAD) += spl_mtd.o
>
> Does this need a $(PHASE_)? (I don't know, but the others have it)
>
>> 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..904f1fbad834
>> --- /dev/null
>> +++ b/common/spl/spl_mtd.c
>> @@ -0,0 +1,83 @@
>> +// 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, hs@denx.de.
>> + */
>> +
>> +#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;
>> +
>> + ret = uclass_get_device_by_seq(UCLASS_MTD, CONFIG_SYS_SPL_MTD_SEQ, &dev);
Actually, I don't think this is correct. NAND devices have have multiple MTDs for each
CS, and SPI-NOR devices are UCLASS_SPI_FLASH and not UCLASS_MTD. So I think it's better
to do something like
mtd_probe_devices();
switch (bootdev->boot_device) {
case BOOT_DEVICE_NAND:
mtd = get_mtd_device_nm(CONFIG_SPL_MTD_NAND_NAME);
break;
case BOOT_DEVICE_SPI:
mtd = get_mtd_device_nm(CONFIG_SPL_MTD_SPI_FLASH_NAME);
break;
default:
mtd = ERR_PTR(-ENODEV);
break;
}
if (IS_ERR(mtd)) {
ret = PTR_ERR(mtd);
goto out;
}
>> + if (ret)
>> + return NULL;
>> +
>> + return dev_get_uclass_priv(dev);
>> +}
>> +
>> +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;
>
> You can just return retlen here. We check it against size in spl_load.
>
>> +
>> + 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) {
>> + puts("SPL: 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);
>
> Should these be a different priority than the "native" loaders? Does it make sense
> to have both enabled or should we disable native loaders in Kconfig so we don't have
> to consider this?
>
> Actually, if CONFIG_SPL_NAND_SUPPORT is enabled then the native nand loader is compiled.
> Maybe we should add a separate Kconfig for it (CONFIG_SPL_NAND_LOAD) defaulting to
> SPL_NAND_SUPPORT. Then users can disable the "native" load method if they want to use MTD.
I have a patch for this that I will try to send this week.
--Sean
>> 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/
>
> Is this necessary? Shouldn't the user just enable CONFIG_SPL_NAND_SUPPORT?
>
>> 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..4bc11054ad74 100644
>> --- a/drivers/mtd/nand/Makefile
>> +++ b/drivers/mtd/nand/Makefile
>> @@ -1,10 +1,12 @@
>> # SPDX-License-Identifier: GPL-2.0+
>> -ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
>> nandcore-objs := core.o bbt.o
>> +ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
>> obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
>> obj-$(CONFIG_MTD_RAW_NAND) += raw/
>> obj-$(CONFIG_MTD_SPI_NAND) += spi/
>> else
>> +obj-$(CONFIG_SPL_MTD_LOAD) += nandcore.o
>
> Shouldn't this be CONFIG_SPL_MTD_SPI_NAND too?
>
>> +obj-$(CONFIG_SPL_MTD_SPI_NAND) += spi/
>> obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += raw/
>> endif
>> diff --git a/include/spl_load.h b/include/spl_load.h
>> index 525e0c9e86c6..5b06fa419dbf 100644
>> --- a/include/spl_load.h
>> +++ b/include/spl_load.h
>> @@ -113,6 +113,7 @@ static inline int _spl_load(struct spl_image_info *spl_image,
>> IS_ENABLED(CONFIG_SPL_NOR_SUPPORT) + \
>> IS_ENABLED(CONFIG_SPL_SEMIHOSTING) + \
>> IS_ENABLED(CONFIG_SPL_SPI_LOAD) + \
>> + IS_ENABLED(CONFIG_SPL_MTD_LOAD) + \
>
> Please keep this alphabetical.
>
> And still needs tests, but hopefully those should be simple to implement based
> on my reply to v1.
>
> --Sean
>
>> 0
>> #if SPL_LOAD_USERS > 1
>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-25 19:45 ` Sean Anderson
@ 2026-02-26 0:08 ` Fabio Estevam
2026-02-26 5:10 ` Sean Anderson
0 siblings, 1 reply; 10+ messages in thread
From: Fabio Estevam @ 2026-02-26 0:08 UTC (permalink / raw)
To: Sean Anderson
Cc: michael, u-boot, trini, dinesh.maniyam, a-dutta, a-nandan, jonas,
Fabio Estevam
Hi Sean,
On Wed, Feb 25, 2026 at 4:45 PM Sean Anderson <seanga2@gmail.com> wrote:
> Actually, I don't think this is correct. NAND devices have have multiple MTDs for each
> CS, and SPI-NOR devices are UCLASS_SPI_FLASH and not UCLASS_MTD. So I think it's better
> to do something like
>
> mtd_probe_devices();
> switch (bootdev->boot_device) {
> case BOOT_DEVICE_NAND:
> mtd = get_mtd_device_nm(CONFIG_SPL_MTD_NAND_NAME);
> break;
> case BOOT_DEVICE_SPI:
> mtd = get_mtd_device_nm(CONFIG_SPL_MTD_SPI_FLASH_NAME);
> break;
> default:
> mtd = ERR_PTR(-ENODEV);
> break;
> }
> if (IS_ERR(mtd)) {
> ret = PTR_ERR(mtd);
> goto out;
> }
...
> > Actually, if CONFIG_SPL_NAND_SUPPORT is enabled then the native nand loader is compiled.
> > Maybe we should add a separate Kconfig for it (CONFIG_SPL_NAND_LOAD) defaulting to
> > SPL_NAND_SUPPORT. Then users can disable the "native" load method if they want to use MTD.
>
> I have a patch for this that I will try to send this week.
If you would like to prepare a patch for the generic SPL MTD loader,
I'll be glad to test it.
Thanks
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-26 0:08 ` Fabio Estevam
@ 2026-02-26 5:10 ` Sean Anderson
2026-02-26 5:34 ` Maniyam, Dinesh
0 siblings, 1 reply; 10+ messages in thread
From: Sean Anderson @ 2026-02-26 5:10 UTC (permalink / raw)
To: Fabio Estevam
Cc: michael, u-boot, trini, dinesh.maniyam, a-dutta, a-nandan, jonas,
Fabio Estevam
On 2/25/26 19:08, Fabio Estevam wrote:
> Hi Sean,
>
> On Wed, Feb 25, 2026 at 4:45 PM Sean Anderson <seanga2@gmail.com> wrote:
>
>> Actually, I don't think this is correct. NAND devices have have multiple MTDs for each
>> CS, and SPI-NOR devices are UCLASS_SPI_FLASH and not UCLASS_MTD. So I think it's better
>> to do something like
>>
>> mtd_probe_devices();
>> switch (bootdev->boot_device) {
>> case BOOT_DEVICE_NAND:
>> mtd = get_mtd_device_nm(CONFIG_SPL_MTD_NAND_NAME);
>> break;
>> case BOOT_DEVICE_SPI:
>> mtd = get_mtd_device_nm(CONFIG_SPL_MTD_SPI_FLASH_NAME);
>> break;
>> default:
>> mtd = ERR_PTR(-ENODEV);
>> break;
>> }
>> if (IS_ERR(mtd)) {
>> ret = PTR_ERR(mtd);
>> goto out;
>> }
> ...
>
>>> Actually, if CONFIG_SPL_NAND_SUPPORT is enabled then the native nand loader is compiled.
>>> Maybe we should add a separate Kconfig for it (CONFIG_SPL_NAND_LOAD) defaulting to
>>> SPL_NAND_SUPPORT. Then users can disable the "native" load method if they want to use MTD.
>>
>> I have a patch for this that I will try to send this week.
>
> If you would like to prepare a patch for the generic SPL MTD loader,
> I'll be glad to test it.
I can try, but I can't promise I'll be done with it in any particular timeframe.
But TBH I don't think a spi_nand.c-style loader is the right way to do things when UBI exists.
Maybe Dinesh can comment, but I don't really see the point except if e.g. you are really short
on space in SPL, but not so much that you can't fit in MTD.
--Sean
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-26 5:10 ` Sean Anderson
@ 2026-02-26 5:34 ` Maniyam, Dinesh
2026-02-26 12:04 ` Fabio Estevam
0 siblings, 1 reply; 10+ messages in thread
From: Maniyam, Dinesh @ 2026-02-26 5:34 UTC (permalink / raw)
To: Sean Anderson, Fabio Estevam
Cc: michael, u-boot, trini, a-dutta, a-nandan, jonas, Fabio Estevam
Hi Fabio,
Thanks for the patch.
On 26/2/2026 1:10 pm, Sean Anderson 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.]
>
> On 2/25/26 19:08, Fabio Estevam wrote:
>> Hi Sean,
>>
>> On Wed, Feb 25, 2026 at 4:45 PM Sean Anderson <seanga2@gmail.com> wrote:
>>
>>> Actually, I don't think this is correct. NAND devices have have
>>> multiple MTDs for each
>>> CS, and SPI-NOR devices are UCLASS_SPI_FLASH and not UCLASS_MTD. So
>>> I think it's better
>>> to do something like
>>>
>>> mtd_probe_devices();
>>> switch (bootdev->boot_device) {
>>> case BOOT_DEVICE_NAND:
>>> mtd = get_mtd_device_nm(CONFIG_SPL_MTD_NAND_NAME);
>>> break;
>>> case BOOT_DEVICE_SPI:
>>> mtd =
>>> get_mtd_device_nm(CONFIG_SPL_MTD_SPI_FLASH_NAME);
>>> break;
>>> default:
>>> mtd = ERR_PTR(-ENODEV);
>>> break;
>>> }
>>> if (IS_ERR(mtd)) {
>>> ret = PTR_ERR(mtd);
>>> goto out;
>>> }
>> ...
>>
>>>> Actually, if CONFIG_SPL_NAND_SUPPORT is enabled then the native
>>>> nand loader is compiled.
>>>> Maybe we should add a separate Kconfig for it
>>>> (CONFIG_SPL_NAND_LOAD) defaulting to
>>>> SPL_NAND_SUPPORT. Then users can disable the "native" load method
>>>> if they want to use MTD.
>>>
>>> I have a patch for this that I will try to send this week.
>>
>> If you would like to prepare a patch for the generic SPL MTD loader,
>> I'll be glad to test it.
>
> I can try, but I can't promise I'll be done with it in any particular
> timeframe.
>
> But TBH I don't think a spi_nand.c-style loader is the right way to do
> things when UBI exists.
> Maybe Dinesh can comment, but I don't really see the point except if
> e.g. you are really short
> on space in SPL, but not so much that you can't fit in MTD.
>
> --Sean
>
> Based on our current design, we rely on the existing NAND framework
> with only a minimal set
> of additional helper functions provided by the controller, which keeps
> the SPL implementation simple and NAND-specific.
>
> The SPI-NAND SPL loader expects a broader set of common SPL
> helpers which lead to compilation failures.
> Adapting to that model would require significant refactoring and
> extensive testing,
> so for now we plan to continue using and extending the existing
> |nand_spl_loaders.c|,
> which aligns better with the current SPL design and our constraints.
>
> --Dinesh
>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-26 5:34 ` Maniyam, Dinesh
@ 2026-02-26 12:04 ` Fabio Estevam
0 siblings, 0 replies; 10+ messages in thread
From: Fabio Estevam @ 2026-02-26 12:04 UTC (permalink / raw)
To: Maniyam, Dinesh
Cc: Sean Anderson, michael, u-boot, trini, a-dutta, a-nandan, jonas,
Fabio Estevam
Sean, Dinesh, Anurag,
On Thu, Feb 26, 2026 at 2:35 AM Maniyam, Dinesh
<dinesh.maniyam@altera.com> wrote:
> I can try, but I can't promise I'll be done with it in any particular timeframe.
>
> But TBH I don't think a spi_nand.c-style loader is the right way to do things when UBI exists.
> Maybe Dinesh can comment, but I don't really see the point except if e.g. you are really short
> on space in SPL, but not so much that you can't fit in MTD.
>
> --Sean
>
> Based on our current design, we rely on the existing NAND framework with only a minimal set
> of additional helper functions provided by the controller, which keeps the SPL implementation simple and NAND-specific.
>
> The SPI-NAND SPL loader expects a broader set of common SPL helpers which lead to compilation failures.
> Adapting to that model would require significant refactoring and extensive testing,
> so for now we plan to continue using and extending the existing nand_spl_loaders.c,
> which aligns better with the current SPL design and our constraints.
Should we focus on getting separate SPI NAND SPL and NAND SPL loaders
for now, and then later work on a generic MTD implementation?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-20 3:12 [PATCH v2] spl: Add generic SPL MTD loader support Fabio Estevam
2026-02-20 3:52 ` Sean Anderson
@ 2026-02-20 7:20 ` Santhosh Kumar K
2026-02-25 15:46 ` Quentin Schulz
2 siblings, 0 replies; 10+ messages in thread
From: Santhosh Kumar K @ 2026-02-20 7:20 UTC (permalink / raw)
To: Fabio Estevam, michael
Cc: u-boot, trini, seanga2, dinesh.maniyam, a-dutta, a-nandan, jonas,
Fabio Estevam, s-k6
Hello Fabio,
On 20/02/26 08:42, Fabio Estevam wrote:
> From: Fabio Estevam <festevam@nabladev.com>
>
> 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 <festevam@nabladev.com>
> ---
> Changes since v1:
> - Use uclass_get_device_by_seq().
> - Use puts() instead of debug() for error.
> - Include the new loader to include/spl_load.h.
> - Introduce SPL_MTD_SPI_NAND.
>
> common/spl/Kconfig | 30 ++++++++++++++
> common/spl/Makefile | 1 +
> common/spl/spl_mtd.c | 83 +++++++++++++++++++++++++++++++++++++++
> drivers/mtd/Makefile | 1 +
> drivers/mtd/nand/Makefile | 4 +-
> include/spl_load.h | 1 +
> 6 files changed, 119 insertions(+), 1 deletion(-)
> create mode 100644 common/spl/spl_mtd.c
>
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index 2998b7acb75f..16dbc5b54324 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -933,6 +933,12 @@ config SYS_MMCSD_FS_BOOT_PARTITION
> used in fs mode.
> Use -1 as a special value to use the first bootable partition.
>
> +config SYS_SPL_MTD_SEQ
> + int "MTD device number for the SPL load"
> + default 0
> + help
> + MTD device number used for the SPL load.
> +
> config SPL_MMC_TINY
> bool "Tiny MMC framework in SPL"
> depends on SPL_MMC
> @@ -1578,6 +1584,30 @@ config SPL_SPI_LOAD
>
> endif # SPL_SPI_FLASH_SUPPORT
>
> +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 the next stage from an MTD device
> + using the MTD subsystem in SPL.
> +
> + This supports raw NAND and SPI NAND devices.
> +
> +config SPL_MTD_SPI_NAND
> + bool "Enable SPI NAND support in SPL"
> + depends on SPL_MTD_LOAD
> + select MTD_SPI_NAND
> + help
> + Build SPI NAND support for SPL.
> +
> +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..67fc1cd1b396 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_SPL_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..904f1fbad834
> --- /dev/null
> +++ b/common/spl/spl_mtd.c
> @@ -0,0 +1,83 @@
> +// 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, hs@denx.de.
> + */
> +
> +#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;
> +
> + ret = uclass_get_device_by_seq(UCLASS_MTD, CONFIG_SYS_SPL_MTD_SEQ, &dev);
> + if (ret)
> + return NULL;
> +
> + return dev_get_uclass_priv(dev);
> +}
> +
> +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) {
> + puts("SPL: 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);
> +}
I believe bad block management is critical during image loading, as
this directly impacts the device boot flow. But, I do not see any check
for bad blocks or logic to skip them in the load_image implementation.
Regards,
Santhosh.
> +
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] spl: Add generic SPL MTD loader support
2026-02-20 3:12 [PATCH v2] spl: Add generic SPL MTD loader support Fabio Estevam
2026-02-20 3:52 ` Sean Anderson
2026-02-20 7:20 ` Santhosh Kumar K
@ 2026-02-25 15:46 ` Quentin Schulz
2 siblings, 0 replies; 10+ messages in thread
From: Quentin Schulz @ 2026-02-25 15:46 UTC (permalink / raw)
To: Fabio Estevam, michael
Cc: u-boot, trini, seanga2, dinesh.maniyam, a-dutta, a-nandan, jonas,
Fabio Estevam
Hi Fabio,
On 2/20/26 4:12 AM, Fabio Estevam wrote:
> From: Fabio Estevam <festevam@nabladev.com>
>
> 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
>
Missing update to docs (at the very least in
doc/device-tree-bindings/config.txt). I'm also not entirely sure we
should have two loaders use the same property for different media.
What happens if you have a system with SPI NOR and MTD support but the
payload is at a different offset? Some Rockchip platforms have support
for SPI flashes and NANDs, e.g. RK3568 to only name one. It seems it's
possible to have both a SPI flash and NAND flash according to the
datasheet and VCCIO2 IO block in Radxa Rock 3A schematics (the PX30
datasheet mentions support for both as well but I only saw the same pins
for both controllers).
> 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 <festevam@nabladev.com>
> ---
> Changes since v1:
> - Use uclass_get_device_by_seq().
> - Use puts() instead of debug() for error.
> - Include the new loader to include/spl_load.h.
> - Introduce SPL_MTD_SPI_NAND.
>
> common/spl/Kconfig | 30 ++++++++++++++
> common/spl/Makefile | 1 +
> common/spl/spl_mtd.c | 83 +++++++++++++++++++++++++++++++++++++++
> drivers/mtd/Makefile | 1 +
> drivers/mtd/nand/Makefile | 4 +-
> include/spl_load.h | 1 +
> 6 files changed, 119 insertions(+), 1 deletion(-)
> create mode 100644 common/spl/spl_mtd.c
>
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index 2998b7acb75f..16dbc5b54324 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -933,6 +933,12 @@ config SYS_MMCSD_FS_BOOT_PARTITION
> used in fs mode.
> Use -1 as a special value to use the first bootable partition.
>
> +config SYS_SPL_MTD_SEQ
> + int "MTD device number for the SPL load"
> + default 0
> + help
> + MTD device number used for the SPL load.
> +
> config SPL_MMC_TINY
> bool "Tiny MMC framework in SPL"
> depends on SPL_MMC
> @@ -1578,6 +1584,30 @@ config SPL_SPI_LOAD
>
> endif # SPL_SPI_FLASH_SUPPORT
>
> +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 the next stage from an MTD device
> + using the MTD subsystem in SPL.
> +
> + This supports raw NAND and SPI NAND devices.
> +
> +config SPL_MTD_SPI_NAND
> + bool "Enable SPI NAND support in SPL"
> + depends on SPL_MTD_LOAD
> + select MTD_SPI_NAND
> + help
> + Build SPI NAND support for SPL.
> +
> +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.
> +
Specify this can be overridden in DT with the DT property you read in
the driver.
Cheers,
Quentin
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-02-26 13:43 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-20 3:12 [PATCH v2] spl: Add generic SPL MTD loader support Fabio Estevam
2026-02-20 3:52 ` Sean Anderson
2026-02-20 14:35 ` Tom Rini
2026-02-25 19:45 ` Sean Anderson
2026-02-26 0:08 ` Fabio Estevam
2026-02-26 5:10 ` Sean Anderson
2026-02-26 5:34 ` Maniyam, Dinesh
2026-02-26 12:04 ` Fabio Estevam
2026-02-20 7:20 ` Santhosh Kumar K
2026-02-25 15:46 ` Quentin Schulz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox