Merge branch 'master' into from_upstream
Conflicts:
.gitmodules
.travis.yml
jimtcl
src/jtag/core.c
src/jtag/drivers/ftdi.c
src/jtag/drivers/libjaylink
src/jtag/drivers/mpsse.c
src/jtag/drivers/stlink_usb.c
src/rtos/hwthread.c
src/target/riscv/riscv-013.c
src/target/riscv/riscv.c
tcl/board/sifive-hifive1-revb.cfg
Change-Id: I2d26ebeffb4c1374730d2e20e6e2a7710403657c
This commit is contained in:
+24
-7
@@ -263,6 +263,7 @@ int nand_read_status(struct nand_device *nand, uint8_t *status)
|
||||
return ERROR_NAND_DEVICE_NOT_PROBED;
|
||||
|
||||
/* Send read status command */
|
||||
/* FIXME: errors returned from nand->controller are mostly ignored! */
|
||||
nand->controller->command(nand, NAND_CMD_STATUS);
|
||||
|
||||
alive_sleep(1);
|
||||
@@ -301,7 +302,8 @@ static int nand_poll_ready(struct nand_device *nand, int timeout)
|
||||
int nand_probe(struct nand_device *nand)
|
||||
{
|
||||
uint8_t manufacturer_id, device_id;
|
||||
uint8_t id_buff[6];
|
||||
uint8_t id_buff[6] = { 0 }; /* zero buff to silence false warning
|
||||
* from clang static analyzer */
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
@@ -392,19 +394,34 @@ int nand_probe(struct nand_device *nand)
|
||||
if (nand->device->page_size == 0 ||
|
||||
nand->device->erase_size == 0) {
|
||||
if (nand->bus_width == 8) {
|
||||
nand->controller->read_data(nand, id_buff + 3);
|
||||
nand->controller->read_data(nand, id_buff + 4);
|
||||
nand->controller->read_data(nand, id_buff + 5);
|
||||
retval = nand->controller->read_data(nand, id_buff + 3);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = nand->controller->read_data(nand, id_buff + 4);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = nand->controller->read_data(nand, id_buff + 5);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
} else {
|
||||
uint16_t data_buf;
|
||||
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
retval = nand->controller->read_data(nand, &data_buf);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
id_buff[3] = data_buf;
|
||||
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
retval = nand->controller->read_data(nand, &data_buf);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
id_buff[4] = data_buf;
|
||||
|
||||
nand->controller->read_data(nand, &data_buf);
|
||||
retval = nand->controller->read_data(nand, &data_buf);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
id_buff[5] = data_buf >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,7 +730,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
info = calloc(1, sizeof *info);
|
||||
info = calloc(1, sizeof(*info));
|
||||
if (info == NULL)
|
||||
goto fail;
|
||||
|
||||
|
||||
@@ -685,7 +685,6 @@ static int do_data_output(struct nand_device *nand)
|
||||
case 2 << 2:
|
||||
LOG_DEBUG("main area readed with more than 1 (incorrectable) error");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
switch (ecc_status & 0x0003) {
|
||||
case 1:
|
||||
@@ -694,7 +693,6 @@ static int do_data_output(struct nand_device *nand)
|
||||
case 2:
|
||||
LOG_DEBUG("main area readed with more than 1 (incorrectable) error");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -874,7 +874,6 @@ int ecc_status_v1(struct nand_device *nand)
|
||||
case 2 << 2:
|
||||
LOG_INFO("main area read with more than 1 (incorrectable) error");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
switch (ecc_status & 0x0003) {
|
||||
case 1:
|
||||
@@ -883,7 +882,6 @@ int ecc_status_v1(struct nand_device *nand)
|
||||
case 2:
|
||||
LOG_INFO("main area read with more than 1 (incorrectable) error");
|
||||
return ERROR_NAND_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ NOR_DRIVERS = \
|
||||
%D%/psoc4.c \
|
||||
%D%/psoc5lp.c \
|
||||
%D%/psoc6.c \
|
||||
%D%/renesas_rpchf.c \
|
||||
%D%/sh_qspi.c \
|
||||
%D%/sim3x.c \
|
||||
%D%/spi.c \
|
||||
%D%/stmsmi.c \
|
||||
@@ -74,6 +76,7 @@ NOR_DRIVERS = \
|
||||
NORHEADERS = \
|
||||
%D%/core.h \
|
||||
%D%/cc3220sf.h \
|
||||
%D%/bluenrg-x.h \
|
||||
%D%/cc26xx.h \
|
||||
%D%/cfi.h \
|
||||
%D%/driver.h \
|
||||
@@ -81,4 +84,5 @@ NORHEADERS = \
|
||||
%D%/non_cfi.h \
|
||||
%D%/ocl.h \
|
||||
%D%/spi.h \
|
||||
%D%/stm32l4x.h \
|
||||
%D%/msp432.h
|
||||
|
||||
@@ -434,10 +434,8 @@ static int aducm360_write_block(struct flash_bank *bank,
|
||||
switch (choice) {
|
||||
case 0:
|
||||
return aducm360_write_block_sync(bank, buffer, offset, count);
|
||||
break;
|
||||
case 1:
|
||||
return aducm360_write_block_async(bank, buffer, offset, count);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("aducm360_write_block was cancelled (no writing method was chosen)!");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
|
||||
@@ -253,8 +253,7 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank)
|
||||
|
||||
}
|
||||
|
||||
if (ambiqmicro_info->target_class <
|
||||
(sizeof(ambiqmicroParts)/sizeof(ambiqmicroParts[0])))
|
||||
if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicroParts))
|
||||
ambiqmicro_info->target_name =
|
||||
ambiqmicroParts[ambiqmicro_info->target_class].partname;
|
||||
else
|
||||
|
||||
@@ -3068,7 +3068,6 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command)
|
||||
((unsigned int)(FLASH_BANK1_BASE_256K_AX)),
|
||||
((unsigned int)(FLASH_BANK1_BASE_512K_AX)));
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
|
||||
/* at91sam3s and at91sam3n series only has bank 0*/
|
||||
/* at91sam3u and at91sam3ax series has the same address for bank 0*/
|
||||
@@ -3621,10 +3620,8 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command)
|
||||
switch (CMD_ARGC) {
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
case 0:
|
||||
goto showall;
|
||||
break;
|
||||
case 1:
|
||||
who = -1;
|
||||
break;
|
||||
@@ -3653,7 +3650,8 @@ showall:
|
||||
}
|
||||
if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
|
||||
r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
|
||||
command_print(CMD, "sam3-gpnvm%u: %u", who, v);
|
||||
if (r == ERROR_OK)
|
||||
command_print(CMD, "sam3-gpnvm%u: %u", who, v);
|
||||
return r;
|
||||
} else {
|
||||
command_print(CMD, "sam3-gpnvm invalid GPNVM: %u", who);
|
||||
@@ -3707,7 +3705,6 @@ COMMAND_HANDLER(sam3_handle_slowclk_command)
|
||||
/* error */
|
||||
command_print(CMD, "Too many parameters");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
command_print(CMD, "Slowclk freq: %d.%03dkhz",
|
||||
(int)(pChip->cfg.slow_freq / 1000),
|
||||
@@ -3729,7 +3726,7 @@ static const struct command_registration at91sam3_exec_command_handlers[] = {
|
||||
.name = "info",
|
||||
.handler = sam3_handle_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Print information about the current at91sam3 chip"
|
||||
.help = "Print information about the current at91sam3 chip "
|
||||
"and its flash configuration.",
|
||||
.usage = "",
|
||||
},
|
||||
|
||||
@@ -2482,7 +2482,6 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command)
|
||||
((unsigned int)(bank->base)),
|
||||
((unsigned int)(FLASH_BANK_BASE_S)));
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
|
||||
/* at91sam4s series only has bank 0*/
|
||||
/* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/
|
||||
@@ -3101,10 +3100,8 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command)
|
||||
switch (CMD_ARGC) {
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
case 0:
|
||||
goto showall;
|
||||
break;
|
||||
case 1:
|
||||
who = -1;
|
||||
break;
|
||||
@@ -3188,7 +3185,6 @@ COMMAND_HANDLER(sam4_handle_slowclk_command)
|
||||
/* error */
|
||||
command_print(CMD, "Too many parameters");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
command_print(CMD, "Slowclk freq: %d.%03dkhz",
|
||||
(int)(pChip->cfg.slow_freq / 1000),
|
||||
@@ -3210,7 +3206,7 @@ static const struct command_registration at91sam4_exec_command_handlers[] = {
|
||||
.name = "info",
|
||||
.handler = sam4_handle_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Print information about the current at91sam4 chip"
|
||||
.help = "Print information about the current at91sam4 chip "
|
||||
"and its flash configuration.",
|
||||
.usage = "",
|
||||
},
|
||||
|
||||
@@ -601,6 +601,7 @@ static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
|
||||
/* There's at least one aligned page to write out. */
|
||||
if (count >= chip->page_size) {
|
||||
assert(chip->page_size > 0);
|
||||
int np = count / chip->page_size + ((count % chip->page_size) ? 1 : 0);
|
||||
|
||||
for (int i = 0; i < np; i++) {
|
||||
|
||||
@@ -711,8 +711,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
||||
uint16_t page_size;
|
||||
uint16_t num_nvmbits;
|
||||
|
||||
char *target_name_t;
|
||||
|
||||
int bnk, sec;
|
||||
|
||||
at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
|
||||
@@ -753,9 +751,6 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
|
||||
strcpy(target_name_t, CMD_ARGV[7]);
|
||||
|
||||
/* calculate bank size */
|
||||
bank_size = num_sectors * pages_per_sector * page_size;
|
||||
|
||||
@@ -794,7 +789,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
|
||||
|
||||
at91sam7_info = t_bank->driver_priv;
|
||||
|
||||
at91sam7_info->target_name = target_name_t;
|
||||
at91sam7_info->target_name = strdup(CMD_ARGV[7]);
|
||||
at91sam7_info->flashmode = 0;
|
||||
at91sam7_info->ext_freq = ext_freq;
|
||||
at91sam7_info->num_nvmbits = num_nvmbits;
|
||||
|
||||
@@ -181,6 +181,23 @@ static const struct samd_part samd21_parts[] = {
|
||||
{ 0x26, "SAMD21E16B", 64, 8 },
|
||||
{ 0x27, "SAMD21E15B", 32, 4 },
|
||||
|
||||
/* SAMD21 D and L Variants (from Errata)
|
||||
http://ww1.microchip.com/downloads/en/DeviceDoc/
|
||||
SAM-D21-Family-Silicon-Errata-and-DataSheet-Clarification-DS80000760D.pdf */
|
||||
{ 0x55, "SAMD21E16BU", 64, 8 },
|
||||
{ 0x56, "SAMD21E15BU", 32, 4 },
|
||||
{ 0x57, "SAMD21G16L", 64, 8 },
|
||||
{ 0x3E, "SAMD21E16L", 64, 8 },
|
||||
{ 0x3F, "SAMD21E15L", 32, 4 },
|
||||
{ 0x62, "SAMD21E16CU", 64, 8 },
|
||||
{ 0x63, "SAMD21E15CU", 32, 4 },
|
||||
{ 0x92, "SAMD21J17D", 128, 16 },
|
||||
{ 0x93, "SAMD21G17D", 128, 16 },
|
||||
{ 0x94, "SAMD21E17D", 128, 16 },
|
||||
{ 0x95, "SAMD21E17DU", 128, 16 },
|
||||
{ 0x96, "SAMD21G17L", 128, 16 },
|
||||
{ 0x97, "SAMD21E17L", 128, 16 },
|
||||
|
||||
/* Known SAMDA1 parts.
|
||||
SAMD-A1 series uses the same series identifier like the SAMD21
|
||||
taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */
|
||||
|
||||
@@ -375,7 +375,6 @@ static int samv_probe(struct flash_bank *bank)
|
||||
default:
|
||||
LOG_ERROR("unrecognized flash size code: %d", nvm_size_code);
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
struct samv_flash_bank *samv_info = bank->driver_priv;
|
||||
@@ -645,7 +644,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command)
|
||||
switch (CMD_ARGC) {
|
||||
case 0:
|
||||
goto showall;
|
||||
break;
|
||||
case 1:
|
||||
who = -1;
|
||||
break;
|
||||
@@ -660,7 +658,6 @@ COMMAND_HANDLER(samv_handle_gpnvm_command)
|
||||
break;
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t v;
|
||||
|
||||
+27
-15
@@ -58,7 +58,7 @@ struct avrf_type {
|
||||
|
||||
struct avrf_flash_bank {
|
||||
int ppage_size;
|
||||
int probed;
|
||||
bool probed;
|
||||
};
|
||||
|
||||
static const struct avrf_type avft_chips_info[] = {
|
||||
@@ -67,6 +67,7 @@ static const struct avrf_type avft_chips_info[] = {
|
||||
*/
|
||||
{"atmega128", 0x9702, 256, 512, 8, 512},
|
||||
{"atmega128rfa1", 0xa701, 128, 512, 8, 512},
|
||||
{"atmega256rfr2", 0xa802, 256, 1024, 8, 1024},
|
||||
{"at90can128", 0x9781, 256, 512, 8, 512},
|
||||
{"at90usb128", 0x9782, 256, 512, 8, 512},
|
||||
{"atmega164p", 0x940a, 128, 128, 4, 128},
|
||||
@@ -142,16 +143,24 @@ static int avr_jtagprg_chiperase(struct avr_common *avr)
|
||||
}
|
||||
|
||||
static int avr_jtagprg_writeflashpage(struct avr_common *avr,
|
||||
const bool ext_addressing,
|
||||
const uint8_t *page_buf,
|
||||
uint32_t buf_size,
|
||||
uint32_t addr,
|
||||
uint32_t page_size)
|
||||
{
|
||||
uint32_t i, poll_value;
|
||||
uint32_t poll_value;
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
/* load extended high byte */
|
||||
if (ext_addressing)
|
||||
avr_jtag_senddat(avr->jtag_info.tap,
|
||||
NULL,
|
||||
0x0b00 | ((addr >> 17) & 0xFF),
|
||||
AVR_JTAG_REG_ProgrammingCommand_Len);
|
||||
|
||||
/* load addr high byte */
|
||||
avr_jtag_senddat(avr->jtag_info.tap,
|
||||
NULL,
|
||||
@@ -166,7 +175,7 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr,
|
||||
|
||||
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD);
|
||||
|
||||
for (i = 0; i < page_size; i++) {
|
||||
for (uint32_t i = 0; i < page_size; i++) {
|
||||
if (i < buf_size)
|
||||
avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8);
|
||||
else
|
||||
@@ -204,7 +213,7 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
|
||||
avrf_info = malloc(sizeof(struct avrf_flash_bank));
|
||||
bank->driver_priv = avrf_info;
|
||||
|
||||
avrf_info->probed = 0;
|
||||
avrf_info->probed = false;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -238,6 +247,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
|
||||
struct target *target = bank->target;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
uint32_t cur_size, cur_buffer_size, page_size;
|
||||
bool ext_addressing;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
@@ -258,6 +268,11 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
|
||||
if (ERROR_OK != avr_jtagprg_enterprogmode(avr))
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (bank->size > 0x20000)
|
||||
ext_addressing = true;
|
||||
else
|
||||
ext_addressing = false;
|
||||
|
||||
cur_size = 0;
|
||||
while (count > 0) {
|
||||
if (count > page_size)
|
||||
@@ -265,6 +280,7 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
|
||||
else
|
||||
cur_buffer_size = count;
|
||||
avr_jtagprg_writeflashpage(avr,
|
||||
ext_addressing,
|
||||
buffer + cur_size,
|
||||
cur_buffer_size,
|
||||
offset + cur_size,
|
||||
@@ -288,7 +304,6 @@ static int avrf_probe(struct flash_bank *bank)
|
||||
struct avrf_flash_bank *avrf_info = bank->driver_priv;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
const struct avrf_type *avr_info = NULL;
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
@@ -296,7 +311,7 @@ static int avrf_probe(struct flash_bank *bank)
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
avrf_info->probed = 0;
|
||||
avrf_info->probed = false;
|
||||
|
||||
avr_jtag_read_jtagid(avr, &device_id);
|
||||
if (ERROR_OK != mcu_execute_queue())
|
||||
@@ -308,7 +323,7 @@ static int avrf_probe(struct flash_bank *bank)
|
||||
EXTRACT_MFG(device_id),
|
||||
0x1F);
|
||||
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) {
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
|
||||
avr_info = &avft_chips_info[i];
|
||||
LOG_INFO("target device is %s", avr_info->name);
|
||||
@@ -328,20 +343,20 @@ static int avrf_probe(struct flash_bank *bank)
|
||||
bank->num_sectors = avr_info->flash_page_num;
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
|
||||
|
||||
for (i = 0; i < avr_info->flash_page_num; i++) {
|
||||
for (int i = 0; i < avr_info->flash_page_num; i++) {
|
||||
bank->sectors[i].offset = i * avr_info->flash_page_size;
|
||||
bank->sectors[i].size = avr_info->flash_page_size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = -1;
|
||||
}
|
||||
|
||||
avrf_info->probed = 1;
|
||||
avrf_info->probed = true;
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
/* chip not supported */
|
||||
LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id));
|
||||
|
||||
avrf_info->probed = 1;
|
||||
avrf_info->probed = true;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
@@ -359,7 +374,6 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
struct target *target = bank->target;
|
||||
struct avr_common *avr = target->arch_info;
|
||||
const struct avrf_type *avr_info = NULL;
|
||||
int i;
|
||||
uint32_t device_id;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
@@ -377,7 +391,7 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
EXTRACT_MFG(device_id),
|
||||
0x1F);
|
||||
|
||||
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(avft_chips_info); i++) {
|
||||
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) {
|
||||
avr_info = &avft_chips_info[i];
|
||||
LOG_INFO("target device is %s", avr_info->name);
|
||||
@@ -418,8 +432,6 @@ static int avrf_mass_erase(struct flash_bank *bank)
|
||||
|
||||
COMMAND_HANDLER(avrf_handle_mass_erase_command)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (CMD_ARGC < 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
@@ -430,7 +442,7 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command)
|
||||
|
||||
if (avrf_mass_erase(bank) == ERROR_OK) {
|
||||
/* set all sectors as erased */
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
for (int i = 0; i < bank->num_sectors; i++)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
|
||||
command_print(CMD, "avr mass erase complete");
|
||||
|
||||
+209
-303
@@ -24,35 +24,62 @@
|
||||
#include <target/armv7m.h>
|
||||
#include <target/cortex_m.h>
|
||||
#include "imp.h"
|
||||
#include "bluenrg-x.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
|
||||
#define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg)
|
||||
#define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg)
|
||||
|
||||
struct bluenrgx_flash_bank {
|
||||
int probed;
|
||||
uint32_t idcode;
|
||||
uint32_t die_id;
|
||||
#define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg)
|
||||
#define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg)
|
||||
#define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size)
|
||||
|
||||
struct flash_ctrl_priv_data {
|
||||
uint32_t die_id_reg;
|
||||
uint32_t jtag_idcode_reg;
|
||||
uint32_t flash_base;
|
||||
uint32_t flash_regs_base;
|
||||
uint32_t flash_page_size;
|
||||
uint32_t jtag_idcode;
|
||||
char *part_name;
|
||||
};
|
||||
|
||||
static int bluenrgx_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
/* Nothing to do. Protection is only handled in SW. */
|
||||
return ERROR_OK;
|
||||
}
|
||||
const struct flash_ctrl_priv_data flash_priv_data_1 = {
|
||||
.die_id_reg = 0x4090001C,
|
||||
.jtag_idcode_reg = 0x40900028,
|
||||
.flash_base = 0x10040000,
|
||||
.flash_regs_base = 0x40100000,
|
||||
.flash_page_size = 2048,
|
||||
.jtag_idcode = 0x00000000,
|
||||
.part_name = "BLUENRG-1",
|
||||
};
|
||||
|
||||
const struct flash_ctrl_priv_data flash_priv_data_2 = {
|
||||
.die_id_reg = 0x4090001C,
|
||||
.jtag_idcode_reg = 0x40900028,
|
||||
.flash_base = 0x10040000,
|
||||
.flash_regs_base = 0x40100000,
|
||||
.flash_page_size = 2048,
|
||||
.jtag_idcode = 0x0200A041,
|
||||
.part_name = "BLUENRG-2",
|
||||
};
|
||||
|
||||
const struct flash_ctrl_priv_data flash_priv_data_lp = {
|
||||
.die_id_reg = 0x40000000,
|
||||
.jtag_idcode_reg = 0x40000004,
|
||||
.flash_base = 0x10040000,
|
||||
.flash_regs_base = 0x40001000,
|
||||
.flash_page_size = 2048,
|
||||
.jtag_idcode = 0x0201E041,
|
||||
.part_name = "BLUENRG-LP",
|
||||
};
|
||||
|
||||
struct bluenrgx_flash_bank {
|
||||
bool probed;
|
||||
uint32_t die_id;
|
||||
const struct flash_ctrl_priv_data *flash_ptr;
|
||||
};
|
||||
|
||||
const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp};
|
||||
|
||||
/* flash_bank bluenrg-x 0 0 0 0 <target#> */
|
||||
FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
|
||||
@@ -67,9 +94,12 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
bank->write_start_alignment = 16;
|
||||
bank->write_end_alignment = 16;
|
||||
|
||||
bank->driver_priv = bluenrgx_info;
|
||||
|
||||
bluenrgx_info->probed = 0;
|
||||
bluenrgx_info->probed = false;
|
||||
|
||||
if (CMD_ARGC < 6)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -77,6 +107,22 @@ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static inline uint32_t bluenrgx_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
|
||||
{
|
||||
struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
|
||||
return bluenrgx_info->flash_ptr->flash_regs_base + reg_offset;
|
||||
}
|
||||
|
||||
static inline int bluenrgx_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
|
||||
{
|
||||
return target_read_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
|
||||
}
|
||||
|
||||
static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
|
||||
{
|
||||
return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value);
|
||||
}
|
||||
|
||||
static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
@@ -87,7 +133,7 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
|
||||
uint32_t address, command;
|
||||
|
||||
/* check preconditions */
|
||||
if (bluenrgx_info->probed == 0)
|
||||
if (!bluenrgx_info->probed)
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
@@ -103,24 +149,25 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
|
||||
if (mass_erase) {
|
||||
command = FLASH_CMD_MASSERASE;
|
||||
address = bank->base;
|
||||
if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
|
||||
if (bluenrgx_write_flash_reg(bank, 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) {
|
||||
if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
|
||||
(address - bank->base) >> 2) != ERROR_OK) {
|
||||
LOG_ERROR("Register write failed");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
|
||||
if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
|
||||
LOG_ERROR("Register write failed");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
for (unsigned int i = 0; i < 100; i++) {
|
||||
uint32_t value;
|
||||
if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
|
||||
if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
|
||||
LOG_ERROR("Register write failed");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -135,26 +182,28 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
|
||||
} else {
|
||||
command = FLASH_CMD_ERASE_PAGE;
|
||||
for (int i = first; i <= last; i++) {
|
||||
address = bank->base+i*FLASH_PAGE_SIZE;
|
||||
address = bank->base+i*FLASH_PAGE_SIZE(bluenrgx_info);
|
||||
LOG_DEBUG("address = %08x, index = %d", address, i);
|
||||
|
||||
if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) {
|
||||
if (bluenrgx_write_flash_reg(bank, 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) {
|
||||
if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS,
|
||||
(address - bank->base) >> 2) != ERROR_OK) {
|
||||
LOG_ERROR("Register write failed");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) {
|
||||
if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, command) != ERROR_OK) {
|
||||
LOG_ERROR("Failed");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 100; j++) {
|
||||
for (unsigned int j = 0; j < 100; j++) {
|
||||
uint32_t value;
|
||||
if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) {
|
||||
if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) {
|
||||
LOG_ERROR("Register write failed");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -172,140 +221,10 @@ static int bluenrgx_erase(struct flash_bank *bank, int first, int last)
|
||||
|
||||
}
|
||||
|
||||
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, ®_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 bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
uint32_t buffer_size = 16384 + 8;
|
||||
struct working_area *write_algorithm;
|
||||
@@ -313,10 +232,9 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
struct working_area *source;
|
||||
uint32_t address = bank->base + offset;
|
||||
struct reg_param reg_params[5];
|
||||
struct mem_param mem_params[1];
|
||||
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!
|
||||
@@ -325,6 +243,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc"
|
||||
};
|
||||
|
||||
/* check preconditions */
|
||||
if (!bluenrgx_info->probed)
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
if ((offset + count) > bank->size) {
|
||||
LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d",
|
||||
(offset + count),
|
||||
@@ -337,132 +259,105 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Program chunk 16 bytes aligned in fast mode */
|
||||
if (fast_size) {
|
||||
retval = target_write_buffer(target, write_algorithm->address,
|
||||
sizeof(bluenrgx_flash_write_code),
|
||||
bluenrgx_flash_write_code);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
retval = target_write_buffer(target, write_algorithm->address,
|
||||
sizeof(bluenrgx_flash_write_code),
|
||||
bluenrgx_flash_write_code);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
/* Stack pointer area */
|
||||
if (target_alloc_working_area(target, 128,
|
||||
&write_algorithm_sp) != ERROR_OK) {
|
||||
LOG_DEBUG("no working area for write code stack pointer");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[4], "sp", 32, PARAM_OUT);
|
||||
/* Put the parameter at the first available stack location */
|
||||
init_mem_param(&mem_params[0], write_algorithm_sp->address + 80, 32, PARAM_OUT);
|
||||
|
||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
/* 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);
|
||||
/* Number of bytes */
|
||||
buf_set_u32(reg_params[3].value, 0, 32, count);
|
||||
/* Stack pointer for program working area */
|
||||
buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address);
|
||||
/* Flash register base address */
|
||||
buf_set_u32(mem_params[0].value, 0, 32, bluenrgx_info->flash_ptr->flash_regs_base);
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[4], "sp", 32, PARAM_OUT);
|
||||
LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address);
|
||||
LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size);
|
||||
LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address);
|
||||
LOG_DEBUG("address = %08x", address);
|
||||
LOG_DEBUG("count = %08x", count);
|
||||
|
||||
/* 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);
|
||||
retval = target_run_flash_async_algorithm(target,
|
||||
buffer,
|
||||
count/16,
|
||||
16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */
|
||||
1,
|
||||
mem_params,
|
||||
5,
|
||||
reg_params,
|
||||
source->address,
|
||||
source->size,
|
||||
write_algorithm->address,
|
||||
0,
|
||||
&armv7m_info);
|
||||
|
||||
LOG_DEBUG("source->address = " TARGET_ADDR_FMT, source->address);
|
||||
LOG_DEBUG("source->address+ source->size = " TARGET_ADDR_FMT, source->address+source->size);
|
||||
LOG_DEBUG("write_algorithm_sp->address = " TARGET_ADDR_FMT, write_algorithm_sp->address);
|
||||
LOG_DEBUG("address = %08x", address+pre_size);
|
||||
LOG_DEBUG("count = %08x", count);
|
||||
if (retval == ERROR_FLASH_OPERATION_FAILED) {
|
||||
LOG_ERROR("error executing bluenrg-x flash write algorithm");
|
||||
|
||||
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);
|
||||
uint32_t error = buf_get_u32(reg_params[0].value, 0, 32);
|
||||
|
||||
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 (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) {
|
||||
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;
|
||||
}
|
||||
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(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
destroy_reg_param(®_params[4]);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
}
|
||||
target_free_working_area(target, source);
|
||||
target_free_working_area(target, write_algorithm);
|
||||
target_free_working_area(target, write_algorithm_sp);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
destroy_reg_param(®_params[4]);
|
||||
destroy_mem_param(&mem_params[0]);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -470,33 +365,50 @@ 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);
|
||||
int retval = target_read_u32(bank->target, BLUENRGLP_JTAG_REG, &idcode);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = target_read_u32(bank->target, DIE_ID_REG, &die_id);
|
||||
if (idcode != flash_priv_data_lp.jtag_idcode) {
|
||||
retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Default device is BlueNRG-1 */
|
||||
bluenrgx_info->flash_ptr = &flash_priv_data_1;
|
||||
bank->base = flash_priv_data_1.flash_base;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(flash_ctrl); i++) {
|
||||
if (idcode == (*flash_ctrl[i]).jtag_idcode) {
|
||||
bluenrgx_info->flash_ptr = flash_ctrl[i];
|
||||
bank->base = (*flash_ctrl[i]).flash_base;
|
||||
break;
|
||||
}
|
||||
}
|
||||
retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
bank->size = (size_info + 1) * 4;
|
||||
bank->base = FLASH_BASE;
|
||||
bank->num_sectors = bank->size/FLASH_PAGE_SIZE;
|
||||
retval = target_read_u32(bank->target, DIE_ID_REG(bluenrgx_info), &die_id);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
bank->size = (size_info + 1) * FLASH_WORD_LEN;
|
||||
bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info);
|
||||
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;
|
||||
for (int i = 0; i < bank->num_sectors; i++) {
|
||||
bank->sectors[i].offset = i * FLASH_PAGE_SIZE(bluenrgx_info);
|
||||
bank->sectors[i].size = FLASH_PAGE_SIZE(bluenrgx_info);
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
|
||||
bluenrgx_info->probed = 1;
|
||||
bluenrgx_info->probed = true;
|
||||
bluenrgx_info->die_id = die_id;
|
||||
bluenrgx_info->idcode = idcode;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -515,7 +427,6 @@ 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);
|
||||
@@ -526,16 +437,11 @@ static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
}
|
||||
}
|
||||
|
||||
if (bluenrgx_info->idcode == BLUENRG2_IDCODE)
|
||||
part_name = "BLUENRG-2";
|
||||
else
|
||||
part_name = "BLUENRG-1";
|
||||
|
||||
mask_number = (bluenrgx_info->die_id >> 4) & 0xF;
|
||||
cut_number = bluenrgx_info->die_id & 0xF;
|
||||
|
||||
snprintf(buf, buf_size,
|
||||
"%s - Rev: %d.%d", part_name, mask_number, cut_number);
|
||||
"%s - Rev: %d.%d", bluenrgx_info->flash_ptr->part_name, mask_number, cut_number);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -543,12 +449,12 @@ const struct flash_driver bluenrgx_flash = {
|
||||
.name = "bluenrg-x",
|
||||
.flash_bank_command = bluenrgx_flash_bank_command,
|
||||
.erase = bluenrgx_erase,
|
||||
.protect = bluenrgx_protect,
|
||||
.protect = NULL,
|
||||
.write = bluenrgx_write,
|
||||
.read = default_flash_read,
|
||||
.probe = bluenrgx_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = bluenrgx_protect_check,
|
||||
.protect_check = NULL,
|
||||
.auto_probe = bluenrgx_auto_probe,
|
||||
.info = bluenrgx_get_info,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2011 by Mauro Gamba <maurillo71@gmail.com> *
|
||||
* Copyright (C) 2019 by STMicroelectronics. *
|
||||
* *
|
||||
* 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 *
|
||||
@@ -15,13 +15,31 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H
|
||||
#define OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H
|
||||
#ifndef OPENOCD_FLASH_NOR_BLUENRGX_H
|
||||
#define OPENOCD_FLASH_NOR_BLUENRGX_H
|
||||
|
||||
#ifdef HAVE_LIBUSB1
|
||||
#include "libusb1_common.h"
|
||||
#else
|
||||
#include "libusb0_common.h"
|
||||
#endif
|
||||
/* Flash Controller registers offsets */
|
||||
#define FLASH_REG_COMMAND 0x00
|
||||
#define FLASH_REG_CONFIG 0x04
|
||||
#define FLASH_REG_IRQSTAT 0x08
|
||||
#define FLASH_REG_IRQMASK 0x0C
|
||||
#define FLASH_REG_IRQRAW 0x10
|
||||
#define FLASH_REG_ADDRESS 0x18
|
||||
#define FLASH_REG_UNLOCKM 0x1C
|
||||
#define FLASH_REG_UNLOCKL 0x20
|
||||
#define FLASH_REG_DATA0 0x40
|
||||
#define FLASH_REG_DATA1 0x44
|
||||
#define FLASH_REG_DATA2 0x48
|
||||
#define FLASH_REG_DATA3 0x4C
|
||||
#define FLASH_SIZE_REG 0x14
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H */
|
||||
/* Flash Controller commands */
|
||||
#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
|
||||
|
||||
#endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */
|
||||
@@ -363,6 +363,8 @@ static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
LOG_ERROR("cc3220sf: Flash operation failed");
|
||||
break;
|
||||
}
|
||||
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
/* Do one word write for any final bytes less than a full word */
|
||||
|
||||
+169
-184
File diff suppressed because it is too large
Load Diff
@@ -73,6 +73,12 @@ struct cfi_flash_bank {
|
||||
unsigned buf_write_timeout;
|
||||
unsigned block_erase_timeout;
|
||||
unsigned chip_erase_timeout;
|
||||
|
||||
/* memory accessors */
|
||||
int (*write_mem)(struct flash_bank *bank, target_addr_t addr,
|
||||
uint32_t count, const uint8_t *buffer);
|
||||
int (*read_mem)(struct flash_bank *bank, target_addr_t addr,
|
||||
uint32_t count, uint8_t *buffer);
|
||||
};
|
||||
|
||||
/* Intel primary extended query table
|
||||
@@ -148,6 +154,24 @@ struct cfi_fixup {
|
||||
const void *param;
|
||||
};
|
||||
|
||||
int cfi_erase(struct flash_bank *bank, int first, int last);
|
||||
int cfi_protect(struct flash_bank *bank, int set, int first, int last);
|
||||
int cfi_probe(struct flash_bank *bank);
|
||||
int cfi_auto_probe(struct flash_bank *bank);
|
||||
int cfi_protect_check(struct flash_bank *bank);
|
||||
int cfi_get_info(struct flash_bank *bank, char *buf, int buf_size);
|
||||
int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **argv);
|
||||
|
||||
uint32_t cfi_flash_address(struct flash_bank *bank, int sector, uint32_t offset);
|
||||
int cfi_spansion_unlock_seq(struct flash_bank *bank);
|
||||
int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address);
|
||||
int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address);
|
||||
int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout);
|
||||
int cfi_reset(struct flash_bank *bank);
|
||||
|
||||
int cfi_target_read_memory(struct flash_bank *bank, target_addr_t addr,
|
||||
uint32_t count, uint8_t *buffer);
|
||||
|
||||
#define CFI_MFR_AMD 0x0001
|
||||
#define CFI_MFR_FUJITSU 0x0004
|
||||
#define CFI_MFR_ATMEL 0x001F
|
||||
@@ -160,4 +184,7 @@ struct cfi_fixup {
|
||||
#define CFI_MFR_ANY 0xffff
|
||||
#define CFI_ID_ANY 0xffff
|
||||
|
||||
#define CFI_MAX_BUS_WIDTH 4
|
||||
#define CFI_MAX_CHIP_WIDTH 4
|
||||
|
||||
#endif /* OPENOCD_FLASH_NOR_CFI_H */
|
||||
|
||||
@@ -66,6 +66,8 @@ extern const struct flash_driver psoc5lp_flash;
|
||||
extern const struct flash_driver psoc5lp_eeprom_flash;
|
||||
extern const struct flash_driver psoc5lp_nvl_flash;
|
||||
extern const struct flash_driver psoc6_flash;
|
||||
extern const struct flash_driver renesas_rpchf_flash;
|
||||
extern const struct flash_driver sh_qspi_flash;
|
||||
extern const struct flash_driver sim3x_flash;
|
||||
extern const struct flash_driver stellaris_flash;
|
||||
extern const struct flash_driver stm32f1x_flash;
|
||||
@@ -136,6 +138,8 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||
&psoc5lp_eeprom_flash,
|
||||
&psoc5lp_nvl_flash,
|
||||
&psoc6_flash,
|
||||
&renesas_rpchf_flash,
|
||||
&sh_qspi_flash,
|
||||
&sim3x_flash,
|
||||
&stellaris_flash,
|
||||
&stm32f1x_flash,
|
||||
|
||||
@@ -154,7 +154,7 @@ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first,
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t* buffer,
|
||||
static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
+13
-15
@@ -99,7 +99,7 @@ struct efm32_family_data {
|
||||
};
|
||||
|
||||
struct efm32x_flash_bank {
|
||||
int probed;
|
||||
bool probed;
|
||||
uint32_t lb_page[LOCKBITS_PAGE_SZ/4];
|
||||
uint32_t reg_base;
|
||||
uint32_t reg_lock;
|
||||
@@ -140,6 +140,7 @@ static const struct efm32_family_data efm32_families[] = {
|
||||
{ 43, "EFR32BG13P Blue", .series = 1 },
|
||||
{ 44, "EFR32BG13B Blue", .series = 1 },
|
||||
{ 45, "EFR32BG13V Blue", .series = 1 },
|
||||
{ 46, "EFR32ZG13P Zen", .series = 1 },
|
||||
{ 49, "EFR32FG13P Flex", .series = 1 },
|
||||
{ 50, "EFR32FG13B Flex", .series = 1 },
|
||||
{ 51, "EFR32FG13V Flex", .series = 1 },
|
||||
@@ -149,6 +150,7 @@ static const struct efm32_family_data efm32_families[] = {
|
||||
{ 55, "EFR32BG14P Blue", .series = 1 },
|
||||
{ 56, "EFR32BG14B Blue", .series = 1 },
|
||||
{ 57, "EFR32BG14V Blue", .series = 1 },
|
||||
{ 58, "EFR32ZG14P Zen", .series = 1 },
|
||||
{ 61, "EFR32FG14P Flex", .series = 1 },
|
||||
{ 62, "EFR32FG14B Flex", .series = 1 },
|
||||
{ 63, "EFR32FG14V Flex", .series = 1 },
|
||||
@@ -166,7 +168,8 @@ static const struct efm32_family_data efm32_families[] = {
|
||||
{ 89, "EFM32PG13B Pearl", .series = 1 },
|
||||
{ 91, "EFM32JG13B Jade", .series = 1 },
|
||||
{ 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 },
|
||||
{ 103, "EFM32TG11B Tiny", .series = 1 },
|
||||
{ 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 },
|
||||
{ 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 },
|
||||
{ 120, "EZR32WG Wonder", .series = 0 },
|
||||
{ 121, "EZR32LG Leopard", .series = 0 },
|
||||
{ 122, "EZR32HG Happy", .series = 0, .page_size = 1024 },
|
||||
@@ -348,7 +351,7 @@ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command)
|
||||
efm32x_info = malloc(sizeof(struct efm32x_flash_bank));
|
||||
|
||||
bank->driver_priv = efm32x_info;
|
||||
efm32x_info->probed = 0;
|
||||
efm32x_info->probed = false;
|
||||
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -467,7 +470,6 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
|
||||
static int efm32x_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (TARGET_HALTED != target->state) {
|
||||
@@ -482,7 +484,7 @@ static int efm32x_erase(struct flash_bank *bank, int first, int last)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
for (int i = first; i <= last; i++) {
|
||||
ret = efm32x_erase_page(bank, bank->sectors[i].offset);
|
||||
if (ERROR_OK != ret)
|
||||
LOG_ERROR("Failed to erase page %d", i);
|
||||
@@ -498,7 +500,6 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
|
||||
{
|
||||
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
int i = 0;
|
||||
int data_size = 0;
|
||||
uint32_t *ptr = NULL;
|
||||
int ret = 0;
|
||||
@@ -510,7 +511,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
|
||||
|
||||
ptr = efm32x_info->lb_page;
|
||||
|
||||
for (i = 0; i < data_size; i++, ptr++) {
|
||||
for (int i = 0; i < data_size; i++, ptr++) {
|
||||
ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr);
|
||||
if (ERROR_OK != ret) {
|
||||
LOG_ERROR("Failed to read PLW %d", i);
|
||||
@@ -616,7 +617,6 @@ static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set)
|
||||
static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!set) {
|
||||
@@ -629,7 +629,7 @@ static int efm32x_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
for (int i = first; i <= last; i++) {
|
||||
ret = efm32x_set_page_lock(bank, i, set);
|
||||
if (ERROR_OK != ret) {
|
||||
LOG_ERROR("Failed to set lock on page %d", i);
|
||||
@@ -960,11 +960,10 @@ static int efm32x_probe(struct flash_bank *bank)
|
||||
struct efm32x_flash_bank *efm32x_info = bank->driver_priv;
|
||||
struct efm32_info efm32_mcu_info;
|
||||
int ret;
|
||||
int i;
|
||||
uint32_t base_address = 0x00000000;
|
||||
char buf[256];
|
||||
|
||||
efm32x_info->probed = 0;
|
||||
efm32x_info->probed = false;
|
||||
memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ);
|
||||
|
||||
ret = efm32x_read_info(bank, &efm32_mcu_info);
|
||||
@@ -1003,14 +1002,14 @@ static int efm32x_probe(struct flash_bank *bank)
|
||||
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
for (int i = 0; i < num_pages; i++) {
|
||||
bank->sectors[i].offset = i * efm32_mcu_info.page_size;
|
||||
bank->sectors[i].size = efm32_mcu_info.page_size;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 1;
|
||||
}
|
||||
|
||||
efm32x_info->probed = 1;
|
||||
efm32x_info->probed = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1027,7 +1026,6 @@ static int efm32x_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
@@ -1042,7 +1040,7 @@ static int efm32x_protect_check(struct flash_bank *bank)
|
||||
|
||||
assert(NULL != bank->sectors);
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
for (int i = 0; i < bank->num_sectors; i++)
|
||||
bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i);
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
@@ -183,7 +183,7 @@ static int fespi_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_
|
||||
}
|
||||
|
||||
static int fespi_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value)
|
||||
{ \
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct fespi_flash_bank *fespi_info = bank->driver_priv;
|
||||
|
||||
|
||||
+5
-3
@@ -207,7 +207,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
|
||||
uint32_t result;
|
||||
unsigned i;
|
||||
int retval;
|
||||
int retval, retval2 = ERROR_OK;
|
||||
const uint8_t write_block_code[] = {
|
||||
#include "../../../contrib/loaders/flash/fm4/write.inc"
|
||||
};
|
||||
@@ -327,7 +327,7 @@ static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
err_run_ret:
|
||||
err_run:
|
||||
err_write_data:
|
||||
retval = fm4_enter_flash_cpu_rom_mode(target);
|
||||
retval2 = fm4_enter_flash_cpu_rom_mode(target);
|
||||
|
||||
err_flash_mode:
|
||||
for (i = 0; i < ARRAY_SIZE(reg_params); i++)
|
||||
@@ -338,7 +338,9 @@ err_alloc_data:
|
||||
err_write_code:
|
||||
target_free_working_area(target, code_workarea);
|
||||
|
||||
return retval;
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
return retval2;
|
||||
}
|
||||
|
||||
static int mb9bf_probe(struct flash_bank *bank)
|
||||
|
||||
+18
-7
@@ -59,7 +59,7 @@ static void jtagspi_set_ir(struct flash_bank *bank)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
struct scan_field field;
|
||||
uint8_t buf[4];
|
||||
uint8_t buf[4] = { 0 };
|
||||
|
||||
LOG_DEBUG("loading jtagspi ir");
|
||||
buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
|
||||
@@ -153,12 +153,12 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
|
||||
jtagspi_set_ir(bank);
|
||||
/* passing from an IR scan to SHIFT-DR clears BYPASS registers */
|
||||
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
int retval = jtag_execute_queue();
|
||||
|
||||
if (is_read)
|
||||
flip_u8(data_buf, data, lenb);
|
||||
free(data_buf);
|
||||
return ERROR_OK;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int jtagspi_probe(struct flash_bank *bank)
|
||||
@@ -228,13 +228,16 @@ static int jtagspi_probe(struct flash_bank *bank)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
|
||||
static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
|
||||
{
|
||||
uint8_t buf;
|
||||
if (jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8) == ERROR_OK) {
|
||||
int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8);
|
||||
if (err == ERROR_OK) {
|
||||
*status = buf;
|
||||
/* LOG_DEBUG("status=0x%08" PRIx32, *status); */
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
|
||||
@@ -245,7 +248,11 @@ static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
|
||||
|
||||
do {
|
||||
dt = timeval_ms() - t0;
|
||||
jtagspi_read_status(bank, &status);
|
||||
|
||||
int retval = jtagspi_read_status(bank, &status);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if ((status & SPIFLASH_BSY_BIT) == 0) {
|
||||
LOG_DEBUG("waited %" PRId64 " ms", dt);
|
||||
return ERROR_OK;
|
||||
@@ -262,7 +269,11 @@ static int jtagspi_write_enable(struct flash_bank *bank)
|
||||
uint32_t status;
|
||||
|
||||
jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0);
|
||||
jtagspi_read_status(bank, &status);
|
||||
|
||||
int retval = jtagspi_read_status(bank, &status);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if ((status & SPIFLASH_WE_BIT) == 0) {
|
||||
LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
|
||||
return ERROR_FAIL;
|
||||
|
||||
+36
-35
@@ -787,9 +787,8 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
|
||||
|
||||
if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) {
|
||||
uint32_t stats[32];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (unsigned int i = 0; i < 32; i++) {
|
||||
stats[i] = MDM_STAT_FREADY;
|
||||
dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]);
|
||||
}
|
||||
@@ -798,7 +797,7 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
|
||||
LOG_DEBUG("MDM: dap_run failed when validating secured state");
|
||||
return ERROR_OK;
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (unsigned int i = 0; i < 32; i++) {
|
||||
if (stats[i] & MDM_STAT_SYSSEC)
|
||||
secured_score++;
|
||||
if (!(stats[i] & MDM_STAT_FREADY))
|
||||
@@ -860,8 +859,7 @@ static struct kinetis_chip *kinetis_get_chip(struct target *target)
|
||||
|
||||
static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < argc; i++) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-sim-base") == 0) {
|
||||
if (i + 1 < argc)
|
||||
k_chip->sim_base = strtoul(argv[++i], NULL, 0);
|
||||
@@ -933,7 +931,6 @@ static void kinetis_free_driver_priv(struct flash_bank *bank)
|
||||
|
||||
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;
|
||||
@@ -968,7 +965,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
for (bank_idx = 1; bank_idx < num_blocks; bank_idx++) {
|
||||
for (unsigned int bank_idx = 1; bank_idx < num_blocks; bank_idx++) {
|
||||
k_bank = &(k_chip->banks[bank_idx]);
|
||||
bank = k_bank->bank;
|
||||
|
||||
@@ -1219,11 +1216,11 @@ static int kinetis_ftfx_clear_error(struct target *target)
|
||||
|
||||
static int kinetis_ftfx_prepare(struct target *target)
|
||||
{
|
||||
int result, i;
|
||||
int result;
|
||||
uint8_t fstat;
|
||||
|
||||
/* wait until busy */
|
||||
for (i = 0; i < 50; i++) {
|
||||
for (unsigned int i = 0; i < 50; i++) {
|
||||
result = target_read_u8(target, FTFx_FSTAT, &fstat);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
@@ -1343,8 +1340,6 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
||||
|
||||
static int kinetis_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (allow_fcf_writes) {
|
||||
LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!");
|
||||
return ERROR_FAIL;
|
||||
@@ -1355,7 +1350,7 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
for (i = first; i < bank->num_prot_blocks && i <= last; i++)
|
||||
for (int i = first; i < bank->num_prot_blocks && i <= last; i++)
|
||||
bank->prot_blocks[i].is_protected = set;
|
||||
|
||||
LOG_INFO("Protection bits will be written at the next FCF sector erase or write.");
|
||||
@@ -1369,7 +1364,7 @@ static int kinetis_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
struct kinetis_flash_bank *k_bank = bank->driver_priv;
|
||||
int result;
|
||||
int i, b;
|
||||
int b;
|
||||
uint32_t fprot;
|
||||
|
||||
if (k_bank->flash_class == FC_PFLASH) {
|
||||
@@ -1397,7 +1392,7 @@ static int kinetis_protect_check(struct flash_bank *bank)
|
||||
}
|
||||
|
||||
b = k_bank->protection_block;
|
||||
for (i = 0; i < bank->num_prot_blocks; i++) {
|
||||
for (int i = 0; i < bank->num_prot_blocks; i++) {
|
||||
if ((fprot >> b) & 1)
|
||||
bank->prot_blocks[i].is_protected = 0;
|
||||
else
|
||||
@@ -1415,8 +1410,6 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
|
||||
uint32_t fprot = 0xffffffff;
|
||||
uint8_t fsec = 0xfe; /* set MCU unsecure */
|
||||
uint8_t fdprot = 0xff;
|
||||
int i;
|
||||
unsigned bank_idx;
|
||||
unsigned num_blocks;
|
||||
uint32_t pflash_bit;
|
||||
uint8_t dflash_bit;
|
||||
@@ -1432,7 +1425,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
|
||||
/* iterate over all kinetis banks */
|
||||
/* current bank is bank 0, it contains FCF */
|
||||
num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks;
|
||||
for (bank_idx = 0; bank_idx < num_blocks; bank_idx++) {
|
||||
for (unsigned int bank_idx = 0; bank_idx < num_blocks; bank_idx++) {
|
||||
k_bank = &(k_chip->banks[bank_idx]);
|
||||
bank_iter = k_bank->bank;
|
||||
|
||||
@@ -1443,8 +1436,10 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
|
||||
|
||||
kinetis_auto_probe(bank_iter);
|
||||
|
||||
assert(bank_iter->prot_blocks);
|
||||
|
||||
if (k_bank->flash_class == FC_PFLASH) {
|
||||
for (i = 0; i < bank_iter->num_prot_blocks; i++) {
|
||||
for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
|
||||
if (bank_iter->prot_blocks[i].is_protected == 1)
|
||||
fprot &= ~pflash_bit;
|
||||
|
||||
@@ -1452,7 +1447,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
|
||||
}
|
||||
|
||||
} else if (k_bank->flash_class == FC_FLEX_NVM) {
|
||||
for (i = 0; i < bank_iter->num_prot_blocks; i++) {
|
||||
for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
|
||||
if (bank_iter->prot_blocks[i].is_protected == 1)
|
||||
fdprot &= ~dflash_bit;
|
||||
|
||||
@@ -1540,7 +1535,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat)
|
||||
|
||||
static int kinetis_check_run_mode(struct kinetis_chip *k_chip)
|
||||
{
|
||||
int result, i;
|
||||
int result;
|
||||
uint8_t pmstat;
|
||||
struct target *target;
|
||||
|
||||
@@ -1578,7 +1573,7 @@ static int kinetis_check_run_mode(struct kinetis_chip *k_chip)
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
for (i = 100; i; i--) {
|
||||
for (unsigned int i = 100; i > 0; i--) {
|
||||
result = kinetis_read_pmstat(k_chip, &pmstat);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
@@ -1623,7 +1618,7 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip)
|
||||
|
||||
static int kinetis_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
int result, i;
|
||||
int result;
|
||||
struct kinetis_flash_bank *k_bank = bank->driver_priv;
|
||||
struct kinetis_chip *k_chip = k_bank->k_chip;
|
||||
|
||||
@@ -1644,7 +1639,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
|
||||
* requested erase is PFlash or NVM and encompasses the entire
|
||||
* block. Should be quicker.
|
||||
*/
|
||||
for (i = first; i <= last; i++) {
|
||||
for (int i = first; i <= last; i++) {
|
||||
/* set command and sector address */
|
||||
result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, NULL);
|
||||
@@ -1798,6 +1793,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer
|
||||
buffer += size;
|
||||
offset += size;
|
||||
count -= size;
|
||||
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
free(buffer_aligned);
|
||||
@@ -1808,25 +1805,26 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer
|
||||
static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
int result, fallback = 0;
|
||||
int result;
|
||||
bool fallback = false;
|
||||
struct kinetis_flash_bank *k_bank = bank->driver_priv;
|
||||
struct kinetis_chip *k_chip = k_bank->k_chip;
|
||||
|
||||
if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) {
|
||||
/* fallback to longword write */
|
||||
fallback = 1;
|
||||
fallback = true;
|
||||
LOG_INFO("This device supports Program Longword execution only.");
|
||||
} else {
|
||||
result = kinetis_make_ram_ready(bank->target);
|
||||
if (result != ERROR_OK) {
|
||||
fallback = 1;
|
||||
fallback = true;
|
||||
LOG_WARNING("FlexRAM not ready, fallback to slow longword write.");
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("flash write @ " TARGET_ADDR_FMT, bank->base + offset);
|
||||
|
||||
if (fallback == 0) {
|
||||
if (!fallback) {
|
||||
/* program section command */
|
||||
kinetis_write_sections(bank, buffer, offset, count);
|
||||
} else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) {
|
||||
@@ -1889,6 +1887,8 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
|
||||
buffer += 4;
|
||||
offset += 4;
|
||||
words_remaining--;
|
||||
|
||||
keep_alive();
|
||||
}
|
||||
}
|
||||
free(new_buffer);
|
||||
@@ -2018,7 +2018,6 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
|
||||
|
||||
unsigned familyid = 0, subfamid = 0;
|
||||
unsigned cpu_mhz = 120;
|
||||
unsigned idx;
|
||||
bool use_nvm_marking = false;
|
||||
char flash_marking[12], nvm_marking[2];
|
||||
char name[40];
|
||||
@@ -2113,7 +2112,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
|
||||
LOG_ERROR("Unsupported K-family FAMID");
|
||||
}
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) {
|
||||
for (size_t idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) {
|
||||
if (kinetis_types_old[idx].sdid == mcu_type) {
|
||||
strcpy(name, kinetis_types_old[idx].name);
|
||||
use_nvm_marking = true;
|
||||
@@ -2619,12 +2618,15 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
|
||||
|
||||
static int kinetis_probe(struct flash_bank *bank)
|
||||
{
|
||||
int result, i;
|
||||
int result;
|
||||
uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1;
|
||||
unsigned num_blocks, first_nvm_bank;
|
||||
uint32_t size_k;
|
||||
struct kinetis_flash_bank *k_bank = bank->driver_priv;
|
||||
struct kinetis_chip *k_chip = k_bank->k_chip;
|
||||
struct kinetis_chip *k_chip;
|
||||
|
||||
assert(k_bank);
|
||||
k_chip = k_bank->k_chip;
|
||||
|
||||
k_bank->probed = false;
|
||||
|
||||
@@ -2668,6 +2670,7 @@ static int kinetis_probe(struct flash_bank *bank)
|
||||
if (k_chip->dflash_size == 0) {
|
||||
k_bank->protection_size = 0;
|
||||
} else {
|
||||
int i;
|
||||
for (i = k_chip->dflash_size; ~i & 1; i >>= 1)
|
||||
;
|
||||
if (i == 1)
|
||||
@@ -2824,8 +2827,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
|
||||
|
||||
if (block_dirty) {
|
||||
/* the whole bank is not erased, check sector-by-sector */
|
||||
int i;
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
for (int i = 0; i < bank->num_sectors; i++) {
|
||||
/* normal margin */
|
||||
result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT,
|
||||
k_bank->prog_base + bank->sectors[i].offset,
|
||||
@@ -2841,8 +2843,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
|
||||
}
|
||||
} else {
|
||||
/* the whole bank is erased, update all sectors */
|
||||
int i;
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
for (int i = 0; i < bank->num_sectors; i++)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -814,7 +814,7 @@ static int kinetis_ke_protect_check(struct flash_bank *bank)
|
||||
|
||||
kinfo->protection_size = 0;
|
||||
} else {
|
||||
LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i", \
|
||||
LOG_WARNING("Flash protected. FPOPEN=%i FPLDIS=%i FPHDIS=%i FPLS=%i FPHS=%i",
|
||||
fpopen ? 1 : 0, fpldis ? 1 : 0, fphdis ? 1 : 0, fpls, fphs);
|
||||
|
||||
/* Retrieve which region is protected and how much */
|
||||
|
||||
@@ -177,8 +177,8 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
|
||||
retval = target_alloc_working_area(target, sizeof(spifi_init_code)
|
||||
+ SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Insufficient working area to initialize SPIFI "\
|
||||
"module. You must allocate at least %zdB of working "\
|
||||
LOG_ERROR("Insufficient working area to initialize SPIFI "
|
||||
"module. You must allocate at least %zdB of working "
|
||||
"area in order to use this driver.",
|
||||
sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
|
||||
);
|
||||
@@ -452,7 +452,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
|
||||
* it, use a bulk erase instead of going sector-by-sector. */
|
||||
if (first == 0 && last == (bank->num_sectors - 1)
|
||||
&& lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) {
|
||||
LOG_DEBUG("Chip supports the bulk erase command."\
|
||||
LOG_DEBUG("Chip supports the bulk erase command."
|
||||
" Will use bulk erase instead of sector-by-sector erase.");
|
||||
retval = lpcspifi_bulk_erase(bank);
|
||||
|
||||
@@ -525,7 +525,7 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
|
||||
retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code),
|
||||
&erase_algorithm);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Insufficient working area. You must configure a working"\
|
||||
LOG_ERROR("Insufficient working area. You must configure a working"
|
||||
" area of at least %zdB in order to erase SPIFI flash.",
|
||||
sizeof(lpcspifi_flash_erase_code));
|
||||
return retval;
|
||||
@@ -685,7 +685,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
|
||||
if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
|
||||
&write_algorithm) != ERROR_OK) {
|
||||
LOG_ERROR("Insufficient working area. You must configure"\
|
||||
LOG_ERROR("Insufficient working area. You must configure"
|
||||
" a working area > %zdB in order to write to SPIFI flash.",
|
||||
sizeof(lpcspifi_flash_write_code));
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
@@ -707,15 +707,15 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
* space, free the algorithm */
|
||||
target_free_working_area(target, write_algorithm);
|
||||
|
||||
LOG_ERROR("Insufficient working area. Please allocate at least"\
|
||||
LOG_ERROR("Insufficient working area. Please allocate at least"
|
||||
" %zdB of working area to enable flash writes.",
|
||||
sizeof(lpcspifi_flash_write_code) + 1
|
||||
);
|
||||
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
} else if (fifo_size < page_size)
|
||||
LOG_WARNING("Working area size is limited; flash writes may be"\
|
||||
" slow. Increase working area size to at least %zdB"\
|
||||
LOG_WARNING("Working area size is limited; flash writes may be"
|
||||
" slow. Increase working area size to at least %zdB"
|
||||
" to reduce write times.",
|
||||
(size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
|
||||
);
|
||||
|
||||
@@ -563,7 +563,7 @@ static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last)
|
||||
if (first == 0 && last == (bank->num_sectors - 1)
|
||||
&& mrvlqspi_info->dev->chip_erase_cmd !=
|
||||
mrvlqspi_info->dev->erase_cmd) {
|
||||
LOG_DEBUG("Chip supports the bulk erase command."\
|
||||
LOG_DEBUG("Chip supports the bulk erase command."
|
||||
" Will use bulk erase instead of sector-by-sector erase.");
|
||||
retval = mrvlqspi_bulk_erase(bank);
|
||||
if (retval == ERROR_OK) {
|
||||
@@ -681,7 +681,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
|
||||
if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code),
|
||||
&write_algorithm) != ERROR_OK) {
|
||||
LOG_ERROR("Insufficient working area. You must configure"\
|
||||
LOG_ERROR("Insufficient working area. You must configure"
|
||||
" a working area > %zdB in order to write to SPIFI flash.",
|
||||
sizeof(mrvlqspi_flash_write_code));
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
@@ -703,15 +703,15 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
* space, free the algorithm */
|
||||
target_free_working_area(target, write_algorithm);
|
||||
|
||||
LOG_ERROR("Insufficient working area. Please allocate at least"\
|
||||
LOG_ERROR("Insufficient working area. Please allocate at least"
|
||||
" %zdB of working area to enable flash writes.",
|
||||
sizeof(mrvlqspi_flash_write_code) + 1
|
||||
);
|
||||
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
} else if (fifo_size < page_size)
|
||||
LOG_WARNING("Working area size is limited; flash writes may be"\
|
||||
" slow. Increase working area size to at least %zdB"\
|
||||
LOG_WARNING("Working area size is limited; flash writes may be"
|
||||
" slow. Increase working area size to at least %zdB"
|
||||
" to reduce write times.",
|
||||
(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
|
||||
);
|
||||
|
||||
+118
-111
@@ -49,7 +49,8 @@ struct msp432_bank {
|
||||
int family_type;
|
||||
int device_type;
|
||||
uint32_t sector_length;
|
||||
bool probed[2];
|
||||
bool probed_main;
|
||||
bool probed_info;
|
||||
bool unlock_bsl;
|
||||
struct working_area *working_area;
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
@@ -194,8 +195,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params
|
||||
return retval;
|
||||
|
||||
/* Write out command to target memory */
|
||||
retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR,
|
||||
sizeof(command), (uint8_t *)&command);
|
||||
retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -210,8 +210,7 @@ static int msp432_wait_return_code(struct target *target)
|
||||
|
||||
start_ms = timeval_ms();
|
||||
while ((0 == return_code) || (FLASH_BUSY == return_code)) {
|
||||
retval = target_read_buffer(target, ALGO_RETURN_CODE_ADDR,
|
||||
sizeof(return_code), (uint8_t *)&return_code);
|
||||
retval = target_read_u32(target, ALGO_RETURN_CODE_ADDR, &return_code);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
@@ -253,8 +252,7 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer)
|
||||
|
||||
start_ms = timeval_ms();
|
||||
while (BUFFER_INACTIVE != status_code) {
|
||||
retval = target_read_buffer(target, status_addr, sizeof(status_code),
|
||||
(uint8_t *)&status_code);
|
||||
retval = target_read_u32(target, status_addr, &status_code);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
@@ -477,15 +475,23 @@ COMMAND_HANDLER(msp432_mass_erase_command)
|
||||
struct flash_bank *bank;
|
||||
struct msp432_bank *msp432_bank;
|
||||
bool all;
|
||||
|
||||
int retval;
|
||||
|
||||
if (0 == CMD_ARGC) {
|
||||
if (1 > CMD_ARGC)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (1 == CMD_ARGC) {
|
||||
all = false;
|
||||
} else if (1 == CMD_ARGC) {
|
||||
} else if (2 == CMD_ARGC) {
|
||||
/* Check argument for how much to erase */
|
||||
if (0 == strcmp(CMD_ARGV[0], "main"))
|
||||
if (0 == strcmp(CMD_ARGV[1], "main"))
|
||||
all = false;
|
||||
else if (0 == strcmp(CMD_ARGV[0], "all"))
|
||||
else if (0 == strcmp(CMD_ARGV[1], "all"))
|
||||
all = true;
|
||||
else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -493,10 +499,6 @@ COMMAND_HANDLER(msp432_mass_erase_command)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
retval = get_flash_bank_by_num(0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
msp432_bank = bank->driver_priv;
|
||||
|
||||
if (MSP432E4 == msp432_bank->family_type) {
|
||||
@@ -513,7 +515,7 @@ COMMAND_HANDLER(msp432_mass_erase_command)
|
||||
LOG_INFO("msp432: Mass erase of flash is complete");
|
||||
} else {
|
||||
LOG_INFO("msp432: Mass erase of %s is complete",
|
||||
all ? "main + info flash" : "main flash");
|
||||
all ? "main + information flash" : "main flash");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -523,13 +525,14 @@ COMMAND_HANDLER(msp432_bsl_command)
|
||||
{
|
||||
struct flash_bank *bank;
|
||||
struct msp432_bank *msp432_bank;
|
||||
|
||||
int retval;
|
||||
|
||||
if (1 < CMD_ARGC)
|
||||
if (1 > CMD_ARGC)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
retval = get_flash_bank_by_num(0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
msp432_bank = bank->driver_priv;
|
||||
@@ -539,13 +542,16 @@ COMMAND_HANDLER(msp432_bsl_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (1 == CMD_ARGC) {
|
||||
if (0 == strcmp(CMD_ARGV[0], "lock"))
|
||||
if (2 == CMD_ARGC) {
|
||||
if (0 == strcmp(CMD_ARGV[1], "lock"))
|
||||
msp432_bank->unlock_bsl = false;
|
||||
else if (0 == strcmp(CMD_ARGV[0], "unlock"))
|
||||
else if (0 == strcmp(CMD_ARGV[1], "unlock"))
|
||||
msp432_bank->unlock_bsl = true;
|
||||
else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
} else if (1 != CMD_ARGC) {
|
||||
/* Extra, unknown argument passed in */
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
LOG_INFO("msp432: BSL flash region is currently %slocked",
|
||||
@@ -561,6 +567,7 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
|
||||
if (CMD_ARGC < 6)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
/* Create shared private struct for flash banks */
|
||||
msp432_bank = malloc(sizeof(struct msp432_bank));
|
||||
if (NULL == msp432_bank)
|
||||
return ERROR_FAIL;
|
||||
@@ -571,14 +578,14 @@ FLASH_BANK_COMMAND_HANDLER(msp432_flash_bank_command)
|
||||
msp432_bank->family_type = MSP432_NO_FAMILY;
|
||||
msp432_bank->device_type = MSP432_NO_TYPE;
|
||||
msp432_bank->sector_length = 0x1000;
|
||||
msp432_bank->probed[0] = false;
|
||||
msp432_bank->probed[1] = false;
|
||||
msp432_bank->probed_main = false;
|
||||
msp432_bank->probed_info = false;
|
||||
msp432_bank->unlock_bsl = false;
|
||||
msp432_bank->working_area = NULL;
|
||||
|
||||
/* Finish initialization of bank 0 (main flash) */
|
||||
/* Finish up initial settings here */
|
||||
bank->driver_priv = msp432_bank;
|
||||
bank->next = NULL;
|
||||
bank->base = FLASH_BASE;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -589,6 +596,9 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
|
||||
struct msp432_bank *msp432_bank = bank->driver_priv;
|
||||
struct msp432_algo_params algo_params;
|
||||
|
||||
bool is_main = FLASH_BASE == bank->base;
|
||||
bool is_info = P4_FLASH_INFO_BASE == bank->base;
|
||||
|
||||
int retval;
|
||||
|
||||
if (TARGET_HALTED != target->state) {
|
||||
@@ -597,8 +607,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
|
||||
}
|
||||
|
||||
/* Do a mass erase if user requested all sectors of main flash */
|
||||
if ((0 == bank->bank_number) && (first == 0) &&
|
||||
(last == (bank->num_sectors - 1))) {
|
||||
if (is_main && (first == 0) && (last == (bank->num_sectors - 1))) {
|
||||
/* Request mass erase of main flash */
|
||||
return msp432_mass_erase(bank, false);
|
||||
}
|
||||
@@ -611,7 +620,7 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
|
||||
msp432_init_params(&algo_params);
|
||||
|
||||
/* Adjust params if this is the info bank */
|
||||
if (1 == bank->bank_number) {
|
||||
if (is_info) {
|
||||
buf_set_u32(algo_params.erase_param, 0, 32, FLASH_ERASE_INFO);
|
||||
/* And flag if BSL is unlocked */
|
||||
if (msp432_bank->unlock_bsl)
|
||||
@@ -622,11 +631,11 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
|
||||
for (int i = first; i <= last; i++) {
|
||||
|
||||
/* Skip TVL (read-only) sector of the info bank */
|
||||
if (1 == bank->bank_number && 1 == i)
|
||||
if (is_info && 1 == i)
|
||||
continue;
|
||||
|
||||
/* Skip BSL sectors of info bank if locked */
|
||||
if (1 == bank->bank_number && (2 == i || 3 == i) &&
|
||||
if (is_info && (2 == i || 3 == i) &&
|
||||
!msp432_bank->unlock_bsl)
|
||||
continue;
|
||||
|
||||
@@ -666,6 +675,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
long long start_ms;
|
||||
long long elapsed_ms;
|
||||
|
||||
bool is_info = P4_FLASH_INFO_BASE == bank->base;
|
||||
|
||||
int retval;
|
||||
|
||||
if (TARGET_HALTED != target->state) {
|
||||
@@ -679,7 +690,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
* The BSL region in sectors 2 and 3 of the info flash may be unlocked
|
||||
* The helper algorithm will hang on attempts to write to TVL
|
||||
*/
|
||||
if (1 == bank->bank_number) {
|
||||
if (is_info) {
|
||||
/* Set read-only start to TVL sector */
|
||||
uint32_t start = 0x1000;
|
||||
/* Set read-only end after BSL region if locked */
|
||||
@@ -722,7 +733,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
buf_set_u32(algo_params.length, 0, 32, count);
|
||||
|
||||
/* Check if this is the info bank */
|
||||
if (1 == bank->bank_number) {
|
||||
if (is_info) {
|
||||
/* And flag if BSL is unlocked */
|
||||
if (msp432_bank->unlock_bsl)
|
||||
buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL);
|
||||
@@ -753,8 +764,8 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
}
|
||||
|
||||
/* Signal the flash helper algorithm that data is ready to flash */
|
||||
retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR,
|
||||
sizeof(data_ready), (uint8_t *)&data_ready);
|
||||
retval = target_write_u32(target, ALGO_BUFFER1_STATUS_ADDR,
|
||||
data_ready);
|
||||
if (ERROR_OK != retval) {
|
||||
(void)msp432_quit(bank);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
@@ -793,20 +804,23 @@ static int msp432_probe(struct flash_bank *bank)
|
||||
struct target *target = bank->target;
|
||||
struct msp432_bank *msp432_bank = bank->driver_priv;
|
||||
|
||||
char *name;
|
||||
|
||||
uint32_t device_id;
|
||||
uint32_t hardware_rev;
|
||||
|
||||
uint32_t base;
|
||||
uint32_t sector_length;
|
||||
uint32_t size;
|
||||
int num_sectors;
|
||||
int bank_id;
|
||||
|
||||
bool is_main = FLASH_BASE == bank->base;
|
||||
bool is_info = P4_FLASH_INFO_BASE == bank->base;
|
||||
|
||||
int retval;
|
||||
|
||||
bank_id = bank->bank_number;
|
||||
/* Check if this bank has already been successfully probed */
|
||||
if (is_main && msp432_bank->probed_main)
|
||||
return ERROR_OK;
|
||||
if (is_info && msp432_bank->probed_info)
|
||||
return ERROR_OK;
|
||||
|
||||
/* Read the flash size register to determine this is a P4 or not */
|
||||
/* MSP432P4s will return the size of flash. MSP432E4s will return zero */
|
||||
@@ -849,63 +863,16 @@ static int msp432_probe(struct flash_bank *bank)
|
||||
msp432_bank->device_type = msp432_device_type(msp432_bank->family_type,
|
||||
msp432_bank->device_id, msp432_bank->hardware_rev);
|
||||
|
||||
/* If not already allocated, create the info bank for MSP432P4 */
|
||||
/* We could not determine it was needed until device was probed */
|
||||
if (MSP432P4 == msp432_bank->family_type) {
|
||||
/* If we've been given bank 1, then this was already done */
|
||||
if (0 == bank_id) {
|
||||
/* And only allocate it if it doesn't exist yet */
|
||||
if (NULL == bank->next) {
|
||||
struct flash_bank *info_bank;
|
||||
info_bank = malloc(sizeof(struct flash_bank));
|
||||
if (NULL == info_bank)
|
||||
return ERROR_FAIL;
|
||||
|
||||
name = malloc(strlen(bank->name)+1);
|
||||
if (NULL == name) {
|
||||
free(info_bank);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
strcpy(name, bank->name);
|
||||
|
||||
/* Initialize bank 1 (info region) */
|
||||
info_bank->name = name;
|
||||
info_bank->target = bank->target;
|
||||
info_bank->driver = bank->driver;
|
||||
info_bank->driver_priv = bank->driver_priv;
|
||||
info_bank->bank_number = 1;
|
||||
info_bank->base = 0x00200000;
|
||||
info_bank->size = 0;
|
||||
info_bank->chip_width = 0;
|
||||
info_bank->bus_width = 0;
|
||||
info_bank->erased_value = 0xff;
|
||||
info_bank->default_padded_value = 0xff;
|
||||
info_bank->write_start_alignment = 0;
|
||||
info_bank->write_end_alignment = 0;
|
||||
info_bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR;
|
||||
info_bank->num_sectors = 0;
|
||||
info_bank->sectors = NULL;
|
||||
info_bank->num_prot_blocks = 0;
|
||||
info_bank->prot_blocks = NULL;
|
||||
info_bank->next = NULL;
|
||||
|
||||
/* Enable the new bank */
|
||||
bank->next = info_bank;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MSP432P4 == msp432_bank->family_type) {
|
||||
/* Set up MSP432P4 specific flash parameters */
|
||||
if (0 == bank_id) {
|
||||
if (is_main) {
|
||||
retval = target_read_u32(target, P4_FLASH_MAIN_SIZE_REG, &size);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
base = P4_FLASH_MAIN_BASE;
|
||||
sector_length = P4_SECTOR_LENGTH;
|
||||
num_sectors = size / sector_length;
|
||||
} else if (1 == bank_id) {
|
||||
} else if (is_info) {
|
||||
if (msp432_bank->device_type == MSP432P411X ||
|
||||
msp432_bank->device_type == MSP432P411X_GUESS) {
|
||||
/* MSP432P411x has an info size register, use that for size */
|
||||
@@ -916,19 +883,22 @@ static int msp432_probe(struct flash_bank *bank)
|
||||
/* All other MSP432P401x devices have fixed info region size */
|
||||
size = 0x4000; /* 16 KB info region */
|
||||
}
|
||||
base = P4_FLASH_INFO_BASE;
|
||||
sector_length = P4_SECTOR_LENGTH;
|
||||
num_sectors = size / sector_length;
|
||||
} else {
|
||||
/* Invalid bank number somehow */
|
||||
/* Invalid bank somehow */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
/* Set up MSP432E4 specific flash parameters */
|
||||
base = E4_FLASH_BASE;
|
||||
size = E4_FLASH_SIZE;
|
||||
sector_length = E4_SECTOR_LENGTH;
|
||||
num_sectors = size / sector_length;
|
||||
if (is_main) {
|
||||
size = E4_FLASH_SIZE;
|
||||
sector_length = E4_SECTOR_LENGTH;
|
||||
num_sectors = size / sector_length;
|
||||
} else {
|
||||
/* Invalid bank somehow */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != bank->sectors) {
|
||||
@@ -936,11 +906,12 @@ static int msp432_probe(struct flash_bank *bank)
|
||||
bank->sectors = NULL;
|
||||
}
|
||||
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
|
||||
if (NULL == bank->sectors)
|
||||
return ERROR_FAIL;
|
||||
if (num_sectors > 0) {
|
||||
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;
|
||||
@@ -955,7 +926,31 @@ static int msp432_probe(struct flash_bank *bank)
|
||||
}
|
||||
|
||||
/* We've successfully determined the stats on this flash bank */
|
||||
msp432_bank->probed[bank_id] = true;
|
||||
if (is_main)
|
||||
msp432_bank->probed_main = true;
|
||||
if (is_info)
|
||||
msp432_bank->probed_info = true;
|
||||
|
||||
if (is_main && MSP432P4 == msp432_bank->family_type) {
|
||||
/* Create the info flash bank needed by MSP432P4 variants */
|
||||
struct flash_bank *info = calloc(sizeof(struct flash_bank), 1);
|
||||
if (NULL == info)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* Create a name for the info bank, append "_1" to main name */
|
||||
char *name = malloc(strlen(bank->name) + 3);
|
||||
strcpy(name, bank->name);
|
||||
strcat(name, "_1");
|
||||
|
||||
/* Initialize info bank */
|
||||
info->name = name;
|
||||
info->target = bank->target;
|
||||
info->driver = bank->driver;
|
||||
info->driver_priv = msp432_bank;
|
||||
info->base = P4_FLASH_INFO_BASE;
|
||||
|
||||
flash_bank_add(info);
|
||||
}
|
||||
|
||||
/* If we fall through to here, then all went well */
|
||||
|
||||
@@ -966,15 +961,17 @@ static int msp432_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct msp432_bank *msp432_bank = bank->driver_priv;
|
||||
|
||||
bool is_main = FLASH_BASE == bank->base;
|
||||
bool is_info = P4_FLASH_INFO_BASE == bank->base;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (bank->bank_number < 0 || bank->bank_number > 1) {
|
||||
/* Invalid bank number somehow */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!msp432_bank->probed[bank->bank_number])
|
||||
retval = msp432_probe(bank);
|
||||
if (is_main)
|
||||
if (!msp432_bank->probed_main)
|
||||
retval = msp432_probe(bank);
|
||||
if (is_info)
|
||||
if (!msp432_bank->probed_info)
|
||||
retval = msp432_probe(bank);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -1036,12 +1033,21 @@ static int msp432_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int msp432_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
/* Added to suppress warning, not needed for MSP432 flash */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void msp432_flash_free_driver_priv(struct flash_bank *bank)
|
||||
{
|
||||
bool is_main = FLASH_BASE == bank->base;
|
||||
|
||||
/* A single private struct is shared between main and info banks */
|
||||
/* Only free it on the call for main bank (#0) */
|
||||
if ((0 == bank->bank_number) && (NULL != bank->driver_priv))
|
||||
/* Only free it on the call for main bank */
|
||||
if (is_main && (NULL != bank->driver_priv))
|
||||
free(bank->driver_priv);
|
||||
|
||||
/* Forget about the private struct on both main and info banks */
|
||||
bank->driver_priv = NULL;
|
||||
}
|
||||
@@ -1052,14 +1058,14 @@ static const struct command_registration msp432_exec_command_handlers[] = {
|
||||
.handler = msp432_mass_erase_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Erase entire flash memory on device.",
|
||||
.usage = "['main' | 'all']",
|
||||
.usage = "bank_id ['main' | 'all']",
|
||||
},
|
||||
{
|
||||
.name = "bsl",
|
||||
.handler = msp432_bsl_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Allow BSL to be erased or written by flash commands.",
|
||||
.usage = "['unlock' | 'lock']",
|
||||
.usage = "bank_id ['unlock' | 'lock']",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
@@ -1085,6 +1091,7 @@ const struct flash_driver msp432_flash = {
|
||||
.probe = msp432_probe,
|
||||
.auto_probe = msp432_auto_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = msp432_protect_check,
|
||||
.info = msp432_info,
|
||||
.free_driver_priv = msp432_flash_free_driver_priv,
|
||||
};
|
||||
|
||||
@@ -34,14 +34,17 @@
|
||||
#define MSP432E411Y 7 /* MSP432E401Y device */
|
||||
#define MSP432E4X_GUESS 8 /* Assuming it's an MSP432E4x device */
|
||||
|
||||
/* Common MSP432 flash parameters */
|
||||
#define FLASH_BASE 0x00000000
|
||||
|
||||
/* MSP432P4 flash parameters */
|
||||
#define P4_FLASH_MAIN_BASE 0x00000000
|
||||
#define P4_FLASH_MAIN_BASE FLASH_BASE
|
||||
#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_BASE FLASH_BASE
|
||||
#define E4_FLASH_SIZE 0x100000
|
||||
#define E4_SECTOR_LENGTH 0x4000
|
||||
#define E4_ALGO_ENTRY_ADDR 0x20000110
|
||||
|
||||
+562
-359
File diff suppressed because it is too large
Load Diff
+7
-22
@@ -1216,7 +1216,7 @@ static int numicro_init_isp(struct target *target)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t* rdata)
|
||||
static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t addr, uint32_t wdata, uint32_t *rdata)
|
||||
{
|
||||
uint32_t timeout, status;
|
||||
int retval = ERROR_OK;
|
||||
@@ -1548,7 +1548,6 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
uint32_t timeout, status;
|
||||
uint8_t *new_buffer = NULL;
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
@@ -1566,20 +1565,8 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (count & 0x3) {
|
||||
uint32_t old_count = count;
|
||||
count = (old_count | 3) + 1;
|
||||
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("odd number of bytes to write (%d), extending to %d "
|
||||
"and padding with 0xff", old_count, count);
|
||||
memset(new_buffer, 0xff, count);
|
||||
buffer = memcpy(new_buffer, buffer, old_count);
|
||||
}
|
||||
assert(offset % 4 == 0);
|
||||
assert(count % 4 == 0);
|
||||
|
||||
uint32_t words_remaining = count / 4;
|
||||
|
||||
@@ -1597,13 +1584,10 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
|
||||
LOG_DEBUG("write longword @ %08X", offset + i);
|
||||
|
||||
uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff};
|
||||
memcpy(padding, buffer + i, MIN(4, count-i));
|
||||
|
||||
retval = target_write_u32(target, NUMICRO_FLASH_ISPADR, bank->base + offset + i);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, padding);
|
||||
retval = target_write_memory(target, NUMICRO_FLASH_ISPDAT, 4, 1, buffer + i);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = target_write_u32(target, NUMICRO_FLASH_ISPTRG, ISPTRG_ISPGO);
|
||||
@@ -1649,7 +1633,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type** cpu)
|
||||
static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_type **cpu)
|
||||
{
|
||||
uint32_t part_id;
|
||||
int retval = ERROR_OK;
|
||||
@@ -1663,7 +1647,7 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_
|
||||
|
||||
LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id);
|
||||
/* search part numbers */
|
||||
for (size_t i = 0; i < sizeof(NuMicroParts)/sizeof(NuMicroParts[0]); i++) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(NuMicroParts); i++) {
|
||||
if (part_id == NuMicroParts[i].partid) {
|
||||
*cpu = &NuMicroParts[i];
|
||||
LOG_INFO("Device Name: %s", (*cpu)->partname);
|
||||
@@ -1754,6 +1738,7 @@ FLASH_BANK_COMMAND_HANDLER(numicro_flash_bank_command)
|
||||
memset(bank_info, 0, sizeof(struct numicro_flash_bank));
|
||||
|
||||
bank->driver_priv = bank_info;
|
||||
bank->write_start_alignment = bank->write_end_alignment = 4;
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ static const struct row_region safe_sflash_regions[] = {
|
||||
{0x16007C00, 0x400}, /* SFLASH: TOC2 */
|
||||
};
|
||||
|
||||
#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0]))
|
||||
#define SFLASH_NUM_REGIONS ARRAY_SIZE(safe_sflash_regions)
|
||||
|
||||
static struct working_area *g_stack_area;
|
||||
static struct armv7m_algorithm g_armv7m_info;
|
||||
@@ -481,20 +481,15 @@ static const char *protection_to_str(uint8_t protection)
|
||||
switch (protection) {
|
||||
case PROTECTION_VIRGIN:
|
||||
return "VIRGIN";
|
||||
break;
|
||||
case PROTECTION_NORMAL:
|
||||
return "NORMAL";
|
||||
break;
|
||||
case PROTECTION_SECURE:
|
||||
return "SECURE";
|
||||
break;
|
||||
case PROTECTION_DEAD:
|
||||
return "DEAD";
|
||||
break;
|
||||
case PROTECTION_UNKNOWN:
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,648 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Renesas RCar Gen3 RPC Hyperflash driver
|
||||
* Based on U-Boot RPC Hyperflash driver
|
||||
*
|
||||
* Copyright (C) 2016 Renesas Electronics Corporation
|
||||
* Copyright (C) 2016 Cogent Embedded, Inc.
|
||||
* Copyright (C) 2017-2019 Marek Vasut <marek.vasut@gmail.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "cfi.h"
|
||||
#include "non_cfi.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <helper/bits.h>
|
||||
#include <helper/time_support.h>
|
||||
|
||||
#define RPC_CMNCR 0x0000 /* R/W */
|
||||
#define RPC_CMNCR_MD BIT(31)
|
||||
#define RPC_CMNCR_MOIIO0(val) (((val) & 0x3) << 16)
|
||||
#define RPC_CMNCR_MOIIO1(val) (((val) & 0x3) << 18)
|
||||
#define RPC_CMNCR_MOIIO2(val) (((val) & 0x3) << 20)
|
||||
#define RPC_CMNCR_MOIIO3(val) (((val) & 0x3) << 22)
|
||||
#define RPC_CMNCR_MOIIO_HIZ (RPC_CMNCR_MOIIO0(3) | RPC_CMNCR_MOIIO1(3) | \
|
||||
RPC_CMNCR_MOIIO2(3) | RPC_CMNCR_MOIIO3(3))
|
||||
#define RPC_CMNCR_IO0FV(val) (((val) & 0x3) << 8)
|
||||
#define RPC_CMNCR_IO2FV(val) (((val) & 0x3) << 12)
|
||||
#define RPC_CMNCR_IO3FV(val) (((val) & 0x3) << 14)
|
||||
#define RPC_CMNCR_IOFV_HIZ (RPC_CMNCR_IO0FV(3) | RPC_CMNCR_IO2FV(3) | \
|
||||
RPC_CMNCR_IO3FV(3))
|
||||
#define RPC_CMNCR_BSZ(val) (((val) & 0x3) << 0)
|
||||
|
||||
#define RPC_SSLDR 0x0004 /* R/W */
|
||||
#define RPC_SSLDR_SPNDL(d) (((d) & 0x7) << 16)
|
||||
#define RPC_SSLDR_SLNDL(d) (((d) & 0x7) << 8)
|
||||
#define RPC_SSLDR_SCKDL(d) (((d) & 0x7) << 0)
|
||||
|
||||
#define RPC_DRCR 0x000C /* R/W */
|
||||
#define RPC_DRCR_SSLN BIT(24)
|
||||
#define RPC_DRCR_RBURST(v) (((v) & 0x1F) << 16)
|
||||
#define RPC_DRCR_RCF BIT(9)
|
||||
#define RPC_DRCR_RBE BIT(8)
|
||||
#define RPC_DRCR_SSLE BIT(0)
|
||||
|
||||
#define RPC_DRCMR 0x0010 /* R/W */
|
||||
#define RPC_DRCMR_CMD(c) (((c) & 0xFF) << 16)
|
||||
#define RPC_DRCMR_OCMD(c) (((c) & 0xFF) << 0)
|
||||
|
||||
#define RPC_DREAR 0x0014 /* R/W */
|
||||
#define RPC_DREAR_EAV(v) (((v) & 0xFF) << 16)
|
||||
#define RPC_DREAR_EAC(v) (((v) & 0x7) << 0)
|
||||
|
||||
#define RPC_DROPR 0x0018 /* R/W */
|
||||
#define RPC_DROPR_OPD3(o) (((o) & 0xFF) << 24)
|
||||
#define RPC_DROPR_OPD2(o) (((o) & 0xFF) << 16)
|
||||
#define RPC_DROPR_OPD1(o) (((o) & 0xFF) << 8)
|
||||
#define RPC_DROPR_OPD0(o) (((o) & 0xFF) << 0)
|
||||
|
||||
#define RPC_DRENR 0x001C /* R/W */
|
||||
#define RPC_DRENR_CDB(o) (uint32_t)((((o) & 0x3) << 30))
|
||||
#define RPC_DRENR_OCDB(o) (((o) & 0x3) << 28)
|
||||
#define RPC_DRENR_ADB(o) (((o) & 0x3) << 24)
|
||||
#define RPC_DRENR_OPDB(o) (((o) & 0x3) << 20)
|
||||
#define RPC_DRENR_SPIDB(o) (((o) & 0x3) << 16)
|
||||
#define RPC_DRENR_DME BIT(15)
|
||||
#define RPC_DRENR_CDE BIT(14)
|
||||
#define RPC_DRENR_OCDE BIT(12)
|
||||
#define RPC_DRENR_ADE(v) (((v) & 0xF) << 8)
|
||||
#define RPC_DRENR_OPDE(v) (((v) & 0xF) << 4)
|
||||
|
||||
#define RPC_SMCR 0x0020 /* R/W */
|
||||
#define RPC_SMCR_SSLKP BIT(8)
|
||||
#define RPC_SMCR_SPIRE BIT(2)
|
||||
#define RPC_SMCR_SPIWE BIT(1)
|
||||
#define RPC_SMCR_SPIE BIT(0)
|
||||
|
||||
#define RPC_SMCMR 0x0024 /* R/W */
|
||||
#define RPC_SMCMR_CMD(c) (((c) & 0xFF) << 16)
|
||||
#define RPC_SMCMR_OCMD(c) (((c) & 0xFF) << 0)
|
||||
|
||||
#define RPC_SMADR 0x0028 /* R/W */
|
||||
#define RPC_SMOPR 0x002C /* R/W */
|
||||
#define RPC_SMOPR_OPD0(o) (((o) & 0xFF) << 0)
|
||||
#define RPC_SMOPR_OPD1(o) (((o) & 0xFF) << 8)
|
||||
#define RPC_SMOPR_OPD2(o) (((o) & 0xFF) << 16)
|
||||
#define RPC_SMOPR_OPD3(o) (((o) & 0xFF) << 24)
|
||||
|
||||
#define RPC_SMENR 0x0030 /* R/W */
|
||||
#define RPC_SMENR_CDB(o) (((o) & 0x3) << 30)
|
||||
#define RPC_SMENR_OCDB(o) (((o) & 0x3) << 28)
|
||||
#define RPC_SMENR_ADB(o) (((o) & 0x3) << 24)
|
||||
#define RPC_SMENR_OPDB(o) (((o) & 0x3) << 20)
|
||||
#define RPC_SMENR_SPIDB(o) (((o) & 0x3) << 16)
|
||||
#define RPC_SMENR_DME BIT(15)
|
||||
#define RPC_SMENR_CDE BIT(14)
|
||||
#define RPC_SMENR_OCDE BIT(12)
|
||||
#define RPC_SMENR_ADE(v) (((v) & 0xF) << 8)
|
||||
#define RPC_SMENR_OPDE(v) (((v) & 0xF) << 4)
|
||||
#define RPC_SMENR_SPIDE(v) (((v) & 0xF) << 0)
|
||||
|
||||
#define RPC_SMRDR0 0x0038 /* R */
|
||||
#define RPC_SMRDR1 0x003C /* R */
|
||||
#define RPC_SMWDR0 0x0040 /* R/W */
|
||||
#define RPC_SMWDR1 0x0044 /* R/W */
|
||||
#define RPC_CMNSR 0x0048 /* R */
|
||||
#define RPC_CMNSR_SSLF BIT(1)
|
||||
#define RPC_CMNSR_TEND BIT(0)
|
||||
|
||||
#define RPC_DRDMCR 0x0058 /* R/W */
|
||||
#define RPC_DRDMCR_DMCYC(v) (((v) & 0xF) << 0)
|
||||
|
||||
#define RPC_DRDRENR 0x005C /* R/W */
|
||||
#define RPC_DRDRENR_HYPE (0x5 << 12)
|
||||
#define RPC_DRDRENR_ADDRE BIT(8)
|
||||
#define RPC_DRDRENR_OPDRE BIT(4)
|
||||
#define RPC_DRDRENR_DRDRE BIT(0)
|
||||
|
||||
#define RPC_SMDMCR 0x0060 /* R/W */
|
||||
#define RPC_SMDMCR_DMCYC(v) (((v) & 0xF) << 0)
|
||||
|
||||
#define RPC_SMDRENR 0x0064 /* R/W */
|
||||
#define RPC_SMDRENR_HYPE (0x5 << 12)
|
||||
#define RPC_SMDRENR_ADDRE BIT(8)
|
||||
#define RPC_SMDRENR_OPDRE BIT(4)
|
||||
#define RPC_SMDRENR_SPIDRE BIT(0)
|
||||
|
||||
#define RPC_PHYCNT 0x007C /* R/W */
|
||||
#define RPC_PHYCNT_CAL BIT(31)
|
||||
#define PRC_PHYCNT_OCTA_AA BIT(22)
|
||||
#define PRC_PHYCNT_OCTA_SA BIT(23)
|
||||
#define PRC_PHYCNT_EXDS BIT(21)
|
||||
#define RPC_PHYCNT_OCT BIT(20)
|
||||
#define RPC_PHYCNT_WBUF2 BIT(4)
|
||||
#define RPC_PHYCNT_WBUF BIT(2)
|
||||
#define RPC_PHYCNT_MEM(v) (((v) & 0x3) << 0)
|
||||
|
||||
#define RPC_PHYINT 0x0088 /* R/W */
|
||||
#define RPC_PHYINT_RSTEN BIT(18)
|
||||
#define RPC_PHYINT_WPEN BIT(17)
|
||||
#define RPC_PHYINT_INTEN BIT(16)
|
||||
#define RPC_PHYINT_RST BIT(2)
|
||||
#define RPC_PHYINT_WP BIT(1)
|
||||
#define RPC_PHYINT_INT BIT(0)
|
||||
|
||||
#define RPC_WBUF 0x8000 /* R/W size=4/8/16/32/64Bytes */
|
||||
#define RPC_WBUF_SIZE 0x100
|
||||
|
||||
static uint32_t rpc_base = 0xee200000;
|
||||
static uint32_t mem_base = 0x08000000;
|
||||
|
||||
enum rpc_hf_size {
|
||||
RPC_HF_SIZE_16BIT = RPC_SMENR_SPIDE(0x8),
|
||||
RPC_HF_SIZE_32BIT = RPC_SMENR_SPIDE(0xC),
|
||||
RPC_HF_SIZE_64BIT = RPC_SMENR_SPIDE(0xF),
|
||||
};
|
||||
|
||||
static int rpc_hf_wait_tend(struct target *target)
|
||||
{
|
||||
uint32_t reg = rpc_base + RPC_CMNSR;
|
||||
uint32_t val;
|
||||
unsigned long timeout = 1000;
|
||||
long long endtime;
|
||||
int ret;
|
||||
|
||||
endtime = timeval_ms() + timeout;
|
||||
do {
|
||||
ret = target_read_u32(target, reg, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (val & RPC_CMNSR_TEND)
|
||||
return ERROR_OK;
|
||||
|
||||
alive_sleep(1);
|
||||
} while (timeval_ms() < endtime);
|
||||
|
||||
LOG_ERROR("timeout");
|
||||
return ERROR_TIMEOUT_REACHED;
|
||||
}
|
||||
|
||||
static int clrsetbits_u32(struct target *target, uint32_t reg,
|
||||
uint32_t clr, uint32_t set)
|
||||
{
|
||||
uint32_t val;
|
||||
int ret;
|
||||
|
||||
ret = target_read_u32(target, reg, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
|
||||
return target_write_u32(target, reg, val);
|
||||
}
|
||||
|
||||
static int rpc_hf_mode(struct target *target, bool manual)
|
||||
{
|
||||
uint32_t val;
|
||||
int ret;
|
||||
|
||||
ret = rpc_hf_wait_tend(target);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("Mode TEND timeout");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clrsetbits_u32(target, rpc_base + RPC_PHYCNT,
|
||||
RPC_PHYCNT_WBUF | RPC_PHYCNT_WBUF2 |
|
||||
RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3),
|
||||
RPC_PHYCNT_CAL | RPC_PHYCNT_MEM(3));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR,
|
||||
RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
|
||||
RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
|
||||
(manual ? RPC_CMNCR_MD : 0) | RPC_CMNCR_BSZ(1));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
if (manual)
|
||||
return ERROR_OK;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_DRCR,
|
||||
RPC_DRCR_RBURST(0x1F) | RPC_DRCR_RCF |
|
||||
RPC_DRCR_RBE);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_DRCMR,
|
||||
RPC_DRCMR_CMD(0xA0));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
ret = target_write_u32(target, rpc_base + RPC_DRENR,
|
||||
RPC_DRENR_CDB(2) | RPC_DRENR_OCDB(2) |
|
||||
RPC_DRENR_ADB(2) | RPC_DRENR_SPIDB(2) |
|
||||
RPC_DRENR_CDE | RPC_DRENR_OCDE |
|
||||
RPC_DRENR_ADE(4));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_DRDMCR,
|
||||
RPC_DRDMCR_DMCYC(0xE));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_DRDRENR,
|
||||
RPC_DRDRENR_HYPE | RPC_DRDRENR_ADDRE |
|
||||
RPC_DRDRENR_DRDRE);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Dummy read */
|
||||
return target_read_u32(target, rpc_base + RPC_DRCR, &val);
|
||||
}
|
||||
|
||||
static int rpc_hf_xfer(struct target *target, target_addr_t addr,
|
||||
uint32_t wdata, uint32_t *rdata, enum rpc_hf_size size,
|
||||
bool write, const uint8_t *wbuf, unsigned int wbuf_size)
|
||||
{
|
||||
int ret;
|
||||
uint32_t val;
|
||||
|
||||
if (wbuf_size != 0) {
|
||||
ret = rpc_hf_wait_tend(target);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("Xfer TEND timeout");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write calibration magic */
|
||||
ret = target_write_u32(target, rpc_base + RPC_DRCR, 0x01FF0301);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_PHYCNT, 0x80030277);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_memory(target, rpc_base | RPC_WBUF, 4,
|
||||
wbuf_size / 4, wbuf);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = clrsetbits_u32(target, rpc_base + RPC_CMNCR,
|
||||
RPC_CMNCR_MD | RPC_CMNCR_BSZ(3),
|
||||
RPC_CMNCR_MOIIO_HIZ | RPC_CMNCR_IOFV_HIZ |
|
||||
RPC_CMNCR_MD | RPC_CMNCR_BSZ(1));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
} else {
|
||||
ret = rpc_hf_mode(target, 1);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Submit HF address, SMCMR CMD[7] ~= CA Bit# 47 (R/nW) */
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMCMR,
|
||||
write ? 0 : RPC_SMCMR_CMD(0x80));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMADR,
|
||||
addr >> 1);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMOPR, 0x0);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMDRENR,
|
||||
RPC_SMDRENR_HYPE | RPC_SMDRENR_ADDRE |
|
||||
RPC_SMDRENR_SPIDRE);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val = RPC_SMENR_CDB(2) | RPC_SMENR_OCDB(2) |
|
||||
RPC_SMENR_ADB(2) | RPC_SMENR_SPIDB(2) |
|
||||
(wbuf_size ? RPC_SMENR_OPDB(2) : 0) |
|
||||
RPC_SMENR_CDE | RPC_SMENR_OCDE | RPC_SMENR_ADE(4) | size;
|
||||
|
||||
if (write) {
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMENR, val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
if (wbuf_size == 0) {
|
||||
buf_bswap32((uint8_t *)&wdata, (uint8_t *)&wdata, 4);
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMWDR0,
|
||||
wdata);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMCR,
|
||||
RPC_SMCR_SPIWE | RPC_SMCR_SPIE);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
} else {
|
||||
val |= RPC_SMENR_DME;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMDMCR,
|
||||
RPC_SMDMCR_DMCYC(0xE));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMENR, val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, rpc_base + RPC_SMCR,
|
||||
RPC_SMCR_SPIRE | RPC_SMCR_SPIE);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = rpc_hf_wait_tend(target);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
uint32_t val32;
|
||||
ret = target_read_u32(target, rpc_base + RPC_SMRDR0, &val32);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
buf_bswap32((uint8_t *)&val32, (uint8_t *)&val32, 4);
|
||||
*rdata = val32;
|
||||
}
|
||||
|
||||
ret = rpc_hf_mode(target, 0);
|
||||
if (ret != ERROR_OK)
|
||||
LOG_ERROR("Xfer done TEND timeout");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rpchf_target_write_memory(struct flash_bank *bank, target_addr_t addr,
|
||||
uint32_t count, const uint8_t *buffer)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
uint32_t wdata;
|
||||
|
||||
if (count != 2)
|
||||
return ERROR_FAIL;
|
||||
|
||||
wdata = buffer[0] | (buffer[1] << 8);
|
||||
|
||||
return rpc_hf_xfer(target, addr, wdata, NULL, RPC_HF_SIZE_16BIT,
|
||||
true, NULL, 0);
|
||||
}
|
||||
|
||||
static int rpchf_target_read_memory(struct flash_bank *bank, target_addr_t addr,
|
||||
uint32_t count, uint8_t *buffer)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
uint32_t i, rdata;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = rpc_hf_xfer(target, addr + (2 * i), 0, &rdata,
|
||||
RPC_HF_SIZE_16BIT, false, NULL, 0);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
buffer[(2 * i) + 0] = rdata & 0xff;
|
||||
buffer[(2 * i) + 1] = (rdata >> 8) & 0xff;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
FLASH_BANK_COMMAND_HANDLER(rpchf_flash_bank_command)
|
||||
{
|
||||
struct cfi_flash_bank *cfi_info;
|
||||
int ret;
|
||||
|
||||
ret = cfi_flash_bank_cmd(bank, CMD_ARGC, CMD_ARGV);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
cfi_info = bank->driver_priv;
|
||||
cfi_info->read_mem = rpchf_target_read_memory;
|
||||
cfi_info->write_mem = rpchf_target_write_memory;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rpchf_spansion_write_words(struct flash_bank *bank, const uint8_t *word,
|
||||
uint32_t wordcount, uint32_t address)
|
||||
{
|
||||
int retval;
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext;
|
||||
|
||||
/* Calculate buffer size and boundary mask
|
||||
* buffersize is (buffer size per chip) * (number of chips)
|
||||
* bufferwsize is buffersize in words */
|
||||
uint32_t buffersize = RPC_WBUF_SIZE;
|
||||
uint32_t buffermask = buffersize - 1;
|
||||
uint32_t bufferwsize = buffersize / 2;
|
||||
|
||||
/* Check for valid range */
|
||||
if (address & buffermask) {
|
||||
LOG_ERROR("Write address at base " TARGET_ADDR_FMT
|
||||
", address 0x%" PRIx32 " not aligned to 2^%d boundary",
|
||||
bank->base, address, cfi_info->max_buf_write_size);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/* Check for valid size */
|
||||
if (wordcount > bufferwsize) {
|
||||
LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %"
|
||||
PRId32, wordcount, buffersize);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/* Unlock */
|
||||
retval = cfi_spansion_unlock_seq(bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = cfi_send_command(bank, 0xa0, cfi_flash_address(bank, 0, pri_ext->_unlock1));
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = rpc_hf_xfer(bank->target, address, 0, NULL, RPC_HF_SIZE_64BIT, true, word, wordcount * 2);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) {
|
||||
retval = cfi_send_command(bank, 0xf0, cfi_flash_address(bank, 0, 0x0));
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
LOG_ERROR("couldn't write block at base " TARGET_ADDR_FMT
|
||||
", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address,
|
||||
bufferwsize);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rpchf_write_words(struct flash_bank *bank, const uint8_t *word,
|
||||
uint32_t wordcount, uint32_t address)
|
||||
{
|
||||
return rpchf_spansion_write_words(bank, word, wordcount, address);
|
||||
}
|
||||
|
||||
static int rpchf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
uint32_t address = bank->base + offset; /* address of first byte to be programmed */
|
||||
uint32_t write_p;
|
||||
int align; /* number of unaligned bytes */
|
||||
uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being
|
||||
*programmed */
|
||||
int i;
|
||||
int retval;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size)
|
||||
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||
|
||||
if (cfi_info->qry[0] != 'Q')
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
/* start at the first byte of the first word (bus_width size) */
|
||||
write_p = address & ~(bank->bus_width - 1);
|
||||
align = address - write_p;
|
||||
if (align != 0) {
|
||||
LOG_INFO("Fixup %d unaligned head bytes", align);
|
||||
|
||||
/* read a complete word from flash */
|
||||
retval = cfi_target_read_memory(bank, write_p, 1, current_word);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* replace only bytes that must be written */
|
||||
for (i = align;
|
||||
(i < bank->bus_width) && (count > 0);
|
||||
i++, count--)
|
||||
if (cfi_info->data_swap)
|
||||
/* data bytes are swapped (reverse endianness) */
|
||||
current_word[bank->bus_width - i] = *buffer++;
|
||||
else
|
||||
current_word[i] = *buffer++;
|
||||
|
||||
retval = cfi_write_word(bank, current_word, write_p);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
write_p += bank->bus_width;
|
||||
}
|
||||
|
||||
/* Calculate buffer size and boundary mask
|
||||
* buffersize is (buffer size per chip) * (number of chips)
|
||||
* bufferwsize is buffersize in words */
|
||||
uint32_t buffersize = RPC_WBUF_SIZE;
|
||||
uint32_t buffermask = buffersize-1;
|
||||
uint32_t bufferwsize = buffersize / bank->bus_width;
|
||||
|
||||
/* fall back to memory writes */
|
||||
while (count >= (uint32_t)bank->bus_width) {
|
||||
int fallback;
|
||||
if ((write_p & 0xff) == 0) {
|
||||
LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08"
|
||||
PRIx32 " bytes remaining", write_p, count);
|
||||
}
|
||||
fallback = 1;
|
||||
if ((bufferwsize > 0) && (count >= buffersize) &&
|
||||
!(write_p & buffermask)) {
|
||||
retval = rpchf_write_words(bank, buffer, bufferwsize, write_p);
|
||||
if (retval == ERROR_OK) {
|
||||
buffer += buffersize;
|
||||
write_p += buffersize;
|
||||
count -= buffersize;
|
||||
fallback = 0;
|
||||
} else if (retval != ERROR_FLASH_OPER_UNSUPPORTED)
|
||||
return retval;
|
||||
}
|
||||
/* try the slow way? */
|
||||
if (fallback) {
|
||||
for (i = 0; i < bank->bus_width; i++)
|
||||
current_word[i] = *buffer++;
|
||||
|
||||
retval = cfi_write_word(bank, current_word, write_p);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
write_p += bank->bus_width;
|
||||
count -= bank->bus_width;
|
||||
}
|
||||
}
|
||||
|
||||
/* return to read array mode, so we can read from flash again for padding */
|
||||
retval = cfi_reset(bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* handle unaligned tail bytes */
|
||||
if (count > 0) {
|
||||
LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count);
|
||||
|
||||
/* read a complete word from flash */
|
||||
retval = cfi_target_read_memory(bank, write_p, 1, current_word);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* replace only bytes that must be written */
|
||||
for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--)
|
||||
if (cfi_info->data_swap)
|
||||
/* data bytes are swapped (reverse endianness) */
|
||||
current_word[bank->bus_width - i] = *buffer++;
|
||||
else
|
||||
current_word[i] = *buffer++;
|
||||
|
||||
retval = cfi_write_word(bank, current_word, write_p);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* return to read array mode */
|
||||
return cfi_reset(bank);
|
||||
}
|
||||
|
||||
static int rpchf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct cfi_flash_bank *cfi_info = bank->driver_priv;
|
||||
struct target *target = bank->target;
|
||||
|
||||
LOG_DEBUG("reading buffer of %" PRIi32 " byte at 0x%8.8" PRIx32,
|
||||
count, offset);
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size)
|
||||
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||
|
||||
if (cfi_info->qry[0] != 'Q')
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
|
||||
return target_read_memory(target, offset | mem_base,
|
||||
4, count / 4, buffer);
|
||||
}
|
||||
|
||||
const struct flash_driver renesas_rpchf_flash = {
|
||||
.name = "rpchf",
|
||||
.flash_bank_command = rpchf_flash_bank_command,
|
||||
.erase = cfi_erase,
|
||||
.protect = cfi_protect,
|
||||
.write = rpchf_write,
|
||||
.read = rpchf_read,
|
||||
.probe = cfi_probe,
|
||||
.auto_probe = cfi_auto_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = cfi_protect_check,
|
||||
.info = cfi_get_info,
|
||||
.free_driver_priv = default_flash_free_driver_priv,
|
||||
};
|
||||
@@ -0,0 +1,912 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* SH QSPI (Quad SPI) driver
|
||||
* Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
|
||||
*
|
||||
* Based on U-Boot SH QSPI driver
|
||||
* Copyright (C) 2013 Renesas Electronics Corporation
|
||||
* Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "spi.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <helper/bits.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/types.h>
|
||||
#include <jtag/jtag.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/arm.h>
|
||||
#include <target/arm_opcodes.h>
|
||||
#include <target/target.h>
|
||||
|
||||
/* SH QSPI register bit masks <REG>_<BIT> */
|
||||
#define SPCR_MSTR 0x08
|
||||
#define SPCR_SPE 0x40
|
||||
#define SPSR_SPRFF 0x80
|
||||
#define SPSR_SPTEF 0x20
|
||||
#define SPPCR_IO3FV 0x04
|
||||
#define SPPCR_IO2FV 0x02
|
||||
#define SPPCR_IO1FV 0x01
|
||||
#define SPBDCR_RXBC0 BIT(0)
|
||||
#define SPCMD_SCKDEN BIT(15)
|
||||
#define SPCMD_SLNDEN BIT(14)
|
||||
#define SPCMD_SPNDEN BIT(13)
|
||||
#define SPCMD_SSLKP BIT(7)
|
||||
#define SPCMD_BRDV0 BIT(2)
|
||||
#define SPCMD_INIT1 (SPCMD_SCKDEN | SPCMD_SLNDEN | \
|
||||
SPCMD_SPNDEN | SPCMD_SSLKP | \
|
||||
SPCMD_BRDV0)
|
||||
#define SPCMD_INIT2 (SPCMD_SPNDEN | SPCMD_SSLKP | \
|
||||
SPCMD_BRDV0)
|
||||
#define SPBFCR_TXRST BIT(7)
|
||||
#define SPBFCR_RXRST BIT(6)
|
||||
#define SPBFCR_TXTRG 0x30
|
||||
#define SPBFCR_RXTRG 0x07
|
||||
|
||||
/* SH QSPI register set */
|
||||
#define SH_QSPI_SPCR 0x00
|
||||
#define SH_QSPI_SSLP 0x01
|
||||
#define SH_QSPI_SPPCR 0x02
|
||||
#define SH_QSPI_SPSR 0x03
|
||||
#define SH_QSPI_SPDR 0x04
|
||||
#define SH_QSPI_SPSCR 0x08
|
||||
#define SH_QSPI_SPSSR 0x09
|
||||
#define SH_QSPI_SPBR 0x0a
|
||||
#define SH_QSPI_SPDCR 0x0b
|
||||
#define SH_QSPI_SPCKD 0x0c
|
||||
#define SH_QSPI_SSLND 0x0d
|
||||
#define SH_QSPI_SPND 0x0e
|
||||
#define SH_QSPI_DUMMY0 0x0f
|
||||
#define SH_QSPI_SPCMD0 0x10
|
||||
#define SH_QSPI_SPCMD1 0x12
|
||||
#define SH_QSPI_SPCMD2 0x14
|
||||
#define SH_QSPI_SPCMD3 0x16
|
||||
#define SH_QSPI_SPBFCR 0x18
|
||||
#define SH_QSPI_DUMMY1 0x19
|
||||
#define SH_QSPI_SPBDCR 0x1a
|
||||
#define SH_QSPI_SPBMUL0 0x1c
|
||||
#define SH_QSPI_SPBMUL1 0x20
|
||||
#define SH_QSPI_SPBMUL2 0x24
|
||||
#define SH_QSPI_SPBMUL3 0x28
|
||||
|
||||
struct sh_qspi_flash_bank {
|
||||
const struct flash_device *dev;
|
||||
uint32_t io_base;
|
||||
int probed;
|
||||
struct working_area *io_algorithm;
|
||||
struct working_area *source;
|
||||
unsigned int buffer_size;
|
||||
};
|
||||
|
||||
struct sh_qspi_target {
|
||||
char *name;
|
||||
uint32_t tap_idcode;
|
||||
uint32_t io_base;
|
||||
};
|
||||
|
||||
static const struct sh_qspi_target target_devices[] = {
|
||||
/* name, tap_idcode, io_base */
|
||||
{ "SH QSPI", 0x4ba00477, 0xe6b10000 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static int sh_qspi_init(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
/* QSPI initialize */
|
||||
/* Set master mode only */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set SSL signal level */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SSLP, 0x00);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set MOSI signal value when transfer is in idle state */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPPCR,
|
||||
SPPCR_IO3FV | SPPCR_IO2FV);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPBR, 0x01);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Disable Dummy Data Transmission */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPDCR, 0x00);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set clock delay value */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPCKD, 0x00);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set SSL negation delay value */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SSLND, 0x00);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set next-access delay value */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPND, 0x00);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set equence command */
|
||||
ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
|
||||
SPCMD_INIT2);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Reset transfer and receive Buffer */
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val |= SPBFCR_TXRST | SPBFCR_RXRST;
|
||||
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Clear transfer and receive Buffer control bit */
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val &= ~(SPBFCR_TXRST | SPBFCR_RXRST);
|
||||
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set equence control method. Use equence0 only */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Enable SPI function */
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val |= SPCR_SPE;
|
||||
|
||||
return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
|
||||
}
|
||||
|
||||
static int sh_qspi_cs_activate(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
/* Set master mode only */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPCR, SPCR_MSTR);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set command */
|
||||
ret = target_write_u16(target, info->io_base + SH_QSPI_SPCMD0,
|
||||
SPCMD_INIT1);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Reset transfer and receive Buffer */
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val |= SPBFCR_TXRST | SPBFCR_RXRST;
|
||||
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Clear transfer and receive Buffer control bit */
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val &= ~(SPBFCR_TXRST | SPBFCR_RXRST);
|
||||
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR, val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Set equence control method. Use equence0 only */
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPSCR, 0x00);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Enable SPI function */
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val |= SPCR_SPE;
|
||||
|
||||
return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
|
||||
}
|
||||
|
||||
static int sh_qspi_cs_deactivate(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
/* Disable SPI Function */
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPCR, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val &= ~SPCR_SPE;
|
||||
|
||||
return target_write_u8(target, info->io_base + SH_QSPI_SPCR, val);
|
||||
}
|
||||
|
||||
static int sh_qspi_wait_for_bit(struct flash_bank *bank, uint8_t reg,
|
||||
uint32_t mask, bool set,
|
||||
unsigned long timeout)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
long long endtime;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
endtime = timeval_ms() + timeout;
|
||||
do {
|
||||
ret = target_read_u8(target, info->io_base + reg, &val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
if (!set)
|
||||
val = ~val;
|
||||
|
||||
if ((val & mask) == mask)
|
||||
return ERROR_OK;
|
||||
|
||||
alive_sleep(1);
|
||||
} while (timeval_ms() < endtime);
|
||||
|
||||
LOG_ERROR("timeout");
|
||||
return ERROR_TIMEOUT_REACHED;
|
||||
}
|
||||
|
||||
static int sh_qspi_xfer_common(struct flash_bank *bank,
|
||||
const uint8_t *dout, unsigned int outlen,
|
||||
uint8_t *din, unsigned int inlen,
|
||||
bool xfer_start, bool xfer_end)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
uint8_t tdata, rdata;
|
||||
uint8_t val;
|
||||
unsigned int nbyte = outlen + inlen;
|
||||
int ret = 0;
|
||||
|
||||
if (xfer_start) {
|
||||
ret = sh_qspi_cs_activate(bank);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_write_u32(target, info->io_base + SH_QSPI_SPBMUL0,
|
||||
nbyte);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPBFCR,
|
||||
&val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
val &= ~(SPBFCR_TXTRG | SPBFCR_RXTRG);
|
||||
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPBFCR,
|
||||
val);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (nbyte > 0) {
|
||||
ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPTEF,
|
||||
true, 1000);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
tdata = outlen ? *dout++ : 0;
|
||||
ret = target_write_u8(target, info->io_base + SH_QSPI_SPDR,
|
||||
tdata);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = sh_qspi_wait_for_bit(bank, SH_QSPI_SPSR, SPSR_SPRFF,
|
||||
true, 1000);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = target_read_u8(target, info->io_base + SH_QSPI_SPDR,
|
||||
&rdata);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
if (!outlen && inlen) {
|
||||
*din++ = rdata;
|
||||
inlen--;
|
||||
}
|
||||
|
||||
if (outlen)
|
||||
outlen--;
|
||||
|
||||
nbyte--;
|
||||
}
|
||||
|
||||
if (xfer_end)
|
||||
return sh_qspi_cs_deactivate(bank);
|
||||
else
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* Send "write enable" command to SPI flash chip. */
|
||||
static int sh_qspi_write_enable(struct flash_bank *bank)
|
||||
{
|
||||
uint8_t dout = SPIFLASH_WRITE_ENABLE;
|
||||
|
||||
return sh_qspi_xfer_common(bank, &dout, 1, NULL, 0, 1, 1);
|
||||
}
|
||||
|
||||
/* Read the status register of the external SPI flash chip. */
|
||||
static int read_status_reg(struct flash_bank *bank, uint32_t *status)
|
||||
{
|
||||
uint8_t dout = SPIFLASH_READ_STATUS;
|
||||
uint8_t din;
|
||||
int ret;
|
||||
|
||||
ret = sh_qspi_xfer_common(bank, &dout, 1, &din, 1, 1, 1);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
*status = din & 0xff;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* check for WIP (write in progress) bit in status register */
|
||||
/* timeout in ms */
|
||||
static int wait_till_ready(struct flash_bank *bank, int timeout)
|
||||
{
|
||||
long long endtime;
|
||||
uint32_t status;
|
||||
int ret;
|
||||
|
||||
endtime = timeval_ms() + timeout;
|
||||
do {
|
||||
/* read flash status register */
|
||||
ret = read_status_reg(bank, &status);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
if ((status & SPIFLASH_BSY_BIT) == 0)
|
||||
return ERROR_OK;
|
||||
alive_sleep(1);
|
||||
} while (timeval_ms() < endtime);
|
||||
|
||||
LOG_ERROR("timeout");
|
||||
return ERROR_TIMEOUT_REACHED;
|
||||
}
|
||||
|
||||
static int sh_qspi_erase_sector(struct flash_bank *bank, int sector)
|
||||
{
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
bool addr4b = info->dev->size_in_bytes > (1UL << 24);
|
||||
uint32_t address = (sector * info->dev->sectorsize) <<
|
||||
(addr4b ? 0 : 8);
|
||||
uint8_t dout[5] = {
|
||||
info->dev->erase_cmd,
|
||||
(address >> 24) & 0xff, (address >> 16) & 0xff,
|
||||
(address >> 8) & 0xff, (address >> 0) & 0xff
|
||||
};
|
||||
unsigned int doutlen = addr4b ? 5 : 4;
|
||||
int ret;
|
||||
|
||||
/* Write Enable */
|
||||
ret = sh_qspi_write_enable(bank);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Erase */
|
||||
ret = sh_qspi_xfer_common(bank, dout, doutlen, NULL, 0, 1, 1);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
/* Poll status register */
|
||||
return wait_till_ready(bank, 3000);
|
||||
}
|
||||
|
||||
static int sh_qspi_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
int retval = ERROR_OK;
|
||||
int sector;
|
||||
|
||||
LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
|
||||
LOG_ERROR("Flash sector invalid");
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
}
|
||||
|
||||
if (!info->probed) {
|
||||
LOG_ERROR("Flash bank not probed");
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
if (info->dev->erase_cmd == 0x00)
|
||||
return ERROR_FLASH_OPER_UNSUPPORTED;
|
||||
|
||||
for (sector = first; sector <= last; sector++) {
|
||||
if (bank->sectors[sector].is_protected) {
|
||||
LOG_ERROR("Flash sector %d protected", sector);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
for (sector = first; sector <= last; sector++) {
|
||||
retval = sh_qspi_erase_sector(bank, sector);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sh_qspi_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
struct reg_param reg_params[4];
|
||||
struct arm_algorithm arm_algo;
|
||||
uint32_t io_base = (uint32_t)(info->io_base);
|
||||
uint32_t src_base = (uint32_t)(info->source->address);
|
||||
uint32_t chunk;
|
||||
bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
|
||||
int ret = ERROR_OK;
|
||||
int sector;
|
||||
|
||||
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
|
||||
__func__, offset, count);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size) {
|
||||
LOG_WARNING("Write pasts end of flash. Extra data discarded.");
|
||||
count = bank->size - offset;
|
||||
}
|
||||
|
||||
if (offset & 0xff) {
|
||||
LOG_ERROR("sh_qspi_write_page: unaligned write address: %08x",
|
||||
offset);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Check sector protection */
|
||||
for (sector = 0; sector < bank->num_sectors; sector++) {
|
||||
/* Start offset in or before this sector? */
|
||||
/* End offset in or behind this sector? */
|
||||
struct flash_sector *bs = &bank->sectors[sector];
|
||||
|
||||
if ((offset < (bs->offset + bs->size)) &&
|
||||
((offset + count - 1) >= bs->offset) &&
|
||||
bs->is_protected) {
|
||||
LOG_ERROR("Flash sector %d protected", sector);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
|
||||
__func__, offset, count);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size) {
|
||||
LOG_WARNING("Reads past end of flash. Extra data discarded.");
|
||||
count = bank->size - offset;
|
||||
}
|
||||
|
||||
arm_algo.common_magic = ARM_COMMON_MAGIC;
|
||||
arm_algo.core_mode = ARM_MODE_SVC;
|
||||
arm_algo.core_state = ARM_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
|
||||
|
||||
while (count > 0) {
|
||||
chunk = (count > info->buffer_size) ?
|
||||
info->buffer_size : count;
|
||||
|
||||
target_write_buffer(target, info->source->address,
|
||||
chunk, buffer);
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, io_base);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, src_base);
|
||||
buf_set_u32(reg_params[2].value, 0, 32,
|
||||
(1 << 31) | (addr4b << 30) |
|
||||
(info->dev->pprog_cmd << 20) | chunk);
|
||||
buf_set_u32(reg_params[3].value, 0, 32, offset);
|
||||
|
||||
ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
|
||||
info->io_algorithm->address,
|
||||
0, 10000, &arm_algo);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("error executing SH QSPI flash IO algorithm");
|
||||
ret = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer += chunk;
|
||||
offset += chunk;
|
||||
count -= chunk;
|
||||
}
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sh_qspi_read(struct flash_bank *bank, uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
struct reg_param reg_params[4];
|
||||
struct arm_algorithm arm_algo;
|
||||
uint32_t io_base = (uint32_t)(info->io_base);
|
||||
uint32_t src_base = (uint32_t)(info->source->address);
|
||||
uint32_t chunk;
|
||||
bool addr4b = !!(info->dev->size_in_bytes > (1UL << 24));
|
||||
int ret = ERROR_OK;
|
||||
|
||||
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
|
||||
__func__, offset, count);
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size) {
|
||||
LOG_WARNING("Reads past end of flash. Extra data discarded.");
|
||||
count = bank->size - offset;
|
||||
}
|
||||
|
||||
arm_algo.common_magic = ARM_COMMON_MAGIC;
|
||||
arm_algo.core_mode = ARM_MODE_SVC;
|
||||
arm_algo.core_state = ARM_STATE_ARM;
|
||||
|
||||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
|
||||
|
||||
while (count > 0) {
|
||||
chunk = (count > info->buffer_size) ?
|
||||
info->buffer_size : count;
|
||||
|
||||
buf_set_u32(reg_params[0].value, 0, 32, io_base);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, src_base);
|
||||
buf_set_u32(reg_params[2].value, 0, 32,
|
||||
(addr4b << 30) | (info->dev->read_cmd << 20) |
|
||||
chunk);
|
||||
buf_set_u32(reg_params[3].value, 0, 32, offset);
|
||||
|
||||
ret = target_run_algorithm(target, 0, NULL, 4, reg_params,
|
||||
info->io_algorithm->address,
|
||||
0, 10000, &arm_algo);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("error executing SH QSPI flash IO algorithm");
|
||||
ret = ERROR_FLASH_OPERATION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
target_read_buffer(target, info->source->address,
|
||||
chunk, buffer);
|
||||
|
||||
buffer += chunk;
|
||||
offset += chunk;
|
||||
count -= chunk;
|
||||
}
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return ID of flash device */
|
||||
static int read_flash_id(struct flash_bank *bank, uint32_t *id)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
uint8_t dout = SPIFLASH_READ_ID;
|
||||
uint8_t din[3] = { 0, 0, 0 };
|
||||
int ret;
|
||||
|
||||
if (target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
ret = sh_qspi_xfer_common(bank, &dout, 1, din, 3, 1, 1);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
*id = (din[0] << 0) | (din[1] << 8) | (din[2] << 16);
|
||||
|
||||
if (*id == 0xffffff) {
|
||||
LOG_ERROR("No SPI flash found");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int sh_qspi_protect(struct flash_bank *bank, int set,
|
||||
int first, int last)
|
||||
{
|
||||
int sector;
|
||||
|
||||
for (sector = first; sector <= last; sector++)
|
||||
bank->sectors[sector].is_protected = set;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int sh_qspi_upload_helper(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
|
||||
/* see contrib/loaders/flash/sh_qspi.s for src */
|
||||
static const uint8_t sh_qspi_io_code[] = {
|
||||
#include "../../../contrib/loaders/flash/sh_qspi/sh_qspi.inc"
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (info->source)
|
||||
target_free_working_area(target, info->source);
|
||||
if (info->io_algorithm)
|
||||
target_free_working_area(target, info->io_algorithm);
|
||||
|
||||
/* flash write code */
|
||||
if (target_alloc_working_area(target, sizeof(sh_qspi_io_code),
|
||||
&info->io_algorithm) != ERROR_OK) {
|
||||
LOG_WARNING("no working area available, can't do block memory writes");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
target_write_buffer(target, info->io_algorithm->address,
|
||||
sizeof(sh_qspi_io_code), sh_qspi_io_code);
|
||||
|
||||
/*
|
||||
* Try to allocate as big work area buffer as possible, start
|
||||
* with 32 kiB and count down. If there is less than 256 Bytes
|
||||
* of work area available, abort.
|
||||
*/
|
||||
info->buffer_size = 32768;
|
||||
while (true) {
|
||||
ret = target_alloc_working_area_try(target, info->buffer_size,
|
||||
&info->source);
|
||||
if (ret == ERROR_OK)
|
||||
return ret;
|
||||
|
||||
info->buffer_size /= 2;
|
||||
if (info->buffer_size <= 256) {
|
||||
target_free_working_area(target, info->io_algorithm);
|
||||
|
||||
LOG_WARNING("no large enough working area available, can't do block memory writes");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int sh_qspi_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
struct flash_sector *sectors;
|
||||
uint32_t id = 0; /* silence uninitialized warning */
|
||||
uint32_t sectorsize;
|
||||
const struct sh_qspi_target *target_device;
|
||||
int ret;
|
||||
|
||||
if (info->probed)
|
||||
free(bank->sectors);
|
||||
|
||||
info->probed = 0;
|
||||
|
||||
for (target_device = target_devices; target_device->name;
|
||||
++target_device)
|
||||
if (target_device->tap_idcode == target->tap->idcode)
|
||||
break;
|
||||
if (!target_device->name) {
|
||||
LOG_ERROR("Device ID 0x%" PRIx32 " is not known",
|
||||
target->tap->idcode);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
info->io_base = target_device->io_base;
|
||||
|
||||
LOG_DEBUG("Found device %s at address " TARGET_ADDR_FMT,
|
||||
target_device->name, bank->base);
|
||||
|
||||
ret = sh_qspi_upload_helper(bank);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = sh_qspi_init(bank);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = read_flash_id(bank, &id);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
info->dev = NULL;
|
||||
for (const struct flash_device *p = flash_devices; p->name; p++)
|
||||
if (p->device_id == id) {
|
||||
info->dev = p;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!info->dev) {
|
||||
LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
|
||||
info->dev->name, info->dev->device_id);
|
||||
|
||||
/* Set correct size value */
|
||||
bank->size = info->dev->size_in_bytes;
|
||||
if (bank->size <= (1UL << 16))
|
||||
LOG_WARNING("device needs 2-byte addresses - not implemented");
|
||||
|
||||
/* if no sectors, treat whole bank as single sector */
|
||||
sectorsize = info->dev->sectorsize ?
|
||||
info->dev->sectorsize :
|
||||
info->dev->size_in_bytes;
|
||||
|
||||
/* create and fill sectors array */
|
||||
bank->num_sectors = info->dev->size_in_bytes / sectorsize;
|
||||
sectors = calloc(1, sizeof(*sectors) * bank->num_sectors);
|
||||
if (!sectors) {
|
||||
LOG_ERROR("not enough memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (int sector = 0; sector < bank->num_sectors; sector++) {
|
||||
sectors[sector].offset = sector * sectorsize;
|
||||
sectors[sector].size = sectorsize;
|
||||
sectors[sector].is_erased = 0;
|
||||
sectors[sector].is_protected = 0;
|
||||
}
|
||||
|
||||
bank->sectors = sectors;
|
||||
info->probed = 1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int sh_qspi_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
|
||||
if (info->probed)
|
||||
return ERROR_OK;
|
||||
|
||||
return sh_qspi_probe(bank);
|
||||
}
|
||||
|
||||
static int sh_qspi_flash_blank_check(struct flash_bank *bank)
|
||||
{
|
||||
/* Not implemented */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int sh_qspi_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
/* Not implemented */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int sh_qspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
struct sh_qspi_flash_bank *info = bank->driver_priv;
|
||||
|
||||
if (!info->probed) {
|
||||
snprintf(buf, buf_size,
|
||||
"\nSH QSPI flash bank not probed yet\n");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
snprintf(buf, buf_size, "\nSH QSPI flash information:\n"
|
||||
" Device \'%s\' (ID 0x%08" PRIx32 ")\n",
|
||||
info->dev->name, info->dev->device_id);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
FLASH_BANK_COMMAND_HANDLER(sh_qspi_flash_bank_command)
|
||||
{
|
||||
struct sh_qspi_flash_bank *info;
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
if (CMD_ARGC < 6 || CMD_ARGC > 7)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if ((CMD_ARGC == 7) && strcmp(CMD_ARGV[6], "cs0")) {
|
||||
LOG_ERROR("Unknown arg: %s", CMD_ARGV[6]);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
info = calloc(1, sizeof(struct sh_qspi_flash_bank));
|
||||
if (!info) {
|
||||
LOG_ERROR("not enough memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
bank->driver_priv = info;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
const struct flash_driver sh_qspi_flash = {
|
||||
.name = "sh_qspi",
|
||||
.flash_bank_command = sh_qspi_flash_bank_command,
|
||||
.erase = sh_qspi_erase,
|
||||
.protect = sh_qspi_protect,
|
||||
.write = sh_qspi_write,
|
||||
.read = sh_qspi_read,
|
||||
.probe = sh_qspi_probe,
|
||||
.auto_probe = sh_qspi_auto_probe,
|
||||
.erase_check = sh_qspi_flash_blank_check,
|
||||
.protect_check = sh_qspi_protect_check,
|
||||
.info = sh_qspi_get_info,
|
||||
.free_driver_priv = default_flash_free_driver_priv,
|
||||
};
|
||||
@@ -471,7 +471,7 @@ static int sim3x_write_block(struct flash_bank *bank, const uint8_t *buf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sim3x_flash_write(struct flash_bank *bank, const uint8_t * buffer, uint32_t offset, uint32_t count)
|
||||
static int sim3x_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int ret;
|
||||
struct target *target;
|
||||
|
||||
+66
-68
@@ -116,7 +116,7 @@ struct stm32x_options {
|
||||
struct stm32x_flash_bank {
|
||||
struct stm32x_options option_bytes;
|
||||
int ppage_size;
|
||||
int probed;
|
||||
bool probed;
|
||||
|
||||
bool has_dual_banks;
|
||||
/* used to access dual flash bank stm32xl */
|
||||
@@ -145,7 +145,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
|
||||
stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
|
||||
|
||||
bank->driver_priv = stm32x_info;
|
||||
stm32x_info->probed = 0;
|
||||
stm32x_info->probed = false;
|
||||
stm32x_info->has_dual_banks = false;
|
||||
stm32x_info->can_load_options = false;
|
||||
stm32x_info->register_base = FLASH_REG_BASE_B0;
|
||||
@@ -229,34 +229,20 @@ static int stm32x_read_options(struct flash_bank *bank)
|
||||
uint32_t option_bytes;
|
||||
int retval;
|
||||
|
||||
/* read user and read protection option bytes */
|
||||
retval = target_read_u32(target, STM32_OB_RDP, &option_bytes);
|
||||
/* read user and read protection option bytes, user data option bytes */
|
||||
retval = target_read_u32(target, STM32_FLASH_OBR_B0, &option_bytes);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
stm32x_info->option_bytes.rdp = option_bytes & 0xFF;
|
||||
stm32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF;
|
||||
|
||||
/* read user data option bytes */
|
||||
retval = target_read_u32(target, STM32_OB_DATA0, &option_bytes);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
stm32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
|
||||
stm32x_info->option_bytes.rdp = (option_bytes & (1 << OPT_READOUT)) ? 0 : stm32x_info->default_rdp;
|
||||
stm32x_info->option_bytes.user = (option_bytes >> stm32x_info->option_offset >> 2) & 0xff;
|
||||
stm32x_info->option_bytes.data = (option_bytes >> stm32x_info->user_data_offset) & 0xffff;
|
||||
|
||||
/* read write protection option bytes */
|
||||
retval = target_read_u32(target, STM32_OB_WRP0, &option_bytes);
|
||||
retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &stm32x_info->option_bytes.protection);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
stm32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
|
||||
|
||||
retval = target_read_u32(target, STM32_OB_WRP2, &option_bytes);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
stm32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -382,7 +368,6 @@ static int stm32x_protect_check(struct flash_bank *bank)
|
||||
static int stm32x_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
int i;
|
||||
|
||||
if (bank->target->state != TARGET_HALTED) {
|
||||
LOG_ERROR("Target not halted");
|
||||
@@ -400,7 +385,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
for (int i = first; i <= last; i++) {
|
||||
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
@@ -711,7 +696,7 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||
int page_size;
|
||||
uint32_t base_address = 0x08000000;
|
||||
|
||||
stm32x_info->probed = 0;
|
||||
stm32x_info->probed = false;
|
||||
stm32x_info->register_base = FLASH_REG_BASE_B0;
|
||||
stm32x_info->user_data_offset = 10;
|
||||
stm32x_info->option_offset = 0;
|
||||
@@ -728,31 +713,79 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||
|
||||
/* set page size, protection granularity and max flash size depending on family */
|
||||
switch (device_id & 0xfff) {
|
||||
case 0x410: /* medium density */
|
||||
case 0x440: /* stm32f05x */
|
||||
page_size = 1024;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 64;
|
||||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
case 0x444: /* stm32f03x */
|
||||
case 0x445: /* stm32f04x */
|
||||
page_size = 1024;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 32;
|
||||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
case 0x448: /* stm32f07x */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 128;
|
||||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
case 0x442: /* stm32f09x */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 256;
|
||||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
case 0x410: /* stm32f1x medium-density */
|
||||
page_size = 1024;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 128;
|
||||
break;
|
||||
case 0x412: /* low density */
|
||||
case 0x412: /* stm32f1x low-density */
|
||||
page_size = 1024;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 32;
|
||||
break;
|
||||
case 0x414: /* high density */
|
||||
case 0x414: /* stm32f1x high-density */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 2;
|
||||
max_flash_size_in_kb = 512;
|
||||
break;
|
||||
case 0x418: /* connectivity line density */
|
||||
case 0x418: /* stm32f1x connectivity */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 2;
|
||||
max_flash_size_in_kb = 256;
|
||||
break;
|
||||
case 0x420: /* value line density */
|
||||
case 0x430: /* stm32f1 XL-density (dual flash banks) */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 2;
|
||||
max_flash_size_in_kb = 1024;
|
||||
stm32x_info->has_dual_banks = true;
|
||||
break;
|
||||
case 0x420: /* stm32f100xx low- and medium-density value line */
|
||||
page_size = 1024;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 128;
|
||||
break;
|
||||
case 0x428: /* stm32f100xx high-density value line */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 512;
|
||||
break;
|
||||
case 0x422: /* stm32f302/3xb/c */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 2;
|
||||
@@ -771,17 +804,6 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
case 0x428: /* value line High density */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 128;
|
||||
break;
|
||||
case 0x430: /* xl line density (dual flash banks) */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 2;
|
||||
max_flash_size_in_kb = 1024;
|
||||
stm32x_info->has_dual_banks = true;
|
||||
break;
|
||||
case 0x432: /* stm32f37x */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 2;
|
||||
@@ -801,27 +823,6 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
case 0x440: /* stm32f05x */
|
||||
case 0x444: /* stm32f03x */
|
||||
case 0x445: /* stm32f04x */
|
||||
page_size = 1024;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 64;
|
||||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
case 0x448: /* stm32f07x */
|
||||
case 0x442: /* stm32f09x */
|
||||
page_size = 2048;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 256;
|
||||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
stm32x_info->default_rdp = 0xAA;
|
||||
stm32x_info->can_load_options = true;
|
||||
break;
|
||||
default:
|
||||
LOG_WARNING("Cannot identify target as a STM32 family.");
|
||||
return ERROR_FAIL;
|
||||
@@ -900,7 +901,7 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||
if (num_prot_blocks == 32)
|
||||
bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size;
|
||||
|
||||
stm32x_info->probed = 1;
|
||||
stm32x_info->probed = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1368,8 +1369,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt);
|
||||
CMD_ARGC--;
|
||||
CMD_ARGV++;
|
||||
}
|
||||
else if (stm32x_info->has_dual_banks) {
|
||||
} else if (stm32x_info->has_dual_banks) {
|
||||
if (strcmp("BOOT0", CMD_ARGV[0]) == 0)
|
||||
optionbyte |= (1 << 3);
|
||||
else if (strcmp("BOOT1", CMD_ARGV[0]) == 0)
|
||||
@@ -1488,8 +1488,6 @@ static int stm32x_mass_erase(struct flash_bank *bank)
|
||||
|
||||
COMMAND_HANDLER(stm32x_handle_mass_erase_command)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (CMD_ARGC < 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
@@ -1501,7 +1499,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
|
||||
retval = stm32x_mass_erase(bank);
|
||||
if (retval == ERROR_OK) {
|
||||
/* set all sectors as erased */
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
for (int i = 0; i < bank->num_sectors; i++)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
|
||||
command_print(CMD, "stm32x mass erase complete");
|
||||
|
||||
+57
-20
@@ -634,7 +634,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
|
||||
*/
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
int snb;
|
||||
unsigned int snb;
|
||||
if (stm32x_info->has_large_mem && i >= 12)
|
||||
snb = (i - 12) | 0x10;
|
||||
else
|
||||
@@ -894,31 +894,68 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
|
||||
}
|
||||
|
||||
static int setup_sector(struct flash_bank *bank, int start, int num, int size)
|
||||
static void setup_sector(struct flash_bank *bank, int i, int size)
|
||||
{
|
||||
assert(i < bank->num_sectors);
|
||||
bank->sectors[i].offset = bank->size;
|
||||
bank->sectors[i].size = size;
|
||||
bank->size += bank->sectors[i].size;
|
||||
LOG_DEBUG("sector %d: %dkBytes", i, size >> 10);
|
||||
}
|
||||
|
||||
for (int i = start; i < (start + num) ; i++) {
|
||||
assert(i < bank->num_sectors);
|
||||
bank->sectors[i].offset = bank->size;
|
||||
bank->sectors[i].size = size;
|
||||
bank->size += bank->sectors[i].size;
|
||||
LOG_DEBUG("sector %d: %d kBytes", i, size >> 10);
|
||||
static uint16_t sector_size_in_kb(int i, uint16_t max_sector_size_in_kb)
|
||||
{
|
||||
assert(i >= 0);
|
||||
if (i < 4)
|
||||
return max_sector_size_in_kb / 8;
|
||||
if (i == 4)
|
||||
return max_sector_size_in_kb / 2;
|
||||
return max_sector_size_in_kb;
|
||||
}
|
||||
|
||||
static int calculate_number_of_sectors(struct flash_bank *bank,
|
||||
uint16_t flash_size_in_kb,
|
||||
uint16_t max_sector_size_in_kb)
|
||||
{
|
||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||
uint16_t remaining_flash_size_in_kb = flash_size_in_kb;
|
||||
int nr_sectors;
|
||||
|
||||
/* Dual Bank Flash has two identically-arranged banks of sectors. */
|
||||
if (stm32x_info->has_large_mem)
|
||||
remaining_flash_size_in_kb /= 2;
|
||||
|
||||
for (nr_sectors = 0; remaining_flash_size_in_kb > 0; nr_sectors++) {
|
||||
uint16_t size_in_kb = sector_size_in_kb(nr_sectors, max_sector_size_in_kb);
|
||||
if (size_in_kb > remaining_flash_size_in_kb) {
|
||||
LOG_INFO("%s Bank %" PRIu16 " kiB final sector clipped to %" PRIu16 " kiB",
|
||||
stm32x_info->has_large_mem ? "Dual" : "Single",
|
||||
flash_size_in_kb, remaining_flash_size_in_kb);
|
||||
remaining_flash_size_in_kb = 0;
|
||||
} else {
|
||||
remaining_flash_size_in_kb -= size_in_kb;
|
||||
}
|
||||
}
|
||||
|
||||
return start + num;
|
||||
return stm32x_info->has_large_mem ? nr_sectors*2 : nr_sectors;
|
||||
}
|
||||
|
||||
static void setup_bank(struct flash_bank *bank, int start,
|
||||
uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb)
|
||||
{
|
||||
int remain;
|
||||
|
||||
start = setup_sector(bank, start, 4, (max_sector_size_in_kb / 8) * 1024);
|
||||
start = setup_sector(bank, start, 1, (max_sector_size_in_kb / 2) * 1024);
|
||||
|
||||
/* remaining sectors all of size max_sector_size_in_kb */
|
||||
remain = (flash_size_in_kb / max_sector_size_in_kb) - 1;
|
||||
start = setup_sector(bank, start, remain, max_sector_size_in_kb * 1024);
|
||||
uint16_t remaining_flash_size_in_kb = flash_size_in_kb;
|
||||
int sector_index = 0;
|
||||
while (remaining_flash_size_in_kb > 0) {
|
||||
uint16_t size_in_kb = sector_size_in_kb(sector_index, max_sector_size_in_kb);
|
||||
if (size_in_kb > remaining_flash_size_in_kb) {
|
||||
/* Clip last sector. Already warned in
|
||||
* calculate_number_of_sectors. */
|
||||
size_in_kb = remaining_flash_size_in_kb;
|
||||
}
|
||||
setup_sector(bank, start + sector_index, size_in_kb * 1024);
|
||||
remaining_flash_size_in_kb -= size_in_kb;
|
||||
sector_index++;
|
||||
}
|
||||
}
|
||||
|
||||
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
|
||||
@@ -1150,12 +1187,12 @@ static int stm32x_probe(struct flash_bank *bank)
|
||||
}
|
||||
|
||||
/* calculate numbers of pages */
|
||||
int num_pages = flash_size_in_kb / max_sector_size_in_kb
|
||||
+ (stm32x_info->has_large_mem ? 8 : 4);
|
||||
int num_pages = calculate_number_of_sectors(
|
||||
bank, flash_size_in_kb, max_sector_size_in_kb);
|
||||
|
||||
bank->base = base_address;
|
||||
bank->num_sectors = num_pages;
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
|
||||
bank->sectors = calloc(num_pages, sizeof(struct flash_sector));
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 0;
|
||||
|
||||
+438
-376
File diff suppressed because it is too large
Load Diff
+719
-390
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2015 by Uwe Bonnes *
|
||||
* bon@elektron.ikp.physik.tu-darmstadt.de *
|
||||
*
|
||||
* 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_STM32L4X
|
||||
#define OPENOCD_FLASH_NOR_STM32L4X
|
||||
|
||||
/* Flash registers offsets */
|
||||
#define STM32_FLASH_ACR 0x00
|
||||
#define STM32_FLASH_KEYR 0x08
|
||||
#define STM32_FLASH_OPTKEYR 0x0c
|
||||
#define STM32_FLASH_SR 0x10
|
||||
#define STM32_FLASH_CR 0x14
|
||||
#define STM32_FLASH_OPTR 0x20
|
||||
#define STM32_FLASH_WRP1AR 0x2c
|
||||
#define STM32_FLASH_WRP1BR 0x30
|
||||
#define STM32_FLASH_WRP2AR 0x4c
|
||||
#define STM32_FLASH_WRP2BR 0x50
|
||||
|
||||
/* FLASH_CR register bits */
|
||||
#define FLASH_PG (1 << 0)
|
||||
#define FLASH_PER (1 << 1)
|
||||
#define FLASH_MER1 (1 << 2)
|
||||
#define FLASH_PAGE_SHIFT 3
|
||||
#define FLASH_CR_BKER (1 << 11)
|
||||
#define FLASH_MER2 (1 << 15)
|
||||
#define FLASH_STRT (1 << 16)
|
||||
#define FLASH_OPTSTRT (1 << 17)
|
||||
#define FLASH_EOPIE (1 << 24)
|
||||
#define FLASH_ERRIE (1 << 25)
|
||||
#define FLASH_OBL_LAUNCH (1 << 27)
|
||||
#define FLASH_OPTLOCK (1 << 30)
|
||||
#define FLASH_LOCK (1 << 31)
|
||||
|
||||
/* FLASH_SR register bits */
|
||||
#define FLASH_BSY (1 << 16)
|
||||
|
||||
/* Fast programming not used => related errors not used*/
|
||||
#define FLASH_PGSERR (1 << 7) /* Programming sequence error */
|
||||
#define FLASH_SIZERR (1 << 6) /* Size error */
|
||||
#define FLASH_PGAERR (1 << 5) /* Programming alignment error */
|
||||
#define FLASH_WRPERR (1 << 4) /* Write protection error */
|
||||
#define FLASH_PROGERR (1 << 3) /* Programming error */
|
||||
#define FLASH_OPERR (1 << 1) /* Operation error */
|
||||
#define FLASH_EOP (1 << 0) /* End of operation */
|
||||
#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | \
|
||||
FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR)
|
||||
|
||||
/* register unlock keys */
|
||||
#define KEY1 0x45670123
|
||||
#define KEY2 0xCDEF89AB
|
||||
|
||||
/* option register unlock key */
|
||||
#define OPTKEY1 0x08192A3B
|
||||
#define OPTKEY2 0x4C5D6E7F
|
||||
|
||||
#define RDP_LEVEL_0 0xAA
|
||||
#define RDP_LEVEL_1 0xBB
|
||||
#define RDP_LEVEL_2 0xCC
|
||||
|
||||
/* other registers */
|
||||
#define DBGMCU_IDCODE_G0 0x40015800
|
||||
#define DBGMCU_IDCODE_L4_G4 0xE0042000
|
||||
#define DBGMCU_IDCODE_L5 0xE0044000
|
||||
|
||||
#define STM32_FLASH_BANK_BASE 0x08000000
|
||||
|
||||
#endif
|
||||
+7
-10
@@ -128,7 +128,7 @@ struct stm32lx_part_info {
|
||||
};
|
||||
|
||||
struct stm32lx_flash_bank {
|
||||
int probed;
|
||||
bool probed;
|
||||
uint32_t idcode;
|
||||
uint32_t user_bank_size;
|
||||
uint32_t flash_base;
|
||||
@@ -297,7 +297,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
|
||||
|
||||
bank->driver_priv = stm32lx_info;
|
||||
|
||||
stm32lx_info->probed = 0;
|
||||
stm32lx_info->probed = false;
|
||||
stm32lx_info->user_bank_size = bank->size;
|
||||
|
||||
/* the stm32l erased value is 0x00 */
|
||||
@@ -308,8 +308,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
|
||||
|
||||
COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (CMD_ARGC < 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
@@ -321,7 +319,7 @@ COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
|
||||
retval = stm32lx_mass_erase(bank);
|
||||
if (retval == ERROR_OK) {
|
||||
/* set all sectors as erased */
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
for (int i = 0; i < bank->num_sectors; i++)
|
||||
bank->sectors[i].is_erased = 1;
|
||||
|
||||
command_print(CMD, "stm32lx mass erase complete");
|
||||
@@ -731,14 +729,13 @@ static int stm32lx_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
|
||||
int i;
|
||||
uint16_t flash_size_in_kb;
|
||||
uint32_t device_id;
|
||||
uint32_t base_address = FLASH_BANK0_ADDRESS;
|
||||
uint32_t second_bank_base;
|
||||
unsigned int n;
|
||||
|
||||
stm32lx_info->probed = 0;
|
||||
stm32lx_info->probed = false;
|
||||
|
||||
int retval = stm32lx_read_id_code(bank->target, &device_id);
|
||||
if (retval != ERROR_OK)
|
||||
@@ -756,7 +753,7 @@ static int stm32lx_probe(struct flash_bank *bank)
|
||||
}
|
||||
|
||||
if (n == ARRAY_SIZE(stm32lx_parts)) {
|
||||
LOG_WARNING("Cannot identify target as a STM32L family.");
|
||||
LOG_ERROR("Cannot identify target as an STM32 L0 or L1 family device.");
|
||||
return ERROR_FAIL;
|
||||
} else {
|
||||
LOG_INFO("Device: %s", stm32lx_info->part_info.device_str);
|
||||
@@ -852,14 +849,14 @@ static int stm32lx_probe(struct flash_bank *bank)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sectors; i++) {
|
||||
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 = -1;
|
||||
}
|
||||
|
||||
stm32lx_info->probed = 1;
|
||||
stm32lx_info->probed = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
+111
-6
@@ -109,7 +109,7 @@ COMMAND_HANDLER(handle_flash_info_command)
|
||||
return retval;
|
||||
}
|
||||
if (retval == ERROR_FLASH_OPER_UNSUPPORTED)
|
||||
LOG_WARNING("Flash protection check is not implemented.");
|
||||
LOG_INFO("Flash protection check is not implemented.");
|
||||
|
||||
command_print(CMD,
|
||||
"#%d : %s at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32
|
||||
@@ -476,7 +476,7 @@ COMMAND_HANDLER(handle_flash_write_image_command)
|
||||
COMMAND_HANDLER(handle_flash_fill_command)
|
||||
{
|
||||
target_addr_t address;
|
||||
uint32_t pattern;
|
||||
uint64_t pattern;
|
||||
uint32_t count;
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
unsigned i;
|
||||
@@ -487,7 +487,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern);
|
||||
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], pattern);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count);
|
||||
|
||||
struct flash_bank *bank;
|
||||
@@ -496,6 +496,9 @@ COMMAND_HANDLER(handle_flash_fill_command)
|
||||
return retval;
|
||||
|
||||
switch (CMD_NAME[4]) {
|
||||
case 'd':
|
||||
wordsize = 8;
|
||||
break;
|
||||
case 'w':
|
||||
wordsize = 4;
|
||||
break;
|
||||
@@ -509,6 +512,11 @@ COMMAND_HANDLER(handle_flash_fill_command)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) {
|
||||
command_print(CMD, "Fill pattern 0x%" PRIx64 " does not fit within %" PRIu32 "-byte word", pattern, wordsize);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
@@ -541,6 +549,10 @@ COMMAND_HANDLER(handle_flash_fill_command)
|
||||
uint8_t *ptr = buffer + padding_at_start;
|
||||
|
||||
switch (wordsize) {
|
||||
case 8:
|
||||
for (i = 0; i < count; i++, ptr += wordsize)
|
||||
target_buffer_set_u64(target, ptr, pattern);
|
||||
break;
|
||||
case 4:
|
||||
for (i = 0; i < count; i++, ptr += wordsize)
|
||||
target_buffer_set_u32(target, ptr, pattern);
|
||||
@@ -577,9 +589,12 @@ COMMAND_HANDLER(handle_flash_fill_command)
|
||||
goto done;
|
||||
|
||||
for (i = 0, ptr = buffer; i < count; i++) {
|
||||
uint32_t readback = 0;
|
||||
uint64_t readback = 0;
|
||||
|
||||
switch (wordsize) {
|
||||
case 8:
|
||||
readback = target_buffer_get_u64(target, ptr);
|
||||
break;
|
||||
case 4:
|
||||
readback = target_buffer_get_u32(target, ptr);
|
||||
break;
|
||||
@@ -593,7 +608,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
|
||||
if (readback != pattern) {
|
||||
LOG_ERROR(
|
||||
"Verification error address " TARGET_ADDR_FMT
|
||||
", read back 0x%02" PRIx32 ", expected 0x%02" PRIx32,
|
||||
", read back 0x%02" PRIx64 ", expected 0x%02" PRIx64,
|
||||
address + i * wordsize, readback, pattern);
|
||||
retval = ERROR_FAIL;
|
||||
goto done;
|
||||
@@ -613,6 +628,67 @@ done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_flash_md_command)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (CMD_ARGC < 1 || CMD_ARGC > 2)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
target_addr_t address;
|
||||
COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address);
|
||||
|
||||
uint32_t count = 1;
|
||||
if (CMD_ARGC == 2)
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count);
|
||||
|
||||
unsigned int wordsize;
|
||||
switch (CMD_NAME[2]) {
|
||||
case 'w':
|
||||
wordsize = 4;
|
||||
break;
|
||||
case 'h':
|
||||
wordsize = 2;
|
||||
break;
|
||||
case 'b':
|
||||
wordsize = 1;
|
||||
break;
|
||||
default:
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct flash_bank *bank;
|
||||
retval = get_flash_bank_by_addr(target, address, true, &bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
uint32_t offset = address - bank->base;
|
||||
uint32_t sizebytes = count * wordsize;
|
||||
if (offset + sizebytes > bank->size) {
|
||||
command_print(CMD, "Cannot cross flash bank borders");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint8_t *buffer = calloc(count, wordsize);
|
||||
if (buffer == NULL) {
|
||||
command_print(CMD, "No memory for flash read buffer");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
retval = flash_driver_read(bank, buffer, offset, sizebytes);
|
||||
if (retval == ERROR_OK)
|
||||
target_handle_md_output(CMD, target, address, wordsize, count, buffer);
|
||||
|
||||
free(buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
COMMAND_HANDLER(handle_flash_write_bank_command)
|
||||
{
|
||||
uint32_t offset;
|
||||
@@ -952,7 +1028,7 @@ COMMAND_HANDLER(handle_flash_padded_value_command)
|
||||
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], p->default_padded_value);
|
||||
|
||||
command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u", \
|
||||
command_print(CMD, "Default padded value set to 0x%" PRIx8 " for flash bank %u",
|
||||
p->default_padded_value, p->bank_number);
|
||||
|
||||
return retval;
|
||||
@@ -1002,6 +1078,14 @@ static const struct command_registration flash_exec_command_handlers[] = {
|
||||
"before erasing.",
|
||||
|
||||
},
|
||||
{
|
||||
.name = "filld",
|
||||
.handler = handle_flash_fill_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "address value n",
|
||||
.help = "Fill n double-words with 64-bit value, starting at "
|
||||
"word address. (No autoerase.)",
|
||||
},
|
||||
{
|
||||
.name = "fillw",
|
||||
.handler = handle_flash_fill_command,
|
||||
@@ -1026,6 +1110,27 @@ static const struct command_registration flash_exec_command_handlers[] = {
|
||||
.help = "Fill n bytes with 8-bit value, starting at "
|
||||
"word address. (No autoerase.)",
|
||||
},
|
||||
{
|
||||
.name = "mdb",
|
||||
.handler = handle_flash_md_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "address [count]",
|
||||
.help = "Display bytes from flash.",
|
||||
},
|
||||
{
|
||||
.name = "mdh",
|
||||
.handler = handle_flash_md_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "address [count]",
|
||||
.help = "Display half-words from flash.",
|
||||
},
|
||||
{
|
||||
.name = "mdw",
|
||||
.handler = handle_flash_md_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "address [count]",
|
||||
.help = "Display words from flash.",
|
||||
},
|
||||
{
|
||||
.name = "write_bank",
|
||||
.handler = handle_flash_write_bank_command,
|
||||
|
||||
@@ -709,6 +709,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector)
|
||||
* Select one or more bits in FMBSEA or FMBSEB to disable Level 1
|
||||
* protection for the particular sector to be erased/written.
|
||||
*/
|
||||
assert(sector >= 0);
|
||||
if (sector < 16) {
|
||||
target_read_u32(target, 0xFFE88008, &fmbsea);
|
||||
target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector));
|
||||
|
||||
@@ -625,7 +625,6 @@ static int xcf_probe(struct flash_bank *bank)
|
||||
default:
|
||||
LOG_ERROR("Unknown flash device ID 0x%X", id);
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));
|
||||
|
||||
+63
-45
@@ -17,9 +17,12 @@ proc program_error {description exit} {
|
||||
|
||||
proc program {filename args} {
|
||||
set exit 0
|
||||
set needsflash 1
|
||||
|
||||
foreach arg $args {
|
||||
if {[string equal $arg "verify"]} {
|
||||
if {[string equal $arg "preverify"]} {
|
||||
set preverify 1
|
||||
} elseif {[string equal $arg "verify"]} {
|
||||
set verify 1
|
||||
} elseif {[string equal $arg "reset"]} {
|
||||
set reset 1
|
||||
@@ -30,6 +33,15 @@ proc program {filename args} {
|
||||
}
|
||||
}
|
||||
|
||||
# Set variables
|
||||
set filename \{$filename\}
|
||||
if {[info exists address]} {
|
||||
set flash_args "$filename $address"
|
||||
} else {
|
||||
set flash_args "$filename"
|
||||
}
|
||||
|
||||
|
||||
# make sure init is called
|
||||
if {[catch {init}] != 0} {
|
||||
program_error "** OpenOCD init failed **" 1
|
||||
@@ -40,40 +52,46 @@ proc program {filename args} {
|
||||
program_error "** Unable to reset target **" $exit
|
||||
}
|
||||
|
||||
# Check whether programming is needed
|
||||
if {[info exists preverify]} {
|
||||
echo "**pre-verifying**"
|
||||
if {[catch {eval verify_image $flash_args}] == 0} {
|
||||
echo "**Verified OK - No flashing**"
|
||||
set needsflash 0
|
||||
}
|
||||
}
|
||||
|
||||
# start programming phase
|
||||
echo "** Programming Started **"
|
||||
set filename \{$filename\}
|
||||
if {[info exists address]} {
|
||||
set flash_args "$filename $address"
|
||||
} else {
|
||||
set flash_args "$filename"
|
||||
if {$needsflash == 1} {
|
||||
echo "** Programming Started **"
|
||||
|
||||
if {[catch {eval flash write_image erase $flash_args}] == 0} {
|
||||
echo "** Programming Finished **"
|
||||
if {[info exists verify]} {
|
||||
# verify phase
|
||||
echo "** Verify Started **"
|
||||
if {[catch {eval verify_image $flash_args}] == 0} {
|
||||
echo "** Verified OK **"
|
||||
} else {
|
||||
program_error "** Verify Failed **" $exit
|
||||
}
|
||||
}
|
||||
} else {
|
||||
program_error "** Programming Failed **" $exit
|
||||
}
|
||||
}
|
||||
|
||||
if {[catch {eval flash write_image erase $flash_args}] == 0} {
|
||||
echo "** Programming Finished **"
|
||||
if {[info exists verify]} {
|
||||
# verify phase
|
||||
echo "** Verify Started **"
|
||||
if {[catch {eval verify_image $flash_args}] == 0} {
|
||||
echo "** Verified OK **"
|
||||
} else {
|
||||
program_error "** Verify Failed **" $exit
|
||||
}
|
||||
if {[info exists reset]} {
|
||||
# reset target if requested
|
||||
if {$exit == 1} {
|
||||
# also disable target polling, we are shutting down anyway
|
||||
poll off
|
||||
}
|
||||
|
||||
if {[info exists reset]} {
|
||||
# reset target if requested
|
||||
if {$exit == 1} {
|
||||
# also disable target polling, we are shutting down anyway
|
||||
poll off
|
||||
}
|
||||
echo "** Resetting Target **"
|
||||
reset run
|
||||
}
|
||||
} else {
|
||||
program_error "** Programming Failed **" $exit
|
||||
echo "** Resetting Target **"
|
||||
reset run
|
||||
}
|
||||
|
||||
|
||||
if {$exit == 1} {
|
||||
shutdown
|
||||
}
|
||||
@@ -81,25 +99,25 @@ proc program {filename args} {
|
||||
}
|
||||
|
||||
add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional"
|
||||
add_usage_text program "<filename> \[address\] \[verify\] \[reset\] \[exit\]"
|
||||
add_usage_text program "<filename> \[address\] \[pre-verify\] \[verify\] \[reset\] \[exit\]"
|
||||
|
||||
# stm32f0x uses the same flash driver as the stm32f1x
|
||||
# this alias enables the use of either name.
|
||||
proc stm32f0x args {
|
||||
eval stm32f1x $args
|
||||
}
|
||||
# stm32[f0x|f3x] uses the same flash driver as the stm32f1x
|
||||
proc stm32f0x args { eval stm32f1x $args }
|
||||
proc stm32f3x args { eval stm32f1x $args }
|
||||
|
||||
# stm32f3x uses the same flash driver as the stm32f1x
|
||||
# this alias enables the use of either name.
|
||||
proc stm32f3x args {
|
||||
eval stm32f1x $args
|
||||
}
|
||||
# stm32[f4x|f7x] uses the same flash driver as the stm32f2x
|
||||
proc stm32f4x args { eval stm32f2x $args }
|
||||
proc stm32f7x args { eval stm32f2x $args }
|
||||
|
||||
# stm32f4x uses the same flash driver as the stm32f2x
|
||||
# this alias enables the use of either name.
|
||||
proc stm32f4x args {
|
||||
eval stm32f2x $args
|
||||
}
|
||||
# stm32lx driver supports both STM32 L0 and L1 devices
|
||||
proc stm32l0x args { eval stm32lx $args }
|
||||
proc stm32l1x args { eval stm32lx $args }
|
||||
|
||||
# stm32[g0|g4|wb|wl] uses the same flash driver as the stm32l4x
|
||||
proc stm32g0x args { eval stm32l4x $args }
|
||||
proc stm32g4x args { eval stm32l4x $args }
|
||||
proc stm32wbx args { eval stm32l4x $args }
|
||||
proc stm32wlx args { eval stm32l4x $args }
|
||||
|
||||
# ease migration to updated flash driver
|
||||
proc stm32x args {
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
* using the bits in @c value. This routine fast-paths writes
|
||||
* of little-endian, byte-aligned, 32-bit words.
|
||||
* @param _buffer The buffer whose bits will be set.
|
||||
* Do not use uninitialized buffer or clang static analyzer emits a warning.
|
||||
* @param first The bit offset in @c _buffer to start writing (0-31).
|
||||
* @param num The number of bits from @c value to copy (1-32).
|
||||
* @param value Up to 32 bits that will be copied to _buffer.
|
||||
@@ -62,6 +63,7 @@ static inline void buf_set_u32(uint8_t *_buffer,
|
||||
* using the bits in @c value. This routine fast-paths writes
|
||||
* of little-endian, byte-aligned, 64-bit words.
|
||||
* @param _buffer The buffer whose bits will be set.
|
||||
* Do not use uninitialized buffer or clang static analyzer emits a warning.
|
||||
* @param first The bit offset in @c _buffer to start writing (0-63).
|
||||
* @param num The number of bits from @c value to copy (1-64).
|
||||
* @param value Up to 64 bits that will be copied to _buffer.
|
||||
|
||||
+32
-24
@@ -52,6 +52,10 @@ struct log_capture_state {
|
||||
Jim_Obj *output;
|
||||
};
|
||||
|
||||
static int unregister_command(struct command_context *context,
|
||||
struct command *parent, const char *name);
|
||||
static char *command_name(struct command *c, char delim);
|
||||
|
||||
static void tcl_output(void *privData, const char *file, unsigned line,
|
||||
const char *function, const char *string)
|
||||
{
|
||||
@@ -126,13 +130,12 @@ extern struct command_context *global_cmd_ctx;
|
||||
|
||||
/* dump a single line to the log for the command.
|
||||
* Do nothing in case we are not at debug level 3 */
|
||||
void script_debug(Jim_Interp *interp, const char *name,
|
||||
unsigned argc, Jim_Obj * const *argv)
|
||||
void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv)
|
||||
{
|
||||
if (debug_level < LOG_LVL_DEBUG)
|
||||
return;
|
||||
|
||||
char *dbg = alloc_printf("command - %s", name);
|
||||
char *dbg = alloc_printf("command -");
|
||||
for (unsigned i = 0; i < argc; i++) {
|
||||
int len;
|
||||
const char *w = Jim_GetString(argv[i], &len);
|
||||
@@ -213,7 +216,7 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
|
||||
struct command *c = interp->cmdPrivData;
|
||||
assert(c);
|
||||
script_debug(interp, c->name, argc, argv);
|
||||
script_debug(interp, argc, argv);
|
||||
return script_command_run(interp, argc, argv, c);
|
||||
}
|
||||
|
||||
@@ -243,11 +246,6 @@ struct command *command_find_in_context(struct command_context *cmd_ctx,
|
||||
{
|
||||
return command_find(cmd_ctx->commands, name);
|
||||
}
|
||||
struct command *command_find_in_parent(struct command *parent,
|
||||
const char *name)
|
||||
{
|
||||
return command_find(parent->children, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the command into the linked list, sorted by name.
|
||||
@@ -333,7 +331,6 @@ static struct command *command_new(struct command_context *cmd_ctx,
|
||||
c->parent = parent;
|
||||
c->handler = cr->handler;
|
||||
c->jim_handler = cr->jim_handler;
|
||||
c->jim_handler_data = cr->jim_handler_data;
|
||||
c->mode = cr->mode;
|
||||
|
||||
command_add_child(command_list_for_parent(cmd_ctx, parent), c);
|
||||
@@ -360,7 +357,7 @@ static int register_command_handler(struct command_context *cmd_ctx,
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct command *register_command(struct command_context *context,
|
||||
static struct command *register_command(struct command_context *context,
|
||||
struct command *parent, const struct command_registration *cr)
|
||||
{
|
||||
if (!context || !cr->name)
|
||||
@@ -382,14 +379,14 @@ struct command *register_command(struct command_context *context,
|
||||
if (NULL == c)
|
||||
return NULL;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
int retval = JIM_OK;
|
||||
if (NULL != cr->jim_handler && NULL == parent) {
|
||||
retval = Jim_CreateCommand(context->interp, cr->name,
|
||||
cr->jim_handler, cr->jim_handler_data, NULL);
|
||||
cr->jim_handler, NULL, NULL);
|
||||
} else if (NULL != cr->handler || NULL != parent)
|
||||
retval = register_command_handler(context, command_root(c));
|
||||
|
||||
if (ERROR_OK != retval) {
|
||||
if (retval != JIM_OK) {
|
||||
unregister_command(context, parent, name);
|
||||
c = NULL;
|
||||
}
|
||||
@@ -442,7 +439,7 @@ int unregister_all_commands(struct command_context *context,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int unregister_command(struct command_context *context,
|
||||
static int unregister_command(struct command_context *context,
|
||||
struct command *parent, const char *name)
|
||||
{
|
||||
if ((!context) || (!name))
|
||||
@@ -550,7 +547,7 @@ static char *__command_name(struct command *c, char delim, unsigned extra)
|
||||
return name;
|
||||
}
|
||||
|
||||
char *command_name(struct command *c, char delim)
|
||||
static char *command_name(struct command *c, char delim)
|
||||
{
|
||||
return __command_name(c, delim, 0);
|
||||
}
|
||||
@@ -1033,8 +1030,7 @@ static int run_usage(Jim_Interp *interp, int argc_valid, int argc, Jim_Obj * con
|
||||
|
||||
static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
{
|
||||
const char *cmd_name = Jim_GetString(argv[0], NULL);
|
||||
script_debug(interp, cmd_name, argc, argv);
|
||||
script_debug(interp, argc, argv);
|
||||
|
||||
struct command_context *cmd_ctx = current_command_context(interp);
|
||||
struct command *c = cmd_ctx->commands;
|
||||
@@ -1220,9 +1216,9 @@ static const struct command_registration command_subcommand_handlers[] = {
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_command_mode,
|
||||
.usage = "[command_name ...]",
|
||||
.help = "Returns the command modes allowed by a command:"
|
||||
"'any', 'config', or 'exec'. If no command is"
|
||||
"specified, returns the current command mode. "
|
||||
.help = "Returns the command modes allowed by a command: "
|
||||
"'any', 'config', or 'exec'. If no command is "
|
||||
"specified, returns the current command mode. "
|
||||
"Returns 'unknown' if an unknown command is given. "
|
||||
"Command can be multiple tokens.",
|
||||
},
|
||||
@@ -1230,6 +1226,21 @@ static const struct command_registration command_subcommand_handlers[] = {
|
||||
};
|
||||
|
||||
static const struct command_registration command_builtin_handlers[] = {
|
||||
{
|
||||
.name = "ocd_find",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_find,
|
||||
.help = "find full path to file",
|
||||
.usage = "file",
|
||||
},
|
||||
{
|
||||
.name = "capture",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_capture,
|
||||
.help = "Capture progress output and return as tcl return value. If the "
|
||||
"progress output was empty, return tcl return value.",
|
||||
.usage = "command",
|
||||
},
|
||||
{
|
||||
.name = "echo",
|
||||
.handler = jim_echo,
|
||||
@@ -1340,9 +1351,6 @@ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp
|
||||
Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS",
|
||||
Jim_NewStringObj(interp, HostOs, strlen(HostOs)));
|
||||
|
||||
Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL);
|
||||
Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL);
|
||||
|
||||
register_commands(context, NULL, command_builtin_handlers);
|
||||
|
||||
Jim_SetAssocData(interp, "context", NULL, context);
|
||||
|
||||
+2
-44
@@ -195,19 +195,9 @@ struct command {
|
||||
struct command *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param c The command to be named.
|
||||
* @param delim The character to place between command names.
|
||||
* @returns A malloc'd string containing the full command name,
|
||||
* which may include one or more ancestor components. Multiple names
|
||||
* are separated by single spaces. The caller must free() the string
|
||||
* when done with it.
|
||||
*/
|
||||
char *command_name(struct command *c, char delim);
|
||||
|
||||
/*
|
||||
* Commands should be registered by filling in one or more of these
|
||||
* structures and passing them to register_command().
|
||||
* structures and passing them to [un]register_commands().
|
||||
*
|
||||
* A conventioal format should be used for help strings, to provide both
|
||||
* usage and basic information:
|
||||
@@ -226,7 +216,6 @@ struct command_registration {
|
||||
const char *name;
|
||||
command_handler_t handler;
|
||||
Jim_CmdProc *jim_handler;
|
||||
void *jim_handler_data;
|
||||
enum command_mode mode;
|
||||
const char *help;
|
||||
/** a string listing the options and arguments, required or optional */
|
||||
@@ -244,24 +233,6 @@ struct command_registration {
|
||||
/** Use this as the last entry in an array of command_registration records. */
|
||||
#define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL }
|
||||
|
||||
/**
|
||||
* Register a command @c handler that can be called from scripts during
|
||||
* the execution @c mode specified.
|
||||
*
|
||||
* If @c parent is non-NULL, the new command will be registered as a
|
||||
* sub-command under it; otherwise, it will be available as a top-level
|
||||
* command.
|
||||
*
|
||||
* @param cmd_ctx The command_context in which to register the command.
|
||||
* @param parent Register this command as a child of this, or NULL to
|
||||
* register a top-level command.
|
||||
* @param rec A command_registration record that contains the desired
|
||||
* command parameters.
|
||||
* @returns The new command, if successful; otherwise, NULL.
|
||||
*/
|
||||
struct command *register_command(struct command_context *cmd_ctx,
|
||||
struct command *parent, const struct command_registration *rec);
|
||||
|
||||
/**
|
||||
* Register one or more commands in the specified context, as children
|
||||
* of @c parent (or top-level commends, if NULL). In a registration's
|
||||
@@ -280,16 +251,6 @@ struct command *register_command(struct command_context *cmd_ctx,
|
||||
int register_commands(struct command_context *cmd_ctx, struct command *parent,
|
||||
const struct command_registration *cmds);
|
||||
|
||||
|
||||
/**
|
||||
* Unregisters command @c name from the given context, @c cmd_ctx.
|
||||
* @param cmd_ctx The context of the registered command.
|
||||
* @param parent The parent of the given command, or NULL.
|
||||
* @param name The name of the command to unregister.
|
||||
* @returns ERROR_OK on success, or an error code.
|
||||
*/
|
||||
int unregister_command(struct command_context *cmd_ctx,
|
||||
struct command *parent, const char *name);
|
||||
/**
|
||||
* Unregisters all commands from the specfied context.
|
||||
* @param cmd_ctx The context that will be cleared of registered commands.
|
||||
@@ -301,8 +262,6 @@ int unregister_all_commands(struct command_context *cmd_ctx,
|
||||
|
||||
struct command *command_find_in_context(struct command_context *cmd_ctx,
|
||||
const char *name);
|
||||
struct command *command_find_in_parent(struct command *parent,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* Update the private command data field for a command and all descendents.
|
||||
@@ -449,7 +408,6 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label);
|
||||
#define COMMAND_PARSE_ENABLE(in, out) \
|
||||
COMMAND_PARSE_BOOL(in, out, "enable", "disable")
|
||||
|
||||
void script_debug(Jim_Interp *interp, const char *cmd,
|
||||
unsigned argc, Jim_Obj * const *argv);
|
||||
void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv);
|
||||
|
||||
#endif /* OPENOCD_HELPER_COMMAND_H */
|
||||
|
||||
+1
-1
@@ -403,7 +403,7 @@ static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc,
|
||||
{
|
||||
if (strcmp("eth0", ifr->ifr_name) != 0)
|
||||
continue;
|
||||
strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
|
||||
strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1);
|
||||
if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
|
||||
close(SockFD);
|
||||
return JIM_ERR;
|
||||
|
||||
+78
-20
@@ -220,6 +220,15 @@ COMMAND_HANDLER(handle_debug_level_command)
|
||||
|
||||
COMMAND_HANDLER(handle_log_output_command)
|
||||
{
|
||||
if (CMD_ARGC == 0 || (CMD_ARGC == 1 && strcmp(CMD_ARGV[0], "default") == 0)) {
|
||||
if (log_output != stderr && log_output != NULL) {
|
||||
/* Close previous log file, if it was open and wasn't stderr. */
|
||||
fclose(log_output);
|
||||
}
|
||||
log_output = stderr;
|
||||
LOG_DEBUG("set log_output to default");
|
||||
return ERROR_OK;
|
||||
}
|
||||
if (CMD_ARGC == 1) {
|
||||
FILE *file = fopen(CMD_ARGV[0], "w");
|
||||
if (file == NULL) {
|
||||
@@ -231,9 +240,11 @@ COMMAND_HANDLER(handle_log_output_command)
|
||||
fclose(log_output);
|
||||
}
|
||||
log_output = file;
|
||||
LOG_DEBUG("set log_output to \"%s\"", CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
static const struct command_registration log_command_handlers[] = {
|
||||
@@ -242,7 +253,7 @@ static const struct command_registration log_command_handlers[] = {
|
||||
.handler = handle_log_output_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "redirect logging to a file (default: stderr)",
|
||||
.usage = "file_name",
|
||||
.usage = "[file_name | \"default\"]",
|
||||
},
|
||||
{
|
||||
.name = "debug_level",
|
||||
@@ -390,25 +401,43 @@ char *alloc_printf(const char *format, ...)
|
||||
* fast when invoked more often than every 500ms.
|
||||
*
|
||||
*/
|
||||
void keep_alive()
|
||||
#define KEEP_ALIVE_KICK_TIME_MS 500
|
||||
#define KEEP_ALIVE_TIMEOUT_MS 1000
|
||||
|
||||
static void gdb_timeout_warning(int64_t delta_time)
|
||||
{
|
||||
extern int gdb_actual_connections;
|
||||
|
||||
if (gdb_actual_connections)
|
||||
LOG_WARNING("keep_alive() was not invoked in the "
|
||||
"%d ms timelimit. GDB alive packet not "
|
||||
"sent! (%" PRId64 " ms). Workaround: increase "
|
||||
"\"set remotetimeout\" in GDB",
|
||||
KEEP_ALIVE_TIMEOUT_MS,
|
||||
delta_time);
|
||||
else
|
||||
LOG_DEBUG("keep_alive() was not invoked in the "
|
||||
"%d ms timelimit (%" PRId64 " ms). This may cause "
|
||||
"trouble with GDB connections.",
|
||||
KEEP_ALIVE_TIMEOUT_MS,
|
||||
delta_time);
|
||||
}
|
||||
|
||||
void keep_alive(void)
|
||||
{
|
||||
current_time = timeval_ms();
|
||||
if (current_time-last_time > 1000) {
|
||||
extern int gdb_actual_connections;
|
||||
|
||||
if (gdb_actual_connections)
|
||||
LOG_WARNING("keep_alive() was not invoked in the "
|
||||
"1000ms timelimit. GDB alive packet not "
|
||||
"sent! (%" PRId64 "). Workaround: increase "
|
||||
"\"set remotetimeout\" in GDB",
|
||||
current_time-last_time);
|
||||
else
|
||||
LOG_DEBUG("keep_alive() was not invoked in the "
|
||||
"1000ms timelimit (%" PRId64 "). This may cause "
|
||||
"trouble with GDB connections.",
|
||||
current_time-last_time);
|
||||
int64_t delta_time = current_time - last_time;
|
||||
|
||||
if (delta_time > KEEP_ALIVE_TIMEOUT_MS) {
|
||||
last_time = current_time;
|
||||
|
||||
gdb_timeout_warning(delta_time);
|
||||
}
|
||||
if (current_time-last_time > 500) {
|
||||
|
||||
if (delta_time > KEEP_ALIVE_KICK_TIME_MS) {
|
||||
last_time = current_time;
|
||||
|
||||
/* this will keep the GDB connection alive */
|
||||
LOG_USER_N("%s", "");
|
||||
|
||||
@@ -419,16 +448,20 @@ void keep_alive()
|
||||
*
|
||||
* These functions should be invoked at a well defined spot in server.c
|
||||
*/
|
||||
|
||||
last_time = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset keep alive timer without sending message */
|
||||
void kept_alive()
|
||||
void kept_alive(void)
|
||||
{
|
||||
current_time = timeval_ms();
|
||||
|
||||
int64_t delta_time = current_time - last_time;
|
||||
|
||||
last_time = current_time;
|
||||
|
||||
if (delta_time > KEEP_ALIVE_TIMEOUT_MS)
|
||||
gdb_timeout_warning(delta_time);
|
||||
}
|
||||
|
||||
/* if we sleep for extended periods of time, we must invoke keep_alive() intermittantly */
|
||||
@@ -454,3 +487,28 @@ void busy_sleep(uint64_t ms)
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/* Maximum size of socket error message retreived from operation system */
|
||||
#define MAX_SOCKET_ERR_MSG_LENGTH 256
|
||||
|
||||
/* Provide log message for the last socket error.
|
||||
Uses errno on *nix and WSAGetLastError() on Windows */
|
||||
void log_socket_error(const char *socket_desc)
|
||||
{
|
||||
int error_code;
|
||||
#ifdef _WIN32
|
||||
error_code = WSAGetLastError();
|
||||
char error_message[MAX_SOCKET_ERR_MSG_LENGTH];
|
||||
error_message[0] = '\0';
|
||||
DWORD retval = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, 0,
|
||||
error_message, MAX_SOCKET_ERR_MSG_LENGTH, NULL);
|
||||
error_message[MAX_SOCKET_ERR_MSG_LENGTH - 1] = '\0';
|
||||
const bool have_message = (retval != 0) && (error_message[0] != '\0');
|
||||
LOG_ERROR("Error on socket '%s': WSAGetLastError==%d%s%s.", socket_desc, error_code,
|
||||
(have_message ? ", message: " : ""),
|
||||
(have_message ? error_message : ""));
|
||||
#else
|
||||
error_code = errno;
|
||||
LOG_ERROR("Error on socket '%s': errno==%d, message: %s.", socket_desc, error_code, strerror(error_code));
|
||||
#endif
|
||||
}
|
||||
|
||||
+4
-1
@@ -82,6 +82,8 @@ void kept_alive(void);
|
||||
void alive_sleep(uint64_t ms);
|
||||
void busy_sleep(uint64_t ms);
|
||||
|
||||
void log_socket_error(const char *socket_desc);
|
||||
|
||||
typedef void (*log_callback_fn)(void *priv, const char *file, unsigned line,
|
||||
const char *function, const char *string);
|
||||
|
||||
@@ -95,7 +97,8 @@ int log_add_callback(log_callback_fn fn, void *priv);
|
||||
int log_remove_callback(log_callback_fn fn, void *priv);
|
||||
|
||||
char *alloc_vprintf(const char *fmt, va_list ap);
|
||||
char *alloc_printf(const char *fmt, ...);
|
||||
char *alloc_printf(const char *fmt, ...)
|
||||
__attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2)));
|
||||
|
||||
extern int debug_level;
|
||||
|
||||
|
||||
@@ -29,4 +29,3 @@ add_help_text script "filename of OpenOCD script (tcl) to run"
|
||||
add_usage_text script "<file>"
|
||||
|
||||
#########
|
||||
|
||||
|
||||
+12
-22
@@ -126,17 +126,17 @@ static inline uint64_t le_to_h_u64(const uint8_t *buf)
|
||||
(uint64_t)buf[7] << 56);
|
||||
}
|
||||
|
||||
static inline uint32_t le_to_h_u32(const uint8_t* buf)
|
||||
static inline uint32_t le_to_h_u32(const uint8_t *buf)
|
||||
{
|
||||
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)
|
||||
static inline uint32_t le_to_h_u24(const uint8_t *buf)
|
||||
{
|
||||
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)
|
||||
static inline uint16_t le_to_h_u16(const uint8_t *buf)
|
||||
{
|
||||
return (uint16_t)((uint16_t)buf[0] | (uint16_t)buf[1] << 8);
|
||||
}
|
||||
@@ -153,17 +153,17 @@ static inline uint64_t be_to_h_u64(const uint8_t *buf)
|
||||
(uint64_t)buf[0] << 56);
|
||||
}
|
||||
|
||||
static inline uint32_t be_to_h_u32(const uint8_t* buf)
|
||||
static inline uint32_t be_to_h_u32(const uint8_t *buf)
|
||||
{
|
||||
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)
|
||||
static inline uint32_t be_to_h_u24(const uint8_t *buf)
|
||||
{
|
||||
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)
|
||||
static inline uint16_t be_to_h_u16(const uint8_t *buf)
|
||||
{
|
||||
return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8);
|
||||
}
|
||||
@@ -192,7 +192,7 @@ static inline void h_u64_to_be(uint8_t *buf, int64_t val)
|
||||
buf[7] = (uint8_t) (val >> 0);
|
||||
}
|
||||
|
||||
static inline void h_u32_to_le(uint8_t* buf, int val)
|
||||
static inline void h_u32_to_le(uint8_t *buf, int val)
|
||||
{
|
||||
buf[3] = (uint8_t) (val >> 24);
|
||||
buf[2] = (uint8_t) (val >> 16);
|
||||
@@ -200,7 +200,7 @@ static inline void h_u32_to_le(uint8_t* buf, int val)
|
||||
buf[0] = (uint8_t) (val >> 0);
|
||||
}
|
||||
|
||||
static inline void h_u32_to_be(uint8_t* buf, int val)
|
||||
static inline void h_u32_to_be(uint8_t *buf, int val)
|
||||
{
|
||||
buf[0] = (uint8_t) (val >> 24);
|
||||
buf[1] = (uint8_t) (val >> 16);
|
||||
@@ -208,27 +208,27 @@ static inline void h_u32_to_be(uint8_t* buf, int val)
|
||||
buf[3] = (uint8_t) (val >> 0);
|
||||
}
|
||||
|
||||
static inline void h_u24_to_le(uint8_t* buf, int val)
|
||||
static inline void h_u24_to_le(uint8_t *buf, int val)
|
||||
{
|
||||
buf[2] = (uint8_t) (val >> 16);
|
||||
buf[1] = (uint8_t) (val >> 8);
|
||||
buf[0] = (uint8_t) (val >> 0);
|
||||
}
|
||||
|
||||
static inline void h_u24_to_be(uint8_t* buf, int val)
|
||||
static inline void h_u24_to_be(uint8_t *buf, int val)
|
||||
{
|
||||
buf[0] = (uint8_t) (val >> 16);
|
||||
buf[1] = (uint8_t) (val >> 8);
|
||||
buf[2] = (uint8_t) (val >> 0);
|
||||
}
|
||||
|
||||
static inline void h_u16_to_le(uint8_t* buf, int val)
|
||||
static inline void h_u16_to_le(uint8_t *buf, int val)
|
||||
{
|
||||
buf[1] = (uint8_t) (val >> 8);
|
||||
buf[0] = (uint8_t) (val >> 0);
|
||||
}
|
||||
|
||||
static inline void h_u16_to_be(uint8_t* buf, int val)
|
||||
static inline void h_u16_to_be(uint8_t *buf, int val)
|
||||
{
|
||||
buf[0] = (uint8_t) (val >> 8);
|
||||
buf[1] = (uint8_t) (val >> 0);
|
||||
@@ -349,7 +349,6 @@ typedef uint64_t uintmax_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if BUILD_TARGET64
|
||||
typedef uint64_t target_addr_t;
|
||||
#define TARGET_ADDR_MAX UINT64_MAX
|
||||
#define TARGET_PRIdADDR PRId64
|
||||
@@ -357,15 +356,6 @@ typedef uint64_t target_addr_t;
|
||||
#define TARGET_PRIoADDR PRIo64
|
||||
#define TARGET_PRIxADDR PRIx64
|
||||
#define TARGET_PRIXADDR PRIX64
|
||||
#else
|
||||
typedef uint32_t target_addr_t;
|
||||
#define TARGET_ADDR_MAX UINT32_MAX
|
||||
#define TARGET_PRIdADDR PRId32
|
||||
#define TARGET_PRIuADDR PRIu32
|
||||
#define TARGET_PRIoADDR PRIo32
|
||||
#define TARGET_PRIxADDR PRIx32
|
||||
#define TARGET_PRIXADDR PRIX32
|
||||
#endif
|
||||
#define TARGET_ADDR_FMT "0x%8.8" TARGET_PRIxADDR
|
||||
|
||||
#endif /* OPENOCD_HELPER_TYPES_H */
|
||||
|
||||
@@ -56,6 +56,7 @@ endif
|
||||
%D%/interface.c \
|
||||
%D%/interfaces.c \
|
||||
%D%/tcl.c \
|
||||
%D%/swim.c \
|
||||
%D%/commands.h \
|
||||
%D%/driver.h \
|
||||
%D%/interface.h \
|
||||
@@ -65,6 +66,7 @@ endif
|
||||
%D%/minidriver/minidriver_imp.h \
|
||||
%D%/minidummy/jtag_minidriver.h \
|
||||
%D%/swd.h \
|
||||
%D%/swim.h \
|
||||
%D%/tcl.h \
|
||||
$(JTAG_SRCS)
|
||||
|
||||
|
||||
+185
-74
@@ -46,7 +46,7 @@
|
||||
* Holds support for configuring debug adapters from TCl scripts.
|
||||
*/
|
||||
|
||||
extern struct jtag_interface *jtag_interface;
|
||||
struct adapter_driver *adapter_driver;
|
||||
const char * const jtag_only[] = { "jtag", NULL };
|
||||
|
||||
static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||
@@ -61,12 +61,12 @@ static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||
Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)");
|
||||
return JIM_ERR;
|
||||
}
|
||||
const char *name = jtag_interface ? jtag_interface->name : NULL;
|
||||
const char *name = adapter_driver ? adapter_driver->name : NULL;
|
||||
Jim_SetResultString(goi.interp, name ? : "undefined", -1);
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(interface_transport_command)
|
||||
COMMAND_HANDLER(adapter_transports_command)
|
||||
{
|
||||
char **transports;
|
||||
int retval;
|
||||
@@ -85,26 +85,26 @@ COMMAND_HANDLER(interface_transport_command)
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_interface_list_command)
|
||||
COMMAND_HANDLER(handle_adapter_list_command)
|
||||
{
|
||||
if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0)
|
||||
if (strcmp(CMD_NAME, "list") == 0 && CMD_ARGC > 0)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
command_print(CMD, "The following debug interfaces are available:");
|
||||
for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) {
|
||||
const char *name = jtag_interfaces[i]->name;
|
||||
command_print(CMD, "The following debug adapters are available:");
|
||||
for (unsigned i = 0; NULL != adapter_drivers[i]; i++) {
|
||||
const char *name = adapter_drivers[i]->name;
|
||||
command_print(CMD, "%u: %s", i + 1, name);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_interface_command)
|
||||
COMMAND_HANDLER(handle_adapter_driver_command)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* check whether the interface is already configured */
|
||||
if (jtag_interface) {
|
||||
if (adapter_driver) {
|
||||
LOG_WARNING("Interface already configured, ignoring");
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -113,20 +113,20 @@ COMMAND_HANDLER(handle_interface_command)
|
||||
if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0')
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) {
|
||||
if (strcmp(CMD_ARGV[0], jtag_interfaces[i]->name) != 0)
|
||||
for (unsigned i = 0; NULL != adapter_drivers[i]; i++) {
|
||||
if (strcmp(CMD_ARGV[0], adapter_drivers[i]->name) != 0)
|
||||
continue;
|
||||
|
||||
if (NULL != jtag_interfaces[i]->commands) {
|
||||
if (NULL != adapter_drivers[i]->commands) {
|
||||
retval = register_commands(CMD_CTX, NULL,
|
||||
jtag_interfaces[i]->commands);
|
||||
adapter_drivers[i]->commands);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
jtag_interface = jtag_interfaces[i];
|
||||
adapter_driver = adapter_drivers[i];
|
||||
|
||||
return allow_transports(CMD_CTX, jtag_interface->transports);
|
||||
return allow_transports(CMD_CTX, adapter_driver->transports);
|
||||
}
|
||||
|
||||
/* no valid interface was found (i.e. the configuration option,
|
||||
@@ -134,7 +134,7 @@ COMMAND_HANDLER(handle_interface_command)
|
||||
*/
|
||||
LOG_ERROR("The specified debug interface was not found (%s)",
|
||||
CMD_ARGV[0]);
|
||||
CALL_COMMAND_HANDLER(handle_interface_list_command);
|
||||
CALL_COMMAND_HANDLER(handle_adapter_list_command);
|
||||
return ERROR_JTAG_INVALID_INTERFACE;
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ next:
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_adapter_nsrst_delay_command)
|
||||
COMMAND_HANDLER(handle_adapter_srst_delay_command)
|
||||
{
|
||||
if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -365,11 +365,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_delay_command)
|
||||
|
||||
jtag_set_nsrst_delay(delay);
|
||||
}
|
||||
command_print(CMD, "adapter_nsrst_delay: %u", jtag_get_nsrst_delay());
|
||||
command_print(CMD, "adapter srst delay: %u", jtag_get_nsrst_delay());
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command)
|
||||
COMMAND_HANDLER(handle_adapter_srst_pulse_width_command)
|
||||
{
|
||||
if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -379,11 +379,11 @@ COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command)
|
||||
|
||||
jtag_set_nsrst_assert_width(width);
|
||||
}
|
||||
command_print(CMD, "adapter_nsrst_assert_width: %u", jtag_get_nsrst_assert_width());
|
||||
command_print(CMD, "adapter srst pulse_width: %u", jtag_get_nsrst_assert_width());
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_adapter_khz_command)
|
||||
COMMAND_HANDLER(handle_adapter_speed_command)
|
||||
{
|
||||
if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -411,6 +411,92 @@ COMMAND_HANDLER(handle_adapter_khz_command)
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_adapter_reset_de_assert)
|
||||
{
|
||||
enum values {
|
||||
VALUE_UNDEFINED = -1,
|
||||
VALUE_DEASSERT = 0,
|
||||
VALUE_ASSERT = 1,
|
||||
};
|
||||
enum values value;
|
||||
enum values srst = VALUE_UNDEFINED;
|
||||
enum values trst = VALUE_UNDEFINED;
|
||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||
char *signal;
|
||||
|
||||
if (CMD_ARGC == 0) {
|
||||
if (transport_is_jtag()) {
|
||||
if (jtag_reset_config & RESET_HAS_TRST)
|
||||
signal = jtag_get_trst() ? "asserted" : "deasserted";
|
||||
else
|
||||
signal = "not present";
|
||||
command_print(CMD, "trst %s", signal);
|
||||
}
|
||||
|
||||
if (jtag_reset_config & RESET_HAS_SRST)
|
||||
signal = jtag_get_srst() ? "asserted" : "deasserted";
|
||||
else
|
||||
signal = "not present";
|
||||
command_print(CMD, "srst %s", signal);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (CMD_ARGC != 1 && CMD_ARGC != 3)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
value = (strcmp(CMD_NAME, "assert") == 0) ? VALUE_ASSERT : VALUE_DEASSERT;
|
||||
if (strcmp(CMD_ARGV[0], "srst") == 0)
|
||||
srst = value;
|
||||
else if (strcmp(CMD_ARGV[0], "trst") == 0)
|
||||
trst = value;
|
||||
else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (CMD_ARGC == 3) {
|
||||
if (strcmp(CMD_ARGV[1], "assert") == 0)
|
||||
value = VALUE_ASSERT;
|
||||
else if (strcmp(CMD_ARGV[1], "deassert") == 0)
|
||||
value = VALUE_DEASSERT;
|
||||
else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (strcmp(CMD_ARGV[2], "srst") == 0 && srst == VALUE_UNDEFINED)
|
||||
srst = value;
|
||||
else if (strcmp(CMD_ARGV[2], "trst") == 0 && trst == VALUE_UNDEFINED)
|
||||
trst = value;
|
||||
else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (trst == VALUE_UNDEFINED) {
|
||||
if (transport_is_jtag())
|
||||
trst = jtag_get_trst() ? VALUE_ASSERT : VALUE_DEASSERT;
|
||||
else
|
||||
trst = VALUE_DEASSERT; /* unused, safe value */
|
||||
}
|
||||
|
||||
if (srst == VALUE_UNDEFINED) {
|
||||
if (jtag_reset_config & RESET_HAS_SRST)
|
||||
srst = jtag_get_srst() ? VALUE_ASSERT : VALUE_DEASSERT;
|
||||
else
|
||||
srst = VALUE_DEASSERT; /* unused, safe value */
|
||||
}
|
||||
|
||||
if (trst == VALUE_ASSERT && !transport_is_jtag()) {
|
||||
LOG_ERROR("transport has no trst signal");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (srst == VALUE_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
|
||||
LOG_ERROR("adapter has no srst signal");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return adapter_resets((trst == VALUE_DEASSERT) ? TRST_DEASSERT : TRST_ASSERT,
|
||||
(srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT);
|
||||
}
|
||||
|
||||
#ifndef HAVE_JTAG_MINIDRIVER_H
|
||||
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
|
||||
COMMAND_HANDLER(handle_usb_location_command)
|
||||
@@ -438,7 +524,70 @@ static const struct command_registration adapter_usb_command_handlers[] = {
|
||||
};
|
||||
#endif /* MINIDRIVER */
|
||||
|
||||
static const struct command_registration adapter_srst_command_handlers[] = {
|
||||
{
|
||||
.name = "delay",
|
||||
.handler = handle_adapter_srst_delay_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "delay after deasserting SRST in ms",
|
||||
.usage = "[milliseconds]",
|
||||
},
|
||||
{
|
||||
.name = "pulse_width",
|
||||
.handler = handle_adapter_srst_pulse_width_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "SRST assertion pulse width in ms",
|
||||
.usage = "[milliseconds]",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration adapter_command_handlers[] = {
|
||||
{
|
||||
.name = "driver",
|
||||
.handler = handle_adapter_driver_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Select a debug adapter driver",
|
||||
.usage = "driver_name",
|
||||
},
|
||||
{
|
||||
.name = "speed",
|
||||
.handler = handle_adapter_speed_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "With an argument, change to the specified maximum "
|
||||
"jtag speed. For JTAG, 0 KHz signifies adaptive "
|
||||
"clocking. "
|
||||
"With or without argument, display current setting.",
|
||||
.usage = "[khz]",
|
||||
},
|
||||
{
|
||||
.name = "list",
|
||||
.handler = handle_adapter_list_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "List all built-in debug adapter drivers",
|
||||
.usage = "",
|
||||
},
|
||||
{
|
||||
.name = "name",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_adapter_name,
|
||||
.help = "Returns the name of the currently "
|
||||
"selected adapter (driver)",
|
||||
},
|
||||
{
|
||||
.name = "srst",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "srst adapter command group",
|
||||
.usage = "",
|
||||
.chain = adapter_srst_command_handlers,
|
||||
},
|
||||
{
|
||||
.name = "transports",
|
||||
.handler = adapter_transports_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Declare transports the adapter supports.",
|
||||
.usage = "transport ... ",
|
||||
},
|
||||
#ifndef HAVE_JTAG_MINIDRIVER_H
|
||||
{
|
||||
.name = "usb",
|
||||
@@ -448,6 +597,20 @@ static const struct command_registration adapter_command_handlers[] = {
|
||||
.chain = adapter_usb_command_handlers,
|
||||
},
|
||||
#endif /* MINIDRIVER */
|
||||
{
|
||||
.name = "assert",
|
||||
.handler = handle_adapter_reset_de_assert,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Controls SRST and TRST lines.",
|
||||
.usage = "|deassert [srst|trst [assert|deassert srst|trst]]",
|
||||
},
|
||||
{
|
||||
.name = "deassert",
|
||||
.handler = handle_adapter_reset_de_assert,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "Controls SRST and TRST lines.",
|
||||
.usage = "|assert [srst|trst [deassert|assert srst|trst]]",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
@@ -459,58 +622,6 @@ static const struct command_registration interface_command_handlers[] = {
|
||||
.usage = "",
|
||||
.chain = adapter_command_handlers,
|
||||
},
|
||||
{
|
||||
.name = "adapter_khz",
|
||||
.handler = handle_adapter_khz_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "With an argument, change to the specified maximum "
|
||||
"jtag speed. For JTAG, 0 KHz signifies adaptive "
|
||||
" clocking. "
|
||||
"With or without argument, display current setting.",
|
||||
.usage = "[khz]",
|
||||
},
|
||||
{
|
||||
.name = "adapter_name",
|
||||
.mode = COMMAND_ANY,
|
||||
.jim_handler = jim_adapter_name,
|
||||
.help = "Returns the name of the currently "
|
||||
"selected adapter (driver)",
|
||||
},
|
||||
{
|
||||
.name = "adapter_nsrst_delay",
|
||||
.handler = handle_adapter_nsrst_delay_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "delay after deasserting SRST in ms",
|
||||
.usage = "[milliseconds]",
|
||||
},
|
||||
{
|
||||
.name = "adapter_nsrst_assert_width",
|
||||
.handler = handle_adapter_nsrst_assert_width_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "delay after asserting SRST in ms",
|
||||
.usage = "[milliseconds]",
|
||||
},
|
||||
{
|
||||
.name = "interface",
|
||||
.handler = handle_interface_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Select a debug adapter interface (driver)",
|
||||
.usage = "driver_name",
|
||||
},
|
||||
{
|
||||
.name = "interface_transports",
|
||||
.handler = interface_transport_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Declare transports the interface supports.",
|
||||
.usage = "transport ... ",
|
||||
},
|
||||
{
|
||||
.name = "interface_list",
|
||||
.handler = handle_interface_list_command,
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "List all built-in debug adapter interfaces (drivers)",
|
||||
.usage = "",
|
||||
},
|
||||
{
|
||||
.name = "reset_config",
|
||||
.handler = handle_reset_config_command,
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <transport/transport.h>
|
||||
#include <target/target.h>
|
||||
#include <jtag/aice/aice_transport.h>
|
||||
#include <jtag/drivers/libusb_common.h>
|
||||
#include "aice_usb.h"
|
||||
|
||||
#define AICE_KHZ_TO_SPEED_MAP_SIZE 16
|
||||
@@ -518,14 +517,20 @@ static const struct command_registration aice_command_handlers[] = {
|
||||
/***************************************************************************/
|
||||
/* End of Command handlers */
|
||||
|
||||
struct jtag_interface aice_interface = {
|
||||
static struct jtag_interface aice_interface = {
|
||||
.execute_queue = aice_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver aice_adapter_driver = {
|
||||
.name = "aice",
|
||||
.commands = aice_command_handlers,
|
||||
.transports = aice_transports,
|
||||
.commands = aice_command_handlers,
|
||||
|
||||
.init = aice_init,
|
||||
.quit = aice_quit,
|
||||
.execute_queue = aice_execute_queue,
|
||||
.speed = aice_speed, /* set interface speed */
|
||||
.speed_div = aice_speed_div, /* return readable value */
|
||||
.khz = aice_khz, /* convert khz to interface speed value */
|
||||
.speed_div = aice_speed_div, /* return readable value */
|
||||
|
||||
.jtag_ops = &aice_interface,
|
||||
};
|
||||
|
||||
@@ -47,6 +47,7 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi,
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
assert(pTap->expected_ids);
|
||||
memcpy(new_expected_ids, pTap->expected_ids, expected_len);
|
||||
|
||||
new_expected_ids[pTap->expected_ids_cnt] = w;
|
||||
@@ -173,7 +174,7 @@ COMMAND_HANDLER(handle_scan_chain_command)
|
||||
while (tap) {
|
||||
uint32_t expected, expected_mask, ii;
|
||||
|
||||
snprintf(expected_id, sizeof expected_id, "0x%08x",
|
||||
snprintf(expected_id, sizeof(expected_id), "0x%08x",
|
||||
(unsigned)((tap->expected_ids_cnt > 0)
|
||||
? tap->expected_ids[0]
|
||||
: 0));
|
||||
@@ -195,7 +196,7 @@ COMMAND_HANDLER(handle_scan_chain_command)
|
||||
(unsigned int)(expected_mask));
|
||||
|
||||
for (ii = 1; ii < tap->expected_ids_cnt; ii++) {
|
||||
snprintf(expected_id, sizeof expected_id, "0x%08x",
|
||||
snprintf(expected_id, sizeof(expected_id), "0x%08x",
|
||||
(unsigned) tap->expected_ids[ii]);
|
||||
if (tap->ignore_version)
|
||||
expected_id[2] = '*';
|
||||
@@ -442,4 +443,3 @@ static void aice_constructor(void)
|
||||
{
|
||||
transport_register(&aice_jtag_transport);
|
||||
}
|
||||
|
||||
|
||||
+50
-36
@@ -19,7 +19,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <jtag/drivers/libusb_common.h>
|
||||
#include <jtag/drivers/libusb_helper.h>
|
||||
#include <helper/log.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <target/target.h>
|
||||
@@ -349,41 +349,53 @@ static void aice_unpack_dthmb(uint8_t *cmd_ack_code, uint8_t *target_id,
|
||||
/* calls the given usb_bulk_* function, allowing for the data to
|
||||
* trickle in with some timeouts */
|
||||
static int usb_bulk_with_retries(
|
||||
int (*f)(jtag_libusb_device_handle *, int, char *, int, int),
|
||||
jtag_libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout)
|
||||
int (*f)(libusb_device_handle *, int, char *, int, int, int *),
|
||||
libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout, int *transferred)
|
||||
{
|
||||
int tries = 3, count = 0;
|
||||
|
||||
while (tries && (count < size)) {
|
||||
int result = f(dev, ep, bytes + count, size - count, timeout);
|
||||
if (result > 0)
|
||||
int result, ret;
|
||||
|
||||
ret = f(dev, ep, bytes + count, size - count, timeout, &result);
|
||||
if (ERROR_OK == ret)
|
||||
count += result;
|
||||
else if ((-ETIMEDOUT != result) || !--tries)
|
||||
return result;
|
||||
else if ((ERROR_TIMEOUT_REACHED != ret) || !--tries)
|
||||
return ret;
|
||||
}
|
||||
return count;
|
||||
|
||||
*transferred = count;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int wrap_usb_bulk_write(jtag_libusb_device_handle *dev, int ep,
|
||||
char *buff, int size, int timeout)
|
||||
static int wrap_usb_bulk_write(libusb_device_handle *dev, int ep,
|
||||
char *buff, int size, int timeout, int *transferred)
|
||||
{
|
||||
|
||||
/* usb_bulk_write() takes const char *buff */
|
||||
return jtag_libusb_bulk_write(dev, ep, buff, size, timeout);
|
||||
jtag_libusb_bulk_write(dev, ep, buff, size, timeout, transferred);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int usb_bulk_write_ex(jtag_libusb_device_handle *dev, int ep,
|
||||
static inline int usb_bulk_write_ex(libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout)
|
||||
{
|
||||
return usb_bulk_with_retries(&wrap_usb_bulk_write,
|
||||
dev, ep, bytes, size, timeout);
|
||||
int tr = 0;
|
||||
|
||||
usb_bulk_with_retries(&wrap_usb_bulk_write,
|
||||
dev, ep, bytes, size, timeout, &tr);
|
||||
return tr;
|
||||
}
|
||||
|
||||
static inline int usb_bulk_read_ex(jtag_libusb_device_handle *dev, int ep,
|
||||
static inline int usb_bulk_read_ex(struct libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout)
|
||||
{
|
||||
return usb_bulk_with_retries(&jtag_libusb_bulk_read,
|
||||
dev, ep, bytes, size, timeout);
|
||||
int tr = 0;
|
||||
usb_bulk_with_retries(&jtag_libusb_bulk_read,
|
||||
dev, ep, bytes, size, timeout, &tr);
|
||||
return tr;
|
||||
}
|
||||
|
||||
/* Write data from out_buffer to USB. */
|
||||
@@ -472,7 +484,9 @@ static int aice_usb_packet_flush(void)
|
||||
|
||||
i = 0;
|
||||
while (1) {
|
||||
aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status);
|
||||
int retval = aice_read_ctrl(AICE_READ_CTRL_BATCH_STATUS, &batch_status);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (batch_status & 0x1)
|
||||
return ERROR_OK;
|
||||
@@ -1785,8 +1799,8 @@ static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val);
|
||||
|
||||
static int check_suppressed_exception(uint32_t coreid, uint32_t dbger_value)
|
||||
{
|
||||
uint32_t ir4_value;
|
||||
uint32_t ir6_value;
|
||||
uint32_t ir4_value = 0;
|
||||
uint32_t ir6_value = 0;
|
||||
/* the default value of handling_suppressed_exception is false */
|
||||
static bool handling_suppressed_exception;
|
||||
|
||||
@@ -1840,7 +1854,7 @@ static int check_privilege(uint32_t coreid, uint32_t dbger_value)
|
||||
static int aice_check_dbger(uint32_t coreid, uint32_t expect_status)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t value_dbger;
|
||||
uint32_t value_dbger = 0;
|
||||
|
||||
while (1) {
|
||||
aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &value_dbger);
|
||||
@@ -1961,7 +1975,7 @@ static int aice_read_reg(uint32_t coreid, uint32_t num, uint32_t *val)
|
||||
|
||||
aice_execute_dim(coreid, instructions, 4);
|
||||
|
||||
uint32_t value_edmsw;
|
||||
uint32_t value_edmsw = 0;
|
||||
aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw);
|
||||
if (value_edmsw & NDS_EDMSW_WDV)
|
||||
aice_read_dtr(coreid, val);
|
||||
@@ -2006,7 +2020,7 @@ static int aice_write_reg(uint32_t coreid, uint32_t num, uint32_t val)
|
||||
LOG_DEBUG("aice_write_reg, reg_no: 0x%08" PRIx32 ", value: 0x%08" PRIx32, num, val);
|
||||
|
||||
uint32_t instructions[4]; /** execute instructions in DIM */
|
||||
uint32_t value_edmsw;
|
||||
uint32_t value_edmsw = 0;
|
||||
|
||||
aice_write_dtr(coreid, val);
|
||||
aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw);
|
||||
@@ -2095,9 +2109,9 @@ static int aice_usb_open(struct aice_port_param_s *param)
|
||||
{
|
||||
const uint16_t vids[] = { param->vid, 0 };
|
||||
const uint16_t pids[] = { param->pid, 0 };
|
||||
struct jtag_libusb_device_handle *devh;
|
||||
struct libusb_device_handle *devh;
|
||||
|
||||
if (jtag_libusb_open(vids, pids, NULL, &devh) != ERROR_OK)
|
||||
if (jtag_libusb_open(vids, pids, NULL, &devh, NULL) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS
|
||||
@@ -2113,7 +2127,7 @@ static int aice_usb_open(struct aice_port_param_s *param)
|
||||
|
||||
#if IS_WIN32 == 0
|
||||
|
||||
jtag_libusb_reset_device(devh);
|
||||
libusb_reset_device(devh);
|
||||
|
||||
#if IS_DARWIN == 0
|
||||
|
||||
@@ -2121,7 +2135,7 @@ static int aice_usb_open(struct aice_port_param_s *param)
|
||||
/* reopen jlink after usb_reset
|
||||
* on win32 this may take a second or two to re-enumerate */
|
||||
int retval;
|
||||
while ((retval = jtag_libusb_open(vids, pids, NULL, &devh)) != ERROR_OK) {
|
||||
while ((retval = jtag_libusb_open(vids, pids, NULL, &devh, NULL)) != ERROR_OK) {
|
||||
usleep(1000);
|
||||
timeout--;
|
||||
if (!timeout)
|
||||
@@ -2134,8 +2148,8 @@ static int aice_usb_open(struct aice_port_param_s *param)
|
||||
#endif
|
||||
|
||||
/* usb_set_configuration required under win32 */
|
||||
jtag_libusb_set_configuration(devh, 0);
|
||||
jtag_libusb_claim_interface(devh, 0);
|
||||
libusb_set_configuration(devh, 0);
|
||||
libusb_claim_interface(devh, 0);
|
||||
|
||||
unsigned int aice_read_ep;
|
||||
unsigned int aice_write_ep;
|
||||
@@ -2435,7 +2449,7 @@ static int aice_backup_tmp_registers(uint32_t coreid)
|
||||
LOG_DEBUG("backup_tmp_registers -");
|
||||
|
||||
/* backup target DTR first(if the target DTR is valid) */
|
||||
uint32_t value_edmsw;
|
||||
uint32_t value_edmsw = 0;
|
||||
aice_read_edmsr(coreid, NDS_EDM_SR_EDMSW, &value_edmsw);
|
||||
core_info[coreid].edmsw_backup = value_edmsw;
|
||||
if (value_edmsw & 0x1) { /* EDMSW.WDV == 1 */
|
||||
@@ -2602,13 +2616,13 @@ static int aice_usb_halt(uint32_t coreid)
|
||||
aice_init_edm_registers(coreid, false);
|
||||
|
||||
/** Clear EDM_CTL.DBGIM & EDM_CTL.DBGACKM */
|
||||
uint32_t edm_ctl_value;
|
||||
uint32_t edm_ctl_value = 0;
|
||||
aice_read_edmsr(coreid, NDS_EDM_SR_EDM_CTL, &edm_ctl_value);
|
||||
if (edm_ctl_value & 0x3)
|
||||
aice_write_edmsr(coreid, NDS_EDM_SR_EDM_CTL, edm_ctl_value & ~(0x3));
|
||||
|
||||
uint32_t dbger;
|
||||
uint32_t acc_ctl_value;
|
||||
uint32_t dbger = 0;
|
||||
uint32_t acc_ctl_value = 0;
|
||||
|
||||
core_info[coreid].debug_under_dex_on = false;
|
||||
aice_read_misc(coreid, NDS_EDM_MISC_DBGER, &dbger);
|
||||
@@ -2649,7 +2663,7 @@ static int aice_usb_halt(uint32_t coreid)
|
||||
* it is only for debugging 'debug exception handler' purpose.
|
||||
* after openocd detaches from target, target behavior is
|
||||
* undefined. */
|
||||
uint32_t ir0_value;
|
||||
uint32_t ir0_value = 0;
|
||||
uint32_t debug_mode_ir0_value;
|
||||
aice_read_reg(coreid, IR0, &ir0_value);
|
||||
debug_mode_ir0_value = ir0_value | 0x408; /* turn on DEX, set POM = 1 */
|
||||
@@ -4017,7 +4031,7 @@ static int aice_usb_profiling(uint32_t coreid, uint32_t interval, uint32_t itera
|
||||
|
||||
/* check status */
|
||||
uint32_t i;
|
||||
uint32_t batch_status;
|
||||
uint32_t batch_status = 0;
|
||||
|
||||
i = 0;
|
||||
while (1) {
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
struct aice_usb_handler_s {
|
||||
unsigned int usb_read_ep;
|
||||
unsigned int usb_write_ep;
|
||||
struct jtag_libusb_device_handle *usb_handle;
|
||||
struct libusb_device_handle *usb_handle;
|
||||
};
|
||||
|
||||
struct cache_info {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#endif
|
||||
|
||||
#include <jtag/jtag.h>
|
||||
#include <transport/transport.h>
|
||||
#include "commands.h"
|
||||
|
||||
struct cmd_queue_page {
|
||||
@@ -48,6 +49,19 @@ static struct jtag_command **next_command_pointer = &jtag_command_queue;
|
||||
|
||||
void jtag_queue_command(struct jtag_command *cmd)
|
||||
{
|
||||
if (!transport_is_jtag()) {
|
||||
/*
|
||||
* FIXME: This should not happen!
|
||||
* There could be old code that queues jtag commands with non jtag interfaces so, for
|
||||
* the moment simply highlight it by log an error.
|
||||
* We should fix it quitting with assert(0) because it is an internal error, or returning
|
||||
* an error after call to jtag_command_queue_reset() to free the jtag queue and avoid
|
||||
* memory leaks.
|
||||
* The fix can be applied immediately after next release (v0.11.0 ?)
|
||||
*/
|
||||
LOG_ERROR("JTAG API jtag_queue_command() called on non JTAG interface");
|
||||
}
|
||||
|
||||
/* this command goes on the end, so ensure the queue terminates */
|
||||
cmd->next = NULL;
|
||||
|
||||
|
||||
+301
-59
@@ -126,10 +126,10 @@ static int rclk_fallback_speed_khz;
|
||||
static enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode;
|
||||
static int jtag_speed;
|
||||
|
||||
static struct jtag_interface *jtag;
|
||||
/* FIXME: change name to this variable, it is not anymore JTAG only */
|
||||
static struct adapter_driver *jtag;
|
||||
|
||||
/* configuration */
|
||||
struct jtag_interface *jtag_interface;
|
||||
extern struct adapter_driver *adapter_driver;
|
||||
|
||||
void jtag_set_flush_queue_sleep(int ms)
|
||||
{
|
||||
@@ -503,7 +503,7 @@ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!(jtag->supported & DEBUG_CAP_TMS_SEQ))
|
||||
if (!(jtag->jtag_ops->supported & DEBUG_CAP_TMS_SEQ))
|
||||
return ERROR_JTAG_NOT_IMPLEMENTED;
|
||||
|
||||
jtag_checks();
|
||||
@@ -611,53 +611,42 @@ void jtag_add_clocks(int num_cycles)
|
||||
}
|
||||
}
|
||||
|
||||
void swd_add_reset(int req_srst)
|
||||
static int adapter_system_reset(int req_srst)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (req_srst) {
|
||||
if (!(jtag_reset_config & RESET_HAS_SRST)) {
|
||||
LOG_ERROR("BUG: can't assert SRST");
|
||||
jtag_set_error(ERROR_FAIL);
|
||||
return;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
req_srst = 1;
|
||||
}
|
||||
|
||||
/* Maybe change SRST signal state */
|
||||
if (jtag_srst != req_srst) {
|
||||
int retval;
|
||||
|
||||
retval = interface_jtag_add_reset(0, req_srst);
|
||||
if (retval != ERROR_OK)
|
||||
jtag_set_error(retval);
|
||||
else
|
||||
retval = jtag_execute_queue();
|
||||
|
||||
retval = jtag->reset(0, req_srst);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("TRST/SRST error");
|
||||
return;
|
||||
LOG_ERROR("SRST error");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* SRST resets everything hooked up to that signal */
|
||||
jtag_srst = req_srst;
|
||||
if (jtag_srst) {
|
||||
|
||||
if (req_srst) {
|
||||
LOG_DEBUG("SRST line asserted");
|
||||
if (adapter_nsrst_assert_width)
|
||||
jtag_add_sleep(adapter_nsrst_assert_width * 1000);
|
||||
jtag_sleep(adapter_nsrst_assert_width * 1000);
|
||||
} else {
|
||||
LOG_DEBUG("SRST line released");
|
||||
if (adapter_nsrst_delay)
|
||||
jtag_add_sleep(adapter_nsrst_delay * 1000);
|
||||
}
|
||||
|
||||
retval = jtag_execute_queue();
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("SRST timings error");
|
||||
return;
|
||||
jtag_sleep(adapter_nsrst_delay * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void jtag_add_reset(int req_tlr_or_trst, int req_srst)
|
||||
static void legacy_jtag_add_reset(int req_tlr_or_trst, int req_srst)
|
||||
{
|
||||
int trst_with_tlr = 0;
|
||||
int new_srst = 0;
|
||||
@@ -765,6 +754,119 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: name is misleading; we do not plan to "add" reset into jtag queue */
|
||||
void jtag_add_reset(int req_tlr_or_trst, int req_srst)
|
||||
{
|
||||
int retval;
|
||||
int trst_with_tlr = 0;
|
||||
int new_srst = 0;
|
||||
int new_trst = 0;
|
||||
|
||||
if (!jtag->reset) {
|
||||
legacy_jtag_add_reset(req_tlr_or_trst, req_srst);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Without SRST, we must use target-specific JTAG operations
|
||||
* on each target; callers should not be requesting SRST when
|
||||
* that signal doesn't exist.
|
||||
*
|
||||
* RESET_SRST_PULLS_TRST is a board or chip level quirk, which
|
||||
* can kick in even if the JTAG adapter can't drive TRST.
|
||||
*/
|
||||
if (req_srst) {
|
||||
if (!(jtag_reset_config & RESET_HAS_SRST)) {
|
||||
LOG_ERROR("BUG: can't assert SRST");
|
||||
jtag_set_error(ERROR_FAIL);
|
||||
return;
|
||||
}
|
||||
if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0
|
||||
&& !req_tlr_or_trst) {
|
||||
LOG_ERROR("BUG: can't assert only SRST");
|
||||
jtag_set_error(ERROR_FAIL);
|
||||
return;
|
||||
}
|
||||
new_srst = 1;
|
||||
}
|
||||
|
||||
/* JTAG reset (entry to TAP_RESET state) can always be achieved
|
||||
* using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE
|
||||
* state first. TRST accelerates it, and bypasses those states.
|
||||
*
|
||||
* RESET_TRST_PULLS_SRST is a board or chip level quirk, which
|
||||
* can kick in even if the JTAG adapter can't drive SRST.
|
||||
*/
|
||||
if (req_tlr_or_trst) {
|
||||
if (!(jtag_reset_config & RESET_HAS_TRST))
|
||||
trst_with_tlr = 1;
|
||||
else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0
|
||||
&& !req_srst)
|
||||
trst_with_tlr = 1;
|
||||
else
|
||||
new_trst = 1;
|
||||
}
|
||||
|
||||
/* Maybe change TRST and/or SRST signal state */
|
||||
if (jtag_srst != new_srst || jtag_trst != new_trst) {
|
||||
/* guarantee jtag queue empty before changing reset status */
|
||||
jtag_execute_queue();
|
||||
|
||||
retval = jtag->reset(new_trst, new_srst);
|
||||
if (retval != ERROR_OK) {
|
||||
jtag_set_error(retval);
|
||||
LOG_ERROR("TRST/SRST error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* SRST resets everything hooked up to that signal */
|
||||
if (jtag_srst != new_srst) {
|
||||
jtag_srst = new_srst;
|
||||
if (jtag_srst) {
|
||||
LOG_DEBUG("SRST line asserted");
|
||||
if (adapter_nsrst_assert_width)
|
||||
jtag_add_sleep(adapter_nsrst_assert_width * 1000);
|
||||
} else {
|
||||
LOG_DEBUG("SRST line released");
|
||||
if (adapter_nsrst_delay)
|
||||
jtag_add_sleep(adapter_nsrst_delay * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/* Maybe enter the JTAG TAP_RESET state ...
|
||||
* - using only TMS, TCK, and the JTAG state machine
|
||||
* - or else more directly, using TRST
|
||||
*
|
||||
* TAP_RESET should be invisible to non-debug parts of the system.
|
||||
*/
|
||||
if (trst_with_tlr) {
|
||||
LOG_DEBUG("JTAG reset with TLR instead of TRST");
|
||||
jtag_add_tlr();
|
||||
jtag_execute_queue();
|
||||
|
||||
} else if (jtag_trst != new_trst) {
|
||||
jtag_trst = new_trst;
|
||||
if (jtag_trst) {
|
||||
LOG_DEBUG("TRST line asserted");
|
||||
tap_set_state(TAP_RESET);
|
||||
if (jtag_ntrst_assert_width)
|
||||
jtag_add_sleep(jtag_ntrst_assert_width * 1000);
|
||||
} else {
|
||||
LOG_DEBUG("TRST line released");
|
||||
if (jtag_ntrst_delay)
|
||||
jtag_add_sleep(jtag_ntrst_delay * 1000);
|
||||
|
||||
/* We just asserted nTRST, so we're now in TAP_RESET.
|
||||
* Inform possible listeners about this, now that
|
||||
* JTAG instructions and data can be shifted. This
|
||||
* sequence must match jtag_add_tlr().
|
||||
*/
|
||||
jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
|
||||
jtag_notify_event(JTAG_TRST_ASSERTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jtag_add_sleep(uint32_t us)
|
||||
{
|
||||
/** @todo Here, keep_alive() appears to be a layering violation!!! */
|
||||
@@ -836,7 +938,88 @@ int default_interface_jtag_execute_queue(void)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return jtag->execute_queue();
|
||||
if (!transport_is_jtag()) {
|
||||
/*
|
||||
* FIXME: This should not happen!
|
||||
* There could be old code that queues jtag commands with non jtag interfaces so, for
|
||||
* the moment simply highlight it by log an error and return on empty execute_queue.
|
||||
* We should fix it quitting with assert(0) because it is an internal error.
|
||||
* The fix can be applied immediately after next release (v0.11.0 ?)
|
||||
*/
|
||||
LOG_ERROR("JTAG API jtag_execute_queue() called on non JTAG interface");
|
||||
if (!jtag->jtag_ops || !jtag->jtag_ops->execute_queue)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int result = jtag->jtag_ops->execute_queue();
|
||||
|
||||
#if !BUILD_ZY1000
|
||||
/* Only build this if we use a regular driver with a command queue.
|
||||
* Otherwise jtag_command_queue won't be found at compile/link time. Its
|
||||
* definition is in jtag/commands.c, which is only built/linked by
|
||||
* jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables
|
||||
* aren't accessible here. */
|
||||
struct jtag_command *cmd = jtag_command_queue;
|
||||
while (debug_level >= LOG_LVL_DEBUG && cmd) {
|
||||
switch (cmd->type) {
|
||||
case JTAG_SCAN:
|
||||
LOG_DEBUG_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);
|
||||
LOG_DEBUG_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);
|
||||
LOG_DEBUG_IO(" %db in: %s", field->num_bits, str);
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JTAG_TLR_RESET:
|
||||
LOG_DEBUG_IO("JTAG TLR RESET to %s",
|
||||
tap_state_name(cmd->cmd.statemove->end_state));
|
||||
break;
|
||||
case JTAG_RUNTEST:
|
||||
LOG_DEBUG_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"
|
||||
};
|
||||
LOG_DEBUG_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:
|
||||
LOG_DEBUG_IO("JTAG PATHMOVE (TODO)");
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
LOG_DEBUG_IO("JTAG SLEEP (TODO)");
|
||||
break;
|
||||
case JTAG_STABLECLOCKS:
|
||||
LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)");
|
||||
break;
|
||||
case JTAG_TMS:
|
||||
LOG_DEBUG_IO("JTAG TMS (TODO)");
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown JTAG command: %d", cmd->type);
|
||||
break;
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void jtag_execute_queue_noclear(void)
|
||||
@@ -1050,7 +1233,7 @@ static int jtag_examine_chain(void)
|
||||
/* Add room for end-of-chain marker. */
|
||||
max_taps++;
|
||||
|
||||
uint8_t *idcode_buffer = malloc(max_taps * 4);
|
||||
uint8_t *idcode_buffer = calloc(4, max_taps);
|
||||
if (idcode_buffer == NULL)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
@@ -1086,7 +1269,7 @@ static int jtag_examine_chain(void)
|
||||
* REVISIT create a jtag_alloc(chip, tap) routine, and
|
||||
* share it with jim_newtap_cmd().
|
||||
*/
|
||||
tap = calloc(1, sizeof *tap);
|
||||
tap = calloc(1, sizeof(*tap));
|
||||
if (!tap) {
|
||||
retval = ERROR_FAIL;
|
||||
goto out;
|
||||
@@ -1107,7 +1290,8 @@ static int jtag_examine_chain(void)
|
||||
|
||||
if ((idcode & 1) == 0) {
|
||||
/* Zero for LSB indicates a device in bypass */
|
||||
LOG_INFO("TAP %s has invalid IDCODE (0x%x)", tap->dotted_name, idcode);
|
||||
LOG_INFO("TAP %s does not have valid IDCODE (idcode=0x%x)",
|
||||
tap->dotted_name, idcode);
|
||||
tap->hasidcode = false;
|
||||
tap->idcode = 0;
|
||||
|
||||
@@ -1222,7 +1406,7 @@ static int jtag_validate_ircapture(void)
|
||||
&& tap->ir_length < JTAG_IRLEN_MAX) {
|
||||
tap->ir_length++;
|
||||
}
|
||||
LOG_WARNING("AUTO %s - use \"jtag newtap " "%s %s -irlen %d "
|
||||
LOG_WARNING("AUTO %s - use \"jtag newtap %s %s -irlen %d "
|
||||
"-expected-id 0x%08" PRIx32 "\"",
|
||||
tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode);
|
||||
}
|
||||
@@ -1335,18 +1519,18 @@ int adapter_init(struct command_context *cmd_ctx)
|
||||
if (jtag)
|
||||
return ERROR_OK;
|
||||
|
||||
if (!jtag_interface) {
|
||||
/* nothing was previously specified by "interface" command */
|
||||
if (!adapter_driver) {
|
||||
/* nothing was previously specified by "adapter driver" command */
|
||||
LOG_ERROR("Debug Adapter has to be specified, "
|
||||
"see \"interface\" command");
|
||||
"see \"adapter driver\" command");
|
||||
return ERROR_JTAG_INVALID_INTERFACE;
|
||||
}
|
||||
|
||||
int retval;
|
||||
retval = jtag_interface->init();
|
||||
retval = adapter_driver->init();
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
jtag = jtag_interface;
|
||||
jtag = adapter_driver;
|
||||
|
||||
if (jtag->speed == NULL) {
|
||||
LOG_INFO("This adapter doesn't support configurable speed");
|
||||
@@ -1355,7 +1539,7 @@ int adapter_init(struct command_context *cmd_ctx)
|
||||
|
||||
if (CLOCK_MODE_UNSELECTED == clock_mode) {
|
||||
LOG_ERROR("An adapter speed is not selected in the init script."
|
||||
" Insert a call to adapter_khz or jtag_rclk to proceed.");
|
||||
" Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed.");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
@@ -1486,17 +1670,19 @@ int adapter_quit(void)
|
||||
|
||||
int swd_init_reset(struct command_context *cmd_ctx)
|
||||
{
|
||||
int retval = adapter_init(cmd_ctx);
|
||||
int retval, retval1;
|
||||
|
||||
retval = adapter_init(cmd_ctx);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
LOG_DEBUG("Initializing with hard SRST reset");
|
||||
|
||||
if (jtag_reset_config & RESET_HAS_SRST)
|
||||
swd_add_reset(1);
|
||||
swd_add_reset(0);
|
||||
retval = jtag_execute_queue();
|
||||
return retval;
|
||||
retval = adapter_system_reset(1);
|
||||
retval1 = adapter_system_reset(0);
|
||||
|
||||
return (retval == ERROR_OK) ? retval1 : retval;
|
||||
}
|
||||
|
||||
int jtag_init_reset(struct command_context *cmd_ctx)
|
||||
@@ -1686,7 +1872,7 @@ void jtag_set_verify(bool enable)
|
||||
jtag_verify = enable;
|
||||
}
|
||||
|
||||
bool jtag_will_verify()
|
||||
bool jtag_will_verify(void)
|
||||
{
|
||||
return jtag_verify;
|
||||
}
|
||||
@@ -1696,7 +1882,7 @@ void jtag_set_verify_capture_ir(bool enable)
|
||||
jtag_verify_capture_ir = enable;
|
||||
}
|
||||
|
||||
bool jtag_will_verify_capture_ir()
|
||||
bool jtag_will_verify_capture_ir(void)
|
||||
{
|
||||
return jtag_verify_capture_ir;
|
||||
}
|
||||
@@ -1819,42 +2005,98 @@ bool transport_is_jtag(void)
|
||||
return get_current_transport() == &jtag_transport;
|
||||
}
|
||||
|
||||
void adapter_assert_reset(void)
|
||||
int adapter_resets(int trst, int srst)
|
||||
{
|
||||
if (get_current_transport() == NULL) {
|
||||
LOG_ERROR("transport is not selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (transport_is_jtag()) {
|
||||
if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
|
||||
LOG_ERROR("adapter has no srst signal");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* adapters without trst signal will eventually use tlr sequence */
|
||||
jtag_add_reset(trst, srst);
|
||||
/*
|
||||
* The jtag queue is still used for reset by some adapter. Flush it!
|
||||
* FIXME: To be removed when all adapter drivers will be updated!
|
||||
*/
|
||||
jtag_execute_queue();
|
||||
return ERROR_OK;
|
||||
} else if (transport_is_swd() || transport_is_hla() ||
|
||||
transport_is_dapdirect_swd() || transport_is_dapdirect_jtag() ||
|
||||
transport_is_swim()) {
|
||||
if (trst == TRST_ASSERT) {
|
||||
LOG_ERROR("transport %s has no trst signal",
|
||||
get_current_transport()->name);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (srst == SRST_ASSERT && !(jtag_reset_config & RESET_HAS_SRST)) {
|
||||
LOG_ERROR("adapter has no srst signal");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
adapter_system_reset(srst);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (trst == TRST_DEASSERT && srst == SRST_DEASSERT)
|
||||
return ERROR_OK;
|
||||
|
||||
LOG_ERROR("reset is not supported on transport %s",
|
||||
get_current_transport()->name);
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int adapter_assert_reset(void)
|
||||
{
|
||||
if (transport_is_jtag()) {
|
||||
if (jtag_reset_config & RESET_SRST_PULLS_TRST)
|
||||
jtag_add_reset(1, 1);
|
||||
else
|
||||
jtag_add_reset(0, 1);
|
||||
} else if (transport_is_swd())
|
||||
swd_add_reset(1);
|
||||
return ERROR_OK;
|
||||
} else if (transport_is_swd() || transport_is_hla() ||
|
||||
transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() ||
|
||||
transport_is_swim())
|
||||
return adapter_system_reset(1);
|
||||
else if (get_current_transport() != NULL)
|
||||
LOG_ERROR("reset is not supported on %s",
|
||||
get_current_transport()->name);
|
||||
else
|
||||
LOG_ERROR("transport is not selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
void adapter_deassert_reset(void)
|
||||
int adapter_deassert_reset(void)
|
||||
{
|
||||
if (transport_is_jtag())
|
||||
if (transport_is_jtag()) {
|
||||
jtag_add_reset(0, 0);
|
||||
else if (transport_is_swd())
|
||||
swd_add_reset(0);
|
||||
return ERROR_OK;
|
||||
} else if (transport_is_swd() || transport_is_hla() ||
|
||||
transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() ||
|
||||
transport_is_swim())
|
||||
return adapter_system_reset(0);
|
||||
else if (get_current_transport() != NULL)
|
||||
LOG_ERROR("reset is not supported on %s",
|
||||
get_current_transport()->name);
|
||||
else
|
||||
LOG_ERROR("transport is not selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
||||
uint32_t port_size, unsigned int *trace_freq)
|
||||
uint32_t port_size, unsigned int *trace_freq,
|
||||
unsigned int traceclkin_freq, uint16_t *prescaler)
|
||||
{
|
||||
if (jtag->config_trace)
|
||||
return jtag->config_trace(enabled, pin_protocol, port_size,
|
||||
trace_freq);
|
||||
else if (enabled) {
|
||||
if (jtag->config_trace) {
|
||||
return jtag->config_trace(enabled, pin_protocol, port_size, trace_freq,
|
||||
traceclkin_freq, prescaler);
|
||||
} else if (enabled) {
|
||||
LOG_ERROR("The selected interface does not support tracing");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ DRIVERFILES += %D%/driver.c
|
||||
DRIVERFILES += %D%/jtag_usb_common.c
|
||||
|
||||
if USE_LIBUSB1
|
||||
DRIVERFILES += %D%/libusb1_common.c
|
||||
DRIVERFILES += %D%/libusb_helper.c
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB1_CFLAGS)
|
||||
%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS)
|
||||
endif
|
||||
@@ -31,9 +31,6 @@ if USE_LIBUSB0
|
||||
DRIVERFILES += %D%/usb_common.c
|
||||
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB0_CFLAGS)
|
||||
%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB0_LIBS)
|
||||
if !USE_LIBUSB1
|
||||
DRIVERFILES += %D%/libusb0_common.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_LIBFTDI
|
||||
@@ -136,6 +133,9 @@ if HLADAPTER
|
||||
DRIVERFILES += %D%/stlink_usb.c
|
||||
DRIVERFILES += %D%/ti_icdi_usb.c
|
||||
endif
|
||||
if RSHIM
|
||||
DRIVERFILES += %D%/rshim.c
|
||||
endif
|
||||
if OSBDM
|
||||
DRIVERFILES += %D%/osbdm.c
|
||||
endif
|
||||
@@ -145,6 +145,9 @@ endif
|
||||
if SYSFSGPIO
|
||||
DRIVERFILES += %D%/sysfsgpio.c
|
||||
endif
|
||||
if XLNX_PCIE_XVC
|
||||
DRIVERFILES += %D%/xlnx-pcie-xvc.c
|
||||
endif
|
||||
if BCM2835GPIO
|
||||
DRIVERFILES += %D%/bcm2835gpio.c
|
||||
endif
|
||||
@@ -168,9 +171,7 @@ DRIVERHEADERS = \
|
||||
%D%/bitbang.h \
|
||||
%D%/bitq.h \
|
||||
%D%/jtag_usb_common.h \
|
||||
%D%/libusb0_common.h \
|
||||
%D%/libusb1_common.h \
|
||||
%D%/libusb_common.h \
|
||||
%D%/libusb_helper.h \
|
||||
%D%/minidriver_imp.h \
|
||||
%D%/mpsse.h \
|
||||
%D%/rlink.h \
|
||||
@@ -183,4 +184,3 @@ DRIVERHEADERS = \
|
||||
%D%/versaloon/versaloon.h \
|
||||
%D%/versaloon/versaloon_include.h \
|
||||
%D%/versaloon/versaloon_internal.h
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ int amt_jtagaccel_get_giveio_access(void)
|
||||
HANDLE h;
|
||||
OSVERSIONINFO version;
|
||||
|
||||
version.dwOSVersionInfoSize = sizeof version;
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
if (!GetVersionEx(&version)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -584,7 +584,11 @@ static const struct command_registration amtjtagaccel_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface amt_jtagaccel_interface = {
|
||||
static struct jtag_interface amt_jtagaccel_interface = {
|
||||
.execute_queue = amt_jtagaccel_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver amt_jtagaccel_adapter_driver = {
|
||||
.name = "amt_jtagaccel",
|
||||
.transports = jtag_only,
|
||||
.commands = amtjtagaccel_command_handlers,
|
||||
@@ -592,5 +596,6 @@ struct jtag_interface amt_jtagaccel_interface = {
|
||||
.init = amt_jtagaccel_init,
|
||||
.quit = amt_jtagaccel_quit,
|
||||
.speed = amt_jtagaccel_speed,
|
||||
.execute_queue = amt_jtagaccel_execute_queue,
|
||||
|
||||
.jtag_ops = &amt_jtagaccel_interface,
|
||||
};
|
||||
|
||||
@@ -107,7 +107,7 @@ static int armjtagew_execute_queue(void)
|
||||
switch (cmd->type) {
|
||||
case JTAG_RUNTEST:
|
||||
LOG_DEBUG_IO("runtest %i cycles, end in %i",
|
||||
cmd->cmd.runtest->num_cycles, \
|
||||
cmd->cmd.runtest->num_cycles,
|
||||
cmd->cmd.runtest->end_state);
|
||||
|
||||
armjtagew_end_state(cmd->cmd.runtest->end_state);
|
||||
@@ -122,8 +122,8 @@ static int armjtagew_execute_queue(void)
|
||||
break;
|
||||
|
||||
case JTAG_PATHMOVE:
|
||||
LOG_DEBUG_IO("pathmove: %i states, end in %i", \
|
||||
cmd->cmd.pathmove->num_states, \
|
||||
LOG_DEBUG_IO("pathmove: %i states, end in %i",
|
||||
cmd->cmd.pathmove->num_states,
|
||||
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
|
||||
|
||||
armjtagew_path_move(cmd->cmd.pathmove->num_states,
|
||||
@@ -459,10 +459,10 @@ static int armjtagew_get_version_info(void)
|
||||
auxinfo[256] = '\0';
|
||||
|
||||
LOG_INFO(
|
||||
"ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s", \
|
||||
"ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s",
|
||||
usb_in_buffer[1],
|
||||
usb_in_buffer[0], \
|
||||
isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X', \
|
||||
usb_in_buffer[0],
|
||||
isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X',
|
||||
sn,
|
||||
auxinfo);
|
||||
|
||||
@@ -495,16 +495,22 @@ static const struct command_registration armjtagew_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface armjtagew_interface = {
|
||||
.name = "arm-jtag-ew",
|
||||
.commands = armjtagew_command_handlers,
|
||||
.transports = jtag_only,
|
||||
static struct jtag_interface armjtagew_interface = {
|
||||
.execute_queue = armjtagew_execute_queue,
|
||||
.speed = armjtagew_speed,
|
||||
.speed_div = armjtagew_speed_div,
|
||||
.khz = armjtagew_khz,
|
||||
};
|
||||
|
||||
struct adapter_driver armjtagew_adapter_driver = {
|
||||
.name = "arm-jtag-ew",
|
||||
.transports = jtag_only,
|
||||
.commands = armjtagew_command_handlers,
|
||||
|
||||
.init = armjtagew_init,
|
||||
.quit = armjtagew_quit,
|
||||
.speed = armjtagew_speed,
|
||||
.khz = armjtagew_khz,
|
||||
.speed_div = armjtagew_speed_div,
|
||||
|
||||
.jtag_ops = &armjtagew_interface,
|
||||
};
|
||||
|
||||
/**************************************************************************
|
||||
@@ -677,7 +683,7 @@ static int armjtagew_tap_execute(void)
|
||||
/****************************************************************************
|
||||
* JLink USB low-level functions */
|
||||
|
||||
static struct armjtagew *armjtagew_usb_open()
|
||||
static struct armjtagew *armjtagew_usb_open(void)
|
||||
{
|
||||
usb_init();
|
||||
|
||||
@@ -744,7 +750,7 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, \
|
||||
result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT,
|
||||
(char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT);
|
||||
|
||||
LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result);
|
||||
@@ -758,7 +764,7 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
|
||||
/* Read data from USB into in_buffer. */
|
||||
static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length)
|
||||
{
|
||||
int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, \
|
||||
int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN,
|
||||
(char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT);
|
||||
|
||||
LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result);
|
||||
|
||||
@@ -111,7 +111,6 @@ static uint32_t *pio_base;
|
||||
*/
|
||||
static bb_value_t at91rm9200_read(void);
|
||||
static int at91rm9200_write(int tck, int tms, int tdi);
|
||||
static int at91rm9200_reset(int trst, int srst);
|
||||
|
||||
static int at91rm9200_init(void);
|
||||
static int at91rm9200_quit(void);
|
||||
@@ -119,7 +118,6 @@ static int at91rm9200_quit(void);
|
||||
static struct bitbang_interface at91rm9200_bitbang = {
|
||||
.read = at91rm9200_read,
|
||||
.write = at91rm9200_write,
|
||||
.reset = at91rm9200_reset,
|
||||
.blink = 0
|
||||
};
|
||||
|
||||
@@ -189,13 +187,20 @@ static const struct command_registration at91rm9200_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface at91rm9200_interface = {
|
||||
.name = "at91rm9200",
|
||||
static struct jtag_interface at91rm9200_interface = {
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver at91rm9200_adapter_driver = {
|
||||
.name = "at91rm9200",
|
||||
.transports = jtag_only,
|
||||
.commands = at91rm9200_command_handlers,
|
||||
|
||||
.init = at91rm9200_init,
|
||||
.quit = at91rm9200_quit,
|
||||
.reset = at91rm9200_reset,
|
||||
|
||||
.jtag_ops = &at91rm9200_interface,
|
||||
};
|
||||
|
||||
static int at91rm9200_init(void)
|
||||
|
||||
@@ -51,7 +51,6 @@ static volatile uint32_t *pio_base;
|
||||
|
||||
static bb_value_t bcm2835gpio_read(void);
|
||||
static int bcm2835gpio_write(int tck, int tms, int tdi);
|
||||
static int bcm2835gpio_reset(int trst, int srst);
|
||||
|
||||
static int bcm2835_swdio_read(void);
|
||||
static void bcm2835_swdio_drive(bool is_output);
|
||||
@@ -62,7 +61,6 @@ static int bcm2835gpio_quit(void);
|
||||
static struct bitbang_interface bcm2835gpio_bitbang = {
|
||||
.read = bcm2835gpio_read,
|
||||
.write = bcm2835gpio_write,
|
||||
.reset = bcm2835gpio_reset,
|
||||
.swdio_read = bcm2835_swdio_read,
|
||||
.swdio_drive = bcm2835_swdio_drive,
|
||||
.blink = NULL
|
||||
@@ -407,18 +405,25 @@ static const struct command_registration bcm2835gpio_command_handlers[] = {
|
||||
|
||||
static const char * const bcm2835_transports[] = { "jtag", "swd", NULL };
|
||||
|
||||
struct jtag_interface bcm2835gpio_interface = {
|
||||
.name = "bcm2835gpio",
|
||||
static struct jtag_interface bcm2835gpio_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver bcm2835gpio_adapter_driver = {
|
||||
.name = "bcm2835gpio",
|
||||
.transports = bcm2835_transports,
|
||||
.swd = &bitbang_swd,
|
||||
.commands = bcm2835gpio_command_handlers,
|
||||
|
||||
.init = bcm2835gpio_init,
|
||||
.quit = bcm2835gpio_quit,
|
||||
.reset = bcm2835gpio_reset,
|
||||
.speed = bcm2835gpio_speed,
|
||||
.khz = bcm2835gpio_khz,
|
||||
.speed_div = bcm2835gpio_speed_div,
|
||||
.commands = bcm2835gpio_command_handlers,
|
||||
.init = bcm2835gpio_init,
|
||||
.quit = bcm2835gpio_quit,
|
||||
|
||||
.jtag_ops = &bcm2835gpio_interface,
|
||||
.swd_ops = &bitbang_swd,
|
||||
};
|
||||
|
||||
static bool bcm2835gpio_jtag_mode_possible(void)
|
||||
@@ -461,7 +466,11 @@ static int bcm2835gpio_init(void)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
|
||||
if (dev_mem_fd < 0) {
|
||||
LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
|
||||
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
}
|
||||
if (dev_mem_fd < 0) {
|
||||
perror("open");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
@@ -314,17 +314,6 @@ int bitbang_execute_queue(void)
|
||||
|
||||
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);
|
||||
if (bitbang_interface->reset(cmd->cmd.reset->trst,
|
||||
cmd->cmd.reset->srst) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
case JTAG_RUNTEST:
|
||||
LOG_DEBUG_IO("runtest %i cycles, end in %s",
|
||||
cmd->cmd.runtest->num_cycles,
|
||||
|
||||
@@ -51,13 +51,12 @@ struct bitbang_interface {
|
||||
|
||||
/** Set TCK, TMS, and TDI to the given values. */
|
||||
int (*write)(int tck, int tms, int tdi);
|
||||
int (*reset)(int trst, int srst);
|
||||
int (*blink)(int on);
|
||||
int (*swdio_read)(void);
|
||||
void (*swdio_drive)(bool on);
|
||||
};
|
||||
|
||||
const struct swd_driver bitbang_swd;
|
||||
extern const struct swd_driver bitbang_swd;
|
||||
|
||||
extern bool swd_mode;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
static int buspirate_execute_queue(void);
|
||||
static int buspirate_init(void);
|
||||
static int buspirate_quit(void);
|
||||
static int buspirate_reset(int trst, int srst);
|
||||
|
||||
static void buspirate_end_state(tap_state_t state);
|
||||
static void buspirate_state_move(void);
|
||||
@@ -133,7 +134,6 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer,
|
||||
struct scan_command *command);
|
||||
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);
|
||||
@@ -213,18 +213,6 @@ static int buspirate_execute_queue(void)
|
||||
buffer, scan_size, cmd->cmd.scan);
|
||||
|
||||
break;
|
||||
case JTAG_RESET:
|
||||
LOG_DEBUG_IO("reset trst: %i srst %i",
|
||||
cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
|
||||
/* flush buffers, so we can reset */
|
||||
buspirate_tap_execute();
|
||||
|
||||
if (cmd->cmd.reset->trst == 1)
|
||||
tap_set_state(TAP_RESET);
|
||||
buspirate_reset(cmd->cmd.reset->trst,
|
||||
cmd->cmd.reset->srst);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
LOG_DEBUG_IO("sleep %i", cmd->cmd.sleep->us);
|
||||
buspirate_tap_execute();
|
||||
@@ -548,14 +536,21 @@ static const struct swd_driver buspirate_swd = {
|
||||
|
||||
static const char * const buspirate_transports[] = { "jtag", "swd", NULL };
|
||||
|
||||
struct jtag_interface buspirate_interface = {
|
||||
.name = "buspirate",
|
||||
static struct jtag_interface buspirate_interface = {
|
||||
.execute_queue = buspirate_execute_queue,
|
||||
.commands = buspirate_command_handlers,
|
||||
};
|
||||
|
||||
struct adapter_driver buspirate_adapter_driver = {
|
||||
.name = "buspirate",
|
||||
.transports = buspirate_transports,
|
||||
.swd = &buspirate_swd,
|
||||
.commands = buspirate_command_handlers,
|
||||
|
||||
.init = buspirate_init,
|
||||
.quit = buspirate_quit
|
||||
.quit = buspirate_quit,
|
||||
.reset = buspirate_reset,
|
||||
|
||||
.jtag_ops = &buspirate_interface,
|
||||
.swd_ops = &buspirate_swd,
|
||||
};
|
||||
|
||||
/*************** jtag execute commands **********************/
|
||||
@@ -860,7 +855,7 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer,
|
||||
/*************** wrapper functions *********************/
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
static void buspirate_reset(int trst, int srst)
|
||||
static int buspirate_reset(int trst, int srst)
|
||||
{
|
||||
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
|
||||
|
||||
@@ -873,6 +868,8 @@ static void buspirate_reset(int trst, int srst)
|
||||
buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE);
|
||||
else
|
||||
buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void buspirate_set_feature(int fd, char feat, char action)
|
||||
|
||||
@@ -364,8 +364,6 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
|
||||
free(pending_fifo[i].transfers);
|
||||
pending_fifo[i].transfers = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen)
|
||||
@@ -509,15 +507,15 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cmsis_dap_cmd_DAP_LED(uint8_t leds)
|
||||
static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state)
|
||||
{
|
||||
int retval;
|
||||
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
|
||||
|
||||
buffer[0] = 0; /* report number */
|
||||
buffer[1] = CMD_DAP_LED;
|
||||
buffer[2] = 0x00;
|
||||
buffer[3] = leds;
|
||||
buffer[2] = led;
|
||||
buffer[3] = state;
|
||||
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4);
|
||||
|
||||
if (retval != ERROR_OK || buffer[1] != 0x00) {
|
||||
@@ -1086,8 +1084,12 @@ static int cmsis_dap_init(void)
|
||||
if (retval != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
/* Both LEDs on */
|
||||
retval = cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_ON);
|
||||
if (retval != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */
|
||||
retval = cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_ON);
|
||||
if (retval != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
@@ -1102,9 +1104,6 @@ static int cmsis_dap_init(void)
|
||||
LOG_INFO("Connecting under reset");
|
||||
}
|
||||
}
|
||||
|
||||
cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */
|
||||
|
||||
LOG_INFO("CMSIS-DAP: Interface ready");
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -1119,28 +1118,31 @@ static int cmsis_dap_swd_init(void)
|
||||
static int cmsis_dap_quit(void)
|
||||
{
|
||||
cmsis_dap_cmd_DAP_Disconnect();
|
||||
cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */
|
||||
/* Both LEDs off */
|
||||
cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_OFF);
|
||||
cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_OFF);
|
||||
|
||||
cmsis_dap_usb_close(cmsis_dap_handle);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void cmsis_dap_execute_reset(struct jtag_command *cmd)
|
||||
static int cmsis_dap_reset(int trst, int srst)
|
||||
{
|
||||
/* Set both TRST and SRST even if they're not enabled as
|
||||
* there's no way to tristate them */
|
||||
|
||||
output_pins = 0;
|
||||
if (!cmd->cmd.reset->srst)
|
||||
if (!srst)
|
||||
output_pins |= SWJ_PIN_SRST;
|
||||
if (!cmd->cmd.reset->trst)
|
||||
if (!trst)
|
||||
output_pins |= SWJ_PIN_TRST;
|
||||
|
||||
int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins,
|
||||
SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("CMSIS-DAP: Interface reset failed");
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void cmsis_dap_execute_sleep(struct jtag_command *cmd)
|
||||
@@ -1581,10 +1583,6 @@ static void cmsis_dap_execute_tms(struct jtag_command *cmd)
|
||||
static void cmsis_dap_execute_command(struct jtag_command *cmd)
|
||||
{
|
||||
switch (cmd->type) {
|
||||
case JTAG_RESET:
|
||||
cmsis_dap_flush();
|
||||
cmsis_dap_execute_reset(cmd);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
cmsis_dap_flush();
|
||||
cmsis_dap_execute_sleep(cmd);
|
||||
@@ -1631,10 +1629,10 @@ static int cmsis_dap_execute_queue(void)
|
||||
static int cmsis_dap_speed(int speed)
|
||||
{
|
||||
if (speed > DAP_MAX_CLOCK)
|
||||
LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed);
|
||||
LOG_INFO("High speed (adapter speed %d) may be limited by adapter firmware.", speed);
|
||||
|
||||
if (speed == 0) {
|
||||
LOG_ERROR("RTCK not supported. Set nonzero adapter_khz.");
|
||||
LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\".");
|
||||
return ERROR_JTAG_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -1789,17 +1787,23 @@ static const struct swd_driver cmsis_dap_swd_driver = {
|
||||
|
||||
static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL };
|
||||
|
||||
struct jtag_interface cmsis_dap_interface = {
|
||||
.name = "cmsis-dap",
|
||||
static struct jtag_interface cmsis_dap_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.commands = cmsis_dap_command_handlers,
|
||||
.swd = &cmsis_dap_swd_driver,
|
||||
.transports = cmsis_dap_transport,
|
||||
|
||||
.execute_queue = cmsis_dap_execute_queue,
|
||||
.speed = cmsis_dap_speed,
|
||||
.speed_div = cmsis_dap_speed_div,
|
||||
.khz = cmsis_dap_khz,
|
||||
};
|
||||
|
||||
struct adapter_driver cmsis_dap_adapter_driver = {
|
||||
.name = "cmsis-dap",
|
||||
.transports = cmsis_dap_transport,
|
||||
.commands = cmsis_dap_command_handlers,
|
||||
|
||||
.init = cmsis_dap_init,
|
||||
.quit = cmsis_dap_quit,
|
||||
.reset = cmsis_dap_reset,
|
||||
.speed = cmsis_dap_speed,
|
||||
.khz = cmsis_dap_khz,
|
||||
.speed_div = cmsis_dap_speed_div,
|
||||
|
||||
.jtag_ops = &cmsis_dap_interface,
|
||||
.swd_ops = &cmsis_dap_swd_driver,
|
||||
};
|
||||
|
||||
+16
-14
@@ -91,7 +91,6 @@ static int dummy_led(int on)
|
||||
static struct bitbang_interface dummy_bitbang = {
|
||||
.read = &dummy_read,
|
||||
.write = &dummy_write,
|
||||
.reset = &dummy_reset,
|
||||
.blink = &dummy_led,
|
||||
};
|
||||
|
||||
@@ -145,19 +144,22 @@ static const struct command_registration dummy_command_handlers[] = {
|
||||
/* The dummy driver is used to easily check the code path
|
||||
* where the target is unresponsive.
|
||||
*/
|
||||
struct jtag_interface dummy_interface = {
|
||||
.name = "dummy",
|
||||
static struct jtag_interface dummy_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.execute_queue = &bitbang_execute_queue,
|
||||
};
|
||||
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.commands = dummy_command_handlers,
|
||||
.transports = jtag_only,
|
||||
struct adapter_driver dummy_adapter_driver = {
|
||||
.name = "dummy",
|
||||
.transports = jtag_only,
|
||||
.commands = dummy_command_handlers,
|
||||
|
||||
.execute_queue = &bitbang_execute_queue,
|
||||
.init = &dummy_init,
|
||||
.quit = &dummy_quit,
|
||||
.reset = &dummy_reset,
|
||||
.speed = &dummy_speed,
|
||||
.khz = &dummy_khz,
|
||||
.speed_div = &dummy_speed_div,
|
||||
|
||||
.speed = &dummy_speed,
|
||||
.khz = &dummy_khz,
|
||||
.speed_div = &dummy_speed_div,
|
||||
|
||||
.init = &dummy_init,
|
||||
.quit = &dummy_quit,
|
||||
};
|
||||
.jtag_ops = &dummy_interface,
|
||||
};
|
||||
|
||||
@@ -50,21 +50,25 @@ static int ep93xx_quit(void);
|
||||
|
||||
struct timespec ep93xx_zzzz;
|
||||
|
||||
struct jtag_interface ep93xx_interface = {
|
||||
.name = "ep93xx",
|
||||
|
||||
static struct jtag_interface ep93xx_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver ep93xx_adapter_driver = {
|
||||
.name = "ep93xx",
|
||||
.transports = jtag_only,
|
||||
|
||||
.init = ep93xx_init,
|
||||
.quit = ep93xx_quit,
|
||||
.reset = ep93xx_reset,
|
||||
|
||||
.jtag_ops = &ep93xx_interface,
|
||||
};
|
||||
|
||||
static struct bitbang_interface ep93xx_bitbang = {
|
||||
.read = ep93xx_read,
|
||||
.write = ep93xx_write,
|
||||
.reset = ep93xx_reset,
|
||||
.blink = 0,
|
||||
};
|
||||
|
||||
|
||||
+23
-21
@@ -29,7 +29,7 @@
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <helper/time_support.h>
|
||||
#include "libusb1_common.h"
|
||||
#include "libusb_helper.h"
|
||||
|
||||
/* system includes */
|
||||
#include <string.h>
|
||||
@@ -71,7 +71,7 @@
|
||||
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 struct libusb_device_handle *adapter;
|
||||
|
||||
static uint8_t *ft232r_output;
|
||||
static size_t ft232r_output_len;
|
||||
@@ -132,11 +132,11 @@ static int ft232r_send_recv(void)
|
||||
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);
|
||||
int n;
|
||||
|
||||
if (n == 0) {
|
||||
if (jtag_libusb_bulk_write(adapter, IN_EP,
|
||||
(char *) ft232r_output + total_written,
|
||||
bytes_to_write, 1000, &n) != ERROR_OK) {
|
||||
LOG_ERROR("usb bulk write failed");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
@@ -147,12 +147,10 @@ static int ft232r_send_recv(void)
|
||||
|
||||
/* Read */
|
||||
uint8_t reply[64];
|
||||
int n;
|
||||
|
||||
int n = jtag_libusb_bulk_read(adapter, OUT_EP,
|
||||
(char *) reply,
|
||||
sizeof(reply), 1000);
|
||||
|
||||
if (n == 0) {
|
||||
if (jtag_libusb_bulk_read(adapter, OUT_EP, (char *) reply,
|
||||
sizeof(reply), 1000, &n) != ERROR_OK) {
|
||||
LOG_ERROR("usb bulk read failed");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
@@ -259,7 +257,7 @@ 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)) {
|
||||
if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter, NULL)) {
|
||||
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;
|
||||
@@ -270,7 +268,7 @@ static int ft232r_init(void)
|
||||
else /* serial port will be restored after jtag: */
|
||||
libusb_set_auto_detach_kernel_driver(adapter, 1); /* 1: DONT_DETACH_SIO_MODULE */
|
||||
|
||||
if (jtag_libusb_claim_interface(adapter, 0)) {
|
||||
if (libusb_claim_interface(adapter, 0)) {
|
||||
LOG_ERROR("unable to claim interface");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
@@ -332,7 +330,7 @@ static int ft232r_quit(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (jtag_libusb_release_interface(adapter, 0) != 0)
|
||||
if (libusb_release_interface(adapter, 0) != 0)
|
||||
LOG_ERROR("usb release interface failed");
|
||||
|
||||
jtag_libusb_close(adapter);
|
||||
@@ -914,17 +912,21 @@ static int syncbb_execute_queue(void)
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct jtag_interface ft232r_interface = {
|
||||
.name = "ft232r",
|
||||
.commands = ft232r_command_handlers,
|
||||
.transports = jtag_only,
|
||||
static struct jtag_interface ft232r_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
|
||||
.execute_queue = syncbb_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver ft232r_adapter_driver = {
|
||||
.name = "ft232r",
|
||||
.transports = jtag_only,
|
||||
.commands = ft232r_command_handlers,
|
||||
|
||||
.speed = ft232r_speed,
|
||||
.init = ft232r_init,
|
||||
.quit = ft232r_quit,
|
||||
.speed_div = ft232r_speed_div,
|
||||
.speed = ft232r_speed,
|
||||
.khz = ft232r_khz,
|
||||
.speed_div = ft232r_speed_div,
|
||||
|
||||
.jtag_ops = &ft232r_interface,
|
||||
};
|
||||
|
||||
+37
-32
@@ -249,7 +249,7 @@ static int ftdi_set_signal(const struct signal *s, char value)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ftdi_get_signal(const struct signal *s, uint16_t * value_out)
|
||||
static int ftdi_get_signal(const struct signal *s, uint16_t *value_out)
|
||||
{
|
||||
uint8_t data_low = 0;
|
||||
uint8_t data_high = 0;
|
||||
@@ -582,46 +582,40 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
|
||||
tap_state_name(tap_get_end_state()));
|
||||
}
|
||||
|
||||
static void ftdi_execute_reset(struct jtag_command *cmd)
|
||||
static int ftdi_reset(int trst, int srst)
|
||||
{
|
||||
LOG_DEBUG_IO("reset trst: %i srst %i",
|
||||
cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
struct signal *sig_ntrst = find_signal_by_name("nTRST");
|
||||
struct signal *sig_nsrst = find_signal_by_name("nSRST");
|
||||
|
||||
if (cmd->cmd.reset->trst == 1
|
||||
|| (cmd->cmd.reset->srst
|
||||
&& (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
|
||||
tap_set_state(TAP_RESET);
|
||||
LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst);
|
||||
|
||||
struct signal *trst = find_signal_by_name("nTRST");
|
||||
if (cmd->cmd.reset->trst == 1) {
|
||||
if (trst)
|
||||
ftdi_set_signal(trst, '0');
|
||||
if (trst == 1) {
|
||||
if (sig_ntrst)
|
||||
ftdi_set_signal(sig_ntrst, '0');
|
||||
else
|
||||
LOG_ERROR("Can't assert TRST: nTRST signal is not defined");
|
||||
} else if (trst && jtag_get_reset_config() & RESET_HAS_TRST &&
|
||||
cmd->cmd.reset->trst == 0) {
|
||||
} else if (sig_ntrst && jtag_get_reset_config() & RESET_HAS_TRST &&
|
||||
trst == 0) {
|
||||
if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
|
||||
ftdi_set_signal(trst, 'z');
|
||||
ftdi_set_signal(sig_ntrst, 'z');
|
||||
else
|
||||
ftdi_set_signal(trst, '1');
|
||||
ftdi_set_signal(sig_ntrst, '1');
|
||||
}
|
||||
|
||||
struct signal *srst = find_signal_by_name("nSRST");
|
||||
if (cmd->cmd.reset->srst == 1) {
|
||||
if (srst)
|
||||
ftdi_set_signal(srst, '0');
|
||||
if (srst == 1) {
|
||||
if (sig_nsrst)
|
||||
ftdi_set_signal(sig_nsrst, '0');
|
||||
else
|
||||
LOG_ERROR("Can't assert SRST: nSRST signal is not defined");
|
||||
} else if (srst && jtag_get_reset_config() & RESET_HAS_SRST &&
|
||||
cmd->cmd.reset->srst == 0) {
|
||||
} else if (sig_nsrst && jtag_get_reset_config() & RESET_HAS_SRST &&
|
||||
srst == 0) {
|
||||
if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
|
||||
ftdi_set_signal(srst, '1');
|
||||
ftdi_set_signal(sig_nsrst, '1');
|
||||
else
|
||||
ftdi_set_signal(srst, 'z');
|
||||
ftdi_set_signal(sig_nsrst, 'z');
|
||||
}
|
||||
|
||||
LOG_DEBUG_IO("trst: %i, srst: %i",
|
||||
cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
return mpsse_flush(mpsse_ctx);
|
||||
}
|
||||
|
||||
static void ftdi_execute_sleep(struct jtag_command *cmd)
|
||||
@@ -727,6 +721,11 @@ static int ftdi_initialize(void)
|
||||
else
|
||||
LOG_DEBUG("ftdi interface using shortest path jtag state transitions");
|
||||
|
||||
if (!ftdi_vid[0] && !ftdi_pid[0]) {
|
||||
LOG_ERROR("Please specify ftdi_vid_pid");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) {
|
||||
mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc,
|
||||
ftdi_serial, jtag_usb_get_location(), ftdi_channel);
|
||||
@@ -1592,17 +1591,23 @@ static const struct swd_driver ftdi_swd = {
|
||||
|
||||
static const char * const ftdi_transports[] = { "jtag", "swd", NULL };
|
||||
|
||||
struct jtag_interface ftdi_interface = {
|
||||
.name = "ftdi",
|
||||
static struct jtag_interface ftdi_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.commands = ftdi_command_handlers,
|
||||
.execute_queue = ftdi_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver ftdi_adapter_driver = {
|
||||
.name = "ftdi",
|
||||
.transports = ftdi_transports,
|
||||
.swd = &ftdi_swd,
|
||||
.commands = ftdi_command_handlers,
|
||||
|
||||
.init = ftdi_initialize,
|
||||
.quit = ftdi_quit,
|
||||
.reset = ftdi_reset,
|
||||
.speed = ftdi_speed,
|
||||
.speed_div = ftdi_speed_div,
|
||||
.khz = ftdi_khz,
|
||||
.execute_queue = ftdi_execute_queue,
|
||||
.speed_div = ftdi_speed_div,
|
||||
|
||||
.jtag_ops = &ftdi_interface,
|
||||
.swd_ops = &ftdi_swd,
|
||||
};
|
||||
|
||||
@@ -350,7 +350,7 @@ static int gw16012_get_giveio_access(void)
|
||||
HANDLE h;
|
||||
OSVERSIONINFO version;
|
||||
|
||||
version.dwOSVersionInfoSize = sizeof version;
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
if (!GetVersionEx(&version)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -448,7 +448,7 @@ static int gw16012_init_device(void)
|
||||
LOG_WARNING("No gw16012 port specified, using default '0x378' (LPT1)");
|
||||
}
|
||||
|
||||
LOG_DEBUG("requesting privileges for parallel port 0x%lx...", (long unsigned)(gw16012_port));
|
||||
LOG_DEBUG("requesting privileges for parallel port 0x%" PRIx16 "...", gw16012_port);
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
if (gw16012_get_giveio_access() != 0) {
|
||||
#else /* PARPORT_USE_GIVEIO */
|
||||
@@ -521,12 +521,17 @@ static const struct command_registration gw16012_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface gw16012_interface = {
|
||||
static struct jtag_interface gw16012_interface = {
|
||||
.execute_queue = gw16012_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver gw16012_adapter_driver = {
|
||||
.name = "gw16012",
|
||||
.transports = jtag_only,
|
||||
.commands = gw16012_command_handlers,
|
||||
|
||||
.init = gw16012_init,
|
||||
.quit = gw16012_quit,
|
||||
.execute_queue = gw16012_execute_queue,
|
||||
|
||||
.jtag_ops = &gw16012_interface,
|
||||
};
|
||||
|
||||
@@ -84,7 +84,6 @@ static inline bool gpio_level(int g)
|
||||
|
||||
static bb_value_t imx_gpio_read(void);
|
||||
static int imx_gpio_write(int tck, int tms, int tdi);
|
||||
static int imx_gpio_reset(int trst, int srst);
|
||||
|
||||
static int imx_gpio_swdio_read(void);
|
||||
static void imx_gpio_swdio_drive(bool is_output);
|
||||
@@ -95,7 +94,6 @@ static int imx_gpio_quit(void);
|
||||
static struct bitbang_interface imx_gpio_bitbang = {
|
||||
.read = imx_gpio_read,
|
||||
.write = imx_gpio_write,
|
||||
.reset = imx_gpio_reset,
|
||||
.swdio_read = imx_gpio_swdio_read,
|
||||
.swdio_drive = imx_gpio_swdio_drive,
|
||||
.blink = NULL
|
||||
@@ -429,18 +427,25 @@ static const struct command_registration imx_gpio_command_handlers[] = {
|
||||
|
||||
static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL };
|
||||
|
||||
struct jtag_interface imx_gpio_interface = {
|
||||
.name = "imx_gpio",
|
||||
static struct jtag_interface imx_gpio_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver imx_gpio_adapter_driver = {
|
||||
.name = "imx_gpio",
|
||||
.transports = imx_gpio_transports,
|
||||
.swd = &bitbang_swd,
|
||||
.commands = imx_gpio_command_handlers,
|
||||
|
||||
.init = imx_gpio_init,
|
||||
.quit = imx_gpio_quit,
|
||||
.reset = imx_gpio_reset,
|
||||
.speed = imx_gpio_speed,
|
||||
.khz = imx_gpio_khz,
|
||||
.speed_div = imx_gpio_speed_div,
|
||||
.commands = imx_gpio_command_handlers,
|
||||
.init = imx_gpio_init,
|
||||
.quit = imx_gpio_quit,
|
||||
|
||||
.jtag_ops = &imx_gpio_interface,
|
||||
.swd_ops = &bitbang_swd,
|
||||
};
|
||||
|
||||
static bool imx_gpio_jtag_mode_possible(void)
|
||||
|
||||
+117
-52
@@ -39,6 +39,7 @@
|
||||
#include <jtag/swd.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <jtag/drivers/jtag_usb_common.h>
|
||||
#include <target/cortex_m.h>
|
||||
|
||||
#include <libjaylink/libjaylink.h>
|
||||
|
||||
@@ -62,6 +63,9 @@ static bool trace_enabled;
|
||||
|
||||
static unsigned int swd_buffer_size = JLINK_TAP_BUFFER_SIZE;
|
||||
|
||||
/* Maximum SWO frequency deviation. */
|
||||
#define SWO_MAX_FREQ_DEV 0.03
|
||||
|
||||
/* 256 byte non-volatile memory */
|
||||
struct device_config {
|
||||
uint8_t usb_address;
|
||||
@@ -90,6 +94,7 @@ static void jlink_path_move(int num_states, tap_state_t *path);
|
||||
static void jlink_stableclocks(int num_cycles);
|
||||
static void jlink_runtest(int num_cycles);
|
||||
static void jlink_reset(int trst, int srst);
|
||||
static int jlink_reset_safe(int trst, int srst);
|
||||
static int jlink_swd_run_queue(void);
|
||||
static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk);
|
||||
static int jlink_swd_switch_seq(enum swd_special_seq seq);
|
||||
@@ -247,16 +252,6 @@ static void jlink_execute_scan(struct jtag_command *cmd)
|
||||
tap_state_name(tap_get_end_state()));
|
||||
}
|
||||
|
||||
static void jlink_execute_reset(struct jtag_command *cmd)
|
||||
{
|
||||
LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst,
|
||||
cmd->cmd.reset->srst);
|
||||
|
||||
jlink_flush();
|
||||
jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
jlink_flush();
|
||||
}
|
||||
|
||||
static void jlink_execute_sleep(struct jtag_command *cmd)
|
||||
{
|
||||
LOG_DEBUG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us);
|
||||
@@ -282,9 +277,6 @@ static int jlink_execute_command(struct jtag_command *cmd)
|
||||
case JTAG_SCAN:
|
||||
jlink_execute_scan(cmd);
|
||||
break;
|
||||
case JTAG_RESET:
|
||||
jlink_execute_reset(cmd);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
jlink_execute_sleep(cmd);
|
||||
break;
|
||||
@@ -952,6 +944,13 @@ static void jlink_reset(int trst, int srst)
|
||||
jaylink_jtag_set_trst(devh);
|
||||
}
|
||||
|
||||
static int jlink_reset_safe(int trst, int srst)
|
||||
{
|
||||
jlink_flush();
|
||||
jlink_reset(trst, srst);
|
||||
return jlink_flush();
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jlink_usb_command)
|
||||
{
|
||||
int tmp;
|
||||
@@ -1267,55 +1266,74 @@ static uint32_t calculate_trace_buffer_size(void)
|
||||
return tmp & 0xffffff00;
|
||||
}
|
||||
|
||||
static bool check_trace_freq(struct jaylink_swo_speed speed,
|
||||
uint32_t trace_freq)
|
||||
static bool calculate_swo_prescaler(unsigned int traceclkin_freq,
|
||||
uint32_t trace_freq, uint16_t *prescaler)
|
||||
{
|
||||
double min;
|
||||
unsigned int presc;
|
||||
double deviation;
|
||||
|
||||
presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / trace_freq + 1;
|
||||
|
||||
if (presc > TPIU_ACPR_MAX_SWOSCALER)
|
||||
return false;
|
||||
|
||||
deviation = fabs(1.0 - ((double)trace_freq * presc / traceclkin_freq));
|
||||
|
||||
if (deviation > SWO_MAX_FREQ_DEV)
|
||||
return false;
|
||||
|
||||
*prescaler = presc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed,
|
||||
unsigned int traceclkin_freq, uint32_t *trace_freq,
|
||||
uint16_t *prescaler)
|
||||
{
|
||||
uint32_t divider;
|
||||
unsigned int presc;
|
||||
double deviation;
|
||||
|
||||
min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div)));
|
||||
for (divider = speed.min_div; divider <= speed.max_div; divider++) {
|
||||
*trace_freq = speed.freq / divider;
|
||||
presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1;
|
||||
|
||||
for (divider = speed.min_div; divider < speed.max_div; divider++) {
|
||||
deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider)));
|
||||
if (presc > TPIU_ACPR_MAX_SWOSCALER)
|
||||
break;
|
||||
|
||||
if (deviation < 0.03) {
|
||||
LOG_DEBUG("Found suitable frequency divider %u with deviation of "
|
||||
"%.02f %%.", divider, deviation);
|
||||
deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq));
|
||||
|
||||
if (deviation <= SWO_MAX_FREQ_DEV) {
|
||||
*prescaler = presc;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (deviation < min)
|
||||
min = deviation;
|
||||
}
|
||||
|
||||
LOG_ERROR("Selected trace frequency is not supported by the device. "
|
||||
"Please choose a different trace frequency.");
|
||||
LOG_ERROR("Maximum permitted deviation is 3.00 %%, but only %.02f %% "
|
||||
"could be achieved.", min * 100);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
||||
uint32_t port_size, unsigned int *trace_freq)
|
||||
uint32_t port_size, unsigned int *trace_freq,
|
||||
unsigned int traceclkin_freq, uint16_t *prescaler)
|
||||
{
|
||||
int ret;
|
||||
uint32_t buffer_size;
|
||||
struct jaylink_swo_speed speed;
|
||||
uint32_t divider;
|
||||
uint32_t min_freq;
|
||||
uint32_t max_freq;
|
||||
|
||||
trace_enabled = enabled;
|
||||
|
||||
if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) {
|
||||
if (!enabled)
|
||||
return ERROR_OK;
|
||||
|
||||
LOG_ERROR("Trace capturing is not supported by the device.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
|
||||
LOG_ERROR("Selected pin protocol is not supported.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
trace_enabled = enabled;
|
||||
|
||||
ret = jaylink_swo_stop(devh);
|
||||
|
||||
if (ret != JAYLINK_OK) {
|
||||
@@ -1334,6 +1352,11 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
|
||||
LOG_ERROR("Selected pin protocol is not supported.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
buffer_size = calculate_trace_buffer_size();
|
||||
|
||||
if (!buffer_size) {
|
||||
@@ -1349,13 +1372,45 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!*trace_freq)
|
||||
*trace_freq = speed.freq / speed.min_div;
|
||||
if (*trace_freq > 0) {
|
||||
divider = speed.freq / *trace_freq;
|
||||
min_freq = speed.freq / speed.max_div;
|
||||
max_freq = speed.freq / speed.min_div;
|
||||
|
||||
if (!check_trace_freq(speed, *trace_freq))
|
||||
return ERROR_FAIL;
|
||||
if (*trace_freq > max_freq) {
|
||||
LOG_INFO("Given SWO frequency too high, using %u Hz instead.",
|
||||
max_freq);
|
||||
*trace_freq = max_freq;
|
||||
} else if (*trace_freq < min_freq) {
|
||||
LOG_INFO("Given SWO frequency too low, using %u Hz instead.",
|
||||
min_freq);
|
||||
*trace_freq = min_freq;
|
||||
} else if (*trace_freq != speed.freq / divider) {
|
||||
*trace_freq = speed.freq / divider;
|
||||
|
||||
LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size);
|
||||
LOG_INFO("Given SWO frequency is not supported by the device, "
|
||||
"using %u Hz instead.", *trace_freq);
|
||||
}
|
||||
|
||||
if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq,
|
||||
prescaler)) {
|
||||
LOG_ERROR("SWO frequency is not suitable. Please choose a "
|
||||
"different frequency or use auto-detection.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
LOG_INFO("Trying to auto-detect SWO frequency.");
|
||||
|
||||
if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq,
|
||||
prescaler)) {
|
||||
LOG_ERROR("Maximum permitted frequency deviation of %.02f %% "
|
||||
"could not be achieved.", SWO_MAX_FREQ_DEV);
|
||||
LOG_ERROR("Auto-detection of SWO frequency failed.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("Using SWO frequency of %u Hz.", *trace_freq);
|
||||
}
|
||||
|
||||
ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq,
|
||||
buffer_size);
|
||||
@@ -1365,6 +1420,9 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Using %u bytes device memory for trace capturing.",
|
||||
buffer_size);
|
||||
|
||||
/*
|
||||
* Adjust the SWD transaction buffer size as starting SWO capturing
|
||||
* allocates device internal memory.
|
||||
@@ -1470,7 +1528,7 @@ COMMAND_HANDLER(jlink_handle_config_mac_address_command)
|
||||
} else if (CMD_ARGC == 1) {
|
||||
str = CMD_ARGV[0];
|
||||
|
||||
if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || \
|
||||
if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' ||
|
||||
str[8] != ':' || str[11] != ':' || str[14] != ':')) {
|
||||
command_print(CMD, "Invalid MAC address format.");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
@@ -2212,17 +2270,24 @@ static const struct swd_driver jlink_swd = {
|
||||
|
||||
static const char * const jlink_transports[] = { "jtag", "swd", NULL };
|
||||
|
||||
struct jtag_interface jlink_interface = {
|
||||
.name = "jlink",
|
||||
.commands = jlink_command_handlers,
|
||||
.transports = jlink_transports,
|
||||
.swd = &jlink_swd,
|
||||
static struct jtag_interface jlink_interface = {
|
||||
.execute_queue = &jlink_execute_queue,
|
||||
.speed = &jlink_speed,
|
||||
.speed_div = &jlink_speed_div,
|
||||
.khz = &jlink_khz,
|
||||
};
|
||||
|
||||
struct adapter_driver jlink_adapter_driver = {
|
||||
.name = "jlink",
|
||||
.transports = jlink_transports,
|
||||
.commands = jlink_command_handlers,
|
||||
|
||||
.init = &jlink_init,
|
||||
.quit = &jlink_quit,
|
||||
.reset = &jlink_reset_safe,
|
||||
.speed = &jlink_speed,
|
||||
.khz = &jlink_khz,
|
||||
.speed_div = &jlink_speed_div,
|
||||
.config_trace = &config_trace,
|
||||
.poll_trace = &poll_trace,
|
||||
|
||||
.jtag_ops = &jlink_interface,
|
||||
.swd_ops = &jlink_swd,
|
||||
};
|
||||
|
||||
+209
-20
@@ -33,6 +33,8 @@
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define NO_TAP_SHIFT 0
|
||||
#define TAP_SHIFT 1
|
||||
|
||||
@@ -47,34 +49,160 @@
|
||||
#define CMD_SCAN_CHAIN_FLIP_TMS 3
|
||||
#define CMD_STOP_SIMU 4
|
||||
|
||||
int server_port = SERVER_PORT;
|
||||
char *server_address;
|
||||
/* jtag_vpi server port and address to connect to */
|
||||
static int server_port = SERVER_PORT;
|
||||
static char *server_address;
|
||||
|
||||
int sockfd;
|
||||
struct sockaddr_in serv_addr;
|
||||
/* Send CMD_STOP_SIMU to server when OpenOCD exits? */
|
||||
static bool stop_sim_on_exit;
|
||||
|
||||
static int sockfd;
|
||||
static struct sockaddr_in serv_addr;
|
||||
|
||||
/* One jtag_vpi "packet" as sent over a TCP channel. */
|
||||
struct vpi_cmd {
|
||||
int cmd;
|
||||
union {
|
||||
uint32_t cmd;
|
||||
unsigned char cmd_buf[4];
|
||||
};
|
||||
unsigned char buffer_out[XFERT_MAX_SIZE];
|
||||
unsigned char buffer_in[XFERT_MAX_SIZE];
|
||||
int length;
|
||||
int nb_bits;
|
||||
union {
|
||||
uint32_t length;
|
||||
unsigned char length_buf[4];
|
||||
};
|
||||
union {
|
||||
uint32_t nb_bits;
|
||||
unsigned char nb_bits_buf[4];
|
||||
};
|
||||
};
|
||||
|
||||
static char *jtag_vpi_cmd_to_str(int cmd_num)
|
||||
{
|
||||
switch (cmd_num) {
|
||||
case CMD_RESET:
|
||||
return "CMD_RESET";
|
||||
case CMD_TMS_SEQ:
|
||||
return "CMD_TMS_SEQ";
|
||||
case CMD_SCAN_CHAIN:
|
||||
return "CMD_SCAN_CHAIN";
|
||||
case CMD_SCAN_CHAIN_FLIP_TMS:
|
||||
return "CMD_SCAN_CHAIN_FLIP_TMS";
|
||||
case CMD_STOP_SIMU:
|
||||
return "CMD_STOP_SIMU";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
static int jtag_vpi_send_cmd(struct vpi_cmd *vpi)
|
||||
{
|
||||
int retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd));
|
||||
if (retval <= 0)
|
||||
return ERROR_FAIL;
|
||||
int retval;
|
||||
|
||||
/* Optional low-level JTAG debug */
|
||||
if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) {
|
||||
if (vpi->nb_bits > 0) {
|
||||
/* command with a non-empty data payload */
|
||||
char *char_buf = buf_to_str(vpi->buffer_out,
|
||||
(vpi->nb_bits > DEBUG_JTAG_IOZ)
|
||||
? DEBUG_JTAG_IOZ
|
||||
: vpi->nb_bits,
|
||||
16);
|
||||
LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, "
|
||||
"length=%" PRIu32 ", "
|
||||
"nb_bits=%" PRIu32 ", "
|
||||
"buf_out=0x%s%s",
|
||||
jtag_vpi_cmd_to_str(vpi->cmd),
|
||||
vpi->length,
|
||||
vpi->nb_bits,
|
||||
char_buf,
|
||||
(vpi->nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : "");
|
||||
free(char_buf);
|
||||
} else {
|
||||
/* command without data payload */
|
||||
LOG_DEBUG_IO("sending JTAG VPI cmd: cmd=%s, "
|
||||
"length=%" PRIu32 ", "
|
||||
"nb_bits=%" PRIu32,
|
||||
jtag_vpi_cmd_to_str(vpi->cmd),
|
||||
vpi->length,
|
||||
vpi->nb_bits);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use little endian when transmitting/receiving jtag_vpi cmds.
|
||||
The choice of little endian goes against usual networking conventions
|
||||
but is intentional to remain compatible with most older OpenOCD builds
|
||||
(i.e. builds on little-endian platforms). */
|
||||
h_u32_to_le(vpi->cmd_buf, vpi->cmd);
|
||||
h_u32_to_le(vpi->length_buf, vpi->length);
|
||||
h_u32_to_le(vpi->nb_bits_buf, vpi->nb_bits);
|
||||
|
||||
retry_write:
|
||||
retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd));
|
||||
|
||||
if (retval < 0) {
|
||||
/* Account for the case when socket write is interrupted. */
|
||||
#ifdef _WIN32
|
||||
int wsa_err = WSAGetLastError();
|
||||
if (wsa_err == WSAEINTR)
|
||||
goto retry_write;
|
||||
#else
|
||||
if (errno == EINTR)
|
||||
goto retry_write;
|
||||
#endif
|
||||
/* Otherwise this is an error using the socket, most likely fatal
|
||||
for the connection. B*/
|
||||
log_socket_error("jtag_vpi xmit");
|
||||
/* TODO: Clean way how adapter drivers can report fatal errors
|
||||
to upper layers of OpenOCD and let it perform an orderly shutdown? */
|
||||
exit(-1);
|
||||
} else if (retval < (int)sizeof(struct vpi_cmd)) {
|
||||
/* This means we could not send all data, which is most likely fatal
|
||||
for the jtag_vpi connection (the underlying TCP connection likely not
|
||||
usable anymore) */
|
||||
LOG_ERROR("Could not send all data through jtag_vpi connection.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Otherwise the packet has been sent successfully. */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
|
||||
{
|
||||
int retval = read_socket(sockfd, vpi, sizeof(struct vpi_cmd));
|
||||
if (retval < (int)sizeof(struct vpi_cmd))
|
||||
return ERROR_FAIL;
|
||||
unsigned bytes_buffered = 0;
|
||||
while (bytes_buffered < sizeof(struct vpi_cmd)) {
|
||||
int bytes_to_receive = sizeof(struct vpi_cmd) - bytes_buffered;
|
||||
int retval = read_socket(sockfd, ((char *)vpi) + bytes_buffered, bytes_to_receive);
|
||||
if (retval < 0) {
|
||||
#ifdef _WIN32
|
||||
int wsa_err = WSAGetLastError();
|
||||
if (wsa_err == WSAEINTR) {
|
||||
/* socket read interrupted by WSACancelBlockingCall() */
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if (errno == EINTR) {
|
||||
/* socket read interrupted by a signal */
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/* Otherwise, this is an error when accessing the socket. */
|
||||
log_socket_error("jtag_vpi recv");
|
||||
exit(-1);
|
||||
} else if (retval == 0) {
|
||||
/* Connection closed by the other side */
|
||||
LOG_ERROR("Connection prematurely closed by jtag_vpi server.");
|
||||
exit(-1);
|
||||
}
|
||||
/* Otherwise, we have successfully received some data */
|
||||
bytes_buffered += retval;
|
||||
}
|
||||
|
||||
/* Use little endian when transmitting/receiving jtag_vpi cmds. */
|
||||
vpi->cmd = le_to_h_u32(vpi->cmd_buf);
|
||||
vpi->length = le_to_h_u32(vpi->length_buf);
|
||||
vpi->nb_bits = le_to_h_u32(vpi->nb_bits_buf);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -87,6 +215,7 @@ static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
|
||||
static int jtag_vpi_reset(int trst, int srst)
|
||||
{
|
||||
struct vpi_cmd vpi;
|
||||
memset(&vpi, 0, sizeof(struct vpi_cmd));
|
||||
|
||||
vpi.cmd = CMD_RESET;
|
||||
vpi.length = 0;
|
||||
@@ -109,6 +238,7 @@ static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits)
|
||||
struct vpi_cmd vpi;
|
||||
int nb_bytes;
|
||||
|
||||
memset(&vpi, 0, sizeof(struct vpi_cmd));
|
||||
nb_bytes = DIV_ROUND_UP(nb_bits, 8);
|
||||
|
||||
vpi.cmd = CMD_TMS_SEQ;
|
||||
@@ -176,6 +306,8 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
|
||||
struct vpi_cmd vpi;
|
||||
int nb_bytes = DIV_ROUND_UP(nb_bits, 8);
|
||||
|
||||
memset(&vpi, 0, sizeof(struct vpi_cmd));
|
||||
|
||||
vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN;
|
||||
|
||||
if (bits)
|
||||
@@ -194,6 +326,16 @@ static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Optional low-level JTAG debug */
|
||||
if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) {
|
||||
char *char_buf = buf_to_str(vpi.buffer_in,
|
||||
(nb_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : nb_bits,
|
||||
16);
|
||||
LOG_DEBUG_IO("recvd JTAG VPI data: nb_bits=%d, buf_in=0x%s%s",
|
||||
nb_bits, char_buf, (nb_bits > DEBUG_JTAG_IOZ) ? "(...)" : "");
|
||||
free(char_buf);
|
||||
}
|
||||
|
||||
if (bits)
|
||||
memcpy(bits, vpi.buffer_in, nb_bytes);
|
||||
|
||||
@@ -384,6 +526,11 @@ static int jtag_vpi_execute_queue(void)
|
||||
case JTAG_SCAN:
|
||||
retval = jtag_vpi_scan(cmd->cmd.scan);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type 0x%X",
|
||||
cmd->type);
|
||||
retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,10 +580,28 @@ static int jtag_vpi_init(void)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jtag_vpi_stop_simulation(void)
|
||||
{
|
||||
struct vpi_cmd cmd;
|
||||
memset(&cmd, 0, sizeof(struct vpi_cmd));
|
||||
cmd.length = 0;
|
||||
cmd.nb_bits = 0;
|
||||
cmd.cmd = CMD_STOP_SIMU;
|
||||
return jtag_vpi_send_cmd(&cmd);
|
||||
}
|
||||
|
||||
static int jtag_vpi_quit(void)
|
||||
{
|
||||
if (stop_sim_on_exit) {
|
||||
if (jtag_vpi_stop_simulation() != ERROR_OK)
|
||||
LOG_WARNING("jtag_vpi: failed to send \"stop simulation\" command");
|
||||
}
|
||||
if (close_socket(sockfd) != 0) {
|
||||
LOG_WARNING("jtag_vpi: could not close jtag_vpi client socket");
|
||||
log_socket_error("jtag_vpi");
|
||||
}
|
||||
free(server_address);
|
||||
return close(sockfd);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jtag_vpi_set_port)
|
||||
@@ -466,31 +631,55 @@ COMMAND_HANDLER(jtag_vpi_set_address)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler)
|
||||
{
|
||||
if (CMD_ARGC != 1) {
|
||||
LOG_ERROR("jtag_vpi_stop_sim_on_exit expects 1 argument (on|off)");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
} else {
|
||||
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit);
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration jtag_vpi_command_handlers[] = {
|
||||
{
|
||||
.name = "jtag_vpi_set_port",
|
||||
.handler = &jtag_vpi_set_port,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the port of the VPI server",
|
||||
.usage = "description_string",
|
||||
.usage = "tcp_port_num",
|
||||
},
|
||||
{
|
||||
.name = "jtag_vpi_set_address",
|
||||
.handler = &jtag_vpi_set_address,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the address of the VPI server",
|
||||
.usage = "description_string",
|
||||
.usage = "ipv4_addr",
|
||||
},
|
||||
{
|
||||
.name = "jtag_vpi_stop_sim_on_exit",
|
||||
.handler = &jtag_vpi_stop_sim_on_exit_handler,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Configure if simulation stop command shall be sent "
|
||||
"before OpenOCD exits (default: off)",
|
||||
.usage = "<on|off>",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface jtag_vpi_interface = {
|
||||
.name = "jtag_vpi",
|
||||
static struct jtag_interface jtag_vpi_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.commands = jtag_vpi_command_handlers,
|
||||
.execute_queue = jtag_vpi_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver jtag_vpi_adapter_driver = {
|
||||
.name = "jtag_vpi",
|
||||
.transports = jtag_only,
|
||||
.commands = jtag_vpi_command_handlers,
|
||||
|
||||
.init = jtag_vpi_init,
|
||||
.quit = jtag_vpi_quit,
|
||||
.execute_queue = jtag_vpi_execute_queue,
|
||||
|
||||
.jtag_ops = &jtag_vpi_interface,
|
||||
};
|
||||
|
||||
+33
-58
@@ -43,7 +43,7 @@
|
||||
#include <jtag/swd.h>
|
||||
#include <jtag/commands.h>
|
||||
|
||||
#include "libusb_common.h"
|
||||
#include "libusb_helper.h"
|
||||
|
||||
#define VID 0x04b4
|
||||
#define PID 0xf139
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
struct kitprog {
|
||||
hid_device *hid_handle;
|
||||
struct jtag_libusb_device_handle *usb_handle;
|
||||
struct libusb_device_handle *usb_handle;
|
||||
uint16_t packet_size;
|
||||
uint16_t packet_index;
|
||||
uint8_t *packet_buffer;
|
||||
@@ -280,7 +280,7 @@ static int kitprog_usb_open(void)
|
||||
const uint16_t pids[] = { PID, 0 };
|
||||
|
||||
if (jtag_libusb_open(vids, pids, kitprog_serial,
|
||||
&kitprog_handle->usb_handle) != ERROR_OK) {
|
||||
&kitprog_handle->usb_handle, NULL) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to open or find the device");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -311,7 +311,7 @@ static int kitprog_usb_open(void)
|
||||
}
|
||||
|
||||
/* Claim the KitProg Programmer (bulk transfer) interface */
|
||||
if (jtag_libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) {
|
||||
if (libusb_claim_interface(kitprog_handle->usb_handle, 1) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to claim KitProg Programmer (bulk transfer) interface");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -358,7 +358,7 @@ static int kitprog_get_version(void)
|
||||
unsigned char command[3] = {HID_TYPE_START | HID_TYPE_WRITE, 0x00, HID_COMMAND_VERSION};
|
||||
unsigned char data[64];
|
||||
|
||||
ret = kitprog_hid_command(command, sizeof command, data, sizeof data);
|
||||
ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
@@ -376,7 +376,7 @@ static int kitprog_get_millivolts(void)
|
||||
unsigned char command[3] = {HID_TYPE_START | HID_TYPE_READ, 0x00, HID_COMMAND_POWER};
|
||||
unsigned char data[64];
|
||||
|
||||
ret = kitprog_hid_command(command, sizeof command, data, sizeof data);
|
||||
ret = kitprog_hid_command(command, sizeof(command), data, sizeof(data));
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
@@ -603,7 +603,7 @@ static int kitprog_generic_acquire(void)
|
||||
* will take the Cortex-M3 out of reset and enable debugging.
|
||||
*/
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (uint8_t j = 0; j < sizeof devices && acquire_count == i; j++) {
|
||||
for (uint8_t j = 0; j < sizeof(devices) && acquire_count == i; j++) {
|
||||
retval = kitprog_acquire_psoc(devices[j], ACQUIRE_MODE_RESET, 3);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_DEBUG("Aquisition function failed for device 0x%02x.", devices[j]);
|
||||
@@ -731,14 +731,14 @@ static int kitprog_swd_run_queue(void)
|
||||
}
|
||||
}
|
||||
|
||||
ret = jtag_libusb_bulk_write(kitprog_handle->usb_handle,
|
||||
BULK_EP_OUT, (char *)buffer, write_count, 0);
|
||||
if (ret > 0) {
|
||||
queued_retval = ERROR_OK;
|
||||
} else {
|
||||
if (jtag_libusb_bulk_write(kitprog_handle->usb_handle,
|
||||
BULK_EP_OUT, (char *)buffer,
|
||||
write_count, 0, &ret)) {
|
||||
LOG_ERROR("Bulk write failed");
|
||||
queued_retval = ERROR_FAIL;
|
||||
break;
|
||||
} else {
|
||||
queued_retval = ERROR_OK;
|
||||
}
|
||||
|
||||
/* KitProg firmware does not send a zero length packet
|
||||
@@ -754,18 +754,17 @@ static int kitprog_swd_run_queue(void)
|
||||
if (read_count % 64 == 0)
|
||||
read_count_workaround = read_count;
|
||||
|
||||
ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle,
|
||||
if (jtag_libusb_bulk_read(kitprog_handle->usb_handle,
|
||||
BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer,
|
||||
read_count_workaround, 1000);
|
||||
if (ret > 0) {
|
||||
read_count_workaround, 1000, &ret)) {
|
||||
LOG_ERROR("Bulk read failed");
|
||||
queued_retval = ERROR_FAIL;
|
||||
break;
|
||||
} else {
|
||||
/* Handle garbage data by offsetting the initial read index */
|
||||
if ((unsigned int)ret > read_count)
|
||||
read_index = ret - read_count;
|
||||
queued_retval = ERROR_OK;
|
||||
} else {
|
||||
LOG_ERROR("Bulk read failed");
|
||||
queued_retval = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pending_transfer_count; i++) {
|
||||
@@ -819,11 +818,16 @@ static void kitprog_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
|
||||
|
||||
/*************** jtag lowlevel functions ********************/
|
||||
|
||||
static void kitprog_execute_reset(struct jtag_command *cmd)
|
||||
static int kitprog_reset(int trst, int srst)
|
||||
{
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (cmd->cmd.reset->srst == 1) {
|
||||
if (trst == 1) {
|
||||
LOG_ERROR("KitProg: Interface has no TRST");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (srst == 1) {
|
||||
retval = kitprog_reset_target();
|
||||
/* Since the previous command also disables SWCLK output, we need to send an
|
||||
* SWD bus reset command to re-enable it. For some reason, running
|
||||
@@ -836,38 +840,7 @@ static void kitprog_execute_reset(struct jtag_command *cmd)
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
LOG_ERROR("KitProg: Interface reset failed");
|
||||
}
|
||||
|
||||
static void kitprog_execute_sleep(struct jtag_command *cmd)
|
||||
{
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
}
|
||||
|
||||
static void kitprog_execute_command(struct jtag_command *cmd)
|
||||
{
|
||||
switch (cmd->type) {
|
||||
case JTAG_RESET:
|
||||
kitprog_execute_reset(cmd);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
kitprog_execute_sleep(cmd);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static int kitprog_execute_queue(void)
|
||||
{
|
||||
struct jtag_command *cmd = jtag_command_queue;
|
||||
|
||||
while (cmd != NULL) {
|
||||
kitprog_execute_command(cmd);
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(kitprog_handle_info_command)
|
||||
@@ -961,12 +934,14 @@ static const struct swd_driver kitprog_swd = {
|
||||
|
||||
static const char * const kitprog_transports[] = { "swd", NULL };
|
||||
|
||||
struct jtag_interface kitprog_interface = {
|
||||
struct adapter_driver kitprog_adapter_driver = {
|
||||
.name = "kitprog",
|
||||
.commands = kitprog_command_handlers,
|
||||
.transports = kitprog_transports,
|
||||
.swd = &kitprog_swd,
|
||||
.execute_queue = kitprog_execute_queue,
|
||||
.commands = kitprog_command_handlers,
|
||||
|
||||
.init = kitprog_init,
|
||||
.quit = kitprog_quit
|
||||
.quit = kitprog_quit,
|
||||
.reset = kitprog_reset,
|
||||
|
||||
.swd_ops = &kitprog_swd,
|
||||
};
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* Copyright (C) 2011 by Mauro Gamba <maurillo71@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 "log.h"
|
||||
#include "libusb0_common.h"
|
||||
|
||||
static bool jtag_libusb_match(struct jtag_libusb_device *dev,
|
||||
const uint16_t vids[], const uint16_t pids[])
|
||||
{
|
||||
for (unsigned i = 0; vids[i]; i++) {
|
||||
if (dev->descriptor.idVendor == vids[i] &&
|
||||
dev->descriptor.idProduct == pids[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns true if the string descriptor indexed by str_index in device matches string */
|
||||
static bool string_descriptor_equal(usb_dev_handle *device, uint8_t str_index,
|
||||
const char *string)
|
||||
{
|
||||
int retval;
|
||||
bool matched;
|
||||
char desc_string[256+1]; /* Max size of string descriptor */
|
||||
|
||||
if (str_index == 0)
|
||||
return false;
|
||||
|
||||
retval = usb_get_string_simple(device, str_index,
|
||||
desc_string, sizeof(desc_string)-1);
|
||||
if (retval < 0) {
|
||||
LOG_ERROR("usb_get_string_simple() failed with %d", retval);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Null terminate descriptor string in case it needs to be logged. */
|
||||
desc_string[sizeof(desc_string)-1] = '\0';
|
||||
|
||||
matched = strncmp(string, desc_string, sizeof(desc_string)) == 0;
|
||||
if (!matched)
|
||||
LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'",
|
||||
desc_string, string);
|
||||
return matched;
|
||||
}
|
||||
|
||||
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
const char *serial,
|
||||
struct jtag_libusb_device_handle **out)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
bool serial_mismatch = false;
|
||||
struct jtag_libusb_device_handle *libusb_handle;
|
||||
usb_init();
|
||||
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
|
||||
struct usb_bus *busses = usb_get_busses();
|
||||
for (struct usb_bus *bus = busses; bus; bus = bus->next) {
|
||||
for (struct usb_device *dev = bus->devices;
|
||||
dev; dev = dev->next) {
|
||||
if (!jtag_libusb_match(dev, vids, pids))
|
||||
continue;
|
||||
|
||||
libusb_handle = usb_open(dev);
|
||||
if (NULL == libusb_handle) {
|
||||
LOG_ERROR("usb_open() failed with %s", usb_strerror());
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Device must be open to use libusb_get_string_descriptor_ascii. */
|
||||
if (serial != NULL &&
|
||||
!string_descriptor_equal(libusb_handle, dev->descriptor.iSerialNumber, serial)) {
|
||||
serial_mismatch = true;
|
||||
usb_close(libusb_handle);
|
||||
continue;
|
||||
}
|
||||
*out = libusb_handle;
|
||||
retval = ERROR_OK;
|
||||
serial_mismatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (serial_mismatch)
|
||||
LOG_INFO("No device matches the serial string");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void jtag_libusb_close(jtag_libusb_device_handle *dev)
|
||||
{
|
||||
/* Close device */
|
||||
usb_close(dev);
|
||||
}
|
||||
|
||||
int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType,
|
||||
uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes,
|
||||
uint16_t size, unsigned int timeout)
|
||||
{
|
||||
int transferred = 0;
|
||||
|
||||
transferred = usb_control_msg(dev, requestType, request, wValue, wIndex,
|
||||
bytes, size, timeout);
|
||||
|
||||
if (transferred < 0)
|
||||
transferred = 0;
|
||||
|
||||
return transferred;
|
||||
}
|
||||
|
||||
int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
|
||||
int size, int timeout)
|
||||
{
|
||||
return usb_bulk_write(dev, ep, bytes, size, timeout);
|
||||
}
|
||||
|
||||
int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes,
|
||||
int size, int timeout)
|
||||
{
|
||||
return usb_bulk_read(dev, ep, bytes, size, timeout);
|
||||
}
|
||||
|
||||
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
int configuration)
|
||||
{
|
||||
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
|
||||
|
||||
return usb_set_configuration(devh,
|
||||
udev->config[configuration].bConfigurationValue);
|
||||
}
|
||||
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol, int trans_type)
|
||||
{
|
||||
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
|
||||
struct usb_interface *iface = udev->config->interface;
|
||||
struct usb_interface_descriptor *desc = iface->altsetting;
|
||||
|
||||
*usb_read_ep = *usb_write_ep = 0;
|
||||
|
||||
for (int i = 0; i < desc->bNumEndpoints; i++) {
|
||||
if ((bclass > 0 && desc->bInterfaceClass != bclass) ||
|
||||
(subclass > 0 && desc->bInterfaceSubClass != subclass) ||
|
||||
(protocol > 0 && desc->bInterfaceProtocol != protocol) ||
|
||||
(trans_type > 0 && (desc->endpoint[i].bmAttributes & 0x3) != trans_type))
|
||||
continue;
|
||||
|
||||
uint8_t epnum = desc->endpoint[i].bEndpointAddress;
|
||||
bool is_input = epnum & 0x80;
|
||||
LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum);
|
||||
if (is_input)
|
||||
*usb_read_ep = epnum;
|
||||
else
|
||||
*usb_write_ep = epnum;
|
||||
|
||||
if (*usb_read_ep && *usb_write_ep) {
|
||||
LOG_DEBUG("Claiming interface %d", (int)desc->bInterfaceNumber);
|
||||
usb_claim_interface(devh, (int)desc->bInterfaceNumber);
|
||||
return ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
|
||||
{
|
||||
if (!dev)
|
||||
return ERROR_FAIL;
|
||||
|
||||
*pid = dev->descriptor.idProduct;
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* Copyright (C) 2011 by Mauro Gamba <maurillo71@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/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H
|
||||
#define OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H
|
||||
|
||||
#include <usb.h>
|
||||
|
||||
#define jtag_libusb_device usb_device
|
||||
#define jtag_libusb_device_handle usb_dev_handle
|
||||
#define jtag_libusb_device_descriptor usb_device_descriptor
|
||||
#define jtag_libusb_interface usb_interface
|
||||
#define jtag_libusb_interface_descriptor usb_interface_descriptor
|
||||
#define jtag_libusb_endpoint_descriptor usb_endpoint_descriptor
|
||||
#define jtag_libusb_config_descriptor usb_config_descriptor
|
||||
|
||||
#define jtag_libusb_reset_device(dev) usb_reset(dev)
|
||||
#define jtag_libusb_get_device(devh) usb_device(devh)
|
||||
|
||||
/* make some defines compatible to libusb1 */
|
||||
#define LIBUSB_REQUEST_TYPE_VENDOR USB_TYPE_VENDOR
|
||||
#define LIBUSB_RECIPIENT_DEVICE USB_RECIP_DEVICE
|
||||
#define LIBUSB_ENDPOINT_OUT USB_ENDPOINT_OUT
|
||||
#define LIBUSB_ENDPOINT_IN USB_ENDPOINT_IN
|
||||
#define LIBUSB_TRANSFER_TYPE_BULK USB_ENDPOINT_TYPE_BULK
|
||||
|
||||
static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh,
|
||||
int iface)
|
||||
{
|
||||
return usb_claim_interface(devh, iface);
|
||||
};
|
||||
|
||||
static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh,
|
||||
int iface)
|
||||
{
|
||||
return usb_release_interface(devh, iface);
|
||||
}
|
||||
|
||||
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
const char *serial,
|
||||
struct jtag_libusb_device_handle **out);
|
||||
void jtag_libusb_close(jtag_libusb_device_handle *dev);
|
||||
int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
|
||||
uint8_t requestType, uint8_t request, uint16_t wValue,
|
||||
uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout);
|
||||
int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout);
|
||||
int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout);
|
||||
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
int configuration);
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol, int trans_type);
|
||||
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB0_COMMON_H */
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <jtag/drivers/jtag_usb_common.h>
|
||||
#include "libusb1_common.h"
|
||||
#include "libusb_helper.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
@@ -33,7 +33,32 @@
|
||||
static struct libusb_context *jtag_libusb_context; /**< Libusb context **/
|
||||
static libusb_device **devs; /**< The usb device list **/
|
||||
|
||||
static bool jtag_libusb_match(struct libusb_device_descriptor *dev_desc,
|
||||
static int jtag_libusb_error(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case LIBUSB_SUCCESS:
|
||||
return ERROR_OK;
|
||||
case LIBUSB_ERROR_TIMEOUT:
|
||||
return ERROR_TIMEOUT_REACHED;
|
||||
case LIBUSB_ERROR_IO:
|
||||
case LIBUSB_ERROR_INVALID_PARAM:
|
||||
case LIBUSB_ERROR_ACCESS:
|
||||
case LIBUSB_ERROR_NO_DEVICE:
|
||||
case LIBUSB_ERROR_NOT_FOUND:
|
||||
case LIBUSB_ERROR_BUSY:
|
||||
case LIBUSB_ERROR_OVERFLOW:
|
||||
case LIBUSB_ERROR_PIPE:
|
||||
case LIBUSB_ERROR_INTERRUPTED:
|
||||
case LIBUSB_ERROR_NO_MEM:
|
||||
case LIBUSB_ERROR_NOT_SUPPORTED:
|
||||
case LIBUSB_ERROR_OTHER:
|
||||
return ERROR_FAIL;
|
||||
default:
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
|
||||
const uint16_t vids[], const uint16_t pids[])
|
||||
{
|
||||
for (unsigned i = 0; vids[i]; i++) {
|
||||
@@ -98,14 +123,45 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in
|
||||
return matched;
|
||||
}
|
||||
|
||||
static bool jtag_libusb_match_serial(libusb_device_handle *device,
|
||||
struct libusb_device_descriptor *dev_desc, const char *serial,
|
||||
adapter_get_alternate_serial_fn adapter_get_alternate_serial)
|
||||
{
|
||||
if (string_descriptor_equal(device, dev_desc->iSerialNumber, serial))
|
||||
return true;
|
||||
|
||||
/* check the alternate serial helper */
|
||||
if (!adapter_get_alternate_serial)
|
||||
return false;
|
||||
|
||||
/* get the alternate serial */
|
||||
char *alternate_serial = adapter_get_alternate_serial(device, dev_desc);
|
||||
|
||||
/* check possible failures */
|
||||
if (alternate_serial == NULL)
|
||||
return false;
|
||||
|
||||
/* then compare and free the alternate serial */
|
||||
bool match = false;
|
||||
if (strcmp(serial, alternate_serial) == 0)
|
||||
match = true;
|
||||
else
|
||||
LOG_DEBUG("Device alternate serial number '%s' doesn't match requested serial '%s'",
|
||||
alternate_serial, serial);
|
||||
|
||||
free(alternate_serial);
|
||||
return match;
|
||||
}
|
||||
|
||||
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
const char *serial,
|
||||
struct jtag_libusb_device_handle **out)
|
||||
struct libusb_device_handle **out,
|
||||
adapter_get_alternate_serial_fn adapter_get_alternate_serial)
|
||||
{
|
||||
int cnt, idx, errCode;
|
||||
int retval = ERROR_FAIL;
|
||||
bool serial_mismatch = false;
|
||||
struct jtag_libusb_device_handle *libusb_handle = NULL;
|
||||
struct libusb_device_handle *libusb_handle = NULL;
|
||||
|
||||
if (libusb_init(&jtag_libusb_context) < 0)
|
||||
return ERROR_FAIL;
|
||||
@@ -118,7 +174,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
if (libusb_get_device_descriptor(devs[idx], &dev_desc) != 0)
|
||||
continue;
|
||||
|
||||
if (!jtag_libusb_match(&dev_desc, vids, pids))
|
||||
if (!jtag_libusb_match_ids(&dev_desc, vids, pids))
|
||||
continue;
|
||||
|
||||
if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx]))
|
||||
@@ -134,7 +190,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
|
||||
/* Device must be open to use libusb_get_string_descriptor_ascii. */
|
||||
if (serial != NULL &&
|
||||
!string_descriptor_equal(libusb_handle, dev_desc.iSerialNumber, serial)) {
|
||||
!jtag_libusb_match_serial(libusb_handle, &dev_desc, serial, adapter_get_alternate_serial)) {
|
||||
serial_mismatch = true;
|
||||
libusb_close(libusb_handle);
|
||||
continue;
|
||||
@@ -152,10 +208,13 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
if (serial_mismatch)
|
||||
LOG_INFO("No device matches the serial string");
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
libusb_exit(jtag_libusb_context);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void jtag_libusb_close(jtag_libusb_device_handle *dev)
|
||||
void jtag_libusb_close(struct libusb_device_handle *dev)
|
||||
{
|
||||
/* Close device */
|
||||
libusb_close(dev);
|
||||
@@ -163,7 +222,7 @@ void jtag_libusb_close(jtag_libusb_device_handle *dev)
|
||||
libusb_exit(jtag_libusb_context);
|
||||
}
|
||||
|
||||
int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType,
|
||||
int jtag_libusb_control_transfer(struct libusb_device_handle *dev, uint8_t requestType,
|
||||
uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes,
|
||||
uint16_t size, unsigned int timeout)
|
||||
{
|
||||
@@ -178,30 +237,44 @@ int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t request
|
||||
return transferred;
|
||||
}
|
||||
|
||||
int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes,
|
||||
int size, int timeout)
|
||||
int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep, char *bytes,
|
||||
int size, int timeout, int *transferred)
|
||||
{
|
||||
int transferred = 0;
|
||||
int ret;
|
||||
|
||||
libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
|
||||
&transferred, timeout);
|
||||
return transferred;
|
||||
*transferred = 0;
|
||||
|
||||
ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
|
||||
transferred, timeout);
|
||||
if (ret != LIBUSB_SUCCESS) {
|
||||
LOG_ERROR("libusb_bulk_write error: %s", libusb_error_name(ret));
|
||||
return jtag_libusb_error(ret);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes,
|
||||
int size, int timeout)
|
||||
int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep, char *bytes,
|
||||
int size, int timeout, int *transferred)
|
||||
{
|
||||
int transferred = 0;
|
||||
int ret;
|
||||
|
||||
libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
|
||||
&transferred, timeout);
|
||||
return transferred;
|
||||
*transferred = 0;
|
||||
|
||||
ret = libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size,
|
||||
transferred, timeout);
|
||||
if (ret != LIBUSB_SUCCESS) {
|
||||
LOG_ERROR("libusb_bulk_read error: %s", libusb_error_name(ret));
|
||||
return jtag_libusb_error(ret);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
int jtag_libusb_set_configuration(struct libusb_device_handle *devh,
|
||||
int configuration)
|
||||
{
|
||||
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
|
||||
struct libusb_device *udev = libusb_get_device(devh);
|
||||
int retCode = -99;
|
||||
|
||||
struct libusb_config_descriptor *config = NULL;
|
||||
@@ -226,12 +299,12 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
return retCode;
|
||||
}
|
||||
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
int jtag_libusb_choose_interface(struct libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol, int trans_type)
|
||||
{
|
||||
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
|
||||
struct libusb_device *udev = libusb_get_device(devh);
|
||||
const struct libusb_interface *inter;
|
||||
const struct libusb_interface_descriptor *interdesc;
|
||||
const struct libusb_endpoint_descriptor *epdesc;
|
||||
@@ -278,7 +351,7 @@ int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
|
||||
int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid)
|
||||
{
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
|
||||
@@ -17,46 +17,29 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H
|
||||
#define OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H
|
||||
#ifndef OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H
|
||||
#define OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#define jtag_libusb_device libusb_device
|
||||
#define jtag_libusb_device_handle libusb_device_handle
|
||||
#define jtag_libusb_device_descriptor libusb_device_descriptor
|
||||
#define jtag_libusb_interface libusb_interface
|
||||
#define jtag_libusb_interface_descriptor libusb_interface_descriptor
|
||||
#define jtag_libusb_endpoint_descriptor libusb_endpoint_descriptor
|
||||
#define jtag_libusb_config_descriptor libusb_config_descriptor
|
||||
|
||||
#define jtag_libusb_reset_device(dev) libusb_reset_device(dev)
|
||||
#define jtag_libusb_get_device(devh) libusb_get_device(devh)
|
||||
|
||||
static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh,
|
||||
int iface)
|
||||
{
|
||||
return libusb_claim_interface(devh, iface);
|
||||
};
|
||||
|
||||
static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh,
|
||||
int iface)
|
||||
{
|
||||
return libusb_release_interface(devh, iface);
|
||||
}
|
||||
/* this callback should return a non NULL value only when the serial could not
|
||||
* be retrieved by the standard 'libusb_get_string_descriptor_ascii' */
|
||||
typedef char * (*adapter_get_alternate_serial_fn)(libusb_device_handle *device,
|
||||
struct libusb_device_descriptor *dev_desc);
|
||||
|
||||
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
const char *serial,
|
||||
struct jtag_libusb_device_handle **out);
|
||||
void jtag_libusb_close(jtag_libusb_device_handle *dev);
|
||||
int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
|
||||
struct libusb_device_handle **out,
|
||||
adapter_get_alternate_serial_fn adapter_get_alternate_serial);
|
||||
void jtag_libusb_close(struct libusb_device_handle *dev);
|
||||
int jtag_libusb_control_transfer(struct libusb_device_handle *dev,
|
||||
uint8_t requestType, uint8_t request, uint16_t wValue,
|
||||
uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout);
|
||||
int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout);
|
||||
int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout);
|
||||
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
int jtag_libusb_bulk_write(struct libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout, int *transferred);
|
||||
int jtag_libusb_bulk_read(struct libusb_device_handle *dev, int ep,
|
||||
char *bytes, int size, int timeout, int *transferred);
|
||||
int jtag_libusb_set_configuration(struct libusb_device_handle *devh,
|
||||
int configuration);
|
||||
/**
|
||||
* Find the first interface optionally matching class, subclass and
|
||||
@@ -72,10 +55,10 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
|
||||
* @param trans_type `bmAttributes Bits 0..1 Transfer type` to match, or -1 to ignore this field.
|
||||
* @returns Returns ERROR_OK on success, ERROR_FAIL otherwise.
|
||||
*/
|
||||
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
|
||||
int jtag_libusb_choose_interface(struct libusb_device_handle *devh,
|
||||
unsigned int *usb_read_ep,
|
||||
unsigned int *usb_write_ep,
|
||||
int bclass, int subclass, int protocol, int trans_type);
|
||||
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
|
||||
int jtag_libusb_get_pid(struct libusb_device *dev, uint16_t *pid);
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB1_COMMON_H */
|
||||
#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_HELPER_H */
|
||||
@@ -890,6 +890,7 @@ int mpsse_flush(struct mpsse_ctx *ctx)
|
||||
|
||||
/* Polling loop, more or less taken from libftdi */
|
||||
int64_t start = timeval_ms();
|
||||
int64_t warn_after = 2000;
|
||||
while (!write_result.done || !read_result.done) {
|
||||
struct timeval timeout_usb;
|
||||
|
||||
@@ -913,9 +914,11 @@ int mpsse_flush(struct mpsse_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (timeval_ms() - start > 2000) {
|
||||
LOG_ERROR("Timed out handling USB events in mpsse_flush().");
|
||||
break;
|
||||
int64_t now = timeval_ms();
|
||||
if (now - start > warn_after) {
|
||||
LOG_WARNING("Haven't made progress in mpsse_flush() for %" PRId64
|
||||
"ms.", now - start);
|
||||
warn_after *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-14
@@ -32,7 +32,7 @@
|
||||
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include "libusb_common.h"
|
||||
#include "libusb_helper.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -134,7 +134,7 @@ static void opendous_tap_append_scan(int length, uint8_t *buffer, struct scan_co
|
||||
|
||||
/* opendous lowlevel functions */
|
||||
struct opendous_jtag {
|
||||
struct jtag_libusb_device_handle *usb_handle;
|
||||
struct libusb_device_handle *usb_handle;
|
||||
};
|
||||
|
||||
static struct opendous_jtag *opendous_usb_open(void);
|
||||
@@ -234,13 +234,19 @@ static const struct command_registration opendous_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface opendous_interface = {
|
||||
static struct jtag_interface opendous_interface = {
|
||||
.execute_queue = opendous_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver opendous_adapter_driver = {
|
||||
.name = "opendous",
|
||||
.transports = jtag_only,
|
||||
.commands = opendous_command_handlers,
|
||||
.execute_queue = opendous_execute_queue,
|
||||
|
||||
.init = opendous_init,
|
||||
.quit = opendous_quit,
|
||||
|
||||
.jtag_ops = &opendous_interface,
|
||||
};
|
||||
|
||||
static int opendous_execute_queue(void)
|
||||
@@ -253,7 +259,7 @@ static int opendous_execute_queue(void)
|
||||
while (cmd != NULL) {
|
||||
switch (cmd->type) {
|
||||
case JTAG_RUNTEST:
|
||||
LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, \
|
||||
LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles,
|
||||
cmd->cmd.runtest->end_state);
|
||||
|
||||
if (cmd->cmd.runtest->end_state != -1)
|
||||
@@ -270,8 +276,8 @@ static int opendous_execute_queue(void)
|
||||
break;
|
||||
|
||||
case JTAG_PATHMOVE:
|
||||
LOG_DEBUG_IO("pathmove: %i states, end in %i", \
|
||||
cmd->cmd.pathmove->num_states, \
|
||||
LOG_DEBUG_IO("pathmove: %i states, end in %i",
|
||||
cmd->cmd.pathmove->num_states,
|
||||
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
|
||||
|
||||
opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path);
|
||||
@@ -708,12 +714,12 @@ struct opendous_jtag *opendous_usb_open(void)
|
||||
{
|
||||
struct opendous_jtag *result;
|
||||
|
||||
struct jtag_libusb_device_handle *devh;
|
||||
if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh) != ERROR_OK)
|
||||
struct libusb_device_handle *devh;
|
||||
if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh, NULL) != ERROR_OK)
|
||||
return NULL;
|
||||
|
||||
jtag_libusb_set_configuration(devh, 0);
|
||||
jtag_libusb_claim_interface(devh, 0);
|
||||
libusb_claim_interface(devh, 0);
|
||||
|
||||
result = malloc(sizeof(*result));
|
||||
result->usb_handle = devh;
|
||||
@@ -764,8 +770,8 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length)
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
|
||||
FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT);
|
||||
} else {
|
||||
result = jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, \
|
||||
(char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT);
|
||||
jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT,
|
||||
(char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT, &result);
|
||||
}
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
LOG_DEBUG("USB write end: %d bytes", result);
|
||||
@@ -791,8 +797,8 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag)
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN,
|
||||
FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT);
|
||||
} else {
|
||||
result = jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT,
|
||||
(char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT);
|
||||
jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT,
|
||||
(char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT, &result);
|
||||
}
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
LOG_DEBUG("USB read end: %d bytes", result);
|
||||
|
||||
+21
-21
@@ -45,7 +45,7 @@
|
||||
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include "libusb_common.h"
|
||||
#include "libusb_helper.h"
|
||||
|
||||
static enum {
|
||||
OPENJTAG_VARIANT_STANDARD,
|
||||
@@ -111,7 +111,7 @@ static uint8_t usb_rx_buf[OPENJTAG_BUFFER_SIZE];
|
||||
static struct openjtag_scan_result openjtag_scan_result_buffer[OPENJTAG_MAX_PENDING_RESULTS];
|
||||
static int openjtag_scan_result_count;
|
||||
|
||||
static jtag_libusb_device_handle *usbh;
|
||||
static struct libusb_device_handle *usbh;
|
||||
|
||||
/* CY7C65215 model only */
|
||||
#define CY7C65215_JTAG_REQUEST 0x40 /* bmRequestType: vendor host-to-device */
|
||||
@@ -229,7 +229,7 @@ static int openjtag_buf_write_standard(
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
*bytes_written += retval;
|
||||
*bytes_written = retval;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -256,10 +256,9 @@ static int openjtag_buf_write_cy7c65215(
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size,
|
||||
CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("bulk write failed, error %d", ret);
|
||||
if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size,
|
||||
CY7C65215_USB_TIMEOUT, &ret)) {
|
||||
LOG_ERROR("bulk write failed, error");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_written = ret;
|
||||
@@ -324,10 +323,9 @@ static int openjtag_buf_read_cy7c65215(
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
ret = jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty,
|
||||
CY7C65215_USB_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("bulk read failed, error %d", ret);
|
||||
if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty,
|
||||
CY7C65215_USB_TIMEOUT, &ret)) {
|
||||
LOG_ERROR("bulk read failed, error");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
*bytes_read = ret;
|
||||
@@ -451,7 +449,7 @@ static int openjtag_init_cy7c65215(void)
|
||||
int ret;
|
||||
|
||||
usbh = NULL;
|
||||
ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh);
|
||||
ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh, NULL);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("unable to open cy7c65215 device");
|
||||
goto err;
|
||||
@@ -654,7 +652,6 @@ static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command *
|
||||
/* whole byte */
|
||||
|
||||
/* bits to transfer */
|
||||
bits = 7;
|
||||
command |= (7 << 5);
|
||||
length -= 8;
|
||||
}
|
||||
@@ -692,7 +689,7 @@ static void openjtag_execute_sleep(struct jtag_command *cmd)
|
||||
|
||||
static void openjtag_set_state(uint8_t openocd_state)
|
||||
{
|
||||
int8_t state = openjtag_get_tap_state(openocd_state);
|
||||
uint8_t state = openjtag_get_tap_state(openocd_state);
|
||||
|
||||
uint8_t buf = 0;
|
||||
buf = 0x01;
|
||||
@@ -892,17 +889,20 @@ static const struct command_registration openjtag_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface openjtag_interface = {
|
||||
static struct jtag_interface openjtag_interface = {
|
||||
.execute_queue = openjtag_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver openjtag_adapter_driver = {
|
||||
.name = "openjtag",
|
||||
.transports = jtag_only,
|
||||
.commands = openjtag_command_handlers,
|
||||
|
||||
.execute_queue = openjtag_execute_queue,
|
||||
.speed = openjtag_speed,
|
||||
.speed_div = openjtag_speed_div,
|
||||
.khz = openjtag_khz,
|
||||
.init = openjtag_init,
|
||||
.quit = openjtag_quit,
|
||||
.speed = openjtag_speed,
|
||||
.khz = openjtag_khz,
|
||||
.speed_div = openjtag_speed_div,
|
||||
|
||||
.jtag_ops = &openjtag_interface,
|
||||
};
|
||||
|
||||
|
||||
|
||||
+23
-18
@@ -23,7 +23,7 @@
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <helper/command.h>
|
||||
#include <jtag/interface.h>
|
||||
#include "libusb_common.h"
|
||||
#include "libusb_helper.h"
|
||||
|
||||
struct sequence {
|
||||
int len;
|
||||
@@ -132,7 +132,7 @@ static const uint16_t osbdm_vid[] = { 0x15a2, 0x15a2, 0x15a2, 0 };
|
||||
static const uint16_t osbdm_pid[] = { 0x0042, 0x0058, 0x005e, 0 };
|
||||
|
||||
struct osbdm {
|
||||
struct jtag_libusb_device_handle *devh; /* USB handle */
|
||||
struct libusb_device_handle *devh; /* USB handle */
|
||||
uint8_t buffer[OSBDM_USB_BUFSIZE]; /* Data to send and receive */
|
||||
int count; /* Count data to send and to read */
|
||||
};
|
||||
@@ -144,10 +144,12 @@ static struct osbdm osbdm_context;
|
||||
static int osbdm_send_and_recv(struct osbdm *osbdm)
|
||||
{
|
||||
/* Send request */
|
||||
int count = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE,
|
||||
(char *)osbdm->buffer, osbdm->count, OSBDM_USB_TIMEOUT);
|
||||
int count, ret;
|
||||
|
||||
if (count != osbdm->count) {
|
||||
ret = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE,
|
||||
(char *)osbdm->buffer, osbdm->count,
|
||||
OSBDM_USB_TIMEOUT, &count);
|
||||
if (ret || count != osbdm->count) {
|
||||
LOG_ERROR("OSBDM communication error: can't write");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -156,13 +158,12 @@ static int osbdm_send_and_recv(struct osbdm *osbdm)
|
||||
uint8_t cmd_saved = osbdm->buffer[0];
|
||||
|
||||
/* Reading answer */
|
||||
osbdm->count = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ,
|
||||
(char *)osbdm->buffer, OSBDM_USB_BUFSIZE, OSBDM_USB_TIMEOUT);
|
||||
|
||||
ret = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ,
|
||||
(char *)osbdm->buffer, OSBDM_USB_BUFSIZE,
|
||||
OSBDM_USB_TIMEOUT, &osbdm->count);
|
||||
/* Now perform basic checks for data sent by BDM device
|
||||
*/
|
||||
|
||||
if (osbdm->count < 0) {
|
||||
if (ret) {
|
||||
LOG_ERROR("OSBDM communication error: can't read");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
@@ -296,7 +297,7 @@ static int osbdm_swap(struct osbdm *osbdm, void *tms, void *tdi,
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int osbdm_flush(struct osbdm *osbdm, struct queue* queue)
|
||||
static int osbdm_flush(struct osbdm *osbdm, struct queue *queue)
|
||||
{
|
||||
uint8_t tms[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)];
|
||||
uint8_t tdi[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)];
|
||||
@@ -373,10 +374,10 @@ static int osbdm_flush(struct osbdm *osbdm, struct queue* queue)
|
||||
static int osbdm_open(struct osbdm *osbdm)
|
||||
{
|
||||
(void)memset(osbdm, 0, sizeof(*osbdm));
|
||||
if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh) != ERROR_OK)
|
||||
if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh, NULL) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (jtag_libusb_claim_interface(osbdm->devh, 0) != ERROR_OK)
|
||||
if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -688,12 +689,16 @@ static int osbdm_init(void)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct jtag_interface osbdm_interface = {
|
||||
.name = "osbdm",
|
||||
|
||||
.transports = jtag_only,
|
||||
static struct jtag_interface osbdm_interface = {
|
||||
.execute_queue = osbdm_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver osbdm_adapter_driver = {
|
||||
.name = "osbdm",
|
||||
.transports = jtag_only,
|
||||
|
||||
.init = osbdm_init,
|
||||
.quit = osbdm_quit
|
||||
.quit = osbdm_quit,
|
||||
|
||||
.jtag_ops = &osbdm_interface,
|
||||
};
|
||||
|
||||
@@ -237,7 +237,7 @@ static int parport_get_giveio_access(void)
|
||||
HANDLE h;
|
||||
OSVERSIONINFO version;
|
||||
|
||||
version.dwOSVersionInfoSize = sizeof version;
|
||||
version.dwOSVersionInfoSize = sizeof(version);
|
||||
if (!GetVersionEx(&version)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
@@ -260,7 +260,6 @@ static int parport_get_giveio_access(void)
|
||||
static struct bitbang_interface parport_bitbang = {
|
||||
.read = &parport_read,
|
||||
.write = &parport_write,
|
||||
.reset = &parport_reset,
|
||||
.blink = &parport_led,
|
||||
};
|
||||
|
||||
@@ -514,16 +513,22 @@ static const struct command_registration parport_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface parport_interface = {
|
||||
.name = "parport",
|
||||
static struct jtag_interface parport_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver parport_adapter_driver = {
|
||||
.name = "parport",
|
||||
.transports = jtag_only,
|
||||
.commands = parport_command_handlers,
|
||||
|
||||
.init = parport_init,
|
||||
.quit = parport_quit,
|
||||
.reset = parport_reset,
|
||||
.speed = parport_speed,
|
||||
.khz = parport_khz,
|
||||
.speed_div = parport_speed_div,
|
||||
.speed = parport_speed,
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
|
||||
.jtag_ops = &parport_interface,
|
||||
};
|
||||
|
||||
@@ -561,15 +561,20 @@ static int presto_jtag_quit(void)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct jtag_interface presto_interface = {
|
||||
static struct jtag_interface presto_interface = {
|
||||
.execute_queue = bitq_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver presto_adapter_driver = {
|
||||
.name = "presto",
|
||||
.transports = jtag_only,
|
||||
.commands = presto_command_handlers,
|
||||
|
||||
.execute_queue = bitq_execute_queue,
|
||||
.init = presto_jtag_init,
|
||||
.quit = presto_jtag_quit,
|
||||
.speed = presto_jtag_speed,
|
||||
.khz = presto_adapter_khz,
|
||||
.speed_div = presto_jtag_speed_div,
|
||||
.init = presto_jtag_init,
|
||||
.quit = presto_jtag_quit,
|
||||
|
||||
.jtag_ops = &presto_interface,
|
||||
};
|
||||
|
||||
@@ -199,7 +199,6 @@ static struct bitbang_interface remote_bitbang_bitbang = {
|
||||
.sample = &remote_bitbang_sample,
|
||||
.read_sample = &remote_bitbang_read_sample,
|
||||
.write = &remote_bitbang_write,
|
||||
.reset = &remote_bitbang_reset,
|
||||
.blink = &remote_bitbang_blink,
|
||||
};
|
||||
|
||||
@@ -342,11 +341,18 @@ static const struct command_registration remote_bitbang_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE,
|
||||
};
|
||||
|
||||
struct jtag_interface remote_bitbang_interface = {
|
||||
.name = "remote_bitbang",
|
||||
static struct jtag_interface remote_bitbang_interface = {
|
||||
.execute_queue = &bitbang_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver remote_bitbang_adapter_driver = {
|
||||
.name = "remote_bitbang",
|
||||
.transports = jtag_only,
|
||||
.commands = remote_bitbang_command_handlers,
|
||||
|
||||
.init = &remote_bitbang_init,
|
||||
.quit = &remote_bitbang_quit,
|
||||
.reset = &remote_bitbang_reset,
|
||||
|
||||
.jtag_ops = &remote_bitbang_interface,
|
||||
};
|
||||
|
||||
@@ -1660,13 +1660,19 @@ static int rlink_quit(void)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct jtag_interface rlink_interface = {
|
||||
static struct jtag_interface rlink_interface = {
|
||||
.execute_queue = rlink_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver rlink_adapter_driver = {
|
||||
.name = "rlink",
|
||||
.transports = jtag_only,
|
||||
|
||||
.init = rlink_init,
|
||||
.quit = rlink_quit,
|
||||
.speed = rlink_speed,
|
||||
.speed_div = rlink_speed_div,
|
||||
.khz = rlink_khz,
|
||||
.execute_queue = rlink_execute_queue,
|
||||
.speed_div = rlink_speed_div,
|
||||
|
||||
.jtag_ops = &rlink_interface,
|
||||
};
|
||||
|
||||
@@ -479,5 +479,3 @@ m4_delay(HOLD_DELAY_CYCLES - 10)
|
||||
A = X
|
||||
DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
|
||||
BRANCH
|
||||
|
||||
|
||||
|
||||
@@ -98,4 +98,3 @@ const struct rlink_speed_table rlink_speed_table[] = {{
|
||||
} };
|
||||
|
||||
const size_t rlink_speed_table_size = ARRAY_SIZE(rlink_speed_table);
|
||||
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Mellanox Technologies Ltd. - All Rights Reserved
|
||||
* Liming Sun <lsun@mellanox.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 <helper/types.h>
|
||||
#include <helper/system.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/list.h>
|
||||
#include <jtag/interface.h>
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <target/arm_adi_v5.h>
|
||||
#include <transport/transport.h>
|
||||
|
||||
/* Rshim channel where the CoreSight register resides. */
|
||||
#define RSH_MMIO_CHANNEL_RSHIM 0x1
|
||||
|
||||
/* APB and tile address translation. */
|
||||
#define RSH_CS_ROM_BASE 0x80000000
|
||||
#define RSH_CS_TILE_BASE 0x44000000
|
||||
#define RSH_CS_TILE_SIZE 0x04000000
|
||||
|
||||
/*
|
||||
* APB-AP Identification Register
|
||||
* The default value is defined in "CoreSight on-chip trace and debug
|
||||
* (Revision: r1p0)", Section 3.16.5 APB-AP register summary.
|
||||
*/
|
||||
#define APB_AP_IDR 0x44770002
|
||||
|
||||
/* CoreSight register definition. */
|
||||
#define RSH_CORESIGHT_CTL 0x0e00
|
||||
#define RSH_CORESIGHT_CTL_GO_SHIFT 0
|
||||
#define RSH_CORESIGHT_CTL_GO_MASK 0x1ULL
|
||||
#define RSH_CORESIGHT_CTL_ACTION_SHIFT 1
|
||||
#define RSH_CORESIGHT_CTL_ACTION_MASK 0x2ULL
|
||||
#define RSH_CORESIGHT_CTL_ADDR_SHIFT 2
|
||||
#define RSH_CORESIGHT_CTL_ADDR_MASK 0x7ffffffcULL
|
||||
#define RSH_CORESIGHT_CTL_ERR_SHIFT 31
|
||||
#define RSH_CORESIGHT_CTL_ERR_MASK 0x80000000ULL
|
||||
#define RSH_CORESIGHT_CTL_DATA_SHIFT 32
|
||||
#define RSH_CORESIGHT_CTL_DATA_MASK 0xffffffff00000000ULL
|
||||
|
||||
/* Util macros to access the CoreSight register. */
|
||||
#define RSH_CS_GET_FIELD(reg, field) \
|
||||
(((uint64_t)(reg) & RSH_CORESIGHT_CTL_##field##_MASK) >> \
|
||||
RSH_CORESIGHT_CTL_##field##_SHIFT)
|
||||
|
||||
#define RSH_CS_SET_FIELD(reg, field, value) \
|
||||
(reg) = (((reg) & ~RSH_CORESIGHT_CTL_##field##_MASK) | \
|
||||
(((uint64_t)(value) << RSH_CORESIGHT_CTL_##field##_SHIFT) & \
|
||||
RSH_CORESIGHT_CTL_##field##_MASK))
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
/* Message used to program rshim via ioctl(). */
|
||||
typedef struct {
|
||||
uint32_t addr;
|
||||
uint64_t data;
|
||||
} __attribute__((packed)) rshim_ioctl_msg;
|
||||
|
||||
enum {
|
||||
RSH_IOC_READ = _IOWR('R', 0, rshim_ioctl_msg),
|
||||
RSH_IOC_WRITE = _IOWR('R', 1, rshim_ioctl_msg),
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Use local variable stub for DP/AP registers. */
|
||||
static uint32_t dp_ctrl_stat;
|
||||
static uint32_t dp_id_code;
|
||||
static uint32_t ap_sel, ap_bank;
|
||||
static uint32_t ap_csw;
|
||||
static uint32_t ap_drw;
|
||||
static uint32_t ap_tar, ap_tar_inc;
|
||||
|
||||
/* Static functions to read/write via rshim/coresight. */
|
||||
static int (*rshim_read)(int chan, int addr, uint64_t *value);
|
||||
static int (*rshim_write)(int chan, int addr, uint64_t value);
|
||||
static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata);
|
||||
static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value);
|
||||
|
||||
/* RShim file handler. */
|
||||
static int rshim_fd = -1;
|
||||
|
||||
/* DAP error code. */
|
||||
static int rshim_dap_retval = ERROR_OK;
|
||||
|
||||
/* Default rshim device. */
|
||||
#define RSHIM_DEV_PATH_DEFAULT "/dev/rshim0/rshim"
|
||||
static char *rshim_dev_path;
|
||||
|
||||
static int rshim_dev_read(int chan, int addr, uint64_t *value)
|
||||
{
|
||||
int rc;
|
||||
|
||||
addr = (addr & 0xFFFF) | (1 << 16);
|
||||
rc = pread(rshim_fd, value, sizeof(*value), addr);
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
if (rc < 0 && errno == ENOSYS) {
|
||||
rshim_ioctl_msg msg;
|
||||
|
||||
msg.addr = addr;
|
||||
msg.data = 0;
|
||||
rc = ioctl(rshim_fd, RSH_IOC_READ, &msg);
|
||||
if (!rc)
|
||||
*value = msg.data;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rshim_dev_write(int chan, int addr, uint64_t value)
|
||||
{
|
||||
int rc;
|
||||
|
||||
addr = (addr & 0xFFFF) | (1 << 16);
|
||||
rc = pwrite(rshim_fd, &value, sizeof(value), addr);
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
if (rc < 0 && errno == ENOSYS) {
|
||||
rshim_ioctl_msg msg;
|
||||
|
||||
msg.addr = addr;
|
||||
msg.data = value;
|
||||
rc = ioctl(rshim_fd, RSH_IOC_WRITE, &msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Convert AP address to tile local address. */
|
||||
static void ap_addr_2_tile(int *tile, uint32_t *addr)
|
||||
{
|
||||
*addr -= RSH_CS_ROM_BASE;
|
||||
|
||||
if (*addr < RSH_CS_TILE_BASE) {
|
||||
*tile = 0;
|
||||
} else {
|
||||
*addr -= RSH_CS_TILE_BASE;
|
||||
*tile = *addr / RSH_CS_TILE_SIZE + 1;
|
||||
*addr = *addr % RSH_CS_TILE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write 4 bytes on the APB bus.
|
||||
* tile = 0: access the root CS_ROM table
|
||||
* > 0: access the ROM table of cluster (tile - 1)
|
||||
*/
|
||||
static int coresight_write(uint32_t tile, uint32_t addr, uint32_t wdata)
|
||||
{
|
||||
uint64_t ctl = 0;
|
||||
int rc;
|
||||
|
||||
if (!rshim_read || !rshim_write)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/*
|
||||
* ADDR[28] - must be set to 1 due to coresight ip.
|
||||
* ADDR[27:24] - linear tile id
|
||||
*/
|
||||
addr = (addr >> 2) | (tile << 24);
|
||||
if (tile)
|
||||
addr |= (1 << 28);
|
||||
RSH_CS_SET_FIELD(ctl, ADDR, addr);
|
||||
RSH_CS_SET_FIELD(ctl, ACTION, 0); /* write */
|
||||
RSH_CS_SET_FIELD(ctl, DATA, wdata);
|
||||
RSH_CS_SET_FIELD(ctl, GO, 1); /* start */
|
||||
|
||||
rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl);
|
||||
|
||||
do {
|
||||
rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM,
|
||||
RSH_CORESIGHT_CTL, &ctl);
|
||||
if (rc < 0) {
|
||||
LOG_ERROR("Failed to read rshim.\n");
|
||||
return rc;
|
||||
}
|
||||
} while (RSH_CS_GET_FIELD(ctl, GO));
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int coresight_read(uint32_t tile, uint32_t addr, uint32_t *value)
|
||||
{
|
||||
uint64_t ctl = 0;
|
||||
int rc;
|
||||
|
||||
if (!rshim_read || !rshim_write)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/*
|
||||
* ADDR[28] - must be set to 1 due to coresight ip.
|
||||
* ADDR[27:24] - linear tile id
|
||||
*/
|
||||
addr = (addr >> 2) | (tile << 24);
|
||||
if (tile)
|
||||
addr |= (1 << 28);
|
||||
RSH_CS_SET_FIELD(ctl, ADDR, addr);
|
||||
RSH_CS_SET_FIELD(ctl, ACTION, 1); /* read */
|
||||
RSH_CS_SET_FIELD(ctl, GO, 1); /* start */
|
||||
|
||||
rshim_write(RSH_MMIO_CHANNEL_RSHIM, RSH_CORESIGHT_CTL, ctl);
|
||||
|
||||
do {
|
||||
rc = rshim_read(RSH_MMIO_CHANNEL_RSHIM,
|
||||
RSH_CORESIGHT_CTL, &ctl);
|
||||
if (rc < 0) {
|
||||
LOG_ERROR("Failed to write rshim.\n");
|
||||
return rc;
|
||||
}
|
||||
} while (RSH_CS_GET_FIELD(ctl, GO));
|
||||
|
||||
*value = RSH_CS_GET_FIELD(ctl, DATA);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dp_q_read(struct adiv5_dap *dap, unsigned int reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return ERROR_OK;
|
||||
|
||||
switch (reg) {
|
||||
case DP_DPIDR:
|
||||
*data = dp_id_code;
|
||||
break;
|
||||
|
||||
case DP_CTRL_STAT:
|
||||
*data = CDBGPWRUPACK | CSYSPWRUPACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dp_q_write(struct adiv5_dap *dap, unsigned int reg,
|
||||
uint32_t data)
|
||||
{
|
||||
switch (reg) {
|
||||
case DP_CTRL_STAT:
|
||||
dp_ctrl_stat = data;
|
||||
break;
|
||||
case DP_SELECT:
|
||||
ap_sel = (data & DP_SELECT_APSEL) >> 24;
|
||||
ap_bank = (data & DP_SELECT_APBANK) >> 4;
|
||||
break;
|
||||
default:
|
||||
LOG_INFO("Unknown command");
|
||||
break;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_ap_q_read(struct adiv5_ap *ap, unsigned int reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
uint32_t addr;
|
||||
int rc = ERROR_OK, tile;
|
||||
|
||||
switch (reg) {
|
||||
case MEM_AP_REG_CSW:
|
||||
*data = ap_csw;
|
||||
break;
|
||||
|
||||
case MEM_AP_REG_CFG:
|
||||
*data = 0;
|
||||
break;
|
||||
|
||||
case MEM_AP_REG_BASE:
|
||||
*data = RSH_CS_ROM_BASE;
|
||||
break;
|
||||
|
||||
case AP_REG_IDR:
|
||||
if (ap->ap_num == 0)
|
||||
*data = APB_AP_IDR;
|
||||
else
|
||||
*data = 0;
|
||||
break;
|
||||
|
||||
case MEM_AP_REG_BD0:
|
||||
case MEM_AP_REG_BD1:
|
||||
case MEM_AP_REG_BD2:
|
||||
case MEM_AP_REG_BD3:
|
||||
addr = (ap_tar & ~0xf) + (reg & 0x0C);
|
||||
ap_addr_2_tile(&tile, &addr);
|
||||
rc = coresight_read(tile, addr, data);
|
||||
break;
|
||||
|
||||
case MEM_AP_REG_DRW:
|
||||
addr = (ap_tar & ~0x3) + ap_tar_inc;
|
||||
ap_addr_2_tile(&tile, &addr);
|
||||
rc = coresight_read(tile, addr, data);
|
||||
if (!rc && (ap_csw & CSW_ADDRINC_MASK))
|
||||
ap_tar_inc += (ap_csw & 0x03) * 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_INFO("Unknown command");
|
||||
rc = ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Track the last error code. */
|
||||
if (rc != ERROR_OK)
|
||||
rshim_dap_retval = rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rshim_ap_q_write(struct adiv5_ap *ap, unsigned int reg,
|
||||
uint32_t data)
|
||||
{
|
||||
int rc = ERROR_OK, tile;
|
||||
uint32_t addr;
|
||||
|
||||
if (ap_bank != 0) {
|
||||
rshim_dap_retval = ERROR_FAIL;
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case MEM_AP_REG_CSW:
|
||||
ap_csw = data;
|
||||
break;
|
||||
|
||||
case MEM_AP_REG_TAR:
|
||||
ap_tar = data;
|
||||
ap_tar_inc = 0;
|
||||
break;
|
||||
|
||||
case MEM_AP_REG_BD0:
|
||||
case MEM_AP_REG_BD1:
|
||||
case MEM_AP_REG_BD2:
|
||||
case MEM_AP_REG_BD3:
|
||||
addr = (ap_tar & ~0xf) + (reg & 0x0C);
|
||||
ap_addr_2_tile(&tile, &addr);
|
||||
rc = coresight_write(tile, addr, data);
|
||||
break;
|
||||
|
||||
case MEM_AP_REG_DRW:
|
||||
ap_drw = data;
|
||||
addr = (ap_tar & ~0x3) + ap_tar_inc;
|
||||
ap_addr_2_tile(&tile, &addr);
|
||||
rc = coresight_write(tile, addr, data);
|
||||
if (!rc && (ap_csw & CSW_ADDRINC_MASK))
|
||||
ap_tar_inc += (ap_csw & 0x03) * 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Track the last error code. */
|
||||
if (rc != ERROR_OK)
|
||||
rshim_dap_retval = rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rshim_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dp_run(struct adiv5_dap *dap)
|
||||
{
|
||||
int retval = rshim_dap_retval;
|
||||
|
||||
/* Clear the error code. */
|
||||
rshim_dap_retval = ERROR_OK;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rshim_connect(struct adiv5_dap *dap)
|
||||
{
|
||||
char *path = rshim_dev_path ? rshim_dev_path : RSHIM_DEV_PATH_DEFAULT;
|
||||
|
||||
rshim_fd = open(path, O_RDWR | O_SYNC);
|
||||
if (rshim_fd == -1) {
|
||||
LOG_ERROR("Unable to open %s\n", path);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set read/write operation via the device file. Funtion pointers
|
||||
* are used here so more ways like remote accessing via socket could
|
||||
* be added later.
|
||||
*/
|
||||
rshim_read = rshim_dev_read;
|
||||
rshim_write = rshim_dev_write;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void rshim_disconnect(struct adiv5_dap *dap)
|
||||
{
|
||||
if (rshim_fd != -1) {
|
||||
close(rshim_fd);
|
||||
rshim_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(rshim_dap_device_command)
|
||||
{
|
||||
if (CMD_ARGC != 1) {
|
||||
command_print(CMD, "Too many arguments");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
free(rshim_dev_path);
|
||||
rshim_dev_path = strdup(CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration rshim_dap_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "device",
|
||||
.handler = rshim_dap_device_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the rshim device",
|
||||
.usage = "</dev/rshim<N>/rshim>",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration rshim_dap_command_handlers[] = {
|
||||
{
|
||||
.name = "rshim",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "perform rshim management",
|
||||
.chain = rshim_dap_subcommand_handlers,
|
||||
.usage = "",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static int rshim_dap_init(void)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dap_quit(void)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dap_reset(int req_trst, int req_srst)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dap_speed(int speed)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dap_khz(int khz, int *jtag_speed)
|
||||
{
|
||||
*jtag_speed = khz;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int rshim_dap_speed_div(int speed, int *khz)
|
||||
{
|
||||
*khz = speed;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* DAP operations. */
|
||||
static const struct dap_ops rshim_dap_ops = {
|
||||
.connect = rshim_connect,
|
||||
.queue_dp_read = rshim_dp_q_read,
|
||||
.queue_dp_write = rshim_dp_q_write,
|
||||
.queue_ap_read = rshim_ap_q_read,
|
||||
.queue_ap_write = rshim_ap_q_write,
|
||||
.queue_ap_abort = rshim_ap_q_abort,
|
||||
.run = rshim_dp_run,
|
||||
.quit = rshim_disconnect,
|
||||
};
|
||||
|
||||
static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL };
|
||||
|
||||
struct adapter_driver rshim_dap_adapter_driver = {
|
||||
.name = "rshim",
|
||||
.transports = rshim_dap_transport,
|
||||
.commands = rshim_dap_command_handlers,
|
||||
|
||||
.init = rshim_dap_init,
|
||||
.quit = rshim_dap_quit,
|
||||
.reset = rshim_dap_reset,
|
||||
.speed = rshim_dap_speed,
|
||||
.khz = rshim_dap_khz,
|
||||
.speed_div = rshim_dap_speed_div,
|
||||
|
||||
.dap_swd_ops = &rshim_dap_ops,
|
||||
};
|
||||
+1002
-153
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <helper/time_support.h>
|
||||
#include <jtag/interface.h>
|
||||
#include "bitbang.h"
|
||||
|
||||
@@ -60,7 +61,7 @@
|
||||
*
|
||||
* Assume here that there will be less than 10000 gpios on a system
|
||||
*/
|
||||
static int is_gpio_valid(int gpio)
|
||||
static bool is_gpio_valid(int gpio)
|
||||
{
|
||||
return gpio >= 0 && gpio < 10000;
|
||||
}
|
||||
@@ -97,8 +98,6 @@ static void unexport_sysfs_gpio(int gpio)
|
||||
snprintf(gpiostr, sizeof(gpiostr), "%d", gpio);
|
||||
if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0)
|
||||
LOG_ERROR("Couldn't unexport gpio %d", gpio);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -112,6 +111,7 @@ static void unexport_sysfs_gpio(int gpio)
|
||||
*/
|
||||
static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
|
||||
{
|
||||
struct timeval timeout, now;
|
||||
char buf[40];
|
||||
char gpiostr[5];
|
||||
int ret;
|
||||
@@ -131,8 +131,19 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&timeout, NULL);
|
||||
timeval_add_time(&timeout, 0, 500000);
|
||||
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio);
|
||||
ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
|
||||
for (;;) {
|
||||
ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
|
||||
if (ret >= 0 || errno != EACCES)
|
||||
break;
|
||||
gettimeofday(&now, NULL);
|
||||
if (timeval_compare(&now, &timeout) >= 0)
|
||||
break;
|
||||
jtag_sleep(10000);
|
||||
}
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("Couldn't set direction for gpio %d", gpio);
|
||||
perror("sysfsgpio: ");
|
||||
@@ -141,7 +152,15 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
|
||||
ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
|
||||
for (;;) {
|
||||
ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
|
||||
if (ret >= 0 || errno != EACCES)
|
||||
break;
|
||||
gettimeofday(&now, NULL);
|
||||
if (timeval_compare(&now, &timeout) >= 0)
|
||||
break;
|
||||
jtag_sleep(10000);
|
||||
}
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("Couldn't open value for gpio %d", gpio);
|
||||
perror("sysfsgpio: ");
|
||||
@@ -530,21 +549,27 @@ static int sysfsgpio_quit(void);
|
||||
|
||||
static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL };
|
||||
|
||||
struct jtag_interface sysfsgpio_interface = {
|
||||
.name = "sysfsgpio",
|
||||
static struct jtag_interface sysfsgpio_interface = {
|
||||
.supported = DEBUG_CAP_TMS_SEQ,
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
};
|
||||
|
||||
struct adapter_driver sysfsgpio_adapter_driver = {
|
||||
.name = "sysfsgpio",
|
||||
.transports = sysfsgpio_transports,
|
||||
.swd = &bitbang_swd,
|
||||
.commands = sysfsgpio_command_handlers,
|
||||
|
||||
.init = sysfsgpio_init,
|
||||
.quit = sysfsgpio_quit,
|
||||
.reset = sysfsgpio_reset,
|
||||
|
||||
.jtag_ops = &sysfsgpio_interface,
|
||||
.swd_ops = &bitbang_swd,
|
||||
};
|
||||
|
||||
static struct bitbang_interface sysfsgpio_bitbang = {
|
||||
.read = sysfsgpio_read,
|
||||
.write = sysfsgpio_write,
|
||||
.reset = sysfsgpio_reset,
|
||||
.swdio_read = sysfsgpio_swdio_read,
|
||||
.swdio_drive = sysfsgpio_swdio_drive,
|
||||
.blink = 0
|
||||
@@ -576,23 +601,23 @@ static void cleanup_all_fds(void)
|
||||
static bool sysfsgpio_jtag_mode_possible(void)
|
||||
{
|
||||
if (!is_gpio_valid(tck_gpio))
|
||||
return 0;
|
||||
return false;
|
||||
if (!is_gpio_valid(tms_gpio))
|
||||
return 0;
|
||||
return false;
|
||||
if (!is_gpio_valid(tdi_gpio))
|
||||
return 0;
|
||||
return false;
|
||||
if (!is_gpio_valid(tdo_gpio))
|
||||
return 0;
|
||||
return 1;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sysfsgpio_swd_mode_possible(void)
|
||||
{
|
||||
if (!is_gpio_valid(swclk_gpio))
|
||||
return 0;
|
||||
return false;
|
||||
if (!is_gpio_valid(swdio_gpio))
|
||||
return 0;
|
||||
return 1;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int sysfsgpio_init(void)
|
||||
@@ -688,4 +713,3 @@ static int sysfsgpio_quit(void)
|
||||
cleanup_all_fds();
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
+33
-43
@@ -235,7 +235,7 @@ int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd);
|
||||
int ulink_post_process_scan(struct ulink_cmd *ulink_cmd);
|
||||
int ulink_post_process_queue(struct ulink *device);
|
||||
|
||||
/* JTAG driver functions (registered in struct jtag_interface) */
|
||||
/* adapter driver functions */
|
||||
static int ulink_execute_queue(void);
|
||||
static int ulink_khz(int khz, int *jtag_speed);
|
||||
static int ulink_speed(int speed);
|
||||
@@ -650,7 +650,7 @@ void ulink_clear_queue(struct ulink *device)
|
||||
int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
|
||||
{
|
||||
int newsize_out, newsize_in;
|
||||
int ret;
|
||||
int ret = ERROR_OK;
|
||||
|
||||
newsize_out = ulink_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1
|
||||
+ ulink_cmd->payload_out_size;
|
||||
@@ -663,14 +663,12 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
|
||||
/* New command does not fit. Execute all commands in queue before starting
|
||||
* new queue with the current command as first entry. */
|
||||
ret = ulink_execute_queued_commands(device, USB_TIMEOUT);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
|
||||
ret = ulink_post_process_queue(device);
|
||||
if (ret != ERROR_OK)
|
||||
return ret;
|
||||
if (ret == ERROR_OK)
|
||||
ret = ulink_post_process_queue(device);
|
||||
|
||||
ulink_clear_queue(device);
|
||||
if (ret == ERROR_OK)
|
||||
ulink_clear_queue(device);
|
||||
}
|
||||
|
||||
if (device->queue_start == NULL) {
|
||||
@@ -687,7 +685,10 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd)
|
||||
device->queue_end = ulink_cmd;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
if (ret != ERROR_OK)
|
||||
ulink_clear_queue(device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -764,58 +765,40 @@ static const char *ulink_cmd_id_string(uint8_t id)
|
||||
switch (id) {
|
||||
case CMD_SCAN_IN:
|
||||
return "CMD_SCAN_IN";
|
||||
break;
|
||||
case CMD_SLOW_SCAN_IN:
|
||||
return "CMD_SLOW_SCAN_IN";
|
||||
break;
|
||||
case CMD_SCAN_OUT:
|
||||
return "CMD_SCAN_OUT";
|
||||
break;
|
||||
case CMD_SLOW_SCAN_OUT:
|
||||
return "CMD_SLOW_SCAN_OUT";
|
||||
break;
|
||||
case CMD_SCAN_IO:
|
||||
return "CMD_SCAN_IO";
|
||||
break;
|
||||
case CMD_SLOW_SCAN_IO:
|
||||
return "CMD_SLOW_SCAN_IO";
|
||||
break;
|
||||
case CMD_CLOCK_TMS:
|
||||
return "CMD_CLOCK_TMS";
|
||||
break;
|
||||
case CMD_SLOW_CLOCK_TMS:
|
||||
return "CMD_SLOW_CLOCK_TMS";
|
||||
break;
|
||||
case CMD_CLOCK_TCK:
|
||||
return "CMD_CLOCK_TCK";
|
||||
break;
|
||||
case CMD_SLOW_CLOCK_TCK:
|
||||
return "CMD_SLOW_CLOCK_TCK";
|
||||
break;
|
||||
case CMD_SLEEP_US:
|
||||
return "CMD_SLEEP_US";
|
||||
break;
|
||||
case CMD_SLEEP_MS:
|
||||
return "CMD_SLEEP_MS";
|
||||
break;
|
||||
case CMD_GET_SIGNALS:
|
||||
return "CMD_GET_SIGNALS";
|
||||
break;
|
||||
case CMD_SET_SIGNALS:
|
||||
return "CMD_SET_SIGNALS";
|
||||
break;
|
||||
case CMD_CONFIGURE_TCK_FREQ:
|
||||
return "CMD_CONFIGURE_TCK_FREQ";
|
||||
break;
|
||||
case CMD_SET_LEDS:
|
||||
return "CMD_SET_LEDS";
|
||||
break;
|
||||
case CMD_TEST:
|
||||
return "CMD_TEST";
|
||||
break;
|
||||
default:
|
||||
return "CMD_UNKNOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1627,6 +1610,7 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd)
|
||||
|
||||
if (ret != ERROR_OK) {
|
||||
free(tdi_buffer_start);
|
||||
free(tdo_buffer_start);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -2209,14 +2193,17 @@ static int ulink_init(void)
|
||||
}
|
||||
ulink_clear_queue(ulink_handle);
|
||||
|
||||
ulink_append_get_signals_cmd(ulink_handle);
|
||||
ulink_execute_queued_commands(ulink_handle, 200);
|
||||
ret = ulink_append_get_signals_cmd(ulink_handle);
|
||||
if (ret == ERROR_OK)
|
||||
ret = ulink_execute_queued_commands(ulink_handle, 200);
|
||||
|
||||
/* Post-process the single CMD_GET_SIGNALS command */
|
||||
input_signals = ulink_handle->queue_start->payload_in[0];
|
||||
output_signals = ulink_handle->queue_start->payload_in[1];
|
||||
if (ret == ERROR_OK) {
|
||||
/* Post-process the single CMD_GET_SIGNALS command */
|
||||
input_signals = ulink_handle->queue_start->payload_in[0];
|
||||
output_signals = ulink_handle->queue_start->payload_in[1];
|
||||
|
||||
ulink_print_signal_states(input_signals, output_signals);
|
||||
ulink_print_signal_states(input_signals, output_signals);
|
||||
}
|
||||
|
||||
ulink_clear_queue(ulink_handle);
|
||||
|
||||
@@ -2272,17 +2259,20 @@ static const struct command_registration ulink_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE,
|
||||
};
|
||||
|
||||
struct jtag_interface ulink_interface = {
|
||||
.name = "ulink",
|
||||
|
||||
.commands = ulink_command_handlers,
|
||||
.transports = jtag_only,
|
||||
|
||||
static struct jtag_interface ulink_interface = {
|
||||
.execute_queue = ulink_execute_queue,
|
||||
.khz = ulink_khz,
|
||||
.speed = ulink_speed,
|
||||
.speed_div = ulink_speed_div,
|
||||
};
|
||||
|
||||
struct adapter_driver ulink_adapter_driver = {
|
||||
.name = "ulink",
|
||||
.transports = jtag_only,
|
||||
.commands = ulink_command_handlers,
|
||||
|
||||
.init = ulink_init,
|
||||
.quit = ulink_quit
|
||||
.quit = ulink_quit,
|
||||
.speed = ulink_speed,
|
||||
.khz = ulink_khz,
|
||||
.speed_div = ulink_speed_div,
|
||||
|
||||
.jtag_ops = &ulink_interface,
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#endif
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <libusb_common.h>
|
||||
#include <libusb_helper.h>
|
||||
#include <target/image.h>
|
||||
|
||||
#include "ublast_access.h"
|
||||
@@ -42,28 +42,37 @@
|
||||
static int ublast2_libusb_read(struct ublast_lowlevel *low, uint8_t *buf,
|
||||
unsigned size, uint32_t *bytes_read)
|
||||
{
|
||||
*bytes_read = jtag_libusb_bulk_read(low->libusb_dev,
|
||||
USBBLASTER_EPIN | \
|
||||
int ret, tmp = 0;
|
||||
|
||||
ret = jtag_libusb_bulk_read(low->libusb_dev,
|
||||
USBBLASTER_EPIN |
|
||||
LIBUSB_ENDPOINT_IN,
|
||||
(char *)buf,
|
||||
size,
|
||||
100);
|
||||
return ERROR_OK;
|
||||
100, &tmp);
|
||||
*bytes_read = tmp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ublast2_libusb_write(struct ublast_lowlevel *low, uint8_t *buf,
|
||||
int size, uint32_t *bytes_written)
|
||||
{
|
||||
*bytes_written = jtag_libusb_bulk_write(low->libusb_dev,
|
||||
USBBLASTER_EPOUT | \
|
||||
int ret, tmp = 0;
|
||||
|
||||
ret = jtag_libusb_bulk_write(low->libusb_dev,
|
||||
USBBLASTER_EPOUT |
|
||||
LIBUSB_ENDPOINT_OUT,
|
||||
(char *)buf,
|
||||
size,
|
||||
100);
|
||||
return ERROR_OK;
|
||||
100, &tmp);
|
||||
*bytes_written = tmp;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libusb_dev,
|
||||
static int ublast2_write_firmware_section(struct libusb_device_handle *libusb_dev,
|
||||
struct image *firmware_image, int section_index)
|
||||
{
|
||||
uint16_t chunk_size;
|
||||
@@ -97,7 +106,7 @@ static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libu
|
||||
chunk_size = bytes_remaining;
|
||||
|
||||
jtag_libusb_control_transfer(libusb_dev,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | \
|
||||
LIBUSB_REQUEST_TYPE_VENDOR |
|
||||
LIBUSB_ENDPOINT_OUT,
|
||||
USBBLASTER_CTRL_LOAD_FIRM,
|
||||
addr,
|
||||
@@ -114,7 +123,7 @@ static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libu
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_dev,
|
||||
static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
|
||||
struct ublast_lowlevel *low)
|
||||
{
|
||||
struct image ublast2_firmware_image;
|
||||
@@ -143,7 +152,7 @@ static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_de
|
||||
|
||||
char value = CPU_RESET;
|
||||
jtag_libusb_control_transfer(libusb_dev,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | \
|
||||
LIBUSB_REQUEST_TYPE_VENDOR |
|
||||
LIBUSB_ENDPOINT_OUT,
|
||||
USBBLASTER_CTRL_LOAD_FIRM,
|
||||
EZUSB_CPUCS,
|
||||
@@ -164,7 +173,7 @@ static int load_usb_blaster_firmware(struct jtag_libusb_device_handle *libusb_de
|
||||
|
||||
value = !CPU_RESET;
|
||||
jtag_libusb_control_transfer(libusb_dev,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | \
|
||||
LIBUSB_REQUEST_TYPE_VENDOR |
|
||||
LIBUSB_ENDPOINT_OUT,
|
||||
USBBLASTER_CTRL_LOAD_FIRM,
|
||||
EZUSB_CPUCS,
|
||||
@@ -182,11 +191,11 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
|
||||
{
|
||||
const uint16_t vids[] = { low->ublast_vid_uninit, 0 };
|
||||
const uint16_t pids[] = { low->ublast_pid_uninit, 0 };
|
||||
struct jtag_libusb_device_handle *temp;
|
||||
struct libusb_device_handle *temp;
|
||||
bool renumeration = false;
|
||||
int ret;
|
||||
|
||||
if (jtag_libusb_open(vids, pids, NULL, &temp) == ERROR_OK) {
|
||||
if (jtag_libusb_open(vids, pids, NULL, &temp, NULL) == ERROR_OK) {
|
||||
LOG_INFO("Altera USB-Blaster II (uninitialized) found");
|
||||
LOG_INFO("Loading firmware...");
|
||||
ret = load_usb_blaster_firmware(temp, low);
|
||||
@@ -200,13 +209,15 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
|
||||
const uint16_t pids_renum[] = { low->ublast_pid, 0 };
|
||||
|
||||
if (renumeration == false) {
|
||||
if (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != ERROR_OK) {
|
||||
if (jtag_libusb_open(vids_renum, pids_renum, NULL,
|
||||
&low->libusb_dev, NULL) != ERROR_OK) {
|
||||
LOG_ERROR("Altera USB-Blaster II not found");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
int retry = 10;
|
||||
while (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != ERROR_OK && retry--) {
|
||||
while (jtag_libusb_open(vids_renum, pids_renum, NULL,
|
||||
&low->libusb_dev, NULL) != ERROR_OK && retry--) {
|
||||
usleep(1000000);
|
||||
LOG_INFO("Waiting for renumerate...");
|
||||
}
|
||||
@@ -219,7 +230,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
|
||||
|
||||
char buffer[5];
|
||||
jtag_libusb_control_transfer(low->libusb_dev,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | \
|
||||
LIBUSB_REQUEST_TYPE_VENDOR |
|
||||
LIBUSB_ENDPOINT_IN,
|
||||
USBBLASTER_CTRL_READ_REV,
|
||||
0,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user