This is an automated email from Gerrit.

Michael Jung (mij...@gmx.net) just uploaded a new patch set to Gerrit, which 
you can find at http://openocd.zylin.com/5344

-- gerrit

commit b480bac4d0ee819f1dd1044e9fd4b95a77632d04
Author: Michael Jung <mij...@gmx.net>
Date:   Fri Nov 15 19:33:25 2019 +0100

    stm32l5x: added support for STM32L5 devices
    
    - Based on the stm32l4x code.
    - Tested with flash programming via gdb 'load' and single stepping
    
    Change-Id: I706c51fe73734475a44be9c77515dbfb58ed04d7
    Signed-off-by: Michael Jung <mij...@gmx.net>

diff --git a/contrib/loaders/flash/stm32/Makefile 
b/contrib/loaders/flash/stm32/Makefile
index b58b412..46d265a 100644
--- a/contrib/loaders/flash/stm32/Makefile
+++ b/contrib/loaders/flash/stm32/Makefile
@@ -8,7 +8,7 @@ OBJDUMP=$(CROSS_COMPILE)objdump
 
 CFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL
 
-all: stm32f1x.inc stm32f2x.inc stm32h7x.inc stm32l4x.inc stm32lx.inc
+all: stm32f1x.inc stm32f2x.inc stm32h7x.inc stm32l4x.inc stm32l5x.inc 
stm32lx.inc
 
 .PHONY: clean
 
