flash/stm32l4x: fix scan-build warnings
[openocd.git] / src / flash / nor / stm32l4x.c
index d770cdfa57d61f9ed05a212e8142ee60e181b2af..0a9d59ccf832f517fed193d71209f2bb3b5ea8e2 100644 (file)
 #include "imp.h"
 #include <helper/align.h>
 #include <helper/binarybuffer.h>
+#include <helper/bits.h>
 #include <target/algorithm.h>
-#include <target/armv7m.h>
-#include "bits.h"
+#include <target/arm_adi_v5.h>
+#include <target/cortex_m.h>
 #include "stm32l4x.h"
 
 /* STM32L4xxx series for reference.
  *  - 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 +151,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 +182,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 +233,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 +245,17 @@ 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;
        enum stm32l4_rdp rdp;
        bool tzen;
+       uint32_t optr;
 };
 
 enum stm32_bank_id {
@@ -227,277 +274,325 @@ 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[] = {
+static const struct stm32l4_rev stm32l47_l48xx_revs[] = {
        { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
 };
 
-static const struct stm32l4_rev stm32_435_revs[] = {
+static const struct stm32l4_rev stm32l43_l44xx_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
 };
 
-static const struct stm32l4_rev stm32_460_revs[] = {
+static const struct stm32l4_rev stm32g05_g06xx_revs[] = {
+       { 0x1000, "A" },
+};
+
+static const struct stm32l4_rev stm32_g07_g08xx_revs[] = {
        { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" },
 };
 
-static const struct stm32l4_rev stm32_461_revs[] = {
+static const struct stm32l4_rev stm32l49_l4axx_revs[] = {
        { 0x1000, "A" }, { 0x2000, "B" },
 };
 
-static const struct stm32l4_rev stm32_462_revs[] = {
+static const struct stm32l4_rev stm32l45_l46xx_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
 };
 
-static const struct stm32l4_rev stm32_464_revs[] = {
+static const struct stm32l4_rev stm32l41_L42xx_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
 };
 
-static const struct stm32l4_rev stm32_466_revs[] = {
+static const struct stm32l4_rev stm32g03_g04xx_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2000, "B" },
 };
 
-static const struct stm32l4_rev stm32_468_revs[] = {
+static const struct stm32l4_rev stm32g0b_g0cxx_revs[] = {
+       { 0x1000, "A" },
+};
+
+static const struct stm32l4_rev stm32g43_g44xx_revs[] = {
        { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
 };
 
-static const struct stm32l4_rev stm32_469_revs[] = {
+static const struct stm32l4_rev stm32g47_g48xx_revs[] = {
        { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
 };
 
-static const struct stm32l4_rev stm32_470_revs[] = {
+static const struct stm32l4_rev stm32l4r_l4sxx_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" },
 };
 
-static const struct stm32l4_rev stm32_471_revs[] = {
+static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = {
        { 0x1001, "Z" },
 };
 
-static const struct stm32l4_rev stm32_472_revs[] = {
+static const struct stm32l4_rev stm32l55_l56xx_revs[] = {
        { 0x1000, "A" }, { 0x2000, "B" },
 };
 
-static const struct stm32l4_rev stm32_479_revs[] = {
+static const struct stm32l4_rev stm32g49_g4axx_revs[] = {
        { 0x1000, "A" },
 };
 
-static const struct stm32l4_rev stm32_495_revs[] = {
+static const struct stm32l4_rev stm32u57_u58xx_revs[] = {
+       { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32wb1xx_revs[] = {
+       { 0x1000, "A" }, { 0x2000, "B" },
+};
+
+static const struct stm32l4_rev stm32wb5xx_revs[] = {
        { 0x2001, "2.1" },
 };
 
-static const struct stm32l4_rev stm32_496_revs[] = {
+static const struct stm32l4_rev stm32wb3xx_revs[] = {
        { 0x1000, "A" },
 };
 
-static const struct stm32l4_rev stm32_497_revs[] = {
+static const struct stm32l4_rev stm32wle_wl5xx_revs[] = {
        { 0x1000, "1.0" },
 };
 
 static const struct stm32l4_part_info stm32l4_parts[] = {
        {
-         .id                    = 0x415,
-         .revs                  = stm32_415_revs,
-         .num_revs              = ARRAY_SIZE(stm32_415_revs),
+         .id                    = DEVID_STM32L47_L48XX,
+         .revs                  = stm32l47_l48xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l47_l48xx_revs),
          .device_str            = "STM32L47/L48xx",
          .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,
        },
        {
-         .id                    = 0x435,
-         .revs                  = stm32_435_revs,
-         .num_revs              = ARRAY_SIZE(stm32_435_revs),
+         .id                    = DEVID_STM32L43_L44XX,
+         .revs                  = stm32l43_l44xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l43_l44xx_revs),
          .device_str            = "STM32L43/L44xx",
          .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                    = 0x460,
-         .revs                  = stm32_460_revs,
-         .num_revs              = ARRAY_SIZE(stm32_460_revs),
+         .id                    = DEVID_STM32G05_G06XX,
+         .revs                  = stm32g05_g06xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32g05_g06xx_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,
+       },
+       {
+         .id                    = DEVID_STM32G07_G08XX,
+         .revs                  = stm32_g07_g08xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32_g07_g08xx_revs),
          .device_str            = "STM32G07/G08xx",
          .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,
        },
        {
-         .id                    = 0x461,
-         .revs                  = stm32_461_revs,
-         .num_revs              = ARRAY_SIZE(stm32_461_revs),
+         .id                    = DEVID_STM32L49_L4AXX,
+         .revs                  = stm32l49_l4axx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l49_l4axx_revs),
          .device_str            = "STM32L49/L4Axx",
          .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,
        },
        {
-         .id                    = 0x462,
-         .revs                  = stm32_462_revs,
-         .num_revs              = ARRAY_SIZE(stm32_462_revs),
+         .id                    = DEVID_STM32L45_L46XX,
+         .revs                  = stm32l45_l46xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l45_l46xx_revs),
          .device_str            = "STM32L45/L46xx",
          .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                    = 0x464,
-         .revs                  = stm32_464_revs,
-         .num_revs              = ARRAY_SIZE(stm32_464_revs),
+         .id                    = DEVID_STM32L41_L42XX,
+         .revs                  = stm32l41_L42xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l41_L42xx_revs),
          .device_str            = "STM32L41/L42xx",
          .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,
        },
        {
-         .id                    = 0x466,
-         .revs                  = stm32_466_revs,
-         .num_revs              = ARRAY_SIZE(stm32_466_revs),
-         .device_str            = "STM32G03/G04xx",
+         .id                    = DEVID_STM32G03_G04XX,
+         .revs                  = stm32g03_g04xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32g03_g04xx_revs),
+         .device_str            = "STM32G03x/G04xx",
          .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                    = 0x468,
-         .revs                  = stm32_468_revs,
-         .num_revs              = ARRAY_SIZE(stm32_468_revs),
+         .id                    = DEVID_STM32G0B_G0CXX,
+         .revs                  = stm32g0b_g0cxx_revs,
+         .num_revs              = ARRAY_SIZE(stm32g0b_g0cxx_revs),
+         .device_str            = "STM32G0B/G0Cx",
+         .max_flash_size_kb     = 512,
+         .flags                 = F_HAS_DUAL_BANK,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
+       {
+         .id                    = DEVID_STM32G43_G44XX,
+         .revs                  = stm32g43_g44xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32g43_g44xx_revs),
          .device_str            = "STM32G43/G44xx",
          .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,
        },
        {
-         .id                    = 0x469,
-         .revs                  = stm32_469_revs,
-         .num_revs              = ARRAY_SIZE(stm32_469_revs),
+         .id                    = DEVID_STM32G47_G48XX,
+         .revs                  = stm32g47_g48xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32g47_g48xx_revs),
          .device_str            = "STM32G47/G48xx",
          .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,
        },
        {
-         .id                    = 0x470,
-         .revs                  = stm32_470_revs,
-         .num_revs              = ARRAY_SIZE(stm32_470_revs),
+         .id                    = DEVID_STM32L4R_L4SXX,
+         .revs                  = stm32l4r_l4sxx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l4r_l4sxx_revs),
          .device_str            = "STM32L4R/L4Sxx",
          .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,
        },
        {
-         .id                    = 0x471,
-         .revs                  = stm32_471_revs,
-         .num_revs              = ARRAY_SIZE(stm32_471_revs),
-         .device_str            = "STM32L4P5/L4Q5x",
+         .id                    = DEVID_STM32L4P_L4QXX,
+         .revs                  = stm32l4p_l4qxx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l4p_l4qxx_revs),
+         .device_str            = "STM32L4P/L4Qxx",
          .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,
        },
        {
-         .id                    = 0x472,
-         .revs                  = stm32_472_revs,
-         .num_revs              = ARRAY_SIZE(stm32_472_revs),
+         .id                    = DEVID_STM32L55_L56XX,
+         .revs                  = stm32l55_l56xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32l55_l56xx_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,
        },
        {
-         .id                    = 0x479,
-         .revs                  = stm32_479_revs,
-         .num_revs              = ARRAY_SIZE(stm32_479_revs),
+         .id                    = DEVID_STM32G49_G4AXX,
+         .revs                  = stm32g49_g4axx_revs,
+         .num_revs              = ARRAY_SIZE(stm32g49_g4axx_revs),
          .device_str            = "STM32G49/G4Axx",
          .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                    = 0x495,
-         .revs                  = stm32_495_revs,
-         .num_revs              = ARRAY_SIZE(stm32_495_revs),
+         .id                    = DEVID_STM32U57_U58XX,
+         .revs                  = stm32u57_u58xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32u57_u58xx_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                    = DEVID_STM32WB1XX,
+         .revs                  = stm32wb1xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32wb1xx_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,
+       },
+       {
+         .id                    = DEVID_STM32WB5XX,
+         .revs                  = stm32wb5xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32wb5xx_revs),
          .device_str            = "STM32WB5x",
          .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,
        },
        {
-         .id                    = 0x496,
-         .revs                  = stm32_496_revs,
-         .num_revs              = ARRAY_SIZE(stm32_496_revs),
+         .id                    = DEVID_STM32WB3XX,
+         .revs                  = stm32wb3xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32wb3xx_revs),
          .device_str            = "STM32WB3x",
          .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,
        },
        {
-         .id                    = 0x497,
-         .revs                  = stm32_497_revs,
-         .num_revs              = ARRAY_SIZE(stm32_497_revs),
-         .device_str            = "STM32WLEx",
+         .id                    = DEVID_STM32WLE_WL5XX,
+         .revs                  = stm32wle_wl5xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32wle_wl5xx_revs),
+         .device_str            = "STM32WLE/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,10 +616,6 @@ 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;
@@ -620,16 +711,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 +743,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 +779,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 +789,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 +816,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 +890,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 +904,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 +923,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 +935,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 +983,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 +1010,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;
@@ -888,7 +1078,7 @@ static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev
        if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode)
                wrp2y_sectors_offset = stm32l4_info->bank1_sectors;
 
-       if (wrp2y_sectors_offset > -1) {
+       if (wrp2y_sectors_offset >= 0) {
                /* get WRP2AR */
                ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2AR_INDEX, wrp2y_sectors_offset);
                if (ret != ERROR_OK)
