bluenrg-x: added support for BlueNRG-LP device

Extended bluenrg-x flash driver with BlueNRG-LP flash controller.
Changes include:
- register set for the flash controller
- made software structure prone to support more easily future devices
- updated target config file

Change-Id: I2e2dc70db32cf98c62e3a43f2e44a4600a25ac5b
Signed-off-by: luca vinci <luca.vinci@st.com>
Reviewed-on: http://openocd.zylin.com/5343
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
luca vinci 2019-11-05 08:45:04 +01:00 committed by Tomas Vanek
parent a2e822834d
commit 6bc0a77a6e
9 changed files with 258 additions and 101 deletions

View File

@ -8,15 +8,18 @@ OBJDUMP=$(CROSS_COMPILE)objdump
CFLAGS = -c -mthumb -mcpu=cortex-m0 -O3 -g CFLAGS = -c -mthumb -mcpu=cortex-m0 -O3 -g
all: bluenrg-x_write.inc all:bluenrg-2_write.inc bluenrg-lp_write.inc
.PHONY: clean .PHONY: clean
.INTERMEDIATE: bluenrg-x_write.o .INTERMEDIATE: bluenrg-x_write.o
%.o: %.c bluenrg-2_write.o: bluenrg-x_write.c
$(CC) $(CFLAGS) -Wall -Wextra -Wa,-adhln=$*.lst $< -o $@ $(CC) $(CFLAGS) -Wall -Wextra -Wa,-adhln=$*.lst $< -o $@
bluenrg-lp_write.o: bluenrg-x_write.c
$(CC) $(CFLAGS) -D BLUENRG_LP -Wall -Wextra -Wa,-adhln=$*.lst $< -o $@
%.bin: %.o %.bin: %.o
$(OBJCOPY) -Obinary $< $@ $(OBJCOPY) -Obinary $< $@

View File

@ -0,0 +1,18 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x05,0x93,0x43,0x68,0x06,0x00,0x09,0x93,0x05,0x9b,0x07,0x91,0x06,0x92,0x34,0x4d,
0x34,0x4c,0x00,0x2b,0x5d,0xd0,0x72,0x68,0x33,0x68,0x9a,0x42,0xfb,0xd0,0x33,0x68,
0x00,0x2b,0x56,0xd0,0x72,0x68,0x33,0x68,0x9a,0x42,0x53,0xd9,0x73,0x68,0x07,0x9a,
0xd3,0x1a,0x0f,0x2b,0xef,0xdd,0x00,0x21,0x2b,0x4a,0x03,0x93,0x11,0x60,0x00,0x2b,
0x37,0xd0,0x2a,0x4a,0x06,0x9b,0x94,0x46,0x63,0x44,0x18,0x00,0x73,0x68,0x08,0x96,
0x04,0x93,0x1a,0x00,0x26,0x4b,0x99,0x46,0x26,0x4b,0x98,0x46,0x26,0x4b,0x9c,0x46,
0x26,0x4b,0x9b,0x46,0x26,0x4b,0x9a,0x46,0x01,0x23,0x91,0x68,0x17,0x68,0x01,0x91,
0xd1,0x68,0x56,0x68,0x02,0x91,0x3f,0x21,0x29,0x60,0x81,0x03,0x09,0x0c,0x21,0x60,
0x49,0x46,0x0f,0x60,0x47,0x46,0x3e,0x60,0x66,0x46,0x01,0x99,0x31,0x60,0x5e,0x46,
0x02,0x99,0x31,0x60,0x51,0x46,0xcc,0x26,0x0e,0x60,0x29,0x68,0x0b,0x42,0xfc,0xd0,
0x04,0x99,0x03,0x9e,0x10,0x32,0x10,0x30,0x51,0x1a,0x8e,0x42,0xdd,0xd8,0x08,0x9e,
0x72,0x60,0x03,0x9a,0x06,0x9b,0x94,0x46,0x63,0x44,0x06,0x93,0x07,0x9a,0x73,0x68,
0x9a,0x42,0x01,0xd8,0x09,0x9b,0x73,0x60,0x05,0x9b,0x03,0x9a,0x9b,0x1a,0x05,0x93,
0xa1,0xd1,0x00,0xbe,0x33,0x68,0x72,0x68,0x9b,0x1a,0xaa,0xd5,0x9b,0xe7,0xc0,0x46,
0x10,0x00,0x10,0x40,0x18,0x00,0x10,0x40,0x0c,0x00,0x10,0x40,0x00,0x00,0xfc,0xef,
0x40,0x00,0x10,0x40,0x44,0x00,0x10,0x40,0x48,0x00,0x10,0x40,0x4c,0x00,0x10,0x40,
0x00,0x00,0x10,0x40,

