flash/nor/stm32l: fix mass erase
authorPaul Fertser <fercerpav@gmail.com>
Fri, 23 Jan 2015 09:33:50 +0000 (12:33 +0300)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 4 Feb 2015 22:00:52 +0000 (22:00 +0000)
Topaz reports on http://sourceforge.net/p/openocd/tickets/87/ that
protection level constants are mixed up. This leads to device ending
up in protection level 1 after mass erase.

Additional work is required to actually put the device in RDP Level 1
and then back to Level 0, as Option bootloader launch is a special
kind of full target reset.

To be able to flash properly after mass_erase a "reset init" is needed
(it's anyway recommended to always perform it before any flash
operation).

Change-Id: I9a838909458039bb0114d3019723bf134fa4d7c9
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2490
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
src/flash/nor/stm32lx.c

index e5b66cf7fdc7d72a8e8223f602faa976dd3001a3..13db7b924a66a7fe76933bdb5c9204516c1541cd 100644 (file)
@@ -95,8 +95,8 @@
 /* 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);
@@ -1222,6 +1222,26 @@ static int stm32lx_wait_status_busy(struct flash_bank *bank, int timeout)
        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;
@@ -1240,18 +1260,33 @@ static int stm32lx_mass_erase(struct flash_bank *bank)
        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;
 
-       /* restore the RDP privilege to 0 */
+       retval = stm32lx_obl_launch(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32lx_unlock_options_bytes(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* 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;
 
-       /* 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 = stm32lx_obl_launch(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
        retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, &reg32);
        if (retval != ERROR_OK)
                return retval;