jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / flash / nor / stm32l4x.c
index 8d463ac0593e6f5af11118115524c6fd9fe118c2..039938512bfa9378cfe87be62b0fec90a7a29761 100644 (file)
@@ -1,22 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
 /***************************************************************************
  *   Copyright (C) 2015 by Uwe Bonnes                                      *
  *   bon@elektron.ikp.physik.tu-darmstadt.de                               *
  *                                                                         *
  *   Copyright (C) 2019 by Tarek Bochkati for STMicroelectronics           *
  *   tarek.bouchkati@gmail.com                                             *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
 #include "imp.h"
 #include <helper/align.h>
 #include <helper/binarybuffer.h>
+#include <helper/bits.h>
 #include <target/algorithm.h>
+#include <target/arm_adi_v5.h>
 #include <target/cortex_m.h>
-#include "bits.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)
+ * RM0493 (STM32WBA52x)
+ * http://www.st.com/resource/en/reference_manual/dm00821869.pdf
+ *
+ * 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.
  * http://www.st.com/resource/en/reference_manual/dm00451556.pdf
  */
 
+/* STM32C0xxx series for reference.
+ *
+ * RM0490 (STM32C0x1)
+ * http://www.st.com/resource/en/reference_manual/dm00781702.pdf
+ */
+
 /* STM32G0xxx series for reference.
  *
  * RM0444 (STM32G0x1)
 #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 ******************************************************/
 
 