View File

@ -0,0 +1,18 @@
/* Autogenerated with ../../../../src/helper/bin2char.sh */
0x05,0x93,0x43,0x68,0x06,0x00,0x09,0x93,0x05,0x9b,0x07,0x91,0x06,0x92,0x34,0x4d,
0x34,0x4c,0x00,0x2b,0x5d,0xd0,0x72,0x68,0x33,0x68,0x9a,0x42,0xfb,0xd0,0x33,0x68,
0x00,0x2b,0x56,0xd0,0x72,0x68,0x33,0x68,0x9a,0x42,0x53,0xd9,0x73,0x68,0x07,0x9a,
0xd3,0x1a,0x0f,0x2b,0xef,0xdd,0x00,0x21,0x2b,0x4a,0x03,0x93,0x11,0x60,0x00,0x2b,
0x37,0xd0,0x2a,0x4a,0x06,0x9b,0x94,0x46,0x63,0x44,0x18,0x00,0x73,0x68,0x08,0x96,
0x04,0x93,0x1a,0x00,0x26,0x4b,0x99,0x46,0x26,0x4b,0x98,0x46,0x26,0x4b,0x9c,0x46,
0x26,0x4b,0x9b,0x46,0x26,0x4b,0x9a,0x46,0x01,0x23,0x91,0x68,0x17,0x68,0x01,0x91,
0xd1,0x68,0x56,0x68,0x02,0x91,0x3f,0x21,0x29,0x60,0x81,0x03,0x09,0x0c,0x21,0x60,
0x49,0x46,0x0f,0x60,0x47,0x46,0x3e,0x60,0x66,0x46,0x01,0x99,0x31,0x60,0x5e,0x46,
0x02,0x99,0x31,0x60,0x51,0x46,0xcc,0x26,0x0e,0x60,0x29,0x68,0x0b,0x42,0xfc,0xd0,
0x04,0x99,0x03,0x9e,0x10,0x32,0x10,0x30,0x51,0x1a,0x8e,0x42,0xdd,0xd8,0x08,0x9e,
0x72,0x60,0x03,0x9a,0x06,0x9b,0x94,0x46,0x63,0x44,0x06,0x93,0x07,0x9a,0x73,0x68,
0x9a,0x42,0x01,0xd8,0x09,0x9b,0x73,0x60,0x05,0x9b,0x03,0x9a,0x9b,0x1a,0x05,0x93,
0xa1,0xd1,0x00,0xbe,0x33,0x68,0x72,0x68,0x9b,0x1a,0xaa,0xd5,0x9b,0xe7,0xc0,0x46,
0x10,0x10,0x00,0x40,0x18,0x10,0x00,0x40,0x0c,0x10,0x00,0x40,0x00,0x00,0xfc,0xef,
0x40,0x10,0x00,0x40,0x44,0x10,0x00,0x40,0x48,0x10,0x00,0x40,0x4c,0x10,0x00,0x40,
0x00,0x10,0x00,0x40,

View File

