[PATCH 6/8] arm: socfpga: rsu: Add SPL multiboot SSBL selection

dinesh.maniyam at altera.com dinesh.maniyam at altera.com
Tue Jun 30 08:55:22 CEST 2026


From: Dinesh Maniyam <dinesh.maniyam at altera.com>

Add the SOCFPGA_RSU_MULTIBOOT feature so the SPL selects the U-Boot
proper (SSBL) image, environment and FIT that pair with the RSU
sub-partition the SPL itself booted from. rsu_spl.c reads the RSU
sub-partition table (SPT), locates the SSBL.<slot> partition matching
the running SPL slot and exposes:

  - spl_spi_get_uboot_offs()  : SSBL offset for SPI boot,
  - rsu_spl_mmc_filename()    : u-boot_<slot>.itb/.img for FAT/MMC boot,
  - rsu_spl_mmc_env_name()    : matching environment file name,
  - env_sf_get_env_offset()   : environment offset within the SSBL slot.

The generic SPL/env code grows small, default-off hooks for this:
spl_mmc.c and env/fat.c call weak filename helpers (default -ENOENT,
overridden by rsu_spl.c), and env/sf.c gains a weak env_sf_get_env_offset()
helper (default CONFIG_ENV_OFFSET) so the SPI environment offset can be
computed at runtime instead of redefining the CONFIG symbol.

SPL_SOCFPGA_RSU_SSBL_FALLBACK bounds the SSBL slot size used when the
SPT lookup fails so the environment-offset math cannot underflow.

Signed-off-by: Dinesh Maniyam <dinesh.maniyam at altera.com>
---
 arch/arm/mach-socfpga/Kconfig                |  21 +
 arch/arm/mach-socfpga/Makefile               |   5 +
 arch/arm/mach-socfpga/include/mach/rsu_spl.h |  14 +
 arch/arm/mach-socfpga/rsu_spl.c              | 388 +++++++++++++++++++
 common/spl/spl_mmc.c                         |  24 +-
 env/fat.c                                    |  64 ++-
 env/sf.c                                     |  33 +-
 include/env_internal.h                       |  11 +
 8 files changed, 541 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm/mach-socfpga/include/mach/rsu_spl.h
 create mode 100644 arch/arm/mach-socfpga/rsu_spl.c

diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index e9d675344f7..889dcc825b0 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -28,6 +28,27 @@ config SOCFPGA_RSU_MULTIFLASH
 	  spans the RSU sub-partition layout across all of them. Leave
 	  disabled for the common single-flash layout.
 
+config SOCFPGA_RSU_MULTIBOOT
+	bool "Enable RSU SPL multiboot SSBL selection"
+	depends on ARCH_SOCFPGA_SOC64 && SPL && SPI_FLASH
+	help
+	  Select the second-stage boot loader (SSBL, i.e. U-Boot proper)
+	  image based on the RSU sub-partition the SPL was loaded from.
+	  SPL reads the RSU sub-partition table (SPT) to locate the SSBL
+	  partition that pairs with the currently running SPL image and
+	  loads U-Boot proper, its environment and FIT from there. This
+	  keeps a multi-image RSU layout self-consistent across updates.
+
+config SPL_SOCFPGA_RSU_SSBL_FALLBACK
+	int "RSU SPL fallback SSBL slot size (MiB)"
+	depends on SOCFPGA_RSU_MULTIBOOT
+	default 8
+	range 1 64
+	help
+	  Conservative upper bound (in MiB) for the SSBL slot used when the
+	  SPT lookup fails, so the environment-offset math in env/sf.c cannot
+	  underflow. Override only if the board's SSBL exceeds the default.
+
 config SOCFPGA_SECURE_VAB_AUTH
 	bool "Enable boot image authentication with Secure Device Manager"
 	depends on ARCH_SOCFPGA_AGILEX || ARCH_SOCFPGA_N5X || \
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 109af31ceb8..14410cee149 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -147,6 +147,11 @@ obj-$(CONFIG_ARMV8_PSCI)	+= smc_rsu_s10.o
 endif
 endif
 
