flash/stm32l4x: add support of STM32WB1x
[openocd.git] / src / flash / nor / stm32l4x.c
index e6d3a8350bba59ae6c38c1ecf7fabb7e5ac4226c..9f7d9e5e06cedbb7269702cf1271b1704ddfe4f5 100644 (file)
@@ -27,7 +27,7 @@
 #include <helper/align.h>
 #include <helper/binarybuffer.h>
 #include <target/algorithm.h>
-#include <target/armv7m.h>
+#include <target/cortex_m.h>
 #include "bits.h"
 #include "stm32l4x.h"
 
  *  - for STM32L4P5/Q5x
  *    In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
  *    In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode.
- *
  */
 
 /* STM32WBxxx series for reference.
  *
- * RM0434 (STM32WB55)
+ * RM0434 (STM32WB55/WB35x)
  * http://www.st.com/resource/en/reference_manual/dm00318631.pdf
  *
- * RM0471 (STM32WB50)
+ * RM0471 (STM32WB50/WB30x)
  * http://www.st.com/resource/en/reference_manual/dm00622834.pdf
+ *
+ * RM0473 (STM32WB15x)
+ * http://www.st.com/resource/en/reference_manual/dm00649196.pdf
+ *
+ * RM0478 (STM32WB10x)
+ * http://www.st.com/resource/en/reference_manual/dm00689203.pdf
  */
 
 /* STM32WLxxx series for reference.
  *
  * RM0461 (STM32WLEx)
  * http://www.st.com/resource/en/reference_manual/dm00530369.pdf
+ *
+ * RM0453 (STM32WL5x)
+ * http://www.st.com/resource/en/reference_manual/dm00451556.pdf
  */
 
 /* STM32G0xxx series for reference.
 /* Erase time can be as high as 25ms, 10x this and assume it's toast... */
 
 #define FLASH_ERASE_TIMEOUT 250
+#define FLASH_WRITE_TIMEOUT 50
 
 
 /* relevant STM32L4 flags ****************************************************/
 #define F_USE_ALL_WRPXX     BIT(1)
 /* this flag indicates if the device embeds a TrustZone security feature */
 #define F_HAS_TZ            BIT(2)
+/* this flag indicates if the device has the same flash registers as STM32L5 */
+#define F_HAS_L5_FLASH_REGS BIT(3)
+/* this flag indicates that programming should be done in quad-word
+ * the default programming word size is double-word */
+#define F_QUAD_WORD_PROG    BIT(4)
 /* end of STM32L4 flags ******************************************************/
 
 
@@ -136,6 +150,9 @@ enum stm32l4_flash_reg_index {
        STM32_FLASH_OPTKEYR_INDEX,
        STM32_FLASH_SR_INDEX,
        STM32_FLASH_CR_INDEX,
+       /* for some devices like STM32WL5x, the CPU2 have a dedicated C2CR register w/o LOCKs,
+        * so it uses the C2CR for flash operations and CR for checking locks and locking */
+       STM32_FLASH_CR_WLK_INDEX, /* FLASH_CR_WITH_LOCK */
        STM32_FLASH_OPTR_INDEX,
        STM32_FLASH_WRP1AR_INDEX,
        STM32_FLASH_WRP1BR_INDEX,
@@ -164,12 +181,37 @@ static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
        [STM32_FLASH_WRP2BR_INDEX]   = 0x050,
 };
 
-static const uint32_t stm32l5_ns_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
+static const uint32_t stm32wl_cpu2_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
        [STM32_FLASH_ACR_INDEX]      = 0x000,
        [STM32_FLASH_KEYR_INDEX]     = 0x008,
        [STM32_FLASH_OPTKEYR_INDEX]  = 0x010,
-       [STM32_FLASH_SR_INDEX]       = 0x020,
-       [STM32_FLASH_CR_INDEX]       = 0x028,
+       [STM32_FLASH_SR_INDEX]       = 0x060,
+       [STM32_FLASH_CR_INDEX]       = 0x064,
+       [STM32_FLASH_CR_WLK_INDEX]   = 0x014,
+       [STM32_FLASH_OPTR_INDEX]     = 0x020,
+       [STM32_FLASH_WRP1AR_INDEX]   = 0x02C,
+       [STM32_FLASH_WRP1BR_INDEX]   = 0x030,
+};
+
+static const uint32_t stm32l5_ns_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
+       [STM32_FLASH_ACR_INDEX]      = 0x000,
+       [STM32_FLASH_KEYR_INDEX]     = 0x008, /* NSKEYR */
+       [STM32_FLASH_OPTKEYR_INDEX]  = 0x010,
+       [STM32_FLASH_SR_INDEX]       = 0x020, /* NSSR */
+       [STM32_FLASH_CR_INDEX]       = 0x028, /* NSCR */
+       [STM32_FLASH_OPTR_INDEX]     = 0x040,
+       [STM32_FLASH_WRP1AR_INDEX]   = 0x058,
+       [STM32_FLASH_WRP1BR_INDEX]   = 0x05C,
+       [STM32_FLASH_WRP2AR_INDEX]   = 0x068,
+       [STM32_FLASH_WRP2BR_INDEX]   = 0x06C,
+};
+
+static const uint32_t stm32l5_s_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
+       [STM32_FLASH_ACR_INDEX]      = 0x000,
+       [STM32_FLASH_KEYR_INDEX]     = 0x00C, /* SECKEYR */
+       [STM32_FLASH_OPTKEYR_INDEX]  = 0x010,
+       [STM32_FLASH_SR_INDEX]       = 0x024, /* SECSR */
+       [STM32_FLASH_CR_INDEX]       = 0x02C, /* SECCR */
        [STM32_FLASH_OPTR_INDEX]     = 0x040,
        [STM32_FLASH_WRP1AR_INDEX]   = 0x058,
        [STM32_FLASH_WRP1BR_INDEX]   = 0x05C,
