coding style: remove useless return statement from void functions
[openocd.git] / src / jtag / drivers / xds110.c
index f0899246b4ca8fb034816228f9538f0517493f20..5e4df93c2d1a2fcfc8c98e9888a00709fafa0862 100644 (file)
 #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
@@ -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),
@@ -1624,7 +1668,11 @@ static int xds110_reset(int trst, int srst)
                        retval = ERROR_FAIL;
 
                /* Toggle TCK to trigger HIB on CC13x/CC26x devices */
-               success = 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;
        }
@@ -1635,14 +1683,11 @@ static int xds110_reset(int trst, int srst)
 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)
@@ -1678,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)
@@ -1751,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)
@@ -1772,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)
@@ -1790,8 +1829,6 @@ 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)
@@ -1842,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) {
@@ -1849,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);
+
+                       /* 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;
                }
        }
 
@@ -1958,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;
 }
@@ -1983,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;
 }
@@ -1997,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
 };
@@ -2038,17 +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,
 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)