+// 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 <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#endif
#include <transport/transport.h>
+#include <jtag/adapter.h>
#include <jtag/swd.h>
#include <jtag/interface.h>
#include <jtag/commands.h>
#include <jtag/tcl.h>
#include <libusb.h>
-/* 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
+
+/* XDS110 stand-alone probe hardware ID */
+#define XDS110_STAND_ALONE_ID 0x21
/* Firmware version that introduced OpenOCD support via block accesses */
#define OCD_FIRMWARE_VERSION 0x02030011
#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 *
***************************************************************************/
#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 *
***************************************************************************/
/* 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
#define SWD_DISCONNECT 0x18 /* Switch from SWD to JTAG connection */
#define CJTAG_CONNECT 0x2b /* Switch from JTAG to cJTAG connection */
#define CJTAG_DISCONNECT 0x2c /* Switch from cJTAG to JTAG connection */
+#define XDS_SET_SUPPLY 0x32 /* Set up stand-alone probe upply voltage */
#define OCD_DAP_REQUEST 0x3a /* Handle block of DAP requests */
#define OCD_SCAN_REQUEST 0x3b /* Handle block of JTAG scan requests */
#define OCD_PATHMOVE 0x3c /* Handle PATHMOVE to navigate JTAG states */
#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 */
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;
/* 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 */
uint32_t firmware;
uint16_t hardware;
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,
.txn_request_size = 0,
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) {
}
}
- 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;
}
* 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;
- /* Set libusb to auto detach kernel and disable debug messages */
+ /* Set libusb to auto detach kernel */
(void)libusb_set_auto_detach_kernel_driver(dev, 1);
-#if LIBUSB_API_VERSION >= 0x01000106
- libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE);
-#else
- libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_NONE);
-#endif
+
/* 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;
}
{
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)
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)
/* 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;
}
if (!success)
count = 0;
- if (NULL != total_bytes_read)
+ if (total_bytes_read)
*total_bytes_read = count;
return success;
int error = 0;
uint32_t bytes_read = 0;
- if (NULL == xds110.dev)
+ if (!xds110.dev)
return false;
while (!done && attempts > 0) {
if (bytes_read != in_length) {
/* Unexpected amount of data returned */
success = false;
+ 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 (error != SC_ERR_NONE)
+ LOG_DEBUG("XDS110: command 0x%02x returned error %d",
+ xds110.write_payload[0], error);
}
}
}
if (!success)
error = SC_ERR_XDS110_FAIL;
- if (0 != error)
+ if (error != 0)
success = false;
return success;
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);
}
DEFAULT_TIMEOUT);
if (success) {
- if (NULL != idcode)
+ if (idcode)
*idcode = xds110_get_u32(idcode_pntr);
}
DEFAULT_TIMEOUT);
if (success) {
- if (NULL != value)
+ if (value)
*value = xds110_get_u32(value_pntr);
}
bool success;
- if (NULL == value)
+ if (!value)
return false;
xds110.write_payload[0] = CMAPI_REG_WRITE;
return success;
}
+static bool xds_set_supply(uint32_t voltage)
+{
+ uint8_t *volts_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */
+ uint8_t *source_pntr = &xds110.write_payload[XDS_OUT_LEN + 4]; /* 8-bits */
+
+ bool success;
+
+ xds110.write_payload[0] = XDS_SET_SUPPLY;
+
+ xds110_set_u32(volts_pntr, voltage);
+ *source_pntr = (uint8_t)(voltage != 0 ? 1 : 0);
+
+ success = xds_execute(XDS_OUT_LEN + 5, XDS_IN_LEN, DEFAULT_ATTEMPTS,
+ DEFAULT_TIMEOUT);
+
+ return success;
+}
+
static bool ocd_dap_request(uint8_t *dap_requests, uint32_t request_size,
uint32_t *dap_results, uint32_t result_count)
{
bool success;
- if (NULL == dap_requests || NULL == dap_results)
+ if (!dap_requests || !dap_results)
return false;
xds110.write_payload[0] = OCD_DAP_REQUEST;
bool success;
- if (NULL == scan_requests || NULL == scan_results)
+ if (!scan_requests || !scan_results)
return false;
xds110.write_payload[0] = OCD_SCAN_REQUEST;
bool success;
- if (NULL == path)
+ if (!path)
return false;
xds110.write_payload[0] = OCD_PATHMOVE;
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);
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 */
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;
}
/* 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) {
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 */
/* 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;
}
* 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;
}
uint32_t value;
bool success = true;
- if (0 == xds110.txn_request_size)
+ if (xds110.txn_request_size == 0)
return ERROR_OK;
/* Terminate request queue */
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;
/* 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;
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;
{
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 */
}
}
+ if (success) {
+ /* Set supply voltage for stand-alone probes */
+ 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 (xds110.voltage != 0) {
+ /* Voltage supply not a feature of embedded probes */
+ LOG_WARNING(
+ "XDS110: ignoring supply voltage, not supported on this probe");
+ }
+ }
+
if (success) {
success = xds_set_trst(0);
if (success)
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 */
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 */
+ 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)
}
free((void *)path);
-
- return;
}
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);
}
xds110.txn_request_size += total_bytes;
xds110.txn_result_size += total_bytes;
-
- return;
}
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)
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);
{
struct jtag_command *cmd = jtag_command_queue;
- while (cmd != NULL) {
+ while (cmd) {
xds110_execute_command(cmd);
cmd = cmd->next;
}
static int xds110_speed(int speed)
{
+ double freq_to_use;
+ uint32_t delay_count;
bool success;
if (speed == 0) {
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);
+
+ /* 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;
+ }
- 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;
}
}
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)
+COMMAND_HANDLER(xds110_handle_supply_voltage_command)
{
- wchar_t serial[XDS110_SERIAL_LEN + 1];
-
- xds110.serial[0] = 0;
+ uint32_t voltage = 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");
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], voltage);
+ if (voltage == 0 || (voltage >= XDS110_MIN_VOLTAGE && voltage
+ <= XDS110_MAX_VOLTAGE)) {
+ /* Requested voltage is in range */
+ xds110.voltage = voltage;
+ } else {
+ LOG_ERROR("XDS110: voltage must be 0 or between %d and %d "
+ "millivolts", XDS110_MIN_VOLTAGE, XDS110_MAX_VOLTAGE);
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 "
- "<serial-number>");
- return ERROR_FAIL;
- }
+ xds110.voltage = voltage;
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
return ERROR_OK;
}
.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
};
.name = "xds110",
.mode = COMMAND_ANY,
.help = "perform XDS110 management",
- .usage = "<cmd>",
+ .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",
- },
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,
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,
};