@@ -190,7 +232,6 @@ struct stm32l4_part_info {
        const uint16_t max_flash_size_kb;
        const uint32_t flags; /* one bit per feature, see STM32L4 flags: macros F_XXX */
        const uint32_t flash_regs_base;
-       const uint32_t *default_flash_regs;
        const uint32_t fsize_addr;
        const uint32_t otp_base;
        const uint32_t otp_size;
@@ -203,12 +244,18 @@ struct stm32l4_flash_bank {
        bool dual_bank_mode;
        int hole_sectors;
        uint32_t user_bank_size;
+       uint32_t data_width;
+       uint32_t cr_bker_mask;
+       uint32_t sr_bsy_mask;
        uint32_t wrpxxr_mask;
        const struct stm32l4_part_info *part_info;
+       uint32_t flash_regs_base;
        const uint32_t *flash_regs;
        bool otp_enabled;
+       bool use_flashloader;
        enum stm32l4_rdp rdp;
        bool tzen;
+       uint32_t optr;
 };
 
 enum stm32_bank_id {
@@ -227,7 +274,7 @@ struct stm32l4_wrp {
 };
 
 /* human readable list of families this drivers supports (sorted alphabetically) */
-static const char *device_families = "STM32G0/G4/L4/L4+/L5/WB/WL";
+static const char *device_families = "STM32G0/G4/L4/L4+/L5/U5/WB/WL";
 
 static const struct stm32l4_rev stm32_415_revs[] = {
        { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
@@ -237,6 +284,10 @@ static const struct stm32l4_rev stm32_435_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
 };
 
+static const struct stm32l4_rev stm32_456_revs[] = {
+       { 0x1000, "A" },
+};
+
 static const struct stm32l4_rev stm32_460_revs[] = {
        { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" },
 };
@@ -257,6 +308,10 @@ static const struct stm32l4_rev stm32_466_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" },
 };
 
+static const struct stm32l4_rev stm32_467_revs[] = {
+       { 0x1000, "A" },
+};
+
 static const struct stm32l4_rev stm32_468_revs[] = {
        { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
 };
@@ -281,6 +336,14 @@ static const struct stm32l4_rev stm32_479_revs[] = {
        { 0x1000, "A" },
 };
 
+static const struct stm32l4_rev stm32_482_revs[] = {
+       { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32_494_revs[] = {
+       { 0x1000, "A" }, { 0x2000, "B" },
+};
+
 static const struct stm32l4_rev stm32_495_revs[] = {
        { 0x2001, "2.1" },
 };
@@ -302,7 +365,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 1024,
          .flags                 = F_HAS_DUAL_BANK,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -315,7 +377,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 256,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
+         .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
+       {
+         .id                    = 0x456,
+         .revs                  = stm32_456_revs,
+         .num_revs              = ARRAY_SIZE(stm32_456_revs),
+         .device_str            = "STM32G05/G06xx",
+         .max_flash_size_kb     = 64,
+         .flags                 = F_NONE,
+         .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -328,7 +401,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 128,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -341,7 +413,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 1024,
          .flags                 = F_HAS_DUAL_BANK,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -354,7 +425,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 512,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -367,7 +437,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 128,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -380,7 +449,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 64,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
+         .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
+       {
+         .id                    = 0x467,
+         .revs                  = stm32_467_revs,
+         .num_revs              = ARRAY_SIZE(stm32_467_revs),
+         .device_str            = "STM32G0Bx/G0Cx",
+         .max_flash_size_kb     = 512,
+         .flags                 = F_HAS_DUAL_BANK,
+         .flash_regs_base       = 0x40022000,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -393,7 +473,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 128,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -406,7 +485,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 512,
          .flags                 = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -419,7 +497,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 2048,
          .flags                 = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -432,7 +509,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 1024,
          .flags                 = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -443,9 +519,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .num_revs              = ARRAY_SIZE(stm32_472_revs),
          .device_str            = "STM32L55/L56xx",
          .max_flash_size_kb     = 512,
-         .flags                 = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX | F_HAS_TZ,
+         .flags                 = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX | F_HAS_TZ | F_HAS_L5_FLASH_REGS,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l5_ns_flash_regs,
          .fsize_addr            = 0x0BFA05E0,
          .otp_base              = 0x0BFA0000,
          .otp_size              = 512,
@@ -458,7 +533,30 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 512,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x40022000,
-         .default_flash_regs    = stm32l4_flash_regs,
+         .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
+       {
+         .id                    = 0x482,
+         .revs                  = stm32_482_revs,
+         .num_revs              = ARRAY_SIZE(stm32_482_revs),
+         .device_str            = "STM32U57/U58xx",
+         .max_flash_size_kb     = 2048,
+         .flags                 = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x0BFA07A0,
+         .otp_base              = 0x0BFA0000,
+         .otp_size              = 512,
+       },
+       {
+         .id                    = 0x494,
+         .revs                  = stm32_494_revs,
+         .num_revs              = ARRAY_SIZE(stm32_494_revs),
+         .device_str            = "STM32WB1x",
+         .max_flash_size_kb     = 320,
+         .flags                 = F_NONE,
+         .flash_regs_base       = 0x58004000,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -471,7 +569,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 1024,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x58004000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -484,7 +581,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 512,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x58004000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -493,11 +589,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .id                    = 0x497,
          .revs                  = stm32_497_revs,
          .num_revs              = ARRAY_SIZE(stm32_497_revs),
-         .device_str            = "STM32WLEx",
+         .device_str            = "STM32WLEx/WL5x",
          .max_flash_size_kb     = 256,
          .flags                 = F_NONE,
          .flash_regs_base       = 0x58004000,
-         .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
@@ -521,13 +616,10 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
                return ERROR_FAIL; /* Checkme: What better error to use?*/
        bank->driver_priv = stm32l4_info;
 
-       /* The flash write must be aligned to a double word (8-bytes) boundary.
-        * Ask the flash infrastructure to ensure required alignment */
-       bank->write_start_alignment = bank->write_end_alignment = 8;
-
        stm32l4_info->probed = false;
        stm32l4_info->otp_enabled = false;
        stm32l4_info->user_bank_size = bank->size;
+       stm32l4_info->use_flashloader = true;
 
        return ERROR_OK;
 }
@@ -620,16 +712,16 @@ static inline bool stm32l4_otp_is_enabled(struct flash_bank *bank)
        return stm32l4_info->otp_enabled;
 }
 
-static void stm32l4_sync_rdp_tzen(struct flash_bank *bank, uint32_t optr_value)
+static void stm32l4_sync_rdp_tzen(struct flash_bank *bank)
 {
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
 
        bool tzen = false;
 
        if (stm32l4_info->part_info->flags & F_HAS_TZ)
-               tzen = (optr_value & FLASH_TZEN) != 0;
+               tzen = (stm32l4_info->optr & FLASH_TZEN) != 0;
 
-       uint32_t rdp = optr_value & FLASH_RDP_MASK;
+       uint32_t rdp = stm32l4_info->optr & FLASH_RDP_MASK;
 
        /* for devices without TrustZone:
         *   RDP level 0 and 2 values are to 0xAA and 0xCC
@@ -652,7 +744,7 @@ static void stm32l4_sync_rdp_tzen(struct flash_bank *bank, uint32_t optr_value)
 static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
 {
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
-       return stm32l4_info->part_info->flash_regs_base + reg_offset;
+       return stm32l4_info->flash_regs_base + reg_offset;
 }
 
 static inline uint32_t stm32l4_get_flash_reg_by_index(struct flash_bank *bank,
@@ -688,6 +780,7 @@ static inline int stm32l4_write_flash_reg_by_index(struct flash_bank *bank,
 
 static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
 {
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        uint32_t status;
        int retval = ERROR_OK;
 
@@ -697,7 +790,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
                if (retval != ERROR_OK)
                        return retval;
                LOG_DEBUG("status: 0x%" PRIx32 "", status);
-               if ((status & FLASH_BSY) == 0)
+               if ((status & stm32l4_info->sr_bsy_mask) == 0)
                        break;
                if (timeout-- <= 0) {
                        LOG_ERROR("timed out waiting for flash");
@@ -724,14 +817,65 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
        return retval;
 }
 
+/** set all FLASH_SECBB registers to the same value */
+static int stm32l4_set_secbb(struct flash_bank *bank, uint32_t value)
+{
+       /* This function should be used only with device with TrustZone, do just a security check */
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       assert(stm32l4_info->part_info->flags & F_HAS_TZ);
+
+       /* based on RM0438 Rev6 for STM32L5x devices:
+        * to modify a page block-based security attribution, it is recommended to
+        *  1- check that no flash operation is ongoing on the related page
+        *  2- add ISB instruction after modifying the page security attribute in SECBBxRy
+        *     this step is not need in case of JTAG direct access
+        */
+       int retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* write SECBBxRy registers */
+       LOG_DEBUG("setting secure block-based areas registers (SECBBxRy) to 0x%08x", value);
+
+       const uint8_t secbb_regs[] = {
+                       FLASH_SECBB1(1), FLASH_SECBB1(2), FLASH_SECBB1(3), FLASH_SECBB1(4), /* bank 1 SECBB register offsets */
+                       FLASH_SECBB2(1), FLASH_SECBB2(2), FLASH_SECBB2(3), FLASH_SECBB2(4)  /* bank 2 SECBB register offsets */
+       };
+
+
+       unsigned int num_secbb_regs = ARRAY_SIZE(secbb_regs);
+
+       /* in single bank mode, it's useless to modify FLASH_SECBB2Rx registers
+        * then consider only the first half of secbb_regs
+        */
+       if (!stm32l4_info->dual_bank_mode)
+               num_secbb_regs /= 2;
+
+       for (unsigned int i = 0; i < num_secbb_regs; i++) {
+               retval = stm32l4_write_flash_reg(bank, secbb_regs[i], value);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static inline int stm32l4_get_flash_cr_with_lock_index(struct flash_bank *bank)
+{
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       return (stm32l4_info->flash_regs[STM32_FLASH_CR_WLK_INDEX]) ?
+               STM32_FLASH_CR_WLK_INDEX : STM32_FLASH_CR_INDEX;
+}
+
 static int stm32l4_unlock_reg(struct flash_bank *bank)
 {
+       const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank);
        uint32_t ctrl;
 
        /* first check if not already unlocked
         * otherwise writing on STM32_FLASH_KEYR will fail
         */
-       int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -747,7 +891,7 @@ static int stm32l4_unlock_reg(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -761,9 +905,10 @@ static int stm32l4_unlock_reg(struct flash_bank *bank)
 
 static int stm32l4_unlock_option_reg(struct flash_bank *bank)
 {
+       const uint32_t flash_cr_index = stm32l4_get_flash_cr_with_lock_index(bank);
        uint32_t ctrl;
 
-       int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       int retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -779,7 +924,7 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank)
        if (retval != ERROR_OK)
                return retval;
 
-       retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
+       retval = stm32l4_read_flash_reg_by_index(bank, flash_cr_index, &ctrl);
        if (retval != ERROR_OK)
                return retval;
 
@@ -791,9 +936,47 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank)
        return ERROR_OK;
 }
 
+static int stm32l4_perform_obl_launch(struct flash_bank *bank)
+{
+       int retval, retval2;
+
+       retval = stm32l4_unlock_reg(bank);
+       if (retval != ERROR_OK)
+               goto err_lock;
+
+       retval = stm32l4_unlock_option_reg(bank);
+       if (retval != ERROR_OK)
+               goto err_lock;
+
+       /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload,
+        * but the RMs explicitly do *NOT* list this as power-on reset cause, and:
+        * "Note: If the read protection is set while the debugger is still
+        * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset."
+        */
+
+       /* "Setting OBL_LAUNCH generates a reset so the option byte loading is performed under system reset" */
+       /* Due to this reset ST-Link reports an SWD_DP_ERROR, despite the write was successful,
+        * then just ignore the returned value */
+       stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OBL_LAUNCH);
+
+       /* Need to re-probe after change */
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       stm32l4_info->probed = false;
+
+err_lock:
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank),
+                       FLASH_LOCK | FLASH_OPTLOCK);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       return retval2;
+}
+
 static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset,
        uint32_t value, uint32_t mask)
 {
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        uint32_t optiondata;
        int retval, retval2;
 
@@ -801,6 +984,12 @@ static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset,
        if (retval != ERROR_OK)
                return retval;
 
+       /* for STM32L5 and similar devices, use always non-secure
+        * registers for option bytes programming */
+       const uint32_t *saved_flash_regs = stm32l4_info->flash_regs;
+       if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS)
+               stm32l4_info->flash_regs = stm32l5_ns_flash_regs;
+
        retval = stm32l4_unlock_reg(bank);
        if (retval != ERROR_OK)
                goto err_lock;
@@ -822,7 +1011,9 @@ static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset,
        retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK | FLASH_OPTLOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank),
+                       FLASH_LOCK | FLASH_OPTLOCK);
+       stm32l4_info->flash_regs = saved_flash_regs;
 
        if (retval != ERROR_OK)
                return retval;
@@ -970,6 +1161,16 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
                return ERROR_TARGET_NOT_HALTED;
        }
 
+       if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+               /* set all FLASH pages as secure */
+               retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE);
+               if (retval != ERROR_OK) {
+                       /* restore all FLASH pages as non-secure */
+                       stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */
+                       return retval;
+               }
+       }
+
        retval = stm32l4_unlock_reg(bank);
        if (retval != ERROR_OK)
                goto err_lock;
