On 2/19/26 22:12, Fabio Estevam wrote:
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]>
---
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, [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;
+
+ 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