stm32x: add support for STM32F20x
authorØyvind Harboe <oyvind.harboe@zylin.com>
Mon, 31 Jan 2011 11:32:07 +0000 (12:32 +0100)
committerØyvind Harboe <oyvind.harboe@zylin.com>
Fri, 4 Feb 2011 09:55:43 +0000 (10:55 +0100)
ready for wider testing and comments on basic erase + programming.

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
contrib/loaders/flash/stm32f2xxx.S [new file with mode: 0644]
src/flash/nor/Makefile.am
src/flash/nor/drivers.c
src/flash/nor/stm32f2xxx.c [new file with mode: 0644]

diff --git a/contrib/loaders/flash/stm32f2xxx.S b/contrib/loaders/flash/stm32f2xxx.S
new file mode 100644 (file)
index 0000000..49c821b
--- /dev/null
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   Copyright (C) 2011 Øyvind Harboe                                      *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+
+// Build : arm-eabi-gcc -c stm32f2xxx.S
+       .text
+       .syntax unified
+       .cpu cortex-m3
+       .thumb
+       .thumb_func
+       .global write
+
+/*
+       r0 - source address
+       r1 - target address
+       r2 - count (halfword-16bit)
+       r3 - result out
+       r4 - flash base
+*/
+
+#define STM32_FLASH_CR_OFFSET  0x10                    /* offset of CR register in FLASH struct */
+#define STM32_FLASH_SR_OFFSET  0x0c                    /* offset of CR register in FLASH struct */
+
+write:
+
+write_half_word:
+       ldr             r3, STM32_PROG16
+       str             r3, [r4, #STM32_FLASH_CR_OFFSET]
+       ldrh    r3, [r0], #0x02                                         /* read one half-word from src, increment ptr */
+       strh    r3, [r1], #0x02                                         /* write one half-word from src, increment ptr */
+busy:
+       ldr     r3, [r4, #STM32_FLASH_SR_OFFSET]
+       tst     r3, #0x10000                                            /* BSY (bit0) == 1 => operation in progress */
+       beq     busy                                                            /* wait more... */
+       tst             r3, #0xf0                                                       /* PGSERR | PGPERR | PGAERR | WRPERR */
+       bne             exit                                                            /* fail... */
+       subs    r2, r2, #0x01                                           /* decrement counter */
+       bne             write_half_word                                         /* write next half-word if anything left */
+exit:
+       bkpt    #0x00
+
+
+STM32_PROG16: .word 0x101                                              /* PG | PSIZE_16*/
index 42707e007ff7ccff69eec86cbd0c1122998b33f5..95bd313d3d5042c53065807ab751d6d267a22c6d 100644 (file)
@@ -25,6 +25,7 @@ NOR_DRIVERS = \
        stmsmi.c \
        stellaris.c \
        stm32x.c \
+       stm32f2xxx.c \
        str7x.c \
        str9x.c \
        str9xpec.c \
index f4479f6c56348fee0717b6ea04f1c6a143f4bce8..5489419f9c8a32b2d79710e46407f6b7f8179f1e 100644 (file)
@@ -33,6 +33,7 @@ extern struct flash_driver aduc702x_flash;
 extern struct flash_driver stellaris_flash;
 extern struct flash_driver str9xpec_flash;
 extern struct flash_driver stm32x_flash;
+extern struct flash_driver stm32xf2xxx_flash;
 extern struct flash_driver tms470_flash;
 extern struct flash_driver ecosflash_flash;
 extern struct flash_driver ocl_flash;
@@ -60,6 +61,7 @@ static struct flash_driver *flash_drivers[] = {
        &stellaris_flash,
        &str9xpec_flash,
        &stm32x_flash,
+       &stm32xf2xxx_flash,
        &tms470_flash,
        &ecosflash_flash,
        &ocl_flash,
diff --git a/src/flash/nor/stm32f2xxx.c b/src/flash/nor/stm32f2xxx.c
new file mode 100644 (file)
index 0000000..2ccf531
--- /dev/null
@@ -0,0 +1,712 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
+ *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
+ *   Copyright (C) 2011 Øyvind Harboe                                      *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+/* Regarding performance:
+ *
+ * Short story - it might be best to leave the performance at
+ * current levels.
+ *
+ * You may see a jump in speed if you change to using
+ * 32bit words for the block programming.
+ *
+ * Its a shame you cannot use the double word as its
+ * even faster - but you require external VPP for that mode.
+ *
+ * Having said all that 16bit writes give us the widest vdd
+ * operating range, so may be worth adding a note to that effect.
+ *
+ */
+
+
+/* Danger!!!! The STM32F1xxxx and STM32F2xxxx series actually have
+ * quite different flash controllers.
+ *
+ * What's more scary is that the names of the registers and their
+ * addresses are the same, but the actual bits and what they do are
+ * can be very different.
+ *
+ * To reduce testing complexity and dangers of regressions,
+ * a seperate file is used for stm32fx2222.
+ *
+ * 1mByte part with 4 x 16, 1 x 64, 7 x 128kBytes sectors
+ *
+ * What's the protection page size???
+ *
+ * Tested with STM3220F-EVAL board.
+ *
+ * STM32F21xx series for reference.
+ *
+ * RM0033
+ * http://www.st.com/internet/mcu/product/250192.jsp
+ *
+ * PM0059
+ * www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/PROGRAMMING_MANUAL/CD00233952.pdf
+ *
+ * STM32F1xxx series - notice that this code was copy, pasted and knocked
+ * into a stm32f2xxx driver, so in case something has been converted or
+ * bugs haven't been fixed, here are the original manuals:
+ *
+ * RM0008 - Reference manual
+ *
+ * RM0042, the Flash programming manual for low-, medium- high-density and
+ * connectivity line STM32F10xxx devices
+ *
+ * PM0068, the Flash programming manual for XL-density STM32F10xxx devices.
+ *
+ */
+
+ // Erase time can be as high as 1000ms, 10x this and it's toast...
+#define FLASH_ERASE_TIMEOUT 10000
+#define FLASH_WRITE_TIMEOUT 5
+
+
+#define STM32_FLASH_BASE       0x40023c00
+#define STM32_FLASH_ACR                0x40023c00
+#define STM32_FLASH_KEYR       0x40023c04
+#define STM32_FLASH_OPTKEYR    0x40023c08
+#define STM32_FLASH_SR         0x40023c0C
+#define STM32_FLASH_CR         0x40023c10
+#define STM32_FLASH_OPTCR      0x40023c14
+#define STM32_FLASH_OBR                0x40023c1C
+
+
+
+/* option byte location */
+
+#define STM32_OB_RDP           0x1FFFF800
+#define STM32_OB_USER          0x1FFFF802
+#define STM32_OB_DATA0         0x1FFFF804
+#define STM32_OB_DATA1         0x1FFFF806
+#define STM32_OB_WRP0          0x1FFFF808
+#define STM32_OB_WRP1          0x1FFFF80A
+#define STM32_OB_WRP2          0x1FFFF80C
+#define STM32_OB_WRP3          0x1FFFF80E
+
+/* FLASH_CR register bits */
+
+#define FLASH_PG               (1 << 0)
+#define FLASH_SER              (1 << 1)
+#define FLASH_MER              (1 << 2)
+#define FLASH_STRT             (1 << 16)
+#define FLASH_PSIZE_8  (0 << 8)
+#define FLASH_PSIZE_16 (1 << 8)
+#define FLASH_PSIZE_32 (2 << 8)
+#define FLASH_PSIZE_64 (3 << 8)
+#define FLASH_SNB(a)   ((a) << 3)
+#define FLASH_LOCK             (1 << 31)
+
+/* FLASH_SR register bits */
+
+#define FLASH_BSY              (1 << 16)
+#define FLASH_PGSERR   (1 << 7) // Programming sequence error
+#define FLASH_PGPERR   (1 << 6) // Programming parallelism error
+#define FLASH_PGAERR   (1 << 5) // Programming alignment error
+#define FLASH_WRPERR   (1 << 4) // Write protection error
+#define FLASH_OPERR            (1 << 1) // Operation error
+
+#define FLASH_ERROR (FLASH_PGSERR | FLASH_PGPERR | FLASH_PGAERR| FLASH_WRPERR| FLASH_OPERR)
+
+/* 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
+#define OPT_BFB2               5       /* dual flash bank only */
+
+/* register unlock keys */
+
+#define KEY1                   0x45670123
+#define KEY2                   0xCDEF89AB
+
+struct stm32x_flash_bank
+{
+       struct working_area *write_algorithm;
+       int probed;
+};
+
+
+/* flash bank stm32x <base> <size> 0 0 <target#>
+ */
+FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
+{
+       struct stm32x_flash_bank *stm32x_info;
+
+       if (CMD_ARGC < 6)
+       {
+               LOG_WARNING("incomplete flash_bank stm32x configuration");
+               return ERROR_FLASH_BANK_INVALID;
+       }
+
+       stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
+       bank->driver_priv = stm32x_info;
+
+       stm32x_info->write_algorithm = NULL;
+       stm32x_info->probed = 0;
+
+       return ERROR_OK;
+}
+
+static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg)
+{
+       return reg;
+}
+
+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, STM32_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 & FLASH_BSY) == 0)
+                       break;
+               if (timeout-- <= 0)
+               {
+                       LOG_ERROR("timed out waiting for flash");
+                       return ERROR_FAIL;
+               }
+               alive_sleep(1);
+       }
+
+
+       if (status & FLASH_WRPERR)
+       {
+               LOG_ERROR("stm32x device protected");
+               retval = ERROR_FAIL;
+       }
+
+       /* Clear but report errors */
+       if (status & FLASH_ERROR)
+       {
+               /* If this operation fails, we ignore it and report the original
+                * retval
+                */
+               target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR),
+                               status & FLASH_ERROR);
+       }
+       return retval;
+}
+
+static int stm32x_unlock_reg(struct target *target)
+{
+       /* unlock flash registers */
+       int retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2);
+       if (retval != ERROR_OK)
+               return retval;
+       return ERROR_OK;
+}
+
+static int stm32x_protect_check(struct flash_bank *bank)
+{
+       return ERROR_OK;
+}
+
+static int stm32x_erase(struct flash_bank *bank, int first, int last)
+{
+       struct target *target = bank->target;
+       int i;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       int retval;
+       retval = stm32x_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 SER bit and select the sector (out of the 12 sectors in the main memory block)
+         you wish to erase (SNB) in the FLASH_CR register
+       3. Set the STRT bit in the FLASH_CR register
+       4. Wait for the BSY bit to be cleared
+        */
+
+       for (i = first; i <= last; i++)
+       {
+               retval = target_write_u32(target,
+                               stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(i) | FLASH_STRT);
+               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, STM32_FLASH_CR), FLASH_LOCK);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       return ERROR_OK;
+}
+
+static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
+               uint32_t offset, uint32_t count)
+{
+       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t buffer_size = 16384;
+       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;
+
+       /* see contib/loaders/flash/stm32x.s for src */
+
+       static const uint16_t stm32x_flash_write_code_16[] = {
+//     00000000 <write>:
+          0x4b07, //           ldr     r3, [pc, #28]   (20 <STM32_PROG16>)
+          0x6123,  //          str     r3, [r4, #16]
+       0xf830, 0x3b02,         //ldrh.w        r3, [r0], #2
+       0xf821, 0x3b02,         //strh.w        r3, [r1], #2
+
+       //0000000c <busy>:
+       0x68e3,         //ldr   r3, [r4, #12]
+0xf413, 0x3f80, //     tst.w   r3, #65536      ; 0x10000
+0xd0fb,        //beq.n c <busy>
+0xf013, 0x0ff0,        //tst.w r3, #240        ; 0xf0
+0xd101,        //bne.n 1e <exit>
+0x3a01,        //subs  r2, #1
+0xd1f0,        //bne.n 0 <write>
+                               //0000001e <exit>:
+       0xbe00, //              bkpt    0x0000
+
+       //00000020 <STM32_PROG16>:
+       0x0101, 0x0000, //      .word   0x00000101
+
+       };
+
+       // Flip endian
+       uint8_t stm32x_flash_write_code[sizeof(stm32x_flash_write_code_16)*2];
+       for (unsigned i = 0; i < sizeof(stm32x_flash_write_code_16) / 2; i++)
+       {
+               stm32x_flash_write_code[i*2 + 0] = stm32x_flash_write_code_16[i] & 0xff;
+               stm32x_flash_write_code[i*2 + 1] = (stm32x_flash_write_code_16[i] >> 8) & 0xff;
+       }
+
+       if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
+                       &stm32x_info->write_algorithm) != ERROR_OK)
+       {
+               LOG_WARNING("no working area available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       };
+
+       if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address,
+                       sizeof(stm32x_flash_write_code),
+                       (uint8_t*)stm32x_flash_write_code)) != ERROR_OK)
+               return retval;
+
+       /* memory buffer */
+       while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
+       {
+               buffer_size /= 2;
+               if (buffer_size <= 256)
+               {
+                       /* if we already allocated the writing code, but failed to get a
+                        * buffer, free the algorithm */
+                       if (stm32x_info->write_algorithm)
+                               target_free_working_area(target, stm32x_info->write_algorithm);
+
+                       LOG_WARNING("no large enough working area available, can't do block memory writes");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+       };
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.core_mode = ARMV7M_MODE_ANY;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT);
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
+
+       while (count > 0)
+       {
+               uint32_t thisrun_count = (count > (buffer_size / 2)) ?
+                               (buffer_size / 2) : count;
+
+               if ((retval = target_write_buffer(target, source->address,
+                               thisrun_count * 2, buffer)) != ERROR_OK)
+                       break;
+
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               buf_set_u32(reg_params[1].value, 0, 32, address);
+               buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
+               // R3 is a return value only
+               buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE);
+
+               if ((retval = target_run_algorithm(target, 0, NULL,
+                               sizeof(reg_params) / sizeof(*reg_params),
+                               reg_params,
+                               stm32x_info->write_algorithm->address,
+                               0,
+                               10000, &armv7m_info)) != ERROR_OK)
+               {
+                       LOG_ERROR("error executing stm32x flash write algorithm");
+                       break;
+               }
+
+               uint32_t error = buf_get_u32(reg_params[3].value, 0, 32) & FLASH_ERROR;
+
+               if (error & FLASH_WRPERR)
+               {
+                       LOG_ERROR("flash memory write protected");
+               }
+
+               if (error != 0)
+               {
+                       LOG_ERROR("flash write failed = %08x", error);
+                       /* Clear but report errors */
+                       target_write_u32(target, STM32_FLASH_SR, error);
+                       retval = ERROR_FAIL;
+                       break;
+               }
+
+               buffer += thisrun_count * 2;
+               address += thisrun_count * 2;
+               count -= thisrun_count;
+       }
+
+       target_free_working_area(target, source);
+       target_free_working_area(target, stm32x_info->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 stm32x_write(struct flash_bank *bank, uint8_t *buffer,
+               uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       uint32_t words_remaining = (count / 2);
+       uint32_t bytes_remaining = (count & 0x00000001);
+       uint32_t address = bank->base + offset;
+       uint32_t bytes_written = 0;
+       int retval;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (offset & 0x1)
+       {
+               LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       retval = stm32x_unlock_reg(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* multiple half words (2-byte) to be programmed? */
+       if (words_remaining > 0)
+       {
+               /* try using a block write */
+               if ((retval = stm32x_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)
+               {
+                       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+                       {
+                               /* if block write failed (no sufficient working area),
+                                * we use normal (slow) single dword accesses */
+                               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+                       }
+               }
+               else
+               {
+                       buffer += words_remaining * 2;
+                       address += words_remaining * 2;
+                       words_remaining = 0;
+               }
+       }
+
+       if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
+               return retval;
+
+       /*
+       Standard programming
+       The Flash memory programming sequence is as follows:
+       1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the
+         FLASH_SR register.
+       2. Set the PG bit in the FLASH_CR register
+       3. Perform the data write operation(s) to the desired memory address (inside main
+         memory block or OTP area):
+       – – Half-word access in case of x16 parallelism
+       – Word access in case of x32 parallelism
+       –
+       4.
+       Byte access in case of x8 parallelism
+       Double word access in case of x64 parallelism
+       Wait for the BSY bit to be cleared
+       */
+       while (words_remaining > 0)
+       {
+               uint16_t value;
+               memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
+
+               retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR),
+                               FLASH_PG | FLASH_PSIZE_16);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = target_write_u16(target, address, value);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               bytes_written += 2;
+               words_remaining--;
+               address += 2;
+       }
+
+       if (bytes_remaining)
+       {
+               retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR),
+                               FLASH_PG | FLASH_PSIZE_8);
+               if (retval != ERROR_OK)
+                       return retval;
+               retval = target_write_u8(target, address, buffer[bytes_written]);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
+}
+
+static void setup_sector(struct flash_bank *bank, int start, int num, int size)
+{
+       for (int i = start; i < (start + num) ; i++)
+       {
+               bank->sectors[i].offset = bank->size;
+               bank->sectors[i].size = size;
+               bank->size += bank->sectors[i].size;
+       }
+}
+
+static int stm32x_probe(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+       int i;
+       uint16_t num_pages;
+       uint32_t device_id;
+       uint32_t base_address = 0x08000000;
+
+       stm32x_info->probed = 0;
+
+       /* read stm32 device id register */
+       int retval = target_read_u32(target, 0xE0042000, &device_id);
+       if (retval != ERROR_OK)
+               return retval;
+       LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
+
+       /* get flash size from target. */
+       retval = target_read_u16(target, 0x1FFFF7E0, &num_pages);
+       if (retval != ERROR_OK)
+       {
+               LOG_WARNING("failed reading flash size, default to max target family");
+               /* failed reading flash size, default to max target family */
+               num_pages = 0xffff;
+       }
+
+       if ((device_id & 0x7ff) != 0x411)
+       {
+               LOG_WARNING("Cannot identify target as a STM32 family, try the other STM32 drivers.");
+               return ERROR_FAIL;
+       }
+
+       /* sectors sizes vary, handle this in a different code path
+        * than the rest.
+        */
+       // Uhhh.... what to use here?
+
+       /* calculate numbers of pages*/
+       num_pages = 4 + 1 + 7;
+
+       if (bank->sectors)
+       {
+               free(bank->sectors);
+               bank->sectors = NULL;
+       }
+
+       bank->base = base_address;
+       bank->num_sectors = num_pages;
+       bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
+
+       bank->size = 0;
+       setup_sector(bank, 0, 4, 16 * 1024);
+       setup_sector(bank, 4, 1, 64 * 1024);
+       setup_sector(bank, 4+1, 7, 128 * 1024);
+
+       for (i = 0; i < num_pages; i++)
+       {
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 0;
+       }
+
+       LOG_INFO("flash size = %dkBytes", bank->size / 1024);
+
+       stm32x_info->probed = 1;
+
+       return ERROR_OK;
+}
+
+static int stm32x_auto_probe(struct flash_bank *bank)
+{
+       struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+       if (stm32x_info->probed)
+               return ERROR_OK;
+       return stm32x_probe(bank);
+}
+
+static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct target *target = bank->target;
+       uint32_t device_id;
+       int printed;
+
+       /* read stm32 device id register */
+       int retval = target_read_u32(target, 0xE0042000, &device_id);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((device_id & 0x7ff) == 0x411)
+       {
+               printed = snprintf(buf, buf_size, "stm32x (1mByte part) - Rev: ");
+               buf += printed;
+               buf_size -= printed;
+
+               switch (device_id >> 16)
+               {
+                       case 0x1000:
+                               snprintf(buf, buf_size, "A");
+                               break;
+
+                       case 0x2000:
+                               snprintf(buf, buf_size, "B");
+                               break;
+
+                       case 0x1001:
+                               snprintf(buf, buf_size, "Z");
+                               break;
+
+                       default:
+                               snprintf(buf, buf_size, "unknown");
+                               break;
+               }
+       }
+       else
+       {
+               snprintf(buf, buf_size, "Cannot identify target as a stm32x\n");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration stm32x_exec_command_handlers[] = {
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration stm32x_command_handlers[] = {
+       {
+               .name = "stm32f2xxx",
+               .mode = COMMAND_ANY,
+               .help = "stm32f2xxx flash command group",
+               .chain = stm32x_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver stm32xf2xxx_flash = {
+       .name = "stm32f2xxx",
+       .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_mem_blank_check,
+       .protect_check = stm32x_protect_check,
+       .info = get_stm32x_info,
+};

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)