@@ -992,7 +1193,7 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
                if (i >= stm32l4_info->bank1_sectors) {
                        uint8_t snb;
                        snb = i - stm32l4_info->bank1_sectors;
-                       erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
+                       erase_flags |= snb << FLASH_PAGE_SHIFT | stm32l4_info->cr_bker_mask;
                } else
                        erase_flags |= i << FLASH_PAGE_SHIFT;
                retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, erase_flags);
@@ -1002,12 +1203,17 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
                retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
                if (retval != ERROR_OK)
                        break;
-
-               bank->sectors[i].is_erased = 1;
        }
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
+
+       if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+               /* restore all FLASH pages as non-secure */
+               int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE);
+               if (retval3 != ERROR_OK)
+                       return retval3;
+       }
 
        if (retval != ERROR_OK)
                return retval;
@@ -1144,16 +1350,16 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
        return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp);
 }
 
-/* Count is in double-words */
+/* count is the size divided by stm32l4_info->data_width */
 static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        uint32_t offset, uint32_t count)
 {
        struct target *target = bank->target;
-       uint32_t buffer_size;
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        struct working_area *write_algorithm;
        struct working_area *source;
        uint32_t address = bank->base + offset;
-       struct reg_param reg_params[6];
+       struct reg_param reg_params[5];
        struct armv7m_algorithm armv7m_info;
        int retval = ERROR_OK;
 
@@ -1175,17 +1381,23 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
                return retval;
        }
 
