X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fxds110.c;h=d6e663997efd7da537fb7888b1364377954fca12;hb=a527112dae0e8b3a31589c27d01a97174f24e1df;hp=20b817879d858d6f3e9cfdb8187a723c3f660038;hpb=615a066629656aaa375c50885ef2f1530d1a5465;p=fw%2Fopenocd diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index 20b817879..d6e663997 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2017 by Texas Instruments, Inc. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -20,15 +9,13 @@ #endif #include +#include #include #include #include #include #include -/* XDS110 USB serial number length */ -#define XDS110_SERIAL_LEN 8 - /* XDS110 stand-alone probe voltage supply limits */ #define XDS110_MIN_VOLTAGE 1800 #define XDS110_MAX_VOLTAGE 3600 @@ -41,6 +28,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 * ***************************************************************************/ @@ -60,15 +53,6 @@ #endif #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 +75,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 @@ -180,7 +173,7 @@ #define CMD_STABLECLOCKS 4 /* Array to convert from OpenOCD tap_state_t to XDS JTAG state */ -const uint32_t xds_jtag_state[] = { +static const uint32_t xds_jtag_state[] = { XDS_JTAG_STATE_EXIT2_DR, /* TAP_DREXIT2 = 0x0 */ XDS_JTAG_STATE_EXIT1_DR, /* TAP_DREXIT1 = 0x1 */ XDS_JTAG_STATE_SHIFT_DR, /* TAP_DRSHIFT = 0x2 */ @@ -207,11 +200,18 @@ struct scan_result { struct xds110_info { /* USB connection handles and data buffers */ - libusb_context *ctx; - libusb_device_handle *dev; + struct libusb_context *ctx; + struct libusb_device_handle *dev; 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; @@ -225,8 +225,6 @@ struct xds110_info { /* TCK speed and delay count*/ uint32_t speed; uint32_t delay_count; - /* XDS110 serial number */ - char serial[XDS110_SERIAL_LEN + 1]; /* XDS110 voltage supply setting */ uint32_t voltage; /* XDS110 firmware and hardware version */ @@ -244,14 +242,18 @@ 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, .firmware = 0, .hardware = 0, @@ -299,23 +301,31 @@ static inline uint16_t xds110_get_u16(uint8_t *buffer) static bool usb_connect(void) { - libusb_context *ctx = NULL; - libusb_device **list = NULL; - libusb_device_handle *dev = NULL; + struct libusb_context *ctx = NULL; + struct libusb_device **list = NULL; + struct libusb_device_handle *dev = NULL; 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); - if (0 == result) { + if (result == 0) { /* Get list of USB devices attached to system */ count = libusb_get_device_list(ctx, &list); if (count <= 0) { @@ -324,29 +334,37 @@ static bool usb_connect(void) } } - if (0 == result) { + if (result == 0) { /* 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 < ARRAY_SIZE(vids); 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]; + if (result == 0) { + const int max_data = 256; + unsigned char data[max_data + 1]; *data = '\0'; /* May be the requested device if serial number matches */ - if (0 == xds110.serial[0]) { + if (!adapter_get_required_serial()) { /* No serial number given; match first XDS110 found */ found = true; break; } else { /* Get the device's serial number string */ result = libusb_get_string_descriptor_ascii(dev, - desc.iSerialNumber, data, MAX_DATA); - if (0 < result && - 0 == strcmp((char *)data, (char *)xds110.serial)) { + desc.iSerialNumber, data, max_data); + if (result > 0 && + strcmp((char *)data, adapter_get_required_serial()) == 0) { found = true; break; } @@ -366,12 +384,21 @@ static bool usb_connect(void) * 2) didn't find the XDS110, and no devices are currently open */ - if (NULL != list) { + if (list) { /* Free the device list, we're done with it */ libusb_free_device_list(list, 1); } 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,43 +407,43 @@ 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; } /* On an error, clean up what we can */ - if (0 != result) { - if (NULL != dev) { + if (result != 0) { + if (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) + if (ctx) libusb_exit(ctx); xds110.ctx = NULL; xds110.dev = NULL; } /* Log the results */ - if (0 == result) + if (result == 0) LOG_INFO("XDS110: connected"); else LOG_ERROR("XDS110: failed to connect"); - return (0 == result) ? true : false; + return (result == 0) ? true : false; } static void usb_disconnect(void) { - if (NULL != xds110.dev) { + if (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; } - if (NULL != xds110.ctx) { + if (xds110.ctx) { libusb_exit(xds110.ctx); xds110.ctx = NULL; } @@ -429,17 +456,17 @@ static bool usb_read(unsigned char *buffer, int size, int *bytes_read, { int result; - if (NULL == xds110.dev || NULL == buffer || NULL == bytes_read) + if (!xds110.dev || !buffer || !bytes_read) return false; /* Force a non-zero timeout to prevent blocking */ - if (0 == timeout) + if (timeout == 0) 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; + return (result == 0) ? true : false; } static bool usb_write(unsigned char *buffer, int size, int *written) @@ -448,24 +475,24 @@ static bool usb_write(unsigned char *buffer, int size, int *written) int result = LIBUSB_SUCCESS; int retries = 0; - if (NULL == xds110.dev || NULL == buffer) + if (!xds110.dev || !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) { + while (result == LIBUSB_ERROR_PIPE && 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++; } - if (NULL != written) + if (written) *written = bytes_written; - return (0 == result && size == bytes_written) ? true : false; + return (result == 0 && size == bytes_written) ? true : false; } static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) @@ -507,7 +534,7 @@ static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) /* Abort now if we didn't receive a valid response */ if (!success) { - if (NULL != total_bytes_read) + if (total_bytes_read) *total_bytes_read = 0; return false; } @@ -544,7 +571,7 @@ static bool usb_get_response(uint32_t *total_bytes_read, uint32_t timeout) if (!success) count = 0; - if (NULL != total_bytes_read) + if (total_bytes_read) *total_bytes_read = count; return success; @@ -593,7 +620,7 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length, int error = 0; uint32_t bytes_read = 0; - if (NULL == xds110.dev) + if (!xds110.dev) return false; while (!done && attempts > 0) { @@ -612,13 +639,13 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length, if (bytes_read != in_length) { /* Unexpected amount of data returned */ success = false; - LOG_DEBUG("XDS110: command 0x%02x return %d bytes, expected %d", + LOG_DEBUG("XDS110: command 0x%02x return %" PRIu32 " bytes, expected %" PRIu32, xds110.write_payload[0], bytes_read, in_length); } else { /* Extract error code from return packet */ error = (int)xds110_get_u32(&xds110.read_payload[0]); done = true; - if (SC_ERR_NONE != error) + if (error != SC_ERR_NONE) LOG_DEBUG("XDS110: command 0x%02x returned error %d", xds110.write_payload[0], error); } @@ -628,7 +655,7 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length, if (!success) error = SC_ERR_XDS110_FAIL; - if (0 != error) + if (error != 0) success = false; return success; @@ -671,9 +698,9 @@ static bool xds_version(uint32_t *firmware_id, uint16_t *hardware_id) DEFAULT_TIMEOUT); if (success) { - if (NULL != firmware_id) + if (firmware_id) *firmware_id = xds110_get_u32(fw_id_pntr); - if (NULL != hardware_id) + if (hardware_id) *hardware_id = xds110_get_u16(hw_id_pntr); } @@ -820,7 +847,7 @@ static bool cmapi_connect(uint32_t *idcode) DEFAULT_TIMEOUT); if (success) { - if (NULL != idcode) + if (idcode) *idcode = xds110_get_u32(idcode_pntr); } @@ -883,7 +910,7 @@ static bool cmapi_read_dap_reg(uint32_t type, uint32_t ap_num, DEFAULT_TIMEOUT); if (success) { - if (NULL != value) + if (value) *value = xds110_get_u32(value_pntr); } @@ -900,7 +927,7 @@ static bool cmapi_write_dap_reg(uint32_t type, uint32_t ap_num, bool success; - if (NULL == value) + if (!value) return false; xds110.write_payload[0] = CMAPI_REG_WRITE; @@ -978,7 +1005,7 @@ static bool xds_set_supply(uint32_t voltage) xds110.write_payload[0] = XDS_SET_SUPPLY; xds110_set_u32(volts_pntr, voltage); - *source_pntr = (uint8_t)(0 != voltage ? 1 : 0); + *source_pntr = (uint8_t)(voltage != 0 ? 1 : 0); success = xds_execute(XDS_OUT_LEN + 5, XDS_IN_LEN, DEFAULT_ATTEMPTS, DEFAULT_TIMEOUT); @@ -994,7 +1021,7 @@ static bool ocd_dap_request(uint8_t *dap_requests, uint32_t request_size, bool success; - if (NULL == dap_requests || NULL == dap_results) + if (!dap_requests || !dap_results) return false; xds110.write_payload[0] = OCD_DAP_REQUEST; @@ -1019,7 +1046,7 @@ static bool ocd_scan_request(uint8_t *scan_requests, uint32_t request_size, bool success; - if (NULL == scan_requests || NULL == scan_results) + if (!scan_requests || !scan_results) return false; xds110.write_payload[0] = OCD_SCAN_REQUEST; @@ -1043,7 +1070,7 @@ static bool ocd_pathmove(uint32_t num_states, uint8_t *path) bool success; - if (NULL == path) + if (!path) return false; xds110.write_payload[0] = OCD_PATHMOVE; @@ -1086,7 +1113,7 @@ static int xds110_swd_switch_seq(enum swd_special_seq seq) xds110.is_cmapi_acquired = false; /* Run sequence to put target in SWD mode */ success = swd_connect(); - /* Re-iniitialize CMAPI API for DAP access */ + /* Re-initialize CMAPI API for DAP access */ if (success) { xds110.is_swd_mode = true; success = cmapi_connect(&idcode); @@ -1122,9 +1149,9 @@ static int xds110_swd_switch_seq(enum swd_special_seq seq) static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) { /* Make sure this is a read request */ - bool is_read_request = (0 != (SWD_CMD_RnW & cmd)); + bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ - uint32_t type = (0 != (SWD_CMD_APnDP & cmd)) ? DAP_AP : DAP_DP; + uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Determine the AP number from cached SELECT value */ uint32_t ap_num = (xds110.select & 0xff000000) >> 24; /* Extract register address from command */ @@ -1140,7 +1167,7 @@ static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) if (!is_read_request) return false; - if (DAP_AP == type) { + if (type == DAP_AP) { /* Add bank address to register address for CMAPI call */ address |= bank; } @@ -1166,7 +1193,7 @@ static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) /* Handle result of read attempt */ if (!success) LOG_ERROR("XDS110: failed to read DAP register"); - else if (NULL != value) + else if (value) *value = reg_value; if (success && DAP_AP == type) { @@ -1184,9 +1211,9 @@ static bool xds110_legacy_read_reg(uint8_t cmd, uint32_t *value) static bool xds110_legacy_write_reg(uint8_t cmd, uint32_t value) { /* Make sure this isn't a read request */ - bool is_read_request = (0 != (SWD_CMD_RnW & cmd)); + bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ - uint32_t type = (0 != (SWD_CMD_APnDP & cmd)) ? DAP_AP : DAP_DP; + uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Determine the AP number from cached SELECT value */ uint32_t ap_num = (xds110.select & 0xff000000) >> 24; /* Extract register address from command */ @@ -1202,12 +1229,12 @@ static bool xds110_legacy_write_reg(uint8_t cmd, uint32_t value) /* Invalidate the RDBUFF cache */ xds110.use_rdbuff = false; - if (DAP_AP == type) { + if (type == DAP_AP) { /* Add bank address to register address for CMAPI call */ address |= bank; /* Any write to an AP register invalidates the firmware's cache */ xds110.is_ap_dirty = true; - } else if (DAP_DP_SELECT == address) { + } else if (address == DAP_DP_SELECT) { /* Any write to the SELECT register invalidates the firmware's cache */ xds110.is_ap_dirty = true; } @@ -1221,7 +1248,7 @@ static bool xds110_legacy_write_reg(uint8_t cmd, uint32_t value) * If the debugger wrote to SELECT, cache the value * to use to build the apNum and address values above */ - if ((DAP_DP == type) && (DAP_DP_SELECT == address)) + if ((type == DAP_DP) && (address == DAP_DP_SELECT)) xds110.select = value; } @@ -1237,7 +1264,7 @@ static int xds110_swd_run_queue(void) uint32_t value; bool success = true; - if (0 == xds110.txn_request_size) + if (xds110.txn_request_size == 0) return ERROR_OK; /* Terminate request queue */ @@ -1253,7 +1280,7 @@ static int xds110_swd_run_queue(void) result = 0; while (xds110.txn_requests[request] != 0) { cmd = xds110.txn_requests[request++]; - if (0 == (SWD_CMD_RnW & cmd)) { + if (0 == (SWD_CMD_RNW & cmd)) { /* DAP register write command */ value = (uint32_t)(xds110.txn_requests[request++]) << 0; value |= (uint32_t)(xds110.txn_requests[request++]) << 8; @@ -1273,7 +1300,7 @@ static int xds110_swd_run_queue(void) /* Transfer results into caller's buffers */ for (result = 0; result < xds110.txn_result_count; result++) - if (0 != xds110.txn_dap_results[result]) + if (xds110.txn_dap_results[result] != 0) *xds110.txn_dap_results[result] = dap_results[result]; xds110.txn_request_size = 0; @@ -1286,9 +1313,9 @@ static int xds110_swd_run_queue(void) static void xds110_swd_queue_cmd(uint8_t cmd, uint32_t *value) { /* Check if this is a read or write request */ - bool is_read_request = (0 != (SWD_CMD_RnW & cmd)); + bool is_read_request = (0 != (SWD_CMD_RNW & cmd)); /* Determine whether this is a DP or AP register access */ - uint32_t type = (0 != (SWD_CMD_APnDP & cmd)) ? DAP_AP : DAP_DP; + uint32_t type = (0 != (SWD_CMD_APNDP & cmd)) ? DAP_AP : DAP_DP; /* Extract register address from command */ uint32_t address = ((cmd & SWD_CMD_A32) >> 1); uint32_t request_size = (is_read_request) ? 1 : 5; @@ -1345,20 +1372,21 @@ static void xds110_show_info(void) { uint32_t firmware = xds110.firmware; - LOG_INFO("XDS110: firmware version = %d.%d.%d.%d", + LOG_INFO("XDS110: vid/pid = %04x/%04x", xds110.vid, xds110.pid); + LOG_INFO("XDS110: firmware version = %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32, (((firmware >> 28) & 0xf) * 10) + ((firmware >> 24) & 0xf), (((firmware >> 20) & 0xf) * 10) + ((firmware >> 16) & 0xf), (((firmware >> 12) & 0xf) * 10) + ((firmware >> 8) & 0xf), (((firmware >> 4) & 0xf) * 10) + ((firmware >> 0) & 0xf)); LOG_INFO("XDS110: hardware version = 0x%04x", xds110.hardware); - if (0 != xds110.serial[0]) - LOG_INFO("XDS110: serial number = %s", xds110.serial); + if (adapter_get_required_serial()) + LOG_INFO("XDS110: serial number = %s", adapter_get_required_serial()); if (xds110.is_swd_mode) { LOG_INFO("XDS110: connected to target via SWD"); - LOG_INFO("XDS110: SWCLK set to %d kHz", xds110.speed); + LOG_INFO("XDS110: SWCLK set to %" PRIu32 " kHz", xds110.speed); } else { LOG_INFO("XDS110: connected to target via JTAG"); - LOG_INFO("XDS110: TCK set to %d kHz", xds110.speed); + LOG_INFO("XDS110: TCK set to %" PRIu32 " kHz", xds110.speed); } /* Alert user that there's a better firmware to use */ @@ -1426,12 +1454,12 @@ static int xds110_init(void) if (success) { /* Set supply voltage for stand-alone probes */ - if (XDS110_STAND_ALONE_ID == xds110.hardware) { + if (xds110.hardware == XDS110_STAND_ALONE_ID) { success = xds_set_supply(xds110.voltage); /* Allow time for target device to power up */ /* (CC32xx takes up to 1300 ms before debug is enabled) */ alive_sleep(1500); - } else if (0 != xds110.voltage) { + } else if (xds110.voltage != 0) { /* Voltage supply not a feature of embedded probes */ LOG_WARNING( "XDS110: ignoring supply voltage, not supported on this probe"); @@ -1513,7 +1541,7 @@ static void xds110_flush(void) uint8_t data_in[MAX_DATA_BLOCK]; uint8_t *data_pntr; - if (0 == xds110.txn_request_size) + if (xds110.txn_request_size == 0) return; /* Terminate request queue */ @@ -1592,48 +1620,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 +1707,6 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) } free((void *)path); - - return; } static void xds110_queue_scan(struct jtag_command *cmd) @@ -1704,7 +1740,7 @@ static void xds110_queue_scan(struct jtag_command *cmd) /* Check if this single request is too large to fit */ if ((1 + total_bytes + sizeof(end_state) + 1) > MAX_DATA_BLOCK) { - LOG_ERROR("BUG: JTAG scan request is too large to handle (%d bits)", + LOG_ERROR("BUG: JTAG scan request is too large to handle (%" PRIu32 " bits)", total_bits); /* Failing to run this scan mucks up debug on this target */ exit(-1); @@ -1742,8 +1778,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 +1797,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 +1813,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); @@ -1825,7 +1851,7 @@ static int xds110_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; - while (cmd != NULL) { + while (cmd) { xds110_execute_command(cmd); cmd = cmd->next; } @@ -1837,6 +1863,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 +1872,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; - while (current_value < freq_to_pulse_width_in_ns) { - current_value += XDS110_TCK_PULSE_INCREMENT; - ++delay_count; + /* 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); + + /* 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; } } @@ -1925,56 +2002,18 @@ static int xds110_khz(int khz, int *jtag_speed) return ERROR_OK; } -static int_least32_t xds110_swd_frequency(int_least32_t hz) -{ - if (hz > 0) - xds110_speed(hz / 1000); - return hz; -} - COMMAND_HANDLER(xds110_handle_info_command) { xds110_show_info(); return ERROR_OK; } -COMMAND_HANDLER(xds110_handle_serial_command) -{ - wchar_t serial[XDS110_SERIAL_LEN + 1]; - - xds110.serial[0] = 0; - - if (CMD_ARGC == 1) { - size_t len = mbstowcs(0, CMD_ARGV[0], 0); - if (len > XDS110_SERIAL_LEN) { - LOG_ERROR("XDS110: serial number is limited to %d characters", - XDS110_SERIAL_LEN); - return ERROR_FAIL; - } - if ((size_t)-1 == mbstowcs(serial, CMD_ARGV[0], len + 1)) { - LOG_ERROR("XDS110: unable to convert serial number"); - return ERROR_FAIL; - } - - for (uint32_t i = 0; i < len; i++) - xds110.serial[i] = (char)serial[i]; - - xds110.serial[len] = 0; - } else { - LOG_ERROR("XDS110: expected exactly one argument to xds110_serial " - ""); - return ERROR_FAIL; - } - - return ERROR_OK; -} - COMMAND_HANDLER(xds110_handle_supply_voltage_command) { uint32_t voltage = 0; if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], voltage); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], voltage); if (voltage == 0 || (voltage >= XDS110_MIN_VOLTAGE && voltage <= XDS110_MAX_VOLTAGE)) { /* Requested voltage is in range */ @@ -1985,11 +2024,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 " - ""); - return ERROR_FAIL; - } + } else + return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } @@ -1999,8 +2035,15 @@ static const struct command_registration xds110_subcommand_handlers[] = { .name = "info", .handler = &xds110_handle_info_command, .mode = COMMAND_EXEC, - .usage = "", .help = "show XDS110 info", + .usage = "", + }, + { + .name = "supply", + .handler = &xds110_handle_supply_voltage_command, + .mode = COMMAND_CONFIG, + .help = "set the XDS110 probe supply voltage", + .usage = "voltage_in_millivolts", }, COMMAND_REGISTRATION_DONE }; @@ -2010,29 +2053,14 @@ static const struct command_registration xds110_command_handlers[] = { .name = "xds110", .mode = COMMAND_ANY, .help = "perform XDS110 management", - .usage = "", + .usage = "", .chain = xds110_subcommand_handlers, }, - { - .name = "xds110_serial", - .handler = &xds110_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the XDS110 probe serial number", - .usage = "serial_string", - }, - { - .name = "xds110_supply_voltage", - .handler = &xds110_handle_supply_voltage_command, - .mode = COMMAND_CONFIG, - .help = "set the XDS110 probe supply voltage", - .usage = "supply_voltage (millivolts)", - }, COMMAND_REGISTRATION_DONE }; static const struct swd_driver xds110_swd_driver = { .init = xds110_swd_init, - .frequency = xds110_swd_frequency, .switch_seq = xds110_swd_switch_seq, .read_reg = xds110_swd_read_reg, .write_reg = xds110_swd_write_reg, @@ -2041,16 +2069,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, };