Merge branch 'master' into from_upstream

Conflicts:
	src/rtos/rtos.c
	src/rtos/rtos.h
	src/server/gdb_server.c

Change-Id: Icd5a8165fe111f699542530c9cb034faf30e09b2
This commit is contained in:
Tim Newsome
2018-04-09 12:17:08 -07:00
212 changed files with 8395 additions and 1608 deletions
+2
View 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 \
@@ -42,6 +43,7 @@ NOR_DRIVERS = \
%D%/ocl.c \
%D%/pic32mx.c \
%D%/psoc4.c \
%D%/psoc6.c \
%D%/sim3x.c \
%D%/spi.c \
%D%/stmsmi.c \
+1
View File
@@ -901,4 +901,5 @@ struct flash_driver ambiqmicro_flash = {
.erase_check = default_flash_blank_check,
.protect_check = ambiqmicro_protect_check,
.info = get_ambiqmicro_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+260 -99
View File
@@ -83,6 +83,9 @@
#define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F))
#define SAMD_GET_DEVSEL(id) (id & 0xFF)
/* Bits to mask out lockbits in user row */
#define NVMUSERROW_LOCKBIT_MASK ((uint64_t)0x0000FFFFFFFFFFFF)
struct samd_part {
uint8_t id;
const char *name;
@@ -159,23 +162,22 @@ static const struct samd_part samd21_parts[] = {
{ 0xC, "SAMD21E16A", 64, 8 },
{ 0xD, "SAMD21E15A", 32, 4 },
{ 0xE, "SAMD21E14A", 16, 2 },
/* Below are B Variants (Table 3-7 from rev I of datasheet) */
{ 0x20, "SAMD21J16B", 64, 8 },
{ 0x21, "SAMD21J15B", 32, 4 },
{ 0x23, "SAMD21G16B", 64, 8 },
{ 0x24, "SAMD21G15B", 32, 4 },
{ 0x26, "SAMD21E16B", 64, 8 },
{ 0x27, "SAMD21E15B", 32, 4 },
};
/* Known SAMR21 parts. */
static const struct samd_part samr21_parts[] = {
/* SAMR21 parts have integrated SAMD21 with a radio */
{ 0x19, "SAMR21G18A", 256, 32 },
{ 0x1A, "SAMR21G17A", 128, 32 },
{ 0x1B, "SAMR21G16A", 64, 32 },
{ 0x1C, "SAMR21E18A", 256, 32 },
{ 0x1D, "SAMR21E17A", 128, 32 },
{ 0x1E, "SAMR21E16A", 64, 32 },
/* SAMD21 B Variants (Table 3-7 from rev I of datasheet) */
{ 0x20, "SAMD21J16B", 64, 8 },
{ 0x21, "SAMD21J15B", 32, 4 },
{ 0x23, "SAMD21G16B", 64, 8 },
{ 0x24, "SAMD21G15B", 32, 4 },
{ 0x26, "SAMD21E16B", 64, 8 },
{ 0x27, "SAMD21E15B", 32, 4 },
};
/* Known SAML21 parts. */
@@ -200,6 +202,10 @@ static const struct samd_part saml21_parts[] = {
{ 0x1A, "SAML21E17B", 128, 16 },
{ 0x1B, "SAML21E16B", 64, 8 },
{ 0x1C, "SAML21E15B", 32, 4 },
/* SAMR30 parts have integrated SAML21 with a radio */
{ 0x1E, "SAMR30G18A", 256, 32 },
{ 0x1F, "SAMR30E18A", 256, 32 },
};
/* Known SAML22 parts. */
@@ -256,30 +262,38 @@ struct samd_family {
uint8_t series;
const struct samd_part *parts;
size_t num_parts;
uint64_t nvm_userrow_res_mask; /* protect bits which are reserved, 0 -> protect */
};
/* Known SAMD families */
static const struct samd_family samd_families[] = {
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20,
samd20_parts, ARRAY_SIZE(samd20_parts) },
samd20_parts, ARRAY_SIZE(samd20_parts),
(uint64_t)0xFFFF01FFFE01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21,
samd21_parts, ARRAY_SIZE(samd21_parts) },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21,
samr21_parts, ARRAY_SIZE(samr21_parts) },
samd21_parts, ARRAY_SIZE(samd21_parts),
(uint64_t)0xFFFF01FFFE01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09,
samd09_parts, ARRAY_SIZE(samd09_parts) },
samd09_parts, ARRAY_SIZE(samd09_parts),
(uint64_t)0xFFFF01FFFE01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10,
samd10_parts, ARRAY_SIZE(samd10_parts) },
samd10_parts, ARRAY_SIZE(samd10_parts),
(uint64_t)0xFFFF01FFFE01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11,
samd11_parts, ARRAY_SIZE(samd11_parts) },
samd11_parts, ARRAY_SIZE(samd11_parts),
(uint64_t)0xFFFF01FFFE01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21,
saml21_parts, ARRAY_SIZE(saml21_parts) },
saml21_parts, ARRAY_SIZE(saml21_parts),
(uint64_t)0xFFFF03FFFC01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_22,
saml22_parts, ARRAY_SIZE(saml22_parts) },
saml22_parts, ARRAY_SIZE(saml22_parts),
(uint64_t)0xFFFF03FFFC01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20,
samc20_parts, ARRAY_SIZE(samc20_parts) },
samc20_parts, ARRAY_SIZE(samc20_parts),
(uint64_t)0xFFFF03FFFC01FF77 },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21,
samc21_parts, ARRAY_SIZE(samc21_parts) },
samc21_parts, ARRAY_SIZE(samc21_parts),
(uint64_t)0xFFFF03FFFC01FF77 },
};
struct samd_info {
@@ -295,24 +309,42 @@ struct samd_info {
static struct samd_info *samd_chips;
static const struct samd_part *samd_find_part(uint32_t id)
/**
* Gives the family structure to specific device id.
* @param id The id of the device.
* @return On failure NULL, otherwise a pointer to the structure.
*/
static const struct samd_family *samd_find_family(uint32_t id)
{
uint8_t processor = SAMD_GET_PROCESSOR(id);
uint8_t family = SAMD_GET_FAMILY(id);
uint8_t series = SAMD_GET_SERIES(id);
uint8_t devsel = SAMD_GET_DEVSEL(id);
for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) {
if (samd_families[i].processor == processor &&
samd_families[i].series == series &&
samd_families[i].family == family) {
for (unsigned j = 0; j < samd_families[i].num_parts; j++) {
if (samd_families[i].parts[j].id == devsel)
return &samd_families[i].parts[j];
}
}
samd_families[i].family == family)
return &samd_families[i];
}
return NULL;
}
/**
* Gives the part structure to specific device id.
* @param id The id of the device.
* @return On failure NULL, otherwise a pointer to the structure.
*/
static const struct samd_part *samd_find_part(uint32_t id)
{
uint8_t devsel = SAMD_GET_DEVSEL(id);
const struct samd_family *family = samd_find_family(id);
if (family == NULL)
return NULL;
for (unsigned i = 0; i < family->num_parts; i++) {
if (family->parts[i].id == devsel)
return &family->parts[i];
}
return NULL;
@@ -483,6 +515,12 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
return samd_check_error(target);
}
/**
* Erases a flash-row at the given address.
* @param target Pointer to the target structure.
* @param address The address of the row.
* @return On success ERROR_OK, on failure an errorcode.
*/
static int samd_erase_row(struct target *target, uint32_t address)
{
int res;
@@ -504,49 +542,62 @@ static int samd_erase_row(struct target *target, uint32_t address)
return ERROR_OK;
}
static bool is_user_row_reserved_bit(uint8_t bit)
/**
* Returns the bitmask of reserved bits in register.
* @param target Pointer to the target structure.
* @param mask Bitmask, 0 -> value stays untouched.
* @return On success ERROR_OK, on failure an errorcode.
*/
static int samd_get_reservedmask(struct target *target, uint64_t *mask)
{
/* See Table 9-3 in the SAMD20 datasheet for more information. */
switch (bit) {
/* Reserved bits */
case 3:
case 7:
/* Voltage regulator internal configuration with default value of 0x70,
* may not be changed. */
case 17 ... 24:
/* 41 is voltage regulator internal configuration and must not be
* changed. 42 through 47 are reserved. */
case 41 ... 47:
return true;
default:
break;
int res;
/* Get the devicetype */
uint32_t id;
res = target_read_u32(target, SAMD_DSU + SAMD_DSU_DID, &id);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read Device ID register");
return res;
}
return false;
const struct samd_family *family;
family = samd_find_family(id);
if (family == NULL) {
LOG_ERROR("Couldn't determine device family");
return ERROR_FAIL;
}
*mask = family->nvm_userrow_res_mask;
return ERROR_OK;
}
/* Modify the contents of the User Row in Flash. These are described in Table
* 9-3 of the SAMD20 datasheet. The User Row itself has a size of one page
* and contains a combination of "fuses" and calibration data in bits 24:17.
* We therefore try not to erase the row's contents unless we absolutely have
* to and we don't permit modifying reserved bits. */
static int samd_modify_user_row(struct target *target, uint32_t value,
uint8_t startb, uint8_t endb)
static int read_userrow(struct target *target, uint64_t *userrow)
{
int res;
uint8_t buffer[8];
res = target_read_memory(target, SAMD_USER_ROW, 4, 2, buffer);
if (res != ERROR_OK)
return res;
*userrow = target_buffer_get_u64(target, buffer);
return ERROR_OK;
}
/**
* Modify the contents of the User Row in Flash. The User Row itself
* has a size of one page and contains a combination of "fuses" and
* calibration data. Bits which have a value of zero in the mask will
* not be changed. Up to now devices only use the first 64 bits.
* @param target Pointer to the target structure.
* @param value_input The value to write.
* @param value_mask Bitmask, 0 -> value stays untouched.
* @return On success ERROR_OK, on failure an errorcode.
*/
static int samd_modify_user_row_masked(struct target *target,
uint64_t value_input, uint64_t value_mask)
{
int res;
uint32_t nvm_ctrlb;
bool manual_wp = true;
if (is_user_row_reserved_bit(startb) || is_user_row_reserved_bit(endb)) {
LOG_ERROR("Can't modify bits in the requested range");
return ERROR_FAIL;
}
/* Check if we need to do manual page write commands */
res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb);
if (res == ERROR_OK)
manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0;
/* Retrieve the MCU's page size, in bytes. This is also the size of the
* entire User Row. */
uint32_t page_size;
@@ -556,44 +607,49 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
return res;
}
/* Make sure the size is sane before we allocate. */
assert(page_size > 0 && page_size <= SAMD_PAGE_SIZE_MAX);
/* Make sure we're within the single page that comprises the User Row. */
if (startb >= (page_size * 8) || endb >= (page_size * 8)) {
LOG_ERROR("Can't modify bits outside the User Row page range");
return ERROR_FAIL;
}
uint8_t *buf = malloc(page_size);
if (!buf)
return ERROR_FAIL;
/* Make sure the size is sane. */
assert(page_size <= SAMD_PAGE_SIZE_MAX &&
page_size >= sizeof(value_input));
uint8_t buf[SAMD_PAGE_SIZE_MAX];
/* Read the user row (comprising one page) by words. */
res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
if (res != ERROR_OK)
goto out_user_row;
return res;
uint64_t value_device;
res = read_userrow(target, &value_device);
if (res != ERROR_OK)
return res;
uint64_t value_new = (value_input & value_mask) | (value_device & ~value_mask);
/* We will need to erase before writing if the new value needs a '1' in any
* position for which the current value had a '0'. Otherwise we can avoid
* erasing. */
uint32_t cur = buf_get_u32(buf, startb, endb - startb + 1);
if ((~cur) & value) {
if ((~value_device) & value_new) {
res = samd_erase_row(target, SAMD_USER_ROW);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't erase user row");
goto out_user_row;
return res;
}
}
/* Modify */
buf_set_u32(buf, startb, endb - startb + 1, value);
target_buffer_set_u64(target, buf, value_new);
/* Write the page buffer back out to the target. */
res = target_write_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
if (res != ERROR_OK)
goto out_user_row;
return res;
/* Check if we need to do manual page write commands */
res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb);
if (res == ERROR_OK)
manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0;
else {
LOG_ERROR("Read of NVM register CTRKB failed.");
return ERROR_FAIL;
}
if (manual_wp) {
/* Trigger flash write */
res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_WAP);
@@ -601,12 +657,28 @@ static int samd_modify_user_row(struct target *target, uint32_t value,
res = samd_check_error(target);
}
out_user_row:
free(buf);
return res;
}
/**
* Modifies the user row register to the given value.
* @param target Pointer to the target structure.
* @param value The value to write.
* @param startb The bit-offset by which the given value is shifted.
* @param endb The bit-offset of the last bit in value to write.
* @return On success ERROR_OK, on failure an errorcode.
*/
static int samd_modify_user_row(struct target *target, uint64_t value,
uint8_t startb, uint8_t endb)
{
uint64_t mask = 0;
int i;
for (i = startb ; i <= endb ; i++)
mask |= ((uint64_t)1) << i;
return samd_modify_user_row_masked(target, value << startb, mask);
}
static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl)
{
int res = ERROR_OK;
@@ -643,7 +715,8 @@ static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int
* corresponding to Sector 15. A '1' means unlocked and a '0' means
* locked. See Table 9-3 in the SAMD20 datasheet for more details. */
res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF,
res = samd_modify_user_row(bank->target,
set ? (uint64_t)0 : (uint64_t)UINT64_MAX,
48 + first_prot_bl, 48 + last_prot_bl);
if (res != ERROR_OK)
LOG_WARNING("SAMD: protect settings were not made persistent!");
@@ -944,6 +1017,83 @@ COMMAND_HANDLER(samd_handle_eeprom_command)
return res;
}
static COMMAND_HELPER(get_u64_from_hexarg, unsigned int num, uint64_t *value)
{
if (num >= CMD_ARGC) {
command_print(CMD_CTX, "Too few Arguments.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (strlen(CMD_ARGV[num]) >= 3 &&
CMD_ARGV[num][0] == '0' &&
CMD_ARGV[num][1] == 'x') {
char *check = NULL;
*value = strtoull(&(CMD_ARGV[num][2]), &check, 16);
if ((value == 0 && errno == ERANGE) ||
check == NULL || *check != 0) {
command_print(CMD_CTX, "Invalid 64-bit hex value in argument %d.",
num + 1);
return ERROR_COMMAND_SYNTAX_ERROR;
}
} else {
command_print(CMD_CTX, "Argument %d needs to be a hex value.", num + 1);
return ERROR_COMMAND_SYNTAX_ERROR;
}
return ERROR_OK;
}
COMMAND_HANDLER(samd_handle_nvmuserrow_command)
{
int res = ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
if (target) {
if (CMD_ARGC > 2) {
command_print(CMD_CTX, "Too much Arguments given.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (CMD_ARGC > 0) {
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted.");
return ERROR_TARGET_NOT_HALTED;
}
uint64_t mask;
res = samd_get_reservedmask(target, &mask);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't determine the mask for reserved bits.");
return ERROR_FAIL;
}
mask &= NVMUSERROW_LOCKBIT_MASK;
uint64_t value;
res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 0, &value);
if (res != ERROR_OK)
return res;
if (CMD_ARGC == 2) {
uint64_t mask_temp;
res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 1, &mask_temp);
if (res != ERROR_OK)
return res;
mask &= mask_temp;
}
res = samd_modify_user_row_masked(target, value, mask);
if (res != ERROR_OK)
return res;
}
/* read register */
uint64_t value;
res = read_userrow(target, &value);
if (res == ERROR_OK)
command_print(CMD_CTX, "NVMUSERROW: 0x%016"PRIX64, value);
else
LOG_ERROR("NVMUSERROW could not be read.");
}
return res;
}
COMMAND_HANDLER(samd_handle_bootloader_command)
{
int res = ERROR_OK;
@@ -1049,29 +1199,29 @@ static const struct command_registration at91samd_exec_command_handlers[] = {
.name = "dsu_reset_deassert",
.handler = samd_handle_reset_deassert,
.mode = COMMAND_EXEC,
.help = "deasert internal reset held by DSU"
.help = "Deasert internal reset held by DSU."
},
{
.name = "info",
.handler = samd_handle_info_command,
.mode = COMMAND_EXEC,
.help = "Print information about the current at91samd chip"
.help = "Print information about the current at91samd chip "
"and its flash configuration.",
},
{
.name = "chip-erase",
.handler = samd_handle_chip_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase the entire Flash by using the Chip"
.help = "Erase the entire Flash by using the Chip-"
"Erase feature in the Device Service Unit (DSU).",
},
{
.name = "set-security",
.handler = samd_handle_set_security_command,
.mode = COMMAND_EXEC,
.help = "Secure the chip's Flash by setting the Security Bit."
"This makes it impossible to read the Flash contents."
"The only way to undo this is to issue the chip-erase"
.help = "Secure the chip's Flash by setting the Security Bit. "
"This makes it impossible to read the Flash contents. "
"The only way to undo this is to issue the chip-erase "
"command.",
},
{
@@ -1079,9 +1229,9 @@ static const struct command_registration at91samd_exec_command_handlers[] = {
.usage = "[size_in_bytes]",
.handler = samd_handle_eeprom_command,
.mode = COMMAND_EXEC,
.help = "Show or set the EEPROM size setting, stored in the User Row."
"Please see Table 20-3 of the SAMD20 datasheet for allowed values."
"Changes are stored immediately but take affect after the MCU is"
.help = "Show or set the EEPROM size setting, stored in the User Row. "
"Please see Table 20-3 of the SAMD20 datasheet for allowed values. "
"Changes are stored immediately but take affect after the MCU is "
"reset.",
},
{
@@ -1089,11 +1239,22 @@ static const struct command_registration at91samd_exec_command_handlers[] = {
.usage = "[size_in_bytes]",
.handler = samd_handle_bootloader_command,
.mode = COMMAND_EXEC,
.help = "Show or set the bootloader size, stored in the User Row."
"Please see Table 20-2 of the SAMD20 datasheet for allowed values."
"Changes are stored immediately but take affect after the MCU is"
.help = "Show or set the bootloader size, stored in the User Row. "
"Please see Table 20-2 of the SAMD20 datasheet for allowed values. "
"Changes are stored immediately but take affect after the MCU is "
"reset.",
},
{
.name = "nvmuserrow",
.usage = "[value] [mask]",
.handler = samd_handle_nvmuserrow_command,
.mode = COMMAND_EXEC,
.help = "Show or set the nvmuserrow register. It is 64 bit wide "
"and located at address 0x804000. Use the optional mask argument "
"to prevent changes at positions where the bitvalue is zero. "
"For security reasons the lock- and reserved-bits are masked out "
"in background and therefore cannot be changed.",
},
COMMAND_REGISTRATION_DONE
};
+1
View File
@@ -898,4 +898,5 @@ struct flash_driver ath79_flash = {
.erase_check = ath79_flash_blank_check,
.protect_check = ath79_protect_check,
.info = get_ath79_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -739,4 +739,5 @@ struct flash_driver atsamv_flash = {
.erase_check = default_flash_blank_check,
.protect_check = samv_protect_check,
.info = samv_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -487,4 +487,5 @@ struct flash_driver avr_flash = {
.erase_check = default_flash_blank_check,
.protect_check = avrf_protect_check,
.info = avrf_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+554
View File
@@ -0,0 +1,554 @@
/***************************************************************************
* 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");
free(new_buffer);
return ERROR_FAIL;
}
}
if (post_bytes) {
if (target_read_u32(target, post_address, &post_word)) {
LOG_ERROR("Memory read failed");
free(new_buffer);
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]);
if (retval != ERROR_OK)
return retval;
}
/* 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,
};
+1
View File
@@ -3128,4 +3128,5 @@ struct flash_driver cfi_flash = {
.erase_check = default_flash_blank_check,
.protect_check = cfi_protect_check,
.info = get_cfi_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+46 -7
View File
@@ -171,6 +171,31 @@ int flash_get_bank_count(void)
return i;
}
void default_flash_free_driver_priv(struct flash_bank *bank)
{
free(bank->driver_priv);
bank->driver_priv = NULL;
}
void flash_free_all_banks(void)
{
struct flash_bank *bank = flash_banks;
while (bank) {
struct flash_bank *next = bank->next;
if (bank->driver->free_driver_priv)
bank->driver->free_driver_priv(bank);
else
LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name);
free(bank->name);
free(bank->sectors);
free(bank->prot_blocks);
free(bank);
bank = next;
}
flash_banks = NULL;
}
struct flash_bank *get_flash_bank_by_name_noprobe(const char *name)
{
unsigned requested = get_flash_name_index(name);
@@ -399,18 +424,21 @@ static int flash_iterate_address_range_inner(struct target *target,
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
addr -= c->base;
last_addr -= c->base;
if (c->prot_blocks == NULL || c->num_prot_blocks == 0) {
/* flash driver does not define protect blocks, use sectors instead */
iterate_protect_blocks = false;
}
if (iterate_protect_blocks && c->prot_blocks && c->num_prot_blocks) {
if (iterate_protect_blocks) {
block_array = c->prot_blocks;
num_blocks = c->num_prot_blocks;
} else {
block_array = c->sectors;
num_blocks = c->num_sectors;
iterate_protect_blocks = false;
}
addr -= c->base;
last_addr -= c->base;
for (i = 0; i < num_blocks; i++) {
struct flash_sector *f = &block_array[i];
@@ -601,7 +629,7 @@ int flash_write_unlock(struct target *target, struct image *image,
uint32_t buffer_size;
uint8_t *buffer;
int section_last;
uint32_t run_address = sections[section]->base_address + section_offset;
target_addr_t run_address = sections[section]->base_address + section_offset;
uint32_t run_size = sections[section]->size - section_offset;
int pad_bytes = 0;
@@ -617,7 +645,7 @@ int flash_write_unlock(struct target *target, struct image *image,
if (retval != ERROR_OK)
goto done;
if (c == NULL) {
LOG_WARNING("no flash bank found for address %" PRIx32, run_address);
LOG_WARNING("no flash bank found for address " TARGET_ADDR_FMT, run_address);
section++; /* and skip it */
section_offset = 0;
continue;
@@ -652,7 +680,18 @@ int flash_write_unlock(struct target *target, struct image *image,
/* if we have multiple sections within our image,
* flash programming could fail due to alignment issues
* attempt to rebuild a consecutive buffer for the flash loader */
pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size);
target_addr_t run_next_addr = run_address + run_size;
if (sections[section_last + 1]->base_address < run_next_addr) {
LOG_ERROR("Section at " TARGET_ADDR_FMT
" overlaps section ending at " TARGET_ADDR_FMT,
sections[section_last + 1]->base_address,
run_next_addr);
LOG_ERROR("Flash write aborted.");
retval = ERROR_FAIL;
goto done;
}
pad_bytes = sections[section_last + 1]->base_address - run_next_addr;
padding[section_last] = pad_bytes;
run_size += sections[++section_last]->size;
run_size += pad_bytes;
+8 -1
View File
@@ -76,7 +76,7 @@ struct flash_sector {
* per-bank basis, if required.
*/
struct flash_bank {
const char *name;
char *name;
struct target *target; /**< Target to which this bank belongs. */
@@ -153,8 +153,15 @@ int flash_write(struct target *target,
* This routine must be called when the system may modify the status.
*/
void flash_set_dirty(void);
/** @returns The number of flash banks currently defined. */
int flash_get_bank_count(void);
/** Deallocates bank->driver_priv */
void default_flash_free_driver_priv(struct flash_bank *bank);
/** Deallocates all flash banks */
void flash_free_all_banks(void);
/**
* Provides default read implementation for flash memory.
* @param bank The bank to read.
+8
View File
@@ -209,6 +209,14 @@ struct flash_driver {
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*auto_probe)(struct flash_bank *bank);
/**
* Deallocates private driver structures.
* Use default_flash_free_driver_priv() to simply free(bank->driver_priv)
*
* @param bank - the bank being destroyed
*/
void (*free_driver_priv)(struct flash_bank *bank);
};
#define FLASH_BANK_COMMAND_HANDLER(name) \
+4
View 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;
@@ -55,6 +56,7 @@ extern struct flash_driver numicro_flash;
extern struct flash_driver ocl_flash;
extern struct flash_driver pic32mx_flash;
extern struct flash_driver psoc4_flash;
extern struct flash_driver psoc6_flash;
extern struct flash_driver sim3x_flash;
extern struct flash_driver stellaris_flash;
extern struct flash_driver stm32f1x_flash;
@@ -88,6 +90,7 @@ static struct flash_driver *flash_drivers[] = {
&ath79_flash,
&atsamv_flash,
&avr_flash,
&bluenrgx_flash,
&cfi_flash,
&dsp5680xx_flash,
&efm32_flash,
@@ -112,6 +115,7 @@ static struct flash_driver *flash_drivers[] = {
&ocl_flash,
&pic32mx_flash,
&psoc4_flash,
&psoc6_flash,
&sim3x_flash,
&stellaris_flash,
&stm32f1x_flash,
+146 -125
View File
@@ -38,19 +38,8 @@
#include <target/armv7m.h>
#include <target/cortex_m.h>
/* keep family IDs in decimal */
#define EFM_FAMILY_ID_GECKO 71
#define EFM_FAMILY_ID_GIANT_GECKO 72
#define EFM_FAMILY_ID_TINY_GECKO 73
#define EFM_FAMILY_ID_LEOPARD_GECKO 74
#define EFM_FAMILY_ID_WONDER_GECKO 75
#define EFM_FAMILY_ID_ZERO_GECKO 76
#define EFM_FAMILY_ID_HAPPY_GECKO 77
#define EZR_FAMILY_ID_WONDER_GECKO 120
#define EZR_FAMILY_ID_LEOPARD_GECKO 121
#define EZR_FAMILY_ID_HAPPY_GECKO 122
#define EFR_FAMILY_ID_MIGHTY_GECKO 16
#define EFR_FAMILY_ID_BLUE_GECKO 20
#define EFM32_FLASH_ERASE_TMO 100
#define EFM32_FLASH_WDATAREADY_TMO 100
@@ -65,7 +54,7 @@
#define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000)
#define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000)
/* PAGE_SIZE is only present in Leopard, Giant and Wonder Gecko MCUs */
/* PAGE_SIZE is not present in Zero, Happy and the original Gecko MCU */
#define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7)
#define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8)
#define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa)
@@ -74,7 +63,7 @@
#define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff)
#define EFM32_MSC_REGBASE 0x400c0000
#define EFR32_MSC_REGBASE 0x400e0000
#define EFM32_MSC_REGBASE_SERIES1 0x400e0000
#define EFM32_MSC_REG_WRITECTRL 0x008
#define EFM32_MSC_WRITECTRL_WREN_MASK 0x1
#define EFM32_MSC_REG_WRITECMD 0x00c
@@ -91,9 +80,24 @@
#define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10
#define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20
#define EFM32_MSC_REG_LOCK 0x03c
#define EFR32_MSC_REG_LOCK 0x040
#define EFM32_MSC_REG_LOCK_SERIES1 0x040
#define EFM32_MSC_LOCK_LOCKKEY 0x1b71
struct efm32_family_data {
int family_id;
const char *name;
/* EFM32 series (EFM32LG995F is the "old" series 0, while EFR32MG12P132
is the "new" series 1). Determines location of MSC registers. */
int series;
/* Page size in bytes, or 0 to read from EFM32_MSC_DI_PAGE_SIZE */
int page_size;
/* MSC register base address, or 0 to use default */
uint32_t msc_regbase;
};
struct efm32x_flash_bank {
int probed;
uint32_t lb_page[LOCKBITS_PAGE_SZ/4];
@@ -102,6 +106,7 @@ struct efm32x_flash_bank {
};
struct efm32_info {
const struct efm32_family_data *family_data;
uint16_t flash_sz_kib;
uint16_t ram_sz_kib;
uint16_t part_num;
@@ -110,6 +115,64 @@ struct efm32_info {
uint16_t page_size;
};
static const struct efm32_family_data efm32_families[] = {
{ 16, "EFR32MG1P Mighty", .series = 1 },
{ 17, "EFR32MG1B Mighty", .series = 1 },
{ 18, "EFR32MG1V Mighty", .series = 1 },
{ 19, "EFR32MG1P Blue", .series = 1 },
{ 20, "EFR32MG1B Blue", .series = 1 },
{ 21, "EFR32MG1V Blue", .series = 1 },
{ 25, "EFR32FG1P Flex", .series = 1 },
{ 26, "EFR32FG1B Flex", .series = 1 },
{ 27, "EFR32FG1V Flex", .series = 1 },
{ 28, "EFR32MG2P Mighty", .series = 1 },
{ 29, "EFR32MG2B Mighty", .series = 1 },
{ 30, "EFR32MG2V Mighty", .series = 1 },
{ 31, "EFR32BG12P Blue", .series = 1 },
{ 32, "EFR32BG12B Blue", .series = 1 },
{ 33, "EFR32BG12V Blue", .series = 1 },
{ 37, "EFR32FG12P Flex", .series = 1 },
{ 38, "EFR32FG12B Flex", .series = 1 },
{ 39, "EFR32FG12V Flex", .series = 1 },
{ 40, "EFR32MG13P Mighty", .series = 1 },
{ 41, "EFR32MG13B Mighty", .series = 1 },
{ 42, "EFR32MG13V Mighty", .series = 1 },
{ 43, "EFR32BG13P Blue", .series = 1 },
{ 44, "EFR32BG13B Blue", .series = 1 },
{ 45, "EFR32BG13V Blue", .series = 1 },
{ 49, "EFR32FG13P Flex", .series = 1 },
{ 50, "EFR32FG13B Flex", .series = 1 },
{ 51, "EFR32FG13V Flex", .series = 1 },
{ 52, "EFR32MG14P Mighty", .series = 1 },
{ 53, "EFR32MG14B Mighty", .series = 1 },
{ 54, "EFR32MG14V Mighty", .series = 1 },
{ 55, "EFR32BG14P Blue", .series = 1 },
{ 56, "EFR32BG14B Blue", .series = 1 },
{ 57, "EFR32BG14V Blue", .series = 1 },
{ 61, "EFR32FG14P Flex", .series = 1 },
{ 62, "EFR32FG14B Flex", .series = 1 },
{ 63, "EFR32FG14V Flex", .series = 1 },
{ 71, "EFM32G", .series = 0, .page_size = 512 },
{ 72, "EFM32GG Giant", .series = 0 },
{ 73, "EFM32TG Tiny", .series = 0, .page_size = 512 },
{ 74, "EFM32LG Leopard", .series = 0 },
{ 75, "EFM32WG Wonder", .series = 0 },
{ 76, "EFM32ZG Zero", .series = 0, .page_size = 1024 },
{ 77, "EFM32HG Happy", .series = 0, .page_size = 1024 },
{ 81, "EFM32PG1B Pearl", .series = 1 },
{ 83, "EFM32JG1B Jade", .series = 1 },
{ 85, "EFM32PG12B Pearl", .series = 1 },
{ 87, "EFM32JG12B Jade", .series = 1 },
{ 89, "EFM32PG13B Pearl", .series = 1 },
{ 91, "EFM32JG13B Jade", .series = 1 },
{ 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 },
{ 103, "EFM32TG11B Tiny", .series = 1 },
{ 120, "EZR32WG Wonder", .series = 0 },
{ 121, "EZR32LG Leopard", .series = 0 },
{ 122, "EZR32HG Happy", .series = 0, .page_size = 1024 },
};
static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count);
@@ -200,51 +263,33 @@ static int efm32x_read_info(struct flash_bank *bank,
if (ERROR_OK != ret)
return ret;
if (EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family ||
EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) {
efm32x_info->reg_base = EFR32_MSC_REGBASE;
efm32x_info->reg_lock = EFR32_MSC_REG_LOCK;
} else {
efm32x_info->reg_base = EFM32_MSC_REGBASE;
efm32x_info->reg_lock = EFM32_MSC_REG_LOCK;
for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) {
if (efm32_families[i].family_id == efm32_info->part_family)
efm32_info->family_data = &efm32_families[i];
}
if (EFM_FAMILY_ID_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family)
efm32_info->page_size = 512;
else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family ||
EZR_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family)
efm32_info->page_size = 1024;
else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) {
if (efm32_info->prod_rev >= 18) {
uint8_t pg_size = 0;
ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE,
&pg_size);
if (ERROR_OK != ret)
return ret;
if (efm32_info->family_data == NULL) {
LOG_ERROR("Unknown MCU family %d", efm32_info->part_family);
return ERROR_FAIL;
}
efm32_info->page_size = (1 << ((pg_size+10) & 0xff));
} else {
/* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid
for MCUs with PROD_REV < 18 */
if (efm32_info->flash_sz_kib < 512)
efm32_info->page_size = 2048;
else
efm32_info->page_size = 4096;
}
switch (efm32_info->family_data->series) {
case 0:
efm32x_info->reg_base = EFM32_MSC_REGBASE;
efm32x_info->reg_lock = EFM32_MSC_REG_LOCK;
break;
case 1:
efm32x_info->reg_base = EFM32_MSC_REGBASE_SERIES1;
efm32x_info->reg_lock = EFM32_MSC_REG_LOCK_SERIES1;
break;
}
if ((2048 != efm32_info->page_size) &&
(4096 != efm32_info->page_size)) {
LOG_ERROR("Invalid page size %u", efm32_info->page_size);
return ERROR_FAIL;
}
} else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family ||
EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family ||
EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family ||
EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family ||
EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) {
if (efm32_info->family_data->msc_regbase != 0)
efm32x_info->reg_base = efm32_info->family_data->msc_regbase;
if (efm32_info->family_data->page_size != 0) {
efm32_info->page_size = efm32_info->family_data->page_size;
} else {
uint8_t pg_size = 0;
ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE,
&pg_size);
@@ -252,13 +297,25 @@ static int efm32x_read_info(struct flash_bank *bank,
return ret;
efm32_info->page_size = (1 << ((pg_size+10) & 0xff));
if (2048 != efm32_info->page_size) {
if (efm32_info->part_family == EFM_FAMILY_ID_GIANT_GECKO ||
efm32_info->part_family == EFM_FAMILY_ID_LEOPARD_GECKO) {
/* Giant or Leopard Gecko */
if (efm32_info->prod_rev < 18) {
/* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid
for MCUs with PROD_REV < 18 */
if (efm32_info->flash_sz_kib < 512)
efm32_info->page_size = 2048;
else
efm32_info->page_size = 4096;
}
}
if ((efm32_info->page_size != 2048) &&
(efm32_info->page_size != 4096)) {
LOG_ERROR("Invalid page size %u", efm32_info->page_size);
return ERROR_FAIL;
}
} else {
LOG_ERROR("Unknown MCU family %d", efm32_info->part_family);
return ERROR_FAIL;
}
return ERROR_OK;
@@ -270,71 +327,10 @@ static int efm32x_read_info(struct flash_bank *bank,
static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size)
{
int printed = 0;
printed = snprintf(buf, buf_size, "%s Gecko, rev %d",
info->family_data->name, info->prod_rev);
switch (info->part_family) {
case EZR_FAMILY_ID_WONDER_GECKO:
case EZR_FAMILY_ID_LEOPARD_GECKO:
case EZR_FAMILY_ID_HAPPY_GECKO:
printed = snprintf(buf, buf_size, "EZR32 ");
break;
case EFR_FAMILY_ID_MIGHTY_GECKO:
case EFR_FAMILY_ID_BLUE_GECKO:
printed = snprintf(buf, buf_size, "EFR32 ");
break;
default:
printed = snprintf(buf, buf_size, "EFM32 ");
}
buf += printed;
buf_size -= printed;
if (0 >= buf_size)
return ERROR_BUF_TOO_SMALL;
switch (info->part_family) {
case EFM_FAMILY_ID_GECKO:
printed = snprintf(buf, buf_size, "Gecko");
break;
case EFM_FAMILY_ID_GIANT_GECKO:
printed = snprintf(buf, buf_size, "Giant Gecko");
break;
case EFM_FAMILY_ID_TINY_GECKO:
printed = snprintf(buf, buf_size, "Tiny Gecko");
break;
case EFM_FAMILY_ID_LEOPARD_GECKO:
case EZR_FAMILY_ID_LEOPARD_GECKO:
printed = snprintf(buf, buf_size, "Leopard Gecko");
break;
case EFM_FAMILY_ID_WONDER_GECKO:
case EZR_FAMILY_ID_WONDER_GECKO:
printed = snprintf(buf, buf_size, "Wonder Gecko");
break;
case EFM_FAMILY_ID_ZERO_GECKO:
printed = snprintf(buf, buf_size, "Zero Gecko");
break;
case EFM_FAMILY_ID_HAPPY_GECKO:
case EZR_FAMILY_ID_HAPPY_GECKO:
printed = snprintf(buf, buf_size, "Happy Gecko");
break;
case EFR_FAMILY_ID_BLUE_GECKO:
printed = snprintf(buf, buf_size, "Blue Gecko");
break;
case EFR_FAMILY_ID_MIGHTY_GECKO:
printed = snprintf(buf, buf_size, "Mighty Gecko");
break;
}
buf += printed;
buf_size -= printed;
if (0 >= buf_size)
return ERROR_BUF_TOO_SMALL;
printed = snprintf(buf, buf_size, " - Rev: %d", info->prod_rev);
buf += printed;
buf_size -= printed;
if (0 >= buf_size)
if (printed >= buf_size)
return ERROR_BUF_TOO_SMALL;
return ERROR_OK;
@@ -522,7 +518,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
}
}
/* also, read ULW, DLW and MLW */
/* also, read ULW, DLW, MLW, ALW and CLW words */
/* ULW, word 126 */
ptr = efm32x_info->lb_page + 126;
@@ -540,7 +536,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
return ret;
}
/* MLW, word 125, present in GG and LG */
/* MLW, word 125, present in GG, LG, PG, JG, EFR32 */
ptr = efm32x_info->lb_page + 125;
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr);
if (ERROR_OK != ret) {
@@ -548,6 +544,30 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
return ret;
}
/* ALW, word 124, present in GG, LG, PG, JG, EFR32 */
ptr = efm32x_info->lb_page + 124;
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+124*4, ptr);
if (ERROR_OK != ret) {
LOG_ERROR("Failed to read ALW");
return ret;
}
/* CLW1, word 123, present in EFR32 */
ptr = efm32x_info->lb_page + 123;
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+123*4, ptr);
if (ERROR_OK != ret) {
LOG_ERROR("Failed to read CLW1");
return ret;
}
/* CLW0, word 122, present in GG, LG, PG, JG, EFR32 */
ptr = efm32x_info->lb_page + 122;
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+122*4, ptr);
if (ERROR_OK != ret) {
LOG_ERROR("Failed to read CLW0");
return ret;
}
return ERROR_OK;
}
@@ -1113,4 +1133,5 @@ struct flash_driver efm32_flash = {
.erase_check = default_flash_blank_check,
.protect_check = efm32x_protect_check,
.info = get_efm32x_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -941,4 +941,5 @@ struct flash_driver em357_flash = {
.auto_probe = em357_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = em357_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+2 -1
View File
@@ -136,5 +136,6 @@ struct flash_driver faux_flash = {
.auto_probe = faux_probe,
.erase_check = default_flash_blank_check,
.protect_check = faux_protect_check,
.info = faux_info
.info = faux_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -997,4 +997,5 @@ struct flash_driver fm3_flash = {
.probe = fm3_probe,
.auto_probe = fm3_auto_probe,
.erase_check = default_flash_blank_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -719,4 +719,5 @@ struct flash_driver fm4_flash = {
.erase = fm4_flash_erase,
.erase_check = default_flash_blank_check,
.write = fm4_flash_write,
.free_driver_priv = default_flash_free_driver_priv,
};
+2 -1
View File
@@ -432,5 +432,6 @@ struct flash_driver jtagspi_flash = {
.auto_probe = jtagspi_probe,
.erase_check = default_flash_blank_check,
.protect_check = jtagspi_protect_check,
.info = jtagspi_info
.info = jtagspi_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+2 -2
View File
@@ -478,14 +478,13 @@ int kinetis_ke_stop_watchdog(struct target *target)
watchdog_algorithm->address, 0, 100000, &armv7m_info);
if (retval != ERROR_OK) {
LOG_ERROR("Error executing Kinetis KE watchdog algorithm");
retval = ERROR_FAIL;
} else {
LOG_INFO("Watchdog stopped");
}
target_free_working_area(target, watchdog_algorithm);
return ERROR_OK;
return retval;
}
COMMAND_HANDLER(kinetis_ke_disable_wdog_handler)
@@ -1311,4 +1310,5 @@ struct flash_driver kinetis_ke_flash = {
.erase_check = kinetis_ke_blank_check,
.protect_check = kinetis_ke_protect_check,
.info = kinetis_ke_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1579,4 +1579,5 @@ struct flash_driver lpc2000_flash = {
.erase_check = lpc2000_erase_check,
.protect_check = lpc2000_protect_check,
.info = get_lpc2000_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -433,4 +433,5 @@ struct flash_driver lpc288x_flash = {
.auto_probe = lpc288x_probe,
.erase_check = lpc288x_erase_check,
.protect_check = lpc288x_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1598,4 +1598,5 @@ struct flash_driver lpc2900_flash = {
.auto_probe = lpc2900_probe,
.erase_check = lpc2900_erase_check,
.protect_check = lpc2900_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -942,4 +942,5 @@ struct flash_driver lpcspifi_flash = {
.erase_check = default_flash_blank_check,
.protect_check = lpcspifi_protect_check,
.info = get_lpcspifi_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -633,4 +633,5 @@ struct flash_driver mdr_flash = {
.erase_check = default_flash_blank_check,
.protect_check = mdr_protect_check,
.info = get_mdr_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -955,4 +955,5 @@ struct flash_driver mrvlqspi_flash = {
.erase_check = mrvlqspi_flash_erase_check,
.protect_check = mrvlqspi_protect_check,
.info = mrvlqspi_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1741,4 +1741,5 @@ struct flash_driver niietcm4_flash = {
.erase_check = default_flash_blank_check,
.protect_check = niietcm4_protect_check,
.info = get_niietcm4_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+6 -5
View File
@@ -155,6 +155,11 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256),
NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256),
/* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
with built-in jlink seem to use engineering samples not listed
in the nRF51 Series Compatibility Matrix V1.0. */
NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
/* nRF51822 Devices (IC rev 2). */
NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256),
NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256),
@@ -175,6 +180,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128),
NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256),
NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256),
NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256),
/* nRF51422 Devices (IC rev 1). */
NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256),
@@ -198,11 +204,6 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
/* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
with built-in jlink seem to use engineering samples not listed
in the nRF51 Series Compatibility Matrix V1.0. */
NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256),
};
static int nrf5_bank_is_probed(struct flash_bank *bank)
+1
View File
@@ -1880,4 +1880,5 @@ struct flash_driver numicro_flash = {
.auto_probe = numicro_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = numicro_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -340,4 +340,5 @@ struct flash_driver ocl_flash = {
.erase_check = ocl_erase_check,
.protect_check = ocl_protect_check,
.auto_probe = ocl_auto_probe,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -980,4 +980,5 @@ struct flash_driver pic32mx_flash = {
.erase_check = default_flash_blank_check,
.protect_check = pic32mx_protect_check,
.info = pic32mx_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+409 -254
View File
@@ -41,24 +41,67 @@
Document Number: 001-87197 Rev. *B Revised August 29, 2013
PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM
Document No. 001-85634 Rev. *C March 25, 2014
Document No. 001-85634 Rev. *E June 28, 2016
PSoC(R) 4 Registers TRM Spec.
Document No. 001-85847 Rev. *A June 25, 2013
PSoC 4000 Family PSoC(R) 4 Technical Reference Manual
Document No. 001-89309 Rev. *B May 9, 2016
PSoC 41XX_BLE/42XX_BLE Family PSoC 4 BLE Architecture TRM
Document No. 001-92738 Rev. *C February 12, 2016
PSoC 4200L Family PSoC 4 Architecture TRM
Document No. 001-97952 Rev. *A December 15, 2015
PSoC 4200L Family PSoC 4 Registers TRM
Document No. 001-98126 Rev. *A December 16, 2015
PSoC 4100M/4200M Family PSoC 4 Architecture TRM
Document No. 001-95223 Rev. *B July 29, 2015
PSoC 4100S Family PSoC 4 Architecture TRM
Document No. 002-10621 Rev. *A July 29, 2016
PSoC 4100S Family PSoC 4 Registers TRM
Document No. 002-10523 Rev. *A July 20, 2016
PSoC Analog Coprocessor Architecture TRM
Document No. 002-10404 Rev. ** December 18, 2015
CY8C4Axx PSoC Analog Coprocessor Registers TRM
Document No. 002-10405 Rev. ** December 18, 2015
CY8C41xx, CY8C42xx Programming Specifications
Document No. 001-81799 Rev. *C March 4, 2014
CYBL10x6x, CY8C4127_BL, CY8C4247_BL Programming Specifications
Document No. 001-91508 Rev. *B September 22, 2014
http://dmitry.gr/index.php?r=05.Projects&proj=24.%20PSoC4%20confidential
*/
/* register locations */
#define PSOC4_CPUSS_SYSREQ 0x40000004
#define PSOC4_CPUSS_SYSARG 0x40000008
#define PSOC4_TEST_MODE 0x40030014
#define PSOC4_SPCIF_GEOMETRY 0x400E0000
#define PSOC4_SFLASH_MACRO0 0x0FFFF000
#define PSOC4_CPUSS_SYSREQ_LEGACY 0x40000004
#define PSOC4_CPUSS_SYSARG_LEGACY 0x40000008
#define PSOC4_SPCIF_GEOMETRY_LEGACY 0x400E0000
#define PSOC4_CPUSS_SYSREQ_NEW 0x40100004
#define PSOC4_CPUSS_SYSARG_NEW 0x40100008
#define PSOC4_SPCIF_GEOMETRY_NEW 0x40110000
#define PSOC4_TEST_MODE 0x40030014
#define PSOC4_ROMTABLE_PID0 0xF0000FE0
#define PSOC4_SFLASH_MACRO 0x0ffff000
/* constants */
#define PSOC4_SFLASH_MACRO_SIZE 0x800
#define PSOC4_ROWS_PER_MACRO 512
#define PSOC4_SROM_KEY1 0xb6
#define PSOC4_SROM_KEY2 0xd3
#define PSOC4_SROM_SYSREQ_BIT (1<<31)
@@ -66,6 +109,10 @@
#define PSOC4_SROM_PRIVILEGED_BIT (1<<28)
#define PSOC4_SROM_STATUS_SUCCEEDED 0xa0000000
#define PSOC4_SROM_STATUS_FAILED 0xf0000000
#define PSOC4_SROM_STATUS_MASK 0xf0000000
/* not documented in any TRM */
#define PSOC4_SROM_ERR_IMO_NOT_IMPLEM 0xf0000013
#define PSOC4_CMD_GET_SILICON_ID 0
#define PSOC4_CMD_LOAD_LATCH 4
@@ -74,76 +121,60 @@
#define PSOC4_CMD_ERASE_ALL 0xa
#define PSOC4_CMD_CHECKSUM 0xb
#define PSOC4_CMD_WRITE_PROTECTION 0xd
#define PSOC4_CMD_SET_IMO48 0x15
#define PSOC4_CMD_WRITE_SFLASH_ROW 0x18
#define PSOC4_CHIP_PROT_VIRGIN 0x0
#define PSOC4_CHIP_PROT_OPEN 0x1
#define PSOC4_CHIP_PROT_PROTECTED 0x2
#define PSOC4_CHIP_PROT_KILL 0x4
#define PSOC4_ROMTABLE_DESIGNER_CHECK 0xb4
struct psoc4_chip_details {
#define PSOC4_FAMILY_FLAG_LEGACY 1
struct psoc4_chip_family {
uint16_t id;
const char *type;
const char *package;
uint32_t flash_size_in_kb;
const char *name;
uint32_t flags;
};
/* list of PSoC 4 chips
* flash_size_in_kb is not necessary as it can be decoded from SPCIF_GEOMETRY
*/
const struct psoc4_chip_details psoc4_devices[] = {
/* 4200 series */
{ 0x04A6, "CY8C4245PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
{ 0x04B6, "CY8C4245LQI-483", "QFN-40", .flash_size_in_kb = 32 },
{ 0x04C8, "CY8C4245AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
{ 0x04FB, "CY8C4245AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
{ 0x04F0, "CY8C4244PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x04F1, "CY8C4244PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x04F6, "CY8C4244LQI-443", "QFN-40", .flash_size_in_kb = 16 },
{ 0x04FA, "CY8C4244AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
/* 4100 series */
{ 0x0410, "CY8C4124PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x0411, "CY8C4124PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x041C, "CY8C4124LQI-443", "QFN-40", .flash_size_in_kb = 16 },
{ 0x041A, "CY8C4124AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
{ 0x041B, "CY8C4125AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
{ 0x0412, "CY8C4125PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
{ 0x0417, "CY8C4125LQI-483", "QFN-40", .flash_size_in_kb = 32 },
{ 0x0416, "CY8C4125AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
/* CCG1 series */
{ 0x0490, "CYPD1103-35FNXI", "CSP-35", .flash_size_in_kb = 32 },
{ 0x0489, "CYPD1121-40LQXI", "QFN-40", .flash_size_in_kb = 32 },
{ 0x048A, "CYPD1122-40LQXI", "QFN-40", .flash_size_in_kb = 32 },
{ 0x0491, "CYPD1131-35FNXI", "CSP-35", .flash_size_in_kb = 32 },
{ 0x0498, "CYPD1132-16SXI", "SOIC-16", .flash_size_in_kb = 32 },
{ 0x0481, "CYPD1134-28PVXI", "SSOP-28", .flash_size_in_kb = 32 },
{ 0x048B, "CYPD1134-40LQXI", "QFN-40", .flash_size_in_kb = 32 },
const struct psoc4_chip_family psoc4_families[] = {
{ 0x93, "PSoC4100/4200", .flags = PSOC4_FAMILY_FLAG_LEGACY },
{ 0x9A, "PSoC4000", .flags = 0 },
{ 0x9E, "PSoC/PRoC BLE (119E)", .flags = 0 },
{ 0xA0, "PSoC4200L", .flags = 0 },
{ 0xA1, "PSoC4100M/4200M", .flags = 0 },
{ 0xA3, "PSoC/PRoC BLE (11A3)", .flags = 0 },
{ 0xA9, "PSoC4000S", .flags = 0 },
{ 0xAA, "PSoC/PRoC BLE (11AA)", .flags = 0 },
{ 0xAB, "PSoC4100S", .flags = 0 },
{ 0xAC, "PSoC Analog Coprocessor", .flags = 0 },
{ 0, "Unknown", .flags = 0 }
};
struct psoc4_flash_bank {
uint32_t row_size;
uint32_t user_bank_size;
int probed;
uint32_t silicon_id;
uint8_t chip_protection;
int num_macros;
bool probed;
uint8_t cmd_program_row;
uint16_t family_id;
bool legacy_family;
uint32_t cpuss_sysreq_addr;
uint32_t cpuss_sysarg_addr;
uint32_t spcif_geometry_addr;
};
static const struct psoc4_chip_details *psoc4_details_by_id(uint32_t silicon_id)
static const struct psoc4_chip_family *psoc4_family_by_id(uint16_t family_id)
{
const struct psoc4_chip_details *p = psoc4_devices;
unsigned int i;
uint16_t id = silicon_id >> 16; /* ignore die revision */
for (i = 0; i < sizeof(psoc4_devices)/sizeof(psoc4_devices[0]); i++, p++) {
if (p->id == id)
return p;
}
LOG_DEBUG("Unknown PSoC 4 device silicon id 0x%08" PRIx32 ".", silicon_id);
return NULL;
const struct psoc4_chip_family *p = psoc4_families;
while (p->id && p->id != family_id)
p++;
return p;
}
static const char *psoc4_decode_chip_protection(uint8_t protection)
@@ -176,7 +207,9 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank));
bank->driver_priv = psoc4_info;
bank->default_padded_value = bank->erased_value = 0x00;
psoc4_info->user_bank_size = bank->size;
psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW;
return ERROR_OK;
}
@@ -189,9 +222,14 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
* Otherwise address of memory parameter block is set in CPUSS_SYSARG
* and the first parameter is written to the first word of parameter block
*/
static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
uint32_t *sysreq_params, uint32_t sysreq_params_size)
static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd,
uint16_t cmd_param,
uint32_t *sysreq_params, uint32_t sysreq_params_size,
uint32_t *sysarg_out)
{
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
struct working_area *sysreq_wait_algorithm;
struct working_area *sysreq_mem;
@@ -212,8 +250,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4;
/* stack must be aligned */
const int stack_size = 196;
/* tested stack sizes on PSoC 4:
const int stack_size = 256;
/* tested stack sizes on PSoC4200:
ERASE_ALL 144
PROGRAM_ROW 112
other sysreq 68
@@ -238,6 +276,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
}
if (sysreq_params_size) {
LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " size %" PRIu32,
cmd, cmd_param, param1, sysreq_params_size);
/* Allocate memory for sysreq_params */
retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem);
if (retval != ERROR_OK) {
@@ -250,21 +290,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
}
/* Write sysreq_params */
sysreq_params[0] = param1;
target_buffer_set_u32(target, (uint8_t *)sysreq_params, param1);
retval = target_write_buffer(target, sysreq_mem->address,
sysreq_params_size, (uint8_t *)sysreq_params);
if (retval != ERROR_OK)
goto cleanup_mem;
/* Set address of sysreq parameters block */
retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, sysreq_mem->address);
retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, sysreq_mem->address);
if (retval != ERROR_OK)
goto cleanup_mem;
} else {
/* Sysreq without memory block of parameters */
LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32,
cmd, cmd_param, param1);
/* Set register parameter */
retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, param1);
retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, param1);
if (retval != ERROR_OK)
goto cleanup_mem;
}
@@ -279,14 +321,14 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
struct armv7m_common *armv7m = target_to_armv7m(target);
if (armv7m == NULL) {
/* something is very wrong if armv7m is NULL */
LOG_ERROR("unable to get armv7m target");
retval = ERROR_FAIL;
goto cleanup;
}
/* Set SROM request */
retval = target_write_u32(target, PSOC4_CPUSS_SYSREQ,
retval = target_write_u32(target, psoc4_info->cpuss_sysreq_addr,
PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd);
if (retval != ERROR_OK)
goto cleanup;
@@ -295,9 +337,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
retval = target_run_algorithm(target, 0, NULL,
sizeof(reg_params) / sizeof(*reg_params), reg_params,
sysreq_wait_algorithm->address, 0, 1000, &armv7m_info);
if (retval != ERROR_OK)
if (retval != ERROR_OK) {
LOG_ERROR("sysreq wait code execution failed");
goto cleanup;
}
uint32_t sysarg_out_tmp;
retval = target_read_u32(target, psoc4_info->cpuss_sysarg_addr, &sysarg_out_tmp);
if (retval != ERROR_OK)
goto cleanup;
if (sysarg_out) {
*sysarg_out = sysarg_out_tmp;
/* If result is an error, do not show now, let caller to decide */
} else if ((sysarg_out_tmp & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) {
LOG_ERROR("sysreq error 0x%" PRIx32, sysarg_out_tmp);
retval = ERROR_FAIL;
}
cleanup:
destroy_reg_param(&reg_params[0]);
@@ -313,42 +369,123 @@ cleanup_algo:
/* helper routine to get silicon ID from a PSoC 4 chip */
static int psoc4_get_silicon_id(struct target *target, uint32_t *silicon_id, uint8_t *protection)
static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, uint16_t *family_id, uint8_t *protection)
{
uint32_t params = PSOC4_SROM_KEY1
| ((PSOC4_SROM_KEY2 + PSOC4_CMD_GET_SILICON_ID) << 8);
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
uint32_t part0, part1;
int retval = psoc4_sysreq(target, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0);
int retval = psoc4_sysreq(bank, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0, &part0);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, PSOC4_CPUSS_SYSARG, &part0);
if (retval != ERROR_OK)
return retval;
if (part0 == params) {
LOG_ERROR("sysreq silicon id request not served");
if ((part0 & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) {
LOG_ERROR("sysreq error 0x%" PRIx32, part0);
return ERROR_FAIL;
}
retval = target_read_u32(target, PSOC4_CPUSS_SYSREQ, &part1);
retval = target_read_u32(target, psoc4_info->cpuss_sysreq_addr, &part1);
if (retval != ERROR_OK)
return retval;
uint32_t silicon = ((part0 & 0xffff) << 16)
| (((part0 >> 16) & 0xff) << 8)
| (part1 & 0xff);
uint8_t prot = (part1 >> 12) & 0xff;
/* build ID as Cypress sw does:
* bit 31..16 silicon ID
* bit 15..8 revision ID (so far 0x11 for all devices)
* bit 7..0 family ID (lowes 8 bits)
*/
if (silicon_id)
*silicon_id = silicon;
if (protection)
*protection = prot;
*silicon_id = ((part0 & 0x0000ffff) << 16)
| ((part0 & 0x00ff0000) >> 8)
| (part1 & 0x000000ff);
LOG_DEBUG("silicon id: 0x%08" PRIx32 "", silicon);
LOG_DEBUG("protection: 0x%02" PRIx8 "", prot);
return retval;
if (family_id)
*family_id = part1 & 0x0fff;
if (protection)
*protection = (part1 >> 12) & 0x0f;
return ERROR_OK;
}
static int psoc4_get_family(struct target *target, uint16_t *family_id)
{
int retval, i;
uint32_t pidbf[3];
uint8_t pid[3];
retval = target_read_memory(target, PSOC4_ROMTABLE_PID0, 4, 3, (uint8_t *)pidbf);
if (retval != ERROR_OK)
return retval;
for (i = 0; i < 3; i++) {
uint32_t tmp = target_buffer_get_u32(target, (uint8_t *)(pidbf + i));
if (tmp & 0xffffff00) {
LOG_ERROR("Unexpected data in ROMTABLE");
return ERROR_FAIL;
}
pid[i] = tmp & 0xff;
}
uint16_t family = pid[0] | ((pid[1] & 0xf) << 8);
uint32_t designer = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0xf) << 4);
if (designer != PSOC4_ROMTABLE_DESIGNER_CHECK) {
LOG_ERROR("ROMTABLE designer is not Cypress");
return ERROR_FAIL;
}
*family_id = family;
return ERROR_OK;
}
static int psoc4_flash_prepare(struct flash_bank *bank)
{
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
uint16_t family_id;
int retval;
/* get family ID from SROM call */
retval = psoc4_get_silicon_id(bank, NULL, &family_id, NULL);
if (retval != ERROR_OK)
return retval;
/* and check with family ID from ROMTABLE */
if (family_id != psoc4_info->family_id) {
LOG_ERROR("Family mismatch");
return ERROR_FAIL;
}
if (!psoc4_info->legacy_family) {
uint32_t sysreq_status;
retval = psoc4_sysreq(bank, PSOC4_CMD_SET_IMO48, 0, NULL, 0, &sysreq_status);
if (retval != ERROR_OK)
return retval;
if ((sysreq_status & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) {
/* This undocumented error code is returned probably when
* PSOC4_CMD_SET_IMO48 command is not implemented.
* Can be safely ignored, programming works.
*/
if (sysreq_status == PSOC4_SROM_ERR_IMO_NOT_IMPLEM)
LOG_INFO("PSOC4_CMD_SET_IMO48 is not implemented on this device.");
else {
LOG_ERROR("sysreq error 0x%" PRIx32, sysreq_status);
return ERROR_FAIL;
}
}
}
return ERROR_OK;
}
@@ -357,48 +494,37 @@ static int psoc4_protect_check(struct flash_bank *bank)
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
uint32_t prot_addr = PSOC4_SFLASH_MACRO;
uint32_t protection;
int i, s;
int num_bits;
int retval = ERROR_OK;
uint32_t prot_addr = PSOC4_SFLASH_MACRO0;
int retval;
int s = 0;
int m, i;
uint8_t bf[PSOC4_ROWS_PER_MACRO/8];
num_bits = bank->num_sectors;
for (i = 0; i < num_bits; i += 32) {
retval = target_read_u32(target, prot_addr, &protection);
for (m = 0; m < psoc4_info->num_macros; m++, prot_addr += PSOC4_SFLASH_MACRO_SIZE) {
retval = target_read_memory(target, prot_addr, 4, PSOC4_ROWS_PER_MACRO/32, bf);
if (retval != ERROR_OK)
return retval;
prot_addr += 4;
for (s = 0; s < 32; s++) {
if (i + s >= num_bits)
break;
bank->sectors[i + s].is_protected = (protection & (1 << s)) ? 1 : 0;
}
for (i = 0; i < PSOC4_ROWS_PER_MACRO && s < bank->num_sectors; i++, s++)
bank->sectors[s].is_protected = bf[i/8] & (1 << (i%8)) ? 1 : 0;
}
retval = psoc4_get_silicon_id(target, NULL, &(psoc4_info->chip_protection));
return retval;
return ERROR_OK;
}
static int psoc4_mass_erase(struct flash_bank *bank)
{
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 = psoc4_flash_prepare(bank);
if (retval != ERROR_OK)
return retval;
/* Call "Erase All" system ROM API */
uint32_t param;
int retval = psoc4_sysreq(target, PSOC4_CMD_ERASE_ALL,
uint32_t param = 0;
retval = psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL,
0,
&param, sizeof(param));
&param, sizeof(param), NULL);
if (retval == ERROR_OK)
/* set all sectors as erased */
@@ -420,7 +546,7 @@ static int psoc4_erase(struct flash_bank *bank, int first, int last)
if ((first == 0) && (last == (bank->num_sectors - 1)))
return psoc4_mass_erase(bank);
LOG_ERROR("Only mass erase available");
LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'");
return ERROR_FAIL;
}
@@ -431,56 +557,63 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last)
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
if (psoc4_info->probed == 0)
if (!psoc4_info->probed)
return ERROR_FAIL;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
int retval = psoc4_flash_prepare(bank);
if (retval != ERROR_OK)
return retval;
uint32_t *sysrq_buffer = NULL;
int retval;
int num_bits = bank->num_sectors;
const int param_sz = 8;
int prot_sz = num_bits / 8;
int chip_prot = PSOC4_CHIP_PROT_OPEN;
int flash_macro = 0; /* PSoC 42xx has only macro 0 */
int i;
int i, m, sect;
int num_bits = bank->num_sectors;
sysrq_buffer = calloc(1, param_sz + prot_sz);
if (num_bits > PSOC4_ROWS_PER_MACRO)
num_bits = PSOC4_ROWS_PER_MACRO;
int prot_sz = num_bits / 8;
sysrq_buffer = malloc(param_sz + prot_sz);
if (sysrq_buffer == NULL) {
LOG_ERROR("no memory for row buffer");
return ERROR_FAIL;
}
for (i = first; i < num_bits && i <= last; i++)
for (i = first; i <= last && i < bank->num_sectors; i++)
bank->sectors[i].is_protected = set;
uint32_t *p = sysrq_buffer + 2;
for (i = 0; i < num_bits; i++) {
if (bank->sectors[i].is_protected)
p[i / 32] |= 1 << (i % 32);
for (m = 0, sect = 0; m < psoc4_info->num_macros; m++) {
uint8_t *p = (uint8_t *)(sysrq_buffer + 2);
memset(p, 0, prot_sz);
for (i = 0; i < num_bits && sect < bank->num_sectors; i++, sect++) {
if (bank->sectors[sect].is_protected)
p[i/8] |= 1 << (i%8);
}
/* Call "Load Latch" system ROM API */
target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1),
prot_sz - 1);
retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH,
0 /* Byte number in latch from what to write */
| (m << 8), /* flash macro index */
sysrq_buffer, param_sz + prot_sz,
NULL);
if (retval != ERROR_OK)
break;
/* Call "Write Protection" system ROM API */
retval = psoc4_sysreq(bank, PSOC4_CMD_WRITE_PROTECTION,
chip_prot | (m << 8), NULL, 0, NULL);
if (retval != ERROR_OK)
break;
}
/* Call "Load Latch" system ROM API */
sysrq_buffer[1] = prot_sz - 1;
retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
0, /* Byte number in latch from what to write */
sysrq_buffer, param_sz + psoc4_info->row_size);
if (retval != ERROR_OK)
goto cleanup;
/* Call "Write Protection" system ROM API */
retval = psoc4_sysreq(target, PSOC4_CMD_WRITE_PROTECTION,
chip_prot | (flash_macro << 8), NULL, 0);
cleanup:
if (retval != ERROR_OK)
psoc4_protect_check(bank);
if (sysrq_buffer)
free(sysrq_buffer);
psoc4_protect_check(bank);
return retval;
}
@@ -516,21 +649,14 @@ COMMAND_HANDLER(psoc4_handle_flash_autoerase_command)
static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
uint32_t *sysrq_buffer = NULL;
int retval = ERROR_OK;
const int param_sz = 8;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (offset & 0x1) {
LOG_ERROR("offset 0x%08" PRIx32 " breaks required 2-byte alignment", offset);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
int retval = psoc4_flash_prepare(bank);
if (retval != ERROR_OK)
return retval;
sysrq_buffer = malloc(param_sz + psoc4_info->row_size);
if (sysrq_buffer == NULL) {
@@ -542,7 +668,7 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t row_num = offset / psoc4_info->row_size;
uint32_t row_offset = offset - row_num * psoc4_info->row_size;
if (row_offset)
memset(row_buffer, 0, row_offset);
memset(row_buffer, bank->default_padded_value, row_offset);
bool save_poll = jtag_poll_get_enabled();
jtag_poll_set_enabled(false);
@@ -551,25 +677,31 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t chunk_size = psoc4_info->row_size - row_offset;
if (chunk_size > count) {
chunk_size = count;
memset(row_buffer + chunk_size, 0, psoc4_info->row_size - chunk_size);
memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size);
}
memcpy(row_buffer + row_offset, buffer, chunk_size);
LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "",
offset, row_offset, chunk_size);
uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO;
/* Call "Load Latch" system ROM API */
sysrq_buffer[1] = psoc4_info->row_size - 1;
retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
0, /* Byte number in latch from what to write */
sysrq_buffer, param_sz + psoc4_info->row_size);
target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1),
psoc4_info->row_size - 1);
retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH,
0 /* Byte number in latch from what to write */
| (macro_idx << 8),
sysrq_buffer, param_sz + psoc4_info->row_size,
NULL);
if (retval != ERROR_OK)
goto cleanup;
/* Call "Program Row" or "Write Row" system ROM API */
uint32_t sysrq_param;
retval = psoc4_sysreq(target, psoc4_info->cmd_program_row,
retval = psoc4_sysreq(bank, psoc4_info->cmd_program_row,
row_num & 0xffff,
&sysrq_param, sizeof(sysrq_param));
&sysrq_param, sizeof(sysrq_param),
NULL);
if (retval != ERROR_OK)
goto cleanup;
@@ -589,84 +721,82 @@ cleanup:
}
/* Due to Cypress's method of market segmentation some devices
* have accessible only 1/2, 1/4 or 1/8 of SPCIF described flash */
static int psoc4_test_flash_wounding(struct target *target, uint32_t flash_size)
{
int retval, i;
for (i = 3; i >= 1; i--) {
uint32_t addr = flash_size >> i;
uint32_t dummy;
retval = target_read_u32(target, addr, &dummy);
if (retval != ERROR_OK)
return i;
}
return 0;
}
static int psoc4_probe(struct flash_bank *bank)
{
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t flash_size_in_kb = 0;
uint32_t max_flash_size_in_kb;
uint32_t cpu_id;
uint32_t silicon_id;
uint32_t row_size;
uint32_t base_address = 0x00000000;
uint8_t protection;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
int retval;
uint16_t family_id;
psoc4_info->probed = 0;
psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW;
psoc4_info->probed = false;
/* Get the CPUID from the ARM Core
* http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */
int retval = target_read_u32(target, 0xE000ED00, &cpu_id);
retval = psoc4_get_family(target, &family_id);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("cpu id = 0x%08" PRIx32 "", cpu_id);
const struct psoc4_chip_family *family = psoc4_family_by_id(family_id);
/* set page size, protection granularity and max flash size depending on family */
switch ((cpu_id >> 4) & 0xFFF) {
case 0xc20: /* M0 -> PSoC4 */
row_size = 128;
max_flash_size_in_kb = 32;
break;
default:
LOG_WARNING("Cannot identify target as a PSoC 4 family.");
if (family->id == 0) {
LOG_ERROR("Cannot identify PSoC 4 family.");
return ERROR_FAIL;
}
uint32_t spcif_geometry;
retval = target_read_u32(target, PSOC4_SPCIF_GEOMETRY, &spcif_geometry);
if (retval == ERROR_OK) {
row_size = 128 * ((spcif_geometry >> 22) & 3);
flash_size_in_kb = (spcif_geometry & 0xffff) * 256 / 1024;
LOG_INFO("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.",
flash_size_in_kb, row_size);
if (family->flags & PSOC4_FAMILY_FLAG_LEGACY) {
LOG_INFO("%s legacy family detected.", family->name);
psoc4_info->legacy_family = true;
psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_LEGACY;
psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_LEGACY;
psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_LEGACY;
} else {
LOG_INFO("%s family detected.", family->name);
psoc4_info->legacy_family = false;
psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_NEW;
psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_NEW;
psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_NEW;
}
/* Early revisions of ST-Link v2 have some problem reading PSOC4_SPCIF_GEOMETRY
and an error is reported late. Dummy read gets this error. */
uint32_t dummy;
target_read_u32(target, PSOC4_CPUSS_SYSREQ, &dummy);
/* get silicon ID from target. */
retval = psoc4_get_silicon_id(target, &silicon_id, &protection);
uint32_t spcif_geometry;
retval = target_read_u32(target, psoc4_info->spcif_geometry_addr, &spcif_geometry);
if (retval != ERROR_OK)
return retval;
const struct psoc4_chip_details *details = psoc4_details_by_id(silicon_id);
if (details) {
LOG_INFO("%s device detected.", details->type);
if (flash_size_in_kb == 0)
flash_size_in_kb = details->flash_size_in_kb;
else if (flash_size_in_kb != details->flash_size_in_kb)
LOG_ERROR("Flash size mismatch");
uint32_t flash_size_in_kb = spcif_geometry & 0x3fff;
/* TRM of legacy, M and L version describes FLASH field as 16-bit.
* S-series and PSoC Analog Coprocessor changes spec to 14-bit only.
* Impose PSoC Analog Coprocessor limit to all devices as it
* does not make any harm: flash size is safely below 4 MByte limit
*/
uint32_t row_size = (spcif_geometry >> 22) & 3;
uint32_t num_macros = (spcif_geometry >> 20) & 3;
if (psoc4_info->legacy_family) {
flash_size_in_kb = flash_size_in_kb * 256 / 1024;
row_size *= 128;
} else {
flash_size_in_kb = (flash_size_in_kb + 1) * 256 / 1024;
row_size = 64 * (row_size + 1);
num_macros++;
}
psoc4_info->row_size = row_size;
psoc4_info->silicon_id = silicon_id;
psoc4_info->chip_protection = protection;
/* failed reading flash size or flash size invalid (early silicon),
* default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
LOG_WARNING("PSoC 4 flash size failed, probe inaccurate - assuming %" PRIu32 " k flash",
max_flash_size_in_kb);
flash_size_in_kb = max_flash_size_in_kb;
}
LOG_DEBUG("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.",
flash_size_in_kb, row_size);
/* if the user sets the size manually then ignore the probed value
* this allows us to work around devices that have a invalid flash size register value */
@@ -675,37 +805,44 @@ static int psoc4_probe(struct flash_bank *bank)
flash_size_in_kb = psoc4_info->user_bank_size / 1024;
}
LOG_INFO("flash size = %" PRIu32 " kbytes", flash_size_in_kb);
char macros_txt[20] = "";
if (num_macros > 1)
snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros);
/* did we assign flash size? */
assert(flash_size_in_kb != 0xffff);
LOG_INFO("flash size = %" PRIu32 " kbytes%s", flash_size_in_kb, macros_txt);
/* calculate numbers of pages */
/* calculate number of pages */
uint32_t num_rows = flash_size_in_kb * 1024 / row_size;
/* check that calculation result makes sense */
assert(num_rows > 0);
/* check number of flash macros */
if (num_macros != (num_rows + PSOC4_ROWS_PER_MACRO - 1) / PSOC4_ROWS_PER_MACRO)
LOG_WARNING("Number of macros does not correspond with flash size!");
if (!psoc4_info->legacy_family) {
int wounding = psoc4_test_flash_wounding(target, num_rows * row_size);
if (wounding > 0) {
flash_size_in_kb = flash_size_in_kb >> wounding;
num_rows = num_rows >> wounding;
LOG_INFO("WOUNDING detected: accessible flash size %" PRIu32 " kbytes", flash_size_in_kb);
}
}
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->base = base_address;
psoc4_info->family_id = family_id;
psoc4_info->num_macros = num_macros;
psoc4_info->row_size = row_size;
bank->base = 0x00000000;
bank->size = num_rows * row_size;
bank->num_sectors = num_rows;
bank->sectors = malloc(sizeof(struct flash_sector) * num_rows);
bank->sectors = alloc_block_array(0, row_size, num_rows);
if (bank->sectors == NULL)
return ERROR_FAIL;
uint32_t i;
for (i = 0; i < num_rows; i++) {
bank->sectors[i].offset = i * row_size;
bank->sectors[i].size = row_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
LOG_INFO("flash bank set %" PRIu32 " rows", num_rows);
psoc4_info->probed = 1;
LOG_DEBUG("flash bank set %" PRIu32 " rows", num_rows);
psoc4_info->probed = true;
return ERROR_OK;
}
@@ -721,28 +858,45 @@ static int psoc4_auto_probe(struct flash_bank *bank)
static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
int printed = 0;
if (psoc4_info->probed == 0)
if (!psoc4_info->probed)
return ERROR_FAIL;
const struct psoc4_chip_details *details = psoc4_details_by_id(psoc4_info->silicon_id);
const struct psoc4_chip_family *family = psoc4_family_by_id(psoc4_info->family_id);
uint32_t size_in_kb = bank->size / 1024;
if (details) {
uint32_t chip_revision = psoc4_info->silicon_id & 0xffff;
printed = snprintf(buf, buf_size, "PSoC 4 %s rev 0x%04" PRIx32 " package %s",
details->type, chip_revision, details->package);
} else
printed = snprintf(buf, buf_size, "PSoC 4 silicon id 0x%08" PRIx32 "",
psoc4_info->silicon_id);
if (target->state != TARGET_HALTED) {
snprintf(buf, buf_size, "%s, flash %" PRIu32 " kb"
" (halt target to see details)", family->name, size_in_kb);
return ERROR_OK;
}
int retval;
int printed = 0;
uint32_t silicon_id;
uint16_t family_id;
uint8_t protection;
retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection);
if (retval != ERROR_OK)
return retval;
if (family_id != psoc4_info->family_id)
printed = snprintf(buf, buf_size, "Family id mismatch 0x%02" PRIx16
"/0x%02" PRIx16 ", silicon id 0x%08" PRIx32,
psoc4_info->family_id, family_id, silicon_id);
else {
printed = snprintf(buf, buf_size, "%s silicon id 0x%08" PRIx32 "",
family->name, silicon_id);
}
buf += printed;
buf_size -= printed;
const char *prot_txt = psoc4_decode_chip_protection(psoc4_info->chip_protection);
uint32_t size_in_kb = bank->size / 1024;
snprintf(buf, buf_size, " flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
const char *prot_txt = psoc4_decode_chip_protection(protection);
snprintf(buf, buf_size, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
return ERROR_OK;
}
@@ -809,4 +963,5 @@ struct flash_driver psoc4_flash = {
.erase_check = default_flash_blank_check,
.protect_check = psoc4_protect_check,
.info = get_psoc4_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+986
View File
@@ -0,0 +1,986 @@
/***************************************************************************
* *
* Copyright (C) 2017 by Bohdan Tymkiv *
* bohdan.tymkiv@cypress.com bohdan200@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 <time.h>
#include "imp.h"
#include "target/target.h"
#include "target/cortex_m.h"
#include "target/breakpoints.h"
#include "target/target_type.h"
#include "time_support.h"
#include "target/algorithm.h"
/**************************************************************************************************
* PSoC6 device definitions
*************************************************************************************************/
#define MFLASH_SECTOR_SIZE (256u * 1024u)
#define WFLASH_SECTOR_SIZE (32u * 1024u)
#define MEM_BASE_MFLASH 0x10000000u
#define MEM_BASE_WFLASH 0x14000000u
#define MEM_WFLASH_SIZE 32768u
#define MEM_BASE_SFLASH 0x16000000u
#define RAM_STACK_WA_SIZE 2048u
#define PSOC6_SPCIF_GEOMETRY 0x4025F00Cu
#define PROTECTION_UNKNOWN 0x00u
#define PROTECTION_VIRGIN 0x01u
#define PROTECTION_NORMAL 0x02u
#define PROTECTION_SECURE 0x03u
#define PROTECTION_DEAD 0x04u
#define MEM_BASE_IPC 0x40230000u
#define IPC_STRUCT_SIZE 0x20u
#define MEM_IPC(n) (MEM_BASE_IPC + (n) * IPC_STRUCT_SIZE)
#define MEM_IPC_ACQUIRE(n) (MEM_IPC(n) + 0x00u)
#define MEM_IPC_NOTIFY(n) (MEM_IPC(n) + 0x08u)
#define MEM_IPC_DATA(n) (MEM_IPC(n) + 0x0Cu)
#define MEM_IPC_LOCK_STATUS(n) (MEM_IPC(n) + 0x10u)
#define MEM_BASE_IPC_INTR 0x40231000u
#define IPC_INTR_STRUCT_SIZE 0x20u
#define MEM_IPC_INTR(n) (MEM_BASE_IPC_INTR + (n) * IPC_INTR_STRUCT_SIZE)
#define MEM_IPC_INTR_MASK(n) (MEM_IPC_INTR(n) + 0x08u)
#define IPC_ACQUIRE_SUCCESS_MSK 0x80000000u
#define IPC_LOCK_ACQUIRED_MSK 0x80000000u
#define IPC_ID 2u
#define IPC_INTR_ID 0u
#define IPC_TIMEOUT_MS 1000
#define SROMAPI_SIID_REQ 0x00000001u
#define SROMAPI_SIID_REQ_FAMILY_REVISION (SROMAPI_SIID_REQ | 0x000u)
#define SROMAPI_SIID_REQ_SIID_PROTECTION (SROMAPI_SIID_REQ | 0x100u)
#define SROMAPI_WRITEROW_REQ 0x05000100u
#define SROMAPI_PROGRAMROW_REQ 0x06000100u
#define SROMAPI_ERASESECTOR_REQ 0x14000100u
#define SROMAPI_ERASEALL_REQ 0x0A000100u
#define SROMAPI_ERASEROW_REQ 0x1C000100u
#define SROMAPI_STATUS_MSK 0xF0000000u
#define SROMAPI_STAT_SUCCESS 0xA0000000u
#define SROMAPI_DATA_LOCATION_MSK 0x00000001u
#define SROMAPI_CALL_TIMEOUT_MS 1500
struct psoc6_target_info {
uint32_t silicon_id;
uint8_t protection;
uint32_t main_flash_sz;
uint32_t row_sz;
bool is_probed;
};
struct timeout {
int64_t start_time;
long timeout_ms;
};
struct row_region {
uint32_t addr;
size_t size;
};
static struct row_region safe_sflash_regions[] = {
{0x16000800, 0x800}, /* SFLASH: User Data */
{0x16001A00, 0x200}, /* SFLASH: NAR */
{0x16005A00, 0xC00}, /* SFLASH: Public Key */
{0x16007C00, 0x400}, /* SFLASH: TOC2 */
};
#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0]))
static struct working_area *g_stack_area;
/**************************************************************************************************
* Initializes timeout_s structure with given timeout in milliseconds
*************************************************************************************************/
static void timeout_init(struct timeout *to, long timeout_ms)
{
to->start_time = timeval_ms();
to->timeout_ms = timeout_ms;
}
/**************************************************************************************************
* Returns true if given timeout_s object has expired
*************************************************************************************************/
static bool timeout_expired(struct timeout *to)
{
return (timeval_ms() - to->start_time) > to->timeout_ms;
}
/**************************************************************************************************
* Prepares PSoC6 for running pseudo flash algorithm. This function allocates Working Area for
* the algorithm and for CPU Stack.
*************************************************************************************************/
static int sromalgo_prepare(struct target *target)
{
int hr;
/* Initialize Vector Table Offset register (in case FW modified it) */
hr = target_write_u32(target, 0xE000ED08, 0x00000000);
if (hr != ERROR_OK)
return hr;
/* Allocate Working Area for Stack and Flash algorithm */
hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area);
if (hr != ERROR_OK)
return hr;
/* Restore THUMB bit in xPSR register */
const struct armv7m_common *cm = target_to_armv7m(target);
hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000);
if (hr != ERROR_OK)
goto exit_free_wa;
return ERROR_OK;
exit_free_wa:
/* Something went wrong, free allocated area */
if (g_stack_area) {
target_free_working_area(target, g_stack_area);
g_stack_area = NULL;
}
return hr;
}
/**************************************************************************************************
* Releases working area
*************************************************************************************************/
static int sromalgo_release(struct target *target)
{
int hr = ERROR_OK;
/* Free Stack/Flash algorithm working area */
if (g_stack_area) {
hr = target_free_working_area(target, g_stack_area);
g_stack_area = NULL;
}
return hr;
}
/**************************************************************************************************
* Runs pseudo flash algorithm. Algorithm itself consist of couple of NOPs followed by BKPT
* instruction. The trick here is that NMI has already been posted to CM0 via IPC structure
* prior to calling this function. CM0 will immediately jump to NMI handler and execute
* SROM API code.
* This approach is borrowed from PSoC4 Flash Driver.
*************************************************************************************************/
static int sromalgo_run(struct target *target)
{
int hr;
struct armv7m_algorithm armv7m_info;
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
struct reg_param reg_params;
init_reg_param(&reg_params, "sp", 32, PARAM_OUT);
buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size);
/* mov r8, r8; mov r8, r8 */
hr = target_write_u32(target, g_stack_area->address + 0, 0x46C046C0);
if (hr != ERROR_OK)
return hr;
/* mov r8, r8; bkpt #0 */
hr = target_write_u32(target, g_stack_area->address + 4, 0xBE0046C0);
if (hr != ERROR_OK)
return hr;
hr = target_run_algorithm(target, 0, NULL, 1, &reg_params, g_stack_area->address,
0, SROMAPI_CALL_TIMEOUT_MS, &armv7m_info);
destroy_reg_param(&reg_params);
return hr;
}
/**************************************************************************************************
* Waits for expected IPC lock status.
* PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API.
* IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the
* system will use same IPC thus corrupting our data. Locking is performed by ipc_acquire(), this
* function ensures that IPC is actually in expected state
*************************************************************************************************/
static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected)
{
int hr;
uint32_t reg_val;
struct timeout to;
timeout_init(&to, IPC_TIMEOUT_MS);
while (!timeout_expired(&to)) {
/* Process any server requests */
keep_alive();
/* Read IPC Lock status */
hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), &reg_val);
if (hr != ERROR_OK) {
LOG_ERROR("Unable to read IPC Lock Status register");
return hr;
}
bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0;
if (lock_expected == is_locked)
return ERROR_OK;
}
if (target->coreid) {
LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. "
"Please perform all Flash-related operations via CM0+ target on dual-core devices.");
}
LOG_ERROR("Timeout polling IPC Lock Status");
return ERROR_TARGET_TIMEOUT;
}
/**************************************************************************************************
* Acquires IPC structure
* PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API.
* IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the
* system will use same IPC thus corrupting our data. This function locks the IPC.
*************************************************************************************************/
static int ipc_acquire(struct target *target, char ipc_id)
{
int hr = ERROR_OK;
bool is_acquired = false;
uint32_t reg_val;
struct timeout to;
timeout_init(&to, IPC_TIMEOUT_MS);
while (!timeout_expired(&to)) {
keep_alive();
hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), IPC_ACQUIRE_SUCCESS_MSK);
if (hr != ERROR_OK) {
LOG_ERROR("Unable to write to IPC Acquire register");
return hr;
}
/* Check if data is written on first step */
hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), &reg_val);
if (hr != ERROR_OK) {
LOG_ERROR("Unable to read IPC Acquire register");
return hr;
}
is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0;
if (is_acquired) {
/* If IPC structure is acquired, the lock status should be set */
hr = ipc_poll_lock_stat(target, ipc_id, true);
break;
}
}
if (!is_acquired)
LOG_ERROR("Timeout acquiring IPC structure");
return hr;
}
/**************************************************************************************************
* Invokes SROM API functions which are responsible for Flash operations
*************************************************************************************************/
static int call_sromapi(struct target *target,
uint32_t req_and_params,
uint32_t working_area,
uint32_t *data_out)
{
int hr;
bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0;
hr = ipc_acquire(target, IPC_ID);
if (hr != ERROR_OK)
return hr;
if (is_data_in_ram)
hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area);
else
hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params);
if (hr != ERROR_OK)
return hr;
/* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */
hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + IPC_ID));
if (hr != ERROR_OK)
return hr;
hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1);
if (hr != ERROR_OK)
return hr;
hr = sromalgo_run(target);
if (hr != ERROR_OK)
return hr;
/* Poll lock status */
hr = ipc_poll_lock_stat(target, IPC_ID, false);
if (hr != ERROR_OK)
return hr;
/* Poll Data byte */
if (is_data_in_ram)
hr = target_read_u32(target, working_area, data_out);
else
hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out);
if (hr != ERROR_OK) {
LOG_ERROR("Error reading SROM API Status location");
return hr;
}
bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS;
if (!is_success) {
LOG_ERROR("SROM API execution failed. Status: 0x%08X", (uint32_t)*data_out);
return ERROR_TARGET_FAILURE;
}
return ERROR_OK;
}
/**************************************************************************************************
* Retrieves SiliconID and Protection status of the target device
*************************************************************************************************/
static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection)
{
int hr;
uint32_t family_rev, siid_prot;
hr = sromalgo_prepare(target);
if (hr != ERROR_OK)
return hr;
/* Read FamilyID and Revision */
hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev);
if (hr != ERROR_OK)
return hr;
/* Read SiliconID and Protection */
hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot);
if (hr != ERROR_OK)
return hr;
*si_id = (siid_prot & 0x0000FFFF) << 16;
*si_id |= (family_rev & 0x00FF0000) >> 8;
*si_id |= (family_rev & 0x000000FF) >> 0;
*protection = (siid_prot & 0x000F0000) >> 0x10;
hr = sromalgo_release(target);
return hr;
}
/**************************************************************************************************
* Translates Protection status to openocd-friendly boolean value
*************************************************************************************************/
static int psoc6_protect_check(struct flash_bank *bank)
{
int is_protected;
struct psoc6_target_info *psoc6_info = bank->driver_priv;
int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
if (hr != ERROR_OK)
return hr;
switch (psoc6_info->protection) {
case PROTECTION_VIRGIN:
case PROTECTION_NORMAL:
is_protected = 0;
break;
case PROTECTION_UNKNOWN:
case PROTECTION_SECURE:
case PROTECTION_DEAD:
default:
is_protected = 1;
break;
}
for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected = is_protected;
return ERROR_OK;
}
/**************************************************************************************************
* Life Cycle transition is not currently supported
*************************************************************************************************/
static int psoc6_protect(struct flash_bank *bank, int set, int first, int last)
{
(void)bank;
(void)set;
(void)first;
(void)last;
LOG_WARNING("Life Cycle transition for PSoC6 is not supported");
return ERROR_OK;
}
/**************************************************************************************************
* Translates Protection status to string
*************************************************************************************************/
static const char *protection_to_str(uint8_t protection)
{
switch (protection) {
case PROTECTION_VIRGIN:
return "VIRGIN";
break;
case PROTECTION_NORMAL:
return "NORMAL";
break;
case PROTECTION_SECURE:
return "SECURE";
break;
case PROTECTION_DEAD:
return "DEAD";
break;
case PROTECTION_UNKNOWN:
default:
return "UNKNOWN";
break;
}
}
/**************************************************************************************************
* Displays human-readable information about acquired device
*************************************************************************************************/
static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct psoc6_target_info *psoc6_info = bank->driver_priv;
if (psoc6_info->is_probed == false)
return ERROR_FAIL;
int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection);
if (hr != ERROR_OK)
return hr;
snprintf(buf, buf_size,
"PSoC6 Silicon ID: 0x%08X\n"
"Protection: %s\n"
"Main Flash size: %d kB\n"
"Work Flash size: 32 kB\n",
psoc6_info->silicon_id,
protection_to_str(psoc6_info->protection),
psoc6_info->main_flash_sz / 1024);
return ERROR_OK;
}
/**************************************************************************************************
* Returns true if flash bank name represents Supervisory Flash
*************************************************************************************************/
static bool is_sflash_bank(struct flash_bank *bank)
{
for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
if (bank->base == safe_sflash_regions[i].addr)
return true;
}
return false;
}
/**************************************************************************************************
* Returns true if flash bank name represents Work Flash
*************************************************************************************************/
static inline bool is_wflash_bank(struct flash_bank *bank)
{
return (bank->base == MEM_BASE_WFLASH);
}
/**************************************************************************************************
* Returns true if flash bank name represents Main Flash
*************************************************************************************************/
static inline bool is_mflash_bank(struct flash_bank *bank)
{
return (bank->base == MEM_BASE_MFLASH);
}
/**************************************************************************************************
* Probes the device and populates related data structures with target flash geometry data.
* This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a
* running target.
* Function assumes that size of Work Flash is 32kB (true for all current part numbers)
*************************************************************************************************/
static int psoc6_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct psoc6_target_info *psoc6_info = bank->driver_priv;
int hr = ERROR_OK;
/* Retrieve data from SPCIF_GEOMATRY */
uint32_t geom;
target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom);
uint32_t row_sz_lg2 = (geom & 0xF0) >> 4;
uint32_t row_sz = (0x01 << row_sz_lg2);
uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8);
uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24);
/* Calculate size of Main Flash*/
uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz;
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
size_t bank_size = 0;
if (is_mflash_bank(bank))
bank_size = flash_sz_bytes;
else if (is_wflash_bank(bank))
bank_size = MEM_WFLASH_SIZE;
else if (is_sflash_bank(bank)) {
for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) {
if (safe_sflash_regions[i].addr == bank->base) {
bank_size = safe_sflash_regions[i].size;
break;
}
}
}
if (bank_size == 0) {
LOG_ERROR("Invalid Flash Bank base address in config file");
return ERROR_FLASH_BANK_INVALID;
}
size_t num_sectors = bank_size / row_sz;
bank->size = bank_size;
bank->chip_width = 4;
bank->bus_width = 4;
bank->erased_value = 0;
bank->default_padded_value = 0;
bank->num_sectors = num_sectors;
bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
for (size_t i = 0; i < num_sectors; i++) {
bank->sectors[i].size = row_sz;
bank->sectors[i].offset = i * row_sz;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = -1;
}
psoc6_info->is_probed = true;
psoc6_info->main_flash_sz = flash_sz_bytes;
psoc6_info->row_sz = row_sz;
return hr;
}
/**************************************************************************************************
* Probes target device only if it hasn't been probed yet
*************************************************************************************************/
static int psoc6_auto_probe(struct flash_bank *bank)
{
struct psoc6_target_info *psoc6_info = bank->driver_priv;
int hr;
if (psoc6_info->is_probed)
hr = ERROR_OK;
else
hr = psoc6_probe(bank);
return hr;
}
/**************************************************************************************************
* Erases single sector (256k) on target device
*************************************************************************************************/
static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
{
struct target *target = bank->target;
LOG_DEBUG("Erasing SECTOR @%08X", addr);
int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ);
if (hr != ERROR_OK)
return hr;
hr = target_write_u32(target, wa->address + 0x04, addr);
if (hr != ERROR_OK)
return hr;
uint32_t data_out;
hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out);
if (hr != ERROR_OK)
LOG_ERROR("SECTOR @%08X not erased!", addr);
return hr;
}
/**************************************************************************************************
* Erases single row (512b) on target device
*************************************************************************************************/
static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr)
{
struct target *target = bank->target;
LOG_DEBUG("Erasing ROW @%08X", addr);
int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ);
if (hr != ERROR_OK)
return hr;
hr = target_write_u32(target, wa->address + 0x04, addr);
if (hr != ERROR_OK)
return hr;
uint32_t data_out;
hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out);
if (hr != ERROR_OK)
LOG_ERROR("ROW @%08X not erased!", addr);
return hr;
}
/**************************************************************************************************
* Performs Erase operation.
* Function will try to use biggest erase block possible to speedup the operation
*************************************************************************************************/
static int psoc6_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
struct psoc6_target_info *psoc6_info = bank->driver_priv;
const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE : MFLASH_SECTOR_SIZE;
int hr;
struct working_area *wa;
if (is_sflash_bank(bank)) {
LOG_INFO("Erase operation on Supervisory Flash is not required, skipping");
return ERROR_OK;
}
hr = sromalgo_prepare(target);
if (hr != ERROR_OK)
return hr;
hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
if (hr != ERROR_OK)
goto exit;
/* Number of rows in single sector */
const int rows_in_sector = sector_size / psoc6_info->row_sz;
while (last >= first) {
/* Erase Sector if we are on sector boundary and erase size covers whole sector */
if ((first % rows_in_sector) == 0 &&
(last - first + 1) >= rows_in_sector) {
hr = psoc6_erase_sector(bank, wa, bank->base + first * psoc6_info->row_sz);
if (hr != ERROR_OK)
goto exit_free_wa;
for (int i = first; i < first + rows_in_sector; i++)
bank->sectors[i].is_erased = 1;
first += rows_in_sector;
} else {
/* Perform Row Erase otherwise */
hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz);
if (hr != ERROR_OK)
goto exit_free_wa;
bank->sectors[first].is_erased = 1;
first += 1;
}
}
exit_free_wa:
target_free_working_area(target, wa);
exit:
sromalgo_release(target);
return hr;
}
/**************************************************************************************************
* Programs single Flash Row
*************************************************************************************************/
static int psoc6_program_row(struct flash_bank *bank,
uint32_t addr,
const uint8_t *buffer,
bool is_sflash)
{
struct target *target = bank->target;
struct psoc6_target_info *psoc6_info = bank->driver_priv;
struct working_area *wa;
const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : SROMAPI_PROGRAMROW_REQ;
uint32_t data_out;
int hr = ERROR_OK;
LOG_DEBUG("Programming ROW @%08X", addr);
hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa);
if (hr != ERROR_OK)
goto exit;
hr = target_write_u32(target, wa->address, sromapi_req);
if (hr != ERROR_OK)
goto exit_free_wa;
hr = target_write_u32(target,
wa->address + 0x04,
0x106);
if (hr != ERROR_OK)
goto exit_free_wa;
hr = target_write_u32(target, wa->address + 0x08, addr);
if (hr != ERROR_OK)
goto exit_free_wa;
hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10);
if (hr != ERROR_OK)
goto exit_free_wa;
hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer);
if (hr != ERROR_OK)
goto exit_free_wa;
hr = call_sromapi(target, sromapi_req, wa->address, &data_out);
exit_free_wa:
target_free_working_area(target, wa);
exit:
return hr;
}
/**************************************************************************************************
* Programs set of Rows
*************************************************************************************************/
static int psoc6_program(struct flash_bank *bank,
const uint8_t *buffer,
uint32_t offset,
uint32_t count)
{
struct target *target = bank->target;
struct psoc6_target_info *psoc6_info = bank->driver_priv;
const bool is_sflash = is_sflash_bank(bank);
int hr;
hr = sromalgo_prepare(target);
if (hr != ERROR_OK)
return hr;
uint8_t page_buf[psoc6_info->row_sz];
while (count) {
uint32_t row_offset = offset % psoc6_info->row_sz;
uint32_t aligned_addr = bank->base + offset - row_offset;
uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, count);
memset(page_buf, 0, sizeof(page_buf));
memcpy(&page_buf[row_offset], buffer, row_bytes);
hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash);
if (hr != ERROR_OK) {
LOG_ERROR("Failed to program Flash at address 0x%08X", aligned_addr);
break;
}
buffer += row_bytes;
offset += row_bytes;
count -= row_bytes;
}
hr = sromalgo_release(target);
return hr;
}
/**************************************************************************************************
* Performs Mass Erase of given flash bank
* Syntax: psoc6 mass_erase bank_id
*************************************************************************************************/
COMMAND_HANDLER(psoc6_handle_mass_erase_command)
{
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (hr != ERROR_OK)
return hr;
hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
return hr;
}
/**************************************************************************************************
* Simulates broken Vector Catch
* Function will try to determine entry point of user application. If it succeeds it will set HW
* breakpoint at that address, issue SW Reset and remove the breakpoint afterwards.
* In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will
* reset CM4 anyway, so using SYSRESETREQ is safe here.
* In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core.
*************************************************************************************************/
int handle_reset_halt(struct target *target)
{
int hr;
uint32_t reset_addr;
bool is_cm0 = (target->coreid == 0);
/* Halt target device */
if (target->state != TARGET_HALTED) {
hr = target_halt(target);
if (hr != ERROR_OK)
return hr;
target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
if (hr != ERROR_OK)
return hr;
}
/* Read Vector Offset register */
uint32_t vt_base;
const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0;
hr = target_read_u32(target, vt_offset_reg, &vt_base);
if (hr != ERROR_OK)
return ERROR_OK;
/* Invalid value means flash is empty */
vt_base &= 0xFFFFFF00;
if ((vt_base == 0) || (vt_base == 0xFFFFFF00))
return ERROR_OK;
/* Read Reset Vector value*/
hr = target_read_u32(target, vt_base + 4, &reset_addr);
if (hr != ERROR_OK)
return hr;
/* Invalid value means flash is empty */
if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00))
return ERROR_OK;
/* Set breakpoint at User Application entry point */
hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD);
if (hr != ERROR_OK)
return hr;
const struct armv7m_common *cm = target_to_armv7m(target);
if (is_cm0) {
/* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */
LOG_INFO("psoc6.cm0: bkpt @0x%08X, issuing SYSRESETREQ", reset_addr);
hr = mem_ap_write_atomic_u32(cm->debug_ap,
NVIC_AIRCR,
AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
/* Wait for bootcode and initialize DAP */
usleep(3000);
dap_dp_init(cm->debug_ap->dap);
} else {
LOG_INFO("psoc6.cm4: bkpt @0x%08X, issuing VECTRESET", reset_addr);
hr = mem_ap_write_atomic_u32(cm->debug_ap,
NVIC_AIRCR,
AIRCR_VECTKEY | AIRCR_VECTRESET);
if (hr != ERROR_OK)
return hr;
}
target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS);
/* Remove the break point */
breakpoint_remove(target, reset_addr);
return hr;
}
COMMAND_HANDLER(psoc6_handle_reset_halt)
{
if (CMD_ARGC)
return ERROR_COMMAND_SYNTAX_ERROR;
struct target *target = get_current_target(CMD_CTX);
return handle_reset_halt(target);
}
FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command)
{
struct psoc6_target_info *psoc6_info;
int hr = ERROR_OK;
if (CMD_ARGC < 6)
hr = ERROR_COMMAND_SYNTAX_ERROR;
else {
psoc6_info = calloc(1, sizeof(struct psoc6_target_info));
psoc6_info->is_probed = false;
bank->driver_priv = psoc6_info;
}
return hr;
}
static const struct command_registration psoc6_exec_command_handlers[] = {
{
.name = "mass_erase",
.handler = psoc6_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.usage = NULL,
.help = "Erases entire Main Flash",
},
{
.name = "reset_halt",
.handler = psoc6_handle_reset_halt,
.mode = COMMAND_EXEC,
.usage = NULL,
.help = "Tries to simulate broken Vector Catch",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration psoc6_command_handlers[] = {
{
.name = "psoc6",
.mode = COMMAND_ANY,
.help = "PSoC 6 flash command group",
.usage = "",
.chain = psoc6_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver psoc6_flash = {
.name = "psoc6",
.commands = psoc6_command_handlers,
.flash_bank_command = psoc6_flash_bank_command,
.erase = psoc6_erase,
.protect = psoc6_protect,
.write = psoc6_program,
.read = default_flash_read,
.probe = psoc6_probe,
.auto_probe = psoc6_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = psoc6_protect_check,
.info = psoc6_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+2 -1
View File
@@ -1122,5 +1122,6 @@ struct flash_driver sim3x_flash = {
.auto_probe = sim3x_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = sim3x_flash_protect_check,
.info = sim3x_flash_info
.info = sim3x_flash_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1452,4 +1452,5 @@ struct flash_driver stellaris_flash = {
.erase_check = default_flash_blank_check,
.protect_check = stellaris_protect_check,
.info = get_stellaris_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1647,4 +1647,5 @@ struct flash_driver stm32f1x_flash = {
.erase_check = default_flash_blank_check,
.protect_check = stm32x_protect_check,
.info = get_stm32x_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1634,4 +1634,5 @@ struct flash_driver stm32f2x_flash = {
.erase_check = default_flash_blank_check,
.protect_check = stm32x_protect_check,
.info = get_stm32x_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1180,4 +1180,5 @@ struct flash_driver stm32h7x_flash = {
.erase_check = default_flash_blank_check,
.protect_check = stm32x_protect_check,
.info = stm32x_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -953,4 +953,5 @@ struct flash_driver stm32l4x_flash = {
.erase_check = default_flash_blank_check,
.protect_check = stm32l4_protect_check,
.info = get_stm32l4_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -965,6 +965,7 @@ struct flash_driver stm32lx_flash = {
.erase_check = default_flash_blank_check,
.protect_check = stm32lx_protect_check,
.info = stm32lx_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
/* Static methods implementation */
+1
View File
@@ -654,4 +654,5 @@ struct flash_driver stmsmi_flash = {
.erase_check = default_flash_blank_check,
.protect_check = stmsmi_protect_check,
.info = get_stmsmi_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -812,4 +812,5 @@ struct flash_driver str7x_flash = {
.erase_check = default_flash_blank_check,
.protect_check = str7x_protect_check,
.info = get_str7x_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -679,4 +679,5 @@ struct flash_driver str9x_flash = {
.auto_probe = str9x_probe,
.erase_check = default_flash_blank_check,
.protect_check = str9x_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1207,4 +1207,5 @@ struct flash_driver str9xpec_flash = {
.auto_probe = str9xpec_probe,
.erase_check = str9xpec_erase_check,
.protect_check = str9xpec_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1186,4 +1186,5 @@ struct flash_driver tms470_flash = {
.erase_check = tms470_erase_check,
.protect_check = tms470_protect_check,
.info = get_tms470_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -231,4 +231,5 @@ struct flash_driver virtual_flash = {
.erase_check = virtual_blank_check,
.protect_check = virtual_protect_check,
.info = virtual_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+3 -1
View File
@@ -636,6 +636,7 @@ static int xcf_probe(struct flash_bank *bank)
fill_sector_table(bank);
priv->probed = true;
/* REVISIT: Why is unchanged bank->driver_priv rewritten by same value? */
bank->driver_priv = priv;
LOG_INFO("product name: %s", product_name(bank));
@@ -893,5 +894,6 @@ struct flash_driver xcf_flash = {
.auto_probe = xcf_auto_probe,
.erase_check = xcf_erase_check,
.protect_check = xcf_protect_check,
.info = xcf_info
.info = xcf_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -546,4 +546,5 @@ struct flash_driver xmc1xxx_flash = {
.erase = xmc1xxx_erase,
.erase_check = xmc1xxx_erase_check,
.write = xmc1xxx_write,
.free_driver_priv = default_flash_free_driver_priv,
};
+1
View File
@@ -1356,4 +1356,5 @@ struct flash_driver xmc4xxx_flash = {
.info = xmc4xxx_get_info_command,
.protect_check = xmc4xxx_protect_check,
.protect = xmc4xxx_protect,
.free_driver_priv = default_flash_free_driver_priv,
};