-       /* memory buffer, size *must* be multiple of dword plus one dword for rp and one for wp */
-       buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1);
+       /* data_width should be multiple of double-word */
+       assert(stm32l4_info->data_width % 8 == 0);
+       const size_t extra_size = sizeof(struct stm32l4_work_area);
+       uint32_t buffer_size = target_get_working_area_avail(target) - extra_size;
+       /* buffer_size should be multiple of stm32l4_info->data_width */
+       buffer_size &= ~(stm32l4_info->data_width - 1);
+
        if (buffer_size < 256) {
                LOG_WARNING("large enough working area not available, can't do block memory writes");
+               target_free_working_area(target, write_algorithm);
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        } else if (buffer_size > 16384) {
                /* probably won't benefit from more than 16k ... */
                buffer_size = 16384;
        }
 
-       if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+       if (target_alloc_working_area_try(target, buffer_size + extra_size, &source) != ERROR_OK) {
                LOG_ERROR("allocating working area failed");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
@@ -1196,28 +1408,46 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);    /* buffer end */
        init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);    /* target address */
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);    /* count (double word-64bit) */
-       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);    /* flash status register */
-       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);    /* flash control register */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);    /* count (of stm32l4_info->data_width) */
+       init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);    /* write algo stack pointer */
 
        buf_set_u32(reg_params[0].value, 0, 32, source->address);
        buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
        buf_set_u32(reg_params[2].value, 0, 32, address);
        buf_set_u32(reg_params[3].value, 0, 32, count);