@@ -970,6 +1160,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 +1192,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);
@@ -1005,7 +1205,14 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
        }
 
 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;
@@ -1013,49 +1220,11 @@ err_lock:
        return retval2;
 }
 
-static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
+static int stm32l4_protect_same_bank(struct flash_bank *bank, enum stm32_bank_id bank_id, int set,
+               unsigned int first, unsigned int last)
 {
-       struct target *target = bank->target;
-       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
-       int ret = ERROR_OK;
        unsigned int i;
 
-       if (stm32l4_is_otp(bank)) {
-               LOG_ERROR("cannot protect/unprotect OTP memory");
-               return ERROR_FLASH_OPER_UNSUPPORTED;
-       }
-
-       if (target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
-       /* the requested sectors could be located into bank1 and/or bank2 */
-       bool use_bank2 = false;
-       if (last >= stm32l4_info->bank1_sectors) {
-               if (first < stm32l4_info->bank1_sectors) {
-                       /* the requested sectors for (un)protection are shared between
-                        * bank 1 and 2, then split the operation */
-
-                       /*  1- deal with bank 1 sectors */
-                       LOG_DEBUG("The requested sectors for %s are shared between bank 1 and 2",
-                                       set ? "protection" : "unprotection");
-                       ret = stm32l4_protect(bank, set, first, stm32l4_info->bank1_sectors - 1);
-                       if (ret != ERROR_OK)
-                               return ret;
-
-                       /*  2- then continue with bank 2 sectors */
-                       first = stm32l4_info->bank1_sectors;
-               }
-
-               use_bank2 = true;
-       }
-
-       /* refresh the sectors' protection */
-       ret = stm32l4_protect_check(bank);
-       if (ret != ERROR_OK)
-               return ret;
-
        /* check if the desired protection is already configured */
        for (i = first; i <= last; i++) {
                if (bank->sectors[i].is_protected != set)
@@ -1071,7 +1240,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
        unsigned int n_wrp;
        struct stm32l4_wrp wrpxy[4];
 
-       ret = stm32l4_get_all_wrpxy(bank, use_bank2 ? STM32_BANK2 : STM32_BANK1, wrpxy, &n_wrp);
+       int ret = stm32l4_get_all_wrpxy(bank, bank_id, wrpxy, &n_wrp);
        if (ret != ERROR_OK)
                return ret;
 
@@ -1142,16 +1311,50 @@ 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 */
+static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
+{
+       struct target *target = bank->target;
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+       if (stm32l4_is_otp(bank)) {
+               LOG_ERROR("cannot protect/unprotect OTP memory");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* refresh the sectors' protection */
+       int ret = stm32l4_protect_check(bank);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* the requested sectors could be located into bank1 and/or bank2 */
+       if (last < stm32l4_info->bank1_sectors) {
+               return stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, last);
+       } else if (first >= stm32l4_info->bank1_sectors) {
+               return stm32l4_protect_same_bank(bank, STM32_BANK2, set, first, last);
+       } else {
+               ret = stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, stm32l4_info->bank1_sectors - 1);
+               if (ret != ERROR_OK)
+                       return ret;
+
+               return stm32l4_protect_same_bank(bank, STM32_BANK2, set, stm32l4_info->bank1_sectors, last);
+       }
+}
+
+/* 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;
 
@@ -1173,17 +1376,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;
        }
@@ -1191,31 +1400,52 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
        armv7m_info.core_mode = ARM_MODE_THREAD;
 
-       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
+       /* contrib/loaders/flash/stm32/stm32l4x.c:write() arguments */
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* stm32l4_work_area ptr , 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) */
 
        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));
 
