Added support for STMicroelectronics BlueNRG-1 and BlueNRG-2 SoC 26/4226/9
authorMichele Sardo <msmttchr@gmail.com>
Tue, 12 Sep 2017 06:51:29 +0000 (08:51 +0200)
committerTomas Vanek <vanekt@fbl.cz>
Wed, 7 Mar 2018 23:40:55 +0000 (23:40 +0000)
Added configuration files and flash loaders.

Change-Id: I768eb3626f4e0eadb206bef90a867cc146fe8c75
Signed-off-by: Michele Sardo <msmttchr@gmail.com>
Reviewed-on: http://openocd.zylin.com/4226
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
contrib/loaders/flash/bluenrg-x/Makefile [new file with mode: 0644]
contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c [new file with mode: 0644]
contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc [new file with mode: 0644]
doc/openocd.texi
src/flash/nor/Makefile.am
src/flash/nor/bluenrg-x.c [new file with mode: 0644]
src/flash/nor/drivers.c
tcl/board/steval-idb007v1.cfg [new file with mode: 0644]
tcl/board/steval-idb008v1.cfg [new file with mode: 0644]
tcl/target/bluenrg-x.cfg [new file with mode: 0644]

diff --git a/contrib/loaders/flash/bluenrg-x/Makefile b/contrib/loaders/flash/bluenrg-x/Makefile
new file mode 100644 (file)
index 0000000..1a5cfc0
--- /dev/null
@@ -0,0 +1,27 @@
+BIN2C = ../../../../src/helper/bin2char.sh
+
+CROSS_COMPILE ?= arm-none-eabi-
+
+CC=$(CROSS_COMPILE)gcc
+OBJCOPY=$(CROSS_COMPILE)objcopy
+OBJDUMP=$(CROSS_COMPILE)objdump
+
+CFLAGS =  -c -mthumb -mcpu=cortex-m0 -O3 -g
+
+all: bluenrg-x_write.inc
+
+.PHONY: clean
+
+.INTERMEDIATE: bluenrg-x_write.o
+
+%.o: %.c
+       $(CC) $(CFLAGS) -Wall -Wextra -Wa,-adhln=$*.lst $< -o $@
+
+%.bin: %.o
+       $(OBJCOPY) -Obinary $< $@
+
+%.inc: %.bin
+       $(BIN2C) < $< > $@
+
+clean:
+       -rm -f *.o *.lst *.bin *.inc
diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c
new file mode 100644 (file)
index 0000000..3dd17b2
--- /dev/null
@@ -0,0 +1,132 @@
+/* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */
+/* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */
+
+#include <stdint.h>
+
+/* Status Values ----------------------------------------------------------*/
+#define SUCCESS             0
+#define ERR_UNALIGNED       1
+#define ERR_INVALID_ADDRESS 2
+#define ERR_INVALID_TYPE    3
+#define ERR_WRITE_PROTECTED 4
+#define ERR_WRITE_FAILED    5
+#define ERR_ERASE_REQUIRED  6
+#define ERR_VERIFY_FAILED   7
+
+/* Flash Controller defines ---------------------------------------------------*/
+#define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000)
+#define FLASH_REG_CONFIG  ((volatile uint32_t *)0x40100004)
+#define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008)
+#define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4010000C)
+#define FLASH_REG_IRQRAW  ((volatile uint32_t *)0x40100010)
+#define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018)
+#define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C)
+#define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020)
+#define FLASH_REG_DATA0    ((volatile uint32_t *)0x40100040)
+#define FLASH_REG_DATA1    ((volatile uint32_t *)0x40100044)
+#define FLASH_REG_DATA2    ((volatile uint32_t *)0x40100048)
+#define FLASH_REG_DATA3    ((volatile uint32_t *)0x4010004C)
+#define FLASH_SIZE_REG 0x40100014
+
+#define MFB_MASS_ERASE 0x01
+#define MFB_PAGE_ERASE 0x02
+
+#define DO_ERASE  0x0100
+#define DO_VERIFY 0x0200
+#define FLASH_CMD_ERASE_PAGE 0x11
+#define FLASH_CMD_MASSERASE  0x22
+#define FLASH_CMD_WRITE      0x33
+#define FLASH_CMD_BURSTWRITE 0xCC
+#define FLASH_INT_CMDDONE    0x01
+#define MFB_BOTTOM          (0x10040000)
+#define MFB_SIZE_B          ((16 * (((*(uint32_t *) FLASH_SIZE_REG) + 1) >> 12)) * 1024)
+#define MFB_SIZE_W          (MFB_SIZE_B/4)
+#define MFB_TOP             (MFB_BOTTOM+MFB_SIZE_B-1)
+#define MFB_PAGE_SIZE_B     (2048)
+#define MFB_PAGE_SIZE_W     (MFB_PAGE_SIZE_B/4)
+
+#define AREA_ERROR 0x01
+#define AREA_MFB   0x04
+
+#define FLASH_WORD_LEN       4
+
+typedef struct {
+       volatile uint8_t *wp;
+       uint8_t *rp;
+} work_area_t;
+
+/* Flash Commands --------------------------------------------------------*/
+static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data,
+                                                                uint32_t writeLength)
+{
+       uint32_t index, flash_word[4];
+       uint8_t i;
+
+       *FLASH_REG_IRQMASK = 0;
+       for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) {
+               for (i = 0; i < 4; i++)
+                       flash_word[i] = (*(uint32_t *) (*data + i*4));
+
+               /* Clear the IRQ flags */
+               *FLASH_REG_IRQRAW = 0x0000003F;
+               /* Load the flash address to write */
+               *FLASH_REG_ADDRESS = (uint16_t)((address + index) >> 2);
+               /* Prepare and load the data to flash */
+               *FLASH_REG_DATA0 = flash_word[0];
+               *FLASH_REG_DATA1 = flash_word[1];
+               *FLASH_REG_DATA2 = flash_word[2];
+               *FLASH_REG_DATA3 = flash_word[3];
+               /* Flash write command */
+               *FLASH_REG_COMMAND = FLASH_CMD_BURSTWRITE;
+               /* Wait the end of the flash write command */
+               while ((*FLASH_REG_IRQRAW & FLASH_INT_CMDDONE) == 0)
+                       ;
+               *data += (FLASH_WORD_LEN * 4);
+       }
+
+       return SUCCESS;
+}
+
+__attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p,
+                                                           uint8_t *fifo_end,
+                                                           uint8_t *target_address,
+                                                           uint32_t count)
+{
+       uint32_t retval;
+       volatile work_area_t *work_area = (work_area_t *) work_area_p;
+       uint8_t *fifo_start = (uint8_t *) work_area->rp;
+
+       while (count) {
+               volatile int32_t fifo_linear_size;
+
+               /* Wait for some data in the FIFO */
+               while (work_area->rp == work_area->wp)
+                       ;
+               if (work_area->wp == 0) {
+                       /* Aborted by other party */
+                       break;
+               }
+               if (work_area->rp > work_area->wp) {
+                       fifo_linear_size = fifo_end-work_area->rp;
+               } else {
+                       fifo_linear_size = (work_area->wp - work_area->rp);
+                       if (fifo_linear_size < 0)
+                               fifo_linear_size = 0;
+               }
+               if (fifo_linear_size < 16) {
+                       /* We should never get here */
+                       continue;
+               }
+
+               retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size);
+               if (retval != SUCCESS) {
+                       work_area->rp = (uint8_t *)retval;
+                       break;
+               }
+               target_address += fifo_linear_size;
+               if (work_area->rp >= fifo_end)
+                       work_area->rp = fifo_start;
+               count -= fifo_linear_size;
+       }
+       __asm("bkpt 0");
+}
diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc
new file mode 100644 (file)
index 0000000..47f3312
--- /dev/null
@@ -0,0 +1,18 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x05,0x93,0x43,0x68,0x05,0x00,0x07,0x93,0x05,0x9b,0x06,0x91,0x03,0x92,0x35,0x4c,
+0x00,0x2b,0x5c,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0,0x2b,0x68,0x00,0x2b,
+0x55,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x52,0xd9,0x6b,0x68,0x06,0x9a,0xd3,0x1a,
+0x09,0x93,0x09,0x9b,0x0f,0x2b,0xed,0xdd,0x00,0x21,0x09,0x9b,0x04,0x93,0x1a,0x1e,
+0x29,0x4b,0x19,0x60,0x32,0xd0,0x29,0x4b,0x00,0x20,0x98,0x46,0x28,0x4b,0x6a,0x68,
+0x9c,0x46,0x28,0x4b,0x28,0x4e,0x9b,0x46,0x28,0x4b,0x9a,0x46,0x28,0x4b,0x99,0x46,
+0x01,0x23,0x51,0x68,0x17,0x68,0x00,0x91,0x91,0x68,0x01,0x91,0xd1,0x68,0x02,0x91,
+0x3f,0x21,0x21,0x60,0x03,0x99,0x09,0x18,0x89,0x03,0x09,0x0c,0x31,0x60,0x41,0x46,
+0x0f,0x60,0x67,0x46,0x00,0x99,0x39,0x60,0x5f,0x46,0x01,0x99,0x39,0x60,0x57,0x46,
+0x02,0x99,0x39,0x60,0x49,0x46,0xcc,0x27,0x0f,0x60,0x21,0x68,0x0b,0x42,0xfc,0xd0,
+0x04,0x99,0x10,0x32,0x10,0x30,0x6a,0x60,0x81,0x42,0xda,0xd8,0x03,0x9a,0x09,0x9b,
+0x94,0x46,0x9c,0x44,0x63,0x46,0x06,0x9a,0x03,0x93,0x6b,0x68,0x9a,0x42,0x01,0xd8,
+0x07,0x9b,0x6b,0x60,0x05,0x9a,0x09,0x9b,0xd3,0x1a,0x05,0x93,0xa2,0xd1,0x00,0xbe,
+0x2b,0x68,0x6a,0x68,0x9b,0x1a,0x09,0x93,0x09,0x9b,0x00,0x2b,0xa9,0xda,0x00,0x23,
+0x09,0x93,0xa6,0xe7,0x10,0x00,0x10,0x40,0x0c,0x00,0x10,0x40,0x40,0x00,0x10,0x40,
+0x44,0x00,0x10,0x40,0x48,0x00,0x10,0x40,0x18,0x00,0x10,0x40,0x4c,0x00,0x10,0x40,
+0x00,0x00,0x10,0x40,
index 9126003b8be5c02725810cfff4dca7d56d4dbe3e..2f01153f84c641625539270db8dc98d8cdbe538c 100644 (file)
@@ -5344,6 +5344,30 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory.
 @comment - defines mass_erase ... pointless given flash_erase_address
 @end deffn
 
+@deffn {Flash Driver} bluenrg-x
+STMicroelectronics BlueNRG-1 and BlueNRG-2 Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0 core and internal flash memory.
+The driver automatically recognizes these chips using
+the chip identification registers, and autoconfigures itself.
+
+@example
+flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME
+@end example
+
+Note that when users ask to erase all the sectors of the flash, a mass erase command is used which is faster than erasing
+each single sector one by one.
+
+@example
+flash erase_sector 0 0 79 # It will perform a mass erase on BlueNRG-1
+@end example
+
+@example
+flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-2
+@end example
+
+Triggering a mass erase is also useful when users want to disable readout protection.
+
+@end deffn
+
 @deffn {Flash Driver} efm32
 All members of the EFM32 microcontroller family from Energy Micro include
 internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes
index 4b74a468254224f595caddb962604b5849bcce34..b9353642feefadfd5cd6e9faab3b83e1abfaeaa1 100644 (file)
@@ -18,6 +18,7 @@ NOR_DRIVERS = \
        %D%/ath79.c \
        %D%/atsamv.c \
        %D%/avrf.c \
+       %D%/bluenrg-x.c \
        %D%/cfi.c \
        %D%/dsp5680xx_flash.c \
        %D%/efm32.c \
diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c
new file mode 100644 (file)
index 0000000..c4a8080
--- /dev/null
@@ -0,0 +1,549 @@
+/***************************************************************************
+ *   Copyright (C) 2017 by Michele Sardo                                   *
+ *   msmttchr@gmail.com                                                    *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+#include <target/cortex_m.h>
+#include "imp.h"
+
+#define FLASH_SIZE_REG       (0x40100014)
+#define DIE_ID_REG           (0x4090001C)
+#define JTAG_IDCODE_REG      (0x40900028)
+#define BLUENRG2_IDCODE      (0x0200A041)
+#define FLASH_BASE           (0x10040000)
+#define FLASH_PAGE_SIZE      (2048)
+#define FLASH_REG_COMMAND    (0x40100000)
+#define FLASH_REG_IRQRAW     (0x40100010)
+#define FLASH_REG_ADDRESS    (0x40100018)
+#define FLASH_REG_DATA       (0x40100040)
+#define FLASH_CMD_ERASE_PAGE 0x11
+#define FLASH_CMD_MASSERASE  0x22
+#define FLASH_CMD_WRITE      0x33
+#define FLASH_CMD_BURSTWRITE 0xCC
+#define FLASH_INT_CMDDONE    0x01
+#define FLASH_WORD_LEN       4
+
+struct bluenrgx_flash_bank {
+       int probed;
+       uint32_t idcode;
+       uint32_t die_id;
+};
+
+static int bluenrgx_protect_check(struct flash_bank *bank)
+{
+       /* Nothing to do. Protection is only handled in SW. */
+       return ERROR_OK;
+}
+
+/* flash_bank bluenrg-x 0 0 0 0 <target#> */
+FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
+{
+       struct bluenrgx_flash_bank *bluenrgx_info;
+       /* Create the bank structure */
+       bluenrgx_info = calloc(1, sizeof(*bluenrgx_info));
+
+       /* Check allocation */
+       if (bluenrgx_info == NULL) {
+               LOG_ERROR("failed to allocate bank structure");
+               return ERROR_FAIL;
+       }
+
+       bank->driver_priv = bluenrgx_info;
+
+       bluenrgx_info->probed = 0;
+
+       if (CMD_ARGC < 6)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       return ERROR_OK;
+}
+
+static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
+{
+       int retval = ERROR_OK;
+       struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
+       int num_sectors = (last - first + 1);
+       int mass_erase = (num_sectors == bank->num_sectors);
+       struct target *target = bank->target;
+       uint32_t address, command;
+
+       /* check preconditions */
+       if (bluenrgx_info->probed == 0)
+               return ERROR_FLASH_BANK_NOT_PROBED;
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+       /* Disable blue module */
+       if (target_write_u32(target, 0x200000c0, 0) != ERROR_OK) {
+               LOG_ERROR("Blue disable failed");
+               return ERROR_FAIL;
+       }
+
+       if (mass_erase) {
+               command = FLASH_CMD_MASSERASE;
+               address = bank->base;
+               if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
+                       LOG_ERROR("Register write failed");
+                       return ERROR_FAIL;
+               }
+
+               if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
+                       LOG_ERROR("Register write failed");
+                       return ERROR_FAIL;
+               }
+
+               if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
+                       LOG_ERROR("Register write failed");
+                       return ERROR_FAIL;
+               }
+
+               for (int i = 0; i < 100; i++) {
+                       uint32_t value;
+                       if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
+                               LOG_ERROR("Register write failed");
+                               return ERROR_FAIL;
+                       }
+                       if (value & FLASH_INT_CMDDONE)
+                               break;
+                       if (i == 99) {
+                               LOG_ERROR("Mass erase command failed (timeout)");
+                               retval = ERROR_FAIL;
+                       }
+               }
+
+       } else {
+               command = FLASH_CMD_ERASE_PAGE;
+               for (int i = first; i <= last; i++) {
+                       address = bank->base+i*FLASH_PAGE_SIZE;
+
+                       if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
+                               LOG_ERROR("Register write failed");
+                               return ERROR_FAIL;
+                       }
+
+                       if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) {
+                               LOG_ERROR("Register write failed");
+                               return ERROR_FAIL;
+                       }
+
+                       if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
+                               LOG_ERROR("Failed");
+                               return ERROR_FAIL;
+                       }
+
+                       for (int j = 0; j < 100; j++) {
+                               uint32_t value;
+                               if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
+                                       LOG_ERROR("Register write failed");
+                                       return ERROR_FAIL;
+                               }
+                               if (value & FLASH_INT_CMDDONE)
+                                       break;
+                               if (j == 99) {
+                                       LOG_ERROR("Erase command failed (timeout)");
+                                       retval = ERROR_FAIL;
+                               }
+                       }
+               }
+       }
+
+       return retval;
+
+}
+
+static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last)
+{
+       /* Protection is only handled in software: no hardware write protection
+          available in BlueNRG-x devices */
+       int sector;
+
+       for (sector = first; sector <= last; sector++)
+               bank->sectors[sector].is_protected = set;
+       return ERROR_OK;
+}
+static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count)
+{
+       int retval = ERROR_OK;
+
+       retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Register write failed, error code: %d", retval);
+               return retval;
+       }
+
+       for (uint32_t i = 0; i < count; i++) {
+               uint32_t address = address_base + i * FLASH_WORD_LEN;
+
+               retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Register write failed, error code: %d", retval);
+                       return retval;
+               }
+
+               retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Register write failed, error code: %d", retval);
+                       return retval;
+               }
+
+               retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Register write failed, error code: %d", retval);
+                       return retval;
+               }
+
+               for (int j = 0; j < 100; j++) {
+                       uint32_t reg_value;
+                       retval = target_read_u32(target, FLASH_REG_IRQRAW, &reg_value);
+
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Register read failed, error code: %d", retval);
+                               return retval;
+                       }
+
+                       if (reg_value & FLASH_INT_CMDDONE)
+                               break;
+
+                       if (j == 99) {
+                               LOG_ERROR("Write command failed (timeout)");
+                               return ERROR_FAIL;
+                       }
+               }
+       }
+       return retval;
+}
+
+static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count)
+{
+       int retval = ERROR_OK;
+       uint8_t *new_buffer = NULL;
+       uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address;
+
+       if (count == 0) {
+               /* Just return if there are no bytes to write */
+               return retval;
+       }
+
+       if (address_base & 3) {
+               pre_bytes = address_base & 3;
+               pre_address = address_base - pre_bytes;
+       }
+
+       if ((count + pre_bytes) & 3) {
+               post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes);
+               post_address = (address_base + count) & ~3;
+       }
+
+       if (pre_bytes || post_bytes) {
+               uint32_t old_count = count;
+
+               count = old_count + pre_bytes + post_bytes;
+
+               new_buffer = malloc(count);
+
+               if (new_buffer == NULL) {
+                       LOG_ERROR("odd number of bytes to write and no memory "
+                                 "for padding buffer");
+                       return ERROR_FAIL;
+               }
+
+               LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %"
+                        PRIu32 " ", old_count, count);
+
+               if (pre_bytes) {
+                       if (target_read_u32(target, pre_address, &pre_word)) {
+                               LOG_ERROR("Memory read failed");
+                               return ERROR_FAIL;
+                       }
+
+               }
+
+               if (post_bytes) {
+                       if (target_read_u32(target, post_address, &post_word)) {
+                               LOG_ERROR("Memory read failed");
+                               return ERROR_FAIL;
+                       }
+
+               }
+
+               memcpy(new_buffer, &pre_word, pre_bytes);
+               memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4);
+               memcpy(new_buffer+pre_bytes, buffer, old_count);
+               buffer = new_buffer;
+       }
+
+       retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4);
+
+       if (new_buffer)
+               free(new_buffer);
+
+       return retval;
+}
+
+static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
+                         uint32_t offset, uint32_t count)
+{
+       struct target *target = bank->target;
+       uint32_t buffer_size = 16384 + 8;
+       struct working_area *write_algorithm;
+       struct working_area *write_algorithm_sp;
+       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;
+       uint32_t pre_size = 0, fast_size = 0, post_size = 0;
+       uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0;
+
+       /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and
+        * hints how to generate the data!
+        */
+       static const uint8_t bluenrgx_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
+       };
+
+       if ((offset + count) > bank->size) {
+               LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d",
+                         (offset + count),
+                         bank->size);
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+       }
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* We are good here and we need to compute pre_size, fast_size, post_size */
+       pre_size  = MIN(count, ((offset+0xF) & ~0xF) - offset);
+       pre_offset = offset;
+       fast_size = 16*((count - pre_size) / 16);
+       fast_offset = offset + pre_size;
+       post_size = (count-pre_size-fast_size) % 16;
+       post_offset = fast_offset + fast_size;
+
+       LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset);
+       LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset);
+       LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset);
+
+       /* Program initial chunk not 16 bytes aligned */
+       retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size);
+       if (retval) {
+               LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
+               return ERROR_FAIL;
+       }
+
+       /* Program chunk 16 bytes aligned in fast mode */
+       if (fast_size) {
+
+               if (target_alloc_working_area(target, sizeof(bluenrgx_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(bluenrgx_flash_write_code),
+                                            bluenrgx_flash_write_code);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* memory buffer */
+               if (target_alloc_working_area(target, buffer_size, &source)) {
+                       LOG_WARNING("no large enough working area available");
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+
+               /* Stack pointer area */
+               if (target_alloc_working_area(target, 64,
+                                             &write_algorithm_sp) != ERROR_OK) {
+                       LOG_DEBUG("no working area for write code stack pointer");
+                       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);
+               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_OUT);
+               init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);
+
+               /* FIFO start address (first two words used for write and read pointers) */
+               buf_set_u32(reg_params[0].value, 0, 32, source->address);
+               /* FIFO end address (first two words used for write and read pointers) */
+               buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
+               /* Flash memory address */
+               buf_set_u32(reg_params[2].value, 0, 32, address+pre_size);
+               /* Number of bytes */
+               buf_set_u32(reg_params[3].value, 0, 32, fast_size);
+               /* Stack pointer for program working area */
+               buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
+
+               LOG_DEBUG("source->address = %08" TARGET_PRIxADDR, source->address);
+               LOG_DEBUG("source->address+ source->size = %08" TARGET_PRIxADDR, source->address+source->size);
+               LOG_DEBUG("write_algorithm_sp->address = %08" TARGET_PRIxADDR, write_algorithm_sp->address);
+               LOG_DEBUG("address = %08x", address+pre_size);
+               LOG_DEBUG("count = %08x", count);
+
+               retval = target_run_flash_async_algorithm(target,
+                                                         buffer+pre_size,
+                                                         fast_size/16,
+                                                         16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
+                                                         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 bluenrg-x flash write algorithm");
+
+                       uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
+
+                       if (error != 0)
+                               LOG_ERROR("flash write failed = %08" PRIx32, error);
+               }
+               if (retval == ERROR_OK) {
+                       uint32_t rp;
+                       /* Read back rp and check that is valid */
+                       retval = target_read_u32(target, source->address+4, &rp);
+                       if (retval == ERROR_OK) {
+                               if ((rp < source->address+8) || (rp > (source->address + source->size))) {
+                                       LOG_ERROR("flash write failed = %08" PRIx32, rp);
+                                       retval = ERROR_FLASH_OPERATION_FAILED;
+                               }
+                       }
+               }
+               target_free_working_area(target, source);
+               target_free_working_area(target, write_algorithm);
+               target_free_working_area(target, write_algorithm_sp);
+
+               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]);
+       }
+
+       /* Program chunk at end, not addressable by fast burst write algorithm */
+       retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size);
+       if (retval) {
+               LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
+               return ERROR_FAIL;
+       }
+       return retval;
+}
+
+static int bluenrgx_probe(struct flash_bank *bank)
+{
+       struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
+       uint32_t idcode, size_info, die_id;
+       int i;
+       int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(bank->target, DIE_ID_REG, &die_id);
+       if (retval != ERROR_OK)
+               return retval;
+
+       bank->size = (size_info + 1) * 4;
+       bank->base = FLASH_BASE;
+       bank->num_sectors = bank->size/FLASH_PAGE_SIZE;
+       bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
+
+       for (i = 0; i < bank->num_sectors; i++) {
+               bank->sectors[i].offset = i * FLASH_PAGE_SIZE;
+               bank->sectors[i].size = FLASH_PAGE_SIZE;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = 0;
+       }
+
+       bluenrgx_info->probed = 1;
+       bluenrgx_info->die_id = die_id;
+       bluenrgx_info->idcode = idcode;
+       return ERROR_OK;
+}
+
+static int bluenrgx_auto_probe(struct flash_bank *bank)
+{
+       struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
+
+       if (bluenrgx_info->probed)
+               return ERROR_OK;
+
+       return bluenrgx_probe(bank);
+}
+
+/* This method must return a string displaying information about the bank */
+static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
+       int mask_number, cut_number;
+       char *part_name;
+
+       if (!bluenrgx_info->probed) {
+               int retval = bluenrgx_probe(bank);
+               if (retval != ERROR_OK) {
+                       snprintf(buf, buf_size,
+                                "Unable to find bank information.");
+                       return retval;
+               }
+       }
+
+       if (bluenrgx_info->idcode == BLUENRG2_IDCODE)
+               part_name = "BLUENRG-2";
+       else
+               part_name = "BLUENRG-1";
+
+       mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
+       cut_number = bluenrgx_info->die_id & 0xF;
+
+       snprintf(buf, buf_size,
+                "%s - Rev: %d.%d", part_name, mask_number, cut_number);
+       return ERROR_OK;
+}
+
+struct flash_driver bluenrgx_flash = {
+       .name = "bluenrg-x",
+       .flash_bank_command = bluenrgx_flash_bank_command,
+       .erase = bluenrgx_erase,
+       .protect = bluenrgx_protect,
+       .write = bluenrgx_write,
+       .read = default_flash_read,
+       .probe = bluenrgx_probe,
+       .erase_check = default_flash_blank_check,
+       .protect_check = bluenrgx_protect_check,
+       .auto_probe = bluenrgx_auto_probe,
+       .info = bluenrgx_get_info,
+};
index 0e6a7382ea80d09952d1d3b23ceeb5c65eb676ab..a4640a5e71f7b8bd6bc23804f1d94b2ad2780336 100644 (file)
@@ -31,6 +31,7 @@ extern struct flash_driver at91samd_flash;
 extern struct flash_driver ath79_flash;
 extern struct flash_driver atsamv_flash;
 extern struct flash_driver avr_flash;
+extern struct flash_driver bluenrgx_flash;
 extern struct flash_driver cfi_flash;
 extern struct flash_driver dsp5680xx_flash;
 extern struct flash_driver efm32_flash;
@@ -88,6 +89,7 @@ static struct flash_driver *flash_drivers[] = {
        &ath79_flash,
        &atsamv_flash,
        &avr_flash,
+       &bluenrgx_flash,
        &cfi_flash,
        &dsp5680xx_flash,
        &efm32_flash,
diff --git a/tcl/board/steval-idb007v1.cfg b/tcl/board/steval-idb007v1.cfg
new file mode 100644 (file)
index 0000000..24dbd1e
--- /dev/null
@@ -0,0 +1,4 @@
+# This is an evaluation board with a single BlueNRG-1 chip.
+# http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb008v1.html
+set CHIPNAME bluenrg-1
+source [find target/bluenrg-x.cfg]
diff --git a/tcl/board/steval-idb008v1.cfg b/tcl/board/steval-idb008v1.cfg
new file mode 100644 (file)
index 0000000..3e9d0e5
--- /dev/null
@@ -0,0 +1,4 @@
+# This is an evaluation board with a single BlueNRG-2 chip.
+# http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb007v1.html
+set CHIPNAME bluenrg-2
+source [find target/bluenrg-x.cfg]
diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg
new file mode 100644 (file)
index 0000000..3ae5108
--- /dev/null
@@ -0,0 +1,73 @@
+#
+# bluenrg-1/2 devices support only SWD transports.
+#
+
+source [find target/swj-dp.tcl]
+
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME bluenrg-1
+}
+
+set _ENDIAN little
+
+# Work-area is a space in RAM used for flash programming
+# By default use 24kB-256bytes
+if { [info exists WORKAREASIZE] } {
+   set _WORKAREASIZE $WORKAREASIZE
+} else {
+   set _WORKAREASIZE 0x5F00
+}
+
+adapter_khz 4000
+
+if { [info exists CPUTAPID] } {
+   set _CPUTAPID $CPUTAPID
+} else {
+   set _CPUTAPID 0x0bb11477
+}
+
+swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+set WDOG_VALUE 0
+set WDOG_VALUE_SET 0
+
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME
+
+$_TARGETNAME configure -work-area-phys 0x20000100 -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+# flash size will be probed
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME
+
+# In BlueNRG-X reset pin is actually a shutdown (power-off), so define reset as none
+reset_config none
+
+if {![using_hla]} {
+   # if srst is not fitted use SYSRESETREQ to
+   # perform a soft reset
+   cortex_m reset_config sysresetreq
+}
+
+$_TARGETNAME configure -event halted {
+       global WDOG_VALUE
+       global WDOG_VALUE_SET
+       # Stop watchdog during halt, if enabled
+       mem2array value 32 0x40700008 1
+       set WDOG_VALUE [expr ($value(0))]
+       if [expr ($value(0) & (1 << 1))] {
+               set WDOG_VALUE_SET 1
+               mww 0x40700008 [expr ($value(0) & 0xFFFFFFFD)]
+       }
+}
+$_TARGETNAME configure -event resumed {
+       global WDOG_VALUE
+       global WDOG_VALUE_SET
+       if [expr $WDOG_VALUE_SET] {
+               # Restore watchdog enable value after resume
+               mww 0x40700008 $WDOG_VALUE
+               set WDOG_VALUE_SET 0
+       }
+}

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)