-       buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX));
-       buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX));
+       buf_set_u32(reg_params[4].value, 0, 32, source->address +
+                       offsetof(struct stm32l4_work_area, stack) + LDR_STACK_SIZE);
+
+       struct stm32l4_loader_params loader_extra_params;
+
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_addr,
+                       stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX));
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_cr_addr,
+                       stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX));
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_word_size,
+                       stm32l4_info->data_width);
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_bsy_mask,
+                       stm32l4_info->sr_bsy_mask);
+
+       retval = target_write_buffer(target, source->address, sizeof(loader_extra_params),
+                       (uint8_t *) &loader_extra_params);
+       if (retval != ERROR_OK)
+               return retval;
 
-       retval = target_run_flash_async_algorithm(target, buffer, count, 8,
+       retval = target_run_flash_async_algorithm(target, buffer, count, stm32l4_info->data_width,
                        0, NULL,
                        ARRAY_SIZE(reg_params), reg_params,
-                       source->address, source->size,
+                       source->address + offsetof(struct stm32l4_work_area, fifo),
+                       source->size - offsetof(struct stm32l4_work_area, fifo),
                        write_algorithm->address, 0,
                        &armv7m_info);
 
        if (retval == ERROR_FLASH_OPERATION_FAILED) {
                LOG_ERROR("error executing stm32l4 flash write algorithm");
 
-               uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR;
+               uint32_t error;
+               stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &error);
+               error &= FLASH_ERROR;
 
                if (error & FLASH_WRPERR)
                        LOG_ERROR("flash memory write protected");
@@ -1238,7 +1468,51 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        destroy_reg_param(&reg_params[2]);
        destroy_reg_param(&reg_params[3]);
        destroy_reg_param(&reg_params[4]);
-       destroy_reg_param(&reg_params[5]);
+
+       return retval;
+}
+
+/* count is the size divided by stm32l4_info->data_width */
+static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uint8_t *buffer,
+                               uint32_t offset, uint32_t count)
+{
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t address = bank->base + offset;
+       int retval = ERROR_OK;
+
+       /* wait for BSY bit */
+       retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* set PG in FLASH_CR */
+       retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_PG);
+       if (retval != ERROR_OK)
+               return retval;
+
+
+       /* write directly to flash memory */
+       const uint8_t *src = buffer;
+       const uint32_t data_width_in_words = stm32l4_info->data_width / 4;
+       while (count--) {
+               retval = target_write_memory(target, address, 4, data_width_in_words, src);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* wait for BSY bit */
+               retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               src += stm32l4_info->data_width;
+               address += stm32l4_info->data_width;
+       }
+
+       /* reset PG in FLASH_CR */
+       retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, 0);
+       if (retval != ERROR_OK)
+               return retval;
 
        return retval;
 }
@@ -1246,6 +1520,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
 static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
        uint32_t offset, uint32_t count)
 {
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        int retval = ERROR_OK, retval2;
 
        if (stm32l4_is_otp(bank) && !stm32l4_otp_is_enabled(bank)) {
@@ -1258,10 +1533,13 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       /* The flash write must be aligned to a double word (8-bytes) boundary.
+       /* ensure that stm32l4_info->data_width is 'at least' a multiple of dword */
+       assert(stm32l4_info->data_width % 8 == 0);
+
+       /* The flash write must be aligned to the 'stm32l4_info->data_width' boundary.
         * The flash infrastructure ensures it, do just a security check */
-       assert(offset % 8 == 0);
-       assert(count % 8 == 0);
+       assert(offset % stm32l4_info->data_width == 0);
+       assert(count % stm32l4_info->data_width == 0);
 
        /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether
         * data to be written does not go into a gap:
@@ -1300,14 +1578,47 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
        if (retval != ERROR_OK)
                return retval;
 
+       if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+               /* set all FLASH pages as secure */
+               retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE);
+               if (retval != ERROR_OK) {
+                       /* restore all FLASH pages as non-secure */
+                       stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */
+                       return retval;
+               }
+       }
+
        retval = stm32l4_unlock_reg(bank);
        if (retval != ERROR_OK)
                goto err_lock;
 
-       retval = stm32l4_write_block(bank, buffer, offset, count / 8);
+       if (stm32l4_info->use_flashloader) {
+               /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5,
+                * the debug is possible only in non-secure state.
+                * Thus means the flashloader will run in non-secure mode,
+                * and the workarea need to be in non-secure RAM */
+               if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5))
+                       LOG_INFO("RDP level is 0.5, the work-area should reside in non-secure RAM");
+
+               retval = stm32l4_write_block(bank, buffer, offset,
+                               count / stm32l4_info->data_width);
+       }
+
+       if (!stm32l4_info->use_flashloader || retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+               LOG_INFO("falling back to single memory accesses");
+               retval = stm32l4_write_block_without_loader(bank, buffer, offset,
+                               count / stm32l4_info->data_width);
+       }
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
+
+       if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+               /* restore all FLASH pages as non-secure */
+               int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE);
+               if (retval3 != ERROR_OK)
+                       return retval3;
+       }
 
        if (retval != ERROR_OK) {
                LOG_ERROR("block write failed");
@@ -1329,6 +1640,30 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
                        return ERROR_OK;
        }
 
