Merge branch 'riscv' into sba_tests

This commit is contained in:
Tim Newsome
2018-08-29 15:55:30 -07:00
committed by GitHub
387 changed files with 33230 additions and 4431 deletions
+10 -1
View File
@@ -18,6 +18,9 @@ NOR_DRIVERS = \
%D%/ath79.c \
%D%/atsamv.c \
%D%/avrf.c \
%D%/bluenrg-x.c \
%D%/cc3220sf.c \
%D%/cc26xx.c \
%D%/cfi.c \
%D%/dsp5680xx_flash.c \
%D%/efm32.c \
@@ -34,6 +37,7 @@ NOR_DRIVERS = \
%D%/lpc2900.c \
%D%/lpcspifi.c \
%D%/mdr.c \
%D%/msp432.c \
%D%/mrvlqspi.c \
%D%/niietcm4.c \
%D%/non_cfi.c \
@@ -42,6 +46,8 @@ NOR_DRIVERS = \
%D%/ocl.c \
%D%/pic32mx.c \
%D%/psoc4.c \
%D%/psoc5lp.c \
%D%/psoc6.c \
%D%/sim3x.c \
%D%/spi.c \
%D%/stmsmi.c \
@@ -62,9 +68,12 @@ NOR_DRIVERS = \
NORHEADERS = \
%D%/core.h \
%D%/cc3220sf.h \
%D%/cc26xx.h \
%D%/cfi.h \
%D%/driver.h \
%D%/imp.h \
%D%/non_cfi.h \
%D%/ocl.h \
%D%/spi.h
%D%/spi.h \
%D%/msp432.h
+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,
};
+17
View File
@@ -3117,6 +3117,22 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
return ERROR_OK;
}
/**
* Remove all chips from the internal list without distingushing which one
* is owned by this bank. This simplification works only for one shot
* deallocation like current flash_free_all_banks()
*/
void sam3_free_driver_priv(struct flash_bank *bank)
{
struct sam3_chip *chip = all_sam3_chips;
while (chip) {
struct sam3_chip *next = chip->next;
free(chip);
chip = next;
}
all_sam3_chips = NULL;
}
static int sam3_GetDetails(struct sam3_bank_private *pPrivate)
{
const struct sam3_chip_details *pDetails;
@@ -3771,4 +3787,5 @@ struct flash_driver at91sam3_flash = {
.auto_probe = sam3_auto_probe,
.erase_check = sam3_erase_check,
.protect_check = sam3_protect_check,
.free_driver_priv = sam3_free_driver_priv,
};
+54 -44
View File
@@ -682,6 +682,40 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
},
/*at91sam4sa16c - TFBGA100/VFBGA100/LQFP100*/
{
.chipid_cidr = 0x28a70ce0,
.name = "at91sam4sa16c",
.total_flash_size = 1024 * 1024,
.total_sram_size = 160 * 1024,
.n_gpnvms = 2,
.n_banks = 1,
/* .bank[0] = { */
{
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 5,
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
.sector_size = 8192,
.page_size = 512,
},
/* .bank[1] = {*/
{
.present = 0,
.probed = 0,
.bank_number = 1,
},
},
},
/*atsam4s16b - LQFP64/QFN64/WLCSP64*/
{
.chipid_cidr = 0x289C0CE0,
@@ -1243,50 +1277,6 @@ static const struct sam4_chip_details all_sam4_details[] = {
.page_size = 512,
},
/* .bank[1] = { */
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 1,
.base_address = FLASH_BANK1_BASE_1024K_SD,
.controller_address = 0x400e0c00,
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
.sector_size = 8192,
.page_size = 512,
},
},
},
/*at91sam4sa16c*/
{
.chipid_cidr = 0x28a70ce0,
.name = "at91sam4sa16c",
.total_flash_size = 1024 * 1024,
.total_sram_size = 160 * 1024,
.n_gpnvms = 3,
.n_banks = 2,
/* .bank[0] = { */
{
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.base_address = FLASH_BANK0_BASE_SD,
.controller_address = 0x400e0a00,
.flash_wait_states = 5,
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
.sector_size = 8192,
.page_size = 512,
},
/* .bank[1] = { */
{
.probed = 0,
@@ -2514,6 +2504,22 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command)
return ERROR_OK;
}
/**
* Remove all chips from the internal list without distingushing which one
* is owned by this bank. This simplification works only for one shot
* deallocation like current flash_free_all_banks()
*/
static void sam4_free_driver_priv(struct flash_bank *bank)
{
struct sam4_chip *chip = all_sam4_chips;
while (chip) {
struct sam4_chip *next = chip->next;
free(chip);
chip = next;
}
all_sam4_chips = NULL;
}
static int sam4_GetDetails(struct sam4_bank_private *pPrivate)
{
const struct sam4_chip_details *pDetails;
@@ -2538,6 +2544,8 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate)
pPrivate->pChip->cfg.CHIPID_CIDR);
sam4_explain_chipid_cidr(pPrivate->pChip);
return ERROR_FAIL;
} else {
LOG_INFO("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr);
}
/* DANGER: THERE ARE DRAGONS HERE */
@@ -2608,6 +2616,7 @@ static int _sam4_probe(struct flash_bank *bank, int noise)
for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) {
if (bank->base == pPrivate->pChip->details.bank[x].base_address) {
bank->size = pPrivate->pChip->details.bank[x].size_bytes;
LOG_INFO("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x);
break;
}
}
@@ -3194,4 +3203,5 @@ struct flash_driver at91sam4_flash = {
.auto_probe = sam4_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = sam4_protect_check,
.free_driver_priv = sam4_free_driver_priv,
};
+14 -27
View File
@@ -129,10 +129,8 @@ struct sam4l_info {
bool probed;
struct target *target;
struct sam4l_info *next;
};
static struct sam4l_info *sam4l_chips;
static int sam4l_flash_wait_until_ready(struct target *target)
{
@@ -204,30 +202,6 @@ static int sam4l_flash_command(struct target *target, uint8_t cmd, int page)
FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command)
{
struct sam4l_info *chip = sam4l_chips;
while (chip) {
if (chip->target == bank->target)
break;
chip = chip->next;
}
if (!chip) {
/* Create a new chip */
chip = calloc(1, sizeof(*chip));
if (!chip)
return ERROR_FAIL;
chip->target = bank->target;
chip->probed = false;
bank->driver_priv = chip;
/* Insert it into the chips list (at head) */
chip->next = sam4l_chips;
sam4l_chips = chip;
}
if (bank->base != SAM4L_FLASH) {
LOG_ERROR("Address 0x%08" PRIx32 " invalid bank address (try 0x%08" PRIx32
"[at91sam4l series] )",
@@ -235,6 +209,18 @@ FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command)
return ERROR_FAIL;
}
struct sam4l_info *chip;
chip = calloc(1, sizeof(*chip));
if (!chip) {
LOG_ERROR("No memory for flash bank chip info");
return ERROR_FAIL;
}
chip->target = bank->target;
chip->probed = false;
bank->driver_priv = chip;
return ERROR_OK;
}
@@ -396,7 +382,7 @@ static int sam4l_protect_check(struct flash_bank *bank)
static int sam4l_protect(struct flash_bank *bank, int set, int first, int last)
{
struct sam4l_info *chip = sam4l_chips;
struct sam4l_info *chip = (struct sam4l_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -709,4 +695,5 @@ struct flash_driver at91sam4l_flash = {
.auto_probe = sam4l_probe,
.erase_check = default_flash_blank_check,
.protect_check = sam4l_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+1 -47
View File
@@ -639,14 +639,6 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
static int at91sam7_erase_check(struct flash_bank *bank)
{
struct target *target = bank->target;
uint16_t retval;
uint32_t blank;
uint16_t fast_check;
uint8_t *buffer;
uint16_t nSector;
uint16_t nByte;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -656,45 +648,7 @@ static int at91sam7_erase_check(struct flash_bank *bank)
at91sam7_read_clock_info(bank);
at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
fast_check = 1;
for (nSector = 0; nSector < bank->num_sectors; nSector++) {
retval = target_blank_check_memory(target,
bank->base + bank->sectors[nSector].offset,
bank->sectors[nSector].size,
&blank, bank->erased_value);
if (retval != ERROR_OK) {
fast_check = 0;
break;
}
if (blank == 0xFF)
bank->sectors[nSector].is_erased = 1;
else
bank->sectors[nSector].is_erased = 0;
}
if (fast_check)
return ERROR_OK;
LOG_USER("Running slow fallback erase check - add working memory");
buffer = malloc(bank->sectors[0].size);
for (nSector = 0; nSector < bank->num_sectors; nSector++) {
bank->sectors[nSector].is_erased = 1;
retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
bank->sectors[nSector].size/4, buffer);
if (retval != ERROR_OK)
return retval;
for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++) {
if (buffer[nByte] != 0xFF) {
bank->sectors[nSector].is_erased = 0;
break;
}
}
}
free(buffer);
return ERROR_OK;
return default_flash_blank_check(bank);
}
static int at91sam7_protect_check(struct flash_bank *bank)
+276 -127
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;
@@ -112,15 +115,16 @@ static const struct samd_part samd10_parts[] = {
/* Known SAMD11 parts */
static const struct samd_part samd11_parts[] = {
{ 0x0, "SAMD11D14AMU", 16, 4 },
{ 0x0, "SAMD11D14AM", 16, 4 },
{ 0x1, "SAMD11D13AMU", 8, 4 },
{ 0x2, "SAMD11D12AMU", 4, 4 },
{ 0x3, "SAMD11D14ASU", 16, 4 },
{ 0x3, "SAMD11D14ASS", 16, 4 },
{ 0x4, "SAMD11D13ASU", 8, 4 },
{ 0x5, "SAMD11D12ASU", 4, 4 },
{ 0x6, "SAMD11C14A", 16, 4 },
{ 0x7, "SAMD11C13A", 8, 4 },
{ 0x8, "SAMD11C12A", 4, 4 },
{ 0x9, "SAMD11D14AU", 16, 4 },
};
/* Known SAMD20 parts. See Table 12-8 in 42129FSAM10/2013 */
@@ -159,23 +163,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 +203,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 +263,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 {
@@ -290,29 +305,45 @@ struct samd_info {
bool probed;
struct target *target;
struct samd_info *next;
};
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 +514,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 +541,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 +606,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 +656,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 +714,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!");
@@ -803,30 +875,6 @@ free_pb:
FLASH_BANK_COMMAND_HANDLER(samd_flash_bank_command)
{
struct samd_info *chip = samd_chips;
while (chip) {
if (chip->target == bank->target)
break;
chip = chip->next;
}
if (!chip) {
/* Create a new chip */
chip = calloc(1, sizeof(*chip));
if (!chip)
return ERROR_FAIL;
chip->target = bank->target;
chip->probed = false;
bank->driver_priv = chip;
/* Insert it into the chips list (at head) */
chip->next = samd_chips;
samd_chips = chip;
}
if (bank->base != SAMD_FLASH) {
LOG_ERROR("Address 0x%08" PRIx32 " invalid bank address (try 0x%08" PRIx32
"[at91samd series] )",
@@ -834,6 +882,18 @@ FLASH_BANK_COMMAND_HANDLER(samd_flash_bank_command)
return ERROR_FAIL;
}
struct samd_info *chip;
chip = calloc(1, sizeof(*chip));
if (!chip) {
LOG_ERROR("No memory for flash bank chip info");
return ERROR_FAIL;
}
chip->target = bank->target;
chip->probed = false;
bank->driver_priv = chip;
return ERROR_OK;
}
@@ -944,6 +1004,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 +1186,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 +1216,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 +1226,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
};
@@ -1120,4 +1268,5 @@ struct flash_driver at91samd_flash = {
.auto_probe = samd_probe,
.erase_check = default_flash_blank_check,
.protect_check = samd_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};
+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,
};
+567
View File
@@ -0,0 +1,567 @@
/***************************************************************************
* Copyright (C) 2017 by Texas Instruments, Inc. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "cc26xx.h"
#include <helper/binarybuffer.h>
#include <helper/time_support.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#include <target/image.h>
#define FLASH_TIMEOUT 8000
struct cc26xx_bank {
const char *family_name;
uint32_t icepick_id;
uint32_t user_id;
uint32_t device_type;
uint32_t sector_length;
bool probed;
struct working_area *working_area;
struct armv7m_algorithm armv7m_info;
const uint8_t *algo_code;
uint32_t algo_size;
uint32_t algo_working_size;
uint32_t buffer_addr[2];
uint32_t params_addr[2];
};
static int cc26xx_auto_probe(struct flash_bank *bank);
static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id)
{
uint32_t device_type = 0;
switch (icepick_id & ICEPICK_ID_MASK) {
case CC26X0_ICEPICK_ID:
device_type = CC26X0_TYPE;
break;
case CC26X1_ICEPICK_ID:
device_type = CC26X1_TYPE;
break;
case CC13X0_ICEPICK_ID:
device_type = CC13X0_TYPE;
break;
case CC13X2_CC26X2_ICEPICK_ID:
default:
if ((user_id & USER_ID_CC13_MASK) != 0)
device_type = CC13X2_TYPE;
else
device_type = CC26X2_TYPE;
break;
}
return device_type;
}
static uint32_t cc26xx_sector_length(uint32_t icepick_id)
{
uint32_t sector_length;
switch (icepick_id & ICEPICK_ID_MASK) {
case CC26X0_ICEPICK_ID:
case CC26X1_ICEPICK_ID:
case CC13X0_ICEPICK_ID:
/* Chameleon family device */
sector_length = CC26X0_SECTOR_LENGTH;
break;
case CC13X2_CC26X2_ICEPICK_ID:
default:
/* Agama family device */
sector_length = CC26X2_SECTOR_LENGTH;
break;
}
return sector_length;
}
static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr)
{
struct target *target = bank->target;
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
uint32_t status_addr = params_addr + CC26XX_STATUS_OFFSET;
uint32_t status = CC26XX_BUFFER_FULL;
long long start_ms;
long long elapsed_ms;
int retval = ERROR_OK;
start_ms = timeval_ms();
while (CC26XX_BUFFER_FULL == status) {
retval = target_read_u32(target, status_addr, &status);
if (ERROR_OK != retval)
return retval;
elapsed_ms = timeval_ms() - start_ms;
if (elapsed_ms > 500)
keep_alive();
if (elapsed_ms > FLASH_TIMEOUT)
break;
};
if (CC26XX_BUFFER_EMPTY != status) {
LOG_ERROR("%s: Flash operation failed", cc26xx_bank->family_name);
return ERROR_FAIL;
}
return ERROR_OK;
}
static int cc26xx_init(struct flash_bank *bank)
{
struct target *target = bank->target;
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
int retval;
/* Make sure we've probed the flash to get the device and size */
retval = cc26xx_auto_probe(bank);
if (ERROR_OK != retval)
return retval;
/* Check for working area to use for flash helper algorithm */
if (NULL != cc26xx_bank->working_area)
target_free_working_area(target, cc26xx_bank->working_area);
retval = target_alloc_working_area(target, cc26xx_bank->algo_working_size,
&cc26xx_bank->working_area);
if (ERROR_OK != retval)
return retval;
/* Confirm the defined working address is the area we need to use */
if (CC26XX_ALGO_BASE_ADDRESS != cc26xx_bank->working_area->address)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
/* Write flash helper algorithm into target memory */
retval = target_write_buffer(target, CC26XX_ALGO_BASE_ADDRESS,
cc26xx_bank->algo_size, cc26xx_bank->algo_code);
if (ERROR_OK != retval) {
LOG_ERROR("%s: Failed to load flash helper algorithm",
cc26xx_bank->family_name);
target_free_working_area(target, cc26xx_bank->working_area);
return retval;
}
/* Initialize the ARMv7 specific info to run the algorithm */
cc26xx_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
cc26xx_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
/* Begin executing the flash helper algorithm */
retval = target_start_algorithm(target, 0, NULL, 0, NULL,
CC26XX_ALGO_BASE_ADDRESS, 0, &cc26xx_bank->armv7m_info);
if (ERROR_OK != retval) {
LOG_ERROR("%s: Failed to start flash helper algorithm",
cc26xx_bank->family_name);
target_free_working_area(target, cc26xx_bank->working_area);
return retval;
}
/*
* At this point, the algorithm is running on the target and
* ready to receive commands and data to flash the target
*/
return retval;
}
static int cc26xx_quit(struct flash_bank *bank)
{
struct target *target = bank->target;
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
int retval;
/* Regardless of the algo's status, attempt to halt the target */
(void)target_halt(target);
/* Now confirm target halted and clean up from flash helper algorithm */
retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, FLASH_TIMEOUT,
&cc26xx_bank->armv7m_info);
target_free_working_area(target, cc26xx_bank->working_area);
cc26xx_bank->working_area = NULL;
return retval;
}
static int cc26xx_mass_erase(struct flash_bank *bank)
{
struct target *target = bank->target;
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
struct cc26xx_algo_params algo_params;
int retval;
if (TARGET_HALTED != target->state) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
retval = cc26xx_init(bank);
if (ERROR_OK != retval)
return retval;
/* Initialize algorithm parameters */
buf_set_u32(algo_params.address, 0, 32, 0);
buf_set_u32(algo_params.length, 0, 32, 4);
buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_ALL);
buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
/* Issue flash helper algorithm parameters for mass erase */
retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
sizeof(algo_params), (uint8_t *)&algo_params);
/* Wait for command to complete */
if (ERROR_OK == retval)
retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
/* Regardless of errors, try to close down algo */
(void)cc26xx_quit(bank);
return retval;
}
FLASH_BANK_COMMAND_HANDLER(cc26xx_flash_bank_command)
{
struct cc26xx_bank *cc26xx_bank;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
cc26xx_bank = malloc(sizeof(struct cc26xx_bank));
if (NULL == cc26xx_bank)
return ERROR_FAIL;
/* Initialize private flash information */
memset((void *)cc26xx_bank, 0x00, sizeof(struct cc26xx_bank));
cc26xx_bank->family_name = "cc26xx";
cc26xx_bank->device_type = CC26XX_NO_TYPE;
cc26xx_bank->sector_length = 0x1000;
/* Finish initialization of bank */
bank->driver_priv = cc26xx_bank;
bank->next = NULL;
return ERROR_OK;
}
static int cc26xx_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
struct cc26xx_algo_params algo_params;
uint32_t address;
uint32_t length;
int retval;
if (TARGET_HALTED != target->state) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Do a mass erase if user requested all sectors of flash */
if ((first == 0) && (last == (bank->num_sectors - 1))) {
/* Request mass erase of flash */
return cc26xx_mass_erase(bank);
}
address = first * cc26xx_bank->sector_length;
length = (last - first + 1) * cc26xx_bank->sector_length;
retval = cc26xx_init(bank);
if (ERROR_OK != retval)
return retval;
/* Set up algorithm parameters for erase command */
buf_set_u32(algo_params.address, 0, 32, address);
buf_set_u32(algo_params.length, 0, 32, length);
buf_set_u32(algo_params.command, 0, 32, CC26XX_CMD_ERASE_SECTORS);
buf_set_u32(algo_params.status, 0, 32, CC26XX_BUFFER_FULL);
/* Issue flash helper algorithm parameters for erase */
retval = target_write_buffer(target, cc26xx_bank->params_addr[0],
sizeof(algo_params), (uint8_t *)&algo_params);
/* If no error, wait for erase to finish */
if (ERROR_OK == retval)
retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[0]);
/* Regardless of errors, try to close down algo */
(void)cc26xx_quit(bank);
return retval;
}
static int cc26xx_protect(struct flash_bank *bank, int set, int first,
int last)
{
return ERROR_OK;
}
static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
struct cc26xx_algo_params algo_params[2];
uint32_t size = 0;
long long start_ms;
long long elapsed_ms;
uint32_t address;
uint32_t index;
int retval;
if (TARGET_HALTED != target->state) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
retval = cc26xx_init(bank);
if (ERROR_OK != retval)
return retval;
/* Initialize algorithm parameters to default values */
buf_set_u32(algo_params[0].command, 0, 32, CC26XX_CMD_PROGRAM);
buf_set_u32(algo_params[1].command, 0, 32, CC26XX_CMD_PROGRAM);
/* Write requested data, ping-ponging between two buffers */
index = 0;
start_ms = timeval_ms();
address = bank->base + offset;
while (count > 0) {
if (count > cc26xx_bank->sector_length)
size = cc26xx_bank->sector_length;
else
size = count;
/* Put next block of data to flash into buffer */
retval = target_write_buffer(target, cc26xx_bank->buffer_addr[index],
size, buffer);
if (ERROR_OK != retval) {
LOG_ERROR("Unable to write data to target memory");
break;
}
/* Update algo parameters for next block */
buf_set_u32(algo_params[index].address, 0, 32, address);
buf_set_u32(algo_params[index].length, 0, 32, size);
buf_set_u32(algo_params[index].status, 0, 32, CC26XX_BUFFER_FULL);
/* Issue flash helper algorithm parameters for block write */
retval = target_write_buffer(target, cc26xx_bank->params_addr[index],
sizeof(algo_params[index]), (uint8_t *)&algo_params[index]);
if (ERROR_OK != retval)
break;
/* Wait for next ping pong buffer to be ready */
index ^= 1;
retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
if (ERROR_OK != retval)
break;
count -= size;
buffer += size;
address += size;
elapsed_ms = timeval_ms() - start_ms;
if (elapsed_ms > 500)
keep_alive();
}
/* If no error yet, wait for last buffer to finish */
if (ERROR_OK == retval) {
index ^= 1;
retval = cc26xx_wait_algo_done(bank, cc26xx_bank->params_addr[index]);
}
/* Regardless of errors, try to close down algo */
(void)cc26xx_quit(bank);
return retval;
}
static int cc26xx_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
uint32_t sector_length;
uint32_t value;
int num_sectors;
int max_sectors;
int retval;
retval = target_read_u32(target, FCFG1_ICEPICK_ID, &value);
if (ERROR_OK != retval)
return retval;
cc26xx_bank->icepick_id = value;
retval = target_read_u32(target, FCFG1_USER_ID, &value);
if (ERROR_OK != retval)
return retval;
cc26xx_bank->user_id = value;
cc26xx_bank->device_type = cc26xx_device_type(cc26xx_bank->icepick_id,
cc26xx_bank->user_id);
sector_length = cc26xx_sector_length(cc26xx_bank->icepick_id);
/* Set up appropriate flash helper algorithm */
switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) {
case CC26X0_ICEPICK_ID:
case CC26X1_ICEPICK_ID:
case CC13X0_ICEPICK_ID:
/* Chameleon family device */
cc26xx_bank->algo_code = cc26x0_algo;
cc26xx_bank->algo_size = sizeof(cc26x0_algo);
cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE;
cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0;
cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1;
cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0;
cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1;
max_sectors = CC26X0_MAX_SECTORS;
break;
case CC13X2_CC26X2_ICEPICK_ID:
default:
/* Agama family device */
cc26xx_bank->algo_code = cc26x2_algo;
cc26xx_bank->algo_size = sizeof(cc26x2_algo);
cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE;
cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0;
cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1;
cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0;
cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1;
max_sectors = CC26X2_MAX_SECTORS;
break;
}
retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value);
if (ERROR_OK != retval)
return retval;
num_sectors = value & 0xff;
if (num_sectors > max_sectors)
num_sectors = max_sectors;
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
if (NULL == bank->sectors)
return ERROR_FAIL;
bank->base = CC26XX_FLASH_BASE_ADDR;
bank->num_sectors = num_sectors;
bank->size = num_sectors * sector_length;
bank->write_start_alignment = 0;
bank->write_end_alignment = 0;
cc26xx_bank->sector_length = sector_length;
for (int i = 0; i < num_sectors; i++) {
bank->sectors[i].offset = i * sector_length;
bank->sectors[i].size = sector_length;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0;
}
/* We've successfully determined the stats on the flash bank */
cc26xx_bank->probed = true;
/* If we fall through to here, then all went well */
return ERROR_OK;
}
static int cc26xx_auto_probe(struct flash_bank *bank)
{
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
int retval = ERROR_OK;
if (bank->bank_number != 0) {
/* Invalid bank number somehow */
return ERROR_FAIL;
}
if (!cc26xx_bank->probed)
retval = cc26xx_probe(bank);
return retval;
}
static int cc26xx_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
int printed = 0;
const char *device;
switch (cc26xx_bank->device_type) {
case CC26X0_TYPE:
device = "CC26x0";
break;
case CC26X1_TYPE:
device = "CC26x1";
break;
case CC13X0_TYPE:
device = "CC13x0";
break;
case CC13X2_TYPE:
device = "CC13x2";
break;
case CC26X2_TYPE:
device = "CC26x2";
break;
case CC26XX_NO_TYPE:
default:
device = "Unrecognized";
break;
}
printed = snprintf(buf, buf_size,
"%s device: ICEPick ID 0x%08x, USER ID 0x%08x\n",
device, cc26xx_bank->icepick_id, cc26xx_bank->user_id);
if (printed >= buf_size)
return ERROR_BUF_TOO_SMALL;
return ERROR_OK;
}
struct flash_driver cc26xx_flash = {
.name = "cc26xx",
.flash_bank_command = cc26xx_flash_bank_command,
.erase = cc26xx_erase,
.protect = cc26xx_protect,
.write = cc26xx_write,
.read = default_flash_read,
.probe = cc26xx_probe,
.auto_probe = cc26xx_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = cc26xx_protect_check,
.info = cc26xx_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+101
View File
@@ -0,0 +1,101 @@
/***************************************************************************
* Copyright (C) 2017 by Texas Instruments, Inc. *
* *
* 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/>. *
***************************************************************************/
#ifndef OPENOCD_FLASH_NOR_CC26XX_H
#define OPENOCD_FLASH_NOR_CC26XX_H
/* Addresses of FCFG1 registers to access ICEPick Device ID and User ID */
#define FCFG1_ICEPICK_ID 0x50001318
#define FCFG1_USER_ID 0x50001294
/* ICEPick device ID mask and values */
#define ICEPICK_ID_MASK 0x0fffffff
#define ICEPICK_REV_MASK 0xf0000000
#define CC26X0_ICEPICK_ID 0x0b99a02f
#define CC26X1_ICEPICK_ID 0x0b9bd02f
#define CC13X0_ICEPICK_ID 0x0b9be02f
#define CC13X2_CC26X2_ICEPICK_ID 0x0bb4102f
/* User ID mask for Agama CC13x2 vs CC26x2 */
#define USER_ID_CC13_MASK 0x00800000
/* Common CC26xx/CC13xx flash and memory parameters */
#define CC26XX_FLASH_BASE_ADDR 0x00000000
#define CC26XX_FLASH_SIZE_INFO 0x4003002c
#define CC26XX_SRAM_SIZE_INFO 0x40082250
#define CC26XX_ALGO_BASE_ADDRESS 0x20000000
/* Chameleon CC26x0/CC13x0 specific parameters */
#define CC26X0_MAX_SECTORS 32
#define CC26X0_SECTOR_LENGTH 0x1000
#define CC26X0_ALGO_BUFFER_0 0x20001c00
#define CC26X0_ALGO_BUFFER_1 0x20002c00
#define CC26X0_ALGO_PARAMS_0 0x20001bd8
#define CC26X0_ALGO_PARAMS_1 0x20001bec
#define CC26X0_WORKING_SIZE (CC26X0_ALGO_BUFFER_1 + CC26X0_SECTOR_LENGTH - \
CC26XX_ALGO_BASE_ADDRESS)
/* Agama CC26x2/CC13x2 specific parameters */
#define CC26X2_MAX_SECTORS 128
#define CC26X2_SECTOR_LENGTH 0x2000
#define CC26X2_ALGO_BUFFER_0 0x20002000
#define CC26X2_ALGO_BUFFER_1 0x20004000
#define CC26X2_ALGO_PARAMS_0 0x20001fd8
#define CC26X2_ALGO_PARAMS_1 0x20001fec
#define CC26X2_WORKING_SIZE (CC26X2_ALGO_BUFFER_1 + CC26X2_SECTOR_LENGTH - \
CC26XX_ALGO_BASE_ADDRESS)
/* CC26xx flash helper algorithm buffer flags */
#define CC26XX_BUFFER_EMPTY 0x00000000
#define CC26XX_BUFFER_FULL 0xffffffff
/* CC26XX flash helper algorithm commands */
#define CC26XX_CMD_NO_ACTION 0
#define CC26XX_CMD_ERASE_ALL 1
#define CC26XX_CMD_PROGRAM 2
#define CC26XX_CMD_ERASE_AND_PROGRAM 3
#define CC26XX_CMD_ERASE_AND_PROGRAM_WITH_RETAIN 4
#define CC26XX_CMD_ERASE_SECTORS 5
/* CC26xx and CC13xx device types */
#define CC26XX_NO_TYPE 0 /* Device type not determined yet */
#define CC26X0_TYPE 1 /* CC26x0 Chameleon device */
#define CC26X1_TYPE 2 /* CC26x1 Chameleon device */
#define CC26X2_TYPE 3 /* CC26x2 Agama device */
#define CC13X0_TYPE 4 /* CC13x0 Chameleon device */
#define CC13X2_TYPE 5 /* CC13x2 Agama device */
/* Flash helper algorithm parameter block struct */
#define CC26XX_STATUS_OFFSET 0x0c
struct cc26xx_algo_params {
uint8_t address[4];
uint8_t length[4];
uint8_t command[4];
uint8_t status[4];
};
/* Flash helper algorithm for CC26x0 Chameleon targets */
const uint8_t cc26x0_algo[] = {
#include "../../../contrib/loaders/flash/cc26xx/cc26x0_algo.inc"
};
/* Flash helper algorithm for CC26x2 Agama targets */
const uint8_t cc26x2_algo[] = {
#include "../../../contrib/loaders/flash/cc26xx/cc26x2_algo.inc"
};
#endif /* OPENOCD_FLASH_NOR_CC26XX_H */
+529
View File
@@ -0,0 +1,529 @@
/***************************************************************************
* Copyright (C) 2017 by Texas Instruments, Inc. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "cc3220sf.h"
#include <helper/time_support.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#define FLASH_TIMEOUT 5000
struct cc3220sf_bank {
bool probed;
struct armv7m_algorithm armv7m_info;
};
static int cc3220sf_mass_erase(struct flash_bank *bank)
{
struct target *target = bank->target;
bool done;
long long start_ms;
long long elapsed_ms;
uint32_t value;
int retval = ERROR_OK;
if (TARGET_HALTED != target->state) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Set starting address to erase to zero */
retval = target_write_u32(target, FMA_REGISTER_ADDR, 0);
if (ERROR_OK != retval)
return retval;
/* Write the MERASE bit of the FMC register */
retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE);
if (ERROR_OK != retval)
return retval;
/* Poll the MERASE bit until the mass erase is complete */
done = false;
start_ms = timeval_ms();
while (!done) {
retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
if (ERROR_OK != retval)
return retval;
if ((value & FMC_MERASE_BIT) == 0) {
/* Bit clears when mass erase is finished */
done = true;
} else {
elapsed_ms = timeval_ms() - start_ms;
if (elapsed_ms > 500)
keep_alive();
if (elapsed_ms > FLASH_TIMEOUT)
break;
}
}
if (!done) {
/* Mass erase timed out waiting for confirmation */
return ERROR_FAIL;
}
return retval;
}
FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
{
struct cc3220sf_bank *cc3220sf_bank;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
if (NULL == cc3220sf_bank)
return ERROR_FAIL;
/* Initialize private flash information */
cc3220sf_bank->probed = false;
/* Finish initialization of flash bank */
bank->driver_priv = cc3220sf_bank;
bank->next = NULL;
return ERROR_OK;
}
static int cc3220sf_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
bool done;
long long start_ms;
long long elapsed_ms;
uint32_t address;
uint32_t value;
int retval = ERROR_OK;
if (TARGET_HALTED != target->state) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Do a mass erase if user requested all sectors of flash */
if ((first == 0) && (last == (bank->num_sectors - 1))) {
/* Request mass erase of flash */
return cc3220sf_mass_erase(bank);
}
/* Erase requested sectors one by one */
for (int i = first; i <= last; i++) {
/* Determine address of sector to erase */
address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE;
/* Set starting address to erase */
retval = target_write_u32(target, FMA_REGISTER_ADDR, address);
if (ERROR_OK != retval)
return retval;
/* Write the ERASE bit of the FMC register */
retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE);
if (ERROR_OK != retval)
return retval;
/* Poll the ERASE bit until the erase is complete */
done = false;
start_ms = timeval_ms();
while (!done) {
retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
if (ERROR_OK != retval)
return retval;
if ((value & FMC_ERASE_BIT) == 0) {
/* Bit clears when mass erase is finished */
done = true;
} else {
elapsed_ms = timeval_ms() - start_ms;
if (elapsed_ms > 500)
keep_alive();
if (elapsed_ms > FLASH_TIMEOUT)
break;
}
}
if (!done) {
/* Sector erase timed out waiting for confirmation */
return ERROR_FAIL;
}
}
return retval;
}
static int cc3220sf_protect(struct flash_bank *bank, int set, int first,
int last)
{
return ERROR_OK;
}
static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
struct working_area *algo_working_area;
struct working_area *buffer_working_area;
struct reg_param reg_params[3];
uint32_t algo_base_address;
uint32_t algo_buffer_address;
uint32_t algo_buffer_size;
uint32_t address;
uint32_t remaining;
uint32_t words;
uint32_t result;
int retval = ERROR_OK;
if (TARGET_HALTED != target->state) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Obtain working area to use for flash helper algorithm */
retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
&algo_working_area);
if (ERROR_OK != retval)
return retval;
/* Obtain working area to use for flash buffer */
retval = target_alloc_working_area(target,
target_get_working_area_avail(target), &buffer_working_area);
if (ERROR_OK != retval) {
target_free_working_area(target, algo_working_area);
return retval;
}
algo_base_address = algo_working_area->address;
algo_buffer_address = buffer_working_area->address;
algo_buffer_size = buffer_working_area->size;
/* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
/* (algo runs more efficiently if it operates on 32 words at a time) */
if (algo_buffer_size > 0x80)
algo_buffer_size &= ~0x7f;
/* Write flash helper algorithm into target memory */
retval = target_write_buffer(target, algo_base_address,
sizeof(cc3220sf_algo), cc3220sf_algo);
if (ERROR_OK != retval) {
target_free_working_area(target, algo_working_area);
target_free_working_area(target, buffer_working_area);
return retval;
}
/* Initialize the ARMv7m specific info to run the algorithm */
cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
/* Initialize register params for flash helper algorithm */
init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
/* Prepare to write to flash */
address = FLASH_BASE_ADDR + offset;
remaining = count;
/* The flash hardware can only write complete words to flash. If
* an unaligned address is passed in, we must do a read-modify-write
* on a word with enough bytes to align the rest of the buffer. And
* if less than a whole word remains at the end, we must also do a
* read-modify-write on a final word to finish up.
*/
/* Do one word write to align address on 32-bit boundary if needed */
if (0 != (address & 0x3)) {
uint8_t head[4];
/* Get starting offset for data to write (will be 1 to 3) */
uint32_t head_offset = address & 0x03;
/* Get the aligned address to write this first word to */
uint32_t head_address = address & 0xfffffffc;
/* Retrieve what is already in flash at the head address */
retval = target_read_buffer(target, head_address, sizeof(head), head);
if (ERROR_OK == retval) {
/* Substitute in the new data to write */
while ((remaining > 0) && (head_offset < 4)) {
head[head_offset] = *buffer;
head_offset++;
address++;
buffer++;
remaining--;
}
}
if (ERROR_OK == retval) {
/* Helper parameters are passed in registers R0-R2 */
/* Set start of data buffer, address to write to, and word count */
buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
buf_set_u32(reg_params[1].value, 0, 32, head_address);
buf_set_u32(reg_params[2].value, 0, 32, 1);
/* Write head value into buffer to flash */
retval = target_write_buffer(target, algo_buffer_address,
sizeof(head), head);
}
if (ERROR_OK == retval) {
/* Execute the flash helper algorithm */
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
algo_base_address, 0, FLASH_TIMEOUT,
&cc3220sf_bank->armv7m_info);
if (ERROR_OK != retval)
LOG_ERROR("cc3220sf: Flash algorithm failed to run");
/* Check that the head value was written to flash */
result = buf_get_u32(reg_params[2].value, 0, 32);
if (0 != result) {
retval = ERROR_FAIL;
LOG_ERROR("cc3220sf: Flash operation failed");
}
}
}
/* Check if there's data at end of buffer that isn't a full word */
uint32_t tail_count = remaining & 0x03;
/* Adjust remaining so it is a multiple of whole words */
remaining -= tail_count;
while ((ERROR_OK == retval) && (remaining > 0)) {
/* Set start of data buffer and address to write to */
buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
buf_set_u32(reg_params[1].value, 0, 32, address);
/* Download data to write into memory buffer */
if (remaining >= algo_buffer_size) {
/* Fill up buffer with data to flash */
retval = target_write_buffer(target, algo_buffer_address,
algo_buffer_size, buffer);
if (ERROR_OK != retval)
break;
/* Count to write is in 32-bit words */
words = algo_buffer_size / 4;
/* Bump variables to next data */
address += algo_buffer_size;
buffer += algo_buffer_size;
remaining -= algo_buffer_size;
} else {
/* Fill buffer with what's left of the data */
retval = target_write_buffer(target, algo_buffer_address,
remaining, buffer);
if (ERROR_OK != retval)
break;
/* Calculate the final word count to write */
words = remaining / 4;
if (0 != (remaining % 4))
words++;
/* Bump variables to any final data */
address += remaining;
buffer += remaining;
remaining = 0;
}
/* Set number of words to write */
buf_set_u32(reg_params[2].value, 0, 32, words);
/* Execute the flash helper algorithm */
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
algo_base_address, 0, FLASH_TIMEOUT,
&cc3220sf_bank->armv7m_info);
if (ERROR_OK != retval) {
LOG_ERROR("cc3220sf: Flash algorithm failed to run");
break;
}
/* Check that all words were written to flash */
result = buf_get_u32(reg_params[2].value, 0, 32);
if (0 != result) {
retval = ERROR_FAIL;
LOG_ERROR("cc3220sf: Flash operation failed");
break;
}
}
/* Do one word write for any final bytes less than a full word */
if ((ERROR_OK == retval) && (0 != tail_count)) {
uint8_t tail[4];
/* Set starting byte offset for data to write */
uint32_t tail_offset = 0;
/* Retrieve what is already in flash at the tail address */
retval = target_read_buffer(target, address, sizeof(tail), tail);
if (ERROR_OK == retval) {
/* Substitute in the new data to write */
while (tail_count > 0) {
tail[tail_offset] = *buffer;
tail_offset++;
buffer++;
tail_count--;
}
}
if (ERROR_OK == retval) {
/* Set start of data buffer, address to write to, and word count */
buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
buf_set_u32(reg_params[1].value, 0, 32, address);
buf_set_u32(reg_params[2].value, 0, 32, 1);
/* Write tail value into buffer to flash */
retval = target_write_buffer(target, algo_buffer_address,
sizeof(tail), tail);
}
if (ERROR_OK == retval) {
/* Execute the flash helper algorithm */
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
algo_base_address, 0, FLASH_TIMEOUT,
&cc3220sf_bank->armv7m_info);
if (ERROR_OK != retval)
LOG_ERROR("cc3220sf: Flash algorithm failed to run");
/* Check that the tail was written to flash */
result = buf_get_u32(reg_params[2].value, 0, 32);
if (0 != result) {
retval = ERROR_FAIL;
LOG_ERROR("cc3220sf: Flash operation failed");
}
}
}
/* Free resources */
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
target_free_working_area(target, algo_working_area);
target_free_working_area(target, buffer_working_area);
return retval;
}
static int cc3220sf_probe(struct flash_bank *bank)
{
struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
uint32_t base;
uint32_t size;
int num_sectors;
int bank_id;
bank_id = bank->bank_number;
if (0 == bank_id) {
base = FLASH_BASE_ADDR;
size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
num_sectors = FLASH_NUM_SECTORS;
} else {
/* Invalid bank number somehow */
return ERROR_FAIL;
}
if (NULL != bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
if (NULL == bank->sectors)
return ERROR_FAIL;
bank->base = base;
bank->size = size;
bank->write_start_alignment = 0;
bank->write_end_alignment = 0;
bank->num_sectors = num_sectors;
for (int i = 0; i < num_sectors; i++) {
bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
bank->sectors[i].size = FLASH_SECTOR_SIZE;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0;
}
/* We've successfully recorded the stats on this flash bank */
cc3220sf_bank->probed = true;
/* If we fall through to here, then all went well */
return ERROR_OK;
}
static int cc3220sf_auto_probe(struct flash_bank *bank)
{
struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
int retval = ERROR_OK;
if (0 != bank->bank_number) {
/* Invalid bank number somehow */
return ERROR_FAIL;
}
if (!cc3220sf_bank->probed)
retval = cc3220sf_probe(bank);
return retval;
}
static int cc3220sf_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
{
int printed;
printed = snprintf(buf, buf_size, "CC3220SF with 1MB internal flash\n");
if (printed >= buf_size)
return ERROR_BUF_TOO_SMALL;
return ERROR_OK;
}
struct flash_driver cc3220sf_flash = {
.name = "cc3220sf",
.flash_bank_command = cc3220sf_flash_bank_command,
.erase = cc3220sf_erase,
.protect = cc3220sf_protect,
.write = cc3220sf_write,
.read = default_flash_read,
.probe = cc3220sf_probe,
.auto_probe = cc3220sf_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = cc3220sf_protect_check,
.info = cc3220sf_info,
.free_driver_priv = default_flash_free_driver_priv,
};
+45
View File
@@ -0,0 +1,45 @@
/***************************************************************************
* Copyright (C) 2017 by Texas Instruments, Inc. *
* *
* 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/>. *
***************************************************************************/
#ifndef OPENOCD_FLASH_NOR_CC3220SF_H
#define OPENOCD_FLASH_NOR_CC3220SF_H
/* CC3220SF device types */
#define CC3220_NO_TYPE 0 /* Device type not determined yet */
#define CC3220_OTHER 1 /* CC3220 variant without flash */
#define CC3220SF 2 /* CC3220SF variant with flash */
/* Flash parameters */
#define FLASH_BASE_ADDR 0x01000000
#define FLASH_SECTOR_SIZE 2048
#define FLASH_NUM_SECTORS 512
/* CC2200SF flash registers */
#define FMA_REGISTER_ADDR 0x400FD000
#define FMC_REGISTER_ADDR 0x400FD008
#define FMC_DEFAULT_VALUE 0xA4420000
#define FMC_ERASE_BIT 0x00000002
#define FMC_MERASE_BIT 0x00000004
#define FMC_ERASE_VALUE (FMC_DEFAULT_VALUE | FMC_ERASE_BIT)
#define FMC_MERASE_VALUE (FMC_DEFAULT_VALUE | FMC_MERASE_BIT)
/* Flash helper algorithm for CC3220SF */
const uint8_t cc3220sf_algo[] = {
#include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc"
};
#endif /* OPENOCD_FLASH_NOR_CC3220SF_H */
+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,
};
+230 -60
View File
@@ -4,6 +4,7 @@
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com> *
* Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> *
* *
* 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 *
@@ -171,6 +172,39 @@ 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);
/* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from
* master flash_bank structure. They point to memory locations allocated by master flash driver
* so master driver is responsible for releasing them.
* Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */
if (strcmp(bank->driver->name, "virtual") != 0) {
free(bank->sectors);
free(bank->prot_blocks);
}
free(bank->name);
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);
@@ -314,36 +348,49 @@ int default_flash_blank_check(struct flash_bank *bank)
struct target *target = bank->target;
int i;
int retval;
int fast_check = 0;
uint32_t blank;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
for (i = 0; i < bank->num_sectors; i++) {
uint32_t address = bank->base + bank->sectors[i].offset;
uint32_t size = bank->sectors[i].size;
struct target_memory_check_block *block_array;
block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block));
if (block_array == NULL)
return default_flash_mem_blank_check(bank);
retval = target_blank_check_memory(target, address, size, &blank, bank->erased_value);
if (retval != ERROR_OK) {
fast_check = 0;
for (i = 0; i < bank->num_sectors; i++) {
block_array[i].address = bank->base + bank->sectors[i].offset;
block_array[i].size = bank->sectors[i].size;
block_array[i].result = UINT32_MAX; /* erase state unknown */
}
bool fast_check = true;
for (i = 0; i < bank->num_sectors; ) {
retval = target_blank_check_memory(target,
block_array + i, bank->num_sectors - i,
bank->erased_value);
if (retval < 1) {
/* Run slow fallback if the first run gives no result
* otherwise use possibly incomplete results */
if (i == 0)
fast_check = false;
break;
}
if (blank == bank->erased_value)
bank->sectors[i].is_erased = 1;
else
bank->sectors[i].is_erased = 0;
fast_check = 1;
i += retval; /* add number of blocks done this round */
}
if (!fast_check) {
if (fast_check) {
for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = block_array[i].result;
retval = ERROR_OK;
} else {
LOG_USER("Running slow fallback erase check - add working memory");
return default_flash_mem_blank_check(bank);
retval = default_flash_mem_blank_check(bank);
}
free(block_array);
return ERROR_OK;
return retval;
}
/* Manipulate given flash region, selecting the bank according to target
@@ -399,18 +446,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];
@@ -559,6 +609,87 @@ static int compare_section(const void *a, const void *b)
return -1;
}
/**
* Get aligned start address of a flash write region
*/
target_addr_t flash_write_align_start(struct flash_bank *bank, target_addr_t addr)
{
if (addr < bank->base || addr >= bank->base + bank->size
|| bank->write_start_alignment <= 1)
return addr;
if (bank->write_start_alignment == FLASH_WRITE_ALIGN_SECTOR) {
uint32_t offset = addr - bank->base;
uint32_t aligned = 0;
int sect;
for (sect = 0; sect < bank->num_sectors; sect++) {
if (bank->sectors[sect].offset > offset)
break;
aligned = bank->sectors[sect].offset;
}
return bank->base + aligned;
}
return addr & ~(bank->write_start_alignment - 1);
}
/**
* Get aligned end address of a flash write region
*/
target_addr_t flash_write_align_end(struct flash_bank *bank, target_addr_t addr)
{
if (addr < bank->base || addr >= bank->base + bank->size
|| bank->write_end_alignment <= 1)
return addr;
if (bank->write_end_alignment == FLASH_WRITE_ALIGN_SECTOR) {
uint32_t offset = addr - bank->base;
uint32_t aligned = 0;
int sect;
for (sect = 0; sect < bank->num_sectors; sect++) {
aligned = bank->sectors[sect].offset + bank->sectors[sect].size - 1;
if (aligned >= offset)
break;
}
return bank->base + aligned;
}
return addr | (bank->write_end_alignment - 1);
}
/**
* Check if gap between sections is bigger than minimum required to discontinue flash write
*/
static bool flash_write_check_gap(struct flash_bank *bank,
target_addr_t addr1, target_addr_t addr2)
{
if (bank->minimal_write_gap == FLASH_WRITE_CONTINUOUS
|| addr1 < bank->base || addr1 >= bank->base + bank->size
|| addr2 < bank->base || addr2 >= bank->base + bank->size)
return false;
if (bank->minimal_write_gap == FLASH_WRITE_GAP_SECTOR) {
int sect;
uint32_t offset1 = addr1 - bank->base;
/* find the sector following the one containing addr1 */
for (sect = 0; sect < bank->num_sectors; sect++) {
if (bank->sectors[sect].offset > offset1)
break;
}
if (sect >= bank->num_sectors)
return false;
uint32_t offset2 = addr2 - bank->base;
return bank->sectors[sect].offset + bank->sectors[sect].size <= offset2;
}
target_addr_t aligned1 = flash_write_align_end(bank, addr1);
target_addr_t aligned2 = flash_write_align_start(bank, addr2);
return aligned1 + bank->minimal_write_gap < aligned2;
}
int flash_write_unlock(struct target *target, struct image *image,
uint32_t *written, int erase, bool unlock)
{
@@ -598,10 +729,10 @@ int flash_write_unlock(struct target *target, struct image *image,
/* loop until we reach end of the image */
while (section < image->num_sections) {
uint32_t buffer_size;
uint32_t buffer_idx;
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 +748,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;
@@ -635,32 +766,37 @@ int flash_write_unlock(struct target *target, struct image *image,
break;
}
/* FIXME This needlessly touches sectors BETWEEN the
* sections it's writing. Without auto erase, it just
* writes ones. That WILL INVALIDATE data in cases
* like Stellaris Tempest chips, corrupting internal
* ECC codes; and at least FreeScale suggests issues
* with that approach (in HC11 documentation).
*
* With auto erase enabled, data in those sectors will
* be needlessly destroyed; and some of the limited
* number of flash erase cycles will be wasted...
*
* In both cases, the extra writes slow things down.
*/
/* 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);
padding[section_last] = pad_bytes;
run_size += sections[++section_last]->size;
run_size += pad_bytes;
target_addr_t run_next_addr = run_address + run_size;
target_addr_t next_section_base = sections[section_last + 1]->base_address;
if (next_section_base < run_next_addr) {
LOG_ERROR("Section at " TARGET_ADDR_FMT
" overlaps section ending at " TARGET_ADDR_FMT,
next_section_base, run_next_addr);
LOG_ERROR("Flash write aborted.");
retval = ERROR_FAIL;
goto done;
}
pad_bytes = next_section_base - run_next_addr;
if (pad_bytes) {
if (flash_write_check_gap(c, run_next_addr - 1, next_section_base)) {
LOG_INFO("Flash write discontinued at " TARGET_ADDR_FMT
", next section at " TARGET_ADDR_FMT,
run_next_addr, next_section_base);
break;
}
}
if (pad_bytes > 0)
LOG_INFO("Padding image section %d with %d bytes",
section_last-1,
pad_bytes);
LOG_INFO("Padding image section %d at " TARGET_ADDR_FMT
" with %d bytes",
section_last, run_next_addr, pad_bytes);
padding[section_last] = pad_bytes;
run_size += pad_bytes;
run_size += sections[++section_last]->size;
}
if (run_address + run_size - 1 > c->base + c->size - 1) {
@@ -673,10 +809,38 @@ int flash_write_unlock(struct target *target, struct image *image,
assert(run_size > 0);
}
/* If we're applying any sector automagic, then pad this
* (maybe-combined) segment to the end of its last sector.
*/
if (unlock || erase) {
uint32_t padding_at_start = 0;
if (c->write_start_alignment || c->write_end_alignment) {
/* align write region according to bank requirements */
target_addr_t aligned_start = flash_write_align_start(c, run_address);
padding_at_start = run_address - aligned_start;
if (padding_at_start > 0) {
LOG_WARNING("Section start address " TARGET_ADDR_FMT
" breaks the required alignment of flash bank %s",
run_address, c->name);
LOG_WARNING("Padding %d bytes from " TARGET_ADDR_FMT,
padding_at_start, aligned_start);
run_address -= padding_at_start;
run_size += padding_at_start;
}
target_addr_t run_end = run_address + run_size - 1;
target_addr_t aligned_end = flash_write_align_end(c, run_end);
pad_bytes = aligned_end - run_end;
if (pad_bytes > 0) {
LOG_INFO("Padding image section %d at " TARGET_ADDR_FMT
" with %d bytes (bank write end alignment)",
section_last, run_end + 1, pad_bytes);
padding[section_last] += pad_bytes;
run_size += pad_bytes;
}
} else if (unlock || erase) {
/* If we're applying any sector automagic, then pad this
* (maybe-combined) segment to the end of its last sector.
*/
int sector;
uint32_t offset_start = run_address - c->base;
uint32_t offset_end = offset_start + run_size;
@@ -701,13 +865,17 @@ int flash_write_unlock(struct target *target, struct image *image,
retval = ERROR_FAIL;
goto done;
}
buffer_size = 0;
if (padding_at_start)
memset(buffer, c->default_padded_value, padding_at_start);
buffer_idx = padding_at_start;
/* read sections to the buffer */
while (buffer_size < run_size) {
while (buffer_idx < run_size) {
size_t size_read;
size_read = run_size - buffer_size;
size_read = run_size - buffer_idx;
if (size_read > sections[section]->size - section_offset)
size_read = sections[section]->size - section_offset;
@@ -720,23 +888,25 @@ int flash_write_unlock(struct target *target, struct image *image,
int t_section_num = diff / sizeof(struct imagesection);
LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, "
"section_offset = %d, buffer_size = %d, size_read = %d",
(int)section, (int)t_section_num, (int)section_offset,
(int)buffer_size, (int)size_read);
"section_offset = %"PRIu32", buffer_idx = %"PRIu32", size_read = %zu",
section, t_section_num, section_offset,
buffer_idx, size_read);
retval = image_read_section(image, t_section_num, section_offset,
size_read, buffer + buffer_size, &size_read);
size_read, buffer + buffer_idx, &size_read);
if (retval != ERROR_OK || size_read == 0) {
free(buffer);
goto done;
}
/* see if we need to pad the section */
while (padding[section]--)
(buffer + buffer_size)[size_read++] = c->default_padded_value;
buffer_size += size_read;
buffer_idx += size_read;
section_offset += size_read;
/* see if we need to pad the section */
if (padding[section]) {
memset(buffer + buffer_idx, c->default_padded_value, padding[section]);
buffer_idx += padding[section];
}
if (section_offset >= sections[section]->size) {
section++;
section_offset = 0;
+43 -1
View File
@@ -65,6 +65,13 @@ struct flash_sector {
int is_protected;
};
/** Special value for write_start_alignment and write_end_alignment field */
#define FLASH_WRITE_ALIGN_SECTOR UINT32_MAX
/** Special values for minimal_write_gap field */
#define FLASH_WRITE_CONTINUOUS 0
#define FLASH_WRITE_GAP_SECTOR UINT32_MAX
/**
* Provides details of a flash bank, available either on-chip or through
* a major interface.
@@ -76,7 +83,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. */
@@ -97,6 +104,18 @@ struct flash_bank {
* erased value. Defaults to 0xFF. */
uint8_t default_padded_value;
/** Required alignment of flash write start address.
* Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */
uint32_t write_start_alignment;
/** Required alignment of flash write end address.
* Default 0, no alignment. Can be any power of two or FLASH_WRITE_ALIGN_SECTOR */
uint32_t write_end_alignment;
/** Minimal gap between sections to discontinue flash write
* Default FLASH_WRITE_GAP_SECTOR splits the write if one or more untouched
* sectors in between.
* Can be size in bytes or FLASH_WRITE_CONTINUOUS */
uint32_t minimal_write_gap;
/**
* The number of sectors on this chip. This value will
* be set intially to 0, and the flash driver must set this to
@@ -135,6 +154,22 @@ int flash_erase_address_range(struct target *target,
int flash_unlock_address_range(struct target *target, uint32_t addr,
uint32_t length);
/**
* Align start address of a flash write region according to bank requirements.
* @param bank Pointer to bank descriptor structure
* @param addr Address to align
* @returns Aligned address
*/
target_addr_t flash_write_align_start(struct flash_bank *bank, target_addr_t addr);
/**
* Align end address of a flash write region according to bank requirements.
* Note: Use address of the last byte to write, not the next after the region.
* @param bank Pointer to bank descriptor structure
* @param addr Address to align (address of the last byte to write)
* @returns Aligned address (address of the last byte of padded region)
*/
target_addr_t flash_write_align_end(struct flash_bank *bank, target_addr_t addr);
/**
* Writes @a image into the @a target flash. The @a written parameter
* will contain the
@@ -153,8 +188,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) \
+16
View File
@@ -31,6 +31,9 @@ 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 cc3220sf_flash;
extern struct flash_driver cc26xx_flash;
extern struct flash_driver cfi_flash;
extern struct flash_driver dsp5680xx_flash;
extern struct flash_driver efm32_flash;
@@ -48,6 +51,7 @@ extern struct flash_driver lpc2900_flash;
extern struct flash_driver lpcspifi_flash;
extern struct flash_driver mdr_flash;
extern struct flash_driver mrvlqspi_flash;
extern struct flash_driver msp432_flash;
extern struct flash_driver niietcm4_flash;
extern struct flash_driver nrf5_flash;
extern struct flash_driver nrf51_flash;
@@ -55,6 +59,10 @@ 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 psoc5lp_flash;
extern struct flash_driver psoc5lp_eeprom_flash;
extern struct flash_driver psoc5lp_nvl_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 +96,9 @@ static struct flash_driver *flash_drivers[] = {
&ath79_flash,
&atsamv_flash,
&avr_flash,
&bluenrgx_flash,
&cc3220sf_flash,
&cc26xx_flash,
&cfi_flash,
&dsp5680xx_flash,
&efm32_flash,
@@ -105,6 +116,7 @@ static struct flash_driver *flash_drivers[] = {
&lpcspifi_flash,
&mdr_flash,
&mrvlqspi_flash,
&msp432_flash,
&niietcm4_flash,
&nrf5_flash,
&nrf51_flash,
@@ -112,6 +124,10 @@ static struct flash_driver *flash_drivers[] = {
&ocl_flash,
&pic32mx_flash,
&psoc4_flash,
&psoc5lp_flash,
&psoc5lp_eeprom_flash,
&psoc5lp_nvl_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,
};
+49 -30
View File
@@ -436,6 +436,12 @@ static int slow_fespi_write_buffer(struct flash_bank *bank,
uint32_t ctrl_base = fespi_info->ctrl_base;
uint32_t ii;
if (offset & 0xFF000000) {
LOG_ERROR("FESPI interface does not support greater than 3B addressing, can't write to offset 0x%x",
offset);
return ERROR_FAIL;
}
/* TODO!!! assert that len < page size */
fespi_tx(bank, SPIFLASH_WRITE_ENABLE);
@@ -607,11 +613,11 @@ struct algorithm_steps {
uint8_t **steps;
};
static struct algorithm_steps *as_new(unsigned size)
static struct algorithm_steps *as_new(void)
{
struct algorithm_steps *as = calloc(1, sizeof(struct algorithm_steps));
as->size = size;
as->steps = calloc(size, sizeof(as->steps[0]));
as->size = 8;
as->steps = malloc(as->size * sizeof(as->steps[0]));
return as;
}
@@ -701,17 +707,27 @@ static unsigned as_compile(struct algorithm_steps *as, uint8_t *target,
return offset;
}
static void as_add_step(struct algorithm_steps *as, uint8_t *step)
{
if (as->used == as->size) {
as->size *= 2;
as->steps = realloc(as->steps, sizeof(as->steps[0]) * as->size);
LOG_DEBUG("Increased size to 0x%x", as->size);
}
as->steps[as->used] = step;
as->used++;
}
static void as_add_tx(struct algorithm_steps *as, unsigned count, const uint8_t *data)
{
LOG_DEBUG("count=%d", count);
while (count > 0) {
unsigned step_count = MIN(count, 255);
assert(as->used < as->size);
as->steps[as->used] = malloc(step_count + 2);
as->steps[as->used][0] = STEP_TX;
as->steps[as->used][1] = step_count;
memcpy(as->steps[as->used] + 2, data, step_count);
as->used++;
uint8_t *step = malloc(step_count + 2);
step[0] = STEP_TX;
step[1] = step_count;
memcpy(step + 2, data, step_count);
as_add_step(as, step);
data += step_count;
count -= step_count;
}
@@ -726,43 +742,45 @@ static void as_add_tx1(struct algorithm_steps *as, uint8_t byte)
static void as_add_write_reg(struct algorithm_steps *as, uint8_t offset, uint8_t data)
{
assert(as->used < as->size);
as->steps[as->used] = malloc(3);
as->steps[as->used][0] = STEP_WRITE_REG;
as->steps[as->used][1] = offset;
as->steps[as->used][2] = data;
as->used++;
uint8_t *step = malloc(3);
step[0] = STEP_WRITE_REG;
step[1] = offset;
step[2] = data;
as_add_step(as, step);
}
static void as_add_txwm_wait(struct algorithm_steps *as)
{
assert(as->used < as->size);
as->steps[as->used] = malloc(1);
as->steps[as->used][0] = STEP_TXWM_WAIT;
as->used++;
uint8_t *step = malloc(1);
step[0] = STEP_TXWM_WAIT;
as_add_step(as, step);
}
static void as_add_wip_wait(struct algorithm_steps *as)
{
assert(as->used < as->size);
as->steps[as->used] = malloc(1);
as->steps[as->used][0] = STEP_WIP_WAIT;
as->used++;
uint8_t *step = malloc(1);
step[0] = STEP_WIP_WAIT;
as_add_step(as, step);
}
static void as_add_set_dir(struct algorithm_steps *as, bool dir)
{
assert(as->used < as->size);
as->steps[as->used] = malloc(2);
as->steps[as->used][0] = STEP_SET_DIR;
as->steps[as->used][1] = FESPI_FMT_DIR(dir);
as->used++;
uint8_t *step = malloc(2);
step[0] = STEP_SET_DIR;
step[1] = FESPI_FMT_DIR(dir);
as_add_step(as, step);
}
/* This should write something less than or equal to a page.*/
static int steps_add_buffer_write(struct algorithm_steps *as,
const uint8_t *buffer, uint32_t chip_offset, uint32_t len)
{
if (chip_offset & 0xFF000000) {
LOG_ERROR("FESPI interface does not support greater than 3B addressing, can't write to offset 0x%x",
chip_offset);
return ERROR_FAIL;
}
as_add_tx1(as, SPIFLASH_WRITE_ENABLE);
as_add_txwm_wait(as);
as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
@@ -910,7 +928,7 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
return retval;
struct algorithm_steps *as = as_new(count / 4);
struct algorithm_steps *as = as_new();
/* unaligned buffer head */
if (count > 0 && (offset & 3) != 0) {
@@ -1161,5 +1179,6 @@ struct flash_driver fespi_flash = {
.auto_probe = fespi_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = fespi_protect_check,
.info = get_fespi_info
.info = get_fespi_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,
};
+24 -5
View File
@@ -915,13 +915,29 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
}
static void kinetis_free_driver_priv(struct flash_bank *bank)
{
struct kinetis_flash_bank *k_bank = bank->driver_priv;
if (k_bank == NULL)
return;
struct kinetis_chip *k_chip = k_bank->k_chip;
if (k_chip == NULL)
return;
k_chip->num_banks--;
if (k_chip->num_banks == 0)
free(k_chip);
}
static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
{
unsigned bank_idx;
unsigned num_blocks;
struct kinetis_flash_bank *k_bank;
struct flash_bank *bank;
char base_name[80], name[80], num[4];
char base_name[69], name[80], num[4];
char *class, *p;
num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks;
@@ -932,19 +948,21 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
bank = k_chip->banks[0].bank;
if (bank && bank->name) {
strncpy(base_name, bank->name, sizeof(base_name));
strncpy(base_name, bank->name, sizeof(base_name) - 1);
base_name[sizeof(base_name) - 1] = '\0';
p = strstr(base_name, ".pflash");
if (p) {
*p = '\0';
if (k_chip->num_pflash_blocks > 1) {
/* rename first bank if numbering is needed */
snprintf(name, sizeof(name), "%s.pflash0", base_name);
free((void *)bank->name);
free(bank->name);
bank->name = strdup(name);
}
}
} else {
strncpy(base_name, target_name(k_chip->target), sizeof(base_name));
strncpy(base_name, target_name(k_chip->target), sizeof(base_name) - 1);
base_name[sizeof(base_name) - 1] = '\0';
p = strstr(base_name, ".cpu");
if (p)
*p = '\0';
@@ -1996,7 +2014,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
unsigned cpu_mhz = 120;
unsigned idx;
bool use_nvm_marking = false;
char flash_marking[11], nvm_marking[2];
char flash_marking[12], nvm_marking[2];
char name[40];
k_chip->probed = false;
@@ -3132,4 +3150,5 @@ struct flash_driver kinetis_flash = {
.erase_check = kinetis_blank_check,
.protect_check = kinetis_protect_check,
.info = kinetis_info,
.free_driver_priv = kinetis_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,
};
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
/***************************************************************************
* Copyright (C) 2018 by Texas Instruments, Inc. *
* *
* 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/>. *
***************************************************************************/
#ifndef OPENOCD_FLASH_NOR_MSP432_H
#define OPENOCD_FLASH_NOR_MSP432_H
/* MSP432 family types */
#define MSP432_NO_FAMILY 0 /* Family type not determined yet */
#define MSP432E4 1 /* MSP432E4 family of devices */
#define MSP432P4 2 /* MSP432P4 family of devices */
/* MSP432 device types */
#define MSP432_NO_TYPE 0 /* Device type not determined yet */
#define MSP432P401X_DEPR 1 /* Early MSP432P401x offerings, now deprecated */
#define MSP432P401X 2 /* MSP432P401x device, revision C or higher */
#define MSP432P411X 3 /* MSP432P411x device, revision A or higher */
#define MSP432P401X_GUESS 4 /* Assuming it's an MSP432P401x device */
#define MSP432P411X_GUESS 5 /* Assuming it's an MSP432P411x device */
#define MSP432E401Y 6 /* MSP432E401Y device */
#define MSP432E411Y 7 /* MSP432E401Y device */
#define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */
/* MSP432P4 flash parameters */
#define P4_FLASH_MAIN_BASE 0x00000000
#define P4_FLASH_INFO_BASE 0x00200000
#define P4_SECTOR_LENGTH 0x1000
#define P4_ALGO_ENTRY_ADDR 0x01000110
/* MSP432E4 flash paramters */
#define E4_FLASH_BASE 0x00000000
#define E4_FLASH_SIZE 0x100000
#define E4_SECTOR_LENGTH 0x4000
#define E4_ALGO_ENTRY_ADDR 0x20000110
/* Flash helper algorithm key addresses */
#define ALGO_BASE_ADDR 0x20000000
#define ALGO_BUFFER1_ADDR 0x20002000
#define ALGO_BUFFER2_ADDR 0x20003000
#define ALGO_PARAMS_BASE_ADDR 0x20000150
#define ALGO_FLASH_COMMAND_ADDR 0x20000150
#define ALGO_RETURN_CODE_ADDR 0x20000154
#define ALGO_FLASH_DEST_ADDR 0x2000015c
#define ALGO_FLASH_LENGTH_ADDR 0x20000160
#define ALGO_BUFFER1_STATUS_ADDR 0x20000164
#define ALGO_BUFFER2_STATUS_ADDR 0x20000168
#define ALGO_ERASE_PARAM_ADDR 0x2000016c
#define ALGO_UNLOCK_BSL_ADDR 0x20000170
#define ALGO_STACK_POINTER_ADDR 0x20002000
/* Flash helper algorithm key sizes */
#define ALGO_BUFFER_SIZE 0x1000
#define ALGO_WORKING_SIZE (ALGO_BUFFER2_ADDR + 0x1000 - ALGO_BASE_ADDR)
/* Flash helper algorithm flash commands */
#define FLASH_NO_COMMAND 0
#define FLASH_MASS_ERASE 1
#define FLASH_SECTOR_ERASE 2
#define FLASH_PROGRAM 4
#define FLASH_INIT 8
#define FLASH_EXIT 16
#define FLASH_CONTINUOUS 32
/* Flash helper algorithm return codes */
#define FLASH_BUSY 0x00000001
#define FLASH_SUCCESS 0x00000ACE
#define FLASH_ERROR 0x0000DEAD
#define FLASH_TIMEOUT_ERROR 0xDEAD0000
#define FLASH_VERIFY_ERROR 0xDEADDEAD
#define FLASH_WRONG_COMMAND 0x00000BAD
#define FLASH_POWER_ERROR 0x00DEAD00
/* Flash helper algorithm buffer status values */
#define BUFFER_INACTIVE 0x00
#define BUFFER_ACTIVE 0x01
#define BUFFER_DATA_READY 0x10
/* Flash helper algorithm erase parameters */
#define FLASH_ERASE_MAIN 0x01
#define FLASH_ERASE_INFO 0x02
/* Flash helper algorithm lock/unlock BSL options */
#define FLASH_LOCK_BSL 0x00
#define FLASH_UNLOCK_BSL 0x0b
/* Flash helper algorithm parameter block struct */
struct msp432_algo_params {
uint8_t flash_command[4];
uint8_t return_code[4];
uint8_t _reserved0[4];
uint8_t address[4];
uint8_t length[4];
uint8_t buffer1_status[4];
uint8_t buffer2_status[4];
uint8_t erase_param[4];
uint8_t unlock_bsl[4];
};
/* Flash helper algorithm for MSP432P401x targets */
const uint8_t msp432p401x_algo[] = {
#include "../../../contrib/loaders/flash/msp432/msp432p401x_algo.inc"
};
/* Flash helper algorithm for MSP432P411x targets */
const uint8_t msp432p411x_algo[] = {
#include "../../../contrib/loaders/flash/msp432/msp432p411x_algo.inc"
};
/* Flash helper algorithm for MSP432E4x targets */
const uint8_t msp432e4x_algo[] = {
#include "../../../contrib/loaders/flash/msp432/msp432e4x_algo.inc"
};
#endif /* OPENOCD_FLASH_NOR_MSP432_H */
+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,
};
+28 -58
View File
@@ -108,6 +108,7 @@ enum nrf5_nvmc_config_bits {
struct nrf5_info {
uint32_t code_page_size;
uint32_t refcount;
struct {
bool probed;
@@ -155,6 +156,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 +181,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 +205,7 @@ 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),
NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
};
static int nrf5_bank_is_probed(struct flash_bank *bank)
@@ -530,7 +533,6 @@ static int nrf5_probe(struct flash_bank *bank)
bank->sectors[0].size = bank->size;
bank->sectors[0].offset = 0;
/* mark as unknown */
bank->sectors[0].is_erased = 0;
bank->sectors[0].is_protected = 0;
@@ -552,17 +554,6 @@ static int nrf5_auto_probe(struct flash_bank *bank)
return nrf5_probe(bank);
}
static struct flash_sector *nrf5_find_sector_by_address(struct flash_bank *bank, uint32_t address)
{
struct nrf5_info *chip = bank->driver_priv;
for (int i = 0; i < bank->num_sectors; i++)
if (bank->sectors[i].offset <= address &&
address < (bank->sectors[i].offset + chip->code_page_size))
return &bank->sectors[i];
return NULL;
}
static int nrf5_erase_all(struct nrf5_info *chip)
{
LOG_DEBUG("Erasing all non-volatile memory");
@@ -614,9 +605,6 @@ static int nrf5_erase_page(struct flash_bank *bank,
sector->offset);
}
if (res == ERROR_OK)
sector->is_erased = 1;
return res;
}
@@ -742,48 +730,22 @@ static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t en
{
int res = ERROR_FAIL;
struct nrf5_info *chip = bank->driver_priv;
struct flash_sector *sector;
uint32_t offset;
assert(start % chip->code_page_size == 0);
assert(end % chip->code_page_size == 0);
/* Erase all sectors */
for (offset = start; offset < end; offset += chip->code_page_size) {
sector = nrf5_find_sector_by_address(bank, offset);
if (!sector) {
LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset);
return ERROR_FLASH_SECTOR_INVALID;
}
if (sector->is_protected) {
LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset);
goto error;
}
if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */
res = nrf5_erase_page(bank, chip, sector);
if (res != ERROR_OK) {
LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
goto error;
}
}
sector->is_erased = 0;
}
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
res = nrf5_ll_flash_write(chip, start, buffer, (end - start));
if (res != ERROR_OK)
goto set_read_only;
goto error;
return nrf5_nvmc_read_only(chip);
set_read_only:
nrf5_nvmc_read_only(chip);
error:
nrf5_nvmc_read_only(chip);
LOG_ERROR("Failed to write to nrf5 flash");
return res;
}
@@ -875,11 +837,9 @@ static int nrf5_uicr_flash_write(struct flash_bank *bank,
if (res != ERROR_OK)
return res;
if (sector->is_erased != 1) {
res = nrf5_erase_page(bank, chip, sector);
if (res != ERROR_OK)
return res;
}
res = nrf5_erase_page(bank, chip, sector);
if (res != ERROR_OK)
return res;
res = nrf5_nvmc_write_enable(chip);
if (res != ERROR_OK)
@@ -910,6 +870,18 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
return chip->bank[bank->bank_number].write(bank, chip, buffer, offset, count);
}
static void nrf5_free_driver_priv(struct flash_bank *bank)
{
struct nrf5_info *chip = bank->driver_priv;
if (chip == NULL)
return;
chip->refcount--;
if (chip->refcount == 0) {
free(chip);
bank->driver_priv = NULL;
}
}
FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
{
@@ -945,6 +917,7 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
break;
}
chip->refcount++;
chip->bank[bank->bank_number].probed = false;
bank->driver_priv = chip;
@@ -991,9 +964,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
return res;
}
for (int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
res = nrf5_protect_check(bank);
if (res != ERROR_OK) {
LOG_ERROR("Failed to check chip's write protection");
@@ -1004,8 +974,6 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
if (res != ERROR_OK)
return res;
bank->sectors[0].is_erased = 1;
return ERROR_OK;
}
@@ -1174,6 +1142,7 @@ struct flash_driver nrf5_flash = {
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
.free_driver_priv = nrf5_free_driver_priv,
};
/* We need to retain the flash-driver name as well as the commands
@@ -1191,4 +1160,5 @@ struct flash_driver nrf51_flash = {
.auto_probe = nrf5_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = nrf5_protect_check,
.free_driver_priv = nrf5_free_driver_priv,
};
+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,
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+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
@@ -54,6 +54,7 @@ const struct flash_device flash_devices[] = {
FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000),
FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000),
FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000),
FLASH_ID("cy s25fl256", 0xd8, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000),
FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000),
FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000),
FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000),
+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,
};
+5 -39
View File
@@ -572,45 +572,8 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
/* see contrib/loaders/flash/stm32f1x.S for src */
static const uint8_t stm32x_flash_write_code[] = {
/* #define STM32_FLASH_SR_OFFSET 0x0C */
/* wait_fifo: */
0x16, 0x68, /* ldr r6, [r2, #0] */
0x00, 0x2e, /* cmp r6, #0 */
0x18, 0xd0, /* beq exit */
0x55, 0x68, /* ldr r5, [r2, #4] */
0xb5, 0x42, /* cmp r5, r6 */
0xf9, 0xd0, /* beq wait_fifo */
0x2e, 0x88, /* ldrh r6, [r5, #0] */
0x26, 0x80, /* strh r6, [r4, #0] */
0x02, 0x35, /* adds r5, #2 */
0x02, 0x34, /* adds r4, #2 */
/* busy: */
0xc6, 0x68, /* ldr r6, [r0, #STM32_FLASH_SR_OFFSET] */
0x01, 0x27, /* movs r7, #1 */
0x3e, 0x42, /* tst r6, r7 */
0xfb, 0xd1, /* bne busy */
0x14, 0x27, /* movs r7, #0x14 */
0x3e, 0x42, /* tst r6, r7 */
0x08, 0xd1, /* bne error */
0x9d, 0x42, /* cmp r5, r3 */
0x01, 0xd3, /* bcc no_wrap */
0x15, 0x46, /* mov r5, r2 */
0x08, 0x35, /* adds r5, #8 */
/* no_wrap: */
0x55, 0x60, /* str r5, [r2, #4] */
0x01, 0x39, /* subs r1, r1, #1 */
0x00, 0x29, /* cmp r1, #0 */
0x02, 0xd0, /* beq exit */
0xe5, 0xe7, /* b wait_fifo */
/* error: */
0x00, 0x20, /* movs r0, #0 */
0x50, 0x60, /* str r0, [r2, #4] */
/* exit: */
0x30, 0x46, /* mov r0, r6 */
0x00, 0xbe, /* bkpt #0 */
#include "../../../contrib/loaders/flash/stm32/stm32f1x.inc"
};
/* flash write code */
@@ -622,8 +585,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code), stm32x_flash_write_code);
if (retval != ERROR_OK)
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
@@ -1647,4 +1612,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,
};
+7 -39
View File
@@ -252,6 +252,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear but report errors */
if (status & FLASH_ERROR) {
if (retval == ERROR_OK)
retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original
* retval
*/
@@ -584,45 +586,8 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
/* see contrib/loaders/flash/stm32f2x.S for src */
static const uint8_t stm32x_flash_write_code[] = {
/* wait_fifo: */
0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */
0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */
0x1A, 0xD0, /* beq exit */
0x47, 0x68, /* ldr r7, [r0, #4] */
0x47, 0x45, /* cmp r7, r8 */
0xF7, 0xD0, /* beq wait_fifo */
0xDF, 0xF8, 0x34, 0x60, /* ldr r6, STM32_PROG16 */
0x26, 0x61, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */
0x37, 0xF8, 0x02, 0x6B, /* ldrh r6, [r7], #0x02 */
0x22, 0xF8, 0x02, 0x6B, /* strh r6, [r2], #0x02 */
0xBF, 0xF3, 0x4F, 0x8F, /* dsb sy */
/* busy: */
0xE6, 0x68, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */
0x16, 0xF4, 0x80, 0x3F, /* tst r6, #0x10000 */
0xFB, 0xD1, /* bne busy */
0x16, 0xF0, 0xF0, 0x0F, /* tst r6, #0xf0 */
0x07, 0xD1, /* bne error */
0x8F, 0x42, /* cmp r7, r1 */
0x28, 0xBF, /* it cs */
0x00, 0xF1, 0x08, 0x07, /* addcs r7, r0, #8 */
0x47, 0x60, /* str r7, [r0, #4] */
0x01, 0x3B, /* subs r3, r3, #1 */
0x13, 0xB1, /* cbz r3, exit */
0xDF, 0xE7, /* b wait_fifo */
/* error: */
0x00, 0x21, /* movs r1, #0 */
0x41, 0x60, /* str r1, [r0, #4] */
/* exit: */
0x30, 0x46, /* mov r0, r6 */
0x00, 0xBE, /* bkpt #0x00 */
/* <STM32_PROG16>: */
0x01, 0x01, 0x00, 0x00, /* .word 0x00000101 */
#include "../../../contrib/loaders/flash/stm32/stm32f2x.inc"
};
if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
@@ -634,8 +599,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code),
stm32x_flash_write_code);
if (retval != ERROR_OK)
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
@@ -1634,4 +1601,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,
};
+9 -47
View File
@@ -64,7 +64,7 @@
#define FLASH_WRPERR (1 << 17) /* Write protection error */
#define FLASH_PGSERR (1 << 18) /* Programming sequence error */
#define FLASH_STRBERR (1 << 19) /* Strobe error */
#define FLASH_INCERR (1 << 21) /* Increment error */
#define FLASH_INCERR (1 << 21) /* Inconsistency error */
#define FLASH_OPERR (1 << 22) /* Operation error */
#define FLASH_RDPERR (1 << 23) /* Read Protection error */
#define FLASH_RDSERR (1 << 24) /* Secure Protection error */
@@ -220,6 +220,8 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear error + EOP flags but report errors */
if (status & FLASH_ERROR) {
if (retval == ERROR_OK)
retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original retval */
target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status);
}
@@ -495,7 +497,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK) {
LOG_ERROR("erase time-out error sector %d", i);
LOG_ERROR("erase time-out or operation error sector %d", i);
return retval;
}
bank->sectors[i].is_erased = 1;
@@ -568,51 +570,8 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
int retval = ERROR_OK;
/* see contrib/loaders/flash/smt32h7x.S for src */
static const uint8_t stm32x_flash_write_code[] = {
/* <code>: */
0x45, 0x68, /* ldr r5, [r0, #4] */
/* <wait_fifo>: */
0x06, 0x68, /* ldr r6, [r0, #0] */
0x26, 0xb3, /* cbz r6, <exit> */
0x76, 0x1b, /* subs r6, r6, r5 */
0x42, 0xbf, /* ittt mi */
0x76, 0x18, /* addmi r6, r6, r1 */
0x36, 0x1a, /* submi r6, r6, r0 */
0x08, 0x3e, /* submi r6, #8 */
0x20, 0x2e, /* cmp r6, #32 */
0xf6, 0xd3, /* bcc.n <wait_fifo> */
0x4f, 0xf0, 0x32, 0x06, /* mov.w r6, #STM32_PROG */
0xe6, 0x60, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */
0x4f, 0xf0, 0x08, 0x07, /* mov.w r7, #8 */
/* <write_flash>: */
0x55, 0xf8, 0x04, 0x6b, /* ldr.w r6, [r5], #4 */
0x42, 0xf8, 0x04, 0x6b, /* str.w r6, [r2], #4 */
0xbf, 0xf3, 0x4f, 0x8f, /* dsb sy */
0x8d, 0x42, /* cmp r5, r1 */
0x28, 0xbf, /* it cs */
0x00, 0xf1, 0x08, 0x05, /* addcs.w r5, r0, #8 */
0x01, 0x3f, /* subs r7, #1 */
0xf3, 0xd1, /* bne.n <write_flash> */
/* <busy>: */
0x26, 0x69, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */
0x16, 0xf0, 0x01, 0x0f, /* tst.w r6, #STM32_SR_BUSY_MASK */
0xfb, 0xd1, /* bne.n <busy> */
0x05, 0x4f, /* ldr r7, [pc, #20] ; (<stm32_sr_error_mask>) */
0x3e, 0x42, /* tst r6, r7 */
0x03, 0xd1, /* bne.n <error> */
0x45, 0x60, /* str r5, [r0, #4] */
0x01, 0x3b, /* subs r3, #1 */
0xdb, 0xd1, /* bne.n <wait_fifo> */
0x01, 0xe0, /* b.n <exit> */
/* <error>: */
0x00, 0x27, /* movs r7, #0 */
0x47, 0x60, /* str r7, [r0, #4] */
/* <exit>: */
0x30, 0x46, /* mov r0, r6 */
0x00, 0xbe, /* bkpt 0x0000 */
/* <stm32_sr_error_mask>: */
0x00, 0x00, 0xee, 0x03 /* .word 0x03ee0000 ; (STM32_SR_ERROR_MASK) */
#include "../../../contrib/loaders/flash/stm32/stm32h7x.inc"
};
if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
@@ -624,8 +583,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code),
stm32x_flash_write_code);
if (retval != ERROR_OK)
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
@@ -1180,4 +1141,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,
};
+7 -13
View File
@@ -187,6 +187,8 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout)
/* Clear but report errors */
if (status & FLASH_ERROR) {
if (retval == ERROR_OK)
retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original
* retval
*/
@@ -461,19 +463,8 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
/* See contrib/loaders/flash/stm32l4x.S for source and
* hints how to generate the data!
*/
static const uint8_t stm32l4_flash_write_code[] = {
0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x21, 0xd0, 0x45, 0x68,
0xb8, 0xeb, 0x05, 0x06, 0x44, 0xbf, 0x76, 0x18, 0x36, 0x1a, 0x08, 0x2e,
0xf2, 0xd3, 0xdf, 0xf8, 0x36, 0x60, 0x66, 0x61, 0xf5, 0xe8, 0x02, 0x67,
0xe2, 0xe8, 0x02, 0x67, 0xbf, 0xf3, 0x4f, 0x8f, 0x26, 0x69, 0x16, 0xf4,
0x80, 0x3f, 0xfb, 0xd1, 0x16, 0xf0, 0xfa, 0x0f, 0x07, 0xd1, 0x8d, 0x42,
0x28, 0xbf, 0x00, 0xf1, 0x08, 0x05, 0x45, 0x60, 0x01, 0x3b, 0x13, 0xb1,
0xda, 0xe7, 0x00, 0x21, 0x41, 0x60, 0x30, 0x46, 0x00, 0xbe, 0x01, 0x00,
0x00, 0x00
#include "../../../contrib/loaders/flash/stm32/stm32l4x.inc"
};
if (target_alloc_working_area(target, sizeof(stm32l4_flash_write_code),
@@ -485,8 +476,10 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32l4_flash_write_code),
stm32l4_flash_write_code);
if (retval != ERROR_OK)
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) !=
@@ -953,4 +946,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,
};
+3 -4
View File
@@ -146,7 +146,7 @@ static const struct stm32lx_rev stm32_425_revs[] = {
{ 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" },
};
static const struct stm32lx_rev stm32_427_revs[] = {
{ 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" },
{ 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" },
};
static const struct stm32lx_rev stm32_429_revs[] = {
{ 0x1000, "A" }, { 0x1018, "Z" },
@@ -448,10 +448,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
int retval = ERROR_OK;
/* see contib/loaders/flash/stm32lx.S for src */
static const uint8_t stm32lx_flash_write_code[] = {
0x92, 0x00, 0x8A, 0x18, 0x01, 0xE0, 0x08, 0xC9, 0x08, 0xC0, 0x91, 0x42, 0xFB, 0xD1, 0x00, 0xBE
#include "../../../contrib/loaders/flash/stm32/stm32lx.inc"
};
/* Make sure we're performing a half-page aligned write. */
@@ -965,6 +963,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,
};
+157 -107
View File
@@ -3,6 +3,7 @@
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* Copyright (C) 2017-2018 Tomas Vanek <vanekt@fbl.cz> *
* *
* 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 *
@@ -287,24 +288,6 @@ COMMAND_HANDLER(handle_flash_erase_address_command)
return retval;
}
static int flash_check_sector_parameters(struct command_context *cmd_ctx,
uint32_t first, uint32_t last, uint32_t num_sectors)
{
if (!(first <= last)) {
command_print(cmd_ctx, "ERROR: "
"first sector must be <= last sector");
return ERROR_FAIL;
}
if (!(last <= (num_sectors - 1))) {
command_print(cmd_ctx, "ERROR: last sector must be <= %" PRIu32,
num_sectors - 1);
return ERROR_FAIL;
}
return ERROR_OK;
}
COMMAND_HANDLER(handle_flash_erase_command)
{
if (CMD_ARGC != 3)
@@ -326,9 +309,18 @@ COMMAND_HANDLER(handle_flash_erase_command)
else
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors);
if (retval != ERROR_OK)
return retval;
if (!(first <= last)) {
command_print(CMD_CTX, "ERROR: "
"first sector must be <= last");
return ERROR_FAIL;
}
if (!(last <= (uint32_t)(p->num_sectors - 1))) {
command_print(CMD_CTX, "ERROR: "
"last sector must be <= %" PRIu32,
p->num_sectors - 1);
return ERROR_FAIL;
}
struct duration bench;
duration_start(&bench);
@@ -374,15 +366,28 @@ COMMAND_HANDLER(handle_flash_protect_command)
bool set;
COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set);
retval = flash_check_sector_parameters(CMD_CTX, first, last, num_blocks);
if (retval != ERROR_OK)
return retval;
if (!(first <= last)) {
command_print(CMD_CTX, "ERROR: "
"first %s must be <= last",
(p->num_prot_blocks) ? "block" : "sector");
return ERROR_FAIL;
}
if (!(last <= (uint32_t)(num_blocks - 1))) {
command_print(CMD_CTX, "ERROR: "
"last %s must be <= %" PRIu32,
(p->num_prot_blocks) ? "block" : "sector",
num_blocks - 1);
return ERROR_FAIL;
}
retval = flash_driver_protect(p, set, first, last);
if (retval == ERROR_OK) {
command_print(CMD_CTX, "%s protection for sectors %" PRIu32
command_print(CMD_CTX, "%s protection for %s %" PRIu32
" through %" PRIu32 " on flash bank %d",
(set) ? "set" : "cleared", first, last, p->bank_number);
(set) ? "set" : "cleared",
(p->num_prot_blocks) ? "blocks" : "sectors",
first, last, p->bank_number);
}
return retval;
@@ -460,42 +465,29 @@ COMMAND_HANDLER(handle_flash_write_image_command)
COMMAND_HANDLER(handle_flash_fill_command)
{
int err = ERROR_OK;
uint32_t address;
target_addr_t address;
uint32_t pattern;
uint32_t count;
uint32_t wrote = 0;
uint32_t cur_size = 0;
uint32_t chunk_count;
struct target *target = get_current_target(CMD_CTX);
unsigned i;
uint32_t wordsize;
int retval = ERROR_OK;
int retval;
static size_t const chunksize = 1024;
uint8_t *chunk = NULL, *readback = NULL;
if (CMD_ARGC != 3) {
retval = ERROR_COMMAND_SYNTAX_ERROR;
goto done;
}
if (CMD_ARGC != 3)
return ERROR_COMMAND_SYNTAX_ERROR;
#if BUILD_TARGET64
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], address);
#else
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
#endif
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
chunk = malloc(chunksize);
if (chunk == NULL)
return ERROR_FAIL;
readback = malloc(chunksize);
if (readback == NULL) {
free(chunk);
return ERROR_FAIL;
}
if (count == 0)
goto done;
struct flash_bank *bank;
retval = get_flash_bank_by_addr(target, address, true, &bank);
if (retval != ERROR_OK)
return retval;
switch (CMD_NAME[4]) {
case 'w':
@@ -508,73 +500,109 @@ COMMAND_HANDLER(handle_flash_fill_command)
wordsize = 1;
break;
default:
retval = ERROR_COMMAND_SYNTAX_ERROR;
goto done;
return ERROR_COMMAND_SYNTAX_ERROR;
}
chunk_count = MIN(count, (chunksize / wordsize));
if (count == 0)
return ERROR_OK;
if (address + count * wordsize > bank->base + bank->size) {
LOG_ERROR("Cannot cross flash bank borders");
return ERROR_FAIL;
}
uint32_t size_bytes = count * wordsize;
target_addr_t aligned_start = flash_write_align_start(bank, address);
target_addr_t end_addr = address + size_bytes - 1;
target_addr_t aligned_end = flash_write_align_end(bank, end_addr);
uint32_t aligned_size = aligned_end + 1 - aligned_start;
uint32_t padding_at_start = address - aligned_start;
uint32_t padding_at_end = aligned_end - end_addr;
uint8_t *buffer = malloc(aligned_size);
if (buffer == NULL)
return ERROR_FAIL;
if (padding_at_start) {
memset(buffer, bank->default_padded_value, padding_at_start);
LOG_WARNING("Start address " TARGET_ADDR_FMT
" breaks the required alignment of flash bank %s",
address, bank->name);
LOG_WARNING("Padding %" PRId32 " bytes from " TARGET_ADDR_FMT,
padding_at_start, aligned_start);
}
uint8_t *ptr = buffer + padding_at_start;
switch (wordsize) {
case 4:
for (i = 0; i < chunk_count; i++)
target_buffer_set_u32(target, chunk + i * wordsize, pattern);
for (i = 0; i < count; i++, ptr += wordsize)
target_buffer_set_u32(target, ptr, pattern);
break;
case 2:
for (i = 0; i < chunk_count; i++)
target_buffer_set_u16(target, chunk + i * wordsize, pattern);
for (i = 0; i < count; i++, ptr += wordsize)
target_buffer_set_u16(target, ptr, pattern);
break;
case 1:
memset(chunk, pattern, chunk_count);
memset(ptr, pattern, count);
ptr += count;
break;
default:
LOG_ERROR("BUG: can't happen");
exit(-1);
}
if (padding_at_end) {
memset(ptr, bank->default_padded_value, padding_at_end);
LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRId32
" bytes (bank write end alignment)",
end_addr + 1, padding_at_end);
}
struct duration bench;
duration_start(&bench);
for (wrote = 0; wrote < (count*wordsize); wrote += cur_size) {
struct flash_bank *bank;
retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size);
if (retval != ERROR_OK)
goto done;
retval = get_flash_bank_by_addr(target, address, true, &bank);
if (retval != ERROR_OK)
goto done;
retval = flash_driver_read(bank, buffer, address - bank->base, size_bytes);
if (retval != ERROR_OK)
goto done;
cur_size = MIN((count * wordsize - wrote), chunksize);
err = flash_driver_write(bank, chunk, address - bank->base + wrote, cur_size);
if (err != ERROR_OK) {
retval = err;
for (i = 0, ptr = buffer; i < count; i++) {
uint32_t readback = 0;
switch (wordsize) {
case 4:
readback = target_buffer_get_u32(target, ptr);
break;
case 2:
readback = target_buffer_get_u16(target, ptr);
break;
case 1:
readback = *ptr;
break;
}
if (readback != pattern) {
LOG_ERROR(
"Verification error address " TARGET_ADDR_FMT
", read back 0x%02" PRIx32 ", expected 0x%02" PRIx32,
address + i * wordsize, readback, pattern);
retval = ERROR_FAIL;
goto done;
}
err = flash_driver_read(bank, readback, address - bank->base + wrote, cur_size);
if (err != ERROR_OK) {
retval = err;
goto done;
}
for (i = 0; i < cur_size; i++) {
if (readback[i] != chunk[i]) {
LOG_ERROR(
"Verification error address 0x%08" PRIx32 ", read back 0x%02x, expected 0x%02x",
address + wrote + i,
readback[i],
chunk[i]);
retval = ERROR_FAIL;
goto done;
}
}
ptr += wordsize;
}
if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD_CTX, "wrote %" PRIu32 " bytes to 0x%8.8" PRIx32
" in %fs (%0.3f KiB/s)", wrote, address,
duration_elapsed(&bench), duration_kbps(&bench, wrote));
command_print(CMD_CTX, "wrote %" PRIu32 " bytes to " TARGET_ADDR_FMT
" in %fs (%0.3f KiB/s)", size_bytes, address,
duration_elapsed(&bench), duration_kbps(&bench, size_bytes));
}
done:
free(readback);
free(chunk);
free(buffer);
return retval;
}
@@ -592,8 +620,8 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
struct duration bench;
duration_start(&bench);
struct flash_bank *p;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
@@ -602,7 +630,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
if (CMD_ARGC > 2)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset);
if (offset > p->size) {
if (offset > bank->size) {
LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank",
offset);
return ERROR_COMMAND_ARGUMENT_INVALID;
@@ -618,7 +646,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
return retval;
}
length = MIN(filesize, p->size - offset);
length = MIN(filesize, bank->size - offset);
if (!length) {
LOG_INFO("Nothing to write to flash bank");
@@ -630,14 +658,33 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
LOG_INFO("File content exceeds flash bank size. Only writing the "
"first %zu bytes of the file", length);
buffer = malloc(length);
target_addr_t start_addr = bank->base + offset;
target_addr_t aligned_start = flash_write_align_start(bank, start_addr);
target_addr_t end_addr = start_addr + length - 1;
target_addr_t aligned_end = flash_write_align_end(bank, end_addr);
uint32_t aligned_size = aligned_end + 1 - aligned_start;
uint32_t padding_at_start = start_addr - aligned_start;
uint32_t padding_at_end = aligned_end - end_addr;
buffer = malloc(aligned_size);
if (buffer == NULL) {
fileio_close(fileio);
LOG_ERROR("Out of memory");
return ERROR_FAIL;
}
if (padding_at_start) {
memset(buffer, bank->default_padded_value, padding_at_start);
LOG_WARNING("Start offset 0x%08" PRIx32
" breaks the required alignment of flash bank %s",
offset, bank->name);
LOG_WARNING("Padding %" PRId32 " bytes from " TARGET_ADDR_FMT,
padding_at_start, aligned_start);
}
uint8_t *ptr = buffer + padding_at_start;
size_t buf_cnt;
if (fileio_read(fileio, length, buffer, &buf_cnt) != ERROR_OK) {
if (fileio_read(fileio, length, ptr, &buf_cnt) != ERROR_OK) {
free(buffer);
fileio_close(fileio);
return ERROR_FAIL;
@@ -649,15 +696,23 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
return ERROR_FAIL;
}
retval = flash_driver_write(p, buffer, offset, length);
ptr += length;
if (padding_at_end) {
memset(ptr, bank->default_padded_value, padding_at_end);
LOG_INFO("Padding at " TARGET_ADDR_FMT " with %" PRId32
" bytes (bank write end alignment)",
end_addr + 1, padding_at_end);
}
retval = flash_driver_write(bank, buffer, aligned_start - bank->base, aligned_size);
free(buffer);
buffer = NULL;
if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) {
command_print(CMD_CTX, "wrote %zu bytes from file %s to flash bank %u"
" at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
length, CMD_ARGV[1], p->bank_number, offset,
length, CMD_ARGV[1], bank->bank_number, offset,
duration_elapsed(&bench), duration_kbps(&bench, length));
}
@@ -1071,21 +1126,16 @@ COMMAND_HANDLER(handle_flash_bank_command)
}
}
struct flash_bank *c = malloc(sizeof(*c));
struct flash_bank *c = calloc(1, sizeof(*c));
c->name = strdup(bank_name);
c->target = target;
c->driver = driver;
c->driver_priv = NULL;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], c->base);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], c->chip_width);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], c->bus_width);
c->default_padded_value = c->erased_value = 0xff;
c->num_sectors = 0;
c->sectors = NULL;
c->num_prot_blocks = 0;
c->prot_blocks = NULL;
c->next = NULL;
c->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
int retval;
retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c);
+10 -21
View File
@@ -151,6 +151,7 @@ static int tms470_read_part_info(struct flash_bank *bank)
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
bank->num_sectors = 0;
}
/*
@@ -754,9 +755,6 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector)
target_write_u32(target, 0xFFFFFFDC, glbctrl);
LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl);
if (result == ERROR_OK)
bank->sectors[sector].is_erased = 1;
return result;
}
@@ -1044,27 +1042,17 @@ static int tms470_erase_check(struct flash_bank *bank)
* an attempt to reduce the JTAG overhead.
*/
for (sector = 0; sector < bank->num_sectors; sector++) {
if (bank->sectors[sector].is_erased != 1) {
uint32_t i, addr = bank->base + bank->sectors[sector].offset;
uint32_t i, addr = bank->base + bank->sectors[sector].offset;
LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector);
target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
target_read_buffer(target, addr, bank->sectors[sector].size, buffer);
bank->sectors[sector].is_erased = 1;
for (i = 0; i < bank->sectors[sector].size; i++) {
if (buffer[i] != 0xff) {
LOG_WARNING("tms470 bank %d, sector %d, not erased.",
tms470_info->ordinal,
sector);
LOG_WARNING(
"at location 0x%08" PRIx32 ": flash data is 0x%02x.",
addr + i,
buffer[i]);
bank->sectors[sector].is_erased = 0;
break;
}
bank->sectors[sector].is_erased = 1;
for (i = 0; i < bank->sectors[sector].size; i++) {
if (buffer[i] != 0xff) {
bank->sectors[sector].is_erased = 0;
break;
}
}
if (bank->sectors[sector].is_erased != 1) {
@@ -1186,4 +1174,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,
};
+6
View File
@@ -46,8 +46,13 @@ static void virtual_update_bank_info(struct flash_bank *bank)
bank->bus_width = master_bank->bus_width;
bank->erased_value = master_bank->erased_value;
bank->default_padded_value = master_bank->default_padded_value;
bank->write_start_alignment = master_bank->write_start_alignment;
bank->write_end_alignment = master_bank->write_end_alignment;
bank->minimal_write_gap = master_bank->minimal_write_gap;
bank->num_sectors = master_bank->num_sectors;
bank->sectors = master_bank->sectors;
bank->num_prot_blocks = master_bank->num_prot_blocks;
bank->prot_blocks = master_bank->prot_blocks;
}
FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command)
@@ -231,4 +236,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,
};
+19 -5
View File
@@ -608,7 +608,23 @@ static int run_command(struct command_context *context,
.argc = num_words - 1,
.argv = words + 1,
};
/* Black magic of overridden current target:
* If the command we are going to handle has a target prefix,
* override the current target temporarily for the time
* of processing the command.
* current_target_override is used also for event handlers
* therefore we prevent touching it if command has no prefix.
* Previous override is saved and restored back to ensure
* correct work when run_command() is re-entered. */
struct target *saved_target_override = context->current_target_override;
if (c->jim_handler_data)
context->current_target_override = c->jim_handler_data;
int retval = c->handler(&cmd);
if (c->jim_handler_data)
context->current_target_override = saved_target_override;
if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
/* Print help for command */
char *full_name = command_name(c, ' ');
@@ -643,6 +659,8 @@ int command_run_line(struct command_context *context, char *line)
* happen when the Jim Tcl interpreter is provided by eCos for
* instance.
*/
context->current_target_override = NULL;
Jim_Interp *interp = context->interp;
Jim_DeleteAssocData(interp, "context");
retcode = Jim_SetAssocData(interp, "context", NULL, context);
@@ -1269,14 +1287,10 @@ static const struct command_registration command_builtin_handlers[] = {
struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp)
{
struct command_context *context = malloc(sizeof(struct command_context));
struct command_context *context = calloc(1, sizeof(struct command_context));
const char *HostOs;
context->mode = COMMAND_EXEC;
context->commands = NULL;
context->current_target = 0;
context->output_handler = NULL;
context->output_handler_priv = NULL;
/* Create a jim interpreter if we were not handed one */
if (interp == NULL) {
+18 -1
View File
@@ -22,8 +22,12 @@
#ifndef OPENOCD_HELPER_COMMAND_H
#define OPENOCD_HELPER_COMMAND_H
#include <stdint.h>
#include <stdbool.h>
#include <jim-nvp.h>
#include <helper/types.h>
/* To achieve C99 printf compatibility in MinGW, gnu_printf should be
* used for __attribute__((format( ... ))), with GCC v4.4 or later
*/
@@ -49,7 +53,15 @@ struct command_context {
Jim_Interp *interp;
enum command_mode mode;
struct command *commands;
int current_target;
struct target *current_target;
/* The target set by 'targets xx' command or the latest created */
struct target *current_target_override;
/* If set overrides current_target
* It happens during processing of
* 1) a target prefixed command
* 2) an event handler
* Pay attention to reentrancy when setting override.
*/
command_output_handler_t output_handler;
void *output_handler_priv;
};
@@ -168,6 +180,11 @@ struct command {
command_handler_t handler;
Jim_CmdProc *jim_handler;
void *jim_handler_data;
/* Currently used only for target of target-prefixed cmd.
* Native OpenOCD commands use jim_handler_data exclusively
* as a target override.
* Jim handlers outside of target cmd tree can use
* jim_handler_data for any handler specific data */
enum command_mode mode;
struct command *next;
};
+15
View File
@@ -51,6 +51,21 @@ void add_config_command(const char *cfg)
config_file_names[num_config_files] = NULL;
}
void free_config(void)
{
while (num_config_files)
free(config_file_names[--num_config_files]);
free(config_file_names);
config_file_names = NULL;
while (num_script_dirs)
free(script_search_dirs[--num_script_dirs]);
free(script_search_dirs);
script_search_dirs = NULL;
}
/* return full path or NULL according to search rules */
char *find_file(const char *file)
{
+2
View File
@@ -32,6 +32,8 @@ void add_config_command(const char *cfg);
void add_script_search_dir(const char *dir);
void free_config(void);
int configuration_output_handler(struct command_context *cmd_ctx,
const char *line);
+5
View File
@@ -153,6 +153,11 @@ int fileio_close(struct fileio *fileio)
return retval;
}
int fileio_feof(struct fileio *fileio)
{
return feof(fileio->file);
}
int fileio_seek(struct fileio *fileio, size_t position)
{
int retval;
+1
View File
@@ -46,6 +46,7 @@ struct fileio;
int fileio_open(struct fileio **fileio, const char *url,
enum fileio_access access_type, enum fileio_type type);
int fileio_close(struct fileio *fileio);
int fileio_feof(struct fileio *fileio);
int fileio_seek(struct fileio *fileio, size_t position);
int fileio_fgets(struct fileio *fileio, size_t size, void *buffer);
+2
View File
@@ -149,6 +149,8 @@ extern int debug_level;
*/
#define ERROR_FAIL (-4)
#define ERROR_WAIT (-5)
/* ERROR_TIMEOUT is already taken by winerror.h. */
#define ERROR_TIMEOUT_REACHED (-6)
#endif /* OPENOCD_HELPER_LOG_H */
+2
View File
@@ -25,6 +25,8 @@
#ifndef OPENOCD_HELPER_REPLACEMENTS_H
#define OPENOCD_HELPER_REPLACEMENTS_H
#include <stdint.h>
/* MIN,MAX macros */
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+11 -6
View File
@@ -22,7 +22,12 @@
#ifndef OPENOCD_HELPER_TYPES_H
#define OPENOCD_HELPER_TYPES_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stddef.h>
#include <assert.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -123,17 +128,17 @@ static inline uint64_t le_to_h_u64(const uint8_t *buf)
static inline uint32_t le_to_h_u32(const uint8_t* buf)
{
return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24);
return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24);
}
static inline uint32_t le_to_h_u24(const uint8_t* buf)
{
return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16);
return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16);
}
static inline uint16_t le_to_h_u16(const uint8_t* buf)
{
return (uint16_t)(buf[0] | buf[1] << 8);
return (uint16_t)((uint16_t)buf[0] | (uint16_t)buf[1] << 8);
}
static inline uint64_t be_to_h_u64(const uint8_t *buf)
@@ -150,17 +155,17 @@ static inline uint64_t be_to_h_u64(const uint8_t *buf)
static inline uint32_t be_to_h_u32(const uint8_t* buf)
{
return (uint32_t)(buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24);
return (uint32_t)((uint32_t)buf[3] | (uint32_t)buf[2] << 8 | (uint32_t)buf[1] << 16 | (uint32_t)buf[0] << 24);
}
static inline uint32_t be_to_h_u24(const uint8_t* buf)
{
return (uint32_t)(buf[2] | buf[1] << 8 | buf[0] << 16);
return (uint32_t)((uint32_t)buf[2] | (uint32_t)buf[1] << 8 | (uint32_t)buf[0] << 16);
}
static inline uint16_t be_to_h_u16(const uint8_t* buf)
{
return (uint16_t)(buf[1] | buf[0] << 8);
return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8);
}
static inline void h_u64_to_le(uint8_t *buf, int64_t val)
+8 -8
View File
@@ -149,14 +149,14 @@ COMMAND_HANDLER(handle_interface_command)
jtag_interface = jtag_interfaces[i];
/* LEGACY SUPPORT ... adapter drivers must declare what
* transports they allow. Until they all do so, assume
* the legacy drivers are JTAG-only
*/
if (!jtag_interface->transports)
LOG_WARNING("Adapter driver '%s' did not declare "
"which transports it allows; assuming "
"legacy JTAG-only", jtag_interface->name);
/* LEGACY SUPPORT ... adapter drivers must declare what
* transports they allow. Until they all do so, assume
* the legacy drivers are JTAG-only
*/
if (!jtag_interface->transports)
LOG_WARNING("Adapter driver '%s' did not declare "
"which transports it allows; assuming "
"legacy JTAG-only", jtag_interface->name);
retval = allow_transports(CMD_CTX, jtag_interface->transports
? jtag_interface->transports : jtag_only);
if (ERROR_OK != retval)
+24
View File
@@ -239,6 +239,30 @@ static int aice_khz(int khz, int *jtag_speed)
return ERROR_OK;
}
int aice_scan_jtag_chain(void)
{
LOG_DEBUG("=== %s ===", __func__);
uint8_t num_of_idcode = 0;
struct target *target;
int res = aice_port->api->idcode(aice_target_id_codes, &num_of_idcode);
if (res != ERROR_OK) {
LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore "
"JTAG Manufacture ID in the JTAG scan chain. "
"Failed to access EDM registers. -->");
return res;
}
for (uint32_t i = 0; i < num_of_idcode; i++)
LOG_DEBUG("id_codes[%d] = 0x%x", i, aice_target_id_codes[i]);
/* Update tap idcode */
for (target = all_targets; target; target = target->next)
target->tap->idcode = aice_target_id_codes[target->tap->abs_chain_position];
return ERROR_OK;
}
/***************************************************************************/
/* Command handlers */
COMMAND_HANDLER(aice_handle_aice_info_command)
+1
View File
@@ -31,5 +31,6 @@ struct aice_interface_param_s {
};
int aice_init_targets(void);
int aice_scan_jtag_chain(void);
#endif /* OPENOCD_JTAG_AICE_AICE_INTERFACE_H */
+60
View File
@@ -158,6 +158,59 @@ COMMAND_HANDLER(handle_aice_init_command)
return jtag_init(CMD_CTX);
}
COMMAND_HANDLER(handle_scan_chain_command)
{
struct jtag_tap *tap;
char expected_id[12];
aice_scan_jtag_chain();
tap = jtag_all_taps();
command_print(CMD_CTX,
" TapName Enabled IdCode Expected IrLen IrCap IrMask");
command_print(CMD_CTX,
"-- ------------------- -------- ---------- ---------- ----- ----- ------");
while (tap) {
uint32_t expected, expected_mask, ii;
snprintf(expected_id, sizeof expected_id, "0x%08x",
(unsigned)((tap->expected_ids_cnt > 0)
? tap->expected_ids[0]
: 0));
if (tap->ignore_version)
expected_id[2] = '*';
expected = buf_get_u32(tap->expected, 0, tap->ir_length);
expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length);
command_print(CMD_CTX,
"%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x",
tap->abs_chain_position,
tap->dotted_name,
tap->enabled ? 'Y' : 'n',
(unsigned int)(tap->idcode),
expected_id,
(unsigned int)(tap->ir_length),
(unsigned int)(expected),
(unsigned int)(expected_mask));
for (ii = 1; ii < tap->expected_ids_cnt; ii++) {
snprintf(expected_id, sizeof expected_id, "0x%08x",
(unsigned) tap->expected_ids[ii]);
if (tap->ignore_version)
expected_id[2] = '*';
command_print(CMD_CTX,
" %s",
expected_id);
}
tap = tap->next_tap;
}
return ERROR_OK;
}
static int jim_aice_arp_init(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{
LOG_DEBUG("No implement: jim_aice_arp_init");
@@ -307,6 +360,13 @@ aice_transport_jtag_subcommand_handlers[] = {
.jim_handler = jim_aice_names,
.help = "Returns list of all JTAG tap names.",
},
{
.name = "scan_chain",
.handler = handle_scan_chain_command,
.mode = COMMAND_ANY,
.help = "print current scan chain configuration",
.usage = ""
},
COMMAND_REGISTRATION_DONE
};
+27 -25
View File
@@ -2289,37 +2289,39 @@ get_delay:
static int aice_usb_set_clock(int set_clock)
{
if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL,
AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK)
return ERROR_FAIL;
if (set_clock & AICE_TCK_CONTROL_TCK_SCAN) {
if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL,
AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK)
return ERROR_FAIL;
/* Read out TCK_SCAN clock value */
uint32_t scan_clock;
if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK)
return ERROR_FAIL;
/* Read out TCK_SCAN clock value */
uint32_t scan_clock;
if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK)
return ERROR_FAIL;
scan_clock &= 0x0F;
scan_clock &= 0x0F;
uint32_t scan_base_freq;
if (scan_clock & 0x8)
scan_base_freq = 48000; /* 48 MHz */
else
scan_base_freq = 30000; /* 30 MHz */
uint32_t scan_base_freq;
if (scan_clock & 0x8)
scan_base_freq = 48000; /* 48 MHz */
else
scan_base_freq = 30000; /* 30 MHz */
uint32_t set_base_freq;
if (set_clock & 0x8)
set_base_freq = 48000;
else
set_base_freq = 30000;
uint32_t set_base_freq;
if (set_clock & 0x8)
set_base_freq = 48000;
else
set_base_freq = 30000;
uint32_t set_freq;
uint32_t scan_freq;
set_freq = set_base_freq >> (set_clock & 0x7);
scan_freq = scan_base_freq >> (scan_clock & 0x7);
uint32_t set_freq;
uint32_t scan_freq;
set_freq = set_base_freq >> (set_clock & 0x7);
scan_freq = scan_base_freq >> (scan_clock & 0x7);
if (scan_freq < set_freq) {
LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock");
return ERROR_FAIL;
if (scan_freq < set_freq) {
LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock");
return ERROR_FAIL;
}
}
if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, set_clock) != ERROR_OK)
+1
View File
@@ -71,6 +71,7 @@
/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */
#define AICE_TCK_CONTROL_TCK3048 0x08
#define AICE_TCK_CONTROL_TCK_SCAN 0x10
/* Constants for AICE command WRITE_CTRL:JTAG_PIN_CONTROL */
#define AICE_JTAG_PIN_CONTROL_SRST 0x01
+23 -71
View File
@@ -836,68 +836,7 @@ int default_interface_jtag_execute_queue(void)
return ERROR_FAIL;
}
int result = jtag->execute_queue();
struct jtag_command *cmd = jtag_command_queue;
while (debug_level >= LOG_LVL_DEBUG && cmd) {
switch (cmd->type) {
case JTAG_SCAN:
DEBUG_JTAG_IO("JTAG %s SCAN to %s",
cmd->cmd.scan->ir_scan ? "IR" : "DR",
tap_state_name(cmd->cmd.scan->end_state));
for (int i = 0; i < cmd->cmd.scan->num_fields; i++) {
struct scan_field *field = cmd->cmd.scan->fields + i;
if (field->out_value) {
char *str = buf_to_str(field->out_value, field->num_bits, 16);
DEBUG_JTAG_IO(" %db out: %s", field->num_bits, str);
free(str);
}
if (field->in_value) {
char *str = buf_to_str(field->in_value, field->num_bits, 16);
DEBUG_JTAG_IO(" %db in: %s", field->num_bits, str);
free(str);
}
}
break;
case JTAG_TLR_RESET:
DEBUG_JTAG_IO("JTAG TLR RESET to %s",
tap_state_name(cmd->cmd.statemove->end_state));
break;
case JTAG_RUNTEST:
DEBUG_JTAG_IO("JTAG RUNTEST %d cycles to %s",
cmd->cmd.runtest->num_cycles,
tap_state_name(cmd->cmd.runtest->end_state));
break;
case JTAG_RESET:
{
const char *reset_str[3] = {
"leave", "deassert", "assert"
};
DEBUG_JTAG_IO("JTAG RESET %s TRST, %s SRST",
reset_str[cmd->cmd.reset->trst + 1],
reset_str[cmd->cmd.reset->srst + 1]);
}
break;
case JTAG_PATHMOVE:
DEBUG_JTAG_IO("JTAG PATHMOVE (TODO)");
break;
case JTAG_SLEEP:
DEBUG_JTAG_IO("JTAG SLEEP (TODO)");
break;
case JTAG_STABLECLOCKS:
DEBUG_JTAG_IO("JTAG STABLECLOCKS (TODO)");
break;
case JTAG_TMS:
DEBUG_JTAG_IO("JTAG STABLECLOCKS (TODO)");
break;
default:
LOG_ERROR("Unknown JTAG command: %d", cmd->type);
break;
}
cmd = cmd->next;
}
return result;
return jtag->execute_queue();
}
void jtag_execute_queue_noclear(void)
@@ -1168,8 +1107,7 @@ static int jtag_examine_chain(void)
if ((idcode & 1) == 0) {
/* Zero for LSB indicates a device in bypass */
LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%x)",
tap->dotted_name, idcode);
LOG_INFO("TAP %s does not have IDCODE", tap->dotted_name);
tap->hasidcode = false;
tap->idcode = 0;
@@ -1370,6 +1308,14 @@ void jtag_tap_free(struct jtag_tap *tap)
{
jtag_unregister_event_callback(&jtag_reset_callback, tap);
struct jtag_tap_event_action *jteap = tap->event_action;
while (jteap) {
struct jtag_tap_event_action *next = jteap->next;
Jim_DecrRefCount(jteap->interp, jteap->body);
free(jteap);
jteap = next;
}
free(tap->expected);
free(tap->expected_mask);
free(tap->expected_ids);
@@ -1534,13 +1480,19 @@ int jtag_init_inner(struct command_context *cmd_ctx)
int adapter_quit(void)
{
if (!jtag || !jtag->quit)
return ERROR_OK;
if (jtag && jtag->quit) {
/* close the JTAG interface */
int result = jtag->quit();
if (ERROR_OK != result)
LOG_ERROR("failed: %d", result);
}
/* close the JTAG interface */
int result = jtag->quit();
if (ERROR_OK != result)
LOG_ERROR("failed: %d", result);
struct jtag_tap *t = jtag_all_taps();
while (t) {
struct jtag_tap *n = t->next_tap;
jtag_tap_free(t);
t = n;
}
return ERROR_OK;
}
@@ -1891,7 +1843,7 @@ void adapter_deassert_reset(void)
LOG_ERROR("transport is not selected");
}
int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (jtag->config_trace)
+6 -1
View File
@@ -80,6 +80,9 @@ if USB_BLASTER_DRIVER
%C%_libocdjtagdrivers_la_LIBADD += %D%/usb_blaster/libocdusbblaster.la
include %D%/usb_blaster/Makefile.am
endif
if FT232R
DRIVERFILES += %D%/ft232r.c
endif
if AMTJTAGACCEL
DRIVERFILES += %D%/amt_jtagaccel.c
endif
@@ -153,10 +156,12 @@ endif
if IMX_GPIO
DRIVERFILES += %D%/imx_gpio.c
endif
if KITPROG
DRIVERFILES += %D%/kitprog.c
endif
if XDS110
DRIVERFILES += %D%/xds110.c
endif
DRIVERHEADERS = \
%D%/bitbang.h \
+459 -50
View File
@@ -22,6 +22,7 @@
#endif
#include <jtag/interface.h>
#include <jtag/swd.h>
#include <jtag/commands.h>
#include <termios.h>
@@ -48,9 +49,21 @@ static void buspirate_stableclocks(int num_cycles);
#define CMD_READ_ADCS 0x03
/*#define CMD_TAP_SHIFT 0x04 // old protocol */
#define CMD_TAP_SHIFT 0x05
#define CMD_ENTER_RWIRE 0x05
#define CMD_ENTER_OOCD 0x06
#define CMD_UART_SPEED 0x07
#define CMD_JTAG_SPEED 0x08
#define CMD_RAW_PERIPH 0x40
#define CMD_RAW_SPEED 0x60
#define CMD_RAW_MODE 0x80
/* raw-wire mode configuration */
#define CMD_RAW_CONFIG_HIZ 0x00
#define CMD_RAW_CONFIG_3V3 0x08
#define CMD_RAW_CONFIG_2W 0x00
#define CMD_RAW_CONFIG_3W 0x04
#define CMD_RAW_CONFIG_MSB 0x00
#define CMD_RAW_CONFIG_LSB 0x02
/* Not all OSes have this speed defined */
#if !defined(B1000000)
@@ -81,6 +94,18 @@ enum {
SERIAL_FAST = 1
};
enum {
SPEED_RAW_5_KHZ = 0x0,
SPEED_RAW_50_KHZ = 0x1,
SPEED_RAW_100_KHZ = 0x2,
SPEED_RAW_400_KHZ = 0x3
};
/* SWD mode specific */
static bool swd_mode;
static int queued_retval;
static char swd_features;
static const cc_t SHORT_TIMEOUT = 1; /* Must be at least 1. */
static const cc_t NORMAL_TIMEOUT = 10;
@@ -93,6 +118,12 @@ static char *buspirate_port;
static enum tap_state last_tap_state = TAP_RESET;
/* SWD interface */
static int buspirate_swd_init(void);
static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk);
static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk);
static int buspirate_swd_switch_seq(enum swd_special_seq seq);
static int buspirate_swd_run_queue(void);
/* TAP interface */
static void buspirate_tap_init(void);
@@ -103,23 +134,31 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer,
static void buspirate_tap_make_space(int scan, int bits);
static void buspirate_reset(int trst, int srst);
static void buspirate_set_feature(int, char, char);
static void buspirate_set_mode(int, char);
static void buspirate_set_speed(int, char);
/* low level interface */
static void buspirate_bbio_enable(int);
static void buspirate_jtag_reset(int);
static void buspirate_jtag_enable(int);
static unsigned char buspirate_jtag_command(int, char *, int);
static unsigned char buspirate_jtag_command(int, uint8_t *, int);
static void buspirate_jtag_set_speed(int, char);
static void buspirate_jtag_set_mode(int, char);
static void buspirate_jtag_set_feature(int, char, char);
static void buspirate_jtag_get_adcs(int);
/* low level two-wire interface */
static void buspirate_swd_set_speed(int, char);
static void buspirate_swd_set_feature(int, char, char);
static void buspirate_swd_set_mode(int, char);
/* low level HW communication interface */
static int buspirate_serial_open(char *port);
static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout);
static int buspirate_serial_write(int fd, char *buf, int size);
static int buspirate_serial_read(int fd, char *buf, int size);
static int buspirate_serial_write(int fd, uint8_t *buf, int size);
static int buspirate_serial_read(int fd, uint8_t *buf, int size);
static void buspirate_serial_close(int fd);
static void buspirate_print_buffer(char *buf, int size);
static void buspirate_print_buffer(uint8_t *buf, int size);
static int buspirate_execute_queue(void)
{
@@ -216,7 +255,7 @@ static bool read_and_discard_all_data(const int fd)
bool was_msg_already_printed = false;
for ( ; ; ) {
char buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */
uint8_t buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */
const ssize_t read_count = read(fd, buffer, sizeof(buffer));
@@ -295,18 +334,20 @@ static int buspirate_init(void)
return ERROR_JTAG_INIT_FAILED;
}
buspirate_jtag_enable(buspirate_fd);
buspirate_bbio_enable(buspirate_fd);
if (buspirate_baudrate != SERIAL_NORMAL)
buspirate_jtag_set_speed(buspirate_fd, SERIAL_FAST);
if (swd_mode || buspirate_baudrate != SERIAL_NORMAL)
buspirate_set_speed(buspirate_fd, SERIAL_FAST);
LOG_INFO("Buspirate Interface ready!");
LOG_INFO("Buspirate %s Interface ready!", swd_mode ? "SWD" : "JTAG");
buspirate_tap_init();
buspirate_jtag_set_mode(buspirate_fd, buspirate_pinmode);
buspirate_jtag_set_feature(buspirate_fd, FEATURE_VREG,
if (!swd_mode)
buspirate_tap_init();
buspirate_set_mode(buspirate_fd, buspirate_pinmode);
buspirate_set_feature(buspirate_fd, FEATURE_VREG,
(buspirate_vreg == 1) ? ACTION_ENABLE : ACTION_DISABLE);
buspirate_jtag_set_feature(buspirate_fd, FEATURE_PULLUP,
buspirate_set_feature(buspirate_fd, FEATURE_PULLUP,
(buspirate_pullup == 1) ? ACTION_ENABLE : ACTION_DISABLE);
buspirate_reset(0, 0);
@@ -316,9 +357,9 @@ static int buspirate_init(void)
static int buspirate_quit(void)
{
LOG_INFO("Shutting down buspirate.");
buspirate_jtag_set_mode(buspirate_fd, MODE_HIZ);
buspirate_set_mode(buspirate_fd, MODE_HIZ);
buspirate_set_speed(buspirate_fd, SERIAL_NORMAL);
buspirate_jtag_set_speed(buspirate_fd, SERIAL_NORMAL);
buspirate_jtag_reset(buspirate_fd);
buspirate_serial_close(buspirate_fd);
@@ -336,6 +377,10 @@ COMMAND_HANDLER(buspirate_handle_adc_command)
if (buspirate_fd == -1)
return ERROR_OK;
/* unavailable in SWD mode */
if (swd_mode)
return ERROR_OK;
/* send the command */
buspirate_jtag_get_adcs(buspirate_fd);
@@ -382,11 +427,11 @@ COMMAND_HANDLER(buspirate_handle_led_command)
if (atoi(CMD_ARGV[0]) == 1) {
/* enable led */
buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED,
buspirate_set_feature(buspirate_fd, FEATURE_LED,
ACTION_ENABLE);
} else if (atoi(CMD_ARGV[0]) == 0) {
/* disable led */
buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED,
buspirate_set_feature(buspirate_fd, FEATURE_LED,
ACTION_DISABLE);
} else {
LOG_ERROR("usage: buspirate_led <1|0>");
@@ -492,10 +537,22 @@ static const struct command_registration buspirate_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
static const struct swd_driver buspirate_swd = {
.init = buspirate_swd_init,
.switch_seq = buspirate_swd_switch_seq,
.read_reg = buspirate_swd_read_reg,
.write_reg = buspirate_swd_write_reg,
.run = buspirate_swd_run_queue,
};
static const char * const buspirate_transports[] = { "jtag", "swd", NULL };
struct jtag_interface buspirate_interface = {
.name = "buspirate",
.execute_queue = buspirate_execute_queue,
.commands = buspirate_command_handlers,
.transports = buspirate_transports,
.swd = &buspirate_swd,
.init = buspirate_init,
.quit = buspirate_quit
};
@@ -633,8 +690,8 @@ static void buspirate_stableclocks(int num_cycles)
make it incompatible with the Bus Pirate firmware. */
#define BUSPIRATE_MAX_PENDING_SCANS 128
static char tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
static char tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
static uint8_t tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
static uint8_t tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */
static int tap_chain_index;
struct pending_scan_result /* this was stolen from arm-jtag-ew */
@@ -659,7 +716,7 @@ static int buspirate_tap_execute(void)
{
static const int CMD_TAP_SHIFT_HEADER_LEN = 3;
char tmp[4096];
uint8_t tmp[4096];
uint8_t *in_buf;
int i;
int fill_index = 0;
@@ -675,8 +732,8 @@ static int buspirate_tap_execute(void)
bytes_to_send = DIV_ROUND_UP(tap_chain_index, 8);
tmp[0] = CMD_TAP_SHIFT; /* this command expects number of bits */
tmp[1] = (char)(tap_chain_index >> 8); /* high */
tmp[2] = (char)(tap_chain_index); /* low */
tmp[1] = tap_chain_index >> 8; /* high */
tmp[2] = tap_chain_index; /* low */
fill_index = CMD_TAP_SHIFT_HEADER_LEN;
for (i = 0; i < bytes_to_send; i++) {
@@ -799,7 +856,7 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer,
tap_pending_scans_num++;
}
/*************** jtag wrapper functions *********************/
/*************** wrapper functions *********************/
/* (1) assert or (0) deassert reset lines */
static void buspirate_reset(int trst, int srst)
@@ -807,33 +864,148 @@ static void buspirate_reset(int trst, int srst)
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
if (trst)
buspirate_jtag_set_feature(buspirate_fd,
FEATURE_TRST, ACTION_DISABLE);
buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_DISABLE);
else
buspirate_jtag_set_feature(buspirate_fd,
FEATURE_TRST, ACTION_ENABLE);
buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_ENABLE);
if (srst)
buspirate_jtag_set_feature(buspirate_fd,
FEATURE_SRST, ACTION_DISABLE);
buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE);
else
buspirate_jtag_set_feature(buspirate_fd,
FEATURE_SRST, ACTION_ENABLE);
buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE);
}
static void buspirate_set_feature(int fd, char feat, char action)
{
if (swd_mode)
buspirate_swd_set_feature(fd, feat, action);
else
buspirate_jtag_set_feature(fd, feat, action);
}
static void buspirate_set_mode(int fd, char mode)
{
if (swd_mode)
buspirate_swd_set_mode(fd, mode);
else
buspirate_jtag_set_mode(fd, mode);
}
static void buspirate_set_speed(int fd, char speed)
{
if (swd_mode)
buspirate_swd_set_speed(fd, speed);
else
buspirate_jtag_set_speed(fd, speed);
}
/*************** swd lowlevel functions ********************/
static void buspirate_swd_set_speed(int fd, char speed)
{
int ret;
uint8_t tmp[1];
LOG_DEBUG("Buspirate speed setting in SWD mode defaults to 400 kHz");
/* speed settings */
tmp[0] = CMD_RAW_SPEED | SPEED_RAW_400_KHZ;
buspirate_serial_write(fd, tmp, 1);
ret = buspirate_serial_read(fd, tmp, 1);
if (ret != 1) {
LOG_ERROR("Buspirate did not answer correctly");
exit(-1);
}
if (tmp[0] != 1) {
LOG_ERROR("Buspirate did not reply as expected to the speed change command");
exit(-1);
}
}
static void buspirate_swd_set_mode(int fd, char mode)
{
int ret;
uint8_t tmp[1];
/* raw-wire mode configuration */
if (mode == MODE_HIZ)
tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB;
else
tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB | CMD_RAW_CONFIG_3V3;
buspirate_serial_write(fd, tmp, 1);
ret = buspirate_serial_read(fd, tmp, 1);
if (ret != 1) {
LOG_ERROR("Buspirate did not answer correctly");
exit(-1);
}
if (tmp[0] != 1) {
LOG_ERROR("Buspirate did not reply as expected to the configure command");
exit(-1);
}
}
static void buspirate_swd_set_feature(int fd, char feat, char action)
{
int ret;
uint8_t tmp[1];
switch (feat) {
case FEATURE_TRST:
LOG_DEBUG("Buspirate TRST feature not available in SWD mode");
return;
case FEATURE_LED:
LOG_ERROR("Buspirate LED feature not available in SWD mode");
return;
case FEATURE_SRST:
swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D;
break;
case FEATURE_PULLUP:
swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B;
break;
case FEATURE_VREG:
swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07;
break;
default:
LOG_DEBUG("Buspirate unknown feature %d", feat);
return;
}
tmp[0] = CMD_RAW_PERIPH | swd_features;
buspirate_serial_write(fd, tmp, 1);
ret = buspirate_serial_read(fd, tmp, 1);
if (ret != 1) {
LOG_DEBUG("Buspirate feature %d not supported in SWD mode", feat);
} else if (tmp[0] != 1) {
LOG_ERROR("Buspirate did not reply as expected to the configure command");
exit(-1);
}
}
/*************** jtag lowlevel functions ********************/
static void buspirate_jtag_enable(int fd)
static void buspirate_bbio_enable(int fd)
{
int ret;
char tmp[21] = { [0 ... 20] = 0x00 };
char command;
const char *mode_answers[2] = { "OCD1", "RAW1" };
const char *correct_ans = NULL;
uint8_t tmp[21] = { [0 ... 20] = 0x00 };
int done = 0;
int cmd_sent = 0;
LOG_DEBUG("Entering binary mode");
if (swd_mode) {
command = CMD_ENTER_RWIRE;
correct_ans = mode_answers[1];
} else {
command = CMD_ENTER_OOCD;
correct_ans = mode_answers[0];
}
LOG_DEBUG("Entering binary mode, that is %s", correct_ans);
buspirate_serial_write(fd, tmp, 20);
usleep(10000);
/* reads 1 to n "BBIO1"s and one "OCD1" */
/* reads 1 to n "BBIO1"s and one "OCD1" or "RAW1" */
while (!done) {
ret = buspirate_serial_read(fd, tmp, 4);
if (ret != 4) {
@@ -841,7 +1013,7 @@ static void buspirate_jtag_enable(int fd)
"/OpenOCD support enabled?");
exit(-1);
}
if (strncmp(tmp, "BBIO", 4) == 0) {
if (strncmp((char *)tmp, "BBIO", 4) == 0) {
ret = buspirate_serial_read(fd, tmp, 1);
if (ret != 1) {
LOG_ERROR("Buspirate did not answer correctly! "
@@ -854,14 +1026,14 @@ static void buspirate_jtag_enable(int fd)
}
if (cmd_sent == 0) {
cmd_sent = 1;
tmp[0] = CMD_ENTER_OOCD;
tmp[0] = command;
ret = buspirate_serial_write(fd, tmp, 1);
if (ret != 1) {
LOG_ERROR("error reading");
exit(-1);
}
}
} else if (strncmp(tmp, "OCD1", 4) == 0)
} else if (strncmp((char *)tmp, correct_ans, 4) == 0)
done = 1;
else {
LOG_ERROR("Buspirate did not answer correctly! "
@@ -874,14 +1046,14 @@ static void buspirate_jtag_enable(int fd)
static void buspirate_jtag_reset(int fd)
{
char tmp[5];
uint8_t tmp[5];
tmp[0] = 0x00; /* exit OCD1 mode */
buspirate_serial_write(fd, tmp, 1);
usleep(10000);
/* We ignore the return value here purposly, nothing we can do */
buspirate_serial_read(fd, tmp, 5);
if (strncmp(tmp, "BBIO1", 5) == 0) {
if (strncmp((char *)tmp, "BBIO1", 5) == 0) {
tmp[0] = 0x0F; /* reset BP */
buspirate_serial_write(fd, tmp, 1);
} else
@@ -891,8 +1063,8 @@ static void buspirate_jtag_reset(int fd)
static void buspirate_jtag_set_speed(int fd, char speed)
{
int ret;
char tmp[2];
char ack[2];
uint8_t tmp[2];
uint8_t ack[2];
ack[0] = 0xAA;
ack[1] = 0x55;
@@ -924,7 +1096,7 @@ static void buspirate_jtag_set_speed(int fd, char speed)
static void buspirate_jtag_set_mode(int fd, char mode)
{
char tmp[2];
uint8_t tmp[2];
tmp[0] = CMD_PORT_MODE;
tmp[1] = mode;
buspirate_jtag_command(fd, tmp, 2);
@@ -932,7 +1104,7 @@ static void buspirate_jtag_set_mode(int fd, char mode)
static void buspirate_jtag_set_feature(int fd, char feat, char action)
{
char tmp[3];
uint8_t tmp[3];
tmp[0] = CMD_FEATURE;
tmp[1] = feat; /* what */
tmp[2] = action; /* action */
@@ -944,7 +1116,7 @@ static void buspirate_jtag_get_adcs(int fd)
uint8_t tmp[10];
uint16_t a, b, c, d;
tmp[0] = CMD_READ_ADCS;
buspirate_jtag_command(fd, (char *)tmp, 1);
buspirate_jtag_command(fd, tmp, 1);
a = tmp[2] << 8 | tmp[3];
b = tmp[4] << 8 | tmp[5];
c = tmp[6] << 8 | tmp[7];
@@ -957,7 +1129,7 @@ static void buspirate_jtag_get_adcs(int fd)
}
static unsigned char buspirate_jtag_command(int fd,
char *cmd, int cmdlen)
uint8_t *cmd, int cmdlen)
{
int res;
int len = 0;
@@ -1048,7 +1220,7 @@ static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout)
return 0;
}
static int buspirate_serial_write(int fd, char *buf, int size)
static int buspirate_serial_write(int fd, uint8_t *buf, int size)
{
int ret = 0;
@@ -1063,7 +1235,7 @@ static int buspirate_serial_write(int fd, char *buf, int size)
return ret;
}
static int buspirate_serial_read(int fd, char *buf, int size)
static int buspirate_serial_read(int fd, uint8_t *buf, int size)
{
int len = 0;
int ret = 0;
@@ -1102,7 +1274,7 @@ static void buspirate_serial_close(int fd)
#define LINE_SIZE 81
#define BYTES_PER_LINE 16
static void buspirate_print_buffer(char *buf, int size)
static void buspirate_print_buffer(uint8_t *buf, int size)
{
char line[LINE_SIZE];
char tmp[10];
@@ -1124,3 +1296,240 @@ static void buspirate_print_buffer(char *buf, int size)
if (line[0] != 0)
LOG_DEBUG("%s", line);
}
/************************* SWD related stuff **********/
static int buspirate_swd_init(void)
{
LOG_INFO("Buspirate SWD mode enabled");
swd_mode = true;
return ERROR_OK;
}
static int buspirate_swd_switch_seq(enum swd_special_seq seq)
{
const uint8_t *sequence;
int sequence_len;
uint8_t tmp[64];
switch (seq) {
case LINE_RESET:
LOG_DEBUG("SWD line reset");
sequence = swd_seq_line_reset;
sequence_len = DIV_ROUND_UP(swd_seq_line_reset_len, 8);
break;
case JTAG_TO_SWD:
LOG_DEBUG("JTAG-to-SWD");
sequence = swd_seq_jtag_to_swd;
sequence_len = DIV_ROUND_UP(swd_seq_jtag_to_swd_len, 8);
break;
case SWD_TO_JTAG:
LOG_DEBUG("SWD-to-JTAG");
sequence = swd_seq_swd_to_jtag;
sequence_len = DIV_ROUND_UP(swd_seq_swd_to_jtag_len, 8);
break;
default:
LOG_ERROR("Sequence %d not supported", seq);
return ERROR_FAIL;
}
/* FIXME: all above sequences fit into one pirate command for now
* but it may cause trouble later
*/
tmp[0] = 0x10 + ((sequence_len - 1) & 0x0F);
memcpy(tmp + 1, sequence, sequence_len);
buspirate_serial_write(buspirate_fd, tmp, sequence_len + 1);
buspirate_serial_read(buspirate_fd, tmp, sequence_len + 1);
return ERROR_OK;
}
static uint8_t buspirate_swd_write_header(uint8_t cmd)
{
uint8_t tmp[8];
int to_send;
tmp[0] = 0x10; /* bus pirate: send 1 byte */
tmp[1] = cmd; /* swd cmd */
tmp[2] = 0x07; /* ack __x */
tmp[3] = 0x07; /* ack _x_ */
tmp[4] = 0x07; /* ack x__ */
tmp[5] = 0x07; /* write mode trn_1 */
tmp[6] = 0x07; /* write mode trn_2 */
to_send = ((cmd & SWD_CMD_RnW) == 0) ? 7 : 5;
buspirate_serial_write(buspirate_fd, tmp, to_send);
/* read ack */
buspirate_serial_read(buspirate_fd, tmp, 2); /* drop pirate command ret vals */
buspirate_serial_read(buspirate_fd, tmp, to_send - 2); /* ack bits */
return tmp[2] << 2 | tmp[1] << 1 | tmp[0];
}
static void buspirate_swd_idle_clocks(uint32_t no_bits)
{
uint32_t no_bytes;
uint8_t tmp[20];
no_bytes = (no_bits + 7) / 8;
memset(tmp + 1, 0x00, sizeof(tmp) - 1);
/* unfortunately bus pirate misbehaves when clocks are sent in parts
* so we need to limit at 128 clock cycles
*/
if (no_bytes > 16)
no_bytes = 16;
while (no_bytes) {
uint8_t to_send = no_bytes > 16 ? 16 : no_bytes;
tmp[0] = 0x10 + ((to_send - 1) & 0x0F);
buspirate_serial_write(buspirate_fd, tmp, to_send + 1);
buspirate_serial_read(buspirate_fd, tmp, to_send + 1);
no_bytes -= to_send;
}
}
static void buspirate_swd_clear_sticky_errors(void)
{
buspirate_swd_write_reg(swd_cmd(false, false, DP_ABORT),
STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
}
static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
{
uint8_t tmp[16];
LOG_DEBUG("buspirate_swd_read_reg");
assert(cmd & SWD_CMD_RnW);
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skip buspirate_swd_read_reg because queued_retval=%d", queued_retval);
return;
}
cmd |= SWD_CMD_START | SWD_CMD_PARK;
uint8_t ack = buspirate_swd_write_header(cmd);
/* do a read transaction */
tmp[0] = 0x06; /* 4 data bytes */
tmp[1] = 0x06;
tmp[2] = 0x06;
tmp[3] = 0x06;
tmp[4] = 0x07; /* parity bit */
tmp[5] = 0x21; /* 2 turnaround clocks */
buspirate_serial_write(buspirate_fd, tmp, 6);
buspirate_serial_read(buspirate_fd, tmp, 6);
/* store the data and parity */
uint32_t data = (uint8_t) tmp[0];
data |= (uint8_t) tmp[1] << 8;
data |= (uint8_t) tmp[2] << 16;
data |= (uint8_t) tmp[3] << 24;
int parity = tmp[4] ? 0x01 : 0x00;
LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
cmd & SWD_CMD_APnDP ? "AP" : "DP",
cmd & SWD_CMD_RnW ? "read" : "write",
(cmd & SWD_CMD_A32) >> 1,
data);
switch (ack) {
case SWD_ACK_OK:
if (parity != parity_u32(data)) {
LOG_DEBUG("Read data parity mismatch %x %x", parity, parity_u32(data));
queued_retval = ERROR_FAIL;
return;
}
if (value)
*value = data;
if (cmd & SWD_CMD_APnDP)
buspirate_swd_idle_clocks(ap_delay_clk);
return;
case SWD_ACK_WAIT:
LOG_DEBUG("SWD_ACK_WAIT");
buspirate_swd_clear_sticky_errors();
return;
case SWD_ACK_FAULT:
LOG_DEBUG("SWD_ACK_FAULT");
queued_retval = ack;
return;
default:
LOG_DEBUG("No valid acknowledge: ack=%d", ack);
queued_retval = ack;
return;
}
}
static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
{
uint8_t tmp[16];
LOG_DEBUG("buspirate_swd_write_reg");
assert(!(cmd & SWD_CMD_RnW));
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skip buspirate_swd_write_reg because queued_retval=%d", queued_retval);
return;
}
cmd |= SWD_CMD_START | SWD_CMD_PARK;
uint8_t ack = buspirate_swd_write_header(cmd);
/* do a write transaction */
tmp[0] = 0x10 + ((4 + 1 - 1) & 0xF); /* bus pirate: send 4+1 bytes */
buf_set_u32((uint8_t *) tmp + 1, 0, 32, value);
/* write sequence ends with parity bit and 7 idle ticks */
tmp[5] = parity_u32(value) ? 0x01 : 0x00;
buspirate_serial_write(buspirate_fd, tmp, 6);
buspirate_serial_read(buspirate_fd, tmp, 6);
LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
cmd & SWD_CMD_APnDP ? "AP" : "DP",
cmd & SWD_CMD_RnW ? "read" : "write",
(cmd & SWD_CMD_A32) >> 1,
value);
switch (ack) {
case SWD_ACK_OK:
if (cmd & SWD_CMD_APnDP)
buspirate_swd_idle_clocks(ap_delay_clk);
return;
case SWD_ACK_WAIT:
LOG_DEBUG("SWD_ACK_WAIT");
buspirate_swd_clear_sticky_errors();
return;
case SWD_ACK_FAULT:
LOG_DEBUG("SWD_ACK_FAULT");
queued_retval = ack;
return;
default:
LOG_DEBUG("No valid acknowledge: ack=%d", ack);
queued_retval = ack;
return;
}
}
static int buspirate_swd_run_queue(void)
{
LOG_DEBUG("buspirate_swd_run_queue");
/* A transaction must be followed by another transaction or at least 8 idle cycles to
* ensure that data is clocked through the AP. */
buspirate_swd_idle_clocks(8);
int retval = queued_retval;
queued_retval = ERROR_OK;
LOG_DEBUG("SWD queue return value: %02x", retval);
return retval;
}
+40 -27
View File
@@ -729,6 +729,20 @@ static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del
cmsis_dap_swd_queue_cmd(cmd, value, 0);
}
static int cmsis_dap_get_serial_info(void)
{
uint8_t *data;
int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data);
if (retval != ERROR_OK)
return retval;
if (data[0]) /* strlen */
LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]);
return ERROR_OK;
}
static int cmsis_dap_get_version_info(void)
{
uint8_t *data;
@@ -802,8 +816,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
/* When we are reconnecting, DAP_Connect needs to be rerun, at
* least on Keil ULINK-ME */
retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ?
CONNECT_SWD : CONNECT_JTAG);
retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD);
if (retval != ERROR_OK)
return retval;
}
@@ -842,17 +855,6 @@ static int cmsis_dap_swd_open(void)
{
int retval;
if (cmsis_dap_handle == NULL) {
/* SWD init */
retval = cmsis_dap_usb_open();
if (retval != ERROR_OK)
return retval;
retval = cmsis_dap_get_caps_info();
if (retval != ERROR_OK)
return retval;
}
if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) {
LOG_ERROR("CMSIS-DAP: SWD not supported");
return ERROR_JTAG_DEVICE_ERROR;
@@ -873,6 +875,22 @@ static int cmsis_dap_init(void)
int retval;
uint8_t *data;
retval = cmsis_dap_usb_open();
if (retval != ERROR_OK)
return retval;
retval = cmsis_dap_get_caps_info();
if (retval != ERROR_OK)
return retval;
retval = cmsis_dap_get_version_info();
if (retval != ERROR_OK)
return retval;
retval = cmsis_dap_get_serial_info();
if (retval != ERROR_OK)
return retval;
if (swd_mode) {
retval = cmsis_dap_swd_open();
if (retval != ERROR_OK)
@@ -880,16 +898,6 @@ static int cmsis_dap_init(void)
}
if (cmsis_dap_handle == NULL) {
/* JTAG init */
retval = cmsis_dap_usb_open();
if (retval != ERROR_OK)
return retval;
retval = cmsis_dap_get_caps_info();
if (retval != ERROR_OK)
return retval;
/* Connect in JTAG mode */
if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) {
LOG_ERROR("CMSIS-DAP: JTAG not supported");
@@ -903,10 +911,6 @@ static int cmsis_dap_init(void)
LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)");
}
retval = cmsis_dap_get_version_info();
if (retval != ERROR_OK)
return retval;
/* INFO_ID_PKT_SZ - short */
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data);
if (retval != ERROR_OK)
@@ -1458,6 +1462,12 @@ static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd)
cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles);
}
static void cmsis_dap_execute_tms(struct jtag_command *cmd)
{
DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits);
cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits);
}
/* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE,
* JTAG_RUNTEST, JTAG_STABLECLOCKS? */
static void cmsis_dap_execute_command(struct jtag_command *cmd)
@@ -1488,6 +1498,8 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd)
cmsis_dap_execute_stableclocks(cmd);
break;
case JTAG_TMS:
cmsis_dap_execute_tms(cmd);
break;
default:
LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type);
exit(-1);
@@ -1650,6 +1662,7 @@ static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL };
struct jtag_interface cmsis_dap_interface = {
.name = "cmsis-dap",
.supported = DEBUG_CAP_TMS_SEQ,
.commands = cmsis_dap_command_handlers,
.swd = &cmsis_dap_swd_driver,
.transports = cmsis_dap_transport,
+669
View File
@@ -0,0 +1,669 @@
/***************************************************************************
* Copyright (C) 2010 Serge Vakulenko *
* serge@vak.ru *
* *
* 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
#if IS_CYGWIN == 1
#include "windows.h"
#undef LOG_ERROR
#endif
/* project specific includes */
#include <jtag/interface.h>
#include <jtag/commands.h>
#include <helper/time_support.h>
#include "libusb1_common.h"
/* system includes */
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
/*
* Bit 7 (0x80, pin 6, RI ): unused.
* Bit 6 (0x40, pin 10,DCD): /SYSRST output.
* Bit 5 (0x20, pin 9, DSR): unused.
* Bit 4 (0x10, pin 2, DTR): /TRST output.
* Bit 3 (0x08, pin 11,CTS): TMS output.
* Bit 2 (0x04, pin 3, RTS): TDO input.
* Bit 1 (0x02, pin 5, RXD): TDI output.
* Bit 0 (0x01, pin 1, TXD): TCK output.
*
* Sync bit bang mode is implemented as described in FTDI Application
* Note AN232R-01: "Bit Bang Modes for the FT232R and FT245R".
*/
#define TCK (1 << 0)
#define TDI (1 << 1)
#define READ_TDO (1 << 2)
#define TMS (1 << 3)
#define NTRST (1 << 4)
#define NSYSRST (1 << 6)
/*
* USB endpoints.
*/
#define IN_EP 0x02
#define OUT_EP 0x81
/* Requests */
#define SIO_RESET 0 /* Reset the port */
#define SIO_MODEM_CTRL 1 /* Set the modem control register */
#define SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define SIO_POLL_MODEM_STATUS 5
#define SIO_SET_EVENT_CHAR 6
#define SIO_SET_ERROR_CHAR 7
#define SIO_SET_LATENCY_TIMER 9
#define SIO_GET_LATENCY_TIMER 10
#define SIO_SET_BITMODE 11
#define SIO_READ_PINS 12
#define SIO_READ_EEPROM 0x90
#define SIO_WRITE_EEPROM 0x91
#define SIO_ERASE_EEPROM 0x92
#define FT232R_BUF_SIZE 4000
static char *ft232r_serial_desc;
static uint16_t ft232r_vid = 0x0403; /* FTDI */
static uint16_t ft232r_pid = 0x6001; /* FT232R */
static jtag_libusb_device_handle *adapter;
static uint8_t *ft232r_output;
static size_t ft232r_output_len;
/**
* Perform sync bitbang output/input transaction.
* Before call, an array ft232r_output[] should be filled with data to send.
* Counter ft232r_output_len contains the number of bytes to send.
* On return, received data is put back to array ft232r_output[].
*/
static int ft232r_send_recv(void)
{
/* FIFO TX buffer has 128 bytes.
* FIFO RX buffer has 256 bytes.
* First two bytes of received packet contain contain modem
* and line status and are ignored.
* Unfortunately, transfer sizes bigger than 64 bytes
* frequently cause hang ups. */
assert(ft232r_output_len > 0);
size_t total_written = 0;
size_t total_read = 0;
int rxfifo_free = 128;
while (total_read < ft232r_output_len) {
/* Write */
int bytes_to_write = ft232r_output_len - total_written;
if (bytes_to_write > 64)
bytes_to_write = 64;
if (bytes_to_write > rxfifo_free)
bytes_to_write = rxfifo_free;
if (bytes_to_write) {
int n = jtag_libusb_bulk_write(adapter, IN_EP,
(char *) ft232r_output + total_written,
bytes_to_write, 1000);
if (n == 0) {
LOG_ERROR("usb bulk write failed");
return ERROR_JTAG_DEVICE_ERROR;
}
total_written += n;
rxfifo_free -= n;
}
/* Read */
uint8_t reply[64];
int n = jtag_libusb_bulk_read(adapter, OUT_EP,
(char *) reply,
sizeof(reply), 1000);
if (n == 0) {
LOG_ERROR("usb bulk read failed");
return ERROR_JTAG_DEVICE_ERROR;
}
if (n > 2) {
/* Copy data, ignoring first 2 bytes. */
memcpy(ft232r_output + total_read, reply + 2, n - 2);
int bytes_read = n - 2;
total_read += bytes_read;
rxfifo_free += bytes_read;
if (total_read > total_written) {
LOG_ERROR("read more bytes than wrote");
return ERROR_JTAG_DEVICE_ERROR;
}
}
}
ft232r_output_len = 0;
return ERROR_OK;
}
/**
* Add one TCK/TMS/TDI sample to send buffer.
*/
static void ft232r_write(int tck, int tms, int tdi)
{
unsigned out_value = NTRST | NSYSRST;
if (tck)
out_value |= TCK;
if (tms)
out_value |= TMS;
if (tdi)
out_value |= TDI;
if (ft232r_output_len >= FT232R_BUF_SIZE) {
/* FIXME: should we just execute queue here? */
LOG_ERROR("ft232r_write: buffer overflow");
return;
}
ft232r_output[ft232r_output_len++] = out_value;
}
/**
* Control /TRST and /SYSRST pins.
* Perform immediate bitbang transaction.
*/
static void ft232r_reset(int trst, int srst)
{
unsigned out_value = NTRST | NSYSRST;
LOG_DEBUG("ft232r_reset(%d,%d)", trst, srst);
if (trst == 1)
out_value &= ~NTRST; /* switch /TRST low */
else if (trst == 0)
out_value |= NTRST; /* switch /TRST high */
if (srst == 1)
out_value &= ~NSYSRST; /* switch /SYSRST low */
else if (srst == 0)
out_value |= NSYSRST; /* switch /SYSRST high */
if (ft232r_output_len >= FT232R_BUF_SIZE) {
/* FIXME: should we just execute queue here? */
LOG_ERROR("ft232r_write: buffer overflow");
return;
}
ft232r_output[ft232r_output_len++] = out_value;
ft232r_send_recv();
}
static int ft232r_speed(int divisor)
{
int baud = (divisor == 0) ? 3000000 :
(divisor == 1) ? 2000000 :
3000000 / divisor;
LOG_DEBUG("ft232r_speed(%d) rate %d bits/sec", divisor, baud);
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BAUD_RATE, divisor, 0, 0, 0, 1000) != 0) {
LOG_ERROR("cannot set baud rate");
return ERROR_JTAG_DEVICE_ERROR;
}
return ERROR_OK;
}
static int ft232r_init(void)
{
uint16_t avids[] = {ft232r_vid, 0};
uint16_t apids[] = {ft232r_pid, 0};
if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter)) {
LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n",
ft232r_vid, ft232r_pid, (ft232r_serial_desc == NULL) ? "[any]" : ft232r_serial_desc);
return ERROR_JTAG_INIT_FAILED;
}
libusb_detach_kernel_driver(adapter, 0);
if (jtag_libusb_claim_interface(adapter, 0)) {
LOG_ERROR("unable to claim interface");
return ERROR_JTAG_INIT_FAILED;
}
/* Reset the device. */
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_RESET, 0, 0, 0, 0, 1000) != 0) {
LOG_ERROR("unable to reset device");
return ERROR_JTAG_INIT_FAILED;
}
/* Sync bit bang mode. */
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BITMODE, TCK | TDI | TMS | NTRST | NSYSRST | 0x400,
0, 0, 0, 1000) != 0) {
LOG_ERROR("cannot set sync bitbang mode");
return ERROR_JTAG_INIT_FAILED;
}
/* Exactly 500 nsec between updates. */
unsigned divisor = 1;
unsigned char latency_timer = 1;
/* Frequency divisor is 14-bit non-zero value. */
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BAUD_RATE, divisor,
0, 0, 0, 1000) != 0) {
LOG_ERROR("cannot set baud rate");
return ERROR_JTAG_INIT_FAILED;
}
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_LATENCY_TIMER, latency_timer, 0, 0, 0, 1000) != 0) {
LOG_ERROR("unable to set latency timer");
return ERROR_JTAG_INIT_FAILED;
}
ft232r_output = malloc(FT232R_BUF_SIZE);
if (ft232r_output == NULL) {
LOG_ERROR("Unable to allocate memory for the buffer");
return ERROR_JTAG_INIT_FAILED;
}
return ERROR_OK;
}
static int ft232r_quit(void)
{
if (jtag_libusb_release_interface(adapter, 0) != 0)
LOG_ERROR("usb release interface failed");
jtag_libusb_close(adapter);
free(ft232r_output);
return ERROR_OK;
}
static int ft232r_speed_div(int divisor, int *khz)
{
/* Maximum 3 Mbaud for bit bang mode. */
if (divisor == 0)
*khz = 3000;
else if (divisor == 1)
*khz = 2000;
else
*khz = 3000 / divisor;
return ERROR_OK;
}
static int ft232r_khz(int khz, int *divisor)
{
if (khz == 0) {
LOG_DEBUG("RCLK not supported");
return ERROR_FAIL;
}
/* Calculate frequency divisor. */
if (khz > 2500)
*divisor = 0; /* Special case: 3 MHz */
else if (khz > 1700)
*divisor = 1; /* Special case: 2 MHz */
else {
*divisor = (2*3000 / khz + 1) / 2;
if (*divisor > 0x3FFF)
*divisor = 0x3FFF;
}
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_serial_desc_command)
{
if (CMD_ARGC == 1)
ft232r_serial_desc = strdup(CMD_ARGV[0]);
else
LOG_ERROR("require exactly one argument to "
"ft232r_serial_desc <serial>");
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_vid_pid_command)
{
if (CMD_ARGC > 2) {
LOG_WARNING("ignoring extra IDs in ft232r_vid_pid "
"(maximum is 1 pair)");
CMD_ARGC = 2;
}
if (CMD_ARGC == 2) {
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_vid);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], ft232r_pid);
} else
LOG_WARNING("incomplete ft232r_vid_pid configuration");
return ERROR_OK;
}
static const struct command_registration ft232r_command_handlers[] = {
{
.name = "ft232r_serial_desc",
.handler = ft232r_handle_serial_desc_command,
.mode = COMMAND_CONFIG,
.help = "USB serial descriptor of the adapter",
.usage = "serial string",
},
{
.name = "ft232r_vid_pid",
.handler = ft232r_handle_vid_pid_command,
.mode = COMMAND_CONFIG,
.help = "USB VID and PID of the adapter",
.usage = "vid pid",
},
COMMAND_REGISTRATION_DONE
};
/*
* Synchronous bitbang protocol implementation.
*/
static void syncbb_end_state(tap_state_t state)
{
if (tap_is_state_stable(state))
tap_set_end_state(state);
else {
LOG_ERROR("BUG: %i is not a valid end state", state);
exit(-1);
}
}
static void syncbb_state_move(int skip)
{
int i = 0, tms = 0;
uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
for (i = skip; i < tms_count; i++) {
tms = (tms_scan >> i) & 1;
ft232r_write(0, tms, 0);
ft232r_write(1, tms, 0);
}
ft232r_write(0, tms, 0);
tap_set_state(tap_get_end_state());
}
/**
* Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG
* (or SWD) state machine.
*/
static int syncbb_execute_tms(struct jtag_command *cmd)
{
unsigned num_bits = cmd->cmd.tms->num_bits;
const uint8_t *bits = cmd->cmd.tms->bits;
DEBUG_JTAG_IO("TMS: %d bits", num_bits);
int tms = 0;
for (unsigned i = 0; i < num_bits; i++) {
tms = ((bits[i/8] >> (i % 8)) & 1);
ft232r_write(0, tms, 0);
ft232r_write(1, tms, 0);
}
ft232r_write(0, tms, 0);
return ERROR_OK;
}
static void syncbb_path_move(struct pathmove_command *cmd)
{
int num_states = cmd->num_states;
int state_count;
int tms = 0;
state_count = 0;
while (num_states) {
if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) {
tms = 0;
} else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) {
tms = 1;
} else {
LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
tap_state_name(tap_get_state()),
tap_state_name(cmd->path[state_count]));
exit(-1);
}
ft232r_write(0, tms, 0);
ft232r_write(1, tms, 0);
tap_set_state(cmd->path[state_count]);
state_count++;
num_states--;
}
ft232r_write(0, tms, 0);
tap_set_end_state(tap_get_state());
}
static void syncbb_runtest(int num_cycles)
{
int i;
tap_state_t saved_end_state = tap_get_end_state();
/* only do a state_move when we're not already in IDLE */
if (tap_get_state() != TAP_IDLE) {
syncbb_end_state(TAP_IDLE);
syncbb_state_move(0);
}
/* execute num_cycles */
for (i = 0; i < num_cycles; i++) {
ft232r_write(0, 0, 0);
ft232r_write(1, 0, 0);
}
ft232r_write(0, 0, 0);
/* finish in end_state */
syncbb_end_state(saved_end_state);
if (tap_get_state() != tap_get_end_state())
syncbb_state_move(0);
}
/**
* Function syncbb_stableclocks
* issues a number of clock cycles while staying in a stable state.
* Because the TMS value required to stay in the RESET state is a 1, whereas
* the TMS value required to stay in any of the other stable states is a 0,
* this function checks the current stable state to decide on the value of TMS
* to use.
*/
static void syncbb_stableclocks(int num_cycles)
{
int tms = (tap_get_state() == TAP_RESET ? 1 : 0);
int i;
/* send num_cycles clocks onto the cable */
for (i = 0; i < num_cycles; i++) {
ft232r_write(1, tms, 0);
ft232r_write(0, tms, 0);
}
}
static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
{
tap_state_t saved_end_state = tap_get_end_state();
int bit_cnt, bit0_index;
if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) {
if (ir_scan)
syncbb_end_state(TAP_IRSHIFT);
else
syncbb_end_state(TAP_DRSHIFT);
syncbb_state_move(0);
syncbb_end_state(saved_end_state);
}
bit0_index = ft232r_output_len;
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) {
int tms = (bit_cnt == scan_size-1) ? 1 : 0;
int tdi;
int bytec = bit_cnt/8;
int bcval = 1 << (bit_cnt % 8);
/* if we're just reading the scan, but don't care about the output
* default to outputting 'low', this also makes valgrind traces more readable,
* as it removes the dependency on an uninitialised value
*/
tdi = 0;
if ((type != SCAN_IN) && (buffer[bytec] & bcval))
tdi = 1;
ft232r_write(0, tms, tdi);
ft232r_write(1, tms, tdi);
}
if (tap_get_state() != tap_get_end_state()) {
/* we *KNOW* the above loop transitioned out of
* the shift state, so we skip the first state
* and move directly to the end state.
*/
syncbb_state_move(1);
}
ft232r_send_recv();
if (type != SCAN_OUT)
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) {
int bytec = bit_cnt/8;
int bcval = 1 << (bit_cnt % 8);
int val = ft232r_output[bit0_index + bit_cnt*2 + 1];
if (val & READ_TDO)
buffer[bytec] |= bcval;
else
buffer[bytec] &= ~bcval;
}
}
static int syncbb_execute_queue(void)
{
struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
int scan_size;
enum scan_type type;
uint8_t *buffer;
int retval;
/* return ERROR_OK, unless a jtag_read_buffer returns a failed check
* that wasn't handled by a caller-provided error handler
*/
retval = ERROR_OK;
/* ft232r_blink(1);*/
while (cmd) {
switch (cmd->type) {
case JTAG_RESET:
LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
if ((cmd->cmd.reset->trst == 1) ||
(cmd->cmd.reset->srst &&
(jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) {
tap_set_state(TAP_RESET);
}
ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
break;
case JTAG_RUNTEST:
LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles,
tap_state_name(cmd->cmd.runtest->end_state));
syncbb_end_state(cmd->cmd.runtest->end_state);
syncbb_runtest(cmd->cmd.runtest->num_cycles);
break;
case JTAG_STABLECLOCKS:
/* this is only allowed while in a stable state. A check for a stable
* state was done in jtag_add_clocks()
*/
syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles);
break;
case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */
LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state));
syncbb_end_state(cmd->cmd.statemove->end_state);
syncbb_state_move(0);
break;
case JTAG_PATHMOVE:
LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states,
tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
syncbb_path_move(cmd->cmd.pathmove);
break;
case JTAG_SCAN:
LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR",
tap_state_name(cmd->cmd.scan->end_state));
syncbb_end_state(cmd->cmd.scan->end_state);
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
type = jtag_scan_type(cmd->cmd.scan);
syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
retval = ERROR_JTAG_QUEUE_FAILED;
if (buffer)
free(buffer);
break;
case JTAG_SLEEP:
LOG_DEBUG_IO("sleep %" PRIi32, cmd->cmd.sleep->us);
jtag_sleep(cmd->cmd.sleep->us);
break;
case JTAG_TMS:
retval = syncbb_execute_tms(cmd);
break;
default:
LOG_ERROR("BUG: unknown JTAG command type encountered");
exit(-1);
}
if (ft232r_output_len > 0)
ft232r_send_recv();
cmd = cmd->next;
}
/* ft232r_blink(0);*/
return retval;
}
struct jtag_interface ft232r_interface = {
.name = "ft232r",
.commands = ft232r_command_handlers,
.transports = jtag_only,
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = syncbb_execute_queue,
.speed = ft232r_speed,
.init = ft232r_init,
.quit = ft232r_quit,
.speed_div = ft232r_speed_div,
.khz = ft232r_khz,
};
+12
View File
@@ -694,6 +694,18 @@ static int ftdi_quit(void)
{
mpsse_close(mpsse_ctx);
struct signal *sig = signals;
while (sig) {
struct signal *next = sig->next;
free((void *)sig->name);
free(sig);
sig = next;
}
free(ftdi_device_desc);
free(ftdi_serial);
free(ftdi_location);
free(swd_cmd_queue);
return ERROR_OK;
+2 -2
View File
@@ -1263,7 +1263,7 @@ static bool check_trace_freq(struct jaylink_swo_speed speed,
return false;
}
static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
int ret;
@@ -1275,7 +1275,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
return ERROR_FAIL;
}
if (pin_protocol != ASYNC_UART) {
if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
LOG_ERROR("Selected pin protocol is not supported.");
return ERROR_FAIL;
}
+6 -9
View File
@@ -204,23 +204,20 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
{
int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8);
uint8_t *xmit_buffer = bits;
int xmit_nb_bits = nb_bits;
int i = 0;
int retval;
while (nb_xfer) {
if (nb_xfer == 1) {
retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], xmit_nb_bits, tap_shift);
retval = jtag_vpi_queue_tdi_xfer(bits, nb_bits, tap_shift);
if (retval != ERROR_OK)
return retval;
} else {
retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
retval = jtag_vpi_queue_tdi_xfer(bits, XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
if (retval != ERROR_OK)
return retval;
xmit_nb_bits -= XFERT_MAX_SIZE * 8;
i += XFERT_MAX_SIZE;
nb_bits -= XFERT_MAX_SIZE * 8;
if (bits)
bits += XFERT_MAX_SIZE;
}
nb_xfer--;
@@ -318,7 +315,7 @@ static int jtag_vpi_runtest(int cycles, tap_state_t state)
if (retval != ERROR_OK)
return retval;
retval = jtag_vpi_queue_tdi(NULL, cycles, NO_TAP_SHIFT);
retval = jtag_vpi_queue_tdi(NULL, cycles, TAP_SHIFT);
if (retval != ERROR_OK)
return retval;
+14 -6
View File
@@ -741,12 +741,22 @@ static int kitprog_swd_run_queue(void)
break;
}
/* We use the maximum buffer size here because the KitProg sometimes
* doesn't like bulk reads of fewer than 62 bytes. (?!?!)
/* KitProg firmware does not send a zero length packet
* after the bulk-in transmission of a length divisible by bulk packet
* size (64 bytes) as required by the USB specification.
* Therefore libusb would wait for continuation of transmission.
* Workaround: Limit bulk read size to expected number of bytes
* for problematic tranfer sizes. Otherwise use the maximum buffer
* size here because the KitProg sometimes doesn't like bulk reads
* of fewer than 62 bytes. (?!?!)
*/
size_t read_count_workaround = SWD_MAX_BUFFER_LENGTH;
if (read_count % 64 == 0)
read_count_workaround = read_count;
ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle,
BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer,
SWD_MAX_BUFFER_LENGTH, 0);
read_count_workaround, 1000);
if (ret > 0) {
/* Handle garbage data by offsetting the initial read index */
if ((unsigned int)ret > read_count)
@@ -878,13 +888,11 @@ COMMAND_HANDLER(kitprog_handle_acquire_psoc_command)
COMMAND_HANDLER(kitprog_handle_serial_command)
{
if (CMD_ARGC == 1) {
size_t len = strlen(CMD_ARGV[0]);
kitprog_serial = calloc(len + 1, sizeof(char));
kitprog_serial = strdup(CMD_ARGV[0]);
if (kitprog_serial == NULL) {
LOG_ERROR("Failed to allocate memory for the serial number");
return ERROR_FAIL;
}
strncpy(kitprog_serial, CMD_ARGV[0], len + 1);
} else {
LOG_ERROR("expected exactly one argument to kitprog_serial <serial-number>");
return ERROR_FAIL;
+7 -1
View File
@@ -335,7 +335,13 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
ctx->write_size = 16384;
ctx->read_chunk = malloc(ctx->read_chunk_size);
ctx->read_buffer = malloc(ctx->read_size);
ctx->write_buffer = malloc(ctx->write_size);
/* Use calloc to make valgrind happy: buffer_write() sets payload
* on bit basis, so some bits can be left uninitialized in write_buffer.
* Although this is perfectly ok with MPSSE, valgrind reports
* Syscall param ioctl(USBDEVFS_SUBMITURB).buffer points to uninitialised byte(s) */
ctx->write_buffer = calloc(1, ctx->write_size);
if (!ctx->read_chunk || !ctx->read_buffer || !ctx->write_buffer)
goto error;
+5 -4
View File
@@ -457,8 +457,8 @@ static int stlink_usb_error_check(void *handle)
LOG_DEBUG("Write error");
return ERROR_FAIL;
case STLINK_JTAG_WRITE_VERIF_ERROR:
LOG_DEBUG("Verify error");
return ERROR_FAIL;
LOG_DEBUG("Write verify error, ignoring");
return ERROR_OK;
case STLINK_SWD_AP_FAULT:
/* git://git.ac6.fr/openocd commit 657e3e885b9ee10
* returns ERROR_OK with the comment:
@@ -2194,12 +2194,13 @@ error_open:
return ERROR_FAIL;
}
int stlink_config_trace(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
struct stlink_usb_handle_s *h = handle;
if (enabled && (h->jtag_api < 2 || pin_protocol != ASYNC_UART)) {
if (enabled && (h->jtag_api < 2 ||
pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
return ERROR_FAIL;
}
+4 -4
View File
@@ -58,11 +58,11 @@
/*
* Helper func to determine if gpio number valid
*
* Assume here that there will be less than 1000 gpios on a system
* Assume here that there will be less than 10000 gpios on a system
*/
static int is_gpio_valid(int gpio)
{
return gpio >= 0 && gpio < 1000;
return gpio >= 0 && gpio < 10000;
}
/*
@@ -89,7 +89,7 @@ static int open_write_close(const char *name, const char *valstr)
*/
static void unexport_sysfs_gpio(int gpio)
{
char gpiostr[4];
char gpiostr[5];
if (!is_gpio_valid(gpio))
return;
@@ -113,7 +113,7 @@ static void unexport_sysfs_gpio(int gpio)
static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
{
char buf[40];
char gpiostr[4];
char gpiostr[5];
int ret;
if (!is_gpio_valid(gpio))
+19 -22
View File
@@ -445,6 +445,7 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
* ublast_tms_seq - write a TMS sequence transition to JTAG
* @bits: TMS bits to be written (bit0, bit1 .. bitN)
* @nb_bits: number of TMS bits (between 1 and 8)
* @skip: number of TMS bits to skip at the beginning of the series
*
* Write a serie of TMS transitions, where each transition consists in :
* - writing out TCK=0, TMS=<new_state>, TDI=<???>
@@ -452,12 +453,12 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes)
* The function ensures that at the end of the sequence, the clock (TCK) is put
* low.
*/
static void ublast_tms_seq(const uint8_t *bits, int nb_bits)
static void ublast_tms_seq(const uint8_t *bits, int nb_bits, int skip)
{
int i;
DEBUG_JTAG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits);
for (i = 0; i < nb_bits; i++)
for (i = skip; i < nb_bits; i++)
ublast_clock_tms((bits[i / 8] >> (i % 8)) & 0x01);
ublast_idle_clock();
}
@@ -469,7 +470,7 @@ static void ublast_tms_seq(const uint8_t *bits, int nb_bits)
static void ublast_tms(struct tms_command *cmd)
{
DEBUG_JTAG_IO("(num_bits=%d)", cmd->num_bits);
ublast_tms_seq(cmd->bits, cmd->num_bits);
ublast_tms_seq(cmd->bits, cmd->num_bits, 0);
}
/**
@@ -501,11 +502,12 @@ static void ublast_path_move(struct pathmove_command *cmd)
/**
* ublast_state_move - move JTAG state to the target state
* @state: the target state
* @skip: number of bits to skip at the beginning of the path
*
* Input the correct TMS sequence to the JTAG TAP so that we end up in the
* target state. This assumes the current state (tap_get_state()) is correct.
*/
static void ublast_state_move(tap_state_t state)
static void ublast_state_move(tap_state_t state, int skip)
{
uint8_t tms_scan;
int tms_len;
@@ -516,7 +518,7 @@ static void ublast_state_move(tap_state_t state)
return;
tms_scan = tap_get_tms_path(tap_get_state(), state);
tms_len = tap_get_tms_path_len(tap_get_state(), state);
ublast_tms_seq(&tms_scan, tms_len);
ublast_tms_seq(&tms_scan, tms_len, skip);
tap_set_state(state);
}
@@ -688,9 +690,9 @@ static void ublast_runtest(int cycles, tap_state_t state)
{
DEBUG_JTAG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state);
ublast_state_move(TAP_IDLE);
ublast_state_move(TAP_IDLE, 0);
ublast_queue_tdi(NULL, cycles, SCAN_OUT);
ublast_state_move(state);
ublast_state_move(state, 0);
}
static void ublast_stableclocks(int cycles)
@@ -720,9 +722,9 @@ static int ublast_scan(struct scan_command *cmd)
scan_bits = jtag_build_buffer(cmd, &buf);
if (cmd->ir_scan)
ublast_state_move(TAP_IRSHIFT);
ublast_state_move(TAP_IRSHIFT, 0);
else
ublast_state_move(TAP_DRSHIFT);
ublast_state_move(TAP_DRSHIFT, 0);
log_buf = hexdump(buf, DIV_ROUND_UP(scan_bits, 8));
DEBUG_JTAG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__,
@@ -733,20 +735,15 @@ static int ublast_scan(struct scan_command *cmd)
ublast_queue_tdi(buf, scan_bits, type);
/*
* As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
* forward to a stable IRPAUSE or DRPAUSE.
*/
ublast_clock_tms(0);
if (cmd->ir_scan)
tap_set_state(TAP_IRPAUSE);
else
tap_set_state(TAP_DRPAUSE);
ret = jtag_read_buffer(buf, cmd);
if (buf)
free(buf);
ublast_state_move(cmd->end_state);
/*
* ublast_queue_tdi sends the last bit with TMS=1. We are therefore
* already in Exit1-DR/IR and have to skip the first step on our way
* to end_state.
*/
ublast_state_move(cmd->end_state, 1);
return ret;
}
@@ -776,7 +773,7 @@ static void ublast_initial_wipeout(void)
/*
* Put JTAG in RESET state (five 1 on TMS)
*/
ublast_tms_seq(&tms_reset, 5);
ublast_tms_seq(&tms_reset, 5, 0);
tap_set_state(TAP_RESET);
}
@@ -805,7 +802,7 @@ static int ublast_execute_queue(void)
ublast_stableclocks(cmd->cmd.stableclocks->num_cycles);
break;
case JTAG_TLR_RESET:
ublast_state_move(cmd->cmd.statemove->end_state);
ublast_state_move(cmd->cmd.statemove->end_state, 0);
break;
case JTAG_PATHMOVE:
ublast_path_move(cmd->cmd.pathmove);
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -119,6 +119,11 @@ static int hl_interface_quit(void)
if (hl_if.layout->api->close)
hl_if.layout->api->close(hl_if.handle);
jtag_command_queue_reset();
free((void *)hl_if.param.device_desc);
free((void *)hl_if.param.serial);
return ERROR_OK;
}
@@ -186,7 +191,7 @@ int hl_interface_override_target(const char **targetname)
return ERROR_FAIL;
}
int hl_interface_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (hl_if.layout->api->config_trace)
+1 -1
View File
@@ -91,7 +91,7 @@ struct hl_layout_api_s {
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
int (*config_trace)(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
* Poll for new trace data
+5 -10
View File
@@ -39,20 +39,15 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi,
return e;
}
unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt;
uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t));
if (new_expected_ids == NULL) {
uint32_t *p = realloc(pTap->expected_ids,
(pTap->expected_ids_cnt + 1) * sizeof(uint32_t));
if (!p) {
Jim_SetResultFormatted(goi->interp, "no memory");
return JIM_ERR;
}
memcpy(new_expected_ids, pTap->expected_ids, expected_len);
new_expected_ids[pTap->expected_ids_cnt] = w;
free(pTap->expected_ids);
pTap->expected_ids = new_expected_ids;
pTap->expected_ids_cnt++;
pTap->expected_ids = p;
pTap->expected_ids[pTap->expected_ids_cnt++] = w;
return JIM_OK;
}
+8
View File
@@ -233,3 +233,11 @@ static void hl_constructor(void)
transport_register(&hl_jtag_transport);
transport_register(&stlink_swim_transport);
}
bool transport_is_hla(void)
{
struct transport *t;
t = get_current_transport();
return t == &hl_swd_transport || t == &hl_jtag_transport
|| t == &stlink_swim_transport;
}
+2 -2
View File
@@ -309,7 +309,7 @@ struct jtag_interface {
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
int (*config_trace)(bool enabled, enum tpio_pin_protocol pin_protocol,
int (*config_trace)(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
@@ -328,7 +328,7 @@ extern const char * const jtag_only[];
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
int adapter_poll_trace(uint8_t *buf, size_t *size);
+12
View File
@@ -60,6 +60,9 @@ extern struct jtag_interface usb_blaster_interface;
#if BUILD_JTAG_VPI == 1
extern struct jtag_interface jtag_vpi_interface;
#endif
#if BUILD_FT232R == 1
extern struct jtag_interface ft232r_interface;
#endif
#if BUILD_AMTJTAGACCEL == 1
extern struct jtag_interface amt_jtagaccel_interface;
#endif
@@ -129,6 +132,9 @@ extern struct jtag_interface kitprog_interface;
#if BUILD_IMX_GPIO == 1
extern struct jtag_interface imx_gpio_interface;
#endif
#if BUILD_XDS110 == 1
extern struct jtag_interface xds110_interface;
#endif
#endif /* standard drivers */
/**
@@ -159,6 +165,9 @@ struct jtag_interface *jtag_interfaces[] = {
#if BUILD_JTAG_VPI == 1
&jtag_vpi_interface,
#endif
#if BUILD_FT232R == 1
&ft232r_interface,
#endif
#if BUILD_AMTJTAGACCEL == 1
&amt_jtagaccel_interface,
#endif
@@ -228,6 +237,9 @@ struct jtag_interface *jtag_interfaces[] = {
#if BUILD_IMX_GPIO == 1
&imx_gpio_interface,
#endif
#if BUILD_XDS110 == 1
&xds110_interface,
#endif
#endif /* standard drivers */
NULL,
};
-4
View File
@@ -153,8 +153,6 @@ struct jtag_tap {
struct jtag_tap_event_action *event_action;
struct jtag_tap *next_tap;
/* dap instance if some null if no instance , initialized to 0 by calloc*/
struct adiv5_dap *dap;
/* private pointer to support none-jtag specific functions */
void *priv;
};
@@ -642,8 +640,6 @@ void jtag_poll_set_enabled(bool value);
* level APIs that are used in inner loops. */
#include <jtag/minidriver.h>
bool transport_is_jtag(void);
int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
#endif /* OPENOCD_JTAG_JTAG_H */
-2
View File
@@ -211,6 +211,4 @@ struct swd_driver {
int swd_init_reset(struct command_context *cmd_ctx);
void swd_add_reset(int req_srst);
bool transport_is_swd(void);
#endif /* OPENOCD_JTAG_SWD_H */

Some files were not shown because too many files have changed in this diff Show More