@ -14,6 +14,21 @@
#define ERR_VERIFY_FAILED 7 #define ERR_VERIFY_FAILED 7
/* Flash Controller defines ---------------------------------------------------*/ /* Flash Controller defines ---------------------------------------------------*/
#ifdef BLUENRG_LP
#define FLASH_REG_COMMAND ((volatile uint32_t *)0x40001000)
#define FLASH_REG_CONFIG ((volatile uint32_t *)0x40001004)
#define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40001008)
#define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4000100C)
#define FLASH_REG_IRQRAW ((volatile uint32_t *)0x40001010)
#define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40001018)
#define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4000101C)
#define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40001020)
#define FLASH_REG_DATA0 ((volatile uint32_t *)0x40001040)
#define FLASH_REG_DATA1 ((volatile uint32_t *)0x40001044)
#define FLASH_REG_DATA2 ((volatile uint32_t *)0x40001048)
#define FLASH_REG_DATA3 ((volatile uint32_t *)0x4000104C)
#define FLASH_SIZE_REG 0x40001014
#else
#define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000) #define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000)
#define FLASH_REG_CONFIG ((volatile uint32_t *)0x40100004) #define FLASH_REG_CONFIG ((volatile uint32_t *)0x40100004)
#define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008) #define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008)
@ -22,11 +37,12 @@
#define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018) #define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018)
#define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C) #define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C)
#define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020) #define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020)
#define FLASH_REG_DATA0 ((volatile uint32_t *)0x40100040) #define FLASH_REG_DATA0 ((volatile uint32_t *)0x40100040)
#define FLASH_REG_DATA1 ((volatile uint32_t *)0x40100044) #define FLASH_REG_DATA1 ((volatile uint32_t *)0x40100044)
#define FLASH_REG_DATA2 ((volatile uint32_t *)0x40100048) #define FLASH_REG_DATA2 ((volatile uint32_t *)0x40100048)
#define FLASH_REG_DATA3 ((volatile uint32_t *)0x4010004C) #define FLASH_REG_DATA3 ((volatile uint32_t *)0x4010004C)
#define FLASH_SIZE_REG 0x40100014 #define FLASH_SIZE_REG 0x40100014
#endif
#define MFB_MASS_ERASE 0x01 #define MFB_MASS_ERASE 0x01
#define MFB_PAGE_ERASE 0x02 #define MFB_PAGE_ERASE 0x02
@ -70,7 +86,7 @@ static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t addres
/* Clear the IRQ flags */ /* Clear the IRQ flags */
*FLASH_REG_IRQRAW = 0x0000003F; *FLASH_REG_IRQRAW = 0x0000003F;
/* Load the flash address to write */ /* Load the flash address to write */
*FLASH_REG_ADDRESS = (uint16_t)((address + index) >> 2); *FLASH_REG_ADDRESS = (uint16_t)((address + index - MFB_BOTTOM) >> 2);
/* Prepare and load the data to flash */ /* Prepare and load the data to flash */
*FLASH_REG_DATA0 = flash_word[0]; *FLASH_REG_DATA0 = flash_word[0];
*FLASH_REG_DATA1 = flash_word[1]; *FLASH_REG_DATA1 = flash_word[1];

View File

