From: Dinesh Maniyam <[email protected]>

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 <[email protected]>
---
 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

Reply via email to