+
+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;
+}