/* option bytes */
#define OPTION_BYTES_ADDRESS 0x1FF80000
-#define OPTION_BYTE_0_PR1 0x015500AA
-#define OPTION_BYTE_0_PR0 0x01FF0011
+#define OPTION_BYTE_0_PR1 0xFFFF0000
+#define OPTION_BYTE_0_PR0 0xFF5500AA
static int stm32lx_unlock_program_memory(struct flash_bank *bank);
static int stm32lx_lock_program_memory(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);
+static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout);
struct stm32lx_rev {
uint16_t rev;
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
*/
*/
second_bank_base = base_address +
stm32lx_info->part_info->first_bank_size_kb * 1024;
- if (bank->base == second_bank_base) {
+ if (bank->base == second_bank_base || !bank->base) {
/* This is the second bank */
base_address = second_bank_base;
flash_size_in_kb = flash_size_in_kb -
stm32lx_info->part_info->first_bank_size_kb;
- } else if (bank->base == 0 || bank->base == base_address) {
+ } else if (bank->base == base_address) {
/* This is the first bank */
flash_size_in_kb = stm32lx_info->part_info->first_bank_size_kb;
} else {
static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank)
{
- struct target *target = bank->target;
- struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
- uint32_t status;
- int retval = ERROR_OK;
- int timeout = 100;
-
- /* wait for busy to clear */
- for (;;) {
- retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_SR, &status);
- if (retval != ERROR_OK)
- return retval;
-
- 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("access denied / write protected");
- retval = ERROR_FAIL;
- }
-
- if (status & FLASH_SR__PGAERR) {
- LOG_ERROR("invalid program address");
- retval = ERROR_FAIL;
- }
-
- return retval;
+ return stm32lx_wait_until_bsy_clear_timeout(bank, 100);
}
static int stm32lx_unlock_options_bytes(struct flash_bank *bank)
return ERROR_OK;
}
-static int stm32lx_wait_status_busy(struct flash_bank *bank, int timeout)
+static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout)
{
struct target *target = bank->target;
+ struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
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;
}
if (status & FLASH_SR__WRPERR) {
- LOG_ERROR("stm32lx device protected");
+ LOG_ERROR("access denied / write protected");
+ retval = ERROR_FAIL;
+ }
+
+ if (status & FLASH_SR__PGAERR) {
+ LOG_ERROR("invalid program address");
retval = ERROR_FAIL;
}
return retval;
}
+static int stm32lx_obl_launch(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
+ int retval;
+
+ /* This will fail as the target gets immediately rebooted */
+ target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
+ FLASH_PECR__OBL_LAUNCH);
+
+ size_t tries = 10;
+ do {
+ target_halt(target);
+ retval = target_poll(target);
+ } while (--tries > 0 &&
+ (retval != ERROR_OK || target->state != TARGET_HALTED));
+
+ return tries ? ERROR_OK : ERROR_FAIL;
+}
+
static int stm32lx_mass_erase(struct flash_bank *bank)
{
int retval;
if (retval != ERROR_OK)
return retval;
- /* mass erase flash memory, write 0x015500AA option byte address 0*/
- /* pass the RDP privilege to 1 */
+ /* mass erase flash memory */
+ /* set the RDP protection level to 1 */
retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR1);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stm32lx_obl_launch(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stm32lx_unlock_options_bytes(bank);
+ if (retval != ERROR_OK)
+ return retval;
- /* restore the RDP privilege to 0 */
+ /* set the RDP protection level to 0 */
retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stm32lx_wait_until_bsy_clear_timeout(bank, 30000);
+ if (retval != ERROR_OK)
+ return retval;
- /* the mass erase occur when the privilege go back to 0 */
- retval = stm32lx_wait_status_busy(bank, 30000);
+ retval = stm32lx_obl_launch(bank);
if (retval != ERROR_OK)
return retval;