X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fxds110.c;h=085d85f4c3c76807dfce92be28b258fca8de7fc2;hb=c9ebd488eadfaec6154db5747f376323f587766d;hp=9bfe02ea87b4cd3f5dea45abbadd9a159c5864ff;hpb=ebf2d733409e140cb220d95eb3a915fed14d69a4;p=openocd.git diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index 9bfe02ea87..085d85f4c3 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -29,11 +29,24 @@ /* 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 * ***************************************************************************/ @@ -84,8 +97,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 @@ -162,6 +184,7 @@ #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 */ @@ -219,6 +242,8 @@ struct xds110_info { 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; @@ -239,9 +264,10 @@ static struct xds110_info xds110 = { .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, @@ -365,13 +391,9 @@ static bool usb_connect(void) 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); } else { @@ -605,10 +627,15 @@ 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", + 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) + LOG_DEBUG("XDS110: command 0x%02x returned error %d", + xds110.write_payload[0], error); } } } @@ -956,6 +983,24 @@ static bool cjtag_disconnect(void) 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)(0 != voltage ? 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) { @@ -1322,7 +1367,7 @@ static void xds110_show_info(void) (((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); + LOG_INFO("XDS110: serial number = %s", xds110.serial); if (xds110.is_swd_mode) { LOG_INFO("XDS110: connected to target via SWD"); LOG_INFO("XDS110: SWCLK set to %d kHz", xds110.speed); @@ -1394,6 +1439,20 @@ static int xds110_init(void) } } + if (success) { + /* Set supply voltage for stand-alone probes */ + if (XDS110_STAND_ALONE_ID == xds110.hardware) { + 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) { + /* 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) @@ -1548,32 +1607,48 @@ 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; + } + 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); } - (void)xds_set_srst(srst); + + if (!success) + retval = ERROR_FAIL; } + + return retval; } static void xds110_execute_sleep(struct jtag_command *cmd) @@ -1741,10 +1816,6 @@ static void xds110_queue_stableclocks(struct jtag_command *cmd) 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); @@ -1790,6 +1861,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) { @@ -1797,61 +1870,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; } } @@ -1878,13 +2000,6 @@ 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(); @@ -1922,6 +2037,31 @@ COMMAND_HANDLER(xds110_handle_serial_command) 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); + 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; + } + xds110.voltage = voltage; + } else { + LOG_ERROR("XDS110: expected one argument to xds110_supply_voltage " + ""); + return ERROR_FAIL; + } + + return ERROR_OK; +} + static const struct command_registration xds110_subcommand_handlers[] = { { .name = "info", @@ -1948,12 +2088,18 @@ static const struct command_registration xds110_command_handlers[] = { .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, @@ -1962,16 +2108,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, };