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 <an...@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

Reply via email to