diff options
Diffstat (limited to 'src/jtag')
71 files changed, 4244 insertions, 1504 deletions
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index a764863..b82914b 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -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) diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 29a9613..af75917 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -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,78 +524,103 @@ static const struct command_registration adapter_usb_command_handlers[] = { }; #endif /* MINIDRIVER */ -static const struct command_registration adapter_command_handlers[] = { -#ifndef HAVE_JTAG_MINIDRIVER_H +static const struct command_registration adapter_srst_command_handlers[] = { { - .name = "usb", + .name = "delay", + .handler = handle_adapter_srst_delay_command, .mode = COMMAND_ANY, - .help = "usb adapter command group", - .usage = "", - .chain = adapter_usb_command_handlers, + .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]", }, -#endif /* MINIDRIVER */ COMMAND_REGISTRATION_DONE }; -static const struct command_registration interface_command_handlers[] = { +static const struct command_registration adapter_command_handlers[] = { { - .name = "adapter", - .mode = COMMAND_ANY, - .help = "adapter command group", - .usage = "", - .chain = adapter_command_handlers, + .name = "driver", + .handler = handle_adapter_driver_command, + .mode = COMMAND_CONFIG, + .help = "Select a debug adapter driver", + .usage = "driver_name", }, { - .name = "adapter_khz", - .handler = handle_adapter_khz_command, + .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. " + "clocking. " "With or without argument, display current setting.", .usage = "[khz]", }, { - .name = "adapter_name", + .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 = "adapter_nsrst_delay", - .handler = handle_adapter_nsrst_delay_command, + .name = "srst", .mode = COMMAND_ANY, - .help = "delay after deasserting SRST in ms", - .usage = "[milliseconds]", + .help = "srst adapter command group", + .usage = "", + .chain = adapter_srst_command_handlers, }, { - .name = "adapter_nsrst_assert_width", - .handler = handle_adapter_nsrst_assert_width_command, + .name = "transports", + .handler = adapter_transports_command, + .mode = COMMAND_CONFIG, + .help = "Declare transports the adapter supports.", + .usage = "transport ... ", + }, +#ifndef HAVE_JTAG_MINIDRIVER_H + { + .name = "usb", .mode = COMMAND_ANY, - .help = "delay after asserting SRST in ms", - .usage = "[milliseconds]", + .help = "usb adapter command group", + .usage = "", + .chain = adapter_usb_command_handlers, }, +#endif /* MINIDRIVER */ { - .name = "interface", - .handler = handle_interface_command, - .mode = COMMAND_CONFIG, - .help = "Select a debug adapter interface (driver)", - .usage = "driver_name", + .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 = "interface_transports", - .handler = interface_transport_command, - .mode = COMMAND_CONFIG, - .help = "Declare transports the interface supports.", - .usage = "transport ... ", + .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 +}; + +static const struct command_registration interface_command_handlers[] = { { - .name = "interface_list", - .handler = handle_interface_list_command, + .name = "adapter", .mode = COMMAND_ANY, - .help = "List all built-in debug adapter interfaces (drivers)", + .help = "adapter command group", .usage = "", + .chain = adapter_command_handlers, }, { .name = "reset_config", diff --git a/src/jtag/aice/aice_interface.c b/src/jtag/aice/aice_interface.c index c83b8c2..90871a1 100644 --- a/src/jtag/aice/aice_interface.c +++ b/src/jtag/aice/aice_interface.c @@ -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, }; diff --git a/src/jtag/aice/aice_transport.c b/src/jtag/aice/aice_transport.c index 15ebcac..ea710ad 100644 --- a/src/jtag/aice/aice_transport.c +++ b/src/jtag/aice/aice_transport.c @@ -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); } - diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c index 324ec7c..4427542 100644 --- a/src/jtag/aice/aice_usb.c +++ b/src/jtag/aice/aice_usb.c @@ -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) { diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h index 15cc1f6..04021de 100644 --- a/src/jtag/aice/aice_usb.h +++ b/src/jtag/aice/aice_usb.h @@ -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 { diff --git a/src/jtag/commands.c b/src/jtag/commands.c index 3352e03..e88a3b7 100644 --- a/src/jtag/commands.c +++ b/src/jtag/commands.c @@ -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; diff --git a/src/jtag/core.c b/src/jtag/core.c index 5e7c1e4..1d424b2 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -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,22 +611,91 @@ 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) { + retval = jtag->reset(0, req_srst); + if (retval != ERROR_OK) { + LOG_ERROR("SRST error"); + return ERROR_FAIL; + } + jtag_srst = req_srst; + + if (req_srst) { + LOG_DEBUG("SRST line asserted"); + if (adapter_nsrst_assert_width) + jtag_sleep(adapter_nsrst_assert_width * 1000); + } else { + LOG_DEBUG("SRST line released"); + if (adapter_nsrst_delay) + jtag_sleep(adapter_nsrst_delay * 1000); + } + } + + return ERROR_OK; +} + +static void legacy_jtag_add_reset(int req_tlr_or_trst, int req_srst) +{ + int trst_with_tlr = 0; + int new_srst = 0; + int new_trst = 0; + + /* 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) { int retval; - retval = interface_jtag_add_reset(0, req_srst); + retval = interface_jtag_add_reset(new_trst, new_srst); if (retval != ERROR_OK) jtag_set_error(retval); else @@ -636,9 +705,11 @@ void swd_add_reset(int req_srst) LOG_ERROR("TRST/SRST error"); return; } + } - /* SRST resets everything hooked up to that signal */ - jtag_srst = req_srst; + /* 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) @@ -648,21 +719,54 @@ void swd_add_reset(int req_srst) 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; + /* 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(); + + } 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); } } } +/* 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. @@ -704,15 +808,12 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) /* Maybe change TRST and/or SRST signal state */ if (jtag_srst != new_srst || jtag_trst != new_trst) { - int retval; - - retval = interface_jtag_add_reset(new_trst, new_srst); - if (retval != ERROR_OK) - jtag_set_error(retval); - else - retval = jtag_execute_queue(); + /* 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; } @@ -741,6 +842,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) 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; @@ -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; } diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 572cd24..07824f6 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -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 - diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index 045672f..f5918a0 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -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, }; diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 285bf9b..405278b 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -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 = { +static struct jtag_interface armjtagew_interface = { + .execute_queue = armjtagew_execute_queue, +}; + +struct adapter_driver armjtagew_adapter_driver = { .name = "arm-jtag-ew", - .commands = armjtagew_command_handlers, .transports = jtag_only, - .execute_queue = armjtagew_execute_queue, - .speed = armjtagew_speed, - .speed_div = armjtagew_speed_div, - .khz = armjtagew_khz, + .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); diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index ac65563..1026847 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -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) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 36e10b6..df557c5 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -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, - .speed = bcm2835gpio_speed, - .khz = bcm2835gpio_khz, - .speed_div = bcm2835gpio_speed_div, .commands = bcm2835gpio_command_handlers, + .init = bcm2835gpio_init, .quit = bcm2835gpio_quit, + .reset = bcm2835gpio_reset, + .speed = bcm2835gpio_speed, + .khz = bcm2835gpio_khz, + .speed_div = bcm2835gpio_speed_div, + + .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; diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index b5078c0..72e9320 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -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, diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h index 577717e..bbbc693 100644 --- a/src/jtag/drivers/bitbang.h +++ b/src/jtag/drivers/bitbang.h @@ -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; diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 872896b..020c4ce 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -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) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index d52d698..ee1cb53 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -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, + .execute_queue = cmsis_dap_execute_queue, +}; + +struct adapter_driver cmsis_dap_adapter_driver = { + .name = "cmsis-dap", .transports = cmsis_dap_transport, + .commands = cmsis_dap_command_handlers, - .execute_queue = cmsis_dap_execute_queue, - .speed = cmsis_dap_speed, - .speed_div = cmsis_dap_speed_div, - .khz = cmsis_dap_khz, .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, }; diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index 4e5b615..e66cb6b 100644 --- a/src/jtag/drivers/dummy.c +++ b/src/jtag/drivers/dummy.c @@ -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", - - .supported = DEBUG_CAP_TMS_SEQ, - .commands = dummy_command_handlers, - .transports = jtag_only, +static struct jtag_interface dummy_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = &bitbang_execute_queue, +}; - .execute_queue = &bitbang_execute_queue, +struct adapter_driver dummy_adapter_driver = { + .name = "dummy", + .transports = jtag_only, + .commands = dummy_command_handlers, - .speed = &dummy_speed, - .khz = &dummy_khz, - .speed_div = &dummy_speed_div, + .init = &dummy_init, + .quit = &dummy_quit, + .reset = &dummy_reset, + .speed = &dummy_speed, + .khz = &dummy_khz, + .speed_div = &dummy_speed_div, - .init = &dummy_init, - .quit = &dummy_quit, - }; + .jtag_ops = &dummy_interface, +}; diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index 4cf3184..5e0e62a 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -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, }; diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index 8cda76e..c9ed304 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -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, }; diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index ebe6016..34b42b8 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -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); - - if (cmd->cmd.reset->trst == 1 - || (cmd->cmd.reset->srst - && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) - tap_set_state(TAP_RESET); - - struct signal *trst = find_signal_by_name("nTRST"); - if (cmd->cmd.reset->trst == 1) { - if (trst) - ftdi_set_signal(trst, '0'); + struct signal *sig_ntrst = find_signal_by_name("nTRST"); + struct signal *sig_nsrst = find_signal_by_name("nSRST"); + + LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); + + 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) @@ -663,7 +657,6 @@ static void ftdi_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_RESET: - ftdi_execute_reset(cmd); #if BUILD_FTDI_OSCAN1 == 1 oscan1_reset_online_activate(); /* put the target back into OSCAN1 mode */ #endif @@ -727,6 +720,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 +1590,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, }; diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index e65f56c..d1699ef 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -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, }; diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index 4923dab..7dcfb67 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -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, - .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, + .reset = imx_gpio_reset, + .speed = imx_gpio_speed, + .khz = imx_gpio_khz, + .speed_div = imx_gpio_speed_div, + + .jtag_ops = &imx_gpio_interface, + .swd_ops = &bitbang_swd, }; static bool imx_gpio_jtag_mode_possible(void) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 09b3a85..1baf345 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -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; + + 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; - min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div))); + if (presc > TPIU_ACPR_MAX_SWOSCALER) + break; - for (divider = speed.min_div; divider < speed.max_div; divider++) { - deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider))); + deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq)); - if (deviation < 0.03) { - LOG_DEBUG("Found suitable frequency divider %u with deviation of " - "%.02f %%.", divider, deviation); + 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)) { - LOG_ERROR("Trace capturing is not supported by the device."); - return ERROR_FAIL; - } + if (!enabled) + return ERROR_OK; - if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { - LOG_ERROR("Selected pin protocol is not supported."); + LOG_ERROR("Trace capturing is not supported by the device."); 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 (*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_INFO("Given SWO frequency is not supported by the device, " + "using %u Hz instead.", *trace_freq); + } - if (!check_trace_freq(speed, *trace_freq)) - return ERROR_FAIL; + 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."); - LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size); + 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 = { +static struct jtag_interface jlink_interface = { + .execute_queue = &jlink_execute_queue, +}; + +struct adapter_driver jlink_adapter_driver = { .name = "jlink", - .commands = jlink_command_handlers, .transports = jlink_transports, - .swd = &jlink_swd, - .execute_queue = &jlink_execute_queue, - .speed = &jlink_speed, - .speed_div = &jlink_speed_div, - .khz = &jlink_khz, + .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, }; diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index 1033ced..a5a95a5 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -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; + +/* Send CMD_STOP_SIMU to server when OpenOCD exits? */ +static bool stop_sim_on_exit; -int sockfd; -struct sockaddr_in serv_addr; +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, }; diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index e3ad84d..efb8da2 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -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, }; diff --git a/src/jtag/drivers/libusb0_common.c b/src/jtag/drivers/libusb0_common.c deleted file mode 100644 index 14a8b61..0000000 --- a/src/jtag/drivers/libusb0_common.c +++ /dev/null @@ -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; -} diff --git a/src/jtag/drivers/libusb0_common.h b/src/jtag/drivers/libusb0_common.h deleted file mode 100644 index 676f43a..0000000 --- a/src/jtag/drivers/libusb0_common.h +++ /dev/null @@ -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 */ diff --git a/src/jtag/drivers/libusb_common.h b/src/jtag/drivers/libusb_common.h deleted file mode 100644 index 599a0a9..0000000 --- a/src/jtag/drivers/libusb_common.h +++ /dev/null @@ -1,27 +0,0 @@ -/*************************************************************************** - * 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_LIBUSB_COMMON_H -#define OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H - -#ifdef HAVE_LIBUSB1 -#include "libusb1_common.h" -#else -#include "libusb0_common.h" -#endif - -#endif /* OPENOCD_JTAG_DRIVERS_LIBUSB_COMMON_H */ diff --git a/src/jtag/drivers/libusb1_common.c b/src/jtag/drivers/libusb_helper.c index d96ac76..184882a 100644 --- a/src/jtag/drivers/libusb1_common.c +++ b/src/jtag/drivers/libusb_helper.c @@ -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; diff --git a/src/jtag/drivers/libusb1_common.h b/src/jtag/drivers/libusb_helper.h index 7c73d29..74bb23c 100644 --- a/src/jtag/drivers/libusb1_common.h +++ b/src/jtag/drivers/libusb_helper.h @@ -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 */ diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index c0d883b..7488d9d 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -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; } } diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 5f352af..bb223f4 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -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); diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 7a3aa23..7eab5c1 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -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, +}; diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index 5db36a1..dc23666 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -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", +static struct jtag_interface osbdm_interface = { + .execute_queue = osbdm_execute_queue, +}; +struct adapter_driver osbdm_adapter_driver = { + .name = "osbdm", .transports = jtag_only, - .execute_queue = osbdm_execute_queue, .init = osbdm_init, - .quit = osbdm_quit + .quit = osbdm_quit, + + .jtag_ops = &osbdm_interface, }; diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 8e44dcb..b3abd12 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -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, }; diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index 2a94d06..3849a27 100644 --- a/src/jtag/drivers/presto.c +++ b/src/jtag/drivers/presto.c @@ -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, }; diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index a354894..6637952 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -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, }; diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 317e8b8..e053399 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -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, }; diff --git a/src/jtag/drivers/rlink_call.m4 b/src/jtag/drivers/rlink_call.m4 index b27f392..bf07afa 100644 --- a/src/jtag/drivers/rlink_call.m4 +++ b/src/jtag/drivers/rlink_call.m4 @@ -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 - - diff --git a/src/jtag/drivers/rlink_speed_table.c b/src/jtag/drivers/rlink_speed_table.c index b843577..660aac4 100644 --- a/src/jtag/drivers/rlink_speed_table.c +++ b/src/jtag/drivers/rlink_speed_table.c @@ -98,4 +98,3 @@ const struct rlink_speed_table rlink_speed_table[] = {{ } }; const size_t rlink_speed_table_size = ARRAY_SIZE(rlink_speed_table); - diff --git a/src/jtag/drivers/rshim.c b/src/jtag/drivers/rshim.c new file mode 100644 index 0000000..c718af5 --- /dev/null +++ b/src/jtag/drivers/rshim.c @@ -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, +}; diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index ea3dc00..72975d5 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -31,27 +31,31 @@ /* project specific includes */ #include <helper/binarybuffer.h> +#include <helper/bits.h> #include <jtag/interface.h> #include <jtag/hla/hla_layout.h> #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> +#include <jtag/swim.h> #include <target/target.h> +#include <transport/transport.h> #include <target/cortex_m.h> -#include "libusb_common.h" +#include "libusb_helper.h" #ifdef HAVE_LIBUSB1 #define USE_LIBUSB_ASYNCIO #endif +#define STLINK_SERIAL_LEN 24 + #define ENDPOINT_IN 0x80 #define ENDPOINT_OUT 0x00 #define STLINK_WRITE_TIMEOUT 1000 #define STLINK_READ_TIMEOUT 1000 -#define STLINK_NULL_EP 0 #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) #define STLINK_TRACE_EP (3|ENDPOINT_IN) @@ -76,7 +80,7 @@ /* * ST-Link/V1, ST-Link/V2 and ST-Link/V2.1 are full-speed USB devices and * this limits the bulk packet size and the 8bit read/writes to max 64 bytes. - * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes. + * STLINK-V3 is a high speed USB 2.0 and the limit is 512 bytes from FW V3J6. */ #define STLINK_MAX_RW8 (64) #define STLINKV3_MAX_RW8 (512) @@ -92,6 +96,15 @@ enum stlink_jtag_api_version { STLINK_JTAG_API_V3, }; +enum stlink_mode { + STLINK_MODE_UNKNOWN = 0, + STLINK_MODE_DFU, + STLINK_MODE_MASS, + STLINK_MODE_DEBUG_JTAG, + STLINK_MODE_DEBUG_SWD, + STLINK_MODE_DEBUG_SWIM +}; + /** */ struct stlink_usb_version { /** */ @@ -109,7 +122,7 @@ struct stlink_usb_version { /** */ struct stlink_usb_handle_s { /** */ - struct jtag_libusb_device_handle *fd; + struct libusb_device_handle *fd; /** */ struct libusb_transfer *trans; /** */ @@ -129,7 +142,7 @@ struct stlink_usb_handle_s { /** */ uint32_t max_mem_packet; /** */ - enum hl_transports transport; + enum stlink_mode st_mode; /** */ struct stlink_usb_version version; /** */ @@ -265,10 +278,14 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42 #define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43 #define STLINK_DEBUG_APIV2_JTAG_SET_FREQ 0x44 - +#define STLINK_DEBUG_APIV2_READ_DAP_REG 0x45 +#define STLINK_DEBUG_APIV2_WRITE_DAP_REG 0x46 #define STLINK_DEBUG_APIV2_READMEM_16BIT 0x47 #define STLINK_DEBUG_APIV2_WRITEMEM_16BIT 0x48 +#define STLINK_DEBUG_APIV2_INIT_AP 0x4B +#define STLINK_DEBUG_APIV2_CLOSE_AP_DBG 0x4C + #define STLINK_APIV3_SET_COM_FREQ 0x61 #define STLINK_APIV3_GET_COM_FREQ 0x62 @@ -278,21 +295,13 @@ struct stlink_usb_handle_s { #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 #define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 +#define STLINK_DEBUG_PORT_ACCESS 0xffff + #define STLINK_TRACE_SIZE 4096 #define STLINK_TRACE_MAX_HZ 2000000 #define STLINK_V3_MAX_FREQ_NB 10 -/** */ -enum stlink_mode { - STLINK_MODE_UNKNOWN = 0, - STLINK_MODE_DFU, - STLINK_MODE_MASS, - STLINK_MODE_DEBUG_JTAG, - STLINK_MODE_DEBUG_SWD, - STLINK_MODE_DEBUG_SWIM -}; - #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 @@ -300,11 +309,17 @@ enum stlink_mode { * Map the relevant features, quirks and workaround for specific firmware * version of stlink */ -#define STLINK_F_HAS_TRACE (1UL << 0) -#define STLINK_F_HAS_SWD_SET_FREQ (1UL << 1) -#define STLINK_F_HAS_JTAG_SET_FREQ (1UL << 2) -#define STLINK_F_HAS_MEM_16BIT (1UL << 3) -#define STLINK_F_HAS_GETLASTRWSTATUS2 (1UL << 4) +#define STLINK_F_HAS_TRACE BIT(0) +#define STLINK_F_HAS_SWD_SET_FREQ BIT(1) +#define STLINK_F_HAS_JTAG_SET_FREQ BIT(2) +#define STLINK_F_HAS_MEM_16BIT BIT(3) +#define STLINK_F_HAS_GETLASTRWSTATUS2 BIT(4) +#define STLINK_F_HAS_DAP_REG BIT(5) +#define STLINK_F_QUIRK_JTAG_DP_READ BIT(6) +#define STLINK_F_HAS_AP_INIT BIT(7) +#define STLINK_F_HAS_DPBANKSEL BIT(8) +#define STLINK_F_HAS_RW8_512BYTES BIT(9) +#define STLINK_F_FIX_CLOSE_AP BIT(10) /* aliases */ #define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE @@ -332,7 +347,6 @@ static const struct speed_map stlink_khz_to_speed_map_swd[] = { /* JTAG clock speed */ static const struct speed_map stlink_khz_to_speed_map_jtag[] = { - {18000, 2}, {9000, 4}, {4500, 8}, {2250, 16}, @@ -347,6 +361,7 @@ static int stlink_swim_status(void *handle); void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size); static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map); static int stlink_speed(void *handle, int khz, bool query); +static int stlink_usb_open_ap(void *handle, unsigned short apsel); /** */ static unsigned int stlink_usb_block(void *handle) @@ -355,7 +370,7 @@ static unsigned int stlink_usb_block(void *handle) assert(handle != NULL); - if (h->version.stlink == 3) + if (h->version.flags & STLINK_F_HAS_RW8_512BYTES) return STLINKV3_MAX_RW8; else return STLINK_MAX_RW8; @@ -437,7 +452,8 @@ struct jtag_xfer { struct libusb_transfer *transfer; }; -static int jtag_libusb_bulk_transfer_n(jtag_libusb_device_handle *dev_handle, +static int jtag_libusb_bulk_transfer_n( + struct libusb_device_handle *dev_handle, struct jtag_xfer *transfers, size_t n_transfers, int timeout) @@ -518,14 +534,16 @@ static int jtag_libusb_bulk_transfer_n(jtag_libusb_device_handle *dev_handle, static int stlink_usb_xfer_v1_get_status(void *handle) { struct stlink_usb_handle_s *h = handle; + int tr, ret; assert(handle != NULL); /* read status */ memset(h->cmdbuf, 0, STLINK_SG_SIZE); - if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, - 13, STLINK_READ_TIMEOUT) != 13) + ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13, + STLINK_READ_TIMEOUT, &tr); + if (ret || tr != 13) return ERROR_FAIL; uint32_t t1; @@ -589,23 +607,26 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; + int tr, ret; assert(handle != NULL); - if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, cmdsize, - STLINK_WRITE_TIMEOUT) != cmdsize) { + ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf, + cmdsize, STLINK_WRITE_TIMEOUT, &tr); + if (ret || tr != cmdsize) return ERROR_FAIL; - } if (h->direction == h->tx_ep && size) { - if (jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf, - size, STLINK_WRITE_TIMEOUT) != size) { + ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf, + size, STLINK_WRITE_TIMEOUT, &tr); + if (ret || tr != size) { LOG_DEBUG("bulk write failed"); return ERROR_FAIL; } } else if (h->direction == h->rx_ep && size) { - if (jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf, - size, STLINK_READ_TIMEOUT) != size) { + ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf, + size, STLINK_READ_TIMEOUT, &tr); + if (ret || tr != size) { LOG_DEBUG("bulk read failed"); return ERROR_FAIL; } @@ -691,7 +712,7 @@ static int stlink_usb_error_check(void *handle) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { switch (h->databuf[0]) { case STLINK_SWIM_ERR_OK: return ERROR_OK; @@ -800,13 +821,13 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) struct stlink_usb_handle_s *h = handle; while (1) { - if ((h->transport != HL_TRANSPORT_SWIM) || !retries) { + if ((h->st_mode != STLINK_MODE_DEBUG_SWIM) || !retries) { res = stlink_usb_xfer_noerrcheck(handle, buf, size); if (res != ERROR_OK) return res; } - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { res = stlink_swim_status(handle); if (res != ERROR_OK) return res; @@ -814,7 +835,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) res = stlink_usb_error_check(handle); if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) { - useconds_t delay_us = (1<<retries++) * 1000; + unsigned int delay_us = (1<<retries++) * 1000; LOG_DEBUG("stlink_cmd_allow_retry ERROR_WAIT, retry %d, delaying %u microseconds", retries, delay_us); usleep(delay_us); continue; @@ -827,13 +848,15 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h = handle; + int tr, ret; assert(handle != NULL); assert(h->version.flags & STLINK_F_HAS_TRACE); - if (jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, - size, STLINK_READ_TIMEOUT) != size) { + ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size, + STLINK_READ_TIMEOUT, &tr); + if (ret || tr != size) { LOG_ERROR("bulk trace read failed"); return ERROR_FAIL; } @@ -991,13 +1014,32 @@ static int stlink_usb_version(void *handle) flags |= STLINK_F_HAS_SWD_SET_FREQ; /* API to set JTAG frequency from J24 */ - if (h->version.jtag >= 24) + /* API to access DAP registers from J24 */ + if (h->version.jtag >= 24) { flags |= STLINK_F_HAS_JTAG_SET_FREQ; + flags |= STLINK_F_HAS_DAP_REG; + } + + /* Quirk for read DP in JTAG mode (V2 only) from J24, fixed in J32 */ + if (h->version.jtag >= 24 && h->version.jtag < 32) + flags |= STLINK_F_QUIRK_JTAG_DP_READ; /* API to read/write memory at 16 bit from J26 */ if (h->version.jtag >= 26) flags |= STLINK_F_HAS_MEM_16BIT; + /* API required to init AP before any AP access from J28 */ + if (h->version.jtag >= 28) + flags |= STLINK_F_HAS_AP_INIT; + + /* API required to return proper error code on close AP from J29 */ + if (h->version.jtag >= 29) + flags |= STLINK_F_FIX_CLOSE_AP; + + /* Banked regs (DPv1 & DPv2) support from V2J32 */ + if (h->version.jtag >= 32) + flags |= STLINK_F_HAS_DPBANKSEL; + break; case 3: /* all STLINK-V3 use api-v3 */ @@ -1012,9 +1054,26 @@ static int stlink_usb_version(void *handle) /* preferred API to get last R/W status */ flags |= STLINK_F_HAS_GETLASTRWSTATUS2; + /* API to access DAP registers */ + flags |= STLINK_F_HAS_DAP_REG; + /* API to read/write memory at 16 bit */ flags |= STLINK_F_HAS_MEM_16BIT; + /* API required to init AP before any AP access */ + flags |= STLINK_F_HAS_AP_INIT; + + /* API required to return proper error code on close AP */ + flags |= STLINK_F_FIX_CLOSE_AP; + + /* Banked regs (DPv1 & DPv2) support from V3J2 */ + if (h->version.jtag >= 2) + flags |= STLINK_F_HAS_DPBANKSEL; + + /* 8bit read/write max packet size 512 bytes from V3J6 */ + if (h->version.jtag >= 6) + flags |= STLINK_F_HAS_RW8_512BYTES; + break; default: break; @@ -1180,9 +1239,8 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) case STLINK_MODE_DEBUG_SWIM: h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; - /* no answer for this function... */ - rx_size = 0; - break; + /* swim enter does not return any response or status */ + return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); case STLINK_MODE_DFU: case STLINK_MODE_MASS: default: @@ -1200,7 +1258,8 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) assert(handle != NULL); - stlink_usb_init_buffer(handle, STLINK_NULL_EP, 0); + /* command with no reply, use a valid endpoint but zero size */ + stlink_usb_init_buffer(handle, h->rx_ep, 0); switch (type) { case STLINK_MODE_DEBUG_JTAG: @@ -1221,7 +1280,7 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) return ERROR_FAIL; } - res = stlink_usb_xfer_noerrcheck(handle, 0, 0); + res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); if (res != ERROR_OK) return res; @@ -1238,20 +1297,17 @@ static enum stlink_mode stlink_get_mode(enum hl_transports t) return STLINK_MODE_DEBUG_SWD; case HL_TRANSPORT_JTAG: return STLINK_MODE_DEBUG_JTAG; - case HL_TRANSPORT_SWIM: - return STLINK_MODE_DEBUG_SWIM; default: return STLINK_MODE_UNKNOWN; } } /** */ -static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed) +static int stlink_usb_exit_mode(void *handle) { int res; uint8_t mode; enum stlink_mode emode; - struct stlink_usb_handle_s *h = handle; assert(handle != NULL); @@ -1280,12 +1336,25 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init break; } - if (emode != STLINK_MODE_UNKNOWN) { - res = stlink_usb_mode_leave(handle, emode); + if (emode != STLINK_MODE_UNKNOWN) + return stlink_usb_mode_leave(handle, emode); - if (res != ERROR_OK) - return res; - } + return ERROR_OK; +} + +/** */ +static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int initial_interface_speed) +{ + int res; + uint8_t mode; + enum stlink_mode emode; + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + res = stlink_usb_exit_mode(handle); + if (res != ERROR_OK) + return res; res = stlink_usb_current_mode(handle, &mode); @@ -1318,7 +1387,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init LOG_DEBUG("MODE: 0x%02X", mode); /* set selected mode */ - emode = stlink_get_mode(h->transport); + emode = h->st_mode; if (emode == STLINK_MODE_UNKNOWN) { LOG_ERROR("selected mode (transport) not supported"); @@ -1326,12 +1395,12 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init } /* set the speed before entering the mode, as the chip discovery phase should be done at this speed too */ - if (h->transport == HL_TRANSPORT_JTAG) { + if (emode == STLINK_MODE_DEBUG_JTAG) { if (h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ) { stlink_dump_speed_map(stlink_khz_to_speed_map_jtag, ARRAY_SIZE(stlink_khz_to_speed_map_jtag)); stlink_speed(h, initial_interface_speed, false); } - } else if (h->transport == HL_TRANSPORT_SWD) { + } else if (emode == STLINK_MODE_DEBUG_SWD) { if (h->version.flags & STLINK_F_HAS_SWD_SET_FREQ) { stlink_dump_speed_map(stlink_khz_to_speed_map_swd, ARRAY_SIZE(stlink_khz_to_speed_map_swd)); stlink_speed(h, initial_interface_speed, false); @@ -1341,7 +1410,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init if (h->version.jtag_api == STLINK_JTAG_API_V3) { struct speed_map map[STLINK_V3_MAX_FREQ_NB]; - stlink_get_com_freq(h, (h->transport == HL_TRANSPORT_JTAG), map); + stlink_get_com_freq(h, (emode == STLINK_MODE_DEBUG_JTAG), map); stlink_dump_speed_map(map, ARRAY_SIZE(map)); stlink_speed(h, initial_interface_speed, false); } @@ -1582,7 +1651,7 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode) assert(handle != NULL); /* there is no swim read core id cmd */ - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { *idcode = 0; return ERROR_OK; } @@ -1713,22 +1782,9 @@ static enum target_state stlink_usb_state(void *handle) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) { - res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport)); - if (res != ERROR_OK) - return TARGET_UNKNOWN; - - res = stlink_swim_resync(handle); - if (res != ERROR_OK) - return TARGET_UNKNOWN; - - return ERROR_OK; - } - if (h->reconnect_pending) { LOG_INFO("Previous state query failed, trying to reconnect"); - res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport)); - + res = stlink_usb_mode_enter(handle, h->st_mode); if (res != ERROR_OK) return TARGET_UNKNOWN; @@ -1768,7 +1824,7 @@ static int stlink_usb_assert_srst(void *handle, int srst) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) return stlink_swim_assert_reset(handle, srst); if (h->version.stlink == 1) @@ -1845,9 +1901,6 @@ static int stlink_usb_reset(void *handle) assert(handle != NULL); - if (h->transport == HL_TRANSPORT_SWIM) - return stlink_swim_generate_rst(handle); - stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; @@ -2269,17 +2322,12 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, while (count) { - bytes_remaining = (size != 1) ? \ + bytes_remaining = (size != 1) ? stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h); if (count < bytes_remaining) bytes_remaining = count; - if (h->transport == HL_TRANSPORT_SWIM) { - retval = stlink_swim_readbytes(handle, addr, bytes_remaining, buffer); - if (retval != ERROR_OK) - return retval; - } else /* * all stlink support 8/32bit memory read/writes and only from * stlink V2J26 there is support for 16 bit memory read/write. @@ -2354,17 +2402,12 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, while (count) { - bytes_remaining = (size != 1) ? \ + bytes_remaining = (size != 1) ? stlink_max_block_size(h->max_mem_packet, addr) : stlink_usb_block(h); if (count < bytes_remaining) bytes_remaining = count; - if (h->transport == HL_TRANSPORT_SWIM) { - retval = stlink_swim_writebytes(handle, addr, bytes_remaining, buffer); - if (retval != ERROR_OK) - return retval; - } else /* * all stlink support 8/32bit memory read/writes and only from * stlink V2J26 there is support for 16 bit memory read/write. @@ -2430,17 +2473,20 @@ static int stlink_usb_override_target(const char *targetname) static int stlink_speed_swim(void *handle, int khz, bool query) { + int retval; + /* - we dont care what the khz rate is we only have low and high speed... before changing speed the SWIM_CSR HS bit must be updated */ - if (khz == 0) - stlink_swim_speed(handle, 0); - else - stlink_swim_speed(handle, 1); - return khz; + if (!query) { + retval = stlink_swim_speed(handle, (khz < SWIM_FREQ_HIGH) ? 0 : 1); + if (retval != ERROR_OK) + LOG_ERROR("Unable to set adapter speed"); + } + + return (khz < SWIM_FREQ_HIGH) ? SWIM_FREQ_LOW : SWIM_FREQ_HIGH; } static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_size, int khz, bool query) @@ -2478,7 +2524,7 @@ static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_ match = false; if (!match && query) { - LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", \ + LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", khz, map[speed_index].speed); } @@ -2624,17 +2670,16 @@ static int stlink_speed(void *handle, int khz, bool query) if (!handle) return khz; - switch (h->transport) { - case HL_TRANSPORT_SWIM: + switch (h->st_mode) { + case STLINK_MODE_DEBUG_SWIM: return stlink_speed_swim(handle, khz, query); - break; - case HL_TRANSPORT_SWD: + case STLINK_MODE_DEBUG_SWD: if (h->version.jtag_api == STLINK_JTAG_API_V3) return stlink_speed_v3(handle, false, khz, query); else return stlink_speed_swd(handle, khz, query); break; - case HL_TRANSPORT_JTAG: + case STLINK_MODE_DEBUG_JTAG: if (h->version.jtag_api == STLINK_JTAG_API_V3) return stlink_speed_v3(handle, true, khz, query); else @@ -2650,53 +2695,101 @@ static int stlink_speed(void *handle, int khz, bool query) /** */ static int stlink_usb_close(void *handle) { - int res; - uint8_t mode; - enum stlink_mode emode; struct stlink_usb_handle_s *h = handle; - if (h && h->fd) - res = stlink_usb_current_mode(handle, &mode); - else - res = ERROR_FAIL; - /* do not exit if return code != ERROR_OK, - it prevents us from closing jtag_libusb */ - - if (res == ERROR_OK) { - /* try to exit current mode */ - switch (mode) { - case STLINK_DEV_DFU_MODE: - emode = STLINK_MODE_DFU; - break; - case STLINK_DEV_DEBUG_MODE: - emode = STLINK_MODE_DEBUG_SWD; - break; - case STLINK_DEV_SWIM_MODE: - emode = STLINK_MODE_DEBUG_SWIM; - break; - case STLINK_DEV_BOOTLOADER_MODE: - case STLINK_DEV_MASS_MODE: - default: - emode = STLINK_MODE_UNKNOWN; - break; - } - - if (emode != STLINK_MODE_UNKNOWN) - stlink_usb_mode_leave(handle, emode); - /* do not check return code, it prevent - us from closing jtag_libusb */ - } - - if (h && h->fd) + if (h && h->fd) { + stlink_usb_exit_mode(h); + /* do not check return code, it prevent + us from closing jtag_libusb */ jtag_libusb_close(h->fd); + } free(h); return ERROR_OK; } +/* Compute ST-Link serial number from the device descriptor + * this function will help to work-around a bug in old ST-Link/V2 DFU + * the buggy DFU returns an incorrect serial in the USB descriptor + * example for the following serial "57FF72067265575742132067" + * - the correct descriptor serial is: + * 0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00, 0x37, 0x00, 0x32, 0x00 ... + * this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the serial in unicode format + * the serial part is: 0x0035, 0x0037, 0x0046, 0x0046, 0x0037, 0x0032 ... >> 57FF72 ... + * this format could be read correctly by 'libusb_get_string_descriptor_ascii' + * so this case is managed by libusb_helper::string_descriptor_equal + * - the buggy DFU is not doing any unicode conversion and returns a raw serial data in the descriptor + * 0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ... + * >> 57 FF 72 ... + * based on the length (0x1a = 26) we could easily decide if we have to fixup the serial + * and then we have just to convert the raw data into printable characters using sprintf + */ +char *stlink_usb_get_alternate_serial(libusb_device_handle *device, + struct libusb_device_descriptor *dev_desc) +{ + int usb_retval; + unsigned char desc_serial[(STLINK_SERIAL_LEN + 1) * 2]; + + if (dev_desc->iSerialNumber == 0) + return NULL; + + /* get the LANGID from String Descriptor Zero */ + usb_retval = libusb_get_string_descriptor(device, 0, 0, desc_serial, + sizeof(desc_serial)); + + if (usb_retval < LIBUSB_SUCCESS) { + LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)", + libusb_error_name(usb_retval), usb_retval); + return NULL; + } else if (usb_retval < 4) { + /* the size should be least 4 bytes to contain a minimum of 1 supported LANGID */ + LOG_ERROR("could not get the LANGID"); + return NULL; + } + + uint32_t langid = desc_serial[2] | (desc_serial[3] << 8); + + /* get the serial */ + usb_retval = libusb_get_string_descriptor(device, dev_desc->iSerialNumber, + langid, desc_serial, sizeof(desc_serial)); + + unsigned char len = desc_serial[0]; + + if (usb_retval < LIBUSB_SUCCESS) { + LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)", + libusb_error_name(usb_retval), usb_retval); + return NULL; + } else if (desc_serial[1] != LIBUSB_DT_STRING || len > usb_retval) { + LOG_ERROR("invalid string in ST-LINK USB serial descriptor"); + return NULL; + } + + if (len == ((STLINK_SERIAL_LEN + 1) * 2)) { + /* good ST-Link adapter, this case is managed by + * libusb::libusb_get_string_descriptor_ascii */ + return NULL; + } else if (len != ((STLINK_SERIAL_LEN / 2 + 1) * 2)) { + LOG_ERROR("unexpected serial length (%d) in descriptor", len); + return NULL; + } + + /* else (len == 26) => buggy ST-Link */ + + char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char)); + if (alternate_serial == NULL) + return NULL; + + for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2) + sprintf(alternate_serial + i, "%02X", desc_serial[i + 2]); + + alternate_serial[STLINK_SERIAL_LEN] = '\0'; + + return alternate_serial; +} + /** */ -static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) +static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) { int err, retry_count = 1; struct stlink_usb_handle_s *h; @@ -2710,11 +2803,11 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) return ERROR_FAIL; } - h->transport = param->transport; + h->st_mode = mode; for (unsigned i = 0; param->vid[i]; i++) { LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", - param->transport, param->vid[i], param->pid[i], + h->st_mode, param->vid[i], param->pid[i], param->serial ? param->serial : ""); } @@ -2728,14 +2821,15 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) in order to become operational. */ do { - if (jtag_libusb_open(param->vid, param->pid, param->serial, &h->fd) != ERROR_OK) { + if (jtag_libusb_open(param->vid, param->pid, param->serial, + &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); goto error_open; } jtag_libusb_set_configuration(h->fd, 0); - if (jtag_libusb_claim_interface(h->fd, 0) != ERROR_OK) { + if (libusb_claim_interface(h->fd, 0) != ERROR_OK) { LOG_DEBUG("claim interface failed"); goto error_open; } @@ -2744,7 +2838,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) h->rx_ep = STLINK_RX_EP; uint16_t pid; - if (jtag_libusb_get_pid(jtag_libusb_get_device(h->fd), &pid) != ERROR_OK) { + if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) { LOG_DEBUG("libusb_get_pid failed"); goto error_open; } @@ -2788,13 +2882,13 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) LOG_ERROR("read version failed"); goto error_open; } else { - err = jtag_libusb_release_interface(h->fd, 0); + err = libusb_release_interface(h->fd, 0); if (err != ERROR_OK) { LOG_ERROR("release interface failed"); goto error_open; } - err = jtag_libusb_reset_device(h->fd); + err = libusb_reset_device(h->fd); if (err != ERROR_OK) { LOG_ERROR("reset device failed"); goto error_open; @@ -2813,16 +2907,16 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) /* check if mode is supported */ err = ERROR_OK; - switch (h->transport) { - case HL_TRANSPORT_SWD: + switch (h->st_mode) { + case STLINK_MODE_DEBUG_SWD: if (h->version.jtag_api == STLINK_JTAG_API_V1) err = ERROR_FAIL; /* fall-through */ - case HL_TRANSPORT_JTAG: + case STLINK_MODE_DEBUG_JTAG: if (h->version.jtag == 0) err = ERROR_FAIL; break; - case HL_TRANSPORT_SWIM: + case STLINK_MODE_DEBUG_SWIM: if (h->version.swim == 0) err = ERROR_FAIL; break; @@ -2844,7 +2938,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) goto error_open; } - if (h->transport == HL_TRANSPORT_SWIM) { + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { err = stlink_swim_enter(h); if (err != ERROR_OK) { LOG_ERROR("stlink_swim_enter_failed (unable to connect to the target)"); @@ -2860,6 +2954,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) h->max_mem_packet = (1 << 10); uint8_t buffer[4]; + stlink_usb_open_ap(h, 0); err = stlink_usb_read_mem32(h, CPUID, 4, buffer); if (err == ERROR_OK) { uint32_t cpuid = le_to_h_u32(buffer); @@ -2882,10 +2977,18 @@ error_open: return ERROR_FAIL; } -int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq) +static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd) +{ + return stlink_usb_open(param, stlink_get_mode(param->transport), fd); +} + +int stlink_config_trace(void *handle, bool enabled, + enum tpiu_pin_protocol pin_protocol, uint32_t port_size, + unsigned int *trace_freq, unsigned int traceclkin_freq, + uint16_t *prescaler) { struct stlink_usb_handle_s *h = handle; + uint16_t presc; if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) || pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) { @@ -2908,15 +3011,116 @@ int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_p if (!*trace_freq) *trace_freq = STLINK_TRACE_MAX_HZ; + + presc = traceclkin_freq / *trace_freq; + + if (traceclkin_freq % *trace_freq > 0) + presc++; + + if (presc > TPIU_ACPR_MAX_SWOSCALER) { + LOG_ERROR("SWO frequency is not suitable. Please choose a different " + "frequency."); + return ERROR_FAIL; + } + + *prescaler = presc; h->trace.source_hz = *trace_freq; return stlink_usb_trace_enable(h); } /** */ +static int stlink_usb_init_access_port(void *handle, unsigned char ap_num) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_COMMAND_NOTFOUND; + + LOG_DEBUG_IO("init ap_num = %d", ap_num); + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_INIT_AP; + h->cmdbuf[h->cmdidx++] = ap_num; + + return stlink_usb_xfer_errcheck(handle, h->databuf, 2); +} + +/** */ +static int stlink_usb_close_access_port(void *handle, unsigned char ap_num) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_COMMAND_NOTFOUND; + + LOG_DEBUG_IO("close ap_num = %d", ap_num); + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_CLOSE_AP_DBG; + h->cmdbuf[h->cmdidx++] = ap_num; + + /* ignore incorrectly returned error on bogus FW */ + if (h->version.flags & STLINK_F_FIX_CLOSE_AP) + return stlink_usb_xfer_errcheck(handle, h->databuf, 2); + else + return stlink_usb_xfer_noerrcheck(handle, h->databuf, 2); + +} + +/** */ +static int stlink_read_dap_register(void *handle, unsigned short dap_port, + unsigned short addr, uint32_t *val) +{ + struct stlink_usb_handle_s *h = handle; + int retval; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) + return ERROR_COMMAND_NOTFOUND; + + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READ_DAP_REG; + h_u16_to_le(&h->cmdbuf[2], dap_port); + h_u16_to_le(&h->cmdbuf[4], addr); + + retval = stlink_usb_xfer_errcheck(handle, h->databuf, 8); + *val = le_to_h_u32(h->databuf + 4); + LOG_DEBUG_IO("dap_port_read = %d, addr = 0x%x, value = 0x%x", dap_port, addr, *val); + return retval; +} + +/** */ +static int stlink_write_dap_register(void *handle, unsigned short dap_port, + unsigned short addr, uint32_t val) +{ + struct stlink_usb_handle_s *h = handle; + + assert(handle != NULL); + + if (!(h->version.flags & STLINK_F_HAS_DAP_REG)) + return ERROR_COMMAND_NOTFOUND; + + LOG_DEBUG_IO("dap_write port = %d, addr = 0x%x, value = 0x%x", dap_port, addr, val); + stlink_usb_init_buffer(handle, h->rx_ep, 16); + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITE_DAP_REG; + h_u16_to_le(&h->cmdbuf[2], dap_port); + h_u16_to_le(&h->cmdbuf[4], addr); + h_u32_to_le(&h->cmdbuf[6], val); + return stlink_usb_xfer_errcheck(handle, h->databuf, 2); +} + +/** */ struct hl_layout_api_s stlink_usb_layout_api = { /** */ - .open = stlink_usb_open, + .open = stlink_usb_hl_open, /** */ .close = stlink_usb_close, /** */ @@ -2954,3 +3158,648 @@ struct hl_layout_api_s stlink_usb_layout_api = { /** */ .poll_trace = stlink_usb_trace_read, }; + +/***************************************************************************** + * DAP direct interface + */ + +static struct stlink_usb_handle_s *stlink_dap_handle; +static struct hl_interface_param_s stlink_dap_param; +static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1); +static int stlink_dap_error = ERROR_OK; + +static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data); + +/** */ +static int stlink_dap_record_error(int error) +{ + if (stlink_dap_error == ERROR_OK) + stlink_dap_error = error; + return ERROR_OK; +} + +/** */ +static int stlink_dap_get_and_clear_error(void) +{ + int retval = stlink_dap_error; + stlink_dap_error = ERROR_OK; + return retval; +} + +static int stlink_usb_open_ap(void *handle, unsigned short apsel) +{ + struct stlink_usb_handle_s *h = handle; + int retval; + + /* nothing to do on old versions */ + if (!(h->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_OK; + + if (apsel > DP_APSEL_MAX) + return ERROR_FAIL; + + if (test_bit(apsel, opened_ap)) + return ERROR_OK; + + retval = stlink_usb_init_access_port(h, apsel); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("AP %d enabled", apsel); + set_bit(apsel, opened_ap); + return ERROR_OK; +} + +static int stlink_dap_open_ap(unsigned short apsel) +{ + return stlink_usb_open_ap(stlink_dap_handle, apsel); +} + +/** */ +static int stlink_dap_closeall_ap(void) +{ + int retval, apsel; + + /* nothing to do on old versions */ + if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT)) + return ERROR_OK; + + for (apsel = 0; apsel <= DP_APSEL_MAX; apsel++) { + if (!test_bit(apsel, opened_ap)) + continue; + retval = stlink_usb_close_access_port(stlink_dap_handle, apsel); + if (retval != ERROR_OK) + return retval; + clear_bit(apsel, opened_ap); + } + return ERROR_OK; +} + +/** */ +static int stlink_dap_reinit_interface(void) +{ + int retval; + + /* + * On JTAG only, it should be enough to call stlink_usb_reset(). But on + * some firmware version it does not work as expected, and there is no + * equivalent for SWD. + * At least for now, to reset the interface quit from JTAG/SWD mode then + * select the mode again. + */ + + if (!stlink_dap_handle->reconnect_pending) { + stlink_dap_handle->reconnect_pending = true; + stlink_usb_mode_leave(stlink_dap_handle, stlink_dap_handle->st_mode); + } + + retval = stlink_usb_mode_enter(stlink_dap_handle, stlink_dap_handle->st_mode); + if (retval != ERROR_OK) + return retval; + + stlink_dap_handle->reconnect_pending = false; + /* on new FW, calling mode-leave closes all the opened AP; reopen them! */ + if (stlink_dap_handle->version.flags & STLINK_F_HAS_AP_INIT) + for (int apsel = 0; apsel <= DP_APSEL_MAX; apsel++) + if (test_bit(apsel, opened_ap)) { + clear_bit(apsel, opened_ap); + stlink_dap_open_ap(apsel); + } + return ERROR_OK; +} + +/** */ +static int stlink_dap_op_connect(struct adiv5_dap *dap) +{ + uint32_t idcode; + int retval; + + LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : ""); + + /* Check if we should reset srst already when connecting, but not if reconnecting. */ + if (!dap->do_reconnect) { + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + adapter_assert_reset(); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } + } + + dap->do_reconnect = false; + dap_invalidate_cache(dap); + + retval = dap_dp_init(dap); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + + retval = stlink_usb_idcode(stlink_dap_handle, &idcode); + if (retval == ERROR_OK) + LOG_INFO("%s %#8.8" PRIx32, + (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) ? "JTAG IDCODE" : "SWD DPIDR", + idcode); + else + dap->do_reconnect = true; + + return retval; +} + +/** */ +static int stlink_dap_check_reconnect(struct adiv5_dap *dap) +{ + int retval; + + if (!dap->do_reconnect) + return ERROR_OK; + + retval = stlink_dap_reinit_interface(); + if (retval != ERROR_OK) + return retval; + + return stlink_dap_op_connect(dap); +} + +/** */ +static int stlink_dap_op_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + /* Ignore the request */ + return ERROR_OK; +} + +/** */ +static int stlink_dap_op_queue_dp_read(struct adiv5_dap *dap, unsigned reg, + uint32_t *data) +{ + uint32_t dummy; + int retval; + + if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL)) + if (reg & 0x000000F0) { + LOG_ERROR("Banked DP registers not supported in current STLink FW"); + return ERROR_COMMAND_NOTFOUND; + } + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + data = data ? : &dummy; + if (stlink_dap_handle->version.flags & STLINK_F_QUIRK_JTAG_DP_READ + && stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) { + /* Quirk required in JTAG. Read RDBUFF to get the data */ + retval = stlink_read_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, reg, &dummy); + if (retval == ERROR_OK) + retval = stlink_read_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, DP_RDBUFF, data); + } else { + retval = stlink_read_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, reg, data); + } + + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_dp_write(struct adiv5_dap *dap, unsigned reg, + uint32_t data) +{ + int retval; + + if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DPBANKSEL)) + if (reg & 0x000000F0) { + LOG_ERROR("Banked DP registers not supported in current STLink FW"); + return ERROR_COMMAND_NOTFOUND; + } + + if (reg == DP_SELECT && (data & DP_SELECT_DPBANK) != 0) { + /* ignored if STLINK_F_HAS_DPBANKSEL, not properly managed otherwise */ + LOG_DEBUG("Ignoring DPBANKSEL while write SELECT"); + data &= ~DP_SELECT_DPBANK; + } + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + /* ST-Link does not like that we set CORUNDETECT */ + if (reg == DP_CTRL_STAT) + data &= ~CORUNDETECT; + + retval = stlink_write_dap_register(stlink_dap_handle, + STLINK_DEBUG_PORT_ACCESS, reg, data); + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_ap_read(struct adiv5_ap *ap, unsigned reg, + uint32_t *data) +{ + struct adiv5_dap *dap = ap->dap; + uint32_t dummy; + int retval; + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + if (reg != AP_REG_IDR) { + retval = stlink_dap_open_ap(ap->ap_num); + if (retval != ERROR_OK) + return retval; + } + data = data ? : &dummy; + retval = stlink_read_dap_register(stlink_dap_handle, ap->ap_num, reg, + data); + dap->stlink_flush_ap_write = false; + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_ap_write(struct adiv5_ap *ap, unsigned reg, + uint32_t data) +{ + struct adiv5_dap *dap = ap->dap; + int retval; + + retval = stlink_dap_check_reconnect(dap); + if (retval != ERROR_OK) + return retval; + + retval = stlink_dap_open_ap(ap->ap_num); + if (retval != ERROR_OK) + return retval; + + retval = stlink_write_dap_register(stlink_dap_handle, ap->ap_num, reg, + data); + dap->stlink_flush_ap_write = true; + return stlink_dap_record_error(retval); +} + +/** */ +static int stlink_dap_op_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) +{ + LOG_WARNING("stlink_dap_op_queue_ap_abort()"); + return ERROR_OK; +} + +/** */ +static int stlink_dap_op_run(struct adiv5_dap *dap) +{ + uint32_t ctrlstat, pwrmask; + int retval, saved_retval; + + /* Here no LOG_DEBUG. This is called continuously! */ + + /* + * ST-Link returns immediately after a DAP write, without waiting for it + * to complete. + * Run a dummy read to DP_RDBUFF, as suggested in + * http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka16363.html + */ + if (dap->stlink_flush_ap_write) { + dap->stlink_flush_ap_write = false; + retval = stlink_dap_op_queue_dp_read(dap, DP_RDBUFF, NULL); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + } + + saved_retval = stlink_dap_get_and_clear_error(); + + retval = stlink_dap_op_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + retval = stlink_dap_get_and_clear_error(); + if (retval != ERROR_OK) { + LOG_ERROR("Fail reading CTRL/STAT register. Force reconnect"); + dap->do_reconnect = true; + return retval; + } + + if (ctrlstat & SSTICKYERR) { + if (stlink_dap_handle->st_mode == STLINK_MODE_DEBUG_JTAG) + retval = stlink_dap_op_queue_dp_write(dap, DP_CTRL_STAT, + ctrlstat & (dap->dp_ctrl_stat | SSTICKYERR)); + else + retval = stlink_dap_op_queue_dp_write(dap, DP_ABORT, STKERRCLR); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + retval = stlink_dap_get_and_clear_error(); + if (retval != ERROR_OK) { + dap->do_reconnect = true; + return retval; + } + } + + /* check for power lost */ + pwrmask = dap->dp_ctrl_stat & (CDBGPWRUPREQ | CSYSPWRUPREQ); + if ((ctrlstat & pwrmask) != pwrmask) + dap->do_reconnect = true; + + return saved_retval; +} + +/** */ +static void stlink_dap_op_quit(struct adiv5_dap *dap) +{ + int retval; + + retval = stlink_dap_closeall_ap(); + if (retval != ERROR_OK) + LOG_ERROR("Error closing APs"); +} + +static int stlink_swim_op_srst(void) +{ + return stlink_swim_generate_rst(stlink_dap_handle); +} + +static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size, + uint32_t count, uint8_t *buffer) +{ + int retval; + uint32_t bytes_remaining; + + LOG_DEBUG_IO("read at 0x%08x len %d*0x%08x", addr, size, count); + count *= size; + + while (count) { + bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count; + retval = stlink_swim_readbytes(stlink_dap_handle, addr, bytes_remaining, buffer); + if (retval != ERROR_OK) + return retval; + + buffer += bytes_remaining; + addr += bytes_remaining; + count -= bytes_remaining; + } + + return ERROR_OK; +} + +static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size, + uint32_t count, const uint8_t *buffer) +{ + int retval; + uint32_t bytes_remaining; + + LOG_DEBUG_IO("write at 0x%08x len %d*0x%08x", addr, size, count); + count *= size; + + while (count) { + bytes_remaining = (count > STLINK_DATA_SIZE) ? STLINK_DATA_SIZE : count; + retval = stlink_swim_writebytes(stlink_dap_handle, addr, bytes_remaining, buffer); + if (retval != ERROR_OK) + return retval; + + buffer += bytes_remaining; + addr += bytes_remaining; + count -= bytes_remaining; + } + + return ERROR_OK; +} + +static int stlink_swim_op_reconnect(void) +{ + int retval; + + retval = stlink_usb_mode_enter(stlink_dap_handle, STLINK_MODE_DEBUG_SWIM); + if (retval != ERROR_OK) + return retval; + + return stlink_swim_resync(stlink_dap_handle); +} + +static int stlink_dap_config_trace(bool enabled, + enum tpiu_pin_protocol pin_protocol, uint32_t port_size, + unsigned int *trace_freq, unsigned int traceclkin_freq, + uint16_t *prescaler) +{ + return stlink_config_trace(stlink_dap_handle, enabled, pin_protocol, + port_size, trace_freq, traceclkin_freq, + prescaler); +} + +static int stlink_dap_trace_read(uint8_t *buf, size_t *size) +{ + return stlink_usb_trace_read(stlink_dap_handle, buf, size); +} + +/** */ +COMMAND_HANDLER(stlink_dap_serial_command) +{ + LOG_DEBUG("stlink_dap_serial_command"); + + if (CMD_ARGC != 1) { + LOG_ERROR("Expected exactly one argument for \"st-link serial <serial-number>\"."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (stlink_dap_param.serial) { + LOG_WARNING("Command \"st-link serial\" already used. Replacing previous value"); + free((void *)stlink_dap_param.serial); + } + + stlink_dap_param.serial = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +/** */ +COMMAND_HANDLER(stlink_dap_vid_pid) +{ + unsigned int i, max_usb_ids = HLA_MAX_USB_IDS; + + if (CMD_ARGC > max_usb_ids * 2) { + LOG_WARNING("ignoring extra IDs in vid_pid " + "(maximum is %d pairs)", max_usb_ids); + CMD_ARGC = max_usb_ids * 2; + } + if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { + LOG_WARNING("incomplete vid_pid configuration directive"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + for (i = 0; i < CMD_ARGC; i += 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], stlink_dap_param.vid[i / 2]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], stlink_dap_param.pid[i / 2]); + } + + /* null termination */ + stlink_dap_param.vid[i / 2] = stlink_dap_param.pid[i / 2] = 0; + + return ERROR_OK; +} + +/** */ +static const struct command_registration stlink_dap_subcommand_handlers[] = { + { + .name = "serial", + .handler = stlink_dap_serial_command, + .mode = COMMAND_CONFIG, + .help = "set the serial number of the adapter", + .usage = "<serial_number>", + }, + { + .name = "vid_pid", + .handler = stlink_dap_vid_pid, + .mode = COMMAND_CONFIG, + .help = "USB VID and PID of the adapter", + .usage = "(vid pid)+", + }, + COMMAND_REGISTRATION_DONE +}; + +/** */ +static const struct command_registration stlink_dap_command_handlers[] = { + { + .name = "st-link", + .mode = COMMAND_ANY, + .help = "perform st-link management", + .chain = stlink_dap_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +/** */ +static int stlink_dap_init(void) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + enum stlink_mode mode; + int retval; + + LOG_DEBUG("stlink_dap_init()"); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + stlink_dap_param.connect_under_reset = true; + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } + + if (transport_is_dapdirect_swd()) + mode = STLINK_MODE_DEBUG_SWD; + else if (transport_is_dapdirect_jtag()) + mode = STLINK_MODE_DEBUG_JTAG; + else if (transport_is_swim()) + mode = STLINK_MODE_DEBUG_SWIM; + else { + LOG_ERROR("Unsupported transport"); + return ERROR_FAIL; + } + + retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle); + if (retval != ERROR_OK) + return retval; + + if ((mode != STLINK_MODE_DEBUG_SWIM) && + !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) { + LOG_ERROR("ST-Link version does not support DAP direct transport"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +/** */ +static int stlink_dap_quit(void) +{ + LOG_DEBUG("stlink_dap_quit()"); + + free((void *)stlink_dap_param.serial); + stlink_dap_param.serial = NULL; + + return stlink_usb_close(stlink_dap_handle); +} + +/** */ +static int stlink_dap_reset(int req_trst, int req_srst) +{ + LOG_DEBUG("stlink_dap_reset(%d)", req_srst); + return stlink_usb_assert_srst(stlink_dap_handle, + req_srst ? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW + : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); +} + +/** */ +static int stlink_dap_speed(int speed) +{ + if (speed == 0) { + LOG_ERROR("RTCK not supported. Set nonzero adapter_khz."); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + + stlink_dap_param.initial_interface_speed = speed; + stlink_speed(stlink_dap_handle, speed, false); + return ERROR_OK; +} + +/** */ +static int stlink_dap_khz(int khz, int *jtag_speed) +{ + if (khz == 0) { + LOG_ERROR("RCLK not supported"); + return ERROR_FAIL; + } + + *jtag_speed = stlink_speed(stlink_dap_handle, khz, true); + return ERROR_OK; +} + +/** */ +static int stlink_dap_speed_div(int speed, int *khz) +{ + *khz = speed; + return ERROR_OK; +} + +static const struct dap_ops stlink_dap_ops = { + .connect = stlink_dap_op_connect, + .send_sequence = stlink_dap_op_send_sequence, + .queue_dp_read = stlink_dap_op_queue_dp_read, + .queue_dp_write = stlink_dap_op_queue_dp_write, + .queue_ap_read = stlink_dap_op_queue_ap_read, + .queue_ap_write = stlink_dap_op_queue_ap_write, + .queue_ap_abort = stlink_dap_op_queue_ap_abort, + .run = stlink_dap_op_run, + .sync = NULL, /* optional */ + .quit = stlink_dap_op_quit, /* optional */ +}; + +static const struct swim_driver stlink_swim_ops = { + .srst = stlink_swim_op_srst, + .read_mem = stlink_swim_op_read_mem, + .write_mem = stlink_swim_op_write_mem, + .reconnect = stlink_swim_op_reconnect, +}; + +static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL }; + +struct adapter_driver stlink_dap_adapter_driver = { + .name = "st-link", + .transports = stlink_dap_transport, + .commands = stlink_dap_command_handlers, + + .init = stlink_dap_init, + .quit = stlink_dap_quit, + .reset = stlink_dap_reset, + .speed = stlink_dap_speed, + .khz = stlink_dap_khz, + .speed_div = stlink_dap_speed_div, + .config_trace = stlink_dap_config_trace, + .poll_trace = stlink_dap_trace_read, + + .dap_jtag_ops = &stlink_dap_ops, + .dap_swd_ops = &stlink_dap_ops, + .swim_ops = &stlink_swim_ops, +}; diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index eb4941e..a4d7ad9 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -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; } - diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index bbe08aa..242c04f 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -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", +static struct jtag_interface ulink_interface = { + .execute_queue = ulink_execute_queue, +}; - .commands = ulink_command_handlers, +struct adapter_driver ulink_adapter_driver = { + .name = "ulink", .transports = jtag_only, + .commands = ulink_command_handlers, - .execute_queue = ulink_execute_queue, - .khz = ulink_khz, + .init = ulink_init, + .quit = ulink_quit, .speed = ulink_speed, + .khz = ulink_khz, .speed_div = ulink_speed_div, - .init = ulink_init, - .quit = ulink_quit + .jtag_ops = &ulink_interface, }; diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index d991733..e2556ce 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -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, diff --git a/src/jtag/drivers/usb_blaster/ublast_access.h b/src/jtag/drivers/usb_blaster/ublast_access.h index 252f003..ad20d65 100644 --- a/src/jtag/drivers/usb_blaster/ublast_access.h +++ b/src/jtag/drivers/usb_blaster/ublast_access.h @@ -28,8 +28,6 @@ #ifndef OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H #define OPENOCD_JTAG_DRIVERS_USB_BLASTER_UBLAST_ACCESS_H -#include <libusb_common.h> - /* Low level flags */ #define COPY_TDO_BUFFER (1 << 0) @@ -39,7 +37,7 @@ struct ublast_lowlevel { uint16_t ublast_vid_uninit; uint16_t ublast_pid_uninit; char *ublast_device_desc; - struct jtag_libusb_device_handle *libusb_dev; + struct libusb_device_handle *libusb_dev; char *firmware_path; int (*write)(struct ublast_lowlevel *low, uint8_t *buf, int size, diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 165ebdc..d30483b 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -816,6 +816,11 @@ static int ublast_execute_queue(void) case JTAG_SCAN: ret = ublast_scan(cmd->cmd.scan); break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", + cmd->type); + ret = ERROR_FAIL; + break; } } @@ -1037,8 +1042,8 @@ static const struct command_registration ublast_command_handlers[] = { .name = "usb_blaster_vid_pid", .handler = ublast_handle_vid_pid_command, .mode = COMMAND_CONFIG, - .help = "the vendor ID and product ID of the USB-Blaster and " \ - "vendor ID and product ID of the uninitialized device " \ + .help = "the vendor ID and product ID of the USB-Blaster and " + "vendor ID and product ID of the uninitialized device " "for USB-Blaster II", .usage = "vid pid vid_uninit pid_uninit", }, @@ -1066,13 +1071,18 @@ static const struct command_registration ublast_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface usb_blaster_interface = { +static struct jtag_interface usb_blaster_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = ublast_execute_queue, +}; + +struct adapter_driver usb_blaster_adapter_driver = { .name = "usb_blaster", .transports = jtag_only, .commands = ublast_command_handlers, - .supported = DEBUG_CAP_TMS_SEQ, - .execute_queue = ublast_execute_queue, .init = ublast_init, .quit = ublast_quit, + + .jtag_ops = &usb_blaster_interface, }; diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 35a9520..7b27eaf 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -381,7 +381,7 @@ static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) { int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100); - if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \ + if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9)) return 1; if (res == msglen) { @@ -596,11 +596,16 @@ static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag) } } -struct jtag_interface usbprog_interface = { +static struct jtag_interface usbprog_interface = { + .execute_queue = usbprog_execute_queue, +}; + +struct adapter_driver usbprog_adapter_driver = { .name = "usbprog", .transports = jtag_only, - .execute_queue = usbprog_execute_queue, .init = usbprog_init, - .quit = usbprog_quit + .quit = usbprog_quit, + + .jtag_ops = &usbprog_interface, }; diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c index 53a7e98..678b097 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c @@ -48,7 +48,7 @@ uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN]; #define usbtoxxx_get_type_name(type) \ types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \ - % (sizeof(types_name) / sizeof(types_name[0]))] + % ARRAY_SIZE(types_name)] static uint8_t type_pre; static uint16_t usbtoxxx_buffer_index; diff --git a/src/jtag/drivers/versaloon/versaloon_internal.h b/src/jtag/drivers/versaloon/versaloon_internal.h index 497b6b9..8372970 100644 --- a/src/jtag/drivers/versaloon/versaloon_internal.h +++ b/src/jtag/drivers/versaloon/versaloon_internal.h @@ -91,7 +91,7 @@ struct versaloon_pending_t { void *extra_data; versaloon_callback_t callback; }; -extern struct versaloon_pending_t \ +extern struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; extern uint16_t versaloon_pending_idx; void versaloon_set_pending_id(uint32_t id); diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index 4907ef0..5fb9bcd 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -59,7 +59,7 @@ static void vsllink_runtest(int num_cycles); static void vsllink_stableclocks(int num_cycles, int tms); static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); -static void vsllink_reset(int trst, int srst); +static int vsllink_reset(int trst, int srst); /* VSLLink tap buffer functions */ static void vsllink_tap_append_step(int tms, int tdi); @@ -164,20 +164,6 @@ static int vsllink_execute_queue(void) cmd->cmd.scan); break; - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - - vsllink_tap_execute(); - - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - - vsllink_reset(cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - break; - case JTAG_SLEEP: LOG_DEBUG_IO("sleep %i", cmd->cmd.sleep->us); vsllink_tap_execute(); @@ -306,7 +292,7 @@ static int vsllink_interface_init(void) libusb_init(&vsllink_handle->libusb_ctx); if (ERROR_OK != vsllink_usb_open(vsllink_handle)) { - LOG_ERROR("Can't find USB JTAG Interface!" \ + LOG_ERROR("Can't find USB JTAG Interface!" "Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } @@ -478,7 +464,7 @@ static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, vsllink_state_move(); } -static void vsllink_reset(int trst, int srst) +static int vsllink_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); @@ -494,7 +480,7 @@ static void vsllink_reset(int trst, int srst) versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0); } - versaloon_interface.adaptors.peripheral_commit(); + return versaloon_interface.adaptors.peripheral_commit(); } COMMAND_HANDLER(vsllink_handle_usb_vid_command) @@ -962,17 +948,23 @@ static const struct swd_driver vsllink_swd_driver = { .run = vsllink_swd_run_queue, }; -struct jtag_interface vsllink_interface = { - .name = "vsllink", +static struct jtag_interface vsllink_interface = { .supported = DEBUG_CAP_TMS_SEQ, - .commands = vsllink_command_handlers, + .execute_queue = vsllink_execute_queue, +}; + +struct adapter_driver vsllink_adapter_driver = { + .name = "vsllink", .transports = vsllink_transports, - .swd = &vsllink_swd_driver, + .commands = vsllink_command_handlers, .init = vsllink_init, .quit = vsllink_quit, - .khz = vsllink_khz, + .reset = vsllink_reset, .speed = vsllink_speed, + .khz = vsllink_khz, .speed_div = vsllink_speed_div, - .execute_queue = vsllink_execute_queue, + + .jtag_ops = &vsllink_interface, + .swd_ops = &vsllink_swd_driver, }; diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index f25023b..5e4df93 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -41,6 +41,12 @@ #define OCD_FIRMWARE_UPGRADE \ "XDS110: upgrade to version 2.3.0.11+ for improved support" +/* Firmware version that introduced improved TCK performance */ +#define FAST_TCK_FIRMWARE_VERSION 0x03000000 + +/* Firmware version that introduced 10 MHz and 12 MHz TCK support */ +#define FAST_TCK_PLUS_FIRMWARE_VERSION 0x03000003 + /*************************************************************************** * USB Connection Buffer Definitions * ***************************************************************************/ @@ -61,15 +67,6 @@ #define MAX_RESULT_QUEUE (MAX_DATA_BLOCK / 4) /*************************************************************************** - * USB Connection Endpoints * - ***************************************************************************/ - -/* Bulk endpoints used by the XDS110 debug interface */ -#define INTERFACE_DEBUG (2) -#define ENDPOINT_DEBUG_IN (3 | LIBUSB_ENDPOINT_IN) -#define ENDPOINT_DEBUG_OUT (2 | LIBUSB_ENDPOINT_OUT) - -/*************************************************************************** * XDS110 Firmware API Definitions * ***************************************************************************/ @@ -91,8 +88,17 @@ /* TCK frequency limits */ #define XDS110_MIN_TCK_SPEED 100 /* kHz */ -#define XDS110_MAX_TCK_SPEED 2500 /* kHz */ -#define XDS110_TCK_PULSE_INCREMENT 66.0 +#define XDS110_MAX_SLOW_TCK_SPEED 2500 /* kHz */ +#define XDS110_MAX_FAST_TCK_SPEED 14000 /* kHz */ +#define XDS110_DEFAULT_TCK_SPEED 2500 /* kHz */ + +/* Fixed TCK delay values for "Fast" TCK frequencies */ +#define FAST_TCK_DELAY_14000_KHZ 0 +#define FAST_TCK_DELAY_10000_KHZ 0xfffffffd +#define FAST_TCK_DELAY_12000_KHZ 0xfffffffe +#define FAST_TCK_DELAY_8500_KHZ 1 +#define FAST_TCK_DELAY_5500_KHZ 2 +/* For TCK frequencies below 5500 kHz, use calculated delay */ /* Scan mode on connect */ #define MODE_JTAG 1 @@ -212,6 +218,13 @@ struct xds110_info { unsigned char read_payload[USB_PAYLOAD_SIZE]; unsigned char write_packet[3]; unsigned char write_payload[USB_PAYLOAD_SIZE]; + /* Device vid/pid */ + uint16_t vid; + uint16_t pid; + /* Debug interface */ + uint8_t interface; + uint8_t endpoint_in; + uint8_t endpoint_out; /* Status flags */ bool is_connected; bool is_cmapi_connected; @@ -244,12 +257,17 @@ struct xds110_info { static struct xds110_info xds110 = { .ctx = NULL, .dev = NULL, + .vid = 0, + .pid = 0, + .interface = 0, + .endpoint_in = 0, + .endpoint_out = 0, .is_connected = false, .is_cmapi_connected = false, .is_cmapi_acquired = false, .is_swd_mode = false, .is_ap_dirty = false, - .speed = XDS110_MAX_TCK_SPEED, + .speed = XDS110_DEFAULT_TCK_SPEED, .delay_count = 0, .serial = {0}, .voltage = 0, @@ -305,12 +323,20 @@ static bool usb_connect(void) struct libusb_device_descriptor desc; - uint16_t vid = 0x0451; - uint16_t pid = 0xbef3; + /* The vid/pids of possible XDS110 configurations */ + uint16_t vids[] = { 0x0451, 0x0451, 0x1cbe }; + uint16_t pids[] = { 0xbef3, 0xbef4, 0x02a5 }; + /* Corresponding interface and endpoint numbers for configurations */ + uint8_t interfaces[] = { 2, 2, 0 }; + uint8_t endpoints_in[] = { 3, 3, 1 }; + uint8_t endpoints_out[] = { 2, 2, 1 }; + ssize_t count = 0; ssize_t i = 0; int result = 0; bool found = false; + uint32_t device = 0; + bool match = false; /* Initialize libusb context */ result = libusb_init(&ctx); @@ -327,13 +353,21 @@ static bool usb_connect(void) if (0 == result) { /* Scan through list of devices for any XDS110s */ for (i = 0; i < count; i++) { - /* Check for device VID/PID match */ + /* Check for device vid/pid match */ libusb_get_device_descriptor(list[i], &desc); - if (desc.idVendor == vid && desc.idProduct == pid) { + match = false; + for (device = 0; device < sizeof(vids)/sizeof(vids[0]); device++) { + if (desc.idVendor == vids[device] && + desc.idProduct == pids[device]) { + match = true; + break; + } + } + if (match) { result = libusb_open(list[i], &dev); if (0 == result) { - const int MAX_DATA = 256; - unsigned char data[MAX_DATA + 1]; + const int max_data = 256; + unsigned char data[max_data + 1]; *data = '\0'; /* May be the requested device if serial number matches */ @@ -344,7 +378,7 @@ static bool usb_connect(void) } else { /* Get the device's serial number string */ result = libusb_get_string_descriptor_ascii(dev, - desc.iSerialNumber, data, MAX_DATA); + desc.iSerialNumber, data, max_data); if (0 < result && 0 == strcmp((char *)data, (char *)xds110.serial)) { found = true; @@ -372,6 +406,15 @@ static bool usb_connect(void) } if (found) { + /* Save the vid/pid of the device we're using */ + xds110.vid = vids[device]; + xds110.pid = pids[device]; + + /* Save the debug interface and endpoints for the device */ + xds110.interface = interfaces[device]; + xds110.endpoint_in = endpoints_in[device] | LIBUSB_ENDPOINT_IN; + xds110.endpoint_out = endpoints_out[device] | LIBUSB_ENDPOINT_OUT; + /* Save the context and device handles */ xds110.ctx = ctx; xds110.dev = dev; @@ -380,7 +423,7 @@ static bool usb_connect(void) (void)libusb_set_auto_detach_kernel_driver(dev, 1); /* Claim the debug interface on the XDS110 */ - result = libusb_claim_interface(dev, INTERFACE_DEBUG); + result = libusb_claim_interface(dev, xds110.interface); } else { /* Couldn't find an XDS110, flag the error */ result = -1; @@ -390,7 +433,7 @@ static bool usb_connect(void) if (0 != result) { if (NULL != dev) { /* Release the debug and data interface on the XDS110 */ - (void)libusb_release_interface(dev, INTERFACE_DEBUG); + (void)libusb_release_interface(dev, xds110.interface); libusb_close(dev); } if (NULL != ctx) @@ -412,7 +455,7 @@ static void usb_disconnect(void) { if (NULL != xds110.dev) { /* Release the debug and data interface on the XDS110 */ - (void)libusb_release_interface(xds110.dev, INTERFACE_DEBUG); + (void)libusb_release_interface(xds110.dev, xds110.interface); libusb_close(xds110.dev); xds110.dev = NULL; } @@ -436,7 +479,7 @@ static bool usb_read(unsigned char *buffer, int size, int *bytes_read, if (0 == timeout) timeout = DEFAULT_TIMEOUT; - result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_IN, buffer, size, + result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_in, buffer, size, bytes_read, timeout); return (0 == result) ? true : false; @@ -451,13 +494,13 @@ static bool usb_write(unsigned char *buffer, int size, int *written) if (NULL == xds110.dev || NULL == buffer) return false; - result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_OUT, buffer, + result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, size, &bytes_written, 0); while (LIBUSB_ERROR_PIPE == result && retries < 3) { /* Try clearing the pipe stall and retry transfer */ - libusb_clear_halt(xds110.dev, ENDPOINT_DEBUG_OUT); - result = libusb_bulk_transfer(xds110.dev, ENDPOINT_DEBUG_OUT, buffer, + libusb_clear_halt(xds110.dev, xds110.endpoint_out); + result = libusb_bulk_transfer(xds110.dev, xds110.endpoint_out, buffer, size, &bytes_written, 0); retries++; } @@ -1345,6 +1388,7 @@ static void xds110_show_info(void) { uint32_t firmware = xds110.firmware; + LOG_INFO("XDS110: vid/pid = %04x/%04x", xds110.vid, xds110.pid); LOG_INFO("XDS110: firmware version = %d.%d.%d.%d", (((firmware >> 28) & 0xf) * 10) + ((firmware >> 24) & 0xf), (((firmware >> 20) & 0xf) * 10) + ((firmware >> 16) & 0xf), @@ -1592,48 +1636,58 @@ static void xds110_flush(void) xds110.txn_result_count = 0; } -static void xds110_execute_reset(struct jtag_command *cmd) +static int xds110_reset(int trst, int srst) { - char trst; - char srst; + uint8_t value; + bool success; + int retval = ERROR_OK; - if (cmd->cmd.reset->trst != -1) { - if (cmd->cmd.reset->trst == 0) { + if (trst != -1) { + if (trst == 0) { /* Deassert nTRST (active low) */ - trst = 1; + value = 1; } else { /* Assert nTRST (active low) */ - trst = 0; + value = 0; } - (void)xds_set_trst(trst); + success = xds_set_trst(value); + if (!success) + retval = ERROR_FAIL; } - if (cmd->cmd.reset->srst != -1) { - if (cmd->cmd.reset->srst == 0) { + if (srst != -1) { + if (srst == 0) { /* Deassert nSRST (active low) */ - srst = 1; + value = 1; } else { /* Assert nSRST (active low) */ - srst = 0; + value = 0; } - (void)xds_set_srst(srst); + success = xds_set_srst(value); + if (!success) + retval = ERROR_FAIL; /* Toggle TCK to trigger HIB on CC13x/CC26x devices */ - (void)xds_cycle_tck(60000); + if (success && !xds110.is_swd_mode) { + /* Toggle TCK for about 50 ms */ + success = xds_cycle_tck(xds110.speed * 50); + } + + if (!success) + retval = ERROR_FAIL; } + + return retval; } static void xds110_execute_sleep(struct jtag_command *cmd) { jtag_sleep(cmd->cmd.sleep->us); - return; } static void xds110_execute_tlr_reset(struct jtag_command *cmd) { (void)xds_goto_state(XDS_JTAG_STATE_RESET); - - return; } static void xds110_execute_pathmove(struct jtag_command *cmd) @@ -1669,8 +1723,6 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) } free((void *)path); - - return; } static void xds110_queue_scan(struct jtag_command *cmd) @@ -1742,8 +1794,6 @@ static void xds110_queue_scan(struct jtag_command *cmd) } xds110.txn_request_size += total_bytes; xds110.txn_result_size += total_bytes; - - return; } static void xds110_queue_runtest(struct jtag_command *cmd) @@ -1763,8 +1813,6 @@ static void xds110_queue_runtest(struct jtag_command *cmd) xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = end_state; - - return; } static void xds110_queue_stableclocks(struct jtag_command *cmd) @@ -1781,17 +1829,11 @@ static void xds110_queue_stableclocks(struct jtag_command *cmd) xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 8) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 16) & 0xff; xds110.txn_requests[xds110.txn_request_size++] = (clocks >> 24) & 0xff; - - return; } static void xds110_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_RESET: - xds110_flush(); - xds110_execute_reset(cmd); - break; case JTAG_SLEEP: xds110_flush(); xds110_execute_sleep(cmd); @@ -1837,6 +1879,8 @@ static int xds110_execute_queue(void) static int xds110_speed(int speed) { + double freq_to_use; + uint32_t delay_count; bool success; if (speed == 0) { @@ -1844,61 +1888,110 @@ static int xds110_speed(int speed) return ERROR_JTAG_NOT_IMPLEMENTED; } - if (speed > XDS110_MAX_TCK_SPEED) { - LOG_INFO("XDS110: reduce speed request: %dkHz to %dkHz maximum", - speed, XDS110_MAX_TCK_SPEED); - speed = XDS110_MAX_TCK_SPEED; - } - if (speed < XDS110_MIN_TCK_SPEED) { - LOG_INFO("XDS110: increase speed request: %dkHz to %dkHz minimum", + LOG_INFO("XDS110: increase speed request: %d kHz to %d kHz minimum", speed, XDS110_MIN_TCK_SPEED); speed = XDS110_MIN_TCK_SPEED; } - /* The default is the maximum frequency the XDS110 can support */ - uint32_t freq_to_use = XDS110_MAX_TCK_SPEED * 1000; /* Hz */ - uint32_t delay_count = 0; + /* Older XDS110 firmware had inefficient scan routines and could only */ + /* achieve a peak TCK frequency of about 2500 kHz */ + if (xds110.firmware < FAST_TCK_FIRMWARE_VERSION) { - if (XDS110_MAX_TCK_SPEED != speed) { - freq_to_use = speed * 1000; /* Hz */ + /* Check for request for top speed or higher */ + if (speed >= XDS110_MAX_SLOW_TCK_SPEED) { - /* Calculate the delay count value */ - double one_giga = 1000000000; - /* Get the pulse duration for the maximum frequency supported in ns */ - double max_freq_pulse_duration = one_giga / - (XDS110_MAX_TCK_SPEED * 1000); + /* Inform user that speed was adjusted down to max possible */ + if (speed > XDS110_MAX_SLOW_TCK_SPEED) { + LOG_INFO( + "XDS110: reduce speed request: %d kHz to %d kHz maximum", + speed, XDS110_MAX_SLOW_TCK_SPEED); + speed = XDS110_MAX_SLOW_TCK_SPEED; + } + delay_count = 0; - /* Convert frequency to pulse duration */ - double freq_to_pulse_width_in_ns = one_giga / freq_to_use; + } else { - /* - * Start with the pulse duration for the maximum frequency. Keep - * decrementing the time added by each count value till the requested - * frequency pulse is less than the calculated value. - */ - double current_value = max_freq_pulse_duration; + const double XDS110_TCK_PULSE_INCREMENT = 66.0; + freq_to_use = speed * 1000; /* Hz */ + delay_count = 0; + + /* Calculate the delay count value */ + double one_giga = 1000000000; + /* Get the pulse duration for the max frequency supported in ns */ + double max_freq_pulse_duration = one_giga / + (XDS110_MAX_SLOW_TCK_SPEED * 1000); - while (current_value < freq_to_pulse_width_in_ns) { - current_value += XDS110_TCK_PULSE_INCREMENT; - ++delay_count; + /* Convert frequency to pulse duration */ + double freq_to_pulse_width_in_ns = one_giga / freq_to_use; + + /* + * Start with the pulse duration for the maximum frequency. Keep + * decrementing time added by each count value till the requested + * frequency pulse is less than the calculated value. + */ + double current_value = max_freq_pulse_duration; + + while (current_value < freq_to_pulse_width_in_ns) { + current_value += XDS110_TCK_PULSE_INCREMENT; + ++delay_count; + } + + /* + * Determine which delay count yields the best match. + * The one obtained above or one less. + */ + if (delay_count) { + double diff_freq_1 = freq_to_use - + (one_giga / (max_freq_pulse_duration + + (XDS110_TCK_PULSE_INCREMENT * delay_count))); + double diff_freq_2 = (one_giga / (max_freq_pulse_duration + + (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) - + freq_to_use; + + /* One less count value yields a better match */ + if (diff_freq_1 > diff_freq_2) + --delay_count; + } } - /* - * Determine which delay count yields the best match. - * The one obtained above or one less. - */ - if (delay_count) { - double diff_freq_1 = freq_to_use - - (one_giga / (max_freq_pulse_duration + - (XDS110_TCK_PULSE_INCREMENT * delay_count))); - double diff_freq_2 = (one_giga / (max_freq_pulse_duration + - (XDS110_TCK_PULSE_INCREMENT * (delay_count - 1)))) - - freq_to_use; - - /* One less count value yields a better match */ - if (diff_freq_1 > diff_freq_2) - --delay_count; + /* Newer firmware has reworked TCK routines that are much more efficient */ + /* and can now achieve a peak TCK frequency of 14000 kHz */ + } else { + + if (speed >= XDS110_MAX_FAST_TCK_SPEED) { + if (speed > XDS110_MAX_FAST_TCK_SPEED) { + LOG_INFO( + "XDS110: reduce speed request: %d kHz to %d kHz maximum", + speed, XDS110_MAX_FAST_TCK_SPEED); + speed = XDS110_MAX_FAST_TCK_SPEED; + } + delay_count = 0; + } else if (speed >= 12000 && xds110.firmware >= + FAST_TCK_PLUS_FIRMWARE_VERSION) { + delay_count = FAST_TCK_DELAY_12000_KHZ; + } else if (speed >= 10000 && xds110.firmware >= + FAST_TCK_PLUS_FIRMWARE_VERSION) { + delay_count = FAST_TCK_DELAY_10000_KHZ; + } else if (speed >= 8500) { + delay_count = FAST_TCK_DELAY_8500_KHZ; + } else if (speed >= 5500) { + delay_count = FAST_TCK_DELAY_5500_KHZ; + } else { + /* Calculate the delay count to set the frequency */ + /* Formula determined by measuring the waveform on Saeleae logic */ + /* analyzer using known values for delay count */ + const double m = 17100000.0; /* slope */ + const double b = -1.02; /* y-intercept */ + + freq_to_use = speed * 1000; /* Hz */ + double period = 1.0/freq_to_use; + double delay = m * period + b; + + if (delay < 1.0) + delay_count = 1; + else + delay_count = (uint32_t)delay; } } @@ -1953,11 +2046,8 @@ COMMAND_HANDLER(xds110_handle_serial_command) xds110.serial[i] = (char)serial[i]; xds110.serial[len] = 0; - } else { - LOG_ERROR("XDS110: expected exactly one argument to xds110_serial " - "<serial-number>"); - return ERROR_FAIL; - } + } else + return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } @@ -1978,11 +2068,8 @@ COMMAND_HANDLER(xds110_handle_supply_voltage_command) return ERROR_FAIL; } xds110.voltage = voltage; - } else { - LOG_ERROR("XDS110: expected one argument to xds110_supply_voltage " - "<millivolts>"); - return ERROR_FAIL; - } + } else + return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } @@ -1992,33 +2079,33 @@ static const struct command_registration xds110_subcommand_handlers[] = { .name = "info", .handler = &xds110_handle_info_command, .mode = COMMAND_EXEC, - .usage = "", .help = "show XDS110 info", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration xds110_command_handlers[] = { - { - .name = "xds110", - .mode = COMMAND_ANY, - .help = "perform XDS110 management", - .usage = "<cmd>", - .chain = xds110_subcommand_handlers, + .usage = "", }, { - .name = "xds110_serial", + .name = "serial", .handler = &xds110_handle_serial_command, .mode = COMMAND_CONFIG, .help = "set the XDS110 probe serial number", .usage = "serial_string", }, { - .name = "xds110_supply_voltage", + .name = "supply", .handler = &xds110_handle_supply_voltage_command, .mode = COMMAND_CONFIG, .help = "set the XDS110 probe supply voltage", - .usage = "supply_voltage (millivolts)", + .usage = "voltage_in_millivolts", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration xds110_command_handlers[] = { + { + .name = "xds110", + .mode = COMMAND_ANY, + .help = "perform XDS110 management", + .usage = "", + .chain = xds110_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; @@ -2033,16 +2120,22 @@ static const struct swd_driver xds110_swd_driver = { static const char * const xds110_transport[] = { "swd", "jtag", NULL }; -struct jtag_interface xds110_interface = { +static struct jtag_interface xds110_interface = { + .execute_queue = xds110_execute_queue, +}; + +struct adapter_driver xds110_adapter_driver = { .name = "xds110", - .commands = xds110_command_handlers, - .swd = &xds110_swd_driver, .transports = xds110_transport, + .commands = xds110_command_handlers, - .execute_queue = xds110_execute_queue, - .speed = xds110_speed, - .speed_div = xds110_speed_div, - .khz = xds110_khz, .init = xds110_init, .quit = xds110_quit, + .reset = xds110_reset, + .speed = xds110_speed, + .khz = xds110_khz, + .speed_div = xds110_speed_div, + + .jtag_ops = &xds110_interface, + .swd_ops = &xds110_swd_driver, }; diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c new file mode 100644 index 0000000..1743859 --- /dev/null +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -0,0 +1,487 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2019 Google, LLC. + * Author: Moritz Fischer <moritzf@google.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdint.h> +#include <stdlib.h> +#include <math.h> +#include <unistd.h> +#include <linux/pci.h> + +#include <jtag/interface.h> +#include <jtag/swd.h> +#include <jtag/commands.h> +#include <helper/replacements.h> +#include <helper/bits.h> + +/* Available only from kernel v4.10 */ +#ifndef PCI_CFG_SPACE_EXP_SIZE +#define PCI_CFG_SPACE_EXP_SIZE 4096 +#endif + +#define PCIE_EXT_CAP_LST 0x100 + +#define XLNX_XVC_EXT_CAP 0x00 +#define XLNX_XVC_VSEC_HDR 0x04 +#define XLNX_XVC_LEN_REG 0x0C +#define XLNX_XVC_TMS_REG 0x10 +#define XLNX_XVC_TDx_REG 0x14 + +#define XLNX_XVC_CAP_SIZE 0x20 +#define XLNX_XVC_VSEC_ID 0x8 +#define XLNX_XVC_MAX_BITS 0x20 + +struct xlnx_pcie_xvc { + int fd; + unsigned offset; + char *device; +}; + +static struct xlnx_pcie_xvc xlnx_pcie_xvc_state; +static struct xlnx_pcie_xvc *xlnx_pcie_xvc = &xlnx_pcie_xvc_state; + +static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) +{ + uint32_t res; + int err; + + /* Note: This should be ok endianess-wise because by going + * through sysfs the kernel does the conversion in the config + * space accessor functions + */ + err = pread(xlnx_pcie_xvc->fd, &res, sizeof(res), + xlnx_pcie_xvc->offset + offset); + if (err != sizeof(res)) { + LOG_ERROR("Failed to read offset %x", offset); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (val) + *val = res; + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) +{ + int err; + + /* Note: This should be ok endianess-wise because by going + * through sysfs the kernel does the conversion in the config + * space accessor functions + */ + err = pwrite(xlnx_pcie_xvc->fd, &val, sizeof(val), + xlnx_pcie_xvc->offset + offset); + if (err != sizeof(val)) { + LOG_ERROR("Failed to write offset: %x with value: %x", + offset, val); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, + uint32_t *tdo) +{ + int err; + + err = xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG, num_bits); + if (err != ERROR_OK) + return err; + + err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG, tms); + if (err != ERROR_OK) + return err; + + err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDx_REG, tdi); + if (err != ERROR_OK) + return err; + + err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDx_REG, tdo); + if (err != ERROR_OK) + return err; + + if (tdo) + LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: %x", + num_bits, tms, tdi, *tdo); + else + LOG_DEBUG_IO("Transact num_bits: %zu, tms: %x, tdi: %x, tdo: <null>", + num_bits, tms, tdi); + return ERROR_OK; +} + +int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) +{ + int tms = tap_get_state() == TAP_RESET ? 1 : 0; + size_t left = cmd->cmd.stableclocks->num_cycles; + size_t write; + int err; + + LOG_DEBUG("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); + + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + if (err != ERROR_OK) + return err; + left -= write; + }; + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_statemove(size_t skip) +{ + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), + tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), + tap_get_end_state()); + int err; + + LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip, + tap_state_name(tap_get_state()), + tap_state_name(tap_get_end_state())); + + + err = xlnx_pcie_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL); + if (err != ERROR_OK) + return err; + + tap_set_state(tap_get_end_state()); + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) +{ + int err = ERROR_OK; + + LOG_DEBUG("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + + tap_state_t tmp_state = tap_get_end_state(); + + if (tap_get_state() != TAP_IDLE) { + tap_set_end_state(TAP_IDLE); + err = xlnx_pcie_xvc_execute_statemove(0); + if (err != ERROR_OK) + return err; + }; + + size_t left = cmd->cmd.runtest->num_cycles; + size_t write; + + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + err = xlnx_pcie_xvc_transact(write, 0, 0, NULL); + if (err != ERROR_OK) + return err; + left -= write; + }; + + tap_set_end_state(tmp_state); + if (tap_get_state() != tap_get_end_state()) + err = xlnx_pcie_xvc_execute_statemove(0); + + return err; +} + +static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) +{ + size_t num_states = cmd->cmd.pathmove->num_states; + tap_state_t *path = cmd->cmd.pathmove->path; + int err = ERROR_OK; + size_t i; + + LOG_DEBUG("pathmove: %i states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + + for (i = 0; i < num_states; i++) { + if (path[i] == tap_state_transition(tap_get_state(), false)) { + err = xlnx_pcie_xvc_transact(1, 1, 0, NULL); + } else if (path[i] == tap_state_transition(tap_get_state(), true)) { + err = xlnx_pcie_xvc_transact(1, 0, 0, NULL); + } else { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", + tap_state_name(tap_get_state()), + tap_state_name(path[i])); + err = ERROR_JTAG_QUEUE_FAILED; + } + if (err != ERROR_OK) + return err; + tap_set_state(path[i]); + } + + tap_set_end_state(tap_get_state()); + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) +{ + enum scan_type type = jtag_scan_type(cmd->cmd.scan); + tap_state_t saved_end_state = cmd->cmd.scan->end_state; + bool ir_scan = cmd->cmd.scan->ir_scan; + uint32_t tdi, tms, tdo; + uint8_t *buf, *rd_ptr; + int err, scan_size; + size_t write; + size_t left; + + scan_size = jtag_build_buffer(cmd->cmd.scan, &buf); + rd_ptr = buf; + LOG_DEBUG("%s scan type %d %d bits; starts in %s end in %s", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", type, scan_size, + tap_state_name(tap_get_state()), + tap_state_name(cmd->cmd.scan->end_state)); + + /* If we're in TAP_DR_SHIFT state but need to do a IR_SCAN or + * vice-versa, do a statemove to corresponding other state, then restore + * end state + */ + if (ir_scan && tap_get_state() != TAP_IRSHIFT) { + tap_set_end_state(TAP_IRSHIFT); + err = xlnx_pcie_xvc_execute_statemove(0); + if (err != ERROR_OK) + goto out_err; + tap_set_end_state(saved_end_state); + } else if (!ir_scan && (tap_get_state() != TAP_DRSHIFT)) { + tap_set_end_state(TAP_DRSHIFT); + err = xlnx_pcie_xvc_execute_statemove(0); + if (err != ERROR_OK) + goto out_err; + tap_set_end_state(saved_end_state); + } + + left = scan_size; + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + /* the last TMS should be a 1, to leave the state */ + tms = left <= XLNX_XVC_MAX_BITS ? BIT(write - 1) : 0; + tdi = (type != SCAN_IN) ? buf_get_u32(rd_ptr, 0, write) : 0; + err = xlnx_pcie_xvc_transact(write, tms, tdi, type != SCAN_OUT ? + &tdo : NULL); + if (err != ERROR_OK) + goto out_err; + left -= write; + if (type != SCAN_OUT) + buf_set_u32(rd_ptr, 0, write, tdo); + rd_ptr += sizeof(uint32_t); + }; + + err = jtag_read_buffer(buf, cmd->cmd.scan); + if (buf) + free(buf); + + if (tap_get_state() != tap_get_end_state()) + err = xlnx_pcie_xvc_execute_statemove(1); + + return err; + +out_err: + if (buf) + free(buf); + return err; +} + +static void xlnx_pcie_xvc_execute_reset(struct jtag_command *cmd) +{ + LOG_DEBUG("reset trst: %i srst: %i", cmd->cmd.reset->trst, + cmd->cmd.reset->srst); +} + +static void xlnx_pcie_xvc_execute_sleep(struct jtag_command *cmd) +{ + LOG_DEBUG("sleep %" PRIi32 "", cmd->cmd.sleep->us); + usleep(cmd->cmd.sleep->us); +} + +static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) +{ + const size_t num_bits = cmd->cmd.tms->num_bits; + const uint8_t *bits = cmd->cmd.tms->bits; + size_t left, write; + uint32_t tms; + int err; + + LOG_DEBUG("execute tms %zu", num_bits); + + left = num_bits; + while (left) { + write = MIN(XLNX_XVC_MAX_BITS, left); + tms = buf_get_u32(bits, 0, write); + err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + if (err != ERROR_OK) + return err; + left -= write; + bits += 4; + }; + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) +{ + LOG_DEBUG("%s: cmd->type: %u", __func__, cmd->type); + switch (cmd->type) { + case JTAG_STABLECLOCKS: + return xlnx_pcie_xvc_execute_stableclocks(cmd); + case JTAG_RUNTEST: + return xlnx_pcie_xvc_execute_runtest(cmd); + case JTAG_TLR_RESET: + tap_set_end_state(cmd->cmd.statemove->end_state); + return xlnx_pcie_xvc_execute_statemove(0); + case JTAG_PATHMOVE: + return xlnx_pcie_xvc_execute_pathmove(cmd); + case JTAG_SCAN: + return xlnx_pcie_xvc_execute_scan(cmd); + case JTAG_RESET: + xlnx_pcie_xvc_execute_reset(cmd); + break; + case JTAG_SLEEP: + xlnx_pcie_xvc_execute_sleep(cmd); + break; + case JTAG_TMS: + return xlnx_pcie_xvc_execute_tms(cmd); + default: + LOG_ERROR("BUG: Unknown JTAG command type encountered."); + return ERROR_JTAG_QUEUE_FAILED; + } + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; + int ret; + + while (cmd) { + ret = xlnx_pcie_xvc_execute_command(cmd); + + if (ret != ERROR_OK) + return ret; + + cmd = cmd->next; + } + + return ERROR_OK; +} + + +static int xlnx_pcie_xvc_init(void) +{ + char filename[PATH_MAX]; + uint32_t cap, vh; + int err; + + snprintf(filename, PATH_MAX, "/sys/bus/pci/devices/%s/config", + xlnx_pcie_xvc->device); + xlnx_pcie_xvc->fd = open(filename, O_RDWR | O_SYNC); + if (xlnx_pcie_xvc->fd < 0) { + LOG_ERROR("Failed to open device: %s", filename); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("Scanning PCIe device %s's for Xilinx XVC/PCIe ...", + xlnx_pcie_xvc->device); + /* Parse the PCIe extended capability list and try to find + * vendor specific header */ + xlnx_pcie_xvc->offset = PCIE_EXT_CAP_LST; + while (xlnx_pcie_xvc->offset <= PCI_CFG_SPACE_EXP_SIZE - sizeof(cap) && + xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) { + err = xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP, &cap); + if (err != ERROR_OK) + return err; + LOG_DEBUG("Checking capability at 0x%x; id=0x%04x version=0x%x next=0x%x", + xlnx_pcie_xvc->offset, + PCI_EXT_CAP_ID(cap), + PCI_EXT_CAP_VER(cap), + PCI_EXT_CAP_NEXT(cap)); + if (PCI_EXT_CAP_ID(cap) == PCI_EXT_CAP_ID_VNDR) { + err = xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR, &vh); + if (err != ERROR_OK) + return err; + LOG_DEBUG("Checking possible match at 0x%x; id: 0x%x; rev: 0x%x; length: 0x%x", + xlnx_pcie_xvc->offset, + PCI_VNDR_HEADER_ID(vh), + PCI_VNDR_HEADER_REV(vh), + PCI_VNDR_HEADER_LEN(vh)); + if ((PCI_VNDR_HEADER_ID(vh) == XLNX_XVC_VSEC_ID) && + (PCI_VNDR_HEADER_LEN(vh) == XLNX_XVC_CAP_SIZE)) + break; + } + xlnx_pcie_xvc->offset = PCI_EXT_CAP_NEXT(cap); + } + if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_XVC_CAP_SIZE) || + xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) { + close(xlnx_pcie_xvc->fd); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("Found Xilinx XVC/PCIe capability at offset: 0x%x", xlnx_pcie_xvc->offset); + + return ERROR_OK; +} + +static int xlnx_pcie_xvc_quit(void) +{ + int err; + + err = close(xlnx_pcie_xvc->fd); + if (err) + return err; + + return ERROR_OK; +} + +COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* we can't really free this in a safe manner, so at least + * limit the memory we're leaking by freeing the old one first + * before allocating a new one ... + */ + if (xlnx_pcie_xvc->device) + free(xlnx_pcie_xvc->device); + + xlnx_pcie_xvc->device = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { + { + .name = "xlnx_pcie_xvc_config", + .handler = xlnx_pcie_xvc_handle_config_command, + .mode = COMMAND_CONFIG, + .help = "Configure XVC/PCIe JTAG adapter", + .usage = "device", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface xlnx_pcie_xvc_interface = { + .execute_queue = &xlnx_pcie_xvc_execute_queue, +}; + +struct adapter_driver xlnx_pcie_xvc_adapter_driver = { + .name = "xlnx_pcie_xvc", + .transports = jtag_only, + .commands = xlnx_pcie_xvc_command_handlers, + + .init = &xlnx_pcie_xvc_init, + .quit = &xlnx_pcie_xvc_quit, + + .jtag_ops = &xlnx_pcie_xvc_interface, +}; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 2abed21..6d5cdc5 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -35,7 +35,7 @@ #include <target/target.h> -static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; +static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; int hl_interface_open(enum hl_transports tr) { @@ -127,22 +127,19 @@ static int hl_interface_quit(void) return ERROR_OK; } -static int hl_interface_execute_queue(void) +static int hl_interface_reset(int req_trst, int req_srst) { - LOG_DEBUG("hl_interface_execute_queue: ignored"); - - return ERROR_OK; + return hl_if.layout->api->assert_srst(hl_if.handle, req_srst ? 0 : 1); } int hl_interface_init_reset(void) { - /* incase the adapter has not already handled asserting srst + /* in case the adapter has not already handled asserting srst * we will attempt it again */ if (hl_if.param.connect_under_reset) { - jtag_add_reset(0, 1); - hl_if.layout->api->assert_srst(hl_if.handle, 0); + adapter_assert_reset(); } else { - jtag_add_reset(0, 0); + adapter_deassert_reset(); } return ERROR_OK; @@ -192,11 +189,12 @@ int hl_interface_override_target(const char **targetname) } int hl_interface_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 (hl_if.layout->api->config_trace) - return hl_if.layout->api->config_trace(hl_if.handle, enabled, pin_protocol, - port_size, trace_freq); + return hl_if.layout->api->config_trace(hl_if.handle, 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; @@ -348,17 +346,19 @@ static const struct command_registration hl_interface_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct jtag_interface hl_interface = { +struct adapter_driver hl_adapter_driver = { .name = "hla", - .supported = 0, - .commands = hl_interface_command_handlers, .transports = hl_transports, + .commands = hl_interface_command_handlers, + .init = hl_interface_init, .quit = hl_interface_quit, - .execute_queue = hl_interface_execute_queue, + .reset = hl_interface_reset, .speed = &hl_interface_speed, .khz = &hl_interface_khz, .speed_div = &hl_interface_speed_div, .config_trace = &hl_interface_config_trace, .poll_trace = &hl_interface_poll_trace, + + /* no ops for HLA, targets hla_target and stm8 intercept them all */ }; diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index 262025e..b6e4a8b 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -41,8 +41,6 @@ struct hl_interface_param_s { /** List of recognised PIDs */ uint16_t pid[HLA_MAX_USB_IDS + 1]; /** */ - unsigned api; - /** */ enum hl_transports transport; /** */ bool connect_under_reset; diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index 9f41b59..1d759e1 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -91,8 +91,10 @@ struct hl_layout_api_s { * its maximum supported rate there * @returns ERROR_OK on success, an error code on failure. */ - int (*config_trace)(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, - uint32_t port_size, unsigned int *trace_freq); + int (*config_trace)(void *handle, bool enabled, + enum tpiu_pin_protocol pin_protocol, uint32_t port_size, + unsigned int *trace_freq, unsigned int traceclkin_freq, + uint16_t *prescaler); /** * Poll for new trace data * diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index ddacea3..fbdddfd 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -175,8 +175,6 @@ static int hl_transport_init(struct command_context *cmd_ctx) tr = HL_TRANSPORT_SWD; else if (strcmp(transport->name, "hla_jtag") == 0) tr = HL_TRANSPORT_JTAG; - else if (strcmp(transport->name, "stlink_swim") == 0) - tr = HL_TRANSPORT_SWIM; int retval = hl_interface_open(tr); @@ -218,26 +216,18 @@ static struct transport hl_jtag_transport = { .override_target = hl_interface_override_target, }; -static struct transport stlink_swim_transport = { - .name = "stlink_swim", - .select = hl_transport_select, - .init = hl_transport_init, -}; - -const char *hl_transports[] = { "hla_swd", "hla_jtag", "stlink_swim", NULL }; +const char *hl_transports[] = { "hla_swd", "hla_jtag", NULL }; static void hl_constructor(void) __attribute__ ((constructor)); static void hl_constructor(void) { transport_register(&hl_swd_transport); transport_register(&hl_jtag_transport); - transport_register(&stlink_swim_transport); } bool transport_is_hla(void) { struct transport *t; t = get_current_transport(); - return t == &hl_swd_transport || t == &hl_jtag_transport - || t == &stlink_swim_transport; + return t == &hl_swd_transport || t == &hl_jtag_transport; } diff --git a/src/jtag/hla/hla_transport.h b/src/jtag/hla/hla_transport.h index 07eb751..0e0bea2 100644 --- a/src/jtag/hla/hla_transport.h +++ b/src/jtag/hla/hla_transport.h @@ -26,7 +26,6 @@ enum hl_transports { HL_TRANSPORT_UNKNOWN = 0, HL_TRANSPORT_SWD, HL_TRANSPORT_JTAG, - HL_TRANSPORT_SWIM }; #endif /* OPENOCD_JTAG_HLA_HLA_TRANSPORT_H */ diff --git a/src/jtag/interface.c b/src/jtag/interface.c index de132bb..56bbf6e 100644 --- a/src/jtag/interface.c +++ b/src/jtag/interface.c @@ -45,7 +45,7 @@ void tap_set_state_impl(tap_state_t new_state) state_follower = new_state; } -tap_state_t tap_get_state() +tap_state_t tap_get_state(void) { return state_follower; } @@ -64,7 +64,7 @@ void tap_set_end_state(tap_state_t new_end_state) end_state_follower = new_end_state; } -tap_state_t tap_get_end_state() +tap_state_t tap_get_end_state(void) { return end_state_follower; } diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 905f1eb..42598c1 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -26,6 +26,7 @@ #define OPENOCD_JTAG_INTERFACE_H #include <jtag/jtag.h> +#include <jtag/swim.h> #include <target/armv7m_trace.h> /* @file @@ -192,32 +193,34 @@ static inline tap_state_t jtag_debug_state_machine(const void *tms_buf, * debugging interface. */ struct jtag_interface { - /** The name of the JTAG interface driver. */ - const char * const name; - /** * Bit vector listing capabilities exposed by this driver. */ unsigned supported; #define DEBUG_CAP_TMS_SEQ (1 << 0) - /** transports supported in C code (NULL terminated vector) */ - const char * const *transports; - - const struct swd_driver *swd; - /** * Execute queued commands. * @returns ERROR_OK on success, or an error code on failure. */ int (*execute_queue)(void); +}; - /** - * Set the interface speed. - * @param speed The new interface speed setting. - * @returns ERROR_OK on success, or an error code on failure. - */ - int (*speed)(int speed); +/** + * Represents a driver for a debugging interface + * + * @todo We need a per-instance structure too, and changes to pass + * that structure to the driver. Instances can for example be in + * either SWD or JTAG modes. This will help remove globals, and + * eventually to cope with systems which have more than one such + * debugging interface. + */ +struct adapter_driver { + /** The name of the interface driver. */ + const char * const name; + + /** transports supported in C code (NULL terminated vector) */ + const char * const *transports; /** * The interface driver may register additional commands to expose @@ -247,6 +250,29 @@ struct jtag_interface { int (*quit)(void); /** + * Control (assert/deassert) the signals SRST and TRST on the interface. + * This function is synchronous and should be called after the adapter + * queue has been properly flushed. + * This function is optional. + * Adapters that don't support resets can either not define this function + * or return an error code. + * Adapters that don't support one of the two reset should ignore the + * request to assert the missing signal and eventually log an error. + * + * @param srst 1 to assert SRST, 0 to deassert SRST. + * @param trst 1 to assert TRST, 0 to deassert TRST. + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*reset)(int srst, int trst); + + /** + * Set the interface speed. + * @param speed The new interface speed setting. + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*speed)(int speed); + + /** * Returns JTAG maxium speed for KHz. 0 = RTCK. The function returns * a failure if it can't support the KHz/RTCK. * @@ -303,10 +329,14 @@ struct jtag_interface { * @param trace_freq A pointer to the configured trace * frequency; if it points to 0, the adapter driver must write * its maximum supported rate there + * @param traceclkin_freq TRACECLKIN frequency provided to the TPIU in Hz + * @param prescaler Pointer to the SWO prescaler calculated by the + * adapter * @returns ERROR_OK on success, an error code on failure. */ 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); /** * Poll for new trace data @@ -318,14 +348,31 @@ struct jtag_interface { * @returns ERROR_OK on success, an error code on failure. */ int (*poll_trace)(uint8_t *buf, size_t *size); + + /** Low-level JTAG APIs */ + struct jtag_interface *jtag_ops; + + /** Low-level SWD APIs */ + const struct swd_driver *swd_ops; + + /* DAP APIs over JTAG transport */ + const struct dap_ops *dap_jtag_ops; + + /* DAP APIs over SWD transport */ + const struct dap_ops *dap_swd_ops; + + /* SWIM APIs */ + const struct swim_driver *swim_ops; }; extern const char * const jtag_only[]; -void adapter_assert_reset(void); -void adapter_deassert_reset(void); +int adapter_resets(int assert_trst, int assert_srst); +int adapter_assert_reset(void); +int adapter_deassert_reset(void); 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); int adapter_poll_trace(uint8_t *buf, size_t *size); #endif /* OPENOCD_JTAG_INTERFACE_H */ diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 286a73a..7d3f8a8 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -34,106 +34,115 @@ /** @file * This file includes declarations for all built-in jtag interfaces, - * which are then listed in the jtag_interfaces array. + * which are then listed in the adapter_drivers array. * * Dynamic loading can be implemented be searching for shared libraries - * that contain a jtag_interface structure that can added to this list. + * that contain an adapter_driver structure that can added to this list. */ #if BUILD_ZY1000 == 1 -extern struct jtag_interface zy1000_interface; +extern struct adapter_driver zy1000_adapter_driver; #elif defined(BUILD_MINIDRIVER_DUMMY) -extern struct jtag_interface minidummy_interface; +extern struct adapter_driver minidummy_adapter_driver; #else /* standard drivers */ #if BUILD_PARPORT == 1 -extern struct jtag_interface parport_interface; +extern struct adapter_driver parport_adapter_driver; #endif #if BUILD_DUMMY == 1 -extern struct jtag_interface dummy_interface; +extern struct adapter_driver dummy_adapter_driver; #endif #if BUILD_FTDI == 1 -extern struct jtag_interface ftdi_interface; +extern struct adapter_driver ftdi_adapter_driver; #endif #if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1 -extern struct jtag_interface usb_blaster_interface; +extern struct adapter_driver usb_blaster_adapter_driver; #endif #if BUILD_JTAG_VPI == 1 -extern struct jtag_interface jtag_vpi_interface; +extern struct adapter_driver jtag_vpi_adapter_driver; #endif #if BUILD_FT232R == 1 -extern struct jtag_interface ft232r_interface; +extern struct adapter_driver ft232r_adapter_driver; #endif #if BUILD_AMTJTAGACCEL == 1 -extern struct jtag_interface amt_jtagaccel_interface; +extern struct adapter_driver amt_jtagaccel_adapter_driver; #endif #if BUILD_EP93XX == 1 -extern struct jtag_interface ep93xx_interface; +extern struct adapter_driver ep93xx_adapter_driver; #endif #if BUILD_AT91RM9200 == 1 -extern struct jtag_interface at91rm9200_interface; +extern struct adapter_driver at91rm9200_adapter_driver; #endif #if BUILD_GW16012 == 1 -extern struct jtag_interface gw16012_interface; +extern struct adapter_driver gw16012_adapter_driver; #endif #if BUILD_PRESTO -extern struct jtag_interface presto_interface; +extern struct adapter_driver presto_adapter_driver; #endif #if BUILD_USBPROG == 1 -extern struct jtag_interface usbprog_interface; +extern struct adapter_driver usbprog_adapter_driver; #endif #if BUILD_OPENJTAG == 1 -extern struct jtag_interface openjtag_interface; +extern struct adapter_driver openjtag_adapter_driver; #endif #if BUILD_JLINK == 1 -extern struct jtag_interface jlink_interface; +extern struct adapter_driver jlink_adapter_driver; #endif #if BUILD_VSLLINK == 1 -extern struct jtag_interface vsllink_interface; +extern struct adapter_driver vsllink_adapter_driver; #endif #if BUILD_RLINK == 1 -extern struct jtag_interface rlink_interface; +extern struct adapter_driver rlink_adapter_driver; #endif #if BUILD_ULINK == 1 -extern struct jtag_interface ulink_interface; +extern struct adapter_driver ulink_adapter_driver; #endif #if BUILD_ARMJTAGEW == 1 -extern struct jtag_interface armjtagew_interface; +extern struct adapter_driver armjtagew_adapter_driver; #endif #if BUILD_BUSPIRATE == 1 -extern struct jtag_interface buspirate_interface; +extern struct adapter_driver buspirate_adapter_driver; #endif #if BUILD_REMOTE_BITBANG == 1 -extern struct jtag_interface remote_bitbang_interface; +extern struct adapter_driver remote_bitbang_adapter_driver; #endif #if BUILD_HLADAPTER == 1 -extern struct jtag_interface hl_interface; +extern struct adapter_driver hl_adapter_driver; #endif #if BUILD_OSBDM == 1 -extern struct jtag_interface osbdm_interface; +extern struct adapter_driver osbdm_adapter_driver; #endif #if BUILD_OPENDOUS == 1 -extern struct jtag_interface opendous_interface; +extern struct adapter_driver opendous_adapter_driver; #endif #if BUILD_SYSFSGPIO == 1 -extern struct jtag_interface sysfsgpio_interface; +extern struct adapter_driver sysfsgpio_adapter_driver; +#endif +#if BUILD_XLNX_PCIE_XVC == 1 +extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; #endif #if BUILD_AICE == 1 -extern struct jtag_interface aice_interface; +extern struct adapter_driver aice_adapter_driver; #endif #if BUILD_BCM2835GPIO == 1 -extern struct jtag_interface bcm2835gpio_interface; +extern struct adapter_driver bcm2835gpio_adapter_driver; #endif #if BUILD_CMSIS_DAP == 1 -extern struct jtag_interface cmsis_dap_interface; +extern struct adapter_driver cmsis_dap_adapter_driver; #endif #if BUILD_KITPROG == 1 -extern struct jtag_interface kitprog_interface; +extern struct adapter_driver kitprog_adapter_driver; #endif #if BUILD_IMX_GPIO == 1 -extern struct jtag_interface imx_gpio_interface; +extern struct adapter_driver imx_gpio_adapter_driver; #endif #if BUILD_XDS110 == 1 -extern struct jtag_interface xds110_interface; +extern struct adapter_driver xds110_adapter_driver; +#endif +#if BUILD_HLADAPTER == 1 +extern struct adapter_driver stlink_dap_adapter_driver; +#endif +#if BUILD_RSHIM == 1 +extern struct adapter_driver rshim_dap_adapter_driver; #endif #endif /* standard drivers */ @@ -144,107 +153,111 @@ extern struct jtag_interface xds110_interface; * The list should be defined to contain either one minidriver interface * or some number of standard driver interfaces, never both. */ -struct jtag_interface *jtag_interfaces[] = { +struct adapter_driver *adapter_drivers[] = { #if BUILD_ZY1000 == 1 - &zy1000_interface, + &zy1000_adapter_driver, #elif defined(BUILD_MINIDRIVER_DUMMY) - &minidummy_interface, + &minidummy_adapter_driver, #else /* standard drivers */ #if BUILD_PARPORT == 1 - &parport_interface, + &parport_adapter_driver, #endif #if BUILD_DUMMY == 1 - &dummy_interface, + &dummy_adapter_driver, #endif #if BUILD_FTDI == 1 - &ftdi_interface, + &ftdi_adapter_driver, #endif #if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1 - &usb_blaster_interface, + &usb_blaster_adapter_driver, #endif #if BUILD_JTAG_VPI == 1 - &jtag_vpi_interface, + &jtag_vpi_adapter_driver, #endif #if BUILD_FT232R == 1 - &ft232r_interface, + &ft232r_adapter_driver, #endif #if BUILD_AMTJTAGACCEL == 1 - &amt_jtagaccel_interface, + &amt_jtagaccel_adapter_driver, #endif #if BUILD_EP93XX == 1 - &ep93xx_interface, + &ep93xx_adapter_driver, #endif #if BUILD_AT91RM9200 == 1 - &at91rm9200_interface, + &at91rm9200_adapter_driver, #endif #if BUILD_GW16012 == 1 - &gw16012_interface, + &gw16012_adapter_driver, #endif #if BUILD_PRESTO - &presto_interface, + &presto_adapter_driver, #endif #if BUILD_USBPROG == 1 - &usbprog_interface, + &usbprog_adapter_driver, #endif #if BUILD_OPENJTAG == 1 - &openjtag_interface, + &openjtag_adapter_driver, #endif #if BUILD_JLINK == 1 - &jlink_interface, + &jlink_adapter_driver, #endif #if BUILD_VSLLINK == 1 - &vsllink_interface, + &vsllink_adapter_driver, #endif #if BUILD_RLINK == 1 - &rlink_interface, + &rlink_adapter_driver, #endif #if BUILD_ULINK == 1 - &ulink_interface, + &ulink_adapter_driver, #endif #if BUILD_ARMJTAGEW == 1 - &armjtagew_interface, + &armjtagew_adapter_driver, #endif #if BUILD_BUSPIRATE == 1 - &buspirate_interface, + &buspirate_adapter_driver, #endif #if BUILD_REMOTE_BITBANG == 1 - &remote_bitbang_interface, + &remote_bitbang_adapter_driver, #endif #if BUILD_HLADAPTER == 1 - &hl_interface, + &hl_adapter_driver, #endif #if BUILD_OSBDM == 1 - &osbdm_interface, + &osbdm_adapter_driver, #endif #if BUILD_OPENDOUS == 1 - &opendous_interface, + &opendous_adapter_driver, #endif #if BUILD_SYSFSGPIO == 1 - &sysfsgpio_interface, + &sysfsgpio_adapter_driver, +#endif +#if BUILD_XLNX_PCIE_XVC == 1 + &xlnx_pcie_xvc_adapter_driver, #endif #if BUILD_AICE == 1 - &aice_interface, + &aice_adapter_driver, #endif #if BUILD_BCM2835GPIO == 1 - &bcm2835gpio_interface, + &bcm2835gpio_adapter_driver, #endif #if BUILD_CMSIS_DAP == 1 - &cmsis_dap_interface, + &cmsis_dap_adapter_driver, #endif #if BUILD_KITPROG == 1 - &kitprog_interface, + &kitprog_adapter_driver, #endif #if BUILD_IMX_GPIO == 1 - &imx_gpio_interface, + &imx_gpio_adapter_driver, #endif #if BUILD_XDS110 == 1 - &xds110_interface, + &xds110_adapter_driver, +#endif +#if BUILD_HLADAPTER == 1 + &stlink_dap_adapter_driver, +#endif +#if BUILD_RSHIM == 1 + &rshim_dap_adapter_driver, #endif #endif /* standard drivers */ NULL, }; - -void jtag_interface_modules_load(const char *path) -{ - /* @todo: implement dynamic module loading for JTAG interface drivers */ -} diff --git a/src/jtag/interfaces.h b/src/jtag/interfaces.h index 02d201b..ddbd735 100644 --- a/src/jtag/interfaces.h +++ b/src/jtag/interfaces.h @@ -36,9 +36,6 @@ #include <jtag/interface.h> -/** Dynamically load all JTAG interface modules from specified directory. */ -void jtag_interface_modules_load(const char *path); - -extern struct jtag_interface *jtag_interfaces[]; +extern struct adapter_driver *adapter_drivers[]; #endif /* OPENOCD_JTAG_INTERFACES_H */ diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index c93243c..7f033e0 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -77,6 +77,14 @@ typedef enum tap_state { } tap_state_t; /** + * Defines arguments for reset functions + */ +#define SRST_DEASSERT 0 +#define SRST_ASSERT 1 +#define TRST_DEASSERT 0 +#define TRST_ASSERT 1 + +/** * Function tap_state_name * Returns a string suitable for display representing the JTAG tap_state */ @@ -154,8 +162,8 @@ void jtag_tap_free(struct jtag_tap *tap); struct jtag_tap *jtag_all_taps(void); const char *jtag_tap_name(const struct jtag_tap *tap); -struct jtag_tap *jtag_tap_by_string(const char* dotted_name); -struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp* interp, Jim_Obj *obj); +struct jtag_tap *jtag_tap_by_string(const char *dotted_name); +struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *obj); struct jtag_tap *jtag_tap_by_position(unsigned abs_position); struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p); unsigned jtag_tap_count_enabled(void); diff --git a/src/jtag/minidummy/minidummy.c b/src/jtag/minidummy/minidummy.c index 2f26004..7ee2067 100644 --- a/src/jtag/minidummy/minidummy.c +++ b/src/jtag/minidummy/minidummy.c @@ -24,18 +24,24 @@ #include <jtag/minidriver.h> #include <jtag/interface.h> -struct jtag_interface minidummy_interface = { - .name = "minidummy", +static struct jtag_interface minidummy_interface = { .execute_queue = NULL, - .speed = NULL, +}; + +struct adapter_driver minidummy_adapter_driver = { + .name = "minidummy", .transports = jtag_only, .commands = NULL, + .init = NULL, .quit = NULL, + .speed = NULL, .khz = NULL, .speed_div = NULL, .power_dropout = NULL, .srst_asserted = NULL, + + .jtag_ops = &minidummy_interface, }; int interface_jtag_execute_queue(void) @@ -77,7 +83,7 @@ int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, return ERROR_OK; } -int interface_jtag_add_tlr() +int interface_jtag_add_tlr(void) { /* synchronously do the operation here */ @@ -164,7 +170,7 @@ void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *bu int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) { - int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, \ + int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count); return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); } diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index d57cafb..f8c4ca0 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -34,16 +34,16 @@ proc init_reset { mode } { proc power_restore {} { echo "Sensed power restore, running reset init and halting GDB." reset init - + # Halt GDB so user can deal with a detected power restore. # # After GDB is halted, then output is no longer forwarded # to the GDB console. - set targets [target names] + set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb - } + } } add_help_text power_restore "Overridable procedure run when power restore is detected. Runs 'reset init' by default." @@ -65,11 +65,11 @@ proc srst_deasserted {} { # # After GDB is halted, then output is no longer forwarded # to the GDB console. - set targets [target names] + set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb - } + } } add_help_text srst_deasserted "Overridable procedure run when srst deassert is detected. Runs 'reset init' by default." @@ -120,18 +120,34 @@ proc jtag_ntrst_assert_width args { # FIXME phase these aids out after about April 2011 # proc jtag_khz args { - echo "DEPRECATED! use 'adapter_khz' not 'jtag_khz'" - eval adapter_khz $args + echo "DEPRECATED! use 'adapter speed' not 'jtag_khz'" + eval adapter speed $args } proc jtag_nsrst_delay args { - echo "DEPRECATED! use 'adapter_nsrst_delay' not 'jtag_nsrst_delay'" - eval adapter_nsrst_delay $args + echo "DEPRECATED! use 'adapter srst delay' not 'jtag_nsrst_delay'" + eval adapter srst delay $args } proc jtag_nsrst_assert_width args { - echo "DEPRECATED! use 'adapter_nsrst_assert_width' not 'jtag_nsrst_assert_width'" - eval adapter_nsrst_assert_width $args + echo "DEPRECATED! use 'adapter srst pulse_width' not 'jtag_nsrst_assert_width'" + eval adapter srst pulse_width $args +} + +proc jtag_reset args { + echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'" + switch $args { + "0 0" + {eval adapter deassert trst deassert srst} + "0 1" + {eval adapter deassert trst assert srst} + "1 0" + {eval adapter assert trst deassert srst} + "1 1" + {eval adapter assert trst assert srst} + default + {return -code 1 -level 1 "jtag_reset: syntax error"} + } } # stlink migration helpers @@ -160,4 +176,54 @@ proc stlink args { eval hla $args } +proc adapter_khz args { + echo "DEPRECATED! use 'adapter speed' not 'adapter_khz'" + eval adapter speed $args +} + +proc adapter_name args { + echo "DEPRECATED! use 'adapter name' not 'adapter_name'" + eval adapter name $args +} + +proc adapter_nsrst_delay args { + echo "DEPRECATED! use 'adapter srst delay' not 'adapter_nsrst_delay'" + eval adapter srst delay $args +} + +proc adapter_nsrst_assert_width args { + echo "DEPRECATED! use 'adapter srst pulse_width' not 'adapter_nsrst_assert_width'" + eval adapter srst pulse_width $args +} + +proc interface args { + echo "DEPRECATED! use 'adapter driver' not 'interface'" + eval adapter driver $args +} + +proc interface_transports args { + echo "DEPRECATED! use 'adapter transports' not 'interface_transports'" + eval adapter transports $args +} + +proc interface_list args { + echo "DEPRECATED! use 'adapter list' not 'interface_list'" + eval adapter list $args +} + +proc ftdi_location args { + echo "DEPRECATED! use 'adapter usb location' not 'ftdi_location'" + eval adapter usb location $args +} + +proc xds110_serial args { + echo "DEPRECATED! use 'xds110 serial' not 'xds110_serial'" + eval xds110 serial $args +} + +proc xds110_supply_voltage args { + echo "DEPRECATED! use 'xds110 supply' not 'xds110_supply_voltage'" + eval xds110 supply $args +} + # END MIGRATION AIDS diff --git a/src/jtag/swd.h b/src/jtag/swd.h index 0b32105..487cb85 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -213,14 +213,6 @@ static const uint8_t swd_seq_dormant_to_jtag[] = { }; static const unsigned swd_seq_dormant_to_jtag_len = 160; -enum swd_special_seq { - LINE_RESET, - JTAG_TO_SWD, - SWD_TO_JTAG, - SWD_TO_DORMANT, - DORMANT_TO_SWD, -}; - struct swd_driver { /** * Initialize the debug link so it can perform SWD operations. @@ -285,6 +277,5 @@ struct swd_driver { }; int swd_init_reset(struct command_context *cmd_ctx); -void swd_add_reset(int req_srst); #endif /* OPENOCD_JTAG_SWD_H */ diff --git a/src/jtag/swim.c b/src/jtag/swim.c new file mode 100644 index 0000000..936268b --- /dev/null +++ b/src/jtag/swim.c @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com + * + * SWIM (Single Wire Interface Module) is a low-pin-count debug protocol + * used by STMicroelectronics MCU family STM8 and documented in UM470 + * https://www.st.com/resource/en/user_manual/cd00173911.pdf + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "interface.h" +#include "swim.h" +#include <helper/command.h> +#include <transport/transport.h> + +extern struct adapter_driver *adapter_driver; + +int swim_system_reset(void) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->srst(); +} + +int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count, + uint8_t *buffer) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->read_mem(addr, size, count, buffer); +} + +int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count, + const uint8_t *buffer) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->write_mem(addr, size, count, buffer); +} + +int swim_reconnect(void) +{ + assert(adapter_driver->swim_ops); + + return adapter_driver->swim_ops->reconnect(); +} + +COMMAND_HANDLER(handle_swim_newtap_command) +{ + struct jtag_tap *tap; + + /* + * only need "basename" and "tap_type", but for backward compatibility + * ignore extra parameters + */ + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap = calloc(1, sizeof(*tap)); + if (!tap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + tap->chip = strdup(CMD_ARGV[0]); + tap->tapname = strdup(CMD_ARGV[1]); + tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]); + if (!tap->chip || !tap->tapname || !tap->dotted_name) { + LOG_ERROR("Out of memory"); + free(tap->dotted_name); + free(tap->tapname); + free(tap->chip); + free(tap); + return ERROR_FAIL; + } + + LOG_DEBUG("Creating new SWIM \"tap\", Chip: %s, Tap: %s, Dotted: %s", + tap->chip, tap->tapname, tap->dotted_name); + + /* default is enabled-after-reset */ + tap->enabled = true; + + jtag_tap_init(tap); + return ERROR_OK; +} + +static const struct command_registration swim_transport_subcommand_handlers[] = { + { + .name = "newtap", + .handler = handle_swim_newtap_command, + .mode = COMMAND_CONFIG, + .help = "Create a new TAP instance named basename.tap_type, " + "and appends it to the scan chain.", + .usage = "basename tap_type", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration swim_transport_command_handlers[] = { + { + .name = "swim", + .mode = COMMAND_ANY, + .help = "perform swim adapter actions", + .usage = "", + .chain = swim_transport_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +static int swim_transport_select(struct command_context *cmd_ctx) +{ + LOG_DEBUG(__func__); + + return register_commands(cmd_ctx, NULL, swim_transport_command_handlers); +} + +static int swim_transport_init(struct command_context *cmd_ctx) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + LOG_DEBUG(__func__); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + adapter_assert_reset(); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } else + adapter_deassert_reset(); + + return ERROR_OK; +} + +static struct transport swim_transport = { + .name = "swim", + .select = swim_transport_select, + .init = swim_transport_init, +}; + +static void swim_constructor(void) __attribute__ ((constructor)); +static void swim_constructor(void) +{ + transport_register(&swim_transport); +} + +bool transport_is_swim(void) +{ + return get_current_transport() == &swim_transport; +} diff --git a/src/jtag/swim.h b/src/jtag/swim.h new file mode 100644 index 0000000..186e0cc --- /dev/null +++ b/src/jtag/swim.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com + */ + +/** + * @file + * This file implements support for STMicroelectronics debug protocol SWIM + * (Single Wire Interface Module). + */ + +#ifndef OPENOCD_JTAG_SWIM_H +#define OPENOCD_JTAG_SWIM_H + +#define SWIM_FREQ_LOW 363 +#define SWIM_FREQ_HIGH 800 + +struct swim_driver { + /** + * Send SRST (system reset) command to target. + * + * @return ERROR_OK on success, else a fault code. + */ + int (*srst)(void); + + /** + * Read target memory through ROTF (read on-the-fly) command. + * + * @param addr Start address to read data from target memory. + * @param size Size in bytes of data units, 1, 2 or 4. + * @param count Number of units (size units, not bytes) to read. + * @param buffer Data buffer to receive data. + * @return ERROR_OK on success, else a fault code. + */ + int (*read_mem)(uint32_t addr, uint32_t size, uint32_t count, + uint8_t *buffer); + + /** + * Write target memory through WOTF (write on-the-fly) command. + * + * @param addr Start address to write data to target memory. + * @param size Size in bytes of data units, 1, 2 or 4. + * @param count Number of units (size units, not bytes) to write. + * @param buffer Data buffer to write. + * @return ERROR_OK on success, else a fault code. + */ + int (*write_mem)(uint32_t addr, uint32_t size, uint32_t count, + const uint8_t *buffer); + + /** + * Reconnect to the target. + * Should be reworked to be more generic and not linked to current + * implementation in stlink driver. + * + * @return ERROR_OK on success, else a fault code. + */ + int (*reconnect)(void); +}; + +int swim_system_reset(void); +int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count, + uint8_t *buffer); +int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count, + const uint8_t *buffer); +int swim_reconnect(void); + +#endif /* OPENOCD_JTAG_SWIM_H */ diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index cbdf2ad..d2f1f0d 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -108,7 +108,7 @@ static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args endstate = TAP_IDLE; - script_debug(interp, "drscan", argc, args); + script_debug(interp, argc, args); /* validate arguments as numbers */ e = JIM_OK; @@ -229,7 +229,7 @@ static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_ERR; } - script_debug(interp, "pathmove", argc, args); + script_debug(interp, argc, args); int i; for (i = 0; i < argc-1; i++) { @@ -261,7 +261,7 @@ static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *ar static int Jim_Command_flush_count(Jim_Interp *interp, int argc, Jim_Obj *const *args) { - script_debug(interp, "flush_count", argc, args); + script_debug(interp, argc, args); Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count())); @@ -965,7 +965,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)); @@ -987,7 +987,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] = '*'; @@ -1059,34 +1059,6 @@ COMMAND_HANDLER(handle_jtag_rclk_command) return retval; } -COMMAND_HANDLER(handle_jtag_reset_command) -{ - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - int trst = -1; - if (CMD_ARGV[0][0] == '1') - trst = 1; - else if (CMD_ARGV[0][0] == '0') - trst = 0; - else - return ERROR_COMMAND_SYNTAX_ERROR; - - int srst = -1; - if (CMD_ARGV[1][0] == '1') - srst = 1; - else if (CMD_ARGV[1][0] == '0') - srst = 0; - else - return ERROR_COMMAND_SYNTAX_ERROR; - - if (adapter_init(CMD_CTX) != ERROR_OK) - return ERROR_JTAG_INIT_FAILED; - - jtag_add_reset(trst, srst); - return jtag_execute_queue(); -} - COMMAND_HANDLER(handle_runtest_command) { if (CMD_ARGC != 1) @@ -1157,14 +1129,19 @@ COMMAND_HANDLER(handle_irscan_command) return ERROR_FAIL; } - int field_size = tap->ir_length; - fields[i].num_bits = field_size; - uint8_t *v = malloc(DIV_ROUND_UP(field_size, 8)); - uint64_t value; retval = parse_u64(CMD_ARGV[i * 2 + 1], &value); if (ERROR_OK != retval) goto error_return; + + int field_size = tap->ir_length; + fields[i].num_bits = field_size; + uint8_t *v = calloc(1, DIV_ROUND_UP(field_size, 8)); + if (!v) { + LOG_ERROR("Out of memory"); + goto error_return; + } + buf_set_u64(v, 0, field_size, value); fields[i].out_value = v; fields[i].in_value = NULL; @@ -1332,14 +1309,6 @@ static const struct command_registration jtag_command_handlers[] = { .usage = "" }, { - .name = "jtag_reset", - .handler = handle_jtag_reset_command, - .mode = COMMAND_EXEC, - .help = "Set reset line values. Value '1' is active, " - "value '0' is inactive.", - .usage = "trst_active srst_active", - }, - { .name = "runtest", .handler = handle_runtest_command, .mode = COMMAND_EXEC, @@ -1350,7 +1319,7 @@ static const struct command_registration jtag_command_handlers[] = { .name = "irscan", .handler = handle_irscan_command, .mode = COMMAND_EXEC, - .help = "Execute Instruction Register (DR) scan. The " + .help = "Execute Instruction Register (IR) scan. The " "specified opcodes are put into each TAP's IR, " "and other TAPs are put in BYPASS.", .usage = "[tap_name instruction]* ['-endstate' state_name]", diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c index 1734983..37af2f7 100644 --- a/src/jtag/zy1000/zy1000.c +++ b/src/jtag/zy1000/zy1000.c @@ -486,7 +486,7 @@ int interface_jtag_add_plain_dr_scan(int num_bits, return ERROR_OK; } -int interface_jtag_add_tlr() +int interface_jtag_add_tlr(void) { setCurrentState(TAP_RESET); return ERROR_OK; @@ -1237,17 +1237,23 @@ int zy1000_init(void) return ERROR_OK; } -struct jtag_interface zy1000_interface = { - .name = "ZY1000", +static struct jtag_interface zy1000_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = NULL, - .speed = zy1000_speed, +}; + +struct adapter_driver zy1000_adapter_driver = { + .name = "ZY1000", .transports = jtag_only, .commands = zy1000_commands, + .init = zy1000_init, .quit = zy1000_quit, + .speed = zy1000_speed, .khz = zy1000_khz, .speed_div = zy1000_speed_div, .power_dropout = zy1000_power_dropout, .srst_asserted = zy1000_srst_asserted, + + .jtag_ops = &zy1000_interface, }; |