tools/bootloader: add force-erase option

If the STM32H7 fails to program or erase a full chunk of 256 bytes, the
ECC check will trigger a busfault when trying to read from it.

To speed up erasing and optimize wear, we read before erasing to check
if it actually needs erasing. That's when a busfault happens and the
erase time outs.

The workaround is to add an option to do a full erase without check.

Credit goes to:
https://github.com/ArduPilot/ardupilot/pull/22090

And the protocol option added to the bootloader is the same as for
ArduPilot, so compatible.

Signed-off-by: Julian Oes <julian@oes.ch>
This commit is contained in:
Julian Oes
2024-02-20 11:52:08 +13:00
parent 4a13e495d7
commit 21e550fdba
5 changed files with 56 additions and 36 deletions
+10 -2
View File
@@ -114,6 +114,7 @@
#define PROTO_RESERVED_0X37 0x37 // Reserved
#define PROTO_RESERVED_0X38 0x38 // Reserved
#define PROTO_RESERVED_0X39 0x39 // Reserved
#define PROTO_CHIP_FULL_ERASE 0x40 // Full erase, without any flash wear optimization
#define PROTO_PROG_MULTI_MAX 64 // maximum PROG_MULTI size
#define PROTO_READ_MULTI_MAX 255 // size of the size field
@@ -649,6 +650,8 @@ bootloader(unsigned timeout)
led_on(LED_ACTIVITY);
bool full_erase = false;
// handle the command byte
switch (c) {
@@ -728,6 +731,10 @@ bootloader(unsigned timeout)
// success reply: INSYNC/OK
// erase failure: INSYNC/FAILURE
//
case PROTO_CHIP_FULL_ERASE:
full_erase = true;
// Fallthrough
case PROTO_CHIP_ERASE:
/* expect EOC */
@@ -755,17 +762,18 @@ bootloader(unsigned timeout)
arch_flash_unlock();
for (int i = 0; flash_func_sector_size(i) != 0; i++) {
flash_func_erase_sector(i);
flash_func_erase_sector(i, full_erase);
}
// disable the LED while verifying the erase
led_set(LED_OFF);
// verify the erase
for (address = 0; address < board_info.fw_size; address += 4)
for (address = 0; address < board_info.fw_size; address += 4) {
if (flash_func_read_word(address) != 0xffffffff) {
goto cmd_fail;
}
}
address = 0;
SET_BL_STATE(STATE_PROTO_CHIP_ERASE);
+3 -1
View File
@@ -39,6 +39,8 @@
#pragma once
#include <stdbool.h>
/*****************************************************************************
* Generic bootloader functions.
*/
@@ -105,7 +107,7 @@ extern void board_deinit(void);
extern uint32_t board_get_devices(void);
extern void clock_deinit(void);
extern uint32_t flash_func_sector_size(unsigned sector);
extern void flash_func_erase_sector(unsigned sector);
extern void flash_func_erase_sector(unsigned sector, bool force);
extern void flash_func_write_word(uintptr_t address, uint32_t word);
extern uint32_t flash_func_read_word(uintptr_t address);
extern uint32_t flash_func_read_otp(uintptr_t address);
@@ -395,6 +395,24 @@ flash_func_sector_size(unsigned sector)
return 0;
}
/* imxRT uses Flash lib, not up_progmem so let's stub it here */
up_progmem_ispageerased(unsigned sector)
{
const uint32_t bytes_per_sector = flash_func_sector_size(sector);
uint32_t *address = (uint32_t *)(IMXRT_FLEXSPI1_CIPHER_BASE + (sector * bytes_per_sector));
const uint32_t uint32_per_sector = bytes_per_sector / sizeof(*address);
int blank = 0; /* Assume it is Bank */
for (uint32_t i = 0; i < uint32_per_sector; i++) {
if (address[i] != 0xffffffff) {
blank = -1; /* It is not blank */
break;
}
}
return blank;
}
/*!
* @name Configuration Option
@@ -407,31 +425,15 @@ flash_func_sector_size(unsigned sector)
* */
locate_code(".ramfunc")
void
flash_func_erase_sector(unsigned sector)
flash_func_erase_sector(unsigned sector, bool force)
{
if (sector > BOARD_FLASH_SECTORS || (int)sector < BOARD_FIRST_FLASH_SECTOR_TO_ERASE) {
return;
}
/* blank-check the sector */
const uint32_t bytes_per_sector = flash_func_sector_size(sector);
uint32_t *address = (uint32_t *)(IMXRT_FLEXSPI1_CIPHER_BASE + (sector * bytes_per_sector));
const uint32_t uint32_per_sector = bytes_per_sector / sizeof(*address);
bool blank = true;
if (force || flash_func_is_sector_blank(sector) != 0) {
struct flexspi_nor_config_s *pConfig = &g_bootConfig;
for (uint32_t i = 0; i < uint32_per_sector; i++) {
if (address[i] != 0xffffffff) {
blank = false;
break;
}
}
struct flexspi_nor_config_s *pConfig = &g_bootConfig;
/* erase the sector if it failed the blank check */
if (!blank) {
uintptr_t offset = ((uintptr_t) address) - IMXRT_FLEXSPI1_CIPHER_BASE;
irqstate_t flags;
flags = enter_critical_section();
@@ -439,8 +441,6 @@ flash_func_erase_sector(unsigned sector)
leave_critical_section(flags);
UNUSED(status);
}
}
void
@@ -466,18 +466,13 @@ flash_func_sector_size(unsigned sector)
}
void
flash_func_erase_sector(unsigned sector)
flash_func_erase_sector(unsigned sector, bool force)
{
if (sector > BOARD_FLASH_SECTORS || (int)sector < BOARD_FIRST_FLASH_SECTOR_TO_ERASE) {
return;
}
/* blank-check the sector */
bool blank = up_progmem_ispageerased(sector) == 0;
/* erase the sector if it failed the blank check */
if (!blank) {
if (force || (up_progmem_ispageerased(sector) != 0)) {
up_progmem_eraseblock(sector);
}
}