diff --git a/contrib/loaders/flash/stm32/stm32l5x.S 
b/contrib/loaders/flash/stm32/stm32l5x.S
new file mode 100644
index 0000000..d0c2f9d
--- /dev/null
+++ b/contrib/loaders/flash/stm32/stm32l5x.S
@@ -0,0 +1,94 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Spencer Oliver                                  *
+ *   s...@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   Copyright (C) 2011 Øyvind Harboe                                      *
+ *   oyvind.har...@zylin.com                                               *
+ *                                                                         *
+ *   Copyright (C) 2015 Uwe Bonnes                                         *
+ *   b...@elektron.ikp.physik.tu-darmstadt.de                               *
+ *                                                                         *
+ *   Copyright (C) 2019 Michael Jung                                       *
+ *   mij...@gmx.net                                                        *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.                                        *
+ ***************************************************************************/
+
+       .text
+       .syntax unified
+       .cpu cortex-m33
+       .thumb
+
+/*
+ * Params :
+ * r0 = workarea start, status (out)
+ * r1 = workarea end
+ * r2 = target address
+ * r3 = count (64bit words)
+ * r4 = flash base
+ *
+ * Clobbered:
+ * r5   - rp
+ * r6/7 - temp (64-bit)
+ * r8   - wp, tmp
+ */
+
+#define STM32_FLASH_NSCR_OFFSET        0x28    /* offset of NSCR register in 
FLASH struct */
+#define STM32_FLASH_NSSR_OFFSET        0x20    /* offset of NSSR register in 
FLASH struct */
+
+#define STM32_PROG      0x1    /* PG */
+
+       .thumb_func
+       .global _start
+_start:
+wait_fifo:
+       ldr     r8, [r0, #0]    /* read wp */
+       cmp     r8, #0          /* abort if wp == 0 */
+       beq     exit
+       ldr     r5, [r0, #4]    /* read rp */
+       subs    r6, r8, r5      /* number of bytes available for read in r6*/
+       itt     mi              /* if wrapped around*/
+       addmi   r6, r1          /* add size of buffer */
+       submi   r6, r0
+       cmp     r6, #8          /* wait until 8 bytes are available */
+       bcc     wait_fifo
+
+       ldr     r6, =STM32_PROG
+       str     r6, [r4, #STM32_FLASH_NSCR_OFFSET]
+       ldrd    r6, [r5], #0x08 /* read one word from src, increment ptr */
+       strd    r6, [r2], #0x08 /* write one word to dst, increment ptr */
+       dsb
+busy:
+       ldr     r6, [r4, #STM32_FLASH_NSSR_OFFSET]
+       tst     r6, #0x10000    /* BSY (bit16) == 1 => operation in progress */
+       bne     busy            /* wait more... */
+       tst     r6, #0xfa       /* PGSERR | PGPERR | PGAERR | WRPERR | PROGERR*/
+       bne     error           /* fail... */
+
+       cmp     r5, r1          /* wrap rp at end of buffer */
+       it      cs
+       addcs   r5, r0, #8      /* skip loader args */
+       str     r5, [r0, #4]    /* store rp */
+       subs    r3, r3, #1      /* decrement dword count */
+       cbz     r3, exit        /* loop if not done */
+       b       wait_fifo
+error:
+       movs    r1, #0
+       str     r1, [r0, #4]    /* set rp = 0 on error */
+exit:
+       mov     r0, r6          /* return status in r0 */
+       bkpt    #0x00
+
+       .pool
diff --git a/contrib/loaders/flash/stm32/stm32l5x.inc 
b/contrib/loaders/flash/stm32/stm32l5x.inc
new file mode 100644
index 0000000..a200565
--- /dev/null
+++ b/contrib/loaders/flash/stm32/stm32l5x.inc
@@ -0,0 +1,7 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x21,0xd0,0x45,0x68,0xb8,0xeb,0x05,0x06,
+0x44,0xbf,0x76,0x18,0x36,0x1a,0x08,0x2e,0xf2,0xd3,0x4f,0xf0,0x01,0x06,0xa6,0x62,
+0xf5,0xe8,0x02,0x67,0xe2,0xe8,0x02,0x67,0xbf,0xf3,0x4f,0x8f,0x26,0x6a,0x16,0xf4,
+0x80,0x3f,0xfb,0xd1,0x16,0xf0,0xfa,0x0f,0x07,0xd1,0x8d,0x42,0x28,0xbf,0x00,0xf1,
+0x08,0x05,0x45,0x60,0x01,0x3b,0x13,0xb1,0xda,0xe7,0x00,0x21,0x41,0x60,0x30,0x46,
+0x00,0xbe,
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 34f91ce..d264552 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -59,6 +59,7 @@ NOR_DRIVERS = \
        %D%/stm32f2x.c \
        %D%/stm32lx.c \
        %D%/stm32l4x.c \
+       %D%/stm32l5x.c \
        %D%/stm32h7x.c \
        %D%/str7x.c \
        %D%/str9x.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 551f389..35a3f15 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -72,6 +72,7 @@ extern const struct flash_driver stm32f1x_flash;
 extern const struct flash_driver stm32f2x_flash;
 extern const struct flash_driver stm32lx_flash;
 extern const struct flash_driver stm32l4x_flash;
+extern const struct flash_driver stm32l5x_flash;
 extern const struct flash_driver stm32h7x_flash;
 extern const struct flash_driver stmsmi_flash;
 extern const struct flash_driver str7x_flash;
@@ -142,6 +143,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &stm32f2x_flash,
        &stm32lx_flash,
        &stm32l4x_flash,
+       &stm32l5x_flash,
        &stm32h7x_flash,
        &stmsmi_flash,
        &str7x_flash,
diff --git a/src/flash/nor/stm32l5x.c b/src/flash/nor/stm32l5x.c
new file mode 100644
index 0000000..923c887
--- /dev/null
+++ b/src/flash/nor/stm32l5x.c
@@ -0,0 +1,1087 @@
+/***************************************************************************
+ *   Copyright (C) 2015 by Uwe Bonnes                                      *
+ *   b...@elektron.ikp.physik.tu-darmstadt.de                               *
+ *                                                                         *
+ *   Copyright (C) 2019 by Michael Jung                                    *
+ *   mij...@gmx.net                                                        *
+ *                                                                         *
+ *   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 "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+/* STM32L562 series for reference.
+ *
+ * RM0428 (STM32L552xx/STM32L562xx)
+ * http://www.st.com/resource/en/reference_manual/dm00346336.pdf
+ */
+
+/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
+
+#define FLASH_ERASE_TIMEOUT 250
+
+#define STM32_FLASH_BASE    0x40022000
+#define STM32_FLASH_ACR     0x40022000
+#define STM32_FLASH_NSKEYR  0x40022008
+#define STM32_FLASH_OPTKEYR 0x40022010
+#define STM32_FLASH_NSSR    0x40022020
+#define STM32_FLASH_NSCR    0x40022028
+#define STM32_FLASH_OPTR    0x40022040
+#define STM32_FLASH_WRP1AR  0x40022058
+#define STM32_FLASH_WRP1BR  0x4002205c
+#define STM32_FLASH_WRP2AR  0x40022068
+#define STM32_FLASH_WRP2BR  0x4002206c
+
+/* FLASH_NSCR register bits */
+
+#define FLASH_NSPG       (1 << 0)
+#define FLASH_NSPER      (1 << 1)
+#define FLASH_NSMER1     (1 << 2)
+#define FLASH_PAGE_SHIFT       3
+#define FLASH_CR_NSBKER  (1 << 11)
+#define FLASH_NSMER2     (1 << 15)
+#define FLASH_NSSTRT     (1 << 16)
+#define FLASH_NSOPTSTRT  (1 << 17)
+#define FLASH_NSEOPIE    (1 << 24)
+#define FLASH_NSERRIE    (1 << 25)
+#define FLASH_OBL_LAUNCH (1 << 27)
+#define FLASH_OPTLOCK    (1 << 30)
+#define FLASH_NSLOCK     (1 << 31)
+
+/* FLASH_NSSR register bits */
+
+#define FLASH_NSBSY      (1 << 16)
+/* Fast programming not used => related errors not used*/
+#define FLASH_NSPGSERR   (1 << 7) /* Programming sequence error */
+#define FLASH_NSSIZERR   (1 << 6) /* Size error */
+#define FLASH_NSPGAERR   (1 << 5) /* Programming alignment error */
+#define FLASH_NSWRPERR   (1 << 4) /* Write protection error */
+#define FLASH_NSPROGERR  (1 << 3) /* Programming error */
+#define FLASH_NSOPERR    (1 << 1) /* Operation error */
+#define FLASH_NSEOP      (1 << 0) /* End of operation */
+
+#define FLASH_ERROR (FLASH_NSPGSERR | FLASH_NSSIZERR | FLASH_NSPGAERR | 
FLASH_NSWRPERR | FLASH_NSOPERR)
+
+/* STM32_FLASH_OBR bit definitions (reading) */
+
+#define OPT_DBANK_C_256K (1 << 21)     /* dual bank for devices with 256 KiB 
flash */
+#define OPT_DBANK_E_512K (1 << 22)     /* dual bank for devices with 512 KiB 
flash */
+
+/* register unlock keys */
+
+#define KEY1           0x45670123
+#define KEY2           0xCDEF89AB
+
+/* option register unlock key */
+#define OPTKEY1        0x08192A3B
+#define OPTKEY2        0x4C5D6E7F
+
+#define RDP_LEVEL_0       0xAA
+#define RDP_LEVEL_1       0xBB
+#define RDP_LEVEL_2       0xCC
+
+
+/* other registers */
+#define DBGMCU_IDCODE  0xE0044000
+#define FLASH_SIZE_REG  0x0BFA05E0
+
+/* Power control macro (PWR) */
+
+#define STM32_PWR_BASE 0x40007000
+#define STM32_PWR_CR1  0x40007000
+#define STM32_PWR_SR2  0x40007014
+
+/* PWR_CR1 register bits */
+
+#define PWR_CR1_VOS_MASK       0x00000600
+#define  PWR_CR1_VOS_RANGE_0   0x00000000
+#define  PWR_CR1_VOS_RANGE_1   0x00000200
+#define  PWR_CR1_VOS_RANGE_2   0x00000400
+
+#define PWR_SR2_VOSF           0x00000400
+
+/* Reset and Clock Control macro (RCC) */
+
+#define STM32_RCC_BASE         0x40021000
+#define STM32_RCC_APB1ENR1     0x40021058
+
+/* RCC_APB1ENR1 register bits */
+
+#define RCC_APB1ENR1_PWREN     0x10000000
+
+struct stm32l5_flash_bank {
+       uint16_t bank2_start;
+       int probed;
+};
+
+/* flash bank stm32l5x <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(stm32l5_flash_bank_command)
+{
+       struct stm32l5_flash_bank *stm32l5_info;
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       stm32l5_info = malloc(sizeof(struct stm32l5_flash_bank));
+       if (!stm32l5_info)
+               return ERROR_FAIL; /* Checkme: What better error to use?*/
+       bank->driver_priv = stm32l5_info;
+
+       stm32l5_info->probed = 0;
+
+       return ERROR_OK;
+}
+
+static inline int stm32l5_get_flash_reg(struct flash_bank *bank, uint32_t reg)
+{
+       return reg;
+}
+
+static inline int stm32l5_get_flash_status(struct flash_bank *bank, uint32_t 
*status)
+{
+       struct target *target = bank->target;
+       return target_read_u32(
+               target, stm32l5_get_flash_reg(bank, STM32_FLASH_NSSR), status);
+}
+
+static int stm32l5_wait_status_busy(struct flash_bank *bank, int timeout)
+{
+       struct target *target = bank->target;
+       uint32_t status;
+       int retval = ERROR_OK;
+
+       /* wait for busy to clear */
+       for (;;) {
+               retval = stm32l5_get_flash_status(bank, &status);
+               if (retval != ERROR_OK)
+                       return retval;
+               LOG_DEBUG("status: 0x%" PRIx32 "", status);
+               if ((status & FLASH_NSBSY) == 0)
+                       break;
+               if (timeout-- <= 0) {
+                       LOG_ERROR("timed out waiting for flash");
+                       return ERROR_FAIL;
+               }
+               alive_sleep(1);
+       }
+
+
+       if (status & FLASH_NSWRPERR) {
+               LOG_ERROR("stm32x device protected");
+               retval = ERROR_FAIL;
+       }
+
+       /* Clear but report errors */
+       if (status & FLASH_ERROR) {
+               if (retval == ERROR_OK)
+                       retval = ERROR_FAIL;
+               /* If this operation fails, we ignore it and report the original
+                * retval
+                */
+               target_write_u32(target, stm32l5_get_flash_reg(bank, 
STM32_FLASH_NSSR),
+                               status & FLASH_ERROR);
+       }
+       return retval;
+}
+
+static int stm32l5_unlock_reg(struct target *target)
+{
+       uint32_t ctrl;
+
+       /* first check if not already unlocked
+        * otherwise writing on STM32_FLASH_NSKEYR will fail
+        */
+       int retval = target_read_u32(target, STM32_FLASH_NSCR, &ctrl);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((ctrl & FLASH_NSLOCK) == 0)
+               return ERROR_OK;
+
+       /* Flash write and erase operations are possible only in medium or
+        * high performance voltage ranges (range 1 or 0, respectively).  Per
+        * default, devices come up in range 2 (low-power range).  Thus, ensure
+        * we are running in an appropriate voltage range.
+        */
+
+       retval = target_read_u32(target, STM32_PWR_CR1, &ctrl);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (((ctrl & PWR_CR1_VOS_MASK) != PWR_CR1_VOS_RANGE_0) &&
+           ((ctrl & PWR_CR1_VOS_MASK) != PWR_CR1_VOS_RANGE_1)) {
+
+               uint32_t enable;
+               uint32_t status;
+               int i;
+
+               /* The device has to be reconfigured to run in voltage range 1.
+                * To be able to do this, the peripheral clock of the PWR macro
+                * has to be enabled first.
+                */
+
+               retval = target_read_u32(target, STM32_RCC_APB1ENR1, &enable);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               enable |= RCC_APB1ENR1_PWREN;
+
+               retval = target_write_u32(target, STM32_RCC_APB1ENR1, enable);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* Now switch to voltage range 1 ... */
+
+               ctrl = (ctrl & ~PWR_CR1_VOS_MASK) | PWR_CR1_VOS_RANGE_1;
+
+               retval = target_write_u32(target, STM32_PWR_CR1, ctrl);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* ... and wait for the power controller to complete */
+
+               for (i = 0; i < 100; i++) {
+                       retval = target_read_u32(target, STM32_PWR_SR2,
+                                                &status);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       if (!(status & PWR_SR2_VOSF))
+                               break;
+               }
+
+               if (status & PWR_SR2_VOSF) {
+                       LOG_ERROR("Dynamic regulator failed to enter selected "
+                                 "voltage range. PWR_SR2: 0x%08" PRIx32,
+                                 status);
+                       return ERROR_TARGET_FAILURE;
+               }
+
+               retval = target_read_u32(target, STM32_PWR_CR1, &ctrl);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               if ((ctrl & PWR_CR1_VOS_MASK) != PWR_CR1_VOS_RANGE_1) {
+                       LOG_ERROR("Dynamic regulator still not in voltage "
+                                 "range 1. PWR_CR1: 0x%08" PRIx32, ctrl);
+                       return ERROR_TARGET_FAILURE;
+               }
+       }
+
+       /* unlock flash registers */
+       retval = target_write_u32(target, STM32_FLASH_NSKEYR, KEY1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, STM32_FLASH_NSKEYR, KEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target, STM32_FLASH_NSCR, &ctrl);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (ctrl & FLASH_NSLOCK) {
+               LOG_ERROR("flash not unlocked STM32_FLASH_CR: %" PRIx32, ctrl);
+               return ERROR_TARGET_FAILURE;
+       }
+
+       return ERROR_OK;
+}
+
+static int stm32l5_unlock_option_reg(struct target *target)
+{
+       uint32_t ctrl;
+
+       int retval = target_read_u32(target, STM32_FLASH_NSCR, &ctrl);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((ctrl & FLASH_OPTLOCK) == 0)
+               return ERROR_OK;
+
+       /* unlock option registers */
+       retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target, STM32_FLASH_NSCR, &ctrl);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (ctrl & FLASH_OPTLOCK) {
+               LOG_ERROR("options not unlocked STM32_FLASH_CR: %" PRIx32, 
ctrl);
+               return ERROR_TARGET_FAILURE;
+       }
+
+       return ERROR_OK;
+}
+
+static int stm32l5_read_option(struct flash_bank *bank, uint32_t address, 
uint32_t* value)
+{
+       struct target *target = bank->target;
+       return target_read_u32(target, address, value);
+}
+
+static int stm32l5_write_option(struct flash_bank *bank, uint32_t address, 
uint32_t value, uint32_t mask)
+{
+       struct target *target = bank->target;
+       uint32_t optiondata;
+
+       int retval = target_read_u32(target, address, &optiondata);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32l5_unlock_reg(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32l5_unlock_option_reg(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       optiondata = (optiondata & ~mask) | (value & mask);
+
+       retval = target_write_u32(target, address, optiondata);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, stm32l5_get_flash_reg(bank, 
STM32_FLASH_NSCR), FLASH_NSOPTSTRT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32l5_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return retval;
+}
+
+static int stm32l5_protect_check(struct flash_bank *bank)
+{
+       struct stm32l5_flash_bank *stm32l5_info = bank->driver_priv;
+       uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
+       stm32l5_read_option(bank, STM32_FLASH_WRP1AR, &wrp1ar);
+       stm32l5_read_option(bank, STM32_FLASH_WRP1BR, &wrp1br);
+       stm32l5_read_option(bank, STM32_FLASH_WRP2AR, &wrp2ar);
+       stm32l5_read_option(bank, STM32_FLASH_WRP2BR, &wrp2br);
+
+       const uint8_t wrp1a_start = wrp1ar & 0xFF;
+       const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF;
+       const uint8_t wrp1b_start = wrp1br & 0xFF;
+       const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF;
+       const uint8_t wrp2a_start = wrp2ar & 0xFF;
+       const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF;
+       const uint8_t wrp2b_start = wrp2br & 0xFF;
+       const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF;
+
+       for (int i = 0; i < bank->num_sectors; i++) {
+               if (i < stm32l5_info->bank2_start) {
+                       if (((i >= wrp1a_start) &&
+                                (i <= wrp1a_end)) ||
+                               ((i >= wrp1b_start) &&
+                                (i <= wrp1b_end)))
+                               bank->sectors[i].is_protected = 1;
+                       else
+                               bank->sectors[i].is_protected = 0;
+               } else {
+                       uint8_t snb;
+                       snb = i - stm32l5_info->bank2_start;
+                       if (((snb >= wrp2a_start) &&
+                                (snb <= wrp2a_end)) ||
+                               ((snb >= wrp2b_start) &&
+                                (snb <= wrp2b_end)))
+                               bank->sectors[i].is_protected = 1;
+                       else
+                               bank->sectors[i].is_protected = 0;
+               }
+       }
+       return ERROR_OK;
+}
+
+static int stm32l5_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       int i;
+
+       assert(first < bank->num_sectors);
+       assert(last < bank->num_sectors);
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       int retval;
+       retval = stm32l5_unlock_reg(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /*
+       Sector Erase
+       To erase a sector, follow the procedure below:
+       1. Check that no Flash memory operation is ongoing by
+       checking the BSY bit in the FLASH_SR register
+       2. Set the PER bit and select the page and bank
+          you wish to erase in the FLASH_CR register
+       3. Set the STRT bit in the FLASH_CR register
+       4. Wait for the BSY bit to be cleared
+        */
+       struct stm32l5_flash_bank *stm32l5_info = bank->driver_priv;
+
+       for (i = first; i <= last; i++) {
+               uint32_t erase_flags;
+               erase_flags = FLASH_NSPER | FLASH_NSSTRT;
+
+               if (i >= stm32l5_info->bank2_start) {
+                       uint8_t snb;
+                       snb = i - stm32l5_info->bank2_start;
+                       erase_flags |= snb << FLASH_PAGE_SHIFT | 
FLASH_CR_NSBKER;
+               } else
+                       erase_flags |= i << FLASH_PAGE_SHIFT;
+               retval = target_write_u32(target,
+                               stm32l5_get_flash_reg(bank, STM32_FLASH_NSCR), 
erase_flags);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = stm32l5_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               bank->sectors[i].is_erased = 1;
+       }
+
+       retval = target_write_u32(
+               target, stm32l5_get_flash_reg(bank, STM32_FLASH_NSCR), 
FLASH_NSLOCK);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32l5_protect(struct flash_bank *bank, int set, int first, int 
last)
+{
+       struct target *target = bank->target;
+       struct stm32l5_flash_bank *stm32l5_info = bank->driver_priv;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       int ret = ERROR_OK;
+       /* Bank 2 */
+       uint32_t reg_value = 0xFF; /* Default to bank un-protected */
+       if (last >= stm32l5_info->bank2_start) {
+               if (set == 1) {
+                       uint8_t begin = first > stm32l5_info->bank2_start ? 
first : 0x00;
+                       reg_value = ((last & 0xFF) << 16) | begin;
+               }
+
+               ret = stm32l5_write_option(bank, STM32_FLASH_WRP2AR, reg_value, 
0xffffffff);
+       }
+       /* Bank 1 */
+       reg_value = 0xFF; /* Default to bank un-protected */
+       if (first < stm32l5_info->bank2_start) {
+               if (set == 1) {
+                       uint8_t end = last >= stm32l5_info->bank2_start ? 0xFF 
: last;
+                       reg_value = (end << 16) | (first & 0xFF);
+               }
+
+               ret = stm32l5_write_option(bank, STM32_FLASH_WRP1AR, reg_value, 
0xffffffff);
+       }
+
+       return ret;
+}
+
+/* Count is in halfwords */
+static int stm32l5_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 = 16384;
+       struct working_area *write_algorithm;
+       struct working_area *source;
+       uint32_t address = bank->base + offset;
+       struct reg_param reg_params[5];
+       struct armv7m_algorithm armv7m_info;
+       int retval = ERROR_OK;
+
+       static const uint8_t stm32l5_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/stm32/stm32l5x.inc"
+       };
+
+       if (target_alloc_working_area(target, sizeof(stm32l5_flash_write_code),
+                       &write_algorithm) != ERROR_OK) {
+               LOG_WARNING("no working area available, can't do block memory 
writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       retval = target_write_buffer(target, write_algorithm->address,
+                       sizeof(stm32l5_flash_write_code),
+                       stm32l5_flash_write_code);
+       if (retval != ERROR_OK) {
+               target_free_working_area(target, write_algorithm);
+               return retval;
+       }
+
+       /* memory buffer */
+       while (target_alloc_working_area_try(target, buffer_size, &source) !=
+                  ERROR_OK) {
+               buffer_size /= 2;
+               if (buffer_size <= 256) {
+                       /* we already allocated the writing code, but failed to 
get a
+                        * buffer, free the algorithm */
+                       target_free_working_area(target, write_algorithm);
+
+                       LOG_WARNING("large enough working area not available, 
can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       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) */
+       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 base */
+
+       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 / 4);
+       buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE);
+
+       retval = target_run_flash_async_algorithm(target, buffer, count, 2,
+                       0, NULL,
+                       5, reg_params,
+                       source->address, source->size,
+                       write_algorithm->address, 0,
+                       &armv7m_info);
+
+       if (retval == ERROR_FLASH_OPERATION_FAILED) {
+               LOG_ERROR("error executing stm32l5 flash write algorithm");
+
+               uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & 
FLASH_ERROR;
+
+               if (error & FLASH_NSWRPERR)
+                       LOG_ERROR("flash memory write protected");
+
+               if (error != 0) {
+                       LOG_ERROR("flash write failed = %08" PRIx32, error);
+                       /* Clear but report errors */
+                       target_write_u32(target, STM32_FLASH_NSSR, error);
+                       retval = ERROR_FAIL;
+               }
+       }
+
+       target_free_working_area(target, source);
+       target_free_working_area(target, write_algorithm);
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+
+       return retval;
+}
+
+static int stm32l5_write(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset & 0x7) {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte 
alignment",
+                                       offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       if (count & 0x7) {
+               LOG_WARNING("Padding %d bytes to keep 8-byte write size",
+                                       count & 7);
+               count = (count + 7) & ~7;
+               /* This pads the write chunk with random bytes by overrunning 
the
+                * write buffer. Padding with the erased pattern 0xff is purely
+                * cosmetical, as 8-byte flash words are ECC secured and the 
first
+                * write will program the ECC bits. A second write would need
+                * to reprogramm these ECC bits.
+                * But this can only be done after erase!
+                */
+       }
+
+       retval = stm32l5_unlock_reg(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Only full double words (8-byte) can be programmed*/
+       retval = stm32l5_write_block(bank, buffer, offset, count / 2);
+       if (retval != ERROR_OK) {
+               LOG_WARNING("block write failed");
+               return retval;
+               }
+
+       LOG_WARNING("block write succeeded");
+       return target_write_u32(target, STM32_FLASH_NSCR, FLASH_NSLOCK);
+}
+
+static int stm32l5_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct stm32l5_flash_bank *stm32l5_info = bank->driver_priv;
+       int i;
+       uint16_t flash_size_in_kb = 0xffff;
+       uint16_t max_flash_size_in_kb;
+       uint32_t device_id;
+       uint32_t options;
+       uint32_t base_address = 0x08000000;
+
+       stm32l5_info->probed = 0;
+
+       /* read stm32 device id register */
+       int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id);
+       if (retval != ERROR_OK)
+               return retval;
+       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
+
+       /* set max flash size depending on family */
+       switch (device_id & 0xfff) {
+       case 0x472:
+               max_flash_size_in_kb = 512;
+               break;
+       default:
+               LOG_WARNING("Cannot identify target as an STM32L5 family 
device.");
+               return ERROR_FAIL;
+       }
+
+       /* get flash size from target. */
+       retval = target_read_u16(target, FLASH_SIZE_REG, &flash_size_in_kb);
+
+       /* failed reading flash size or flash size invalid (early silicon),
+        * default to max target family */
+       if (retval != ERROR_OK || flash_size_in_kb == 0xffff || 
flash_size_in_kb == 0) {
+               LOG_WARNING("STM32 flash size failed, probe inaccurate - 
assuming %dk flash",
+                       max_flash_size_in_kb);
+               flash_size_in_kb = max_flash_size_in_kb;
+       }
+
+       LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
+
+       /* did we assign a flash size? */
+       assert((flash_size_in_kb != 0xffff) && flash_size_in_kb);
+
+       /* get options for DUAL BANK. */
+       retval = target_read_u32(target, STM32_FLASH_OPTR, &options);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       int num_pages = 0;
+       int page_size = 0;
+
+       switch (device_id & 0xfff) {
+               case 0x472:
+                       /* L552/L562 have 512 KiB FLASH and dual/single bank 
mode.
+                        * Page size is 2K or 4K.*/
+                       if (flash_size_in_kb == 512) {
+                               stm32l5_info->bank2_start = 128;
+                               if (options & OPT_DBANK_E_512K) {
+                                       page_size = 2048;
+                                       num_pages = 256;
+                               } else {
+                                       page_size = 4096;
+                                       num_pages = 128;
+                               }
+                               break;
+                       }
+                       /* Invalid FLASH size for this device. */
+                       LOG_WARNING("Invalid flash size for STM32L5+ family 
device.");
+                       return ERROR_FAIL;
+               default:
+                       /* Invalid FLASH size for this device. */
+                       LOG_WARNING("Invalid flash size for STM32L5+ family 
device.");
+                       return ERROR_FAIL;
+       }
+
+       /* Release sector table if allocated. */
+       if (bank->sectors) {
+               free(bank->sectors);
+               bank->sectors = NULL;
+       }
+
+       /* Set bank configuration and construct sector table. */
+       bank->base = base_address;
+       bank->size = num_pages * page_size;
+       bank->num_sectors = num_pages;
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+       if (!bank->sectors)
+               return ERROR_FAIL; /* Checkme: What better error to use?*/
+
+       for (i = 0; i < num_pages; i++) {
+               bank->sectors[i].offset = i * page_size;
+               bank->sectors[i].size = page_size;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 1;
+       }
+
+       stm32l5_info->probed = 1;
+
+       return ERROR_OK;
+}
+
+static int stm32l5_auto_probe(struct flash_bank *bank)
+{
+       struct stm32l5_flash_bank *stm32l5_info = bank->driver_priv;
+       if (stm32l5_info->probed)
+               return ERROR_OK;
+       return stm32l5_probe(bank);
+}
+
+static int get_stm32l5_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct target *target = bank->target;
+       uint32_t dbgmcu_idcode;
+
+       /* read stm32 device id register */
+       int retval = target_read_u32(target, DBGMCU_IDCODE, &dbgmcu_idcode);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint16_t device_id = dbgmcu_idcode & 0xfff;
+       uint8_t rev_id = dbgmcu_idcode >> 28;
+       uint8_t rev_minor = 0;
+       int i;
+
+       for (i = 16; i < 28; i++) {
+               if (dbgmcu_idcode & (1 << i))
+                       rev_minor++;
+               else
+                       break;
+       }
+
+       const char *device_str;
+
+       switch (device_id) {
+       case 0x472:
+               device_str = "STM32L552/562";
+               break;
+
+       default:
+               snprintf(buf, buf_size, "Cannot identify target as a 
STM32L5\n");
+               return ERROR_FAIL;
+       }
+
+       snprintf(buf, buf_size, "%s - Rev: %1d.%02d",
+                        device_str, rev_id, rev_minor);
+
+       return ERROR_OK;
+}
+
+static int stm32l5_mass_erase(struct flash_bank *bank, uint32_t action)
+{
+       int retval;
+       struct target *target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       retval = stm32l5_unlock_reg(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* mass erase flash memory */
+       retval = target_write_u32(
+               target, stm32l5_get_flash_reg(bank, STM32_FLASH_NSCR), action);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(
+               target, stm32l5_get_flash_reg(bank, STM32_FLASH_NSCR),
+               action | FLASH_NSSTRT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32l5_wait_status_busy(bank,  FLASH_ERASE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(
+               target, stm32l5_get_flash_reg(bank, STM32_FLASH_NSCR), 
FLASH_NSLOCK);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32l5_handle_mass_erase_command)
+{
+       int i;
+       uint32_t action;
+
+       if (CMD_ARGC < 1) {
+               command_print(CMD, "stm32l5x mass_erase <STM32L5 bank>");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       action =  FLASH_NSMER1 |  FLASH_NSMER2;
+       retval = stm32l5_mass_erase(bank, action);
+       if (retval == ERROR_OK) {
+               /* set all sectors as erased */
+               for (i = 0; i < bank->num_sectors; i++)
+                       bank->sectors[i].is_erased = 1;
+
+               command_print(CMD, "stm32l5x mass erase complete");
+       } else {
+               command_print(CMD, "stm32l5x mass erase failed");
+       }
+
+       return retval;
+}
+
+COMMAND_HANDLER(stm32l5_handle_option_read_command)
+{
+       if (CMD_ARGC < 2) {
+               command_print(CMD, "stm32l5x option_read <STM32L5 bank> 
<option_reg offset>");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       uint32_t reg_addr = STM32_FLASH_BASE;
+       uint32_t value = 0;
+
+       reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+
+       retval = stm32l5_read_option(bank, reg_addr, &value);
+       if (ERROR_OK != retval)
+               return retval;
+
+       command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", 
reg_addr, value);
+
+       return retval;
+}
+
+COMMAND_HANDLER(stm32l5_handle_option_write_command)
+{
+       if (CMD_ARGC < 3) {
+               command_print(CMD, "stm32l5x option_write <STM32L5 bank> 
<option_reg offset> <value> [mask]");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       uint32_t reg_addr = STM32_FLASH_BASE;
+       uint32_t value = 0;
+       uint32_t mask = 0xFFFFFFFF;
+
+       reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+       value = strtoul(CMD_ARGV[2], NULL, 16);
+       if (CMD_ARGC > 3)
+               mask = strtoul(CMD_ARGV[3], NULL, 16);
+
+       command_print(CMD, "%s Option written.\n"
+                               "INFO: a reset or power cycle is required "
+                               "for the new settings to take effect.", 
bank->driver->name);
+
+       retval = stm32l5_write_option(bank, reg_addr, value, mask);
+       return retval;
+}
+
+COMMAND_HANDLER(stm32l5_handle_option_load_command)
+{
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       struct target *target = bank->target;
+
+       retval = stm32l5_unlock_reg(target);
+       if (ERROR_OK != retval)
+               return retval;
+
+       retval = stm32l5_unlock_option_reg(target);
+       if (ERROR_OK != retval)
+               return retval;
+
+       /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes 
reload */
+       retval = target_write_u32(target, stm32l5_get_flash_reg(bank, 
STM32_FLASH_NSCR), FLASH_OBL_LAUNCH);
+
+       command_print(CMD, "stm32l5x option load (POR) completed.");
+       return retval;
+}
+
+COMMAND_HANDLER(stm32l5_handle_lock_command)
+{
+       struct target *target = NULL;
+
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* set readout protection level 1 by erasing the RDP option byte */
+       if (stm32l5_write_option(bank, STM32_FLASH_OPTR, 0, 0x000000FF) != 
ERROR_OK) {
+               command_print(CMD, "%s failed to lock device", 
bank->driver->name);
+               return ERROR_OK;
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32l5_handle_unlock_command)
+{
+       struct target *target = NULL;
+
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (stm32l5_write_option(bank, STM32_FLASH_OPTR, RDP_LEVEL_0, 
0x000000FF) != ERROR_OK) {
+               command_print(CMD, "%s failed to unlock device", 
bank->driver->name);
+               return ERROR_OK;
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration stm32l5_exec_command_handlers[] = {
+       {
+               .name = "lock",
+               .handler = stm32l5_handle_lock_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Lock entire flash device.",
+       },
+       {
+               .name = "unlock",
+               .handler = stm32l5_handle_unlock_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Unlock entire protected flash device.",
+       },
+       {
+               .name = "mass_erase",
+               .handler = stm32l5_handle_mass_erase_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Erase entire flash device.",
+       },
+       {
+               .name = "option_read",
+               .handler = stm32l5_handle_option_read_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id reg_offset",
+               .help = "Read & Display device option bytes.",
+       },
+       {
+               .name = "option_write",
+               .handler = stm32l5_handle_option_write_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id reg_offset value mask",
+               .help = "Write device option bit fields with provided value.",
+       },
+       {
+               .name = "option_load",
+               .handler = stm32l5_handle_option_load_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Force re-load of device options (will cause device 
reset).",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration stm32l5_command_handlers[] = {
+       {
+               .name = "stm32l5x",
+               .mode = COMMAND_ANY,
+               .help = "stm32l5x flash command group",
+               .usage = "",
+               .chain = stm32l5_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct flash_driver stm32l5x_flash = {
+       .name = "stm32l5x",
+       .commands = stm32l5_command_handlers,
+       .flash_bank_command = stm32l5_flash_bank_command,
+       .erase = stm32l5_erase,
+       .protect = stm32l5_protect,
+       .write = stm32l5_write,
+       .read = default_flash_read,
+       .probe = stm32l5_probe,
+       .auto_probe = stm32l5_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = stm32l5_protect_check,
+       .info = get_stm32l5_info,
+       .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/tcl/target/stm32l5x.cfg b/tcl/target/stm32l5x.cfg
new file mode 100644
index 0000000..8ee602c
--- /dev/null
+++ b/tcl/target/stm32l5x.cfg
@@ -0,0 +1,103 @@
+# script for stm32l5x family
+
+#
+# stm32l5 devices support both JTAG and SWD transports.
+#
+source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME stm32l5x
+}
+
+set _ENDIAN little
+
+# Work-area is a space in RAM used for flash programming
+# Smallest current target has 256kB ram, use 32kB by default to avoid surprises
+if { [info exists WORKAREASIZE] } {
+   set _WORKAREASIZE $WORKAREASIZE
+} else {
+   set _WORKAREASIZE 0x8000
+}
+
+#jtag scan chain
+if { [info exists CPUTAPID] } {
+   set _CPUTAPID $CPUTAPID
+} else {
+   if { [using_jtag] } {
+      # See STM Document RM0438
+      # Section 51.2.10 Debug port registers - corresponds to Cortex-M33 r0p0
+      set _CPUTAPID 0x0be11477
+   } {
+      set _CPUTAPID 0x0be12477
+   }
+}
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 
$_CPUTAPID
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+if {[using_jtag]} {
+   jtag newtap $_CHIPNAME bs -irlen 5
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE -work-area-backup 0
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME stm32l5x 0 0 0 0 $_TARGETNAME
+
+# Common knowledges tells JTAG speed should be <= F_CPU/6.
+# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on
+# the safe side.
+#
+# Note that there is a pretty wide band where things are
+# more or less stable, see http://openocd.zylin.com/#/c/3366/
+adapter_khz 500
+
+adapter_nsrst_delay 100
+if {[using_jtag]} {
+ jtag_ntrst_delay 100
+}
+
+reset_config srst_nogate
+
+if {![using_hla]} {
+   # if srst is not fitted use SYSRESETREQ to
+   # perform a soft reset
+   cortex_m reset_config sysresetreq
+}
+
+$_TARGETNAME configure -event reset-init {
+       # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 6 (4 MHz).
+       # Use MSI 24 MHz clock, compliant even with VOS == 2.
+       # 3 WS compliant with VOS == 2 and 24 MHz.
+       mww 0x40022000 0x00000103   ;# FLASH_ACR = PRFTBE | 3(Latency)
+       mww 0x40021000 0x00000099   ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9
+       # Boost JTAG frequency
+       adapter_khz 4000
+}
+
+$_TARGETNAME configure -event reset-start {
+       # Reset clock is MSI (4 MHz)
+       adapter_khz 500
+}
+
+$_TARGETNAME configure -event examine-end {
+       # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
+       mmw 0xE0042004 0x00000007 0
+
+       # Stop watchdog counters during halt
+       # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP
+       mmw 0xE0042008 0x00001800 0
+}
+
+$_TARGETNAME configure -event trace-config {
+       # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+       # change this value accordingly to configure trace pins
+       # assignment
+       mmw 0xE0042004 0x00000020 0
+}

-- 


_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to