+       /* Workaround for STM32WL5x devices:
+        * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1,
+        * to solve this read the UID64 (IEEE 64-bit unique device ID register) */
+
+       struct cortex_m_common *cortex_m = target_to_cm(bank->target);
+
+       if (cortex_m->core_info->partno == CORTEX_M0P_PARTNO && cortex_m->armv7m.debug_ap->ap_num == 1) {
+               uint32_t uid64_ids;
+
+               /* UID64 is contains
+                *  - Bits 63:32 : DEVNUM (unique device number, different for each individual device)
+                *  - Bits 31:08 : STID (company ID) = 0x0080E1
+                *  - Bits 07:00 : DEVID (device ID) = 0x15
+                *
+                *  read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx
+                */
+               retval = target_read_u32(bank->target, UID64_IDS, &uid64_ids);
+               if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) {
+                       /* force the DEV_ID to 0x497 and the REV_ID to unknown */
+                       *id = 0x00000497;
+                       return ERROR_OK;
+               }
+       }
+
        LOG_ERROR("can't get the device id");
        return (retval == ERROR_OK) ? ERROR_FAIL : retval;
 }
@@ -1359,10 +1694,10 @@ static const char *get_stm32l4_bank_type_str(struct flash_bank *bank)
 static int stm32l4_probe(struct flash_bank *bank)
 {
        struct target *target = bank->target;
+       struct armv7m_common *armv7m = target_to_armv7m(target);
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
        const struct stm32l4_part_info *part_info;
        uint16_t flash_size_kb = 0xffff;
-       uint32_t options;
 
        stm32l4_info->probed = false;
 
@@ -1389,18 +1724,41 @@ static int stm32l4_probe(struct flash_bank *bank)
        const char *rev_str = get_stm32l4_rev_str(bank);
        const uint16_t rev_id = stm32l4_info->idcode >> 16;
 
-       LOG_INFO("device idcode = 0x%08" PRIx32 " (%s - Rev %s : 0x%04x - %s-bank)",
-                       stm32l4_info->idcode, part_info->device_str, rev_str, rev_id,
-                       get_stm32l4_bank_type_str(bank));
+       LOG_INFO("device idcode = 0x%08" PRIx32 " (%s - Rev %s : 0x%04x)",
+                       stm32l4_info->idcode, part_info->device_str, rev_str, rev_id);
 
-       stm32l4_info->flash_regs = stm32l4_info->part_info->default_flash_regs;
+       stm32l4_info->flash_regs_base = stm32l4_info->part_info->flash_regs_base;
+       stm32l4_info->data_width = (part_info->flags & F_QUAD_WORD_PROG) ? 16 : 8;
+       stm32l4_info->cr_bker_mask = FLASH_BKER;
+       stm32l4_info->sr_bsy_mask = FLASH_BSY;
+
+       /* Set flash write alignment boundaries.
+        * Ask the flash infrastructure to ensure required alignment */
+       bank->write_start_alignment = bank->write_end_alignment = stm32l4_info->data_width;
+
+       /* initialise the flash registers layout */
+       if (part_info->flags & F_HAS_L5_FLASH_REGS)
+               stm32l4_info->flash_regs = stm32l5_ns_flash_regs;
+       else
+               stm32l4_info->flash_regs = stm32l4_flash_regs;
 
        /* read flash option register */
-       retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &options);
+       retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &stm32l4_info->optr);
        if (retval != ERROR_OK)
                return retval;
 
-       stm32l4_sync_rdp_tzen(bank, options);
+       stm32l4_sync_rdp_tzen(bank);
+
+       /* for devices with trustzone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */
+       if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+               if (part_info->flags & F_HAS_L5_FLASH_REGS) {
+                       stm32l4_info->flash_regs_base |= STM32L5_REGS_SEC_OFFSET;
+                       stm32l4_info->flash_regs = stm32l5_s_flash_regs;
+               } else {
+                       LOG_ERROR("BUG: device supported incomplete");
+                       return ERROR_NOT_IMPLEMENTED;
+               }
+       }
 
        if (part_info->flags & F_HAS_TZ)
                LOG_INFO("TZEN = %d : TrustZone %s by option bytes",
@@ -1428,7 +1786,7 @@ static int stm32l4_probe(struct flash_bank *bank)
 
                stm32l4_info->probed = true;
                return ERROR_OK;
-       } else if (bank->base != STM32_FLASH_BANK_BASE) {
+       } else if (bank->base != STM32_FLASH_BANK_BASE && bank->base != STM32_FLASH_S_BANK_BASE) {
                LOG_ERROR("invalid bank base address");
                return ERROR_FAIL;
        }
@@ -1482,24 +1840,39 @@ static int stm32l4_probe(struct flash_bank *bank)
                stm32l4_info->bank1_sectors = num_pages;
 
                /* check DUAL_BANK bit[21] if the flash is less than 1M */