@ -1,18 +0,0 @@
/* 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,

View File

@ -5830,7 +5830,7 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory.
@end deffn @end deffn
@deffn {Flash Driver} bluenrg-x @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. STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory.
The driver automatically recognizes these chips using The driver automatically recognizes these chips using
the chip identification registers, and autoconfigures itself. the chip identification registers, and autoconfigures itself.
@ -5849,6 +5849,10 @@ flash erase_sector 0 0 79 # It will perform a mass erase on BlueNRG-1
flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-2 flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-2
@end example @end example
@example
flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-LP
@end example
Triggering a mass erase is also useful when users want to disable readout protection. Triggering a mass erase is also useful when users want to disable readout protection.
@end deffn @end deffn

View File

@ -25,16 +25,20 @@
#include <target/cortex_m.h> #include <target/cortex_m.h>
#include "imp.h" #include "imp.h"
#define FLASH_SIZE_REG (0x40100014)
#define DIE_ID_REG (0x4090001C)
#define JTAG_IDCODE_REG (0x40900028)
#define BLUENRG2_IDCODE (0x0200A041) #define BLUENRG2_IDCODE (0x0200A041)
#define FLASH_BASE (0x10040000) #define BLUENRGLP_IDCODE (0x0201E041)
#define FLASH_PAGE_SIZE (2048) #define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg)
#define FLASH_REG_COMMAND (0x40100000) #define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg)
#define FLASH_REG_IRQRAW (0x40100010)
#define FLASH_REG_ADDRESS (0x40100018) #define FLASH_SIZE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_size_reg)
#define FLASH_REG_DATA (0x40100040) #define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg)
#define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg)
#define FLASH_BASE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_base)
#define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size)
#define FLASH_REG_COMMAND(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_reg_command)
#define FLASH_REG_IRQRAW(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_reg_irqraw)
#define FLASH_REG_ADDRESS(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_reg_address)
#define FLASH_REG_DATA(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_reg_data)
#define FLASH_CMD_ERASE_PAGE 0x11 #define FLASH_CMD_ERASE_PAGE 0x11
#define FLASH_CMD_MASSERASE 0x22 #define FLASH_CMD_MASSERASE 0x22
#define FLASH_CMD_WRITE 0x33 #define FLASH_CMD_WRITE 0x33
@ -42,12 +46,91 @@
#define FLASH_INT_CMDDONE 0x01 #define FLASH_INT_CMDDONE 0x01
#define FLASH_WORD_LEN 4 #define FLASH_WORD_LEN 4
/* 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_2[] = {
#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-2_write.inc"
};
static const uint8_t bluenrgx_flash_write_code_lp[] = {
#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-lp_write.inc"
};
struct flash_ctrl_priv_data {
uint32_t flash_size_reg;
uint32_t die_id_reg;
uint32_t jtag_idcode_reg;
uint32_t flash_base;
uint32_t flash_page_size;
uint32_t flash_reg_command;
uint32_t flash_reg_irqraw;
uint32_t flash_reg_address;
uint32_t flash_reg_data;
uint32_t jtag_idcode;
char *part_name;
const uint8_t *flash_write_code;
uint32_t flash_write_code_size;
};
const struct flash_ctrl_priv_data flash_priv_data_1 = {
.flash_size_reg = 0x40100014,
.die_id_reg = 0x4090001C,
.jtag_idcode_reg = 0x40900028,
.flash_base = 0x10040000,
.flash_page_size = 2048,
.flash_reg_command = 0x40100000,
.flash_reg_irqraw = 0x40100010,
.flash_reg_address = 0x40100018,
.flash_reg_data = 0x40100040,
.jtag_idcode = 0x00000000,
.part_name = "BLUENRG-1",
.flash_write_code = bluenrgx_flash_write_code_2,
.flash_write_code_size = sizeof(bluenrgx_flash_write_code_2),
};
const struct flash_ctrl_priv_data flash_priv_data_2 = {
.flash_size_reg = 0x40100014,
.die_id_reg = 0x4090001C,
.jtag_idcode_reg = 0x40900028,
.flash_base = 0x10040000,
.flash_page_size = 2048,
.flash_reg_command = 0x40100000,
.flash_reg_irqraw = 0x40100010,
.flash_reg_address = 0x40100018,
.flash_reg_data = 0x40100040,
.jtag_idcode = BLUENRG2_IDCODE,
.part_name = "BLUENRG-2",
.flash_write_code = bluenrgx_flash_write_code_2,
.flash_write_code_size = sizeof(bluenrgx_flash_write_code_2),
};
const struct flash_ctrl_priv_data flash_priv_data_lp = {
.flash_size_reg = 0x40001014,
.die_id_reg = 0x40000000,
.jtag_idcode_reg = 0x40000004,
.flash_base = 0x10040000,
.flash_page_size = 2048,
.flash_reg_command = 0x40001000,
.flash_reg_irqraw = 0x40001010,
.flash_reg_address = 0x40001018,
.flash_reg_data = 0x40001040,
.jtag_idcode = BLUENRGLP_IDCODE,
.part_name = "BLUENRG-LP",
.flash_write_code = bluenrgx_flash_write_code_lp,
.flash_write_code_size = sizeof(bluenrgx_flash_write_code_lp),
};
struct bluenrgx_flash_bank { struct bluenrgx_flash_bank {
int probed; int probed;
uint32_t idcode;
uint32_t die_id; uint32_t die_id;
const struct flash_ctrl_priv_data *flash_ptr;
const uint8_t *flash_write_code;
uint32_t flash_write_code_size;
}; };
const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp};
static int bluenrgx_protect_check(struct flash_bank *bank) static int bluenrgx_protect_check(struct flash_bank *bank)
{ {
/* Nothing to do. Protection is only handled in SW. */ /* Nothing to do. Protection is only handled in SW. */
@ -103,24 +186,25 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
if (mass_erase) { if (mass_erase) {
command = FLASH_CMD_MASSERASE; command = FLASH_CMD_MASSERASE;
address = bank->base; address = bank->base;
if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { if (target_write_u32(target, FLASH_REG_IRQRAW(bluenrgx_info), 0x3f) != ERROR_OK) {
LOG_ERROR("Register write failed"); LOG_ERROR("Register write failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { if (target_write_u32(target, FLASH_REG_ADDRESS(bluenrgx_info),
(address - FLASH_BASE(bluenrgx_info)) >> 2) != ERROR_OK) {
LOG_ERROR("Register write failed"); LOG_ERROR("Register write failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { if (target_write_u32(target, FLASH_REG_COMMAND(bluenrgx_info), command) != ERROR_OK) {
LOG_ERROR("Register write failed"); LOG_ERROR("Register write failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
uint32_t value; uint32_t value;
if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { if (target_read_u32(target, FLASH_REG_IRQRAW(bluenrgx_info), &value)) {
LOG_ERROR("Register write failed"); LOG_ERROR("Register write failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -135,26 +219,28 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
} else { } else {
command = FLASH_CMD_ERASE_PAGE; command = FLASH_CMD_ERASE_PAGE;
for (int i = first; i <= last; i++) { for (int i = first; i <= last; i++) {
address = bank->base+i*FLASH_PAGE_SIZE; address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info);
LOG_DEBUG("address = %08x, index = %d", address, i);
if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { if (target_write_u32(target, FLASH_REG_IRQRAW(bluenrgx_info), 0x3f) != ERROR_OK) {
LOG_ERROR("Register write failed"); LOG_ERROR("Register write failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { if (target_write_u32(target, FLASH_REG_ADDRESS(bluenrgx_info),
(address - FLASH_BASE(bluenrgx_info)) >> 2) != ERROR_OK) {
LOG_ERROR("Register write failed"); LOG_ERROR("Register write failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { if (target_write_u32(target, FLASH_REG_COMMAND(bluenrgx_info), command) != ERROR_OK) {
LOG_ERROR("Failed"); LOG_ERROR("Failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
for (int j = 0; j < 100; j++) { for (int j = 0; j < 100; j++) {
uint32_t value; uint32_t value;
if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { if (target_read_u32(target, FLASH_REG_IRQRAW(bluenrgx_info), &value)) {
LOG_ERROR("Register write failed"); LOG_ERROR("Register write failed");
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -182,11 +268,14 @@ static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int las
bank->sectors[sector].is_protected = set; bank->sectors[sector].is_protected = set;
return ERROR_OK; return ERROR_OK;
} }
static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count)
static int bluenrgx_write_word(struct flash_bank *bank, uint32_t address_base, uint8_t *values, uint32_t count)
{ {
int retval = ERROR_OK; int retval = ERROR_OK;
struct target *target = bank->target;
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f); retval = target_write_u32(target, FLASH_REG_IRQRAW(bluenrgx_info), 0x3f);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("Register write failed, error code: %d", retval); LOG_ERROR("Register write failed, error code: %d", retval);
return retval; return retval;
@ -195,19 +284,21 @@ static int bluenrgx_write_word(struct target *target, uint32_t address_base, uin
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
uint32_t address = address_base + i * FLASH_WORD_LEN; uint32_t address = address_base + i * FLASH_WORD_LEN;
retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2); retval = target_write_u32(target, FLASH_REG_ADDRESS(bluenrgx_info),
(address - FLASH_BASE(bluenrgx_info)) >> 2);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("Register write failed, error code: %d", retval); LOG_ERROR("Register write failed, error code: %d", retval);
return retval; return retval;
} }
retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN); retval = target_write_buffer(target, FLASH_REG_DATA(bluenrgx_info),
FLASH_WORD_LEN, values + i * FLASH_WORD_LEN);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("Register write failed, error code: %d", retval); LOG_ERROR("Register write failed, error code: %d", retval);
return retval; return retval;
} }
retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE); retval = target_write_u32(target, FLASH_REG_COMMAND(bluenrgx_info), FLASH_CMD_WRITE);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("Register write failed, error code: %d", retval); LOG_ERROR("Register write failed, error code: %d", retval);
return retval; return retval;
@ -215,7 +306,7 @@ static int bluenrgx_write_word(struct target *target, uint32_t address_base, uin
for (int j = 0; j < 100; j++) { for (int j = 0; j < 100; j++) {
uint32_t reg_value; uint32_t reg_value;
retval = target_read_u32(target, FLASH_REG_IRQRAW, &reg_value); retval = target_read_u32(target, FLASH_REG_IRQRAW(bluenrgx_info), &reg_value);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("Register read failed, error code: %d", retval); LOG_ERROR("Register read failed, error code: %d", retval);
@ -234,9 +325,10 @@ static int bluenrgx_write_word(struct target *target, uint32_t address_base, uin
return retval; return retval;
} }
static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count) static int bluenrgx_write_bytes(struct flash_bank *bank, uint32_t address_base, uint8_t *buffer, uint32_t count)
{ {
int retval = ERROR_OK; int retval = ERROR_OK;
struct target *target = bank->target;
uint8_t *new_buffer = NULL; uint8_t *new_buffer = NULL;
uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address; uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address;
@ -295,7 +387,7 @@ static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, ui
buffer = new_buffer; buffer = new_buffer;
} }
retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4); retval = bluenrgx_write_word(bank, address_base - pre_bytes, buffer, count/4);
if (new_buffer) if (new_buffer)
free(new_buffer); free(new_buffer);
@ -306,6 +398,7 @@ static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, ui
static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count) uint32_t offset, uint32_t count)
{ {
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
struct target *target = bank->target; struct target *target = bank->target;
uint32_t buffer_size = 16384 + 8; uint32_t buffer_size = 16384 + 8;
struct working_area *write_algorithm; struct working_area *write_algorithm;
@ -318,12 +411,9 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t pre_size = 0, fast_size = 0, post_size = 0; uint32_t pre_size = 0, fast_size = 0, post_size = 0;
uint32_t pre_offset = 0, fast_offset = 0, post_offset = 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 /* check preconditions */
* hints how to generate the data! if (bluenrgx_info->probed == 0)
*/ return ERROR_FLASH_BANK_NOT_PROBED;
static const uint8_t bluenrgx_flash_write_code[] = {
#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
};
if ((offset + count) > bank->size) { if ((offset + count) > bank->size) {
LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d", LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d",
@ -350,7 +440,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset); LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset);
/* Program initial chunk not 16 bytes aligned */ /* Program initial chunk not 16 bytes aligned */
retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size); retval = bluenrgx_write_bytes(bank, bank->base+pre_offset, (uint8_t *) buffer, pre_size);
if (retval) { if (retval) {
LOG_ERROR("bluenrgx_write_bytes failed %d", retval); LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
return ERROR_FAIL; return ERROR_FAIL;
@ -359,15 +449,15 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
/* Program chunk 16 bytes aligned in fast mode */ /* Program chunk 16 bytes aligned in fast mode */
if (fast_size) { if (fast_size) {
if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), if (target_alloc_working_area(target, bluenrgx_info->flash_write_code_size,
&write_algorithm) != ERROR_OK) { &write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes"); LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
retval = target_write_buffer(target, write_algorithm->address, retval = target_write_buffer(target, write_algorithm->address,
sizeof(bluenrgx_flash_write_code), bluenrgx_info->flash_write_code_size,
bluenrgx_flash_write_code); bluenrgx_info->flash_write_code);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -379,7 +469,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
/* Stack pointer area */ /* Stack pointer area */
if (target_alloc_working_area(target, 64, if (target_alloc_working_area(target, 64,
&write_algorithm_sp) != ERROR_OK) { &write_algorithm_sp) != ERROR_OK) {
LOG_DEBUG("no working area for write code stack pointer"); LOG_DEBUG("no working area for write code stack pointer");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
@ -458,7 +548,8 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
} }
/* Program chunk at end, not addressable by fast burst write algorithm */ /* 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); retval = bluenrgx_write_bytes(bank, bank->base+post_offset,
(uint8_t *) (buffer+pre_size+fast_size), post_size);
if (retval) { if (retval) {
LOG_ERROR("bluenrgx_write_bytes failed %d", retval); LOG_ERROR("bluenrgx_write_bytes failed %d", retval);
return ERROR_FAIL; return ERROR_FAIL;
@ -471,32 +562,54 @@ static int bluenrgx_probe(struct flash_bank *bank)
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
uint32_t idcode, size_info, die_id; uint32_t idcode, size_info, die_id;
int i; int i;
int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode); int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
retval = target_read_u32(bank->target, DIE_ID_REG, &die_id); if (idcode != BLUENRGLP_IDCODE) {
retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
if (retval != ERROR_OK)
return retval;
}
/* Default device is BlueNRG-1 */
bluenrgx_info->flash_ptr = &flash_priv_data_1;
bluenrgx_info->flash_write_code = flash_priv_data_1.flash_write_code;
bluenrgx_info->flash_write_code_size = flash_priv_data_1.flash_write_code_size;
for (i = 0; i < (int)(sizeof(flash_ctrl)/sizeof(*flash_ctrl)); i++) {
if (idcode == (*flash_ctrl[i]).jtag_idcode) {
bluenrgx_info->flash_ptr = flash_ctrl[i];
bluenrgx_info->flash_write_code = (*flash_ctrl[i]).flash_write_code;
bluenrgx_info->flash_write_code_size = (*flash_ctrl[i]).flash_write_code_size;
break;
}
}
retval = target_read_u32(bank->target, FLASH_SIZE_REG(bluenrgx_info), &size_info);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
bank->size = (size_info + 1) * 4; retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id);
bank->base = FLASH_BASE; if (retval != ERROR_OK)
bank->num_sectors = bank->size/FLASH_PAGE_SIZE; return retval;
bank->size = (size_info + 1) * FLASH_WORD_LEN;
bank->base = FLASH_BASE(bluenrgx_info);
bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors);
for (i = 0; i < bank->num_sectors; i++) { for (i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = i * FLASH_PAGE_SIZE; bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors[i].size = FLASH_PAGE_SIZE; bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info);
bank->sectors[i].is_erased = -1; bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0; bank->sectors[i].is_protected = 0;
} }
bluenrgx_info->probed = 1; bluenrgx_info->probed = 1;
bluenrgx_info->die_id = die_id; bluenrgx_info->die_id = die_id;
bluenrgx_info->idcode = idcode;
return ERROR_OK; return ERROR_OK;
} }
@ -515,7 +628,6 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
int mask_number, cut_number; int mask_number, cut_number;
char *part_name;
if (!bluenrgx_info->probed) { if (!bluenrgx_info->probed) {
int retval = bluenrgx_probe(bank); int retval = bluenrgx_probe(bank);
@ -526,16 +638,11 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
} }
} }
if (bluenrgx_info->idcode == BLUENRG2_IDCODE)
part_name = "BLUENRG-2";
else
part_name = "BLUENRG-1";
mask_number = (bluenrgx_info->die_id >> 4) & 0xF; mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
cut_number = bluenrgx_info->die_id & 0xF; cut_number = bluenrgx_info->die_id & 0xF;
snprintf(buf, buf_size, snprintf(buf, buf_size,
"%s - Rev: %d.%d", part_name, mask_number, cut_number); "%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number);
return ERROR_OK; return ERROR_OK;
} }

View File

@ -0,0 +1,3 @@
# This is an evaluation board with a single BlueNRG-LP chip.
set CHIPNAME bluenrg-lp
source [find target/bluenrg-x.cfg]

View File

@ -1,8 +1,9 @@
# #
# bluenrg-1/2 devices support only SWD transports. # bluenrg-1/2 and bluenrg-lp devices support only SWD transports.
# #
source [find target/swj-dp.tcl] source [find target/swj-dp.tcl]
source [find mem_helper.tcl]
if { [info exists CHIPNAME] } { if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME set _CHIPNAME $CHIPNAME
@ -53,22 +54,27 @@ if {![using_hla]} {
} }
$_TARGETNAME configure -event halted { $_TARGETNAME configure -event halted {
global WDOG_VALUE global WDOG_VALUE
global WDOG_VALUE_SET global WDOG_VALUE_SET
# Stop watchdog during halt, if enabled set _JTAG_IDCODE [mrw 0x40000004]
mem2array value 32 0x40700008 1 if {$_JTAG_IDCODE != 0x0201E041} {
set WDOG_VALUE [expr ($value(0))] # Stop watchdog during halt, if enabled. Only Bluenrg-1/2
if [expr ($value(0) & (1 << 1))] { set WDOG_VALUE [mrw 0x40700008]
set WDOG_VALUE_SET 1 if [expr ($WDOG_VALUE & (1 << 1))] {
mww 0x40700008 [expr ($value(0) & 0xFFFFFFFD)] set WDOG_VALUE_SET 1
} mww 0x40700008 [expr ($WDOG_VALUE & 0xFFFFFFFD)]
}
}
} }
$_TARGETNAME configure -event resumed { $_TARGETNAME configure -event resumed {
global WDOG_VALUE global WDOG_VALUE
global WDOG_VALUE_SET global WDOG_VALUE_SET
if [expr $WDOG_VALUE_SET] { set _JTAG_IDCODE [mrw 0x40000004]
# Restore watchdog enable value after resume if {$_JTAG_IDCODE != 0x0201E041} {
mww 0x40700008 $WDOG_VALUE if [expr $WDOG_VALUE_SET] {
set WDOG_VALUE_SET 0 # Restore watchdog enable value after resume. Only Bluenrg-1/2
} mww 0x40700008 $WDOG_VALUE
set WDOG_VALUE_SET 0
}
}
} }