X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32lx.c;h=e5b66cf7fdc7d72a8e8223f602faa976dd3001a3;hp=f7074c3eea18ffe58597cff912b1ebc0af4a7f1e;hb=832f0a5bfb439ed9b6e16df69c4dd95e001db015;hpb=3751214b9cecf69d729985c05361b5bd5441d24a diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index f7074c3eea..e5b66cf7fd 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -92,11 +92,19 @@ #define FLASH_SECTOR_SIZE 4096 #define FLASH_BANK0_ADDRESS 0x08000000 +/* option bytes */ +#define OPTION_BYTES_ADDRESS 0x1FF80000 + +#define OPTION_BYTE_0_PR1 0x015500AA +#define OPTION_BYTE_0_PR0 0x01FF0011 + static int stm32lx_unlock_program_memory(struct flash_bank *bank); static int stm32lx_lock_program_memory(struct flash_bank *bank); static int stm32lx_enable_write_half_page(struct flash_bank *bank); static int stm32lx_erase_sector(struct flash_bank *bank, int sector); static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank); +static int stm32lx_mass_erase(struct flash_bank *bank); +static int stm32lx_wait_status_busy(struct flash_bank *bank, int timeout); struct stm32lx_rev { uint16_t rev; @@ -214,7 +222,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) return ERROR_COMMAND_SYNTAX_ERROR; /* Create the bank structure */ - stm32lx_info = malloc(sizeof(struct stm32lx_flash_bank)); + stm32lx_info = calloc(1, sizeof(*stm32lx_info)); /* Check allocation */ if (stm32lx_info == NULL) { @@ -233,6 +241,32 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) return ERROR_OK; } +COMMAND_HANDLER(stm32lx_handle_mass_erase_command) +{ + int i; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + retval = stm32lx_mass_erase(bank); + if (retval == ERROR_OK) { + /* set all sectors as erased */ + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = 1; + + command_print(CMD_CTX, "stm32lx mass erase complete"); + } else { + command_print(CMD_CTX, "stm32lx mass erase failed"); + } + + return retval; +} + static int stm32lx_protect_check(struct flash_bank *bank) { int retval; @@ -273,6 +307,9 @@ static int stm32lx_erase(struct flash_bank *bank, int first, int last) return ERROR_TARGET_NOT_HALTED; } + if ((first == 0) && (last == (bank->num_sectors - 1))) + return stm32lx_mass_erase(bank); + /* * Loop over the selected sectors and erase them */ @@ -325,7 +362,6 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff 0x93, 0x42, /* cmp r3, r2 */ 0xf8, 0xd3, /* bcc write_word */ 0x00, 0xbe, /* bkpt 0 */ - }; /* Make sure we're performing a half-page aligned write. */ @@ -624,6 +660,7 @@ static int stm32lx_probe(struct flash_bank *bank) uint32_t second_bank_base; stm32lx_info->probed = 0; + stm32lx_info->part_info = NULL; int retval = stm32lx_read_id_code(bank->target, &device_id); if (retval != ERROR_OK) @@ -808,7 +845,6 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) } } - const struct stm32lx_part_info *info = stm32lx_info->part_info; if (info) { @@ -838,6 +874,13 @@ static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) } static const struct command_registration stm32lx_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = stm32lx_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Erase entire flash device. including available EEPROM", + }, COMMAND_REGISTRATION_DONE }; @@ -1052,6 +1095,14 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector) return ERROR_OK; } +static inline int stm32lx_get_flash_status(struct flash_bank *bank, uint32_t *status) +{ + struct target *target = bank->target; + struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; + + return target_read_u32(target, stm32lx_info->flash_base + FLASH_SR, status); +} + static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank) { struct target *target = bank->target; @@ -1062,8 +1113,7 @@ static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank) /* wait for busy to clear */ for (;;) { - retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_SR, - &status); + retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_SR, &status); if (retval != ERROR_OK) return retval; @@ -1088,3 +1138,127 @@ static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank) return retval; } + +static int stm32lx_unlock_options_bytes(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; + int retval; + uint32_t reg32; + + /* + * Unlocking the options bytes is done by unlocking the PECR, + * then by writing the 2 FLASH_PEKEYR to the FLASH_OPTKEYR register + */ + + /* check flash is not already unlocked */ + retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); + if (retval != ERROR_OK) + return retval; + + if ((reg32 & FLASH_PECR__OPTLOCK) == 0) + return ERROR_OK; + + if ((reg32 & FLASH_PECR__PELOCK) != 0) { + + retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY2); + if (retval != ERROR_OK) + return retval; + } + + /* To unlock the PECR write the 2 OPTKEY to the FLASH_OPTKEYR register */ + retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_OPTKEYR, OPTKEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_OPTKEYR, OPTKEY2); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32lx_wait_status_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + uint32_t status; + + int retval = ERROR_OK; + struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; + + /* wait for busy to clear */ + for (;;) { + + retval = stm32lx_get_flash_status(bank, &status); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("status: 0x%" PRIx32 "", status); + if ((status & FLASH_SR__BSY) == 0) + break; + + if (timeout-- <= 0) { + LOG_ERROR("timed out waiting for flash"); + return ERROR_FAIL; + } + alive_sleep(1); + } + + if (status & FLASH_SR__WRPERR) { + LOG_ERROR("stm32lx device protected"); + retval = ERROR_FAIL; + } + + /* Clear but report errors */ + if (status & FLASH_SR__OPTVERR) { + /* If this operation fails, we ignore it and report the original retval */ + target_write_u32(target, stm32lx_info->flash_base + FLASH_SR, status & FLASH_SR__OPTVERR); + } + + return retval; +} + +static int stm32lx_mass_erase(struct flash_bank *bank) +{ + int retval; + struct target *target = bank->target; + struct stm32lx_flash_bank *stm32lx_info = NULL; + uint32_t reg32; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + stm32lx_info = bank->driver_priv; + + retval = stm32lx_unlock_options_bytes(bank); + if (retval != ERROR_OK) + return retval; + + /* mass erase flash memory, write 0x015500AA option byte address 0*/ + /* pass the RDP privilege to 1 */ + retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR1); + + /* restore the RDP privilege to 0 */ + retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR0); + + /* the mass erase occur when the privilege go back to 0 */ + retval = stm32lx_wait_status_busy(bank, 30000); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, ®32); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32 | FLASH_PECR__OPTLOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +}