This is an automated email from Gerrit. "Marc Schink <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9319
-- gerrit commit e93a65009d7b9bce03e4376e73b3fed4506e68b0 Author: Marc Schink <[email protected]> Date: Wed Dec 17 11:07:45 2025 +0000 flash/nor: Support erase check on banks without sectors The current implementation of the deletion check is closely tied to the concept of sectors. Implement a workaround to support sectorless banks without having to make many changes to the code base. Tested with nRF54L15-DK, tested for regression with AT32F421C8T7. Change-Id: I88fd5d56f2edbd8337663bea8d25cd499c09add6 Signed-off-by: Marc Schink <[email protected]> diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 93ad9bffb9..8e495730bd 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -368,6 +368,67 @@ done: return retval; } +static int flash_blank_check_no_sectors_fast(struct flash_bank *bank) +{ + struct target_memory_check_block check_block; + + check_block.address = bank->base; + check_block.size = bank->size; + // Erase state unknown. + check_block.result = UINT32_MAX; + + int retval = target_blank_check_memory(bank->target, &check_block, 1, + bank->erased_value); + + if (retval < 1) + return retval; + + bank->is_erased = check_block.result; + + return ERROR_OK; +} + +static int flash_blank_check_no_sectors(struct flash_bank *bank) +{ + struct target *target = bank->target; + const uint32_t buffer_size = 1024; + uint8_t buffer[buffer_size]; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = flash_blank_check_no_sectors_fast(bank); + if (retval == ERROR_OK) + return retval; + + LOG_WARNING("Fast erase check failed, running slow fallback"); + + bank->is_erased = 1; + + for (uint32_t offset = 0; offset < bank->size; offset += buffer_size) { + uint32_t chunk_size = MIN(buffer_size, bank->size - offset); + + retval = target_read_memory(target, + bank->base + offset, + 4, + chunk_size / 4, + buffer); + if (retval != ERROR_OK) + return retval; + + for (uint32_t i = 0; i < chunk_size; i++) { + if (buffer[i] != bank->erased_value) { + bank->is_erased = 0; + break; + } + } + } + + return ERROR_OK; +} + int default_flash_blank_check(struct flash_bank *bank) { struct target *target = bank->target; @@ -378,6 +439,9 @@ int default_flash_blank_check(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } + if (bank->num_sectors == 0) + return flash_blank_check_no_sectors(bank); + struct target_memory_check_block *block_array; block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block)); if (!block_array) diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index f8cf5e2698..369c6c3069 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -114,6 +114,17 @@ struct flash_bank { unsigned int num_sectors; /** Array of sectors, allocated and initialized by the flash driver */ struct flash_sector *sectors; + /** + * Indication of erasure status: 0 = not erased, 1 = erased, + * other = unknown. Set by @c flash_driver::erase_check only. + * + * Use this only if the flash bank has no sectors. + * + * This information must be considered stale immediately. + * Don't set it in flash_driver::erase or a device mass_erase + * Don't clear it in flash_driver::write + */ + int is_erased; /** * The number of protection blocks in this bank. This value diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 60bdad5562..d2566fe720 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -218,6 +218,9 @@ COMMAND_HANDLER(handle_flash_erase_check_command) erase_state); } + if (p->num_sectors == 0) + blank = (p->is_erased == 1); + if (blank) command_print(CMD, "\tBank is erased"); return retval; --