+# RSU SPL multiboot selects the SSBL (U-Boot proper) image to load; the
+# helpers are consumed from both SPL (spl_mmc/spl_spi) and U-Boot proper
+# (env/fat, env/sf), so build for both.
+obj-$(CONFIG_SOCFPGA_RSU_MULTIBOOT)	+= rsu_spl.o
+
 ifdef CONFIG_ARCH_SOCFPGA_GEN5
 # QTS-generated config file wrappers
 CFLAGS_wrap_iocsr_config.o	+= -I$(srctree)/board/$(BOARDDIR)
diff --git a/arch/arm/mach-socfpga/include/mach/rsu_spl.h b/arch/arm/mach-socfpga/include/mach/rsu_spl.h
new file mode 100644
index 00000000000..c9507b4d934
--- /dev/null
+++ b/arch/arm/mach-socfpga/include/mach/rsu_spl.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022-2023 Intel Corporation <www.intel.com>
+ */
+
+#ifndef _RSU_S10_SPL_H_
+#define _RSU_S10_SPL_H_
+
+#include <asm/arch/rsu_s10.h>
+
+u32 rsu_spl_ssbl_address(bool is_qspi_imge_check);
+u32 rsu_spl_ssbl_size(bool is_qspi_imge_check);
+
+#endif /* _RSU_S10_SPL_H_ */
diff --git a/arch/arm/mach-socfpga/rsu_spl.c b/arch/arm/mach-socfpga/rsu_spl.c
new file mode 100644
index 00000000000..a3145cce9c3
--- /dev/null
+++ b/arch/arm/mach-socfpga/rsu_spl.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022-2023 Intel Corporation <www.intel.com>
+ * Copyright (C) 2026 Altera Corporation <www.altera.com>
+ */
+
+#include <env_internal.h>
+#include <log.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <stdio.h>
+#include <dm/device.h>
+#include <asm/arch/mailbox_s10.h>
+#include <asm/arch/rsu.h>
+#include <asm/arch/rsu_flash_if.h>
+#include <asm/arch/rsu_s10.h>
+#include <asm/arch/rsu_spl.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <linux/string.h>
+
+#define SSBL_PART_PREFIX	"SSBL."
+#define RSU_ADDR_MASK		0xFFFFFFFF
+#define RSU_ADDR_SHIFT		32
+#define UBOOT_ENV_EXT		".env"
+#define UBOOT_IMG_EXT		".img"
+#define UBOOT_ITB_EXT		".itb"
+#define UBOOT_ENV_PREFIX	"u-boot_"
+#define UBOOT_ENV_REDUND_PREFIX	"u-boot-redund_"
+#define UBOOT_PREFIX		"u-boot_"
+#define FACTORY_IMG_NAME	"FACTORY_IM"
+
+#define RSU_SPL_SPT_SLOT_MAX	127
+
+/* Bytes; pairs with CONFIG_SYS_SPI_U_BOOT_OFFS so env-offset math cannot underflow. */
+#define RSU_SPL_SSBL_FALLBACK_BYTES \
+	(CONFIG_SPL_SOCFPGA_RSU_SSBL_FALLBACK * SZ_1M)
+
+static unsigned int rsu_spl_spt_nentries(const struct socfpga_rsu_s10_spt *spt)
+{
+	if (spt->magic_number != RSU_S10_SPT_MAGIC_NUMBER)
+		return 0;
+	if (spt->entries > RSU_SPL_SPT_SLOT_MAX)
+		return RSU_SPL_SPT_SLOT_MAX;
+	return spt->entries;
+}
+
+static int get_spl_slot(struct socfpga_rsu_s10_spt *rsu_spt,
+			size_t rsu_spt_size, int *crt_spt_index)
+{
+	u32 rsu_spt0_offset = 0, rsu_spt1_offset = 0;
+	u32 spt_offset[4] = {0};
+	struct rsu_status_info rsu_status = {0};
+#ifdef CONFIG_DM_SPI_FLASH
+	struct udevice *flash;
+#else
+	struct spi_flash *flash;
+#endif
+	unsigned int nentries;
+	int i;
+	int pret;
+	int ret = -EINVAL;
+
+	/* get rsu status */
+	if (mbox_rsu_status((u32 *)&rsu_status, sizeof(rsu_status) / 4)) {
+		puts("RSU: Error - mbox_rsu_status failed!\n");
+		return -EOPNOTSUPP;
+	}
+
+	/* get spt offsets */
+	if (mbox_rsu_get_spt_offset(spt_offset, 4)) {
+		puts("RSU: Error - mbox_rsu_get_spt_offset failed!\n");
+		return -EINVAL;
+	}
+
+	rsu_spt0_offset = spt_offset[SPT0_INDEX];
+	rsu_spt1_offset = spt_offset[SPT1_INDEX];
+
+	pret = rsu_mtd_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SOCFPGA_RSU_SF_CS, &flash);
+	if (pret) {
+		printf("RSU: Error - rsu_mtd_probe failed (%d)!\n", pret);
+		return pret;
+	}
+
+	/* read spt0 */
+	pret = rsu_mtd_read(flash, rsu_spt0_offset, rsu_spt_size, rsu_spt);
+	if (pret) {
+		printf("RSU: Error - rsu_mtd_read spt0 failed (%d)!\n", pret);
+		ret = pret;
+		goto out;
+	}
+
+	/* if spt0 does not have the correct magic number */
+	if (rsu_spt->magic_number != RSU_S10_SPT_MAGIC_NUMBER) {
+		/* read spt1 */
+		pret = rsu_mtd_read(flash, rsu_spt1_offset, rsu_spt_size, rsu_spt);
+		if (pret) {
+			printf("RSU: Error - rsu_mtd_read spt1 failed (%d)!\n",
+			       pret);
+			ret = pret;
+			goto out;
+		}
+
+		/* bail out if spt1 does not have the correct magic number */
+		if (rsu_spt->magic_number != RSU_S10_SPT_MAGIC_NUMBER) {
+			printf("RSU: Error: spt table magic number not match 0x%08x!\n",
+			       rsu_spt->magic_number);
+			goto out;
+		}
+	}
+
+	nentries = rsu_spl_spt_nentries(rsu_spt);
+	if (!nentries)
+		goto out;
+
+	/* Flash may omit NUL in 16-byte names; cap strings for strstr/printf safety */
+	for (i = 0; i < (int)nentries; i++)
+		rsu_spt->spt_slot[i].name[MAX_PART_NAME_LENGTH - 1] = '\0';
+
+	/* display status */
+	debug("RSU current image:  0x%08x\n", (u32)rsu_status.current_image);
+	debug("RSU state:          0x%08x\n", rsu_status.state);
+	debug("RSU error location: 0x%08x\n", rsu_status.error_location);
+	debug("RSU error details:  0x%08x\n", rsu_status.error_details);
+
+	/* display partitions */
+	for (i = 0; i < (int)nentries; i++) {
+		debug("RSU: Partition '%s' start=0x%08x length=0x%08x\n",
+		      rsu_spt->spt_slot[i].name, rsu_spt->spt_slot[i].offset[0],
+		      rsu_spt->spt_slot[i].length);
+	}
+
+	/* locate the SPT entry for currently loaded image */
+	for (i = 0; i < (int)nentries; i++) {
+		if (((rsu_status.current_image & RSU_ADDR_MASK) ==
+			rsu_spt->spt_slot[i].offset[0]) &&
+		   ((rsu_status.current_image >> RSU_ADDR_SHIFT) ==
+			rsu_spt->spt_slot[i].offset[1])) {
+			*crt_spt_index = i;
+			ret = 0;
+			goto out;
+		}
+	}
+
+	puts("RSU: Error - could not locate SPL partition in the SPT table!\n");
+out:
+	/* Release the probed SPI flash; no-op under DM_SPI_FLASH. */
+	rsu_mtd_unclaim(flash);
+	return ret;
+}
+
+static int get_ssbl_slot(struct socfpga_rsu_s10_spt_slot *rsu_ssbl_slot)
+{
+	struct socfpga_rsu_s10_spt rsu_spt = {0};
+	int crt_spt_index = -EINVAL;
+	char *result;
+	unsigned int nentries;
+	int i, ret;
+
+	rsu_ssbl_slot->offset[0] = -EINVAL;
+
+	ret = get_spl_slot(&rsu_spt, sizeof(rsu_spt), &crt_spt_index);
+	if (ret) {
+		puts("RSU: Error - could not locate partition in the SPT table!\n");
+		return ret;
+	}
+
+	nentries = rsu_spl_spt_nentries(&rsu_spt);
+
+	/* locate the u-boot proper(SSBL) partition and return its address */
+	for (i = 0; i < (int)nentries; i++) {
+		/* get the substring ptr to the first occurrence of SSBL. prefix */
+		result = strstr(rsu_spt.spt_slot[i].name, SSBL_PART_PREFIX);
+
+		/* skip if not found the SSBL prefix */
+		if (!result)
+			continue;
+
+		/* check if the prefix is located at the first */
+		if (result == rsu_spt.spt_slot[i].name) {
+			/* move to the substring after SSBL. prefix */
+			result += strlen(SSBL_PART_PREFIX);
+
+			/* compare SPL's spt name after the prefix */
+			if (!strncmp(result, rsu_spt.spt_slot[crt_spt_index].name,
+				     MAX_PART_NAME_LENGTH - strlen(SSBL_PART_PREFIX)) ||
+			    !strncmp(result, rsu_spt.spt_slot[crt_spt_index].name,
+				     strlen(FACTORY_IMG_NAME))) {
+				printf("RSU: found SSBL partition %s at address 0x%08x.\n",
+				       result, (int)rsu_spt.spt_slot[i].offset[0]);
+				memcpy(rsu_ssbl_slot, &rsu_spt.spt_slot[i],
+				       sizeof(struct socfpga_rsu_s10_spt_slot));
+
+				return 0;
+			}
+		}
+	}
+
+	/* fail to find u-boot proper(SSBL) */
+	if (crt_spt_index >= 0 && crt_spt_index < (int)nentries)
+		printf("RSU: Error - could not find u-boot proper partition SSBL.%s!\n",
+		       rsu_spt.spt_slot[crt_spt_index].name);
+	else
+		puts("RSU: Error - could not find u-boot proper (SSBL) partition!\n");
+
+	return -EINVAL;
+}
+
+int rsu_spl_mmc_filename(char *filename, int max_size)
+{
+	struct socfpga_rsu_s10_spt rsu_spt = {0};
+	int crt_spt_index = -EINVAL;
+	int ret;
+
+	if (!filename) {
+		printf("RSU: filename is NULL!\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * max_size is `int` for ABI reasons but used as size_t below;
+	 * reject non-positive up front so it cannot sign-extend.
+	 */
+	if (max_size <= 0)
+		return -EINVAL;
+
+	if ((strlen(UBOOT_PREFIX) + MAX_PART_NAME_LENGTH + strlen(UBOOT_ITB_EXT))
+	     > (size_t)max_size)
+		return -ENAMETOOLONG;
+
+	ret = get_spl_slot(&rsu_spt, sizeof(rsu_spt), &crt_spt_index);
+	if (ret) {
+		if (ret == -EOPNOTSUPP) {
+			puts("RSU: Error - mbox_rsu_status failed! Check for RSU image.\n");
+			return -EOPNOTSUPP;
+		}
+
+		panic("ERROR: could not find u-boot proper (SSBL) for MMC load");
+	}
+
+	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT))
+		ret = snprintf(filename, (size_t)max_size, "%s%s%s", UBOOT_PREFIX,
+			       rsu_spt.spt_slot[crt_spt_index].name, UBOOT_ITB_EXT);
+	else
+		ret = snprintf(filename, (size_t)max_size, "%s%s%s", UBOOT_PREFIX,
+			       rsu_spt.spt_slot[crt_spt_index].name, UBOOT_IMG_EXT);
+
+	if (ret < 0 || ret >= max_size)
+		return -ENAMETOOLONG;
+
+	printf("%s, filename: %s\n", __func__, filename);
+	return 0;
+}
+
+int rsu_spl_mmc_env_name(char *filename, int max_size, bool redund)
+{
+	struct socfpga_rsu_s10_spt rsu_spt = {0};
+	int crt_spt_index = -EINVAL;
+	int ret;
+
+	if (!filename) {
+		printf("RSU: filename is NULL!\n");
+		return -ENOENT;
+	}
+
+	/* Same signed/unsigned guard as rsu_spl_mmc_filename(). */
+	if (max_size <= 0)
+		return -EINVAL;
+
+	/*
+	 * Only one of UBOOT_ENV_REDUND_PREFIX / UBOOT_ENV_PREFIX is used
+	 * per call; size against the chosen one so a buffer that actually
+	 * fits is not falsely rejected.
+	 */
+	if ((strlen(redund ? UBOOT_ENV_REDUND_PREFIX : UBOOT_ENV_PREFIX) +
+	     MAX_PART_NAME_LENGTH + strlen(UBOOT_ENV_EXT)) > (size_t)max_size)
+		return -ENAMETOOLONG;
+
+	ret = get_spl_slot(&rsu_spt, sizeof(rsu_spt), &crt_spt_index);
+	if (ret) {
+		if (ret == -EOPNOTSUPP) {
+			puts("RSU: Error - mbox_rsu_status failed! Check for RSU image.\n");
+			return -EOPNOTSUPP;
+		}
+
+		/* should throw error if cannot find u-boot proper(SSBL) in MMC */
+		printf("ERROR: could not find u-boot.env!");
+		return ret;
+	}
+
+	if (redund)
+		ret = snprintf(filename, (size_t)max_size, "%s%s%s",
+			       UBOOT_ENV_REDUND_PREFIX,
+			       rsu_spt.spt_slot[crt_spt_index].name,
+			       UBOOT_ENV_EXT);
+	else
+		ret = snprintf(filename, (size_t)max_size, "%s%s%s",
+			       UBOOT_ENV_PREFIX,
+			       rsu_spt.spt_slot[crt_spt_index].name,
+			       UBOOT_ENV_EXT);
+
+	if (ret < 0 || ret >= max_size)
+		return -ENAMETOOLONG;
+
+	printf("%s, filename: %s\n", __func__, filename);
+	return 0;
+}
+
+u32 rsu_spl_ssbl_address(bool is_qspi_imge_check)
+{
+	int ret;
+	struct socfpga_rsu_s10_spt_slot rsu_ssbl_slot = {0};
+
+	ret = get_ssbl_slot(&rsu_ssbl_slot);
+	if (ret) {
+		if (ret == -EOPNOTSUPP) {
+			puts("RSU: Error - mbox_rsu_status failed! Check for RSU image.\n");
+			return CONFIG_SYS_SPI_U_BOOT_OFFS;
+		}
+
+		/* should throw error if cannot find u-boot proper(SSBL) address */
+		if (is_qspi_imge_check) {
+			panic("ERROR: could not find u-boot proper(SSBL) address!");
+		} else {
+			printf("ERROR: could not find u-boot env address!");
+			return CONFIG_SYS_SPI_U_BOOT_OFFS;
+		}
+	}
+
+	if (!rsu_ssbl_slot.length) {
+		if (is_qspi_imge_check)
+			panic("ERROR: could not find u-boot proper(SSBL) size!");
+		/* No log here; the size() variant reports it. */
+		return CONFIG_SYS_SPI_U_BOOT_OFFS;
+	}
+
+	printf("RSU: Success found SSBL at offset: %08x.\n",
+	       rsu_ssbl_slot.offset[0]);
+	return rsu_ssbl_slot.offset[0];
+}
+
+u32 rsu_spl_ssbl_size(bool is_qspi_imge_check)
+{
+	int ret;
+	struct socfpga_rsu_s10_spt_slot rsu_ssbl_slot = {0};
+
+	/* check for valid u-boot proper(SSBL) address for the size */
+	ret = get_ssbl_slot(&rsu_ssbl_slot);
+	if (ret) {
+		if (ret == -EOPNOTSUPP) {
+			printf("ERROR: Invalid address, could not retrieve SSBL size!");
+			return RSU_SPL_SSBL_FALLBACK_BYTES;
+		}
+
+		/* should throw error if cannot find u-boot proper(SSBL) address */
+		if (is_qspi_imge_check) {
+			panic("ERROR: could not find u-boot proper(SSBL) address!");
+		} else {
+			printf("ERROR: could not find u-boot env address!");
+			return RSU_SPL_SSBL_FALLBACK_BYTES;
+		}
+	}
+
+	if (!rsu_ssbl_slot.length) {
+		/* throw error if cannot find u-boot proper(SSBL) size */
+		printf("ERROR: could not retrieve u-boot proper(SSBL) size!");
+		if (is_qspi_imge_check)
+			panic("ERROR: could not find u-boot proper(SSBL) size!");
+		return RSU_SPL_SSBL_FALLBACK_BYTES;
+	}
+
+	printf("RSU: Success found SSBL with length: %08x.\n",
+	       rsu_ssbl_slot.length);
+	return rsu_ssbl_slot.length;
+}
+
+unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash)
+{
+	return rsu_spl_ssbl_address(true);
+}
+
+u32 env_sf_get_env_offset(void)
+{
+	/* Place the environment at the tail of the selected SSBL slot. */
+	return rsu_spl_ssbl_address(false) + rsu_spl_ssbl_size(false) -
+	       CONFIG_ENV_SIZE;
+}
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index cc16709dc9b..e4002591605 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -11,6 +11,7 @@
 #include <spl.h>
 #include <spl_load.h>
 #include <linux/compiler.h>
