[PATCH 2/2] Forward chosen raw mmc A/B sector to OS

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


This adds a property named u-boot,mmc-boot-sector to the /chosen node in
the device tree. It can be either "a" or "b", based on which sector was
chosen by the SPL to boot U-Boot Proper.

This makes it possible to check from the OS if an upgrade to U-Boot was
successful before committing to it.

The way this is intended to be used is as follows:

 - Write new U-Boot image to the sector that's currently unused
 - Write 00 XX to control sector, where XX = 1 for A and 2 for B
 - Reboot
 - If u-boot,mmc-boot-sector contains the correct value, update the
   control sector to boot from the new U-Boot.
 - If it contains the wrong value, then the update must have failed.

Signed-off-by: Andri Yngvason <andri at yngvason.is>
---
 boot/fdt_support.c   | 20 ++++++++++++++++++++
 common/bloblist.c    |  1 +
 common/spl/spl_mmc.c | 21 ++++++++++++++++++++-
 include/bloblist.h   |  1 +
 include/spl.h        |  9 +++++++++
 5 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/boot/fdt_support.c b/boot/fdt_support.c
index b7331bb76b3..309f3726314 100644
--- a/boot/fdt_support.c
+++ b/boot/fdt_support.c
@@ -27,6 +27,8 @@
 #include <fdtdec.h>
 #include <version.h>
 #include <video.h>
+#include <bloblist.h>
+#include <spl.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -342,6 +344,7 @@ int fdt_chosen(void *fdt)
 	int   nodeoffset;
 	int   err;
 	const char *str;		/* used to set string properties */
+	__maybe_unused struct spl_mmcsd_raw_ab_handoff *handoff;
 
 	err = fdt_check_header(fdt);
 	if (err < 0) {
@@ -396,6 +399,23 @@ int fdt_chosen(void *fdt)
 		return err;
 	}
 
+	if (IS_ENABLED(CONFIG_BLOBLIST) &&
+	    IS_ENABLED(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR_AB)) {
+		handoff = bloblist_find(BLOBLISTT_MMCSD_RAW_AB,
+					sizeof(struct spl_mmcsd_raw_ab_handoff));
+		if (handoff) {
+			err = fdt_setprop(fdt, nodeoffset, "u-boot,mmc-boot-sector",
+					  handoff->sector == SPL_MMCSD_RAW_B_SECTOR ? "b" : "a", 2);
+			if (err < 0) {
+				printf("WARNING: could not set u-boot,mmc-boot-sector %s.\n",
+				       fdt_strerror(err));
+				return err;
+			}
+		} else {
+			printf("WARNING: Missing mmc a/b boot sector\n");
+		}
+	}
+
 	return fdt_fixup_stdout(fdt, nodeoffset);
 }
 
diff --git a/common/bloblist.c b/common/bloblist.c
index 6e4f020d7c4..cafa2036084 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -61,6 +61,7 @@ static struct tag_name {
 	{ BLOBLISTT_U_BOOT_SPL_HANDOFF, "SPL hand-off" },
 	{ BLOBLISTT_VBE, "VBE" },
 	{ BLOBLISTT_U_BOOT_VIDEO, "SPL video handoff" },
+	{ BLOBLISTT_MMCSD_RAW_AB, "MMC raw A/B boot sector" },
 
 	/* BLOBLISTT_VENDOR_AREA */
 };
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index f4a1a3425b5..22cea00bc96 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -16,6 +16,7 @@
 #include <mmc.h>
 #include <image.h>
 #include <imx_container.h>
+#include <bloblist.h>
 
 static ulong h_spl_load_read(struct spl_load_info *load, ulong off,
 			     ulong size, void *buf)
@@ -330,6 +331,7 @@ int __weak spl_mmc_emmc_boot_partition(struct mmc *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)
 {
+	__maybe_unused struct spl_mmcsd_raw_ab_handoff *handoff;
 	u8 buf[512];
 	int ret = blk_dread(mmc_get_blk_desc(mmc),
 			CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_AB_CONTROL_SECTOR,
@@ -357,7 +359,7 @@ unsigned long spl_mmc_get_raw_ab_sector(struct mmc *mmc, unsigned long raw_sect)
 			raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_B;
 			puts("Selected mmc raw sector B\n");
 		}
-		return raw_sect;
+		goto out;
 	}
 
 	buf[1] = 0xff;
@@ -370,6 +372,23 @@ unsigned long spl_mmc_get_raw_ab_sector(struct mmc *mmc, unsigned long raw_sect)
 	}
 
 out:
+	if (IS_ENABLED(CONFIG_BLOBLIST)) {
+		ret = bloblist_ensure_size(BLOBLISTT_MMCSD_RAW_AB,
+					   sizeof(struct spl_mmcsd_raw_ab_handoff),
+					   0, (void **)&handoff);
+		if (ret)
+			return raw_sect;
+
+		switch (raw_sect) {
+		case CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR:
+			handoff->sector = SPL_MMCSD_RAW_A_SECTOR;
+			break;
+		case CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_B:
+			handoff->sector = SPL_MMCSD_RAW_B_SECTOR;
+			break;
+		}
+	}
+
 	return raw_sect;
 }
 #endif
diff --git a/include/bloblist.h b/include/bloblist.h
index f32faf78560..bf50b82ef3c 100644
--- a/include/bloblist.h
+++ b/include/bloblist.h
@@ -153,6 +153,7 @@ enum bloblist_tag_t {
 	BLOBLISTT_U_BOOT_SPL_HANDOFF	= 0xfff000, /* Hand-off info from SPL */
 	BLOBLISTT_VBE			= 0xfff001, /* VBE per-phase state */
 	BLOBLISTT_U_BOOT_VIDEO		= 0xfff002, /* Video info from SPL */
+	BLOBLISTT_MMCSD_RAW_AB		= 0xfff003, /* MMC A/B Sector from SPL */
 };
 
 /**
diff --git a/include/spl.h b/include/spl.h
index 7736b00c474..e1895db736b 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -804,6 +804,15 @@ struct spl_image_loader {
 			  struct spl_boot_device *bootdev);
 };
 
+enum spl_mmcsd_raw_ab_sector {
+	SPL_MMCSD_RAW_A_SECTOR = 0,
+	SPL_MMCSD_RAW_B_SECTOR,
+};
+
+struct spl_mmcsd_raw_ab_handoff {
+	enum spl_mmcsd_raw_ab_sector sector;
+};
+
 /* Helper function for accessing the name */
 static inline const char *spl_loader_name(const struct spl_image_loader *loader)
 {
-- 
2.50.0



More information about the U-Boot mailing list