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/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..0f123f34bd3 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 { @@ -950,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); @@ -968,9 +967,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 +984,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..92bff7222bb 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; } @@ -174,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; } @@ -201,7 +212,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,24 +220,13 @@ 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) +/* 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_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)) - 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); - - hc32l110_slock_lock_all(target); - return result; + target_mem32_write32(target, 0x0U, 0U); + return hc32l110_check_flash_completion(target, 4000U, print_progess); } 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/kinetis.c b/src/target/kinetis.c index c6dabf44462..896b22becaa 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[] = { @@ -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; @@ -593,13 +594,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 +626,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..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); 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,8 +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) -{ - 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 53d90b0f6dc..8e1905f6120 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,31 +168,25 @@ 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)) { - lpc17xx_exit_flash_mode(target); + if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { 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)) { - lpc17xx_exit_flash_mode(target); + if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { 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)) { - lpc17xx_exit_flash_mode(target); + if (lpc17xx_iap_call(target, &result, print_progess, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { DEBUG_ERROR("lpc17xx_cmd_erase: blankcheck failed %" PRIu32 "\n", result.return_code); return false; } - lpc17xx_exit_flash_mode(target); - tc_printf(target, "Erase OK.\n"); return true; } @@ -222,7 +217,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 = { @@ -237,7 +233,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 */ @@ -250,7 +246,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) */ @@ -260,12 +256,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 fedad18e11a..6b3bbd20b25 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,31 +162,25 @@ 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)) { - lpc40xx_exit_flash_mode(target); + if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR - 1U)) { 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)) { - lpc40xx_exit_flash_mode(target); + if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR - 1U, CPU_CLK_KHZ)) { 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)) { - lpc40xx_exit_flash_mode(target); + if (lpc40xx_iap_call(target, &result, print_progess, IAP_CMD_BLANKCHECK, 0, FLASH_NUM_SECTOR - 1U)) { DEBUG_ERROR("lpc40xx_cmd_erase: blankcheck failed %" PRIu32 "\n", result.return_code); return false; } - lpc40xx_exit_flash_mode(target); - tc_printf(target, "Erase OK.\n"); return true; } @@ -216,7 +211,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 = { @@ -231,7 +227,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 */ @@ -244,22 +240,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..c95a4ae08c1 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); @@ -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); @@ -1000,19 +999,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..5fb23bce113 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); 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,20 +180,14 @@ static void lpc546xx_reset_attach(target_s *t) cortexm_attach(t); } -static bool lpc546xx_mass_erase(target_s *t) -{ - 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) { + 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; - return lpc546xx_flash_erase(t->flash, sector_addr, 1U); + return target_flash_erase(t, sector_addr, 1U); } return true; } diff --git a/src/target/lpc55xx.c b/src/target/lpc55xx.c index 8284aec38c5..9c7edf95d09 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) @@ -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; @@ -656,8 +657,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..a60975c9291 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,29 +164,36 @@ 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; } -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) @@ -225,20 +232,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 +402,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) @@ -420,6 +423,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; @@ -436,21 +440,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..ead63ad8060 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,11 @@ 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; + /* 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); /* Adjust security byte if needed */ 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/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..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) +bool bmp_spi_mass_erase(target_flash_s *const flash, 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__); - /* 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); + + /* Extract the Target and Flash structure */ + target_s *const target = flash->t; + const spi_flash_s *const spi_flash = (spi_flash_s *)flash; + + /* 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(&timeout); + /* 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 3de75bbec80..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); +bool bmp_spi_mass_erase(target_flash_s *flash, 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..6e2213ad754 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,22 +357,13 @@ 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); - - /* 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/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..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); 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,16 +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) -{ - 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. 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.c b/src/target/target.c index 0fa3f69f3c1..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, @@ -486,12 +492,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..ad7dcef69b9 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, 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; + + /* 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; } @@ -174,6 +185,65 @@ 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) +{ + 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 */ + result = target->mass_erase(target, &print_progess); + } else { + 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) { + /* 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 = 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); + break; + } + } + } + + target_exit_flash_mode(target); + return result; +} + bool flash_buffer_alloc(target_flash_s *flash) { /* Allocate buffer */ diff --git a/src/target/target_internal.h b/src/target/target_internal.h index ab7b11e5489..f7755cc94ae 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,30 +53,37 @@ 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 */ }; +/* + * ¹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 { @@ -138,7 +146,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); @@ -192,6 +200,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 */