+#include <linux/sizes.h>
 #include <errno.h>
 #include <mmc.h>
 #include <image.h>
@@ -456,11 +457,32 @@ int spl_mmc_load(struct spl_image_info *spl_image,
 	return ret;
 }
 
+#if IS_ENABLED(CONFIG_SOCFPGA_RSU_MULTIBOOT)
+__weak int rsu_spl_mmc_filename(char *filename, int max_size)
+{
+	return -ENOENT;
+}
+#endif
+
 int spl_mmc_load_image(struct spl_image_info *spl_image,
 		       struct spl_boot_device *bootdev)
 {
+#if IS_ENABLED(CONFIG_SOCFPGA_RSU_MULTIBOOT)
+	char filename[SZ_256] = {0};
+	int ret;
+
+	ret = rsu_spl_mmc_filename(filename, SZ_256);
+	if (ret) {
+		printf("RSU: multiboot filename not found\n");
+		return ret;
+	}
+
+	printf("%s: boot from filename: %s\n", __func__, filename);
+#endif
 	return spl_mmc_load(spl_image, bootdev,
-#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
+#if IS_ENABLED(CONFIG_SOCFPGA_RSU_MULTIBOOT)
+			    filename,
+#elif defined(CONFIG_SPL_FS_LOAD_PAYLOAD_NAME)
 			    CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
 #else
 			    NULL,
diff --git a/env/fat.c b/env/fat.c
index 7e164822383..9490be7d6f9 100644
--- a/env/fat.c
+++ b/env/fat.c
@@ -22,6 +22,7 @@
 #include <virtio.h>
 #include <asm/cache.h>
 #include <asm/global_data.h>
+#include <linux/sizes.h>
 #include <linux/stddef.h>
 
 #ifdef CONFIG_XPL_BUILD
@@ -35,6 +36,37 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#if IS_ENABLED(CONFIG_SOCFPGA_RSU_MULTIBOOT)
+__weak int rsu_spl_mmc_env_name(char *filename, int max_size, bool redund)
+{
+	return -ENOENT;
+}
+#endif
+
+/*
+ * Resolve the FAT filename that holds the environment. With RSU multiboot
+ * the name is derived at runtime from the booted SSBL slot (written into
+ * @buf); otherwise it is the static CONFIG_ENV_FAT_FILE[_REDUND]. Returns
+ * NULL on failure.
+ */
+static const char *env_fat_filename(char *buf, int size, bool redund)
+{
+#if IS_ENABLED(CONFIG_SOCFPGA_RSU_MULTIBOOT)
+	if (rsu_spl_mmc_env_name(buf, size, redund)) {
+		printf("RSU: multiboot env filename not found\n");
+		return NULL;
+	}
+
+	return buf;
+#else
+#ifdef CONFIG_ENV_REDUNDANT
+	if (redund)
+		return CONFIG_ENV_FAT_FILE_REDUND;
+#endif
+	return CONFIG_ENV_FAT_FILE;
+#endif
+}
+
 __weak const char *env_fat_get_intf(void)
 {
 	return (const char *)CONFIG_ENV_FAT_INTERFACE;
@@ -62,13 +94,18 @@ static int env_fat_save(void)
 	env_t __aligned(ARCH_DMA_MINALIGN) env_new;
 	struct blk_desc *dev_desc = NULL;
 	struct disk_partition info;
-	const char *file = CONFIG_ENV_FAT_FILE;
+	char env_file[SZ_256] = {0};
+	const char *file;
 	int dev, part;
 	int err;
 	loff_t size;
 	const char *ifname = env_fat_get_intf();
 	const char *dev_and_part = env_fat_get_dev_part();
 
+	file = env_fat_filename(env_file, sizeof(env_file), false);
+	if (!file)
+		return 1;
+
 	err = env_export(&env_new);
 	if (err)
 		return err;
@@ -89,8 +126,11 @@ static int env_fat_save(void)
 	}
 
 #ifdef CONFIG_ENV_REDUNDANT
-	if (gd->env_valid == ENV_VALID)
-		file = CONFIG_ENV_FAT_FILE_REDUND;
+	if (gd->env_valid == ENV_VALID) {
+		file = env_fat_filename(env_file, sizeof(env_file), true);
+		if (!file)
+			return 1;
+	}
 #endif
 
 	err = file_fat_write(file, (void *)&env_new, 0, sizeof(env_t), &size);
@@ -120,6 +160,8 @@ static int env_fat_load(void)
 #endif
 	struct blk_desc *dev_desc = NULL;
 	struct disk_partition info;
+	char env_file[SZ_256] = {0};
+	const char *file;
 	int dev, part;
 	int err1;
 	const char *ifname = env_fat_get_intf();
@@ -162,9 +204,17 @@ static int env_fat_load(void)
 		goto err_env_relocate;
 	}
 
-	err1 = file_fat_read(CONFIG_ENV_FAT_FILE, buf1, CONFIG_ENV_SIZE);
+	file = env_fat_filename(env_file, sizeof(env_file), false);
+	if (!file)
+		goto err_env_relocate;
+
+	err1 = file_fat_read(file, buf1, CONFIG_ENV_SIZE);
 #ifdef CONFIG_ENV_REDUNDANT
-	err2 = file_fat_read(CONFIG_ENV_FAT_FILE_REDUND, buf2, CONFIG_ENV_SIZE);
+	file = env_fat_filename(env_file, sizeof(env_file), true);
+	if (!file)
+		goto err_env_relocate;
+
+	err2 = file_fat_read(file, buf2, CONFIG_ENV_SIZE);
 
 	err1 = (err1 >= 0) ? 0 : -1;
 	err2 = (err2 >= 0) ? 0 : -1;
@@ -175,8 +225,8 @@ static int env_fat_load(void)
 		 * This printf is embedded in the messages from env_save that
 		 * will calling it. The missing \n is intentional.
 		 */
-		printf("Unable to read \"%s\" from %s%d:%d... \n",
-			CONFIG_ENV_FAT_FILE, ifname, dev, part);
+		printf("Unable to read \"%s\" from %s%d:%d...\n",
+		       file, ifname, dev, part);
 		goto err_env_relocate;
 	}
 
