This is an automated email from Gerrit.

Brian Shewan ([email protected]) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/5131

-- gerrit

commit dcec354bfc756c4a4e1034c9461b5d3f4e55a63e
Author: Brian Shewan <[email protected]>
Date:   Tue Apr 23 19:42:47 2019 -0300

    flash: added support for stm32g0
    
    Change-Id: Ia979ae12c2f9512c6dbf129c93913b2398191dd7
    Signed-off-by: Brian Shewan <[email protected]>

diff --git a/contrib/loaders/flash/stm32/Makefile 
b/contrib/loaders/flash/stm32/Makefile
index b58b412..efa7df0 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 stm32lx.inc 
stm32g0x.inc
 
 .PHONY: clean
 
diff --git a/contrib/loaders/flash/stm32/stm32g0x.S 
b/contrib/loaders/flash/stm32/stm32g0x.S
new file mode 100644
index 0000000..437b631
--- /dev/null
+++ b/contrib/loaders/flash/stm32/stm32g0x.S
@@ -0,0 +1,75 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by Andreas Fritiofson                              *
+ *   [email protected]                                          *
+ *                                                                         *
+ *   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.                          *
+ *                                                                         *
+ ***************************************************************************/
+
+       .text
+       .syntax unified
+       .cpu cortex-m0plus
+       .thumb
+
+       /* Params:
+        * r0 - flash base (in), status (out)
+        * r1 - count (double word - 64bit)
+        * r2 - workarea start
+        * r3 - workarea end
+        * r4 - target address
+        * Clobbered:
+        * r5 - rp
+        * r6 - wp, tmp
+        * r7 - tmp
+        */
+
+#define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register from flash reg 
base */
+
+       .thumb_func
+       .global _start
+_start:
+wait_fifo:
+       ldr     r6, [r2, #0]    /* load R6 with 32-bit word from workarea start 
address */
+       cmp     r6, #0                    /* is word zero? */
+       beq     exit          /* if so, exit */
+       ldr     r5, [r2, #4]    /* load R5 with next word from workarea */
+       cmp     r5, r6                    /* are the two words the same? */
+       beq     wait_fifo     /* if so, goto wait_fifo */
+       ldr       r6, [r5]          /* load R6 with word from R5 */
+       str       r6, [r4]      /* store word in R6 to target address */
+       ldr       r6, [r5, #4]  /* load R6 with word from R5 */
+       str       r6, [r4, #4]  /* store word in R6 to target address */
+       adds    r5, #8        /* add 8 to R5 */
+       adds    r4, #8        /* add 8 to R4 */
+busy:
+       ldr     r6, [r0, #STM32_FLASH_SR_OFFSET]        /* wait until BSY flag 
is reset */
+       movs    r7, #0x10000  /* set R7 = 0x10000 */
+       tst     r6, r7        /* AND SR reg with 0x10000 */
+       bne     busy          /* if bit is set, go to busy and check again */
+       movs    r7, #0xFA           /* set R7 = 0xFA */ /* check the error bits 
*/
+       tst     r6, r7        /* AND SR reg with 0x3FA */
+       bne     error         /* if error bits set, goto error */
+       cmp     r5, r3                    /* is R5 at end of workarea? */ /* 
wrap rp at end of buffer */
+       bcc       no_wrap       /* if R5 < R3 */
+       mov       r5, r2        /* set R5 to start of ring buffer */
+       adds    r5, #8        /* skip over rp and wp pointers */
+no_wrap:
+       str     r5, [r2, #4]    /* store rp */
+       subs    r1, r1, #1              /* decrement doubleword count */
+       cmp   r1, #0
+       beq   exit              /* loop if not done */
+       b           wait_fifo
+error:
+       movs    r0, #0
+       str     r0, [r2, #4]    /* set rp = 0 on error */
+exit:
+       mov             r0, r6                  /* return status in r0 */
+       bkpt    #0
diff --git a/contrib/loaders/flash/stm32/stm32g0x.inc 
b/contrib/loaders/flash/stm32/stm32g0x.inc
new file mode 100644
index 0000000..36c7dd7
--- /dev/null
+++ b/contrib/loaders/flash/stm32/stm32g0x.inc
@@ -0,0 +1,7 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x16,0x68,0x00,0x2e,0x1b,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0,0x2e,0x68,0x26,0x60,
+0x6e,0x68,0x66,0x60,0x08,0x35,0x08,0x34,0x06,0x69,0x01,0x27,0x3f,0x04,0x3e,0x42,
+0xfa,0xd1,0xfa,0x27,0x3e,0x42,0x08,0xd1,0x9d,0x42,0x01,0xd3,0x15,0x46,0x08,0x35,
+0x55,0x60,0x01,0x39,0x00,0x29,0x02,0xd0,0xe2,0xe7,0x00,0x20,0x50,0x60,0x30,0x46,
+0x00,0xbe,
+
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 135128e..3f99ce9 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -60,6 +60,7 @@ NOR_DRIVERS = \
        %D%/stm32lx.c \
        %D%/stm32l4x.c \
        %D%/stm32h7x.c \
+       %D%/stm32g0x.c \
        %D%/str7x.c \
        %D%/str9x.c \
        %D%/str9xpec.c \
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 955d149..3305bde 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -73,6 +73,7 @@ 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 stm32h7x_flash;
+extern const struct flash_driver stm32g0x_flash;
 extern const struct flash_driver stmsmi_flash;
 extern const struct flash_driver str7x_flash;
 extern const struct flash_driver str9x_flash;
@@ -142,6 +143,7 @@ static const struct flash_driver * const flash_drivers[] = {
        &stm32lx_flash,
        &stm32l4x_flash,
        &stm32h7x_flash,
+       &stm32g0x_flash,
        &stmsmi_flash,
        &str7x_flash,
        &str9x_flash,
diff --git a/src/flash/nor/stm32g0x.c b/src/flash/nor/stm32g0x.c
new file mode 100644
index 0000000..cd2b1a3
--- /dev/null
+++ b/src/flash/nor/stm32g0x.c
@@ -0,0 +1,1284 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   [email protected]                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   [email protected]                                                  *
+ *                                                                         *
+ *   Copyright (C) 2011 by Andreas Fritiofson                              *
+ *   [email protected]                                          *
+ *
+ *   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>
+
+/* stm32x register locations */
+
+#define FLASH_REG_BASE 0x40022000
+
+#define STM32_FLASH_ACR     0x00
+#define STM32_FLASH_KEYR    0x04
+#define STM32_FLASH_OPTKEYR 0x08
+#define STM32_FLASH_SR      0x0C
+#define STM32_FLASH_CR      0x10
+#define STM32_FLASH_AR      0x14
+#define STM32_FLASH_OBR     0x1C
+#define STM32_FLASH_WRPR    0x20
+
+#define STM32G0_FLASH_KEYR      0x08
+#define STM32G0_FLASH_OPTKEYR   0x0C
+#define STM32G0_FLASH_SR        0x10
+#define STM32G0_FLASH_CR        0x14
+#define STM32G0_FLASH_WRP1AR    0x2C
+#define STM32G0_FLASH_WRP1BR    0x30
+
+/* option byte location */
+
+#define STM32_OB_USER_RDP              0x1FFF7800
+#define STM32_OB_PCROP1A_STRT  0x1FFF7808
+#define STM32_OB_PCROP1A_END   0x1FFF7810
+#define STM32_OB_WRP1A                 0x1FFF7818
+#define STM32_OB_WRP1B                 0x1FFF7820
+#define STM32_OB_PCROP1B_STRT  0x1FFF7828
+#define STM32_OB_PCROP1B_END   0x1FFF7830
+#define STM32_OB_BOOT_SEC              0x1FFF7870
+
+/* FLASH_CR register bits */
+
+#define FLASH_PG                       (1 << 0)
+#define FLASH_PER                      (1 << 1)
+#define FLASH_MER                      (1 << 2)
+#define FLASH_OPTPG                    (1 << 4)
+#define FLASH_OPTER                    (1 << 5)
+#define FLASH_STRT                     (1 << 6)
+#define FLASH_LOCK                     (1 << 7)
+#define FLASH_OPTWRE           (1 << 9)
+#define FLASH_OBL_LAUNCH       (1 << 13)       /* except stm32f1x series */
+
+#define STM32G0_FLASH_PG        (1 << 0)
+#define STM32G0_FLASH_PER       (1 << 1)
+#define STM32G0_FLASH_MER       (1 << 2)
+#define STM32G0_FLASH_STRT      (1 << 16)
+#define STM32G0_FLASH_OPTSTRT   (1 << 17)
+#define STM32G0_FLASH_OBL_LAUNCH (1 << 27)
+#define STM32G0_FLASH_LOCK      (1 << 31)
+
+/* FLASH_SR register bits */
+
+#define FLASH_BSY              (1 << 0)
+#define FLASH_PGERR            (1 << 2)
+#define FLASH_WRPRTERR (1 << 4)
+#define FLASH_EOP              (1 << 5)
+
+#define STM32G0_FLASH_EOP       (1 << 0)    /* end of operation */
+#define STM32G0_FLASH_OPERR     (1 << 1)    /* operation error */
+#define STM32G0_FLASH_PROGERR   (1 << 3)    /* programming error */
+#define STM32G0_FLASH_WRPERR    (1 << 4)    /* write protection error */
+#define STM32G0_FLASH_BSY1      (1 << 16)   /* busy */
+
+/* STM32_FLASH_OBR bit definitions (reading) */
+
+#define OPT_ERROR              0
+#define OPT_READOUT            1
+#define OPT_RDWDGSW            2
+#define OPT_RDRSTSTOP  3
+#define OPT_RDRSTSTDBY 4
+
+/* register unlock keys */
+
+#define KEY1                   0x45670123
+#define KEY2                   0xCDEF89AB
+
+#define OPTKEY1         0x08192A3B
+#define OPTKEY2         0x4C5D6E7F
+
+/* timeout values */
+
+#define FLASH_WRITE_TIMEOUT 10
+#define FLASH_ERASE_TIMEOUT 100
+
+struct stm32g0x_options {
+       union {
+               struct {
+                       unsigned rdp:8;
+                       unsigned bor_en:1;
+                       unsigned borf_lev:2;
+                       unsigned borr_lev:2;
+                       unsigned rst_stop:1;
+                       unsigned rst_stdby:1;
+                       unsigned rst_shdw:1;
+                       unsigned iwdg_sw:1;
+                       unsigned iwdg_stop:1;
+                       unsigned iwdg_stdby:1;
+                       unsigned wwdg_sw:1;
+                       unsigned :2;
+                       unsigned ram_parity_check:1;
+                       unsigned :1;
+                       unsigned boot_sel:1;
+                       unsigned boot1:1;
+                       unsigned boot0:1;
+                       unsigned nrst_mode:2;
+                       unsigned irhen:1;
+               };
+               uint32_t user_rdp;
+       };
+       uint32_t pcrop1a;
+       uint32_t pcrop1b;
+       uint32_t wrp1a;
+       uint32_t wrp1b;
+       uint32_t security;
+};
+
+struct stm32g0x_flash_bank {
+       struct stm32g0x_options option_bytes;
+       int probed;
+
+       uint32_t register_base;
+       uint8_t default_rdp;
+       uint32_t user_bank_size;
+};
+
+static int stm32x_mass_erase(struct flash_bank *bank);
+static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id);
+static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t address, uint32_t count);
+
+/* flash bank stm32x <base> <size> 0 0 <target#>
+*/
+FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
+{
+       struct stm32g0x_flash_bank *stm32x_info;
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       stm32x_info = malloc(sizeof(struct stm32g0x_flash_bank));
+
+       bank->driver_priv = stm32x_info;
+       stm32x_info->probed = 0;
+       stm32x_info->register_base = FLASH_REG_BASE;
+       stm32x_info->user_bank_size = bank->size;
+
+       return ERROR_OK;
+}
+
+static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg)
+{
+       struct stm32g0x_flash_bank *stm32x_info = bank->driver_priv;
+       return reg + stm32x_info->register_base;
+}
+
+static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t 
*status)
+{
+       struct target *target = bank->target;
+       return target_read_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_SR), status);
+}
+
+static int stm32x_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 = stm32x_get_flash_status(bank, &status);
+               if (retval != ERROR_OK)
+                       return retval;
+               LOG_DEBUG("status: 0x%" PRIx32 "", status);
+               if ((status & STM32G0_FLASH_BSY1) == 0)
+                       break;
+               if (timeout-- <= 0) {
+                       LOG_ERROR("timed out waiting for flash");
+                       return ERROR_FAIL;
+               }
+               alive_sleep(1);
+       }
+
+       if (status & STM32G0_FLASH_WRPERR) {
+               LOG_ERROR("stm32x device protected");
+               retval = ERROR_FAIL;
+       }
+
+       if (status & STM32G0_FLASH_PROGERR) {
+               LOG_ERROR("stm32x device programming failed");
+               retval = ERROR_FAIL;
+       }
+
+       /* Clear but report errors */
+       if (status & (STM32G0_FLASH_WRPERR | STM32G0_FLASH_PROGERR)) {
+               /* If this operation fails, we ignore it and report the original
+                * retval
+                */
+               target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_SR),
+                               STM32G0_FLASH_WRPERR | STM32G0_FLASH_PROGERR);
+       }
+       return retval;
+}
+
+static int stm32x_read_options(struct flash_bank *bank)
+{
+       struct stm32g0x_flash_bank *stm32x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       int retval;
+
+       /* read user and read protection option bytes */
+       retval = target_read_u32(target, STM32_OB_USER_RDP, 
&(stm32x_info->option_bytes.user_rdp));
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target, STM32_OB_WRP1A, 
&(stm32x_info->option_bytes.wrp1a));
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target, STM32_OB_WRP1B, 
&(stm32x_info->option_bytes.wrp1b));
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t start, end;
+       retval = target_read_u32(target, STM32_OB_PCROP1A_STRT, &start);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_read_u32(target, STM32_OB_PCROP1A_END, &end);
+       if (retval != ERROR_OK)
+               return retval;
+       stm32x_info->option_bytes.pcrop1a = start + (end << 16);
+
+       retval = target_read_u32(target, STM32_OB_PCROP1B_STRT, &start);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_read_u32(target, STM32_OB_PCROP1B_END, &end);
+       if (retval != ERROR_OK)
+               return retval;
+       stm32x_info->option_bytes.pcrop1b = start + (end << 16);
+
+       retval = target_read_u32(target, STM32_OB_BOOT_SEC, 
&(stm32x_info->option_bytes.security));
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32x_write_options(struct flash_bank *bank)
+{
+       struct stm32g0x_flash_bank *stm32x_info = NULL;
+       struct target *target = bank->target;
+
+       stm32x_info = bank->driver_priv;
+
+       /* unlock flash registers */
+       int retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY1);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* unlock option flash registers */
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_OPTKEYR), OPTKEY1);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_OPTKEYR), OPTKEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* program option dwords */
+       uint8_t opt_bytes[64];
+
+       target_buffer_set_u64(target, opt_bytes, 
stm32x_info->option_bytes.user_rdp);
+       target_buffer_set_u64(target, opt_bytes + 8, 
stm32x_info->option_bytes.pcrop1a & 0xff);
+       target_buffer_set_u64(target, opt_bytes + 16, 
(stm32x_info->option_bytes.pcrop1a >> 16) & 0xff);
+       target_buffer_set_u64(target, opt_bytes + 24, 
stm32x_info->option_bytes.wrp1a);
+       target_buffer_set_u64(target, opt_bytes + 32, 
stm32x_info->option_bytes.wrp1b);
+       target_buffer_set_u64(target, opt_bytes + 40, 
stm32x_info->option_bytes.pcrop1b);
+       target_buffer_set_u64(target, opt_bytes + 48, 
(stm32x_info->option_bytes.pcrop1b >> 16) & 0xff);
+       target_buffer_set_u64(target, opt_bytes + 56, 
stm32x_info->option_bytes.security);
+
+       retval = stm32x_write_block(bank, opt_bytes, STM32_OB_USER_RDP, 
sizeof(opt_bytes) / 8);
+       if (retval != ERROR_OK) {
+               if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       LOG_ERROR("working area required to erase options 
bytes");
+               return retval;
+       }
+
+       retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), STM32G0_FLASH_OPTSTRT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), STM32G0_FLASH_LOCK);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32x_protect_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       uint32_t protection;
+
+       for (int i = 0; i < bank->num_prot_blocks; i++)
+               bank->prot_blocks[i].is_protected = 0;
+
+       /* area A register */
+       /* bits 21:16 - WRP1A_END[5:0], bits 5:0 - WRP1A_START[5:0] */
+       int retval = target_read_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_WRP1AR), &protection);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* the bank is protected, if it is in the area defined by the start and 
end */
+       uint8_t start = protection & 0x3F;
+       uint8_t end = (protection >> 16) & 0x3F;
+       if (start <= end) {
+               for (int i = 0; i < bank->num_prot_blocks; i++) {
+                       if ((i >= start) && (i <= end))
+                               bank->prot_blocks[i].is_protected = 1;
+               }
+       }
+
+       /* area B register */
+       /* bits 21:16 - WRP1B_END[5:0], bits 5:0 - WRP1B_START[5:0] */
+       retval = target_read_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_WRP1BR), &protection);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* the bank is protected, if it is in the area defined by the start and 
end */
+       start = protection & 0x3F;
+       end = (protection >> 16) & 0x3F;
+       if (start <= end) {
+               for (int i = 0; i < bank->num_prot_blocks; i++) {
+                       if ((i >= start) && (i <= end))
+                               bank->prot_blocks[i].is_protected = 1;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int stm32gx_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+
+       /* unlock flash registers */
+       int retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY1);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t val = 0x00L;
+       for (int i = first; i <= last; i++) {
+               retval = target_read_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), &val);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               val &= ~(0x3F << 3);
+               val |= (STM32G0_FLASH_PER | (i << 3) | STM32G0_FLASH_STRT);
+
+               retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), val);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               bank->sectors[i].is_erased = 1;
+       }
+
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), STM32G0_FLASH_LOCK);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32x_erase(struct flash_bank *bank, int first, int last)
+{
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((first == 0) && (last == (bank->num_sectors - 1)))
+               return stm32x_mass_erase(bank);
+
+       int retval = stm32gx_erase(bank, first, last);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32x_protect(struct flash_bank *bank, int set, int first, int 
last)
+{
+       struct target *target = bank->target;
+       struct stm32g0x_flash_bank *stm32x_info = bank->driver_priv;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (first > last) {
+               LOG_ERROR("Invalid memory range");
+               return ERROR_FLASH_SECTOR_INVALID;
+       }
+
+       if (set)
+               stm32x_info->option_bytes.wrp1a = first + (last << 16);
+       else
+               stm32x_info->option_bytes.wrp1a = 0;
+
+       return stm32x_write_options(bank);
+}
+
+static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t address, uint32_t count)
+{
+       struct stm32g0x_flash_bank *stm32x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t buffer_size = 16384;
+       struct working_area *write_algorithm;
+       struct working_area *source;
+       struct reg_param reg_params[5];
+       struct armv7m_algorithm armv7m_info;
+       int retval = ERROR_OK;
+
+       static const uint8_t stm32x_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/stm32/stm32g0x.inc"
+       };
+
+       /* flash write code */
+       if (target_alloc_working_area(target, sizeof(stm32x_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(stm32x_flash_write_code), 
stm32x_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;
+               buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
+               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("no large enough working area available, 
can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       }
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* flash base 
(in), status (out) */
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);    /* count 
(halfword-16bit) */
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);    /* buffer start 
*/
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);    /* buffer end */
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_IN_OUT); /* target 
address */
+
+       buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base);
+       buf_set_u32(reg_params[1].value, 0, 32, count);
+       buf_set_u32(reg_params[2].value, 0, 32, source->address);
+       buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
+       buf_set_u32(reg_params[4].value, 0, 32, address);
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.core_mode = ARM_MODE_THREAD;
+
+       retval = target_run_flash_async_algorithm(target, buffer, count, 8,
+                       0, NULL,
+                       5, reg_params,
+                       source->address, source->size,
+                       write_algorithm->address, 0,
+                       &armv7m_info);
+
+       if (retval == ERROR_FLASH_OPERATION_FAILED) {
+               LOG_ERROR("flash write failed at address 0x%"PRIx32,
+                               buf_get_u32(reg_params[4].value, 0, 32));
+
+               if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) {
+                       LOG_ERROR("flash memory not erased before writing");
+                       /* Clear but report errors */
+                       target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32_FLASH_SR), FLASH_PGERR);
+               }
+
+               if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) {
+                       LOG_ERROR("flash memory write protected");
+                       /* Clear but report errors */
+                       target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32_FLASH_SR), FLASH_WRPRTERR);
+               }
+       }
+
+       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 stm32gx_write(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+
+       uint8_t *new_buffer = NULL;
+
+       if (offset & 0x7) {
+               LOG_ERROR("offset 0x%" PRIx32 " breaks required 8-byte 
alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       /* If there's an odd number of bytes, the data has to be padded. 
Duplicate
+        * the buffer and use the normal code path with a single block write 
since
+        * it's probably cheaper than to special case the last odd write using
+        * discrete accesses. */
+       if (count & 7) {
+               int pad_count = 8 - (count & 7);
+               new_buffer = malloc(count + pad_count);
+               if (new_buffer == NULL) {
+                       LOG_ERROR("odd number of bytes to write and no memory 
for padding buffer");
+                       return ERROR_FAIL;
+               }
+               LOG_INFO("odd number of bytes to write, padding with 0xff");
+               buffer = memcpy(new_buffer, buffer, count);
+               for (int i = 0; i < pad_count; i++) 
+                       new_buffer[count++] = 0xff;
+       }
+
+       uint32_t dwords_remaining = count / 8;
+       int retval, retval2;
+
+       /* unlock flash registers */
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY1);
+       if (retval != ERROR_OK)
+               goto cleanup;
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY2);
+       if (retval != ERROR_OK)
+               goto cleanup;
+
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), STM32G0_FLASH_PG);
+       if (retval != ERROR_OK)
+               goto cleanup;
+
+       /* try using a block write */
+       retval = stm32x_write_block(bank, buffer, bank->base + offset, 
dwords_remaining);
+
+       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+               /* if block write failed (no sufficient working area),
+                * we use normal (slow) double word accesses */
+               LOG_WARNING("couldn't use block writes, falling back to single 
memory accesses");
+
+               while (dwords_remaining > 0) {
+                       uint64_t value;
+                       memcpy(&value, buffer, sizeof(uint64_t));
+
+                       retval = target_write_u64(target, bank->base + offset, 
value);
+                       if (retval != ERROR_OK)
+                               goto reset_pg_and_lock;
+
+                       retval = stm32x_wait_status_busy(bank, 5);
+                       if (retval != ERROR_OK)
+                               goto reset_pg_and_lock;
+
+                       dwords_remaining--;
+                       buffer += 8;
+                       offset += 8;
+               }
+       }
+
+reset_pg_and_lock:
+       retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), STM32G0_FLASH_LOCK);
+       if (retval == ERROR_OK)
+               retval = retval2;
+
+cleanup:
+       if (new_buffer)
+               free(new_buffer);
+
+       return retval;
+}
+
+static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t offset, uint32_t count)
+{
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       int retval = stm32gx_write(bank, buffer, offset, count);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
+{
+       /* This check the device CPUID core register to detect
+        * the M0 from the M3 devices. */
+
+       struct target *target = bank->target;
+       uint32_t cpuid, device_id_register = 0;
+
+       /* Get the CPUID from the ARM Core
+        * 
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf
 4.2.1 */
+       int retval = target_read_u32(target, 0xE000ED00, &cpuid);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (((cpuid >> 4) & 0xFFF) == 0xC60) {
+               /* 0xC60 is M0+ devices */
+               device_id_register = 0x40015800;
+       } else {
+               LOG_ERROR("Cannot identify target as a stm32g0x");
+               return ERROR_FAIL;
+       }
+
+       /* read stm32 device id register */
+       retval = target_read_u32(target, device_id_register, device_id);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return retval;
+}
+
+static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t 
*flash_size_in_kb)
+{
+       struct target *target = bank->target;
+       uint32_t cpuid, flash_size_reg;
+
+       int retval = target_read_u32(target, 0xE000ED00, &cpuid);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (((cpuid >> 4) & 0xFFF) == 0xC60) {
+               /* 0xC60 is M0+ devices */
+               flash_size_reg = 0x1FFF75E0;
+       } else {
+               LOG_ERROR("Cannot identify target as a stm32g0x");
+               return ERROR_FAIL;
+       }
+
+       retval = target_read_u16(target, flash_size_reg, flash_size_in_kb);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return retval;
+}
+
+static int stm32x_probe(struct flash_bank *bank)
+{
+       struct stm32g0x_flash_bank *stm32x_info = bank->driver_priv;
+       uint16_t flash_size_in_kb;
+       uint16_t max_flash_size_in_kb;
+       uint32_t device_id;
+       int page_size;
+       uint32_t base_address = 0x08000000;
+
+       stm32x_info->probed = 0;
+       stm32x_info->register_base = FLASH_REG_BASE;
+
+       /* default factory read protection level 0 */
+       stm32x_info->default_rdp = 0xAA;
+
+       /* read stm32 device id register */
+       int retval = stm32x_get_device_id(bank, &device_id);
+       if (retval != ERROR_OK)
+               return retval;
+
+       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
+
+       /* set page size, protection granularity and max flash size depending 
on family */
+       switch (device_id & 0xfff) {
+               case 0x460: /* stm32g07x */
+                       page_size = 2048;
+                       max_flash_size_in_kb = 128;
+                       break;
+               default:
+                       LOG_WARNING("Cannot identify target as a STM32 
family.");
+                       return ERROR_FAIL;
+       }
+
+       /* get flash size from target. */
+       retval = stm32x_get_flash_size(bank, &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;
+       }
+
+       /* if the user sets the size manually then ignore the probed value
+        * this allows us to work around devices that have a invalid flash size 
register value */
+       if (stm32x_info->user_bank_size) {
+               LOG_INFO("ignoring flash probed value, using configured bank 
size");
+               flash_size_in_kb = stm32x_info->user_bank_size / 1024;
+       }
+
+       LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
+
+       /* did we assign flash size? */
+       assert(flash_size_in_kb != 0xffff);
+
+       /* calculate numbers of pages */
+       int num_pages = flash_size_in_kb * 1024 / page_size;
+
+       /* check that calculation result makes sense */
+       assert(num_pages > 0);
+
+       if (bank->sectors) {
+               free(bank->sectors);
+               bank->sectors = NULL;
+       }
+
+       if (bank->prot_blocks) {
+               free(bank->prot_blocks);
+               bank->prot_blocks = NULL;
+       }
+
+       bank->base = base_address;
+       bank->size = (num_pages * page_size);
+
+       bank->num_sectors = num_pages;
+       bank->sectors = alloc_block_array(0, page_size, num_pages);
+       if (!bank->sectors)
+               return ERROR_FAIL;
+
+       bank->num_prot_blocks = num_pages;
+       bank->prot_blocks = alloc_block_array(0, page_size, num_pages);
+       if (!bank->prot_blocks)
+               return ERROR_FAIL;
+
+       stm32x_info->probed = 1;
+
+       return ERROR_OK;
+}
+
+static int stm32x_auto_probe(struct flash_bank *bank)
+{
+       struct stm32g0x_flash_bank *stm32x_info = bank->driver_priv;
+       if (stm32x_info->probed)
+               return ERROR_OK;
+       return stm32x_probe(bank);
+}
+
+#if 0
+COMMAND_HANDLER(stm32x_handle_part_id_command)
+{
+       return ERROR_OK;
+}
+#endif
+
+static const char *get_stm32g0_revision(uint16_t rev_id)
+{
+       const char *rev_str = NULL;
+
+       switch (rev_id) {
+               case 0x1000:
+                       rev_str = "A";
+                       break;
+               case 0x2000:
+                       rev_str = "B";
+                       break;
+       }
+       return rev_str;
+}
+
+static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       uint32_t dbgmcu_idcode;
+
+       /* read stm32 device id register */
+       int retval = stm32x_get_device_id(bank, &dbgmcu_idcode);
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint16_t device_id = dbgmcu_idcode & 0xfff;
+       uint16_t rev_id = dbgmcu_idcode >> 16;
+       const char *device_str;
+       const char *rev_str = NULL;
+
+       switch (device_id) {
+
+               case 0x460:
+                       device_str = "STM32G07x";
+                       rev_str = get_stm32g0_revision(rev_id);
+                       break;
+
+               default:
+                       snprintf(buf, buf_size, "Cannot identify target as a 
STM32G0\n");
+                       return ERROR_FAIL;
+       }
+
+       if (rev_str != NULL)
+               snprintf(buf, buf_size, "%s - Rev: %s", device_str, rev_str);
+       else
+               snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)", 
device_str, rev_id);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_lock_command)
+{
+       struct target *target = NULL;
+       struct stm32g0x_flash_bank *stm32x_info = 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;
+
+       stm32x_info = bank->driver_priv;
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* set readout protection */
+       stm32x_info->option_bytes.rdp = 0;
+
+       if (stm32x_write_options(bank) != ERROR_OK) {
+               command_print(CMD_CTX, "stm32x failed to lock device");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "stm32x locked");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_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 (stm32x_write_options(bank) != ERROR_OK) {
+               command_print(CMD_CTX, "stm32x failed to unlock device");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "stm32x unlocked.\n"
+                       "INFO: a reset or power cycle is required "
+                       "for the new settings to take effect.");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_options_read_command)
+{
+       struct target *target = NULL;
+       struct stm32g0x_flash_bank *stm32x_info = 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;
+
+       stm32x_info = bank->driver_priv;
+
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       struct stm32g0x_options options;
+
+       retval = target_read_u32(target, STM32_OB_USER_RDP, 
&(options.user_rdp));
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target, STM32_OB_WRP1A, &(options.wrp1a));
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(target, STM32_OB_WRP1B, &(options.wrp1b));
+       if (retval != ERROR_OK)
+               return retval;
+
+       command_print(CMD_CTX, "option byte register = 0x%" PRIx32 "", 
options.user_rdp);
+       command_print(CMD_CTX, "write protection register A = 0x%" PRIx32 "", 
options.wrp1a);
+       command_print(CMD_CTX, "write protection register B = 0x%" PRIx32 "", 
options.wrp1b);
+
+       command_print(CMD_CTX, "window watchdog: %sware",
+                       options.wwdg_sw ? "soft" : "hard");
+
+       command_print(CMD_CTX, "stop mode: %sreset generated upon entry",
+                       options.rst_stop ? "no " : "");
+
+       command_print(CMD_CTX, "standby mode: %sreset generated upon entry",
+                       options.rst_stdby ? "no " : "");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_options_write_command)
+{
+       struct target *target = NULL;
+       struct stm32g0x_flash_bank *stm32x_info = NULL;
+       struct stm32g0x_options options;
+       uint8_t bor_level;
+
+       if (CMD_ARGC < 2)
+               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;
+
+       stm32x_info = bank->driver_priv;
+       target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       retval = stm32x_read_options(bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       /* start with current options */
+       options = stm32x_info->option_bytes;
+
+       /* skip over flash bank */
+       CMD_ARGC--;
+       CMD_ARGV++;
+
+       while (CMD_ARGC) {
+               if (strcmp("BOREN", CMD_ARGV[0]) == 0)
+                       options.bor_en = 1;
+               else if (strcmp("NOBOREN", CMD_ARGV[0]) == 0)
+                       options.bor_en = 0;
+               else if (strcmp("BORFLEV", CMD_ARGV[0]) == 0) {
+                       if (CMD_ARGC < 2)
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], bor_level);
+                       options.borf_lev = bor_level;
+                       CMD_ARGC--;
+                       CMD_ARGV++;
+               } else if (strcmp("BORRLEV", CMD_ARGV[0]) == 0) {
+                       if (CMD_ARGC < 2)
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], bor_level);
+                       options.borr_lev = bor_level;
+                       CMD_ARGC--;
+                       CMD_ARGV++;
+               } else if (strcmp("NORSTSTOP", CMD_ARGV[0]) == 0)
+                       options.rst_stop = 1;
+               else if (strcmp("RSTSTOP", CMD_ARGV[0]) == 0)
+                       options.rst_stop = 0;
+               else if (strcmp("NORSTSTNDBY", CMD_ARGV[0]) == 0)
+                       options.rst_stdby = 1;
+               else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0)
+                       options.rst_stdby = 0;
+               else if (strcmp("NORSTSHDW", CMD_ARGV[0]) == 0)
+                       options.rst_shdw = 1;
+               else if (strcmp("RSTSHDW", CMD_ARGV[0]) == 0)
+                       options.rst_shdw = 0;
+               else if (strcmp("IDWGSW", CMD_ARGV[0]) == 0)
+                       options.iwdg_sw = 1;
+               else if (strcmp("IDWGHW", CMD_ARGV[0]) == 0)
+                       options.iwdg_sw = 0;
+               else if (strcmp("IDWGSTOP", CMD_ARGV[0]) == 0)
+                       options.iwdg_stop = 1;
+               else if (strcmp("NOIDWGSTOP", CMD_ARGV[0]) == 0)
+                       options.iwdg_stop = 0;
+               else if (strcmp("IDWGSTDBY", CMD_ARGV[0]) == 0)
+                       options.iwdg_stdby = 1;
+               else if (strcmp("NOIDWGSTDBY", CMD_ARGV[0]) == 0)
+                       options.iwdg_stdby = 0;
+               else if (strcmp("WWDGSW", CMD_ARGV[0]) == 0)
+                       options.wwdg_sw = 1;
+               else if (strcmp("WWDGHW", CMD_ARGV[0]) == 0)
+                       options.wwdg_sw = 0;
+               else if (strcmp("PARITY", CMD_ARGV[0]) == 0)
+                       options.ram_parity_check = 1;
+               else if (strcmp("NOPARITY", CMD_ARGV[0]) == 0)
+                       options.ram_parity_check = 0;
+               else if (strcmp("BOOTSEL", CMD_ARGV[0]) == 0)
+                       options.boot_sel = 1;
+               else if (strcmp("NOBOOTSEL", CMD_ARGV[0]) == 0)
+                       options.boot_sel = 0;
+               else if (strcmp("BOOT1", CMD_ARGV[0]) == 0)
+                       options.boot1 = 1;
+               else if (strcmp("NOBOOT1", CMD_ARGV[0]) == 0)
+                       options.boot1 = 0;
+               else if (strcmp("BOOT0", CMD_ARGV[0]) == 0)
+                       options.boot0 = 1;
+               else if (strcmp("NOBOOT0", CMD_ARGV[0]) == 0)
+                       options.boot0 = 0;
+               else
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               CMD_ARGC--;
+               CMD_ARGV++;
+       }
+
+       stm32x_info->option_bytes = options;
+
+       if (stm32x_write_options(bank) != ERROR_OK) {
+               command_print(CMD_CTX, "stm32x failed to write options");
+               return ERROR_OK;
+       }
+
+       command_print(CMD_CTX, "stm32x write options complete.\n"
+                       "INFO: %spower cycle is required "
+                       "for the new settings to take effect.",
+                       "'stm32g0x options_load' command or ");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_options_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;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* unlock flash registers */
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY1);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* unlock option flash registers */
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_OPTKEYR), OPTKEY1);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_OPTKEYR), OPTKEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* force re-load of option bytes - generates software reset */
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), STM32G0_FLASH_OBL_LAUNCH);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32gx_mass_erase(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+
+       /* unlock option flash registers */
+       int retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY1);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_KEYR), KEY2);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* mass erase flash memory */
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR),
+                       STM32G0_FLASH_MER | STM32G0_FLASH_STRT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, stm32x_get_flash_reg(bank, 
STM32G0_FLASH_CR), STM32G0_FLASH_LOCK);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+
+static int stm32x_mass_erase(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       int retval = stm32gx_mass_erase(bank);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_mass_erase_command)
+{
+       int i;
+
+       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;
+
+       retval = stm32x_mass_erase(bank);
+       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_CTX, "stm32x mass erase complete");
+       } else
+               command_print(CMD_CTX, "stm32x mass erase failed");
+
+       return retval;
+}
+
+static const struct command_registration stm32x_exec_command_handlers[] = {
+       {
+               .name = "lock",
+               .handler = stm32x_handle_lock_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Lock entire flash device.",
+       },
+       {
+               .name = "unlock",
+               .handler = stm32x_handle_unlock_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Unlock entire protected flash device.",
+       },
+       {
+               .name = "mass_erase",
+               .handler = stm32x_handle_mass_erase_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Erase entire flash device.",
+       },
+       {
+               .name = "options_read",
+               .handler = stm32x_handle_options_read_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Read and display device option bytes.",
+       },
+       {
+               .name = "options_write",
+               .handler = stm32x_handle_options_write_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id ('SWWDG'|'HWWDG') "
+                       "('RSTSTNDBY'|'NORSTSTNDBY') "
+                       "('RSTSTOP'|'NORSTSTOP') ('USEROPT' user_data)",
+               .help = "Replace bits in device option bytes.",
+       },
+       {
+               .name = "options_load",
+               .handler = stm32x_handle_options_load_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id",
+               .help = "Force re-load of device option bytes.",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration stm32x_command_handlers[] = {
+       {
+               .name = "stm32g0x",
+               .mode = COMMAND_ANY,
+               .help = "stm32g0x flash command group",
+               .usage = "",
+               .chain = stm32x_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct flash_driver stm32g0x_flash = {
+       .name = "stm32g0x",
+       .commands = stm32x_command_handlers,
+       .flash_bank_command = stm32x_flash_bank_command,
+       .erase = stm32x_erase,
+       .protect = stm32x_protect,
+       .write = stm32x_write,
+       .read = default_flash_read,
+       .probe = stm32x_probe,
+       .auto_probe = stm32x_auto_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = stm32x_protect_check,
+       .info = get_stm32x_info,
+       .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/tcl/board/st_nucleo_g0.cfg b/tcl/board/st_nucleo_g0.cfg
new file mode 100644
index 0000000..a5234a1
--- /dev/null
+++ b/tcl/board/st_nucleo_g0.cfg
@@ -0,0 +1,8 @@
+
+source [find interface/stlink.cfg]
+
+transport select hla_swd
+
+source [find target/stm32g0x.cfg]
+
+reset_config srst_only
diff --git a/tcl/target/stm32g0x.cfg b/tcl/target/stm32g0x.cfg
new file mode 100644
index 0000000..170cc7e
--- /dev/null
+++ b/tcl/target/stm32g0x.cfg
@@ -0,0 +1,92 @@
+# script for stm32g0x family
+
+#
+# stm32 devices support SWD transports only.
+#
+source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+       set _CHIPNAME $CHIPNAME
+} else {
+       set _CHIPNAME stm32g0x
+}
+
+set _ENDIAN little
+
+# Work-area is a space in RAM used for flash programming
+# By default use 4kB
+if { [info exists WORKAREASIZE] } {
+       set _WORKAREASIZE $WORKAREASIZE
+} else {
+       set _WORKAREASIZE 0x1000
+}
+
+# Allow overriding the Flash bank size
+if { [info exists FLASH_SIZE] } {
+       set _FLASH_SIZE $FLASH_SIZE
+} else {
+       # autodetect size
+       set _FLASH_SIZE 0
+}
+
+#jtag scan chain
+if { [info exists CPUTAPID] } {
+       set _CPUTAPID $CPUTAPID
+} else {
+       # See STM Document RM0091
+       # Section 29.5.3
+       set _CPUTAPID 0x0bc11477
+}
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 
$_CPUTAPID
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+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
+
+# flash size will be probed
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME stm32g0x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME
+
+# adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use 
F_JTAG = 1.8MHz
+adapter_khz 1800
+
+adapter_nsrst_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-start {
+       # Reset clock is HSI (16 MHz)
+       adapter_khz 1800
+}
+
+$_TARGETNAME configure -event examine-end {
+       # Enable debug during low power modes (uses more power)
+       mmw 0x40015804 0x00000006 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP
+
+       # Stop watchdog counters during halt
+       mmw 0x40015808 0x00001800 0 ;# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | 
DBG_WWDG_STOP
+}
+
+$_TARGETNAME configure -event reset-init {
+       # Configure PLL to boost clock to HSI x 4 (64 MHz)
+       mmw 0x40021000 0 0x01000000 ;# RCC_CR[31:16] &= ~PLLON
+       sleep 10                    ;# Wait for PLLRDY is cleared
+       mww 0x4002100C 0x30000802   ;# RCC_CFGR = PLLM[1] | PLLR[2] | PLLN[8] 
(1 * 8 / 2 = 4)
+       mmw 0x40021000 0x01000000 0 ;# RCC_CR[31:16] |= PLLON
+       mww 0x40022000 0x00040102   ;# FLASH_ACR = PRFTBE | LATENCY[2]
+       sleep 10                    ;# Wait for PLL to lock
+       mmw 0x40021008 0x00000002 0 ;# RCC_CFGR |= SW[1]
+
+       # Boost JTAG frequency
+       adapter_khz 4000
+}

-- 


_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to