Hi Fabio,

On 2/8/2026 10:26 PM, Fabio Estevam wrote:
> From: Fabio Estevam <[email protected]>
> 
> Add support for booting U-Boot SPL from SPI NAND devices
> using the MTD subsystem.
> 
>  - Introduce CONFIG_SPL_SPI_NAND_LOAD to enable SPL loading
>   from SPI NAND flash.
>  - Implement spl_spi_nand.c as a dedicated SPL loader that
>   reads the FIT image from SPI NAND via MTD.
>  - Update common/spl/Kconfig and Makefiles to include the
>   new loader in SPL builds.
>  - Adjust drivers/mtd/Makefile and drivers/mtd/nand/Makefile
>   to build the necessary SPI NAND MTD objects only when
>   CONFIG_SPL_SPI_NAND_LOAD is enabled, avoiding size impact
>   on other boards.
> 
> This allows boards like the Omega4 RV1103 to boot SPL directly
> from SPI NAND, keeping the SPL small and avoiding unnecessary
> inclusion of SPI NOR code.

The content in this patch seem very generic and could possible be sent
as a separate series that adds a generic SPL MTD loader.

There also seem to be another SPL NAND loader part of the series at [1]
that may be related.

[1] https://lore.kernel.org/all/[email protected]/

> 
> Signed-off-by: Fabio Estevam <[email protected]>
> ---
> Changes since v1:
> - None.
> 
>  common/spl/Kconfig        | 10 ++++-
>  common/spl/Makefile       |  1 +
>  common/spl/spl_spi_nand.c | 82 +++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/Makefile      |  1 +
>  drivers/mtd/nand/Makefile | 13 ++++++-
>  5 files changed, 105 insertions(+), 2 deletions(-)
>  create mode 100644 common/spl/spl_spi_nand.c
> 
> diff --git a/common/spl/Kconfig b/common/spl/Kconfig
> index 2998b7acb75f..126855b804ce 100644
> --- a/common/spl/Kconfig
> +++ b/common/spl/Kconfig
> @@ -1576,13 +1576,21 @@ config SPL_SPI_LOAD
>         Enable support for loading next stage, U-Boot or otherwise, from
>         SPI NOR in U-Boot SPL.
>  
> +config SPL_SPI_NAND_LOAD
> +     bool "Support loading from SPI NAND flash"
> +     depends on SPL
> +     depends on MTD && DM_MTD
> +     help
> +       Enable support for loading next stage, U-Boot or otherwise, from
> +       SPI NAND in U-Boot SPL.
> +
>  endif # SPL_SPI_FLASH_SUPPORT
>  
>  config SYS_SPI_U_BOOT_OFFS
>       hex "address of u-boot payload in SPI flash"
>       default 0x8000 if ARCH_SUNXI
>       default 0x0
> -     depends on SPL_SPI_LOAD || SPL_SPI_SUNXI
> +     depends on SPL_SPI_LOAD || SPL_SPI_NAND_LOAD || SPL_SPI_SUNXI
>       help
>        Address within SPI-Flash from where the u-boot payload is fetched
>        from.
> diff --git a/common/spl/Makefile b/common/spl/Makefile
> index 4c9482bd3096..4628902e7e31 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_)SPI_NAND_LOAD) += spl_spi_nand.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_spi_nand.c b/common/spl/spl_spi_nand.c
> new file mode 100644
> index 000000000000..20b877f75a05
> --- /dev/null
> +++ b/common/spl/spl_spi_nand.c
> @@ -0,0 +1,82 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * SPL loader for SPI NAND devices using the MTD subsystem.
> + *
> + * 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 <image.h>
> +#include <log.h>
> +#include <errno.h>
> +#include <spl.h>
> +#include <spl_load.h>
> +#include <asm/io.h>
> +#include <dm/device_compat.h>
> +#include <dm/ofnode.h>
> +#include <dm/uclass.h>
> +#include <mtd.h>
> +
> +static struct mtd_info *spl_spi_nand_get_mtd(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;
> +             if (device_is_compatible(dev, "spi-nand"))
> +                     return dev_get_uclass_priv(dev);

Is there a reason why you limit this to only spi-nand?

I think it would be better to pivot this into a more generic SPL MTD
loader.

> +     }
> +
> +     return NULL;
> +}
> +
> +static ulong spl_spinand_fit_read(struct spl_load_info *load, ulong offs,
> +                               ulong size, void *buf)

The _fit_ part can probably be dropped.

> +{
> +     struct mtd_info *mtd = load->priv;
> +     size_t retlen = 0;
> +     int ret;
> +
> +     ret = mtd_read(mtd, offs, size, &retlen, buf);
> +     if (ret && ret != -EUCLEAN) {

Maybe use mtd_is_bitflip(ret)

> +             printf("SPI NAND read failed offs=0x%lx size=0x%lx ret=%d\n",
> +                    offs, size, ret);
> +             return 0;
> +     }
> +     if (retlen != size)

Why do we need an error message above and not here?

> +             return 0;
> +
> +     return retlen;
> +}
> +
> +static int spl_spinand_load_image(struct spl_image_info *spl_image,
> +                               struct spl_boot_device *bootdev)
> +{
> +     struct spl_load_info load;
> +     struct mtd_info *mtd;
> +
> +     mtd = spl_spi_nand_get_mtd();
> +     if (!mtd) {
> +             puts("SPI NAND probe failed.\n");
> +             return -ENODEV;
> +     }
> +
> +     spl_load_init(&load, spl_spinand_fit_read, mtd, 1);

Should probably use mtd->writesize as bl_len.

        spl_load_init(&load, spl_mtd_read, mtd, mtd->writesize);

> +
> +     return spl_load(spl_image, bootdev, &load, 0, 
> CONFIG_SYS_SPI_U_BOOT_OFFS);

Suggest you could use something like following to closer match SPL flash.

        offset = CONFIG_SYS_SPI_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);

> +}
> +
> +/* Use priority 1 so that boards can override this */
> +SPL_LOAD_IMAGE_METHOD("SPI NAND", 1, BOOT_DEVICE_SPI, 
> spl_spinand_load_image);
> diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
> index ce05e206073d..a12d880a9e90 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_SPI_NAND_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..7cd2a5f1af9b 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -1,10 +1,21 @@
>  # 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),)

Having both XPL and TPL is redundant and could be cleaned up to just
have ($(CONFIG_XPL_BUILD),).

Regards,
Jonas

> +
> +# U-Boot proper
>  obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
>  obj-$(CONFIG_MTD_RAW_NAND) += raw/
>  obj-$(CONFIG_MTD_SPI_NAND) += spi/
> +
>  else
> +
> +# SPL / XPL / TPL
> +# SPL has no MTD_NAND_CORE symbol, so we must key off SPI NAND usage
> +obj-$(CONFIG_SPL_SPI_NAND_LOAD) += nandcore.o
> +obj-$(CONFIG_SPL_SPI_NAND_LOAD) += spi/
> +
> +# raw NAND still follows the normal SPL rule
>  obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += raw/
>  endif

Reply via email to