-               if (flash_size_kb == 1024 || (options & BIT(21))) {
+               if (flash_size_kb == 1024 || (stm32l4_info->optr & BIT(21))) {
                        stm32l4_info->dual_bank_mode = true;
                        stm32l4_info->bank1_sectors = num_pages / 2;
                }
                break;
        case 0x435: /* STM32L43/L44xx */
+       case 0x456: /* STM32G05/G06xx */
        case 0x460: /* STM32G07/G08xx */
        case 0x462: /* STM32L45/L46xx */
        case 0x464: /* STM32L41/L42xx */
        case 0x466: /* STM32G03/G04xx */
        case 0x468: /* STM32G43/G44xx */
        case 0x479: /* STM32G49/G4Axx */
-       case 0x497: /* STM32WLEx */
+       case 0x494: /* STM32WB1x */
                /* single bank flash */
                page_size_kb = 2;
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                break;
+       case 0x467: /* STM32G0B/G0Cxx */
+               /* single/dual bank depending on bit(21) */
+               page_size_kb = 2;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               stm32l4_info->cr_bker_mask = FLASH_BKER_G0;
+
+               /* check DUAL_BANK bit */
+               if (stm32l4_info->optr & BIT(21)) {
+                       stm32l4_info->sr_bsy_mask = FLASH_BSY | FLASH_BSY2;
+                       stm32l4_info->dual_bank_mode = true;
+                       stm32l4_info->bank1_sectors = num_pages / 2;
+               }
+               break;
        case 0x469: /* STM32G47/G48xx */
                /* STM32G47/8 can be single/dual bank:
                 *   if DUAL_BANK = 0 -> single bank
@@ -1508,7 +1881,7 @@ static int stm32l4_probe(struct flash_bank *bank)
                page_size_kb = 4;
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
-               if (options & BIT(22)) {
+               if (stm32l4_info->optr & BIT(22)) {
                        stm32l4_info->dual_bank_mode = true;
                        page_size_kb = 2;
                        num_pages = flash_size_kb / page_size_kb;
@@ -1532,8 +1905,8 @@ static int stm32l4_probe(struct flash_bank *bank)
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb;
-               if ((use_dbank_bit && (options & BIT(22))) ||
-                       (!use_dbank_bit && (options & BIT(21)))) {
+               if ((use_dbank_bit && (stm32l4_info->optr & BIT(22))) ||
+                       (!use_dbank_bit && (stm32l4_info->optr & BIT(21)))) {
                        stm32l4_info->dual_bank_mode = true;
                        page_size_kb = 4;
                        num_pages = flash_size_kb / page_size_kb;
@@ -1549,14 +1922,26 @@ static int stm32l4_probe(struct flash_bank *bank)
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb;
-               if ((use_dbank_bit && (options & BIT(22))) ||
-                       (!use_dbank_bit && (options & BIT(21)))) {
+               if ((use_dbank_bit && (stm32l4_info->optr & BIT(22))) ||
+                       (!use_dbank_bit && (stm32l4_info->optr & BIT(21)))) {
                        stm32l4_info->dual_bank_mode = true;
                        page_size_kb = 2;
                        num_pages = flash_size_kb / page_size_kb;
                        stm32l4_info->bank1_sectors = num_pages / 2;
                }
                break;
+       case 0x482: /* STM32U57/U58xx */
+               /* if flash size is max (2M) the device is always dual bank
+                * otherwise check DUALBANK bit(21)
+                */
+               page_size_kb = 8;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               if ((flash_size_kb == part_info->max_flash_size_kb) || (stm32l4_info->optr & BIT(21))) {
+                       stm32l4_info->dual_bank_mode = true;
+                       stm32l4_info->bank1_sectors = num_pages / 2;
+               }
+               break;
        case 0x495: /* STM32WB5x */
        case 0x496: /* STM32WB3x */
                /* single bank flash */
@@ -1564,6 +1949,14 @@ static int stm32l4_probe(struct flash_bank *bank)
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                break;
+       case 0x497: /* STM32WLEx/WL5x */
+               /* single bank flash */
+               page_size_kb = 2;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               if (armv7m->debug_ap->ap_num == 1)
+                       stm32l4_info->flash_regs = stm32wl_cpu2_flash_regs;
+               break;
        default:
                LOG_ERROR("unsupported device");
                return ERROR_FAIL;
@@ -1589,10 +1982,8 @@ static int stm32l4_probe(struct flash_bank *bank)
 
        /* use *max_flash_size* instead of actual size as the trimmed versions
         * certainly use the same number of bits
-        * max_flash_size is always power of two, so max_pages too
         */
        uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb;
-       assert(IS_PWR_OF_2(max_pages));
 
        /* in dual bank mode number of pages is doubled, but extra bit is bank selection */
        stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1);
@@ -1627,8 +2018,17 @@ static int stm32l4_probe(struct flash_bank *bank)
 static int stm32l4_auto_probe(struct flash_bank *bank)
 {
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
-       if (stm32l4_info->probed)
-               return ERROR_OK;
+       if (stm32l4_info->probed) {
+               uint32_t optr_cur;
+
+               /* read flash option register and re-probe if optr value is changed */
+               int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &optr_cur);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (stm32l4_info->optr == optr_cur)
+                       return ERROR_OK;
+       }
 
        return stm32l4_probe(bank);
 }
@@ -1672,6 +2072,16 @@ static int stm32l4_mass_erase(struct flash_bank *bank)
                return ERROR_TARGET_NOT_HALTED;
        }
 
+       if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+               /* set all FLASH pages as secure */
+               retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE);
+               if (retval != ERROR_OK) {
+                       /* restore all FLASH pages as non-secure */
+                       stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */
+                       return retval;
+               }
+       }
+
        retval = stm32l4_unlock_reg(bank);
        if (retval != ERROR_OK)
                goto err_lock;
@@ -1692,7 +2102,14 @@ static int stm32l4_mass_erase(struct flash_bank *bank)
        retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
 
 err_lock:
-       retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
+       retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
+
+       if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+               /* restore all FLASH pages as non-secure */
+               int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE);
+               if (retval3 != ERROR_OK)
+                       return retval3;
+       }
 
        if (retval != ERROR_OK)
                return retval;
@@ -1713,15 +2130,10 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
                return retval;
 
        retval = stm32l4_mass_erase(bank);
-       if (retval == ERROR_OK) {
-               /* set all sectors as erased */
-               for (unsigned int i = 0; i < bank->num_sectors; i++)
-                       bank->sectors[i].is_erased = 1;
-
+       if (retval == ERROR_OK)
                command_print(CMD, "stm32l4x mass erase complete");
-       } else {
+       else
                command_print(CMD, "stm32l4x mass erase failed");
-       }
 
        return retval;
 }
@@ -1741,7 +2153,7 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command)
        uint32_t reg_offset, reg_addr;
        uint32_t value = 0;
 
