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>
This commit is contained in:
parent
4a4f269a1a
commit
c99ed8d6fa
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue