From 92488826e4b75f0b651a1e87e9a4b2503318ba56 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 01:14:42 +0100 Subject: [PATCH 01/17] target: implement target_flash_mass_erase mass erase wrapper target_flash_mass_erase abstracts the implementation details of the target mass erase --- src/include/target.h | 1 + src/target/lpc17xx.c | 1 - src/target/lpc40xx.c | 1 - src/target/target.c | 6 +++--- src/target/target_flash.c | 14 ++++++++++++++ 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/include/target.h b/src/include/target.h index 1d12469c1dc..5b4c9a15346 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -70,6 +70,7 @@ bool target_mem_access_needs_halt(target_s *target); bool target_flash_erase(target_s *target, target_addr_t addr, size_t len); bool target_flash_write(target_s *target, target_addr_t dest, const void *src, size_t len); bool target_flash_complete(target_s *target); +bool target_flash_mass_erase(target_s *target); /* Register access functions */ size_t target_regs_size(target_s *target); diff --git a/src/target/lpc17xx.c b/src/target/lpc17xx.c index 53d90b0f6dc..82657959426 100644 --- a/src/target/lpc17xx.c +++ b/src/target/lpc17xx.c @@ -191,7 +191,6 @@ static bool lpc17xx_mass_erase(target_s *target) } lpc17xx_exit_flash_mode(target); - tc_printf(target, "Erase OK.\n"); return true; } diff --git a/src/target/lpc40xx.c b/src/target/lpc40xx.c index fedad18e11a..d8a1b881bd1 100644 --- a/src/target/lpc40xx.c +++ b/src/target/lpc40xx.c @@ -185,7 +185,6 @@ static bool lpc40xx_mass_erase(target_s *target) } lpc40xx_exit_flash_mode(target); - tc_printf(target, "Erase OK.\n"); return true; } diff --git a/src/target/target.c b/src/target/target.c index 0fa3f69f3c1..d5cedf1b55c 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -486,12 +486,12 @@ static bool target_cmd_mass_erase(target_s *const target, const int argc, const { (void)argc; (void)argv; - if (!target || !target->mass_erase) { - gdb_out("Mass erase not implemented for target\n"); + if (!target) { + gdb_out("Mass erase not available\n"); return true; } gdb_out("Erasing device Flash: "); - const bool result = target->mass_erase(target); + const bool result = target_flash_mass_erase(target); gdb_out("done\n"); return result; } diff --git a/src/target/target_flash.c b/src/target/target_flash.c index 2d744937634..f43374c42b3 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -174,6 +174,20 @@ bool target_flash_erase(target_s *target, target_addr_t addr, size_t len) return result; } +/* Run specialized target mass erase if available, otherwise erase all flash' */ +bool target_flash_mass_erase(target_s *const target) +{ + if (target->mass_erase) { + DEBUG_TARGET("Running specialized target mass erase\n"); + + /* Run specialized target mass erase */ + return target->mass_erase(target); + } else { + DEBUG_WARN("No specialized target mass erase available\n"); + return false; + } +} + bool flash_buffer_alloc(target_flash_s *flash) { /* Allocate buffer */ From 6eb3367d8515f9afb716dc48847c5d9a1b604ef5 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 01:52:53 +0100 Subject: [PATCH 02/17] target: move scope of print progress timeout Move the scope of the print progress timeout creation to the common target API --- src/target/at32f43x.c | 10 ++++------ src/target/efm32.c | 24 ++++++++++-------------- src/target/hc32l110.c | 17 ++++++++++------- src/target/kinetis.c | 12 +++++------- src/target/lmi.c | 5 +++-- src/target/lpc17xx.c | 28 +++++++++++++++------------- src/target/lpc40xx.c | 30 ++++++++++++++++-------------- src/target/lpc43xx.c | 10 +++++----- src/target/lpc546xx.c | 6 ++++-- src/target/lpc55xx.c | 5 +++-- src/target/msp432e4.c | 8 +++----- src/target/nrf51.c | 26 ++++++++++---------------- src/target/nxpke04.c | 6 ++++-- src/target/samd.c | 14 ++++++-------- src/target/samx5x.c | 2 +- src/target/spi.c | 12 ++++++------ src/target/spi.h | 2 +- src/target/stm32f1.c | 10 ++++------ src/target/stm32f4.c | 12 +++++------- src/target/stm32g0.c | 8 +++----- src/target/stm32h5.c | 8 +++----- src/target/stm32h7.c | 10 ++++------ src/target/stm32l0.c | 6 ++++-- src/target/stm32l4.c | 22 ++++++++++------------ src/target/stm32wb0.c | 8 +++----- src/target/target_flash.c | 6 +++++- src/target/target_internal.h | 2 +- 27 files changed, 148 insertions(+), 161 deletions(-) diff --git a/src/target/at32f43x.c b/src/target/at32f43x.c index 0e5d100bec0..49fdcfb295e 100644 --- a/src/target/at32f43x.c +++ b/src/target/at32f43x.c @@ -50,7 +50,7 @@ static bool at32f43_flash_prepare(target_flash_s *flash); static bool at32f43_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool at32f43_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); static bool at32f43_flash_done(target_flash_s *flash); -static bool at32f43_mass_erase(target_s *target); +static bool at32f43_mass_erase(target_s *target, platform_timeout_s *print_progess); /* Flash memory controller register map */ #define AT32F43x_FLASH_REG_BASE 0x40023c00U @@ -538,17 +538,15 @@ static bool at32f43_mass_erase_bank( return at32f43_flash_busy_wait(target, bank_reg_offset, timeout); } -static bool at32f43_mass_erase(target_s *target) +static bool at32f43_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { /* Datasheet: bank erase takes seconds to complete */ - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); - if (!at32f43_mass_erase_bank(target, AT32F43x_FLASH_BANK1_REG_OFFSET, &timeout)) + if (!at32f43_mass_erase_bank(target, AT32F43x_FLASH_BANK1_REG_OFFSET, print_progess)) return false; /* For dual-bank targets, mass erase bank 2 as well */ if (target->flash->next) - return at32f43_mass_erase_bank(target, AT32F43x_FLASH_BANK2_REG_OFFSET, &timeout); + return at32f43_mass_erase_bank(target, AT32F43x_FLASH_BANK2_REG_OFFSET, print_progess); return true; } diff --git a/src/target/efm32.c b/src/target/efm32.c index fda2fc8e201..66ddbceaf36 100644 --- a/src/target/efm32.c +++ b/src/target/efm32.c @@ -47,7 +47,7 @@ static bool efm32_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool efm32_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); -static bool efm32_mass_erase(target_s *t); +static bool efm32_mass_erase(target_s *t, platform_timeout_s *print_progess); static const uint16_t efm32_flash_write_stub[] = { #include "flashstub/efm32.stub" @@ -666,7 +666,7 @@ static bool efm32_flash_write(target_flash_s *f, target_addr_t dest, const void } /* Uses the MSC ERASEMAIN0/1 command to erase the entire flash */ -static bool efm32_mass_erase(target_s *t) +static bool efm32_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { efm32_priv_s *priv_storage = (efm32_priv_s *)t->target_storage; if (!priv_storage || !priv_storage->device) @@ -691,17 +691,15 @@ static bool efm32_mass_erase(target_s *t) /* Erase operation */ target_mem32_write32(t, EFM32_MSC_WRITECMD(msc), EFM32_MSC_WRITECMD_ERASEMAIN0); - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Poll MSC Busy */ while ((target_mem32_read32(t, EFM32_MSC_STATUS(msc)) & EFM32_MSC_STATUS_BUSY)) { if (target_check_error(t)) return false; - target_print_progress(&timeout); + target_print_progress(print_progess); } /* Parts with >= 512 kiB flash have 2 mass erase regions */ - if (flash_kib >= 512) { + if (flash_kib >= 512U) { /* Erase operation */ target_mem32_write32(t, EFM32_MSC_WRITECMD(msc), EFM32_MSC_WRITECMD_ERASEMAIN1); @@ -709,7 +707,7 @@ static bool efm32_mass_erase(target_s *t) while ((target_mem32_read32(t, EFM32_MSC_STATUS(msc)) & EFM32_MSC_STATUS_BUSY)) { if (target_check_error(t)) return false; - target_print_progress(&timeout); + target_print_progress(print_progess); } } @@ -926,7 +924,7 @@ static bool efm32_cmd_bootloader(target_s *t, int argc, const char **argv) #define CMDKEY 0xcfacc118U -static bool efm32_aap_mass_erase(target_s *t); +static bool efm32_aap_mass_erase(target_s *t, platform_timeout_s *print_progess); /* AAP Probe */ typedef struct efm32_aap_priv { @@ -968,9 +966,9 @@ bool efm32_aap_probe(adiv5_access_port_s *ap) return true; } -static bool efm32_aap_mass_erase(target_s *t) +static bool efm32_aap_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { - adiv5_access_port_s *ap = t->priv; + adiv5_access_port_s *ap = cortex_ap(t); uint32_t status; /* Read status */ @@ -985,14 +983,12 @@ static bool efm32_aap_mass_erase(target_s *t) DEBUG_INFO("EFM32: Issuing DEVICEERASE...\n"); adiv5_ap_write(ap, AAP_CMDKEY, CMDKEY); - adiv5_ap_write(ap, AAP_CMD, 1); + adiv5_ap_write(ap, AAP_CMD, 1U); - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Read until 0, probably should have a timeout here... */ do { status = adiv5_ap_read(ap, AAP_STATUS); - target_print_progress(&timeout); + target_print_progress(print_progess); } while (status & AAP_STATUS_ERASEBUSY); /* Read status */ diff --git a/src/target/hc32l110.c b/src/target/hc32l110.c index 28a90703919..1efc94a1b15 100644 --- a/src/target/hc32l110.c +++ b/src/target/hc32l110.c @@ -78,7 +78,7 @@ static bool hc32l110_flash_prepare(target_flash_s *flash); static bool hc32l110_flash_done(target_flash_s *flash); static bool hc32l110_flash_erase(target_flash_s *flash, target_addr_t addr, size_t length); static bool hc32l110_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); -static bool hc32l110_mass_erase(target_s *target); +static bool hc32l110_mass_erase(target_s *target, platform_timeout_s *print_progess); static void hc32l110_add_flash(target_s *target, const uint32_t flash_size) { @@ -130,7 +130,8 @@ static void hc32l110_flash_cr_unlock(target_s *const target) target_mem32_write32(target, HC32L110_FLASH_BYPASS, 0xa5a5U); } -static bool hc32l110_check_flash_completion(target_s *const target, const uint32_t timeout_ms) +static bool hc32l110_check_flash_completion( + target_s *const target, const uint32_t timeout_ms, platform_timeout_s *const print_progess) { platform_timeout_s timeout; platform_timeout_set(&timeout, timeout_ms); @@ -139,6 +140,8 @@ static bool hc32l110_check_flash_completion(target_s *const target, const uint32 status = target_mem32_read32(target, HC32L110_FLASH_CR); if (target_check_error(target) || platform_timeout_is_expired(&timeout)) return false; + if (print_progess) + target_print_progress(print_progess); } return true; } @@ -201,7 +204,7 @@ static bool hc32l110_flash_erase(target_flash_s *const flash, const target_addr_ (void)length; /* The Flash controller automatically erases the whole sector after one write operation */ target_mem32_write32(flash->t, addr, 0); - return hc32l110_check_flash_completion(flash->t, 1000); + return hc32l110_check_flash_completion(flash->t, 1000, NULL); } static bool hc32l110_flash_write( @@ -209,23 +212,23 @@ static bool hc32l110_flash_write( { (void)length; target_mem32_write32(flash->t, dest, *(const uint32_t *)src); - return hc32l110_check_flash_completion(flash->t, 1000); + return hc32l110_check_flash_completion(flash->t, 1000, NULL); } -static bool hc32l110_mass_erase(target_s *target) +static bool hc32l110_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { hc32l110_enter_flash_mode(target); hc32l110_flash_cr_unlock(target); target_mem32_write32(target, HC32L110_FLASH_CR, HC32L110_FLASH_CR_OP_ERASE_CHIP); - if (!hc32l110_check_flash_completion(target, 500)) + if (!hc32l110_check_flash_completion(target, 500U, print_progess)) return false; hc32l110_slock_unlock_all(target); // The Flash controller automatically erases the whole Flash after one write operation target_mem32_write32(target, 0, 0); - const bool result = hc32l110_check_flash_completion(target, 4000); + const bool result = hc32l110_check_flash_completion(target, 4000U, print_progess); hc32l110_slock_lock_all(target); return result; diff --git a/src/target/kinetis.c b/src/target/kinetis.c index c6dabf44462..39b9c795f91 100644 --- a/src/target/kinetis.c +++ b/src/target/kinetis.c @@ -539,7 +539,7 @@ static bool kinetis_flash_done(target_flash_s *const f) * device. This provides a fake target to allow a monitor command interface */ -static bool kinetis_mdm_mass_erase(target_s *t); +static bool kinetis_mdm_mass_erase(target_s *t, platform_timeout_s *const print_progess); static bool kinetis_mdm_cmd_ke04_mode(target_s *t, int argc, const char **argv); const command_s kinetis_mdm_cmd_list[] = { @@ -593,13 +593,13 @@ static bool kinetis_mdm_cmd_ke04_mode(target_s *t, int argc, const char **argv) return true; } -static bool kinetis_mdm_mass_erase(target_s *t) +static bool kinetis_mdm_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { adiv5_access_port_s *ap = t->priv; /* Keep the MCU in reset as stated in KL25PxxM48SF0RM */ if (t->ke04_mode) - adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_SYS_RESET); + adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_SYS_RESET); /* FIXME: move this to enter_flash_mode? */ uint32_t status = adiv5_ap_read(ap, MDM_STATUS); uint32_t control = adiv5_ap_read(ap, MDM_CONTROL); @@ -625,18 +625,16 @@ static bool kinetis_mdm_mass_erase(target_s *t) } adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_MASS_ERASE); - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); do { status = adiv5_ap_read(ap, MDM_STATUS); - target_print_progress(&timeout); + target_print_progress(print_progess); } while (!(status & MDM_STATUS_MASS_ERASE_ACK)); tc_printf(t, "Mass erase acknowledged\n"); do { control = adiv5_ap_read(ap, MDM_CONTROL); - target_print_progress(&timeout); + target_print_progress(print_progess); } while (!(control & MDM_CONTROL_MASS_ERASE)); tc_printf(t, "Mass erase complete\n"); diff --git a/src/target/lmi.c b/src/target/lmi.c index ab6c998724e..0a4ec323e9b 100644 --- a/src/target/lmi.c +++ b/src/target/lmi.c @@ -102,7 +102,7 @@ static bool lmi_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool lmi_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool lmi_mass_erase(target_s *target); +static bool lmi_mass_erase(target_s *target, platform_timeout_s *print_progess); static const uint16_t lmi_flash_write_stub[] = { #include "flashstub/lmi.stub" @@ -237,7 +237,8 @@ static bool lmi_flash_write(target_flash_s *flash, target_addr_t dest, const voi return cortexm_run_stub(target, SRAM_BASE, dest, STUB_BUFFER_BASE, len, 0) == 0; } -static bool lmi_mass_erase(target_s *target) +static bool lmi_mass_erase(target_s *target, platform_timeout_s *print_progess) { + (void)print_progess; return lmi_flash_erase(target->flash, target->flash->start, target->flash->length); } diff --git a/src/target/lpc17xx.c b/src/target/lpc17xx.c index 82657959426..717b02ea7b7 100644 --- a/src/target/lpc17xx.c +++ b/src/target/lpc17xx.c @@ -64,8 +64,9 @@ typedef struct lpc17xx_priv { static void lpc17xx_extended_reset(target_s *target); static bool lpc17xx_enter_flash_mode(target_s *target); static bool lpc17xx_exit_flash_mode(target_s *target); -static bool lpc17xx_mass_erase(target_s *target); -iap_status_e lpc17xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e cmd, ...); +static bool lpc17xx_mass_erase(target_s *target, platform_timeout_s *print_progess); +iap_status_e lpc17xx_iap_call( + target_s *target, iap_result_s *result, platform_timeout_s *print_progess, iap_cmd_e cmd, ...); static void lpc17xx_add_flash(target_s *target, uint32_t addr, size_t len, size_t erasesize, uint8_t base_sector) { @@ -102,7 +103,7 @@ bool lpc17xx_probe(target_s *target) lpc17xx_enter_flash_mode(target); /* Read the Part ID */ iap_result_s result; - lpc17xx_iap_call(target, &result, IAP_CMD_PARTID); + lpc17xx_iap_call(target, &result, NULL, IAP_CMD_PARTID); /* Transition back to normal mode and resume the target */ lpc17xx_exit_flash_mode(target); target_halt_resume(target, false); @@ -167,24 +168,24 @@ static bool lpc17xx_exit_flash_mode(target_s *const target) return true; } -static bool lpc17xx_mass_erase(target_s *target) +static bool lpc17xx_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { iap_result_s result; lpc17xx_enter_flash_mode(target); - if (lpc17xx_iap_call(target, &result, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { + if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { lpc17xx_exit_flash_mode(target); DEBUG_ERROR("lpc17xx_cmd_erase: prepare failed %" PRIu32 "\n", result.return_code); return false; } - if (lpc17xx_iap_call(target, &result, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { + if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { lpc17xx_exit_flash_mode(target); DEBUG_ERROR("lpc17xx_cmd_erase: erase failed %" PRIu32 "\n", result.return_code); return false; } - if (lpc17xx_iap_call(target, &result, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { + if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { lpc17xx_exit_flash_mode(target); DEBUG_ERROR("lpc17xx_cmd_erase: blankcheck failed %" PRIu32 "\n", result.return_code); return false; @@ -221,7 +222,8 @@ static size_t lpc17xx_iap_params(const iap_cmd_e cmd) } } -iap_status_e lpc17xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e cmd, ...) +iap_status_e lpc17xx_iap_call( + target_s *const target, iap_result_s *const result, platform_timeout_s *const print_progess, iap_cmd_e cmd, ...) { /* Set up our IAP frame with the break opcode and command to run */ iap_frame_s frame = { @@ -236,7 +238,7 @@ iap_status_e lpc17xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e for (size_t i = 0; i < params_count; ++i) frame.config.params[i] = va_arg(params, uint32_t); va_end(params); - for (size_t i = params_count; i < 4; ++i) + for (size_t i = params_count; i < 4U; ++i) frame.config.params[i] = 0U; /* Copy the structure to RAM */ @@ -249,7 +251,7 @@ iap_status_e lpc17xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e /* Point r0 to the start of the config block */ regs[0] = iap_params_addr; /* And r1 to the same so we re-use the same memory for the results */ - regs[1] = iap_params_addr; + regs[1U] = iap_params_addr; /* Set the top of stack to the top of the RAM block we're using */ regs[CORTEX_REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE; /* Point the return address to our breakpoint opcode (thumb mode) */ @@ -259,12 +261,12 @@ iap_status_e lpc17xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e target_regs_write(target, regs); platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); + platform_timeout_set(&timeout, 500U); /* Start the target and wait for it to halt again */ target_halt_resume(target, false); while (!target_halt_poll(target, NULL)) { - if (cmd == IAP_CMD_ERASE) - target_print_progress(&timeout); + if (print_progess) + target_print_progress(print_progess); else if (cmd == IAP_CMD_PARTID && platform_timeout_is_expired(&timeout)) { target_halt_request(target); return IAP_STATUS_INVALID_COMMAND; diff --git a/src/target/lpc40xx.c b/src/target/lpc40xx.c index d8a1b881bd1..218661f4629 100644 --- a/src/target/lpc40xx.c +++ b/src/target/lpc40xx.c @@ -66,8 +66,9 @@ typedef struct lpc40xx_priv { static void lpc40xx_extended_reset(target_s *target); static bool lpc40xx_enter_flash_mode(target_s *target); static bool lpc40xx_exit_flash_mode(target_s *target); -static bool lpc40xx_mass_erase(target_s *target); -iap_status_e lpc40xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e cmd, ...); +static bool lpc40xx_mass_erase(target_s *target, platform_timeout_s *print_progess); +iap_status_e lpc40xx_iap_call( + target_s *target, iap_result_s *result, platform_timeout_s *print_progess, iap_cmd_e cmd, ...); static void lpc40xx_add_flash(target_s *target, uint32_t addr, size_t len, size_t erasesize, uint8_t base_sector) { @@ -105,7 +106,7 @@ bool lpc40xx_probe(target_s *target) lpc40xx_enter_flash_mode(target); /* Read the Part ID */ iap_result_s result; - lpc40xx_iap_call(target, &result, IAP_CMD_PARTID); + lpc40xx_iap_call(target, &result, NULL, IAP_CMD_PARTID); /* Transition back to normal mode and resume the target */ lpc40xx_exit_flash_mode(target); target_halt_resume(target, false); @@ -161,24 +162,24 @@ static bool lpc40xx_exit_flash_mode(target_s *const target) return true; } -static bool lpc40xx_mass_erase(target_s *target) +static bool lpc40xx_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { iap_result_s result; lpc40xx_enter_flash_mode(target); - if (lpc40xx_iap_call(target, &result, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { + if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { lpc40xx_exit_flash_mode(target); DEBUG_ERROR("lpc40xx_cmd_erase: prepare failed %" PRIu32 "\n", result.return_code); return false; } - if (lpc40xx_iap_call(target, &result, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { + if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { lpc40xx_exit_flash_mode(target); DEBUG_ERROR("lpc40xx_cmd_erase: erase failed %" PRIu32 "\n", result.return_code); return false; } - if (lpc40xx_iap_call(target, &result, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { + if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { lpc40xx_exit_flash_mode(target); DEBUG_ERROR("lpc40xx_cmd_erase: blankcheck failed %" PRIu32 "\n", result.return_code); return false; @@ -215,7 +216,8 @@ static size_t lpc40xx_iap_params(const iap_cmd_e cmd) } } -iap_status_e lpc40xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e cmd, ...) +iap_status_e lpc40xx_iap_call( + target_s *const target, iap_result_s *const result, platform_timeout_s *const print_progess, iap_cmd_e cmd, ...) { /* Set up our IAP frame with the break opcode and command to run */ iap_frame_s frame = { @@ -230,7 +232,7 @@ iap_status_e lpc40xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e for (size_t i = 0; i < params_count; ++i) frame.config.params[i] = va_arg(params, uint32_t); va_end(params); - for (size_t i = params_count; i < 4; ++i) + for (size_t i = params_count; i < 4U; ++i) frame.config.params[i] = 0U; /* Copy the structure to RAM */ @@ -243,22 +245,22 @@ iap_status_e lpc40xx_iap_call(target_s *target, iap_result_s *result, iap_cmd_e /* Point r0 to the start of the config block */ regs[0] = iap_params_addr; /* And r1 to the same so we re-use the same memory for the results */ - regs[1] = iap_params_addr; + regs[1U] = iap_params_addr; /* Set the top of stack to the top of the RAM block we're using */ regs[CORTEX_REG_MSP] = IAP_RAM_BASE + MIN_RAM_SIZE; /* Point the return address to our breakpoint opcode (thumb mode) */ - regs[CORTEX_REG_LR] = IAP_RAM_BASE | 1; + regs[CORTEX_REG_LR] = IAP_RAM_BASE | 1U; /* And set the program counter to the IAP ROM entrypoint */ regs[CORTEX_REG_PC] = IAP_ENTRYPOINT; target_regs_write(target, regs); platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); + platform_timeout_set(&timeout, 500U); /* Start the target and wait for it to halt again */ target_halt_resume(target, false); while (!target_halt_poll(target, NULL)) { - if (cmd == IAP_CMD_ERASE) - target_print_progress(&timeout); + if (print_progess) + target_print_progress(print_progess); else if (cmd == IAP_CMD_PARTID && platform_timeout_is_expired(&timeout)) { target_halt_request(target); return IAP_STATUS_INVALID_COMMAND; diff --git a/src/target/lpc43xx.c b/src/target/lpc43xx.c index 2e6fe84e19d..352df6a9a47 100644 --- a/src/target/lpc43xx.c +++ b/src/target/lpc43xx.c @@ -285,7 +285,7 @@ static bool lpc43xx_iap_init(target_flash_s *flash); static lpc43xx_partid_s lpc43xx_iap_read_partid(target_s *t); static bool lpc43xx_enter_flash_mode(target_s *t); static bool lpc43xx_iap_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); -static bool lpc43xx_iap_mass_erase(target_s *t); +static bool lpc43xx_iap_mass_erase(target_s *t, platform_timeout_s *print_progess); static void lpc43xx_wdt_set_period(target_s *t); static void lpc43xx_wdt_kick(target_s *t); @@ -1000,19 +1000,19 @@ static bool lpc43xx_iap_flash_erase(target_flash_s *f, const target_addr_t addr, return lpc_flash_erase(f, addr, len); } -static bool lpc43xx_iap_mass_erase(target_s *t) +static bool lpc43xx_iap_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { lpc43xx_priv_s *const priv = (lpc43xx_priv_s *)t->target_storage; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); + lpc43xx_iap_init(t->flash); + /* FIXME: since this is looking like bank mass erases, maybe this should be in flash->mass_erase */ for (size_t bank = 0; bank < priv->flash_banks; ++bank) { lpc_flash_s *const f = (lpc_flash_s *)t->flash; if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U, bank) || lpc_iap_call(f, NULL, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ, bank)) return false; - target_print_progress(&timeout); + target_print_progress(print_progess); } return true; diff --git a/src/target/lpc546xx.c b/src/target/lpc546xx.c index 341f2a1f352..2e1cb76fccb 100644 --- a/src/target/lpc546xx.c +++ b/src/target/lpc546xx.c @@ -61,7 +61,7 @@ static bool lpc546xx_cmd_write_sector(target_s *t, int argc, const char **argv); static void lpc546xx_reset_attach(target_s *t); static bool lpc546xx_flash_init(target_s *t); static bool lpc546xx_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); -static bool lpc546xx_mass_erase(target_s *t); +static bool lpc546xx_mass_erase(target_s *t, platform_timeout_s *print_progess); static void lpc546xx_wdt_set_period(target_s *t); static void lpc546xx_wdt_kick(target_s *t); @@ -182,8 +182,10 @@ static void lpc546xx_reset_attach(target_s *t) cortexm_attach(t); } -static bool lpc546xx_mass_erase(target_s *t) +static bool lpc546xx_mass_erase(target_s *t, platform_timeout_s *const print_progess) { + (void)print_progess; + const int result = lpc546xx_flash_erase(t->flash, t->flash->start, t->flash->length); if (result != 0) tc_printf(t, "Error erasing flash: %d\n", result); diff --git a/src/target/lpc55xx.c b/src/target/lpc55xx.c index 8284aec38c5..2bf4d04acb7 100644 --- a/src/target/lpc55xx.c +++ b/src/target/lpc55xx.c @@ -519,7 +519,7 @@ static const command_s lpc55xx_cmd_list[] = { }; static bool lpc55_dmap_cmd(adiv5_access_port_s *ap, uint32_t cmd); -static bool lpc55_dmap_mass_erase(target_s *target); +static bool lpc55_dmap_mass_erase(target_s *target, platform_timeout_s *print_progess); static void lpc55_dmap_ap_free(void *priv); void lpc55_dp_prepare(adiv5_debug_port_s *const dp) @@ -656,8 +656,9 @@ static bool lpc55_dmap_cmd(adiv5_access_port_s *const ap, const uint32_t cmd) } } -static bool lpc55_dmap_mass_erase(target_s *target) +static bool lpc55_dmap_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { + (void)print_progess; /* * TODO: This doesn't actually work at least on the LPC550x, there seems to be * a lot more to figure out about the debug mailbox before this code can work. diff --git a/src/target/msp432e4.c b/src/target/msp432e4.c index df15b20c363..6253ba592a2 100644 --- a/src/target/msp432e4.c +++ b/src/target/msp432e4.c @@ -185,7 +185,7 @@ typedef struct msp432e4_flash { static bool msp432e4_flash_erase(target_flash_s *flash, target_addr_t addr, size_t length); static bool msp432e4_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); -static bool msp432e4_mass_erase(target_s *target); +static bool msp432e4_mass_erase(target_s *target, platform_timeout_s *print_progess); static void msp432e4_add_flash( target_s *const target, const uint32_t sector_size, const uint32_t base, const size_t length) @@ -299,15 +299,13 @@ static bool msp432e4_flash_write( } /* Mass erases the Flash */ -static bool msp432e4_mass_erase(target_s *const target) +static bool msp432e4_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { const msp432e4_flash_s *const flash = (msp432e4_flash_s *)target->flash; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Kick off the mass erase */ target_mem32_write32(target, MSP432E4_FLASH_CTRL, (flash->flash_key << 16U) | MSP432E4_FLASH_CTRL_MASS_ERASE); /* Wait for the erase to complete, printing a '.' every so often to keep GDB happy */ while (target_mem32_read32(target, MSP432E4_FLASH_CTRL) & MSP432E4_FLASH_CTRL_MASS_ERASE) - target_print_progress(&timeout); + target_print_progress(print_progess); return true; } diff --git a/src/target/nrf51.c b/src/target/nrf51.c index 2424168eebc..5cc112f8ebd 100644 --- a/src/target/nrf51.c +++ b/src/target/nrf51.c @@ -31,7 +31,7 @@ static bool nrf51_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool nrf51_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool nrf51_flash_prepare(target_flash_s *f); static bool nrf51_flash_done(target_flash_s *f); -static bool nrf51_mass_erase(target_s *t); +static bool nrf51_mass_erase(target_s *t, platform_timeout_s *print_progess); static bool nrf51_cmd_erase_uicr(target_s *t, int argc, const char **argv); static bool nrf51_cmd_protect_flash(target_s *t, int argc, const char **argv); @@ -164,14 +164,14 @@ bool nrf51_probe(target_s *t) return true; } -static bool nrf51_wait_ready(target_s *const t, platform_timeout_s *const timeout) +static bool nrf51_wait_ready(target_s *const t, platform_timeout_s *const print_progress) { /* Poll for NVMC_READY */ while (target_mem32_read32(t, NRF51_NVMC_READY) == 0) { if (target_check_error(t)) return false; - if (timeout) - target_print_progress(timeout); + if (print_progress) + target_print_progress(print_progress); } return true; } @@ -225,20 +225,16 @@ static bool nrf51_flash_write(target_flash_s *f, target_addr_t dest, const void return nrf51_wait_ready(t, NULL); } -static bool nrf51_mass_erase(target_s *t) +static bool nrf51_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { - target_reset(t); - /* Enable erase */ target_mem32_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN); if (!nrf51_wait_ready(t, NULL)) return false; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500U); /* Erase all */ target_mem32_write32(t, NRF51_NVMC_ERASEALL, 1U); - return nrf51_wait_ready(t, &timeout); + return nrf51_wait_ready(t, print_progess); } static bool nrf51_cmd_erase_uicr(target_s *t, int argc, const char **argv) @@ -399,7 +395,7 @@ static bool nrf51_cmd_read(target_s *t, int argc, const char **argv) #define NRF52_MDM_IDR 0x02880000U -static bool nrf51_mdm_mass_erase(target_s *t); +static bool nrf51_mdm_mass_erase(target_s *t, platform_timeout_s *print_progess); #define MDM_POWER_EN ADIV5_DP_REG(0x01U) #define MDM_SELECT_AP ADIV5_DP_REG(0x02U) @@ -436,21 +432,19 @@ bool nrf51_mdm_probe(adiv5_access_port_s *ap) return true; } -static bool nrf51_mdm_mass_erase(target_s *t) +static bool nrf51_mdm_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { - adiv5_access_port_s *ap = t->priv; + adiv5_access_port_s *const ap = t->priv; uint32_t status = adiv5_ap_read(ap, MDM_STATUS); adiv5_dp_write(ap->dp, MDM_POWER_EN, 0x50000000U); adiv5_dp_write(ap->dp, MDM_SELECT_AP, 0x01000000U); adiv5_ap_write(ap, MDM_CONTROL, 0x00000001U); - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500U); // Read until 0, probably should have a timeout here... do { status = adiv5_ap_read(ap, MDM_STATUS); - target_print_progress(&timeout); + target_print_progress(print_progess); } while (status); // The second read will provide true prot status diff --git a/src/target/nxpke04.c b/src/target/nxpke04.c index 5bf31fc4cd3..5a056c4154b 100644 --- a/src/target/nxpke04.c +++ b/src/target/nxpke04.c @@ -118,7 +118,7 @@ static bool ke04_command(target_s *t, uint8_t cmd, uint32_t addr, const void *da static bool ke04_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool ke04_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool ke04_flash_done(target_flash_s *f); -static bool ke04_mass_erase(target_s *t); +static bool ke04_mass_erase(target_s *t, platform_timeout_s *print_progess); /* Target specific commands */ static bool kinetis_cmd_unsafe(target_s *t, int argc, const char **argv); @@ -239,8 +239,10 @@ bool ke04_probe(target_s *t) return true; } -static bool ke04_mass_erase(target_s *t) +static bool ke04_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { + (void)print_progess; + /* Erase and verify the whole flash */ ke04_command(t, CMD_ERASE_ALL_BLOCKS, 0, NULL); /* Adjust security byte if needed */ diff --git a/src/target/samd.c b/src/target/samd.c index 60daa430ba1..99873ea662e 100644 --- a/src/target/samd.c +++ b/src/target/samd.c @@ -45,7 +45,7 @@ static bool samd_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool samd_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); /* NB: This is not marked static on purpose as it's used by samx5x.c. */ -bool samd_mass_erase(target_s *t); +bool samd_mass_erase(target_s *t, platform_timeout_s *print_progess); static bool samd_cmd_lock_flash(target_s *t, int argc, const char **argv); static bool samd_cmd_unlock_flash(target_s *t, int argc, const char **argv); @@ -601,15 +601,15 @@ static bool samd_wait_nvm_ready(target_s *t) return true; } -static bool samd_wait_dsu_ready(target_s *const t, uint32_t *const result, platform_timeout_s *const timeout) +static bool samd_wait_dsu_ready(target_s *const t, uint32_t *const result, platform_timeout_s *const print_progress) { uint32_t status = 0; while ((status & (SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL)) == 0) { status = target_mem32_read32(t, SAMD_DSU_CTRLSTAT); if (target_check_error(t)) return false; - if (timeout) - target_print_progress(timeout); + if (print_progress) + target_print_progress(print_progress); } *result = status; return true; @@ -666,7 +666,7 @@ static bool samd_flash_write(target_flash_s *f, target_addr_t dest, const void * } /* Uses the Device Service Unit to erase the entire flash */ -bool samd_mass_erase(target_s *t) +bool samd_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { /* Clear the DSU status bits */ target_mem32_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_DONE | SAMD_STATUSA_PERR | SAMD_STATUSA_FAIL); @@ -675,9 +675,7 @@ bool samd_mass_erase(target_s *t) target_mem32_write32(t, SAMD_DSU_CTRLSTAT, SAMD_CTRL_CHIP_ERASE); uint32_t status = 0; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); - if (!samd_wait_dsu_ready(t, &status, &timeout)) + if (!samd_wait_dsu_ready(t, &status, print_progess)) return false; /* Test the protection error bit in Status A */ diff --git a/src/target/samx5x.c b/src/target/samx5x.c index 736d52c27ab..50d0fb570ce 100644 --- a/src/target/samx5x.c +++ b/src/target/samx5x.c @@ -52,7 +52,7 @@ static bool samx5x_cmd_ssb(target_s *t, int argc, const char **argv); static bool samx5x_cmd_update_user_word(target_s *t, int argc, const char **argv); /* (The SAM D1x/2x implementation of erase_all is reused as it's identical)*/ -bool samd_mass_erase(target_s *t); +extern bool samd_mass_erase(target_s *t, platform_timeout_s *print_progess); #define samx5x_mass_erase samd_mass_erase #ifdef SAMX5X_EXTRA_CMDS diff --git a/src/target/spi.c b/src/target/spi.c index 523fef9a2cd..33bce203508 100644 --- a/src/target/spi.c +++ b/src/target/spi.c @@ -144,13 +144,13 @@ spi_flash_s *bmp_spi_add_flash(target_s *const target, const target_addr_t begin } /* Note: These routines assume that the first Flash registered on the target is a SPI Flash device */ -bool bmp_spi_mass_erase(target_s *const target) +bool bmp_spi_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { - /* Extract the Flash structure and set up timeouts */ - const spi_flash_s *const flash = (spi_flash_s *)target->flash; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); DEBUG_TARGET("Running %s\n", __func__); + + /* Extract the Flash structure */ + const spi_flash_s *const flash = (spi_flash_s *)target->flash; + /* Go into Flash mode and tell the Flash to enable writing */ target->enter_flash_mode(target); flash->run_command(target, SPI_FLASH_CMD_WRITE_ENABLE, 0U); @@ -162,7 +162,7 @@ bool bmp_spi_mass_erase(target_s *const target) /* Execute a full chip erase and wait for the operatoin to complete */ flash->run_command(target, SPI_FLASH_CMD_CHIP_ERASE, 0U); while (bmp_spi_read_status(target, flash) & SPI_FLASH_STATUS_BUSY) - target_print_progress(&timeout); + target_print_progress(print_progess); /* Finally, leave Flash mode to conclude business */ return target->exit_flash_mode(target); diff --git a/src/target/spi.h b/src/target/spi.h index 3de75bbec80..bbdbbc10708 100644 --- a/src/target/spi.h +++ b/src/target/spi.h @@ -93,6 +93,6 @@ void bmp_spi_run_command(spi_bus_e bus, uint8_t device, uint16_t command, target spi_flash_s *bmp_spi_add_flash(target_s *target, target_addr_t begin, size_t length, spi_read_func spi_read, spi_write_func spi_write, spi_run_command_func spi_run_command); -bool bmp_spi_mass_erase(target_s *target); +bool bmp_spi_mass_erase(target_s *target, platform_timeout_s *print_progess); #endif /* TARGET_SPI_H */ diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 455184203f7..fdc2b818b4d 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -174,7 +174,7 @@ static bool stm32f1_attach(target_s *target); static void stm32f1_detach(target_s *target); static bool stm32f1_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool stm32f1_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32f1_mass_erase(target_s *target); +static bool stm32f1_mass_erase(target_s *target, platform_timeout_s *print_progess); static void stm32f1_add_flash(target_s *target, uint32_t addr, size_t length, size_t erasesize) { @@ -1162,19 +1162,17 @@ static bool stm32f1_mass_erase_bank( return stm32f1_flash_busy_wait(target, bank_offset, timeout); } -static bool stm32f1_mass_erase(target_s *target) +static bool stm32f1_mass_erase(target_s *target, platform_timeout_s *const print_progess) { if (!stm32f1_flash_unlock(target, 0)) return false; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); - if (!stm32f1_mass_erase_bank(target, FLASH_BANK1_OFFSET, &timeout)) + if (!stm32f1_mass_erase_bank(target, FLASH_BANK1_OFFSET, print_progess)) return false; /* If we're on a part that has a second bank, mass erase that bank too */ if (stm32f1_is_dual_bank(target->part_id)) - return stm32f1_mass_erase_bank(target, FLASH_BANK2_OFFSET, &timeout); + return stm32f1_mass_erase_bank(target, FLASH_BANK2_OFFSET, print_progess); return true; } diff --git a/src/target/stm32f4.c b/src/target/stm32f4.c index af95c1d4980..4336c458dcc 100644 --- a/src/target/stm32f4.c +++ b/src/target/stm32f4.c @@ -152,7 +152,7 @@ static bool gd32f4_attach(target_s *target); static void stm32f4_detach(target_s *target); static bool stm32f4_flash_erase(target_flash_s *target_flash, target_addr_t addr, size_t len); static bool stm32f4_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32f4_mass_erase(target_s *target); +static bool stm32f4_mass_erase(target_s *target, platform_timeout_s *print_progess); static void stm32f4_add_flash(target_s *const target, const uint32_t addr, const size_t length, const size_t blocksize, const uint8_t base_sector, const uint8_t split) @@ -589,21 +589,19 @@ static bool stm32f4_flash_write(target_flash_s *flash, target_addr_t dest, const return stm32f4_flash_busy_wait(target, NULL); } -static bool stm32f4_mass_erase(target_s *target) +static bool stm32f4_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { /* XXX: Is it correct to grab the most recently added Flash region here? What is this really trying to do? */ - stm32f4_flash_s *sf = (stm32f4_flash_s *)target->flash; + stm32f4_flash_s *stm32f4_flash = (stm32f4_flash_s *)target->flash; stm32f4_flash_unlock(target); /* Flash mass erase start instruction */ - const uint32_t ctrl = FLASH_CR_MER | (sf->bank_split ? FLASH_CR_MER1 : 0); + const uint32_t ctrl = FLASH_CR_MER | (stm32f4_flash->bank_split ? FLASH_CR_MER1 : 0); target_mem32_write32(target, FLASH_CR, ctrl); target_mem32_write32(target, FLASH_CR, ctrl | FLASH_CR_STRT); - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Wait for completion or an error */ - return stm32f4_flash_busy_wait(target, &timeout); + return stm32f4_flash_busy_wait(target, print_progess); } /* diff --git a/src/target/stm32g0.c b/src/target/stm32g0.c index 6fd51ce8d0d..0dd95b443ac 100644 --- a/src/target/stm32g0.c +++ b/src/target/stm32g0.c @@ -168,7 +168,7 @@ static bool stm32g0_attach(target_s *target); static void stm32g0_detach(target_s *target); static bool stm32g0_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool stm32g0_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32g0_mass_erase(target_s *target); +static bool stm32g0_mass_erase(target_s *target, platform_timeout_s *print_progess); /* Custom commands */ static bool stm32g0_cmd_erase_bank(target_s *target, int argc, const char **argv); @@ -471,17 +471,15 @@ static bool stm32g0_flash_write(target_flash_s *flash, target_addr_t dest, const return true; } -static bool stm32g0_mass_erase(target_s *target) +static bool stm32g0_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { const uint32_t ctrl = FLASH_CR_MER1 | FLASH_CR_MER2 | FLASH_CR_START; stm32g0_flash_unlock(target); target_mem32_write32(target, FLASH_CR, ctrl); - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Wait for completion or an error */ - if (!stm32g0_wait_busy(target, &timeout)) { + if (!stm32g0_wait_busy(target, print_progess)) { stm32g0_flash_op_finish(target); return false; } diff --git a/src/target/stm32h5.c b/src/target/stm32h5.c index 9340853ba01..d613618502b 100644 --- a/src/target/stm32h5.c +++ b/src/target/stm32h5.c @@ -151,7 +151,7 @@ static bool stm32h5_enter_flash_mode(target_s *target); static bool stm32h5_exit_flash_mode(target_s *target); static bool stm32h5_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool stm32h5_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32h5_mass_erase(target_s *target); +static bool stm32h5_mass_erase(target_s *target, platform_timeout_s *print_progess); static void stm32h5_add_flash( target_s *const target, const uint32_t base_addr, const size_t length, const uint32_t bank_and_sector_count) @@ -357,19 +357,17 @@ static bool stm32h5_flash_write( return true; } -static bool stm32h5_mass_erase(target_s *const target) +static bool stm32h5_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { /* To start mass erase, enter into Flash mode */ if (!stm32h5_enter_flash_mode(target)) return false; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Trigger the mass erase */ target_mem32_write32(target, STM32H5_FLASH_CTRL, STM32H5_FLASH_CTRL_MASS_ERASE); target_mem32_write32(target, STM32H5_FLASH_CTRL, STM32H5_FLASH_CTRL_MASS_ERASE | STM32H5_FLASH_CTRL_START); /* And wait for it to complete, reporting errors along the way */ - const bool result = stm32h5_flash_wait_complete(target, &timeout); + const bool result = stm32h5_flash_wait_complete(target, print_progess); /* When done, leave Flash mode */ return stm32h5_exit_flash_mode(target) && result; diff --git a/src/target/stm32h7.c b/src/target/stm32h7.c index 2e3b52ed3f7..99d758da120 100644 --- a/src/target/stm32h7.c +++ b/src/target/stm32h7.c @@ -212,7 +212,7 @@ static bool stm32h7_flash_erase(target_flash_s *target_flash, target_addr_t addr static bool stm32h7_flash_write(target_flash_s *target_flash, target_addr_t dest, const void *src, size_t len); static bool stm32h7_flash_prepare(target_flash_s *target_flash); static bool stm32h7_flash_done(target_flash_s *target_flash); -static bool stm32h7_mass_erase(target_s *target); +static bool stm32h7_mass_erase(target_s *target, platform_timeout_s *print_progess); static uint32_t stm32h7_flash_bank_base(const uint32_t addr) { @@ -600,7 +600,7 @@ static bool stm32h7_check_bank(target_s *const target, const uint32_t reg_base) } /* Both banks are erased in parallel.*/ -static bool stm32h7_mass_erase(target_s *target) +static bool stm32h7_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { align_e psize = ALIGN_64BIT; /* @@ -617,11 +617,9 @@ static bool stm32h7_mass_erase(target_s *target) !stm32h7_erase_bank(target, psize, STM32H7_FPEC2_BASE)) return false; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Wait for the banks to finish erasing */ - if (!stm32h7_wait_erase_bank(target, &timeout, STM32H7_FPEC1_BASE) || - !stm32h7_wait_erase_bank(target, &timeout, STM32H7_FPEC2_BASE)) + if (!stm32h7_wait_erase_bank(target, print_progess, STM32H7_FPEC1_BASE) || + !stm32h7_wait_erase_bank(target, print_progess, STM32H7_FPEC2_BASE)) return false; /* Check the banks for final errors */ diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 7f8fd334a2e..416c2ba1193 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -177,7 +177,7 @@ static bool stm32lx_flash_erase(target_flash_s *flash, target_addr_t addr, size_ static bool stm32lx_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); static bool stm32lx_eeprom_erase(target_flash_s *flash, target_addr_t addr, size_t length); static bool stm32lx_eeprom_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); -static bool stm32lx_mass_erase(target_s *target); +static bool stm32lx_mass_erase(target_s *target, platform_timeout_s *print_progess); typedef struct stm32l_priv { target_addr32_t uid_taddr; @@ -659,8 +659,10 @@ static bool stm32lx_eeprom_write( return stm32lx_nvm_busy_wait(target, flash_base, NULL); } -static bool stm32lx_mass_erase(target_s *const target) +static bool stm32lx_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { + (void)print_progess; + for (target_flash_s *flash = target->flash; flash; flash = flash->next) { const bool result = stm32lx_flash_erase(flash, flash->start, flash->length); if (!result) diff --git a/src/target/stm32l4.c b/src/target/stm32l4.c index 0faa4c1438d..7734338f348 100644 --- a/src/target/stm32l4.c +++ b/src/target/stm32l4.c @@ -65,7 +65,7 @@ static bool stm32l4_attach(target_s *target); static void stm32l4_detach(target_s *target); static bool stm32l4_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool stm32l4_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32l4_mass_erase(target_s *target); +static bool stm32l4_mass_erase(target_s *target, platform_timeout_s *print_progess); const command_s stm32l4_cmd_list[] = { {"erase_bank1", stm32l4_cmd_erase_bank1, "Erase entire bank1 flash memory"}, @@ -855,7 +855,7 @@ static void stm32l4_flash_unlock(target_s *const target) } } -static bool stm32l4_flash_busy_wait(target_s *const target, platform_timeout_s *timeout) +static bool stm32l4_flash_busy_wait(target_s *const target, platform_timeout_s *const print_progess) { /* Read FLASH_SR to poll for BSY bit */ uint32_t status = FLASH_SR_BSY; @@ -865,8 +865,8 @@ static bool stm32l4_flash_busy_wait(target_s *const target, platform_timeout_s * DEBUG_ERROR("stm32l4 Flash error: status 0x%" PRIx32 "\n", status); return false; } - if (timeout) - target_print_progress(timeout); + if (print_progess) + target_print_progress(print_progess); } return true; } @@ -911,7 +911,7 @@ static bool stm32l4_flash_write(target_flash_s *flash, target_addr_t dest, const return stm32l4_flash_busy_wait(target, NULL); } -static bool stm32l4_cmd_erase(target_s *const target, const uint32_t action) +static bool stm32l4_cmd_erase(target_s *const target, const uint32_t action, platform_timeout_s *const print_progess) { stm32l4_flash_unlock(target); /* Erase time is 25 ms. Timeout logic shouldn't get fired.*/ @@ -919,15 +919,13 @@ static bool stm32l4_cmd_erase(target_s *const target, const uint32_t action) stm32l4_flash_write32(target, FLASH_CR, action); stm32l4_flash_write32(target, FLASH_CR, action | FLASH_CR_STRT); - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500); /* Wait for completion or an error */ - return stm32l4_flash_busy_wait(target, &timeout); + return stm32l4_flash_busy_wait(target, print_progess); } -static bool stm32l4_mass_erase(target_s *const target) +static bool stm32l4_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { - return stm32l4_cmd_erase(target, FLASH_CR_MER1 | FLASH_CR_MER2); + return stm32l4_cmd_erase(target, FLASH_CR_MER1 | FLASH_CR_MER2, print_progess); } static bool stm32l4_cmd_erase_bank1(target_s *const target, const int argc, const char **const argv) @@ -935,7 +933,7 @@ static bool stm32l4_cmd_erase_bank1(target_s *const target, const int argc, cons (void)argc; (void)argv; tc_printf(target, "Erasing bank %u: ", 1U); - const bool result = stm32l4_cmd_erase(target, FLASH_CR_MER1); + const bool result = stm32l4_cmd_erase(target, FLASH_CR_MER1, NULL); tc_printf(target, "done\n"); return result; } @@ -945,7 +943,7 @@ static bool stm32l4_cmd_erase_bank2(target_s *const target, const int argc, cons (void)argc; (void)argv; tc_printf(target, "Erasing bank %u: ", 2U); - const bool result = stm32l4_cmd_erase(target, FLASH_CR_MER2); + const bool result = stm32l4_cmd_erase(target, FLASH_CR_MER2, NULL); tc_printf(target, "done\n"); return result; } diff --git a/src/target/stm32wb0.c b/src/target/stm32wb0.c index 3875f12ffd7..401648a4f68 100644 --- a/src/target/stm32wb0.c +++ b/src/target/stm32wb0.c @@ -82,7 +82,7 @@ static bool stm32wb0_enter_flash_mode(target_s *target); static bool stm32wb0_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool stm32wb0_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool stm32wb0_mass_erase(target_s *target); +static bool stm32wb0_mass_erase(target_s *target, platform_timeout_s *print_progess); static void stm32wb0_add_flash(target_s *const target, const size_t length) { @@ -208,16 +208,14 @@ static bool stm32wb0_flash_write( return true; } -static bool stm32wb0_mass_erase(target_s *const target) +static bool stm32wb0_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { /* To start the mass erase, prep the controller */ if (!stm32wb0_enter_flash_mode(target)) return false; - platform_timeout_s timeout; - platform_timeout_set(&timeout, 500U); /* Set up and run the mass erase */ target_mem32_write32(target, STM32WB0_FLASH_COMMAND, STM32WB0_FLASH_COMMAND_MASS_ERASE); /* Then wait for the erase to complete and report any errors */ - return stm32wb0_flash_wait_complete(target, &timeout); + return stm32wb0_flash_wait_complete(target, print_progess); } diff --git a/src/target/target_flash.c b/src/target/target_flash.c index f43374c42b3..4d3cb109b3c 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -177,11 +177,15 @@ bool target_flash_erase(target_s *target, target_addr_t addr, size_t len) /* Run specialized target mass erase if available, otherwise erase all flash' */ bool target_flash_mass_erase(target_s *const target) { + /* Setup progress printout */ + platform_timeout_s print_progess; + platform_timeout_set(&print_progess, 500U); + if (target->mass_erase) { DEBUG_TARGET("Running specialized target mass erase\n"); /* Run specialized target mass erase */ - return target->mass_erase(target); + return target->mass_erase(target, &print_progess); } else { DEBUG_WARN("No specialized target mass erase available\n"); return false; diff --git a/src/target/target_internal.h b/src/target/target_internal.h index ab7b11e5489..8c7c06ec6d1 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -138,7 +138,7 @@ struct target { breakwatch_s *bw_list; /* Recovery functions */ - bool (*mass_erase)(target_s *target); + bool (*mass_erase)(target_s *target, platform_timeout_s *print_progess); /* Mass erase all target flash */ /* Flash functions */ bool (*enter_flash_mode)(target_s *target); From aa2883848817c705f55cbe4719b334e82dc681eb Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 15:24:44 +0100 Subject: [PATCH 03/17] target: implement target_enter_flash_mode_stub target_enter_flash_mode_stub is a No-op stub for use in the target->enter_flash_mode API where the default behaviour of resetting the target is undesirable --- src/target/target.c | 6 ++++++ src/target/target_internal.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/target/target.c b/src/target/target.c index d5cedf1b55c..156326d5af7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -233,6 +233,12 @@ void target_add_flash(target_s *target, target_flash_s *flash) target->flash = flash; } +bool target_enter_flash_mode_stub(target_s *target) +{ + (void)target; + return true; +} + static ssize_t map_ram(char *buf, size_t len, target_ram_s *ram) { return snprintf(buf, len, "", ram->start, diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 8c7c06ec6d1..26545fa12c6 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -192,6 +192,9 @@ void target_add_ram32(target_s *target, target_addr32_t start, uint32_t len); void target_add_ram64(target_s *target, target_addr64_t start, uint64_t len); void target_add_flash(target_s *target, target_flash_s *flash); +/* No-op stub for enter flash mode */ +bool target_enter_flash_mode_stub(target_s *target); + target_flash_s *target_flash_for_addr(target_s *target, uint32_t addr); /* Convenience function for MMIO access */ From 0ce5867a0bdefbddb57f4b341ad8672715bfedd4 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 15:46:54 +0100 Subject: [PATCH 04/17] target: enter target flash mode before runing mass erase routine --- src/target/efm32.c | 1 + src/target/hc32l110.c | 2 -- src/target/kinetis.c | 1 + src/target/lpc17xx.c | 5 ----- src/target/lpc40xx.c | 5 ----- src/target/lpc55xx.c | 1 + src/target/nrf51.c | 1 + src/target/stm32h5.c | 9 +-------- src/target/target_flash.c | 10 ++++++++-- 9 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/target/efm32.c b/src/target/efm32.c index 66ddbceaf36..0f123f34bd3 100644 --- a/src/target/efm32.c +++ b/src/target/efm32.c @@ -948,6 +948,7 @@ bool efm32_aap_probe(adiv5_access_port_s *ap) return false; } + t->enter_flash_mode = target_enter_flash_mode_stub; t->mass_erase = efm32_aap_mass_erase; adiv5_ap_ref(ap); diff --git a/src/target/hc32l110.c b/src/target/hc32l110.c index 1efc94a1b15..41a3f3a11c4 100644 --- a/src/target/hc32l110.c +++ b/src/target/hc32l110.c @@ -217,8 +217,6 @@ static bool hc32l110_flash_write( static bool hc32l110_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { - hc32l110_enter_flash_mode(target); - hc32l110_flash_cr_unlock(target); target_mem32_write32(target, HC32L110_FLASH_CR, HC32L110_FLASH_CR_OP_ERASE_CHIP); if (!hc32l110_check_flash_completion(target, 500U, print_progess)) diff --git a/src/target/kinetis.c b/src/target/kinetis.c index 39b9c795f91..896b22becaa 100644 --- a/src/target/kinetis.c +++ b/src/target/kinetis.c @@ -569,6 +569,7 @@ bool kinetis_mdm_probe(adiv5_access_port_s *ap) return false; } + t->enter_flash_mode = target_enter_flash_mode_stub; t->mass_erase = kinetis_mdm_mass_erase; adiv5_ap_ref(ap); t->priv = ap; diff --git a/src/target/lpc17xx.c b/src/target/lpc17xx.c index 717b02ea7b7..8e1905f6120 100644 --- a/src/target/lpc17xx.c +++ b/src/target/lpc17xx.c @@ -171,27 +171,22 @@ static bool lpc17xx_exit_flash_mode(target_s *const target) static bool lpc17xx_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { iap_result_s result; - lpc17xx_enter_flash_mode(target); if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { - lpc17xx_exit_flash_mode(target); DEBUG_ERROR("lpc17xx_cmd_erase: prepare failed %" PRIu32 "\n", result.return_code); return false; } if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { - lpc17xx_exit_flash_mode(target); DEBUG_ERROR("lpc17xx_cmd_erase: erase failed %" PRIu32 "\n", result.return_code); return false; } if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { - lpc17xx_exit_flash_mode(target); DEBUG_ERROR("lpc17xx_cmd_erase: blankcheck failed %" PRIu32 "\n", result.return_code); return false; } - lpc17xx_exit_flash_mode(target); return true; } diff --git a/src/target/lpc40xx.c b/src/target/lpc40xx.c index 218661f4629..6b3bbd20b25 100644 --- a/src/target/lpc40xx.c +++ b/src/target/lpc40xx.c @@ -165,27 +165,22 @@ static bool lpc40xx_exit_flash_mode(target_s *const target) static bool lpc40xx_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { iap_result_s result; - lpc40xx_enter_flash_mode(target); if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { - lpc40xx_exit_flash_mode(target); DEBUG_ERROR("lpc40xx_cmd_erase: prepare failed %" PRIu32 "\n", result.return_code); return false; } if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { - lpc40xx_exit_flash_mode(target); DEBUG_ERROR("lpc40xx_cmd_erase: erase failed %" PRIu32 "\n", result.return_code); return false; } if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { - lpc40xx_exit_flash_mode(target); DEBUG_ERROR("lpc40xx_cmd_erase: blankcheck failed %" PRIu32 "\n", result.return_code); return false; } - lpc40xx_exit_flash_mode(target); return true; } diff --git a/src/target/lpc55xx.c b/src/target/lpc55xx.c index 2bf4d04acb7..9c7edf95d09 100644 --- a/src/target/lpc55xx.c +++ b/src/target/lpc55xx.c @@ -620,6 +620,7 @@ bool lpc55_dmap_probe(adiv5_access_port_s *ap) target->driver = "LPC55 Debug Mailbox"; target->regs_size = 0; + target->enter_flash_mode = target_enter_flash_mode_stub; target->mass_erase = lpc55_dmap_mass_erase; return true; diff --git a/src/target/nrf51.c b/src/target/nrf51.c index 5cc112f8ebd..27ae11a91b0 100644 --- a/src/target/nrf51.c +++ b/src/target/nrf51.c @@ -416,6 +416,7 @@ bool nrf51_mdm_probe(adiv5_access_port_s *ap) if (!t) return false; + t->enter_flash_mode = target_enter_flash_mode_stub; t->mass_erase = nrf51_mdm_mass_erase; adiv5_ap_ref(ap); t->priv = ap; diff --git a/src/target/stm32h5.c b/src/target/stm32h5.c index d613618502b..6e2213ad754 100644 --- a/src/target/stm32h5.c +++ b/src/target/stm32h5.c @@ -359,18 +359,11 @@ static bool stm32h5_flash_write( static bool stm32h5_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { - /* To start mass erase, enter into Flash mode */ - if (!stm32h5_enter_flash_mode(target)) - return false; - /* Trigger the mass erase */ target_mem32_write32(target, STM32H5_FLASH_CTRL, STM32H5_FLASH_CTRL_MASS_ERASE); target_mem32_write32(target, STM32H5_FLASH_CTRL, STM32H5_FLASH_CTRL_MASS_ERASE | STM32H5_FLASH_CTRL_START); /* And wait for it to complete, reporting errors along the way */ - const bool result = stm32h5_flash_wait_complete(target, print_progess); - - /* When done, leave Flash mode */ - return stm32h5_exit_flash_mode(target) && result; + return stm32h5_flash_wait_complete(target, print_progess); } static bool stm32h5_cmd_uid(target_s *target, int argc, const char **argv) diff --git a/src/target/target_flash.c b/src/target/target_flash.c index 4d3cb109b3c..5e44c415d8a 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -177,19 +177,25 @@ bool target_flash_erase(target_s *target, target_addr_t addr, size_t len) /* Run specialized target mass erase if available, otherwise erase all flash' */ bool target_flash_mass_erase(target_s *const target) { + if (!target_enter_flash_mode(target)) + return false; + /* Setup progress printout */ platform_timeout_s print_progess; platform_timeout_set(&print_progess, 500U); + bool result = false; if (target->mass_erase) { DEBUG_TARGET("Running specialized target mass erase\n"); /* Run specialized target mass erase */ - return target->mass_erase(target, &print_progess); + result = target->mass_erase(target, &print_progess); } else { DEBUG_WARN("No specialized target mass erase available\n"); - return false; } + + target_exit_flash_mode(target); + return result; } bool flash_buffer_alloc(target_flash_s *flash) From c2a0599f1dbae3a4d8eda2d69f1e99e0108d4e90 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 15:54:40 +0100 Subject: [PATCH 05/17] target: erase all flash block by block if no specialized mass erase routine is available Targets that don't provide a dedicated mass erase routine will have it's flash erased block by block when the user requests a mass erase --- src/target/target_flash.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/target/target_flash.c b/src/target/target_flash.c index 5e44c415d8a..e2ca7a83505 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -174,6 +174,16 @@ bool target_flash_erase(target_s *target, target_addr_t addr, size_t len) return result; } +static inline bool flash_manual_mass_erase(target_flash_s *const flash, platform_timeout_s *const print_progess) +{ + for (target_addr_t addr = flash->start; addr < flash->start + flash->length; addr += flash->blocksize) { + if (!flash->erase(flash, addr, flash->blocksize)) + return false; + target_print_progress(print_progess); + } + return true; +} + /* Run specialized target mass erase if available, otherwise erase all flash' */ bool target_flash_mass_erase(target_s *const target) { @@ -191,7 +201,23 @@ bool target_flash_mass_erase(target_s *const target) /* Run specialized target mass erase */ result = target->mass_erase(target, &print_progess); } else { - DEBUG_WARN("No specialized target mass erase available\n"); + DEBUG_WARN("No specialized target mass erase available, erasing all flash\n"); + + /* Erase all target flash */ + for (target_flash_s *flash = target->flash; flash; flash = flash->next) { + result = flash_prepare(flash, FLASH_OPERATION_ERASE); + if (!result) { + DEBUG_ERROR("Failed to prepare flash 0x%08" PRIx32 " for mass erase\n", flash->start); + break; + } + + result = flash_manual_mass_erase(flash, &print_progess); + result &= flash_done(flash); /* Don't overwrite previous result, AND with it instead */ + if (!result) { + DEBUG_ERROR("Failed to mass erase flash 0x%08" PRIx32 "\n", flash->start); + break; + } + } } target_exit_flash_mode(target); From da06536c719ad5afe21cb59291ac33286c6e8781 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 15:59:44 +0100 Subject: [PATCH 06/17] target/stm32l0: remove deprecated mass erase Mass erase now by default manually erases target flash block by block when no specialized routine is available, the removed mass erase routine duplicates said functionality --- src/target/stm32l0.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/target/stm32l0.c b/src/target/stm32l0.c index 416c2ba1193..b19087ac50e 100644 --- a/src/target/stm32l0.c +++ b/src/target/stm32l0.c @@ -177,7 +177,6 @@ static bool stm32lx_flash_erase(target_flash_s *flash, target_addr_t addr, size_ static bool stm32lx_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); static bool stm32lx_eeprom_erase(target_flash_s *flash, target_addr_t addr, size_t length); static bool stm32lx_eeprom_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t length); -static bool stm32lx_mass_erase(target_s *target, platform_timeout_s *print_progess); typedef struct stm32l_priv { target_addr32_t uid_taddr; @@ -277,7 +276,6 @@ bool stm32l0_probe(target_s *const target) target->driver = "STM32L0"; target->attach = stm32l0_attach; target->detach = stm32l0_detach; - target->mass_erase = stm32lx_mass_erase; target_add_commands(target, stm32lx_cmd_list, target->driver); /* Having identified that it's a STM32L0 of some sort, read out how much Flash it has */ @@ -351,7 +349,6 @@ bool stm32l1_probe(target_s *const target) stm32l1_configure_dbgmcu(target); target->driver = "STM32L1"; - target->mass_erase = stm32lx_mass_erase; target_add_commands(target, stm32lx_cmd_list, target->driver); /* There's no good way to tell how much RAM a part has, so use a one-size map */ target_add_ram32(target, STM32Lx_SRAM_BASE, STM32L1_SRAM_SIZE); @@ -659,18 +656,6 @@ static bool stm32lx_eeprom_write( return stm32lx_nvm_busy_wait(target, flash_base, NULL); } -static bool stm32lx_mass_erase(target_s *const target, platform_timeout_s *const print_progess) -{ - (void)print_progess; - - for (target_flash_s *flash = target->flash; flash; flash = flash->next) { - const bool result = stm32lx_flash_erase(flash, flash->start, flash->length); - if (!result) - return false; - } - return true; -} - /* * Write one option word. * The address is the physical address of the word and the value is a complete word value. From 9fc85ac5ecaa60eb2a04c98f3d833a1acc35cadf Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:02:32 +0100 Subject: [PATCH 07/17] target/lpc546xx: remove deprecated mass erase Mass erase now by default manually erases target flash block by block when no specialized routine is available, this mass erase routine duplicates said functionality --- src/target/lpc546xx.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/target/lpc546xx.c b/src/target/lpc546xx.c index 2e1cb76fccb..e751714690c 100644 --- a/src/target/lpc546xx.c +++ b/src/target/lpc546xx.c @@ -61,7 +61,6 @@ static bool lpc546xx_cmd_write_sector(target_s *t, int argc, const char **argv); static void lpc546xx_reset_attach(target_s *t); static bool lpc546xx_flash_init(target_s *t); static bool lpc546xx_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); -static bool lpc546xx_mass_erase(target_s *t, platform_timeout_s *print_progess); static void lpc546xx_wdt_set_period(target_s *t); static void lpc546xx_wdt_kick(target_s *t); @@ -152,7 +151,6 @@ bool lpc546xx_probe(target_s *t) */ sram123_size = device->sram123_kbytes * 1024U; - t->mass_erase = lpc546xx_mass_erase; lpc546xx_add_flash(t, IAP_ENTRYPOINT_LOCATION, 0, 0x0, flash_size, 0x8000); /* @@ -182,22 +180,12 @@ static void lpc546xx_reset_attach(target_s *t) cortexm_attach(t); } -static bool lpc546xx_mass_erase(target_s *t, platform_timeout_s *const print_progess) -{ - (void)print_progess; - - const int result = lpc546xx_flash_erase(t->flash, t->flash->start, t->flash->length); - if (result != 0) - tc_printf(t, "Error erasing flash: %d\n", result); - return result == 0; -} - static bool lpc546xx_cmd_erase_sector(target_s *t, int argc, const char **argv) { if (argc > 1) { uint32_t sector_addr = strtoul(argv[1], NULL, 0); sector_addr *= t->flash->blocksize; - return lpc546xx_flash_erase(t->flash, sector_addr, 1U); + return target_flash_erase(t, sector_addr, 1U); } return true; } From f0bc3673a03d789214215d8e2bee86d39b1af430 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:05:32 +0100 Subject: [PATCH 08/17] target/lmi: remove deprecated mass erase Mass erase now by default manually erases target flash block by block when no specialized routine is available, this mass erase routine duplicates said functionality --- src/target/lmi.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/target/lmi.c b/src/target/lmi.c index 0a4ec323e9b..a30460370a7 100644 --- a/src/target/lmi.c +++ b/src/target/lmi.c @@ -102,7 +102,6 @@ static bool lmi_flash_erase(target_flash_s *flash, target_addr_t addr, size_t len); static bool lmi_flash_write(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); -static bool lmi_mass_erase(target_s *target, platform_timeout_s *print_progess); static const uint16_t lmi_flash_write_stub[] = { #include "flashstub/lmi.stub" @@ -141,7 +140,6 @@ bool lm3s_probe(target_s *const target, const uint16_t did1) return false; } target->driver = "Stellaris"; - target->mass_erase = lmi_mass_erase; return true; } @@ -177,7 +175,6 @@ bool tm4c_probe(target_s *const target, const uint16_t did1) return false; } target->driver = "Tiva-C"; - target->mass_erase = lmi_mass_erase; cortex_ap(target)->dp->quirks |= ADIV5_DP_QUIRK_DUPED_AP; return true; } @@ -236,9 +233,3 @@ static bool lmi_flash_write(target_flash_s *flash, target_addr_t dest, const voi return cortexm_run_stub(target, SRAM_BASE, dest, STUB_BUFFER_BASE, len, 0) == 0; } - -static bool lmi_mass_erase(target_s *target, platform_timeout_s *print_progess) -{ - (void)print_progess; - return lmi_flash_erase(target->flash, target->flash->start, target->flash->length); -} From f25eb50bc26d4c2c91210c8aae4c43f614bae6ce Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:07:34 +0100 Subject: [PATCH 09/17] target: add flash specific mass erase routine This routine, like the other flash routines is called in between a flash prepare and flash done, with the FLASH_OPERATION_MASS_ERASE. It is meant to be used where the flash controller implements functionality to totally erase the relevant flash, and nothing else, mainly targeted at targets with multiple flash banks and funcionality to erase the banks wholly, individually --- src/target/target_internal.h | 37 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 26545fa12c6..7c651e891ee 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -36,6 +36,7 @@ extern target_s *target_list; typedef enum flash_operation { FLASH_OPERATION_NONE, FLASH_OPERATION_ERASE, + FLASH_OPERATION_MASS_ERASE, FLASH_OPERATION_WRITE, } flash_operation_e; @@ -52,28 +53,30 @@ typedef struct target_flash target_flash_s; typedef bool (*flash_prepare_func)(target_flash_s *flash); typedef bool (*flash_erase_func)(target_flash_s *flash, target_addr_t addr, size_t len); +typedef bool (*flash_mass_erase_func)(target_flash_s *flash, platform_timeout_s *print_progess); typedef bool (*flash_write_func)(target_flash_s *flash, target_addr_t dest, const void *src, size_t len); typedef bool (*flash_done_func)(target_flash_s *flash); struct target_flash { /* XXX: This needs adjusting for 64-bit operations */ - target_s *t; /* Target this flash is attached to */ - target_addr32_t start; /* Start address of flash */ - size_t length; /* Flash length */ - size_t blocksize; /* Erase block size */ - size_t writesize; /* Write operation size, must be <= blocksize/writebufsize */ - size_t writebufsize; /* Size of write buffer, this is calculated and not set in target code */ - uint8_t erased; /* Byte erased state */ - uint8_t operation; /* Current Flash operation (none means it's idle/unprepared) */ - flash_prepare_func prepare; /* Prepare for flash operations */ - flash_erase_func erase; /* Erase a range of flash */ - flash_write_func write; /* Write to flash */ - flash_done_func done; /* Finish flash operations */ - uint8_t *buf; /* Buffer for flash operations */ - target_addr32_t buf_addr_base; /* Address of block this buffer is for */ - target_addr32_t buf_addr_low; /* Address of lowest byte written */ - target_addr32_t buf_addr_high; /* Address of highest byte written */ - target_flash_s *next; /* Next flash in list */ + target_s *t; /* Target this flash is attached to */ + target_addr32_t start; /* Start address of flash */ + size_t length; /* Flash length */ + size_t blocksize; /* Erase block size */ + size_t writesize; /* Write operation size, must be <= blocksize/writebufsize */ + size_t writebufsize; /* Size of write buffer, this is calculated and not set in target code */ + uint8_t erased; /* Byte erased state */ + uint8_t operation; /* Current Flash operation (none means it's idle/unprepared) */ + flash_prepare_func prepare; /* Prepare for flash operations */ + flash_erase_func erase; /* Erase a range of flash */ + flash_mass_erase_func mass_erase; /* Mass erase flash (this flash only) */ + flash_write_func write; /* Write to flash */ + flash_done_func done; /* Finish flash operations */ + uint8_t *buf; /* Buffer for flash operations */ + target_addr32_t buf_addr_base; /* Address of block this buffer is for */ + target_addr32_t buf_addr_low; /* Address of lowest byte written */ + target_addr32_t buf_addr_high; /* Address of highest byte written */ + target_flash_s *next; /* Next flash in list */ }; typedef bool (*cmd_handler_fn)(target_s *target, int argc, const char **argv); From 370df7f9f3d34e8b7895e098d341c25cdd67c871 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:13:55 +0100 Subject: [PATCH 10/17] target: use flash mass erase routine when available --- src/target/target_flash.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/target/target_flash.c b/src/target/target_flash.c index e2ca7a83505..94b3580ff2c 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -205,13 +205,22 @@ bool target_flash_mass_erase(target_s *const target) /* Erase all target flash */ for (target_flash_s *flash = target->flash; flash; flash = flash->next) { - result = flash_prepare(flash, FLASH_OPERATION_ERASE); + /* If the flash has a mass erase function, use it */ + const bool can_use_mass_erase = flash->mass_erase != NULL; + + if (can_use_mass_erase) + DEBUG_TARGET("Running specialized flash mass erase for flash 0x%08" PRIx32 "\n", flash->start); + else + DEBUG_WARN("No specialized flash mass erase available for 0x%08" PRIx32 "\n", flash->start); + + result = flash_prepare(flash, can_use_mass_erase ? FLASH_OPERATION_MASS_ERASE : FLASH_OPERATION_ERASE); if (!result) { DEBUG_ERROR("Failed to prepare flash 0x%08" PRIx32 " for mass erase\n", flash->start); break; } - result = flash_manual_mass_erase(flash, &print_progess); + result = can_use_mass_erase ? flash->mass_erase(flash, &print_progess) : + flash_manual_mass_erase(flash, &print_progess); result &= flash_done(flash); /* Don't overwrite previous result, AND with it instead */ if (!result) { DEBUG_ERROR("Failed to mass erase flash 0x%08" PRIx32 "\n", flash->start); From d5fb79130c13fee30d3472451e235ba49c50108b Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:24:14 +0100 Subject: [PATCH 11/17] target/spi: refactor bmp_spi_mass_erase as a flash mass erase routine All targets that add a spi flash will have mass erase routines by default without te need to explicitly provide them, this also is more correct for scope and fixes the assumption that the first target flash registred is a spi flash --- src/target/imxrt.c | 1 - src/target/lpc43xx.c | 1 - src/target/renesas_rz.c | 3 --- src/target/rp2040.c | 1 - src/target/rp2350.c | 1 - src/target/spi.c | 31 +++++++++++++++---------------- src/target/spi.h | 2 +- 7 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/target/imxrt.c b/src/target/imxrt.c index 7f0c1141eac..16ff530777c 100644 --- a/src/target/imxrt.c +++ b/src/target/imxrt.c @@ -253,7 +253,6 @@ bool imxrt_probe(target_s *const target) spi_flash_id_s flash_id; imxrt_spi_read(target, SPI_FLASH_CMD_READ_JEDEC_ID, 0, &flash_id, sizeof(flash_id)); - target->mass_erase = bmp_spi_mass_erase; target->enter_flash_mode = imxrt_enter_flash_mode; target->exit_flash_mode = imxrt_exit_flash_mode; diff --git a/src/target/lpc43xx.c b/src/target/lpc43xx.c index 352df6a9a47..c95a4ae08c1 100644 --- a/src/target/lpc43xx.c +++ b/src/target/lpc43xx.c @@ -504,7 +504,6 @@ bool lpc43xx_probe(target_s *const t) if (part_id.part == LPC43xx_PARTID_INVALID) return false; - t->mass_erase = bmp_spi_mass_erase; t->enter_flash_mode = lpc43x0_enter_flash_mode; t->exit_flash_mode = lpc43x0_exit_flash_mode; lpc43x0_detect(t, part_id); diff --git a/src/target/renesas_rz.c b/src/target/renesas_rz.c index 0055a9e182c..2d8646e5987 100644 --- a/src/target/renesas_rz.c +++ b/src/target/renesas_rz.c @@ -166,9 +166,6 @@ static void renesas_rz_add_flash(target_s *const target) /* Put the controller back into bus usage mode */ target_mem32_write32(target, RENESAS_MULTI_IO_SPI_COMMON_CTRL, target_mem32_read32(target, RENESAS_MULTI_IO_SPI_COMMON_CTRL) & ~RENESAS_MULTI_IO_SPI_COMMON_CTRL_MODE_SPI); - - /* Register the SPI Flash mass erase implementation for mass erase */ - target->mass_erase = bmp_spi_mass_erase; } bool renesas_rz_probe(target_s *const target) diff --git a/src/target/rp2040.c b/src/target/rp2040.c index 2e9613f93e9..ffb11fce803 100644 --- a/src/target/rp2040.c +++ b/src/target/rp2040.c @@ -247,7 +247,6 @@ bool rp2040_probe(target_s *const target) } target->target_storage = (void *)priv_storage; - target->mass_erase = bmp_spi_mass_erase; target->driver = "RP2040"; target->target_options |= TOPT_INHIBIT_NRST; target->attach = rp_attach; diff --git a/src/target/rp2350.c b/src/target/rp2350.c index 3006d4e2f27..c70faff87ab 100644 --- a/src/target/rp2350.c +++ b/src/target/rp2350.c @@ -169,7 +169,6 @@ bool rp2350_probe(target_s *const target) } DEBUG_TARGET("Boot ROM version: %x\n", (uint8_t)(boot_magic >> RP2350_BOOTROM_VERSION_SHIFT)); - target->mass_erase = bmp_spi_mass_erase; target->driver = "RP2350"; target->attach = rp2350_attach; target->enter_flash_mode = rp2350_flash_prepare; diff --git a/src/target/spi.c b/src/target/spi.c index 33bce203508..872c68f4451 100644 --- a/src/target/spi.c +++ b/src/target/spi.c @@ -132,6 +132,7 @@ spi_flash_s *bmp_spi_add_flash(target_s *const target, const target_addr_t begin flash->blocksize = spi_parameters.sector_size; flash->write = bmp_spi_flash_write; flash->erase = bmp_spi_flash_erase; + flash->mass_erase = bmp_spi_mass_erase; flash->erased = 0xffU; target_add_flash(target, flash); @@ -143,29 +144,27 @@ spi_flash_s *bmp_spi_add_flash(target_s *const target, const target_addr_t begin return spi_flash; } -/* Note: These routines assume that the first Flash registered on the target is a SPI Flash device */ -bool bmp_spi_mass_erase(target_s *const target, platform_timeout_s *const print_progess) +bool bmp_spi_mass_erase(target_flash_s *const flash, platform_timeout_s *const print_progess) { DEBUG_TARGET("Running %s\n", __func__); - /* Extract the Flash structure */ - const spi_flash_s *const flash = (spi_flash_s *)target->flash; + /* Extract the Target and Flash structure */ + target_s *const target = flash->t; + const spi_flash_s *const spi_flash = (spi_flash_s *)flash; - /* Go into Flash mode and tell the Flash to enable writing */ - target->enter_flash_mode(target); - flash->run_command(target, SPI_FLASH_CMD_WRITE_ENABLE, 0U); - if (!(bmp_spi_read_status(target, flash) & SPI_FLASH_STATUS_WRITE_ENABLED)) { - target->exit_flash_mode(target); + /* Tell the Flash to enable writing */ + spi_flash->run_command(target, SPI_FLASH_CMD_WRITE_ENABLE, 0U); + if (!(bmp_spi_read_status(target, spi_flash) & SPI_FLASH_STATUS_WRITE_ENABLED)) return false; - } - /* Execute a full chip erase and wait for the operatoin to complete */ - flash->run_command(target, SPI_FLASH_CMD_CHIP_ERASE, 0U); - while (bmp_spi_read_status(target, flash) & SPI_FLASH_STATUS_BUSY) - target_print_progress(print_progess); + /* Execute a full chip erase and wait for the operation to complete */ + spi_flash->run_command(target, SPI_FLASH_CMD_CHIP_ERASE, 0U); + while (bmp_spi_read_status(target, spi_flash) & SPI_FLASH_STATUS_BUSY) { + if (print_progess) + target_print_progress(print_progess); + } - /* Finally, leave Flash mode to conclude business */ - return target->exit_flash_mode(target); + return true; } static bool bmp_spi_flash_erase(target_flash_s *const flash, const target_addr_t addr, const size_t length) diff --git a/src/target/spi.h b/src/target/spi.h index bbdbbc10708..225fdbe4934 100644 --- a/src/target/spi.h +++ b/src/target/spi.h @@ -93,6 +93,6 @@ void bmp_spi_run_command(spi_bus_e bus, uint8_t device, uint16_t command, target spi_flash_s *bmp_spi_add_flash(target_s *target, target_addr_t begin, size_t length, spi_read_func spi_read, spi_write_func spi_write, spi_run_command_func spi_run_command); -bool bmp_spi_mass_erase(target_s *target, platform_timeout_s *print_progess); +bool bmp_spi_mass_erase(target_flash_s *flash, platform_timeout_s *print_progess); #endif /* TARGET_SPI_H */ From 3f9b32cc892667c34f7e2e90fbf53e612ff25951 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:26:08 +0100 Subject: [PATCH 12/17] target/hc32l110: streamline mass erase routine with target flash api --- src/target/hc32l110.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/target/hc32l110.c b/src/target/hc32l110.c index 41a3f3a11c4..92bff7222bb 100644 --- a/src/target/hc32l110.c +++ b/src/target/hc32l110.c @@ -177,18 +177,26 @@ static bool hc32l110_flash_prepare(target_flash_s *const flash) { hc32l110_flash_cr_unlock(flash->t); + uint32_t cr_operation = 0; switch (flash->operation) { case FLASH_OPERATION_WRITE: - target_mem32_write32(flash->t, HC32L110_FLASH_CR, HC32L110_FLASH_CR_OP_PROGRAM); + cr_operation = HC32L110_FLASH_CR_OP_PROGRAM; break; case FLASH_OPERATION_ERASE: - target_mem32_write32(flash->t, HC32L110_FLASH_CR, HC32L110_FLASH_CR_OP_ERASE_SECTOR); + cr_operation = HC32L110_FLASH_CR_OP_ERASE_SECTOR; + break; + case FLASH_OPERATION_MASS_ERASE: + cr_operation = HC32L110_FLASH_CR_OP_ERASE_CHIP; break; default: DEBUG_WARN("unsupported operation %u", flash->operation); return false; } + target_mem32_write32(flash->t, HC32L110_FLASH_CR, cr_operation); + if (!hc32l110_check_flash_completion(flash->t, 500U, NULL)) + return false; + hc32l110_slock_unlock_all(flash->t); return true; } @@ -215,19 +223,10 @@ static bool hc32l110_flash_write( return hc32l110_check_flash_completion(flash->t, 1000, NULL); } +/* FIXME: looks like this might make sense as a flash->mass erase routine */ static bool hc32l110_mass_erase(target_s *const target, platform_timeout_s *const print_progess) { - hc32l110_flash_cr_unlock(target); - target_mem32_write32(target, HC32L110_FLASH_CR, HC32L110_FLASH_CR_OP_ERASE_CHIP); - if (!hc32l110_check_flash_completion(target, 500U, print_progess)) - return false; - - hc32l110_slock_unlock_all(target); - // The Flash controller automatically erases the whole Flash after one write operation - target_mem32_write32(target, 0, 0); - const bool result = hc32l110_check_flash_completion(target, 4000U, print_progess); - - hc32l110_slock_lock_all(target); - return result; + target_mem32_write32(target, 0x0U, 0U); + return hc32l110_check_flash_completion(target, 4000U, print_progess); } From 5a8778d6eb4bf7b181096e69c0a268581b0c8959 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:28:51 +0100 Subject: [PATCH 13/17] target/nrf51: use flash api operation in place of undefined behaviour Using the buffer allocation state as a means to determine the flash operation is undefined and not guaranteed to work in the future, use proper API --- src/target/nrf51.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/target/nrf51.c b/src/target/nrf51.c index 27ae11a91b0..a60975c9291 100644 --- a/src/target/nrf51.c +++ b/src/target/nrf51.c @@ -176,17 +176,24 @@ static bool nrf51_wait_ready(target_s *const t, platform_timeout_s *const print_ return true; } -static bool nrf51_flash_prepare(target_flash_s *f) +static bool nrf51_flash_prepare(target_flash_s *const f) { - target_s *t = f->t; - /* If there is a buffer allocated, we're in the Flash write phase, otherwise it's erase */ - if (f->buf) + target_s *const target = f->t; + + switch (f->operation) { + case FLASH_OPERATION_WRITE: /* Enable write */ - target_mem32_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_WEN); - else + target_mem32_write32(target, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_WEN); + break; + case FLASH_OPERATION_ERASE: /* Enable erase */ - target_mem32_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN); - return nrf51_wait_ready(t, NULL); + target_mem32_write32(target, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN); + break; + default: + return false; /* Unsupported operation */ + } + + return nrf51_wait_ready(target, NULL); } static bool nrf51_flash_done(target_flash_s *f) From 86b3a7b12f8e641a8233d32c8c9388769513aab4 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:29:08 +0100 Subject: [PATCH 14/17] target/nxpke04: add fixme note --- src/target/nxpke04.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/nxpke04.c b/src/target/nxpke04.c index 5a056c4154b..ead63ad8060 100644 --- a/src/target/nxpke04.c +++ b/src/target/nxpke04.c @@ -242,6 +242,7 @@ bool ke04_probe(target_s *t) static bool ke04_mass_erase(target_s *const t, platform_timeout_s *const print_progess) { (void)print_progess; + /* FIXME: looks like this might make sense as a flash->mass erase routine */ /* Erase and verify the whole flash */ ke04_command(t, CMD_ERASE_ALL_BLOCKS, 0, NULL); From 3a64c12dde1213b74fcbdb92a9ad497c2b1784a3 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Sep 2023 16:30:33 +0100 Subject: [PATCH 15/17] target: optimize flash erase using the mass erase routine When an erase is requested that would result in a complete erase of a flash and the mass erase routine is provided, use it as a speed optimization --- src/target/target_flash.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/target/target_flash.c b/src/target/target_flash.c index 94b3580ff2c..d45342cd73e 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -154,18 +154,29 @@ bool target_flash_erase(target_s *target, target_addr_t addr, size_t len) active_flash = flash; } + /* Align the start address to the erase block size */ const target_addr_t local_start_addr = addr & ~(flash->blocksize - 1U); - const target_addr_t local_end_addr = local_start_addr + flash->blocksize; - if (!flash_prepare(flash, FLASH_OPERATION_ERASE)) + /* Check if we can use mass erase */ + const bool can_use_mass_erase = + flash->mass_erase != NULL && local_start_addr == flash->start && addr + len >= flash->start + flash->length; + + /* Calculate the address at the end of the erase block */ + const target_addr_t local_end_addr = + can_use_mass_erase ? flash->start + flash->length : local_start_addr + flash->blocksize; + + if (!flash_prepare(flash, can_use_mass_erase ? FLASH_OPERATION_MASS_ERASE : FLASH_OPERATION_ERASE)) return false; - result &= flash->erase(flash, local_start_addr, flash->blocksize); + /* Erase flash, either a single aligned block size or a full mass erase */ + result &= can_use_mass_erase ? flash->mass_erase(flash, NULL) : + flash->erase(flash, local_start_addr, flash->blocksize); if (!result) { DEBUG_ERROR("Erase failed at %" PRIx32 "\n", local_start_addr); break; } + /* Update the remaining length and address, taking into account the alignment */ len -= MIN(local_end_addr - addr, len); addr = local_end_addr; } From 5627de9d7535c29114da05c78ca72348571c77df Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Fri, 8 Nov 2024 15:12:31 +0000 Subject: [PATCH 16/17] target_flash: add note to flash mass erase api method This is a very important restriction to ensure the method is safe to use during normal load operations --- src/target/target_flash.c | 2 +- src/target/target_internal.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/target/target_flash.c b/src/target/target_flash.c index d45342cd73e..ad7dcef69b9 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -157,7 +157,7 @@ bool target_flash_erase(target_s *target, target_addr_t addr, size_t len) /* Align the start address to the erase block size */ const target_addr_t local_start_addr = addr & ~(flash->blocksize - 1U); - /* Check if we can use mass erase */ + /* Check if we can use mass erase, i.e. if the erase range covers the entire flash address space */ const bool can_use_mass_erase = flash->mass_erase != NULL && local_start_addr == flash->start && addr + len >= flash->start + flash->length; diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 7c651e891ee..f7755cc94ae 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -69,7 +69,7 @@ struct target_flash { uint8_t operation; /* Current Flash operation (none means it's idle/unprepared) */ flash_prepare_func prepare; /* Prepare for flash operations */ flash_erase_func erase; /* Erase a range of flash */ - flash_mass_erase_func mass_erase; /* Mass erase flash (this flash only) */ + flash_mass_erase_func mass_erase; /* Mass erase flash (this flash only¹) */ flash_write_func write; /* Write to flash */ flash_done_func done; /* Finish flash operations */ uint8_t *buf; /* Buffer for flash operations */ @@ -79,6 +79,11 @@ struct target_flash { target_flash_s *next; /* Next flash in list */ }; +/* + * ¹the mass_erase method must not cause any side effects outside the scope/address space of the flash + * consider using the target mass_erase method instead for such cases + */ + typedef bool (*cmd_handler_fn)(target_s *target, int argc, const char **argv); typedef struct command { From 3576cdffd7f9c5b68f578433a586f19bcb726850 Mon Sep 17 00:00:00 2001 From: Rafael Silva Date: Mon, 11 Nov 2024 16:57:04 +0000 Subject: [PATCH 17/17] target/lpc546xx: mark cmd erase_sector as deprecated in favor of erase_range --- src/target/lpc546xx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/target/lpc546xx.c b/src/target/lpc546xx.c index e751714690c..5fb23bce113 100644 --- a/src/target/lpc546xx.c +++ b/src/target/lpc546xx.c @@ -182,6 +182,8 @@ static void lpc546xx_reset_attach(target_s *t) static bool lpc546xx_cmd_erase_sector(target_s *t, int argc, const char **argv) { + tc_printf(t, "This command is deprecated in favor of erase_range and may be removed in the future\n"); + if (argc > 1) { uint32_t sector_addr = strtoul(argv[1], NULL, 0); sector_addr *= t->flash->blocksize;