-       retval = target_run_flash_async_algorithm(target, buffer, count, 8,
+       /* write algo stack pointer */
+       init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);
+       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, 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");
@@ -1236,7 +1466,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;
 }
@@ -1244,6 +1518,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)) {
@@ -1256,10 +1531,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:
@@ -1298,14 +1576,48 @@ 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);
+
+       /* 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_WARNING("RDP = 0x55, the work-area should be in non-secure RAM (check SAU partitioning)");
+
+       /* first try to write using the loader, for better performance */
+       retval = stm32l4_write_block(bank, buffer, offset,
+                       count / stm32l4_info->data_width);
+
+       /* if resources are not available write without a loader */
+       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+               LOG_WARNING("falling back to programming without a flash loader (slower)");
+               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");
@@ -1316,17 +1628,49 @@ err_lock:
 
 static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
 {
-       int retval;
+       int retval = ERROR_OK;
+       struct target *target = bank->target;
 
        /* try reading possible IDCODE registers, in the following order */
        uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5};
 
        for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) {
-               retval = target_read_u32(bank->target, dbgmcu_idcode[i], id);
+               retval = target_read_u32(target, dbgmcu_idcode[i], id);
                if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff))
                        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 armv7m_common *armv7m = target_to_armv7m_safe(target);
