From 87ca431f3fa3fc87094526e33b77c50d6f968100 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 2 Jun 2022 13:43:46 +1000 Subject: [PATCH] stm32/boards/LEGO_HUB_NO6: Implement robust filesystem-load updates. Signed-off-by: Damien George --- ports/stm32/boards/LEGO_HUB_NO6/board_init.c | 38 ++++++++++++++++++- .../stm32/boards/LEGO_HUB_NO6/mpconfigboard.h | 2 + 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/LEGO_HUB_NO6/board_init.c b/ports/stm32/boards/LEGO_HUB_NO6/board_init.c index 8b2c0ce1ba..37a80bc91f 100644 --- a/ports/stm32/boards/LEGO_HUB_NO6/board_init.c +++ b/ports/stm32/boards/LEGO_HUB_NO6/board_init.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2021 Damien P. George + * Copyright (c) 2021-2022 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -75,6 +75,7 @@ void board_init(void) { #if BUILDING_MBOOT +#include "drivers/memory/spiflash.h" #include "mboot/mboot.h" #include "boardctrl.h" #include "adc.h" @@ -88,6 +89,14 @@ void board_init(void) { #define PATTERN_N (0x01296ad2) #define PATTERN_S (0x0064104c) +// Location and value for the SPI flash update key. If this key exists at the defined +// location then mboot will attempt to do a filesystem-load update of the main firmware. +// This makes the update robust to power failures: if the update does not complete then +// it will be restarted the next time it powers up. Only when it fully completes will +// this key be erased, and then the application can run. +#define SPIFLASH_UPDATE_KEY_ADDR (1020 * 1024) +#define SPIFLASH_UPDATE_KEY_VALUE (0x12345678) + static void board_led_pattern(int reset_mode, uint16_t brightness) { static const uint32_t pixels[] = { 0, @@ -162,9 +171,36 @@ int board_mboot_get_reset_mode(uint32_t *initial_r0) { mp_hal_delay_ms(50); } mp_hal_delay_ms(300); + } else { + // Button not pressed, check flash for update key and start an update if the key exists. + + // Initialise the external SPI flash. + MBOOT_SPIFLASH_SPIFLASH->config = MBOOT_SPIFLASH_CONFIG; + mp_spiflash_init(MBOOT_SPIFLASH_SPIFLASH); + + // Read in the key. + uint32_t buf; + mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR, 4, (uint8_t *)&buf); + + if (buf == SPIFLASH_UPDATE_KEY_VALUE) { + // The key has the correct value, so read in the FS-load elements and enter the bootloader. + mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR + 4, ELEM_DATA_SIZE, ELEM_DATA_START); + *initial_r0 = MBOOT_INITIAL_R0_KEY_FSLOAD; + reset_mode = BOARDCTRL_RESET_MODE_BOOTLOADER; + } } board_led_pattern(0, 0); return reset_mode; } +void board_mboot_state_change(int state, uint32_t arg) { + if (state == MBOOT_STATE_FSLOAD_END) { + // The FS-load update completed (either with success or failure), so erase the + // update key and write the result of the FS-load operation into flash. + mp_spiflash_erase_block(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR); + mp_spiflash_write(MBOOT_SPIFLASH_SPIFLASH, SPIFLASH_UPDATE_KEY_ADDR + 4, 4, (const uint8_t *)&arg); + } + mboot_state_change_default(state, arg); +} + #endif diff --git a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h index 8aa9da951b..cab46fa02d 100644 --- a/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h +++ b/ports/stm32/boards/LEGO_HUB_NO6/mpconfigboard.h @@ -153,6 +153,7 @@ #define MBOOT_BOARD_EARLY_INIT(initial_r0) board_init() #define MBOOT_BOARD_CLEANUP board_mboot_cleanup #define MBOOT_BOARD_GET_RESET_MODE board_mboot_get_reset_mode +#define MBOOT_BOARD_STATE_CHANGE board_mboot_state_change /******************************************************************************/ // Function declarations @@ -167,4 +168,5 @@ void board_mboot_cleanup(int reset_mode); void board_mboot_led_init(void); void board_mboot_led_state(int led, int state); int board_mboot_get_reset_mode(uint32_t *initial_r0); +void board_mboot_state_change(int state, uint32_t arg); void *btstack_chipset_cc256x_instance(void);