The am335x knows nothing about eMMC boot partitions, so in order to implement an update procedure of the bootloader which is robust against power failure or other interruptions, one must make use of the fact that ROM code on the am335x looks for a valid first stage bootloader at several different offsets. Updating that can then be implemented by (assume we put MLO at offsets 128K and 256K):
(1) At least one of the two slots must contain a valid header, since we successfully booted. Pick the other one. (2) Overwrite the first sector of the slot chosen in step (a) with all zeroes. (3) Write everything but the first sector to the chosen slot. (4) Write the first sector (containing the magic signature that the boot ROM uses to identify a valid image) to the chosen slot. (5) Repeat steps (2)-(4) for the other slot. It's not possible to simply write the whole MLO in one go, especially not when updating the 128K slot, because an interruption after the first sector is written would make the ROM code believe the image is valid. But this only caters for SPL itself; regardless of where SPL was loaded from, it would go on to load U-Boot proper from SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR. So in order to update the whole bootloader, we need to teach SPL to use a different offset for U-Boot proper depending on where SPL itself was loaded from (*). With that, the update procedure is just amended by a step (3a) Write U-Boot proper to the offset corresponding to the SPL slot being updated. We can know (*) because the ROM code sets a new bit in a certain "trace vector" before each successive attempt. Signed-off-by: Rasmus Villemoes <[email protected]> --- arch/arm/mach-omap2/Kconfig | 37 +++++++++++++++++++++++++++++++ arch/arm/mach-omap2/boot-common.c | 31 ++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index c07dd68e6ce..1e989ac48ac 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -156,6 +156,43 @@ config SYS_DEFAULT_LPDDR2_TIMINGS endchoice +config SPL_AM33XX_MMCSD_MULTIPLE + bool "Support multiple locations of next boot phase" + depends on AM33XX + depends on SPL_SYS_MMCSD_RAW_MODE + depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR + help + The boot ROM on the am33xx looks for the first stage + bootloader at several hard-coded offsets in the mmc device + (0, 128K, 256K, 384K) and uses the first location which has + a valid header. This can be used to implement failsafe + update of that first stage (SPL). But in order for the + update of the whole bootloader to be failsafe, SPL must load + U-Boot proper from a location dependent on where SPL itself + was loaded from. This option allows you to specify four + different offsets corresponding to the different places + where SPL could have been loaded from. + +if SPL_AM33XX_MMCSD_MULTIPLE + +config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_0K + hex "Address on the MMC to load U-Boot from when SPL was loaded from offset 0K" + default SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR + +config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_128K + hex "Address on the MMC to load U-Boot from when SPL was loaded from offset 128K" + default SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR + +config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_256K + hex "Address on the MMC to load U-Boot from when SPL was loaded from offset 256K" + default SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR + +config SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_384K + hex "Address on the MMC to load U-Boot from when SPL was loaded from offset 384K" + default SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR + +endif + source "arch/arm/mach-omap2/omap3/Kconfig" source "arch/arm/mach-omap2/omap5/Kconfig" diff --git a/arch/arm/mach-omap2/boot-common.c b/arch/arm/mach-omap2/boot-common.c index 95b44c8b1e5..88fa59feaf1 100644 --- a/arch/arm/mach-omap2/boot-common.c +++ b/arch/arm/mach-omap2/boot-common.c @@ -318,3 +318,34 @@ static void tee_image_process(ulong tee_image, size_t tee_size) } U_BOOT_FIT_LOADABLE_HANDLER(IH_TYPE_TEE, tee_image_process); #endif + +#ifdef CONFIG_SPL_AM33XX_MMCSD_MULTIPLE + +#define AM335X_TRACE_VECTOR2 0x4030CE44 + +unsigned long arch_spl_mmc_get_uboot_raw_sector(struct mmc *mmc, unsigned long raw_sect) +{ + u32 bits = *(u32 *)AM335X_TRACE_VECTOR2; + + bits &= 0xf000; + + /* + * The ROM code sets the "trial bit 3", bit 15, first, when + * attempting offset 0, then "trial bit 2", bit 14, when + * attempting offset 128K, and so on. If the tracing vector + * has completely unexpected contents, fall back to the + * raw_sect we were given. + */ + switch (bits) { + case 0x8000: raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_0K; break; + case 0xc000: raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_128K; break; + case 0xe000: raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_256K; break; + case 0xf000: raw_sect = CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR_384K; break; + default: + printf("Warning: Unexpected trial bits 0x%04x in trace vector 2, falling back to 0x%lx\n", + bits, raw_sect); + } + + return raw_sect; +} +#endif -- 2.52.0

