flash/stm32l4x: add support of STM32WB1x
[openocd.git] / src / flash / nor / stm32l4x.c
index db8d5e78d3175d5ecf010b5e06ce7acf37c594c0..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_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 ******************************************************/
 
 
@@ -138,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,
@@ -166,6 +181,18 @@ static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
        [STM32_FLASH_WRP2BR_INDEX]   = 0x050,
 };
 
+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]       = 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 */
@@ -205,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;
@@ -218,11 +244,15 @@ 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;
@@ -244,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" }
@@ -254,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" },
 };
@@ -274,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" },
 };
@@ -298,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" },
 };
@@ -319,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,
@@ -332,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,
@@ -345,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,
@@ -358,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,
@@ -371,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,
@@ -384,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,
@@ -397,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,
@@ -410,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,
@@ -423,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,
@@ -436,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,
@@ -449,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,
@@ -462,7 +521,6 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .max_flash_size_kb     = 512,
          .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,
@@ -475,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,
@@ -488,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,
@@ -501,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,
@@ -510,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,
@@ -538,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;
 }
@@ -705,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;
 
@@ -714,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");
@@ -784,14 +860,22 @@ static int stm32l4_set_secbb(struct flash_bank *bank, uint32_t value)
        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;
 
@@ -807,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;
 
@@ -821,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;
 
@@ -839,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;
 
@@ -879,7 +964,8 @@ static int stm32l4_perform_obl_launch(struct flash_bank *bank)
        stm32l4_info->probed = false;
 
 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);
 
        if (retval != ERROR_OK)
                return retval;
@@ -925,7 +1011,8 @@ 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)
@@ -1106,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);
@@ -1119,7 +1206,7 @@ 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 */
@@ -1263,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;
 
@@ -1294,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;
        }
@@ -1315,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");
@@ -1357,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;
 }
@@ -1378,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:
@@ -1434,10 +1592,26 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
        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 */
@@ -1466,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;
 }
@@ -1496,6 +1694,7 @@ 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;
@@ -1529,7 +1728,19 @@ static int stm32l4_probe(struct flash_bank *bank)
                        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->flash_regs = stm32l4_info->part_info->default_flash_regs;
+       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, &stm32l4_info->optr);
@@ -1538,6 +1749,17 @@ static int stm32l4_probe(struct flash_bank *bank)
 
        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",
                                stm32l4_info->tzen,
@@ -1624,18 +1846,33 @@ static int stm32l4_probe(struct flash_bank *bank)
                }
                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
@@ -1692,14 +1929,17 @@ static int stm32l4_probe(struct flash_bank *bank)
                        num_pages = flash_size_kb / page_size_kb;
                        stm32l4_info->bank1_sectors = num_pages / 2;
                }
-
-               /**
-                * by default use the non-secure registers,
-                * switch secure registers if TZ is enabled and RDP is LEVEL_0
+               break;
+       case 0x482: /* STM32U57/U58xx */
+               /* if flash size is max (2M) the device is always dual bank
+                * otherwise check DUALBANK bit(21)
                 */
-               if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
-                       stm32l4_info->flash_regs_base |= 0x10000000;
-                       stm32l4_info->flash_regs = stm32l5_s_flash_regs;
+               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 */
@@ -1709,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;
@@ -1734,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);
@@ -1856,7 +2102,7 @@ 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 */
@@ -2010,6 +2256,26 @@ COMMAND_HANDLER(stm32l4_handle_trustzone_command)
        return stm32l4_perform_obl_launch(bank);
 }
 
+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;
+
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+       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)
@@ -2215,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,

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)