diff --git a/env/sf.c b/env/sf.c
index 14c35324e64..6cdb0e4a632 100644
--- a/env/sf.c
+++ b/env/sf.c
@@ -38,6 +38,17 @@ static ulong env_new_offset	= CONFIG_ENV_OFFSET_REDUND;
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/*
+ * Offset of the primary environment within the SPI flash. Defaults to the
+ * static CONFIG_ENV_OFFSET, but boards may override this weak helper to
+ * compute the offset at runtime (e.g. RSU multiboot derives it from the
+ * SSBL slot the SPL booted from).
+ */
+__weak u32 env_sf_get_env_offset(void)
+{
+	return CONFIG_ENV_OFFSET;
+}
+
 __weak int spi_get_env_dev(void)
 {
 #ifdef CONFIG_ENV_SPI_BUS
@@ -98,9 +109,9 @@ static int env_sf_save(void)
 
 	if (gd->env_valid == ENV_VALID) {
 		env_new_offset = CONFIG_ENV_OFFSET_REDUND;
-		env_offset = CONFIG_ENV_OFFSET;
+		env_offset = env_sf_get_env_offset();
 	} else {
-		env_new_offset = CONFIG_ENV_OFFSET;
+		env_new_offset = env_sf_get_env_offset();
 		env_offset = CONFIG_ENV_OFFSET_REDUND;
 	}
 
@@ -182,7 +193,7 @@ static int env_sf_load(void)
 	if (ret)
 		goto out;
 
-	read1_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET,
+	read1_fail = spi_flash_read(env_flash, env_sf_get_env_offset(),
 				    CONFIG_ENV_SIZE, tmp_env1);
 	read2_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND,
 				    CONFIG_ENV_SIZE, tmp_env2);