@@ -236,6 +243,7 @@ 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;
@@ -243,7 +251,6 @@ struct stm32l4_flash_bank {
        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;
@@ -265,81 +272,108 @@ 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 = "STM32C0/G0/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 stm32c01xx_revs[] = {
+       { 0x1000, "A" }, { 0x1001, "Z" },
+};
+
+static const struct stm32l4_rev stm32c03xx_revs[] = {
+       { 0x1000, "A" }, { 0x1001, "Z" },
+};
+
+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_467_revs[] = {
+static const struct stm32l4_rev stm32g0b_g0cxx_revs[] = {
        { 0x1000, "A" },
 };
 
-static const struct stm32l4_rev stm32_468_revs[] = {
+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" },
+       { 0x101F, "V" },
 };
 
-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[] = {
-       { 0x1000, "A" }, { 0x2000, "B" },
+static const struct stm32l4_rev stm32l55_l56xx_revs[] = {
+       { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
+};
+
+static const struct stm32l4_rev stm32g49_g4axx_revs[] = {
+       { 0x1000, "A" },
+};
+
+static const struct stm32l4_rev stm32u57_u58xx_revs[] = {
+       { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" },
+       { 0x2001, "X" }, { 0x3000, "C" },
 };
 
-static const struct stm32l4_rev stm32_479_revs[] = {
+static const struct stm32l4_rev stm32wba5x_revs[] = {
        { 0x1000, "A" },
 };
 
-static const struct stm32l4_rev stm32_495_revs[] = {
+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,
@@ -349,9 +383,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -361,9 +395,45 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_size              = 1024,
        },
        {
-         .id                    = 0x460,
-         .revs                  = stm32_460_revs,
-         .num_revs              = ARRAY_SIZE(stm32_460_revs),
+         .id                    = DEVID_STM32C01XX,
+         .revs                  = stm32c01xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32c01xx_revs),
+         .device_str            = "STM32C01xx",
+         .max_flash_size_kb     = 32,
+         .flags                 = F_NONE,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x1FFF75A0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
+       {
+         .id                    = DEVID_STM32C03XX,
+         .revs                  = stm32c03xx_revs,
+         .num_revs              = ARRAY_SIZE(stm32c03xx_revs),
+         .device_str            = "STM32C03xx",
+         .max_flash_size_kb     = 32,
+         .flags                 = F_NONE,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x1FFF75A0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
+       {
+         .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,
@@ -373,9 +443,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -385,9 +455,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -397,9 +467,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -409,10 +479,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -421,10 +491,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_size              = 1024,
        },
        {
-         .id                    = 0x467,
-         .revs                  = stm32_467_revs,
-         .num_revs              = ARRAY_SIZE(stm32_467_revs),
-         .device_str            = "STM32G0Bx/G0Cx",
+         .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,
@@ -433,9 +503,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_size              = 1024,
        },
        {
-         .id                    = 0x468,
-         .revs                  = stm32_468_revs,
-         .num_revs              = ARRAY_SIZE(stm32_468_revs),
+         .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,
@@ -445,9 +515,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -457,9 +527,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -469,10 +539,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -481,9 +551,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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 | F_HAS_L5_FLASH_REGS,
@@ -493,9 +563,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -505,9 +575,45 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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_STM32WBA5X,
+         .revs                  = stm32wba5x_revs,
+         .num_revs              = ARRAY_SIZE(stm32wba5x_revs),
+         .device_str            = "STM32WBA5x",
+         .max_flash_size_kb     = 1024,
+         .flags                 = F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x0FF907A0,
+         .otp_base              = 0x0FF90000,
+         .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,
@@ -517,9 +623,9 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .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,
@@ -529,10 +635,10 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_size              = 1024,
        },
        {
-         .id                    = 0x497,
-         .revs                  = stm32_497_revs,
-         .num_revs              = ARRAY_SIZE(stm32_497_revs),
-         .device_str            = "STM32WLEx/WL5x",
+         .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,
@@ -559,14 +665,9 @@ 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;
 }
@@ -1026,7 +1127,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)
@@ -1168,49 +1269,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)
@@ -1226,7 +1289,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;
 
@@ -1297,16 +1360,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;
 
@@ -1328,17 +1425,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;
        }
@@ -1346,31 +1449,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");
@@ -1391,15 +1515,15 @@ 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 in double-words */
+/* 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;
@@ -1417,8 +1541,9 @@ static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uin
 
        /* 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, 2, src);
+               retval = target_write_memory(target, address, 4, data_width_in_words, src);
                if (retval != ERROR_OK)
                        return retval;
 
@@ -1427,8 +1552,8 @@ static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uin
                if (retval != ERROR_OK)
                        return retval;
 
-               src += 8;
-               address += 8;
+               src += stm32l4_info->data_width;
+               address += stm32l4_info->data_width;
        }
 
        /* reset PG in FLASH_CR */
@@ -1455,10 +1580,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:
@@ -1511,34 +1639,25 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
        if (retval != ERROR_OK)
                goto err_lock;
 
-       /**
-        * FIXME update the flash loader to use a custom FLASH_SR_BSY mask
-        * Workaround for STM32G0Bx/G0Cx devices in dual bank mode,
-        * as the flash loader does not use the SR_BSY2
-        */
-       bool use_flashloader = stm32l4_info->use_flashloader;
-       if ((stm32l4_info->part_info->id == 0x467) && stm32l4_info->dual_bank_mode) {
-               LOG_INFO("Couldn't use the flash loader in dual-bank mode");
-               use_flashloader = false;
-       }
 
-       if (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");
+       /* 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)");
 
-               retval = stm32l4_write_block(bank, buffer, offset, count / 8);
-       }
+       /* first try to write using the loader, for better performance */
+       retval = stm32l4_write_block(bank, buffer, offset,
+                       count / stm32l4_info->data_width);
 
-       if (!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 / 8);
+       /* 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, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
 
@@ -1558,13 +1677,14 @@ 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;
        }
@@ -1573,9 +1693,16 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
         * 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);
+       struct armv7m_common *armv7m = target_to_armv7m_safe(target);
+       if (!armv7m) {
+               LOG_ERROR("Flash requires Cortex-M target");
+               return ERROR_TARGET_INVALID;
+       }
 
-       if (cortex_m->core_info->partno == CORTEX_M0P_PARTNO && cortex_m->armv7m.debug_ap->ap_num == 1) {
+       /* 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_impl_part(target) == CORTEX_M0P_PARTNO &&
+                       armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) {
                uint32_t uid64_ids;
 
                /* UID64 is contains
@@ -1585,10 +1712,10 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
                 *
                 *  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);
+               retval = target_read_u32(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;
+                       /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */
+                       *id = DEVID_STM32WLE_WL5XX;
                        return ERROR_OK;
                }
        }
@@ -1623,11 +1750,21 @@ 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;
 
+       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;
 
        /* read stm32 device id registers */
@@ -1657,10 +1794,16 @@ 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->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;
 
-       /* initialise the flash registers layout */
+       /* Set flash write alignment boundaries.
+        * Ask the flash infrastructure to ensure required alignment */
+       bank->write_start_alignment = stm32l4_info->data_width;
+       bank->write_end_alignment = stm32l4_info->data_width;
+
+       /* Initialize the flash registers layout */
        if (part_info->flags & F_HAS_L5_FLASH_REGS)
                stm32l4_info->flash_regs = stm32l5_ns_flash_regs;
        else
@@ -1673,7 +1816,7 @@ 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 */
+       /* 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;
@@ -1734,11 +1877,13 @@ static int stm32l4_probe(struct flash_bank *bank)
                flash_size_kb = stm32l4_info->user_bank_size / 1024;
        }
 
-       LOG_INFO("flash size = %dkbytes", flash_size_kb);
+       LOG_INFO("flash size = %d KiB", flash_size_kb);
 
        /* 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;
 
@@ -1746,14 +1891,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
@@ -1763,39 +1907,43 @@ 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 || (stm32l4_info->optr & 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 DEVID_STM32L43_L44XX:
+       case DEVID_STM32C01XX:
+       case DEVID_STM32C03XX:
+       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 0x467: /* STM32G0B/G0Cxx */
-               /* single/dual bank depending on bit(21) */
+       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 & BIT(21)) {
+               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 0x469: /* STM32G47/G48xx */
+       case DEVID_STM32G47_G48XX:
                /* STM32G47/8 can be single/dual bank:
                 *   if DUAL_BANK = 0 -> single bank
                 *   else -> dual bank WITH gap
@@ -1803,7 +1951,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 (stm32l4_info->optr & 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;
@@ -1814,57 +1962,78 @@ 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 && (stm32l4_info->optr & BIT(22))) ||
-                       (!use_dbank_bit && (stm32l4_info->optr & 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 && (stm32l4_info->optr & BIT(22))) ||
-                       (!use_dbank_bit && (stm32l4_info->optr & 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_STM32WBA5X:
+               /* single bank flash */
+               page_size_kb = 8;
+               num_pages = flash_size_kb / page_size_kb;
+               stm32l4_info->bank1_sectors = num_pages;
+               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 0x497: /* STM32WLEx/WL5x */
+       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;
-               if (armv7m->debug_ap->ap_num == 1)
+
+               /* 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:
@@ -1872,6 +2041,15 @@ static int stm32l4_probe(struct flash_bank *bank)
                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;
@@ -1892,10 +2070,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);
@@ -1933,8 +2109,19 @@ static int stm32l4_auto_probe(struct flash_bank *bank)
        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;
 
@@ -2031,10 +2218,8 @@ err_lock:
 
 COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
 {
-       if (CMD_ARGC < 1) {
-               command_print(CMD, "stm32l4x mass_erase <STM32L4 bank>");
+       if (CMD_ARGC != 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
@@ -2052,10 +2237,8 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
 
 COMMAND_HANDLER(stm32l4_handle_option_read_command)
 {
-       if (CMD_ARGC < 2) {
-               command_print(CMD, "stm32l4x option_read <STM32L4 bank> <option_reg offset>");
+       if (CMD_ARGC != 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
@@ -2079,10 +2262,8 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command)
 
 COMMAND_HANDLER(stm32l4_handle_option_write_command)
 {
-       if (CMD_ARGC < 3) {
-               command_print(CMD, "stm32l4x option_write <STM32L4 bank> <option_reg offset> <value> [mask]");
+       if (CMD_ARGC != 3 && CMD_ARGC != 4)
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
        struct flash_bank *bank;
        int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
@@ -2168,26 +2349,6 @@ 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)
@@ -2214,7 +2375,7 @@ COMMAND_HANDLER(stm32l4_handle_lock_command)
 {
        struct target *target = NULL;
 
-       if (CMD_ARGC < 1)
+       if (CMD_ARGC != 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        struct flash_bank *bank;
@@ -2249,7 +2410,7 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
 {
        struct target *target = NULL;
 
-       if (CMD_ARGC < 1)
+       if (CMD_ARGC != 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        struct flash_bank *bank;
@@ -2353,7 +2514,7 @@ COMMAND_HANDLER(stm32l4_handle_wrp_info_command)
 
 COMMAND_HANDLER(stm32l4_handle_otp_command)
 {
-       if (CMD_ARGC < 2)
+       if (CMD_ARGC != 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        struct flash_bank *bank;
@@ -2393,13 +2554,6 @@ 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)