+       if (!armv7m) {
+               LOG_ERROR("Flash requires Cortex-M target");
+               return ERROR_TARGET_INVALID;
+       }
+
+       /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1.
+        * Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */
+       if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO &&
+                       armv7m->debug_ap && 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(target, UID64_IDS, &uid64_ids);
+               if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) {
+                       /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */
+                       *id = DEVID_STM32WLE_WL5XX;
+                       return ERROR_OK;
+               }
+       }
+
        LOG_ERROR("can't get the device id");
        return (retval == ERROR_OK) ? ERROR_FAIL : retval;
 }
@@ -1360,7 +1704,17 @@ static int stm32l4_probe(struct flash_bank *bank)
        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;
+
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target not examined yet");
+               return ERROR_TARGET_NOT_EXAMINED;
+       }
+
+       struct armv7m_common *armv7m = target_to_armv7m_safe(target);
+       if (!armv7m) {
+               LOG_ERROR("Flash requires Cortex-M target");
+               return ERROR_TARGET_INVALID;
+       }
 
        stm32l4_info->probed = false;
 
@@ -1387,18 +1741,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_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;
 
-       stm32l4_info->flash_regs = stm32l4_info->part_info->default_flash_regs;
+       /* Initialize 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",
@@ -1426,7 +1803,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;
        }
@@ -1455,6 +1832,8 @@ static int stm32l4_probe(struct flash_bank *bank)
        /* did we assign a flash size? */
        assert((flash_size_kb != 0xffff) && flash_size_kb);
 
+       const bool is_max_flash_size = flash_size_kb == stm32l4_info->part_info->max_flash_size_kb;
+
        stm32l4_info->bank1_sectors = 0;
        stm32l4_info->hole_sectors = 0;
 
@@ -1462,14 +1841,13 @@ static int stm32l4_probe(struct flash_bank *bank)
        int page_size_kb = 0;
 
        stm32l4_info->dual_bank_mode = false;
-       bool use_dbank_bit = false;
 
        switch (device_id) {
-       case 0x415: /* STM32L47/L48xx */
-       case 0x461: /* STM32L49/L4Axx */
+       case DEVID_STM32L47_L48XX:
+       case DEVID_STM32L49_L4AXX:
                /* if flash size is max (1M) the device is always dual bank
-                * 0x415: has variants with 512K
-                * 0x461: has variants with 512 and 256
+                * STM32L47/L48xx: has variants with 512K
+                * STM32L49/L4Axx: has variants with 512 and 256
                 * for these variants:
                 *   if DUAL_BANK = 0 -> single bank
                 *   else -> dual bank without gap
@@ -1479,26 +1857,41 @@ static int stm32l4_probe(struct flash_bank *bank)
                num_pages = flash_size_kb / page_size_kb;
                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))) {
+               /* check DUAL_BANK option bit if the flash is less than 1M */
+               if (is_max_flash_size || (stm32l4_info->optr & FLASH_L4_DUAL_BANK)) {
                        stm32l4_info->dual_bank_mode = true;
                        stm32l4_info->bank1_sectors = num_pages / 2;
                }
                break;
-       case 0x435: /* STM32L43/L44xx */
-       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 DEVID_STM32L43_L44XX:
+       case DEVID_STM32G05_G06XX:
+       case DEVID_STM32G07_G08XX:
+       case DEVID_STM32L45_L46XX:
+       case DEVID_STM32L41_L42XX:
+       case DEVID_STM32G03_G04XX:
+       case DEVID_STM32G43_G44XX:
+       case DEVID_STM32G49_G4AXX:
+       case DEVID_STM32WB1XX:
                /* single bank flash */
                page_size_kb = 2;
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                break;
-       case 0x469: /* STM32G47/G48xx */
+       case DEVID_STM32G0B_G0CXX:
+               /* single/dual bank depending on DUAL_BANK option bit */
+               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 & FLASH_G0_DUAL_BANK) {
+                       stm32l4_info->sr_bsy_mask = FLASH_BSY | FLASH_BSY2;
+                       stm32l4_info->dual_bank_mode = true;
+                       stm32l4_info->bank1_sectors = num_pages / 2;
+               }
+               break;
+       case DEVID_STM32G47_G48XX:
                /* STM32G47/8 can be single/dual bank:
                 *   if DUAL_BANK = 0 -> single bank
                 *   else -> dual bank WITH gap
@@ -1506,7 +1899,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 & FLASH_G4_DUAL_BANK) {
                        stm32l4_info->dual_bank_mode = true;
                        page_size_kb = 2;
                        num_pages = flash_size_kb / page_size_kb;
@@ -1517,56 +1910,88 @@ static int stm32l4_probe(struct flash_bank *bank)
                                (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb);
                }
                break;
-       case 0x470: /* STM32L4R/L4Sxx */
-       case 0x471: /* STM32L4P5/L4Q5x */
+       case DEVID_STM32L4R_L4SXX:
+       case DEVID_STM32L4P_L4QXX:
                /* STM32L4R/S can be single/dual bank:
-                *   if size = 2M check DBANK bit(22)
-                *   if size = 1M check DB1M bit(21)
+                *   if size = 2M check DBANK bit
+                *   if size = 1M check DB1M bit
                 * STM32L4P/Q can be single/dual bank
-                *   if size = 1M check DBANK bit(22)
-                *   if size = 512K check DB512K bit(21)
+                *   if size = 1M check DBANK bit
+                *   if size = 512K check DB512K bit (same as DB1M bit)
                 */
                page_size_kb = 8;
                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 ((is_max_flash_size && (stm32l4_info->optr & FLASH_L4R_DBANK)) ||
+                       (!is_max_flash_size && (stm32l4_info->optr & FLASH_LRR_DB1M))) {
                        stm32l4_info->dual_bank_mode = true;
                        page_size_kb = 4;
                        num_pages = flash_size_kb / page_size_kb;
                        stm32l4_info->bank1_sectors = num_pages / 2;
                }
                break;
-       case 0x472: /* STM32L55/L56xx */
+       case DEVID_STM32L55_L56XX:
                /* STM32L55/L56xx can be single/dual bank:
-                *   if size = 512K check DBANK bit(22)
-                *   if size = 256K check DB256K bit(21)
+                *   if size = 512K check DBANK bit
+                *   if size = 256K check DB256K bit
+                *
+                * default page size is 4kb, if DBANK = 1, the page size is 2kb.
                 */
-               page_size_kb = 4;
+
+               page_size_kb = (stm32l4_info->optr & FLASH_L5_DBANK) ? 2 : 4;
                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 ((is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DBANK)) ||
+                       (!is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DB256))) {
                        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 0x495: /* STM32WB5x */
-       case 0x496: /* STM32WB3x */
+       case DEVID_STM32U57_U58XX:
+               /* if flash size is max (2M) the device is always dual bank
+                * otherwise check DUALBANK
+                */
+               page_size_kb = 8;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               if (is_max_flash_size || (stm32l4_info->optr & FLASH_U5_DUALBANK)) {
+                       stm32l4_info->dual_bank_mode = true;
+                       stm32l4_info->bank1_sectors = num_pages / 2;
+               }
+               break;
+       case DEVID_STM32WB5XX:
+       case DEVID_STM32WB3XX:
                /* single bank flash */
                page_size_kb = 4;
                num_pages = flash_size_kb / page_size_kb;
                stm32l4_info->bank1_sectors = num_pages;
                break;
+       case DEVID_STM32WLE_WL5XX:
+               /* single bank flash */
+               page_size_kb = 2;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+
+               /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1.
+                * Using HLA adapters armv7m->debug_ap is null, and checking ap_num triggers a segfault */
+               if (armv7m->debug_ap && armv7m->debug_ap->ap_num == 1)
+                       stm32l4_info->flash_regs = stm32wl_cpu2_flash_regs;
+               break;
        default:
                LOG_ERROR("unsupported device");
                return ERROR_FAIL;
        }
 
+       /* ensure that at least there is 1 flash sector / page */
+       if (num_pages == 0) {
+               if (stm32l4_info->user_bank_size)
+                       LOG_ERROR("The specified flash size is less than page size");
+
+               LOG_ERROR("Flash pages count cannot be zero");
+               return ERROR_FAIL;
+       }
+
        LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single");
 
        const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb;
@@ -1587,10 +2012,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);
@@ -1625,8 +2048,28 @@ 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;
+
+               /* save flash_regs_base */
+               uint32_t saved_flash_regs_base = stm32l4_info->flash_regs_base;
+
+               /* for devices with TrustZone, use NS flash registers to read OPTR */
+               if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS)
+                       stm32l4_info->flash_regs_base &= ~STM32L5_REGS_SEC_OFFSET;
+
+               /* 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);
+
+               /* restore saved flash_regs_base */
+               stm32l4_info->flash_regs_base = saved_flash_regs_base;
+
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if (stm32l4_info->optr == optr_cur)
+                       return ERROR_OK;
+       }
 
        return stm32l4_probe(bank);
 }
@@ -1670,6 +2113,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;
@@ -1690,7 +2143,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;
@@ -1776,9 +2236,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;
@@ -1786,28 +2246,77 @@ 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_option_load_command)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
 
-       /* Need to re-probe after change */
-       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
-       stm32l4_info->probed = false;
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (retval != ERROR_OK)
+               return retval;
 
-       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)
@@ -2014,6 +2523,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)