-       reg_offset = strtoul(CMD_ARGV[1], NULL, 16);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
        reg_addr = stm32l4_get_flash_reg(bank, reg_offset);
 
        retval = stm32l4_read_flash_reg(bank, reg_offset, &value);
@@ -1769,10 +2181,11 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command)
        uint32_t value = 0;
        uint32_t mask = 0xFFFFFFFF;
 
-       reg_offset = strtoul(CMD_ARGV[1], NULL, 16);
-       value = strtoul(CMD_ARGV[2], NULL, 16);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
+
        if (CMD_ARGC > 3)
-               mask = strtoul(CMD_ARGV[3], NULL, 16);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask);
 
        command_print(CMD, "%s Option written.\n"
                                "INFO: a reset or power cycle is required "
@@ -1782,9 +2195,9 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command)
        return retval;
 }
 
-COMMAND_HANDLER(stm32l4_handle_option_load_command)
+COMMAND_HANDLER(stm32l4_handle_trustzone_command)
 {
-       if (CMD_ARGC != 1)
+       if (CMD_ARGC < 1 || CMD_ARGC > 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        struct flash_bank *bank;
@@ -1792,28 +2205,97 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command)
        if (retval != ERROR_OK)
                return retval;
 
-       retval = stm32l4_unlock_reg(bank);
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       if (!(stm32l4_info->part_info->flags & F_HAS_TZ)) {
+               LOG_ERROR("This device does not have a TrustZone");
+               return ERROR_FAIL;
+       }
+
+       retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &stm32l4_info->optr);
        if (retval != ERROR_OK)
                return retval;
 
-       retval = stm32l4_unlock_option_reg(bank);
+       stm32l4_sync_rdp_tzen(bank);
+
+       if (CMD_ARGC == 1) {
+               /* only display the TZEN value */
+               LOG_INFO("Global TrustZone Security is %s", stm32l4_info->tzen ? "enabled" : "disabled");
+               return ERROR_OK;
+       }
+
+       bool new_tzen;
+       COMMAND_PARSE_ENABLE(CMD_ARGV[1], new_tzen);
+
+       if (new_tzen == stm32l4_info->tzen) {
+               LOG_INFO("The requested TZEN is already programmed");
+               return ERROR_OK;
+       }
+
+       if (new_tzen) {
+               if (stm32l4_info->rdp != RDP_LEVEL_0) {
+                       LOG_ERROR("TZEN can be set only when RDP level is 0");
+                       return ERROR_FAIL;
+               }
+               retval = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX],
+                               FLASH_TZEN, FLASH_TZEN);
+       } else {
+               /* Deactivation of TZEN (from 1 to 0) is only possible when the RDP is
+                * changing to level 0 (from level 1 to level 0 or from level 0.5 to level 0). */
+               if (stm32l4_info->rdp != RDP_LEVEL_1 && stm32l4_info->rdp != RDP_LEVEL_0_5) {
+                       LOG_ERROR("Deactivation of TZEN is only possible when the RDP is changing to level 0");
+                       return ERROR_FAIL;
+               }
+
+               retval = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX],
+                               RDP_LEVEL_0, FLASH_RDP_MASK | FLASH_TZEN);
+       }
+
        if (retval != ERROR_OK)
                return retval;
 
-       /* Set OBL_LAUNCH bit in CR -> system reset and option bytes reload,
-        * but the RMs explicitly do *NOT* list this as power-on reset cause, and:
-        * "Note: If the read protection is set while the debugger is still
-        * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset."
-        */
-       retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OBL_LAUNCH);
+       return stm32l4_perform_obl_launch(bank);
+}
 
-       command_print(CMD, "stm32l4x option load completed. Power-on reset might be required");
+COMMAND_HANDLER(stm32l4_handle_flashloader_command)
+{
+       if (CMD_ARGC < 1 || CMD_ARGC > 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (retval != ERROR_OK)
+               return retval;
 
-       /* Need to re-probe after change */
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
-       stm32l4_info->probed = false;
 
-       return retval;
+       if (CMD_ARGC == 2)
+               COMMAND_PARSE_ENABLE(CMD_ARGV[1], stm32l4_info->use_flashloader);
+
+       command_print(CMD, "FlashLoader usage is %s", stm32l4_info->use_flashloader ? "enabled" : "disabled");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32l4_handle_option_load_command)
+{
+       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 (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32l4_perform_obl_launch(bank);
+       if (retval != ERROR_OK) {
+               command_print(CMD, "stm32l4x option load failed");
+               return retval;
+       }
+
+
+       command_print(CMD, "stm32l4x option load completed. Power-on reset might be required");
+
+       return ERROR_OK;
 }
 
 COMMAND_HANDLER(stm32l4_handle_lock_command)
@@ -1999,6 +2481,13 @@ static const struct command_registration stm32l4_exec_command_handlers[] = {
                .usage = "bank_id",
                .help = "Unlock entire protected flash device.",
        },
+       {
+               .name = "flashloader",
+               .handler = stm32l4_handle_flashloader_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank_id> [enable|disable]",
+               .help = "Configure the flashloader usage",
+       },
        {
                .name = "mass_erase",
                .handler = stm32l4_handle_mass_erase_command,
@@ -2020,6 +2509,13 @@ static const struct command_registration stm32l4_exec_command_handlers[] = {
                .usage = "bank_id reg_offset value mask",
                .help = "Write device option bit fields with provided value.",
        },
+       {
+               .name = "trustzone",
+               .handler = stm32l4_handle_trustzone_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank_id> [enable|disable]",
+               .help = "Configure TrustZone security",
+       },
        {
                .name = "wrp_info",
                .handler = stm32l4_handle_wrp_info_command,

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)