[PATCH 1/2] spl: Add A/B sector mode for mmc raw mode

Andri Yngvason andri at yngvason.is
Thu Jul 31 20:15:32 CEST 2025


This makes it possible to select between 2 raw sectors from which
to boot U-Boot Proper by writing to one pre-defined sector.

If the first byte of the sector contains the value 1, SPL will load
U-Boot Proper. The second byte, if set to 1 or 2, instructs SPL to try
loading only once from A or B, respectively.

Signed-off-by: Andri Yngvason <andri at yngvason.is>
---
 common/spl/Kconfig   | 28 +++++++++++++++++--
 common/spl/spl_mmc.c | 66 ++++++++++++++++++++++++++++++++++++++++++--
 include/spl.h        |  1 +
 3 files changed, 90 insertions(+), 5 deletions(-)

diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index ab05536bd02..706f7db1225 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -565,6 +565,14 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
 	  Use sector number for specifying U-Boot location on MMC/SD in
 	  raw mode.
 
+config SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB
+	bool "MMC raw mode: by sector with A/B selection"
+	select SPL_LOAD_BLOCK
+	select SPL_MMC_WRITE
+	help
+	  Use sector numbers for specifying U-Boot location on MMC/SD in
+	  raw mode. Allows selecting between two sectors.
+
 config SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
 	bool "MMC raw mode: by partition"
 	select SPL_LOAD_BLOCK
@@ -583,7 +591,8 @@ endchoice
 
 config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
 	hex "Address on the MMC to load U-Boot from"
-	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR || \
+		   SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB
 	default 0x40 if ARCH_SUNXI
 	default 0x75 if ARCH_DAVINCI
 	default 0x8a if ARCH_MX6 || ARCH_MX7
@@ -598,9 +607,24 @@ config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
 	  Address on the MMC to load U-Boot from, when the MMC is being used
 	  in raw mode. Units: MMC sectors (1 sector = 512 bytes).
 
+config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_B
+	hex "Secondary address on the MMC to load U-Boot from"
+	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB
+	help
+	  Address on the MMC to load secondary U-Boot from, when the MMC is
+	  being used in raw mode. Units: MMC sectors (1 sector = 512 bytes).
+
+config SYS_MMCSD_RAW_MODE_U_BOOT_AB_CONTROL_SECTOR
+	hex "Raw MMC A/B boot control sector"
+	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB
+	help
+	  Location of A/B bool control sector on the MMC. The contents of this
+	  sector control from which sector U-Boot is loaded.
+
 config SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET
 	hex "U-Boot main hardware partition image offset"
-	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+	depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR || \
+		   SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB
 	default 0x10 if ARCH_SUNXI
 	default 0x0
 	help
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index d06f9f0dee6..f4a1a3425b5 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -29,7 +29,8 @@ static ulong h_spl_load_read(struct spl_load_info *load, ulong off,
 
 static __maybe_unused unsigned long spl_mmc_raw_uboot_offset(int part)
 {
-#if IS_ENABLED(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR)
+#if IS_ENABLED(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR) || \
+	IS_ENABLED(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB)
 	if (part == 0)
 		return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET;
 #endif
@@ -137,7 +138,8 @@ static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
 		return ret;
 	}
 
-#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+#if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR) || \
+	defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB)
 	return mmc_load_image_raw_sector(spl_image, bootdev, mmc, info.start + sector);
 #else
 	return mmc_load_image_raw_sector(spl_image, bootdev, mmc, info.start);
@@ -270,6 +272,8 @@ u32 __weak spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)
 	return MMCSD_MODE_FS;
 #elif defined(CONFIG_SUPPORT_EMMC_BOOT)
 	return MMCSD_MODE_EMMCBOOT;
+#elif defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB)
+	return MMCSD_MODE_RAW_AB;
 #else
 	return MMCSD_MODE_RAW;
 #endif
@@ -323,6 +327,53 @@ int __weak spl_mmc_emmc_boot_partition(struct mmc *mmc)
 	return default_spl_mmc_emmc_boot_partition(mmc);
 }
 
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB
+unsigned long spl_mmc_get_raw_ab_sector(struct mmc *mmc, unsigned long raw_sect)
+{
+	u8 buf[512];
+	int ret = blk_dread(mmc_get_blk_desc(mmc),
+			CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_AB_CONTROL_SECTOR,
+			1, buf);
+	if (ret < 0) {
+		puts("Failed to read mmc a/b control sector\n");
+		log_debug("(error=%d)\n", ret);
+		goto out;
+	}
+
+	switch (buf[1]) {
+	case 1:
+		raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR;
+		puts("Trying to boot from mmc raw sector A\n");
+		break;
+	case 2:
+		raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_B;
+		puts("Trying to boot from mmc raw sector B\n");
+		break;
+	default:
+		if (buf[0] != 1) {
+			raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR;
+			puts("Selected mmc raw sector A\n");
+		} else {
+			raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_B;
+			puts("Selected mmc raw sector B\n");
+		}
+		return raw_sect;
+	}
+
+	buf[1] = 0xff;
+	ret = blk_dwrite(mmc_get_blk_desc(mmc),
+			 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_AB_CONTROL_SECTOR,
+			 1, buf);
+	if (ret < 0) {
+		puts("Failed to update mmc a/b control sector\n");
+		log_debug("(error=%d)\n", ret);
+	}
+
+out:
+	return raw_sect;
+}
+#endif
+
 static int spl_mmc_get_mmc_devnum(struct mmc *mmc)
 {
 	struct blk_desc *block_dev;
@@ -385,6 +436,14 @@ int spl_mmc_load(struct spl_image_info *spl_image,
 			return ret;
 		}
 		/* Fall through */
+#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB
+	case MMCSD_MODE_RAW_AB:
+		debug("spl: mmc boot mode: raw a/b\n");
+
+		raw_sect = spl_mmc_get_raw_ab_sector(mmc, raw_sect);
+
+		fallthrough;
+#endif
 	case MMCSD_MODE_RAW:
 		debug("spl: mmc boot mode: raw\n");
 
@@ -403,7 +462,8 @@ int spl_mmc_load(struct spl_image_info *spl_image,
 		if (!ret)
 			return 0;
 #endif
-#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
+#if defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR) || \
+	defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB)
 		ret = mmc_load_image_raw_sector(spl_image, bootdev, mmc,
 						raw_sect +
 						spl_mmc_raw_uboot_offset(part));
diff --git a/include/spl.h b/include/spl.h
index 7c10c7f792e..7736b00c474 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -28,6 +28,7 @@ struct legacy_img_hdr;
 #define MMCSD_MODE_RAW		1
 #define MMCSD_MODE_FS		2
 #define MMCSD_MODE_EMMCBOOT	3
+#define MMCSD_MODE_RAW_AB	4
 
 struct blk_desc;
 struct legacy_img_hdr;
-- 
2.50.0



More information about the U-Boot mailing list