@@ -217,7 +228,7 @@ static int env_sf_save(void)
 	/* Is the sector larger than the env (i.e. embedded) */
 	if (sect_size > CONFIG_ENV_SIZE) {
 		saved_size = sect_size - CONFIG_ENV_SIZE;
-		saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
+		saved_offset = env_sf_get_env_offset() + CONFIG_ENV_SIZE;
 		saved_buffer = malloc(saved_size);
 		if (!saved_buffer) {
 			ret = -ENOMEM;
@@ -237,14 +248,14 @@ static int env_sf_save(void)
 	sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, sect_size);
 
 	puts("Erasing SPI flash...");
-	ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET,
-		sector * sect_size);
+	ret = spi_flash_erase(env_flash, env_sf_get_env_offset(),
+			      sector * sect_size);
 	if (ret)
 		goto done;
 
 	puts("Writing to SPI flash...");
-	ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET,
-		CONFIG_ENV_SIZE, &env_new);
+	ret = spi_flash_write(env_flash, env_sf_get_env_offset(),
+			      CONFIG_ENV_SIZE, &env_new);
 	if (ret)
 		goto done;
 
@@ -284,7 +295,7 @@ static int env_sf_load(void)
 		goto out;
 
 	ret = spi_flash_read(env_flash,
-		CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf);
+		env_sf_get_env_offset(), CONFIG_ENV_SIZE, buf);
 	if (ret) {
 		env_set_default("spi_flash_read() failed", 0);
 		goto err_read;
@@ -314,7 +325,7 @@ static int env_sf_erase(void)
 		return ret;
 
 	memset(&env, 0, sizeof(env_t));
-	ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, &env);
+	ret = spi_flash_write(env_flash, env_sf_get_env_offset(), CONFIG_ENV_SIZE, &env);
 	if (ret)
 		goto done;
 
@@ -391,7 +402,7 @@ static int env_sf_init_early(void)
 	if (ret)
 		goto out;
 
-	read1_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET,
+	read1_fail = spi_flash_read(env_flash, env_sf_get_env_offset(),
 				    CONFIG_ENV_SIZE, tmp_env1);
 
 	if (IS_ENABLED(CONFIG_ENV_REDUNDANT)) {
diff --git a/include/env_internal.h b/include/env_internal.h
index 0589c435e84..8ce200fd6f1 100644
--- a/include/env_internal.h
+++ b/include/env_internal.h
@@ -273,6 +273,17 @@ const char *env_fat_get_intf(void);
  * Return: string of device and partition
  */
 char *env_fat_get_dev_part(void);
+
+/**
+ * env_sf_get_env_offset() - Provide the offset of the env in SPI flash
+ *
+ * It is a weak function allowing boards to override the default offset of
+ * the U-Boot environment in SPI flash (CONFIG_ENV_OFFSET) with a value
+ * computed at runtime, e.g. derived from the RSU multiboot SSBL slot.
+ *
+ * Return: byte offset of the primary environment within the SPI flash
+ */
+u32 env_sf_get_env_offset(void);
 #endif /* DO_DEPS_ONLY */
 
 #endif /* _ENV_INTERNAL_H_ */
-- 
2.43.7



More information about the U-Boot mailing list