stm32/powerctrl: Write bootloader-state as 64-bit word to work on H7.

H7 MCUs have ECC and writes do not go through to SRAM until 64-bits have
been written (on another location is written).  So use 64-bit writes for
the bootloader-state variable so it is committed before the system reset.

As part of this change, the lower byte of the bootloader address in
BL_STATE must now be the magic number 0x5a5 for the state to be valid
(previously this was 0x000 which is not as robust).

Signed-off-by: Damien George <damien@micropython.org>
pull/6055/merge
Damien George 2022-01-31 16:40:15 +11:00
rodzic 4a4f269a1a
commit c99ed8d6fa
1 zmienionych plików z 19 dodań i 11 usunięć

Wyświetl plik

@ -75,9 +75,19 @@
#endif
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
// Location in RAM of bootloader state (just after the top of the stack)
extern uint32_t _estack[];
#define BL_STATE ((uint32_t *)&_estack)
// Location in RAM of bootloader state (just after the top of the stack).
// STM32H7 has ECC and writes to RAM must be 64-bit so they are fully committed
// to actual SRAM before a system reset occurs.
#define BL_STATE_PTR ((uint64_t *)&_estack)
#define BL_STATE_KEY (0x5a5)
#define BL_STATE_KEY_MASK (0xfff)
#define BL_STATE_KEY_SHIFT (32)
#define BL_STATE_INVALID (0)
#define BL_STATE_VALID(reg, addr) ((uint64_t)(reg) | ((uint64_t)((addr) | BL_STATE_KEY)) << BL_STATE_KEY_SHIFT)
#define BL_STATE_GET_REG(s) ((s) & 0xffffffff)
#define BL_STATE_GET_KEY(s) (((s) >> BL_STATE_KEY_SHIFT) & BL_STATE_KEY_MASK)
#define BL_STATE_GET_ADDR(s) (((s) >> BL_STATE_KEY_SHIFT) & ~BL_STATE_KEY_MASK)
extern uint64_t _estack[];
#endif
static inline void powerctrl_disable_hsi_if_unused(void) {
@ -89,7 +99,7 @@ static inline void powerctrl_disable_hsi_if_unused(void) {
NORETURN void powerctrl_mcu_reset(void) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
BL_STATE[1] = 1; // invalidate bootloader address
*BL_STATE_PTR = BL_STATE_INVALID;
#if __DCACHE_PRESENT == 1
SCB_CleanDCache();
#endif
@ -112,8 +122,7 @@ NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
// Enter the bootloader via a reset, so everything is reset (including WDT).
// Upon reset powerctrl_check_enter_bootloader() will jump to the bootloader.
BL_STATE[0] = r0;
BL_STATE[1] = bl_addr;
*BL_STATE_PTR = BL_STATE_VALID(r0, bl_addr);
#if __DCACHE_PRESENT == 1
SCB_CleanDCache();
#endif
@ -129,16 +138,15 @@ NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
void powerctrl_check_enter_bootloader(void) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
uint32_t bl_addr = BL_STATE[1];
BL_STATE[1] = 1; // invalidate bootloader address
if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) {
uint64_t bl_state = *BL_STATE_PTR;
*BL_STATE_PTR = BL_STATE_INVALID;
if (BL_STATE_GET_KEY(bl_state) == BL_STATE_KEY && (RCC->RCC_SR & RCC_SR_SFTRSTF)) {
// Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader
RCC->RCC_SR = RCC_SR_RMVF;
#if defined(STM32F0) || defined(STM32F4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB)
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
#endif
uint32_t r0 = BL_STATE[0];
branch_to_bootloader(r0, bl_addr);
branch_to_bootloader(BL_STATE_GET_REG(bl_state), BL_STATE_GET_ADDR(bl_state));
}
#endif
}