X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fjlink.c;h=40665c3e788e3d47c7d6963fafece1a7330dfb38;hp=ae80eb89b069c721ddab68fc03e0fcc3e9504e0b;hb=fb9277191b715566c82b633a474a5c7c78fcfe1a;hpb=ff120440d66962b33fc84b2363d2197172fd2a6e diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index ae80eb89b0..40665c3e78 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -29,6 +29,7 @@ #endif #include +#include #include #include "libusb_common.h" @@ -46,14 +47,12 @@ * pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address) */ -#define VID 0x1366, 0x1366, 0x1366, 0x1366 -#define PID 0x0101, 0x0102, 0x0103, 0x0104 +#define JLINK_USB_INTERFACE_CLASS 0xff +#define JLINK_USB_INTERFACE_SUBCLASS 0xff +#define JLINK_USB_INTERFACE_PROTOCOL 0xff -#define JLINK_WRITE_ENDPOINT 0x02 -#define JLINK_READ_ENDPOINT 0x81 - -static unsigned int jlink_write_ep = JLINK_WRITE_ENDPOINT; -static unsigned int jlink_read_ep = JLINK_READ_ENDPOINT; +static unsigned int jlink_write_ep; +static unsigned int jlink_read_ep; static unsigned int jlink_hw_jtag_version = 2; #define JLINK_USB_TIMEOUT 1000 @@ -78,6 +77,7 @@ static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; #define EMU_CMD_SET_SPEED 0x05 #define EMU_CMD_GET_STATE 0x07 #define EMU_CMD_SET_KS_POWER 0x08 +#define EMU_CMD_REGISTER 0x09 #define EMU_CMD_GET_SPEEDS 0xc0 #define EMU_CMD_GET_HW_INFO 0xc1 #define EMU_CMD_GET_COUNTERS 0xc2 @@ -113,6 +113,10 @@ static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; #define EMU_CMD_WRITE_MEM_ARM79 0xf7 #define EMU_CMD_READ_MEM_ARM79 0xf8 +/* Register subcommands */ +#define REG_CMD_REGISTER 100 +#define REG_CMD_UNREGISTER 101 + /* bits return from EMU_CMD_GET_CAPS */ #define EMU_CAP_RESERVED_1 0 #define EMU_CAP_GET_HW_VERSION 1 @@ -147,7 +151,7 @@ static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; #define EMU_CAP_RAWTRACE 30 #define EMU_CAP_RESERVED_3 31 -static char *jlink_cap_str[] = { +static const char * const jlink_cap_str[] = { "Always 1.", "Supports command EMU_CMD_GET_HARDWARE_VERSION", "Supports command EMU_CMD_WRITE_DCC", @@ -186,18 +190,18 @@ static char *jlink_cap_str[] = { #define JLINK_MAX_SPEED 12000 /* J-Link hardware versions */ -#define JLINK_HW_TYPE_JLINK 0 -#define JLINK_HW_TYPE_JTRACE 1 -#define JLINK_HW_TYPE_FLASHER 2 -#define JLINK_HW_TYPE_JLINK_PRO 3 -#define JLINK_HW_TYPE_MAX 4 - -static char *jlink_hw_type_str[] = { - "J-Link", - "J-Trace", - "Flasher", - "J-Link Pro", -}; +#define JLINK_HW_TYPE_JLINK 0 +#define JLINK_HW_TYPE_JTRACE 1 +#define JLINK_HW_TYPE_FLASHER 2 +#define JLINK_HW_TYPE_JLINK_PRO 3 +#define JLINK_HW_TYPE_JLINK_LITE_ADI 5 +#define JLINK_HW_TYPE_LPCLINK2 18 + +/* Interface selection */ +#define JLINK_TIF_JTAG 0 +#define JLINK_TIF_SWD 1 +#define JLINK_SWD_DIR_IN 0 +#define JLINK_SWD_DIR_OUT 1 /* Queue command functions */ static void jlink_end_state(tap_state_t state); @@ -209,6 +213,9 @@ static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, static void jlink_reset(int trst, int srst); static void jlink_simple_command(uint8_t command); static int jlink_get_status(void); +static int jlink_swd_run_queue(struct adiv5_dap *dap); +static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data); +static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq); /* J-Link tap buffer functions */ static void jlink_tap_init(void); @@ -246,12 +253,17 @@ static enum tap_state jlink_last_state = TAP_RESET; static struct jlink *jlink_handle; /* pid could be specified at runtime */ -static uint16_t vids[] = { VID, 0 }; -static uint16_t pids[] = { PID, 0 }; +static uint16_t vids[] = { 0x1366, 0x1366, 0x1366, 0x1366, 0x1366, 0 }; +static uint16_t pids[] = { 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0 }; + +static char *jlink_serial; static uint32_t jlink_caps; static uint32_t jlink_hw_type; +static int queued_retval; +static bool swd_mode; + /* 256 byte non-volatile memory */ struct jlink_config { uint8_t usb_address; @@ -420,6 +432,41 @@ static int jlink_khz(int khz, int *jtag_speed) return ERROR_OK; } +static int jlink_register(void) +{ + int result; + usb_out_buffer[0] = EMU_CMD_REGISTER; + usb_out_buffer[1] = REG_CMD_REGISTER; + /* 2 - 11 is "additional parameter", + * 12 - 13 is connection handle, zero initially */ + memset(&usb_out_buffer[2], 0, 10 + 2); + + result = jlink_usb_write(jlink_handle, 14); + if (result != 14) { + LOG_ERROR("J-Link register write failed (%d)", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* Returns: + * 0 - 1 connection handle, + * 2 - 3 number of information entities, + * 4 - 5 size of a single information struct, + * 6 - 7 number of additional bytes, + * 8 - ... reply data + * + * Try to read the whole USB bulk packet + */ + result = jtag_libusb_bulk_read(jlink_handle->usb_handle, jlink_read_ep, + (char *)usb_in_buffer, sizeof(usb_in_buffer), + JLINK_USB_TIMEOUT); + if (!result) { + LOG_ERROR("J-Link register read failed (0 bytes received)"); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + /* * select transport interface * @@ -464,7 +511,7 @@ static int jlink_select_interface(int iface) uint32_t iface_mask = buf_get_u32(usb_in_buffer, 0, 32); if (!(iface_mask & (1<kickstart_power_on_jtag_pin_19); } @@ -919,10 +958,29 @@ static int jlink_get_version_info(void) LOG_INFO("J-Link hw version %i", (int)jlink_hw_version); - if (jlink_hw_type >= JLINK_HW_TYPE_MAX) - LOG_INFO("J-Link hw type uknown 0x%x", jlink_hw_type); - else - LOG_INFO("J-Link hw type %s", jlink_hw_type_str[jlink_hw_type]); + switch (jlink_hw_type) { + case JLINK_HW_TYPE_JLINK: + LOG_INFO("J-Link hw type J-Link"); + break; + case JLINK_HW_TYPE_JTRACE: + LOG_INFO("J-Link hw type J-Trace"); + break; + case JLINK_HW_TYPE_FLASHER: + LOG_INFO("J-Link hw type Flasher"); + break; + case JLINK_HW_TYPE_JLINK_PRO: + LOG_INFO("J-Link hw type J-Link Pro"); + break; + case JLINK_HW_TYPE_JLINK_LITE_ADI: + LOG_INFO("J-Link hw type J-Link Lite-ADI"); + break; + case JLINK_HW_TYPE_LPCLINK2: + LOG_INFO("J-Link hw type J-Link on LPC-Link2"); + break; + default: + LOG_INFO("J-Link hw type unknown 0x%" PRIx32, jlink_hw_type); + break; + } } if (jlink_caps & (1 << EMU_CAP_GET_MAX_BLOCK_SIZE)) { @@ -963,6 +1021,19 @@ COMMAND_HANDLER(jlink_pid_command) return ERROR_OK; } +COMMAND_HANDLER(jlink_serial_command) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Need exactly one argument to jlink_serial"); + return ERROR_FAIL; + } + if (jlink_serial) + free(jlink_serial); + jlink_serial = strdup(CMD_ARGV[0]); + + return ERROR_OK; +} + COMMAND_HANDLER(jlink_handle_jlink_info_command) { if (jlink_get_version_info() == ERROR_OK) { @@ -1279,6 +1350,12 @@ static const struct command_registration jlink_subcommand_handlers[] = { .mode = COMMAND_CONFIG, .help = "set the pid of the interface we want to use", }, + { + .name = "serial", + .handler = &jlink_serial_command, + .mode = COMMAND_CONFIG, + .help = "set the serial number of the J-Link adapter we want to use" + }, COMMAND_REGISTRATION_DONE }; @@ -1292,10 +1369,50 @@ static const struct command_registration jlink_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static int jlink_swd_init(void) +{ + LOG_INFO("JLink SWD mode enabled"); + swd_mode = true; + + return ERROR_OK; +} + +static void jlink_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value) +{ + assert(!(cmd & SWD_CMD_RnW)); + jlink_swd_queue_cmd(dap, cmd, NULL, value); +} + +static void jlink_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value) +{ + assert(cmd & SWD_CMD_RnW); + jlink_swd_queue_cmd(dap, cmd, value, 0); +} + +static int_least32_t jlink_swd_frequency(struct adiv5_dap *dap, int_least32_t hz) +{ + if (hz > 0) + jlink_speed(hz / 1000); + + return hz; +} + +static const struct swd_driver jlink_swd = { + .init = jlink_swd_init, + .frequency = jlink_swd_frequency, + .switch_seq = jlink_swd_switch_seq, + .read_reg = jlink_swd_read_reg, + .write_reg = jlink_swd_write_reg, + .run = jlink_swd_run_queue, +}; + +static const char * const jlink_transports[] = { "jtag", "swd", NULL }; + struct jtag_interface jlink_interface = { .name = "jlink", .commands = jlink_command_handlers, - .transports = jtag_only, + .transports = jlink_transports, + .swd = &jlink_swd, .execute_queue = jlink_execute_queue, .speed = jlink_speed, @@ -1310,6 +1427,7 @@ struct jtag_interface jlink_interface = { static unsigned tap_length; +/* In SWD mode use tms buffer for direction control */ static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE]; static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[JLINK_TAP_BUFFER_SIZE]; @@ -1318,7 +1436,7 @@ struct pending_scan_result { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ - uint8_t *buffer; + void *buffer; }; #define MAX_PENDING_SCAN_RESULTS 256 @@ -1428,7 +1546,8 @@ static int jlink_tap_execute(void) result = use_jtag3 ? usb_in_buffer[byte_length] : 0; if (result != 0) { - LOG_ERROR("jlink_tap_execute failed, result %d", result); + LOG_ERROR("jlink_tap_execute failed, result %d (%s)", result, + result == 1 ? "adaptive clocking timeout" : "unknown"); jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } @@ -1462,13 +1581,191 @@ static int jlink_tap_execute(void) return ERROR_OK; } +static void fill_buffer(uint8_t *buf, uint32_t val, uint32_t len) +{ + unsigned int tap_pos = tap_length; + + while (len > 32) { + buf_set_u32(buf, tap_pos, 32, val); + len -= 32; + tap_pos += 32; + } + if (len) + buf_set_u32(buf, tap_pos, len, val); +} + +static void jlink_queue_data_out(const uint8_t *data, uint32_t len) +{ + const uint32_t dir_out = 0xffffffff; + + if (data) + bit_copy(tdi_buffer, tap_length, data, 0, len); + else + fill_buffer(tdi_buffer, 0, len); + fill_buffer(tms_buffer, dir_out, len); + tap_length += len; +} + +static void jlink_queue_data_in(uint32_t len) +{ + const uint32_t dir_in = 0; + + fill_buffer(tms_buffer, dir_in, len); + tap_length += len; +} + +static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq) +{ + const uint8_t *s; + unsigned int s_len; + + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + s = swd_seq_line_reset; + s_len = swd_seq_line_reset_len; + break; + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + s = swd_seq_jtag_to_swd; + s_len = swd_seq_jtag_to_swd_len; + break; + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + s = swd_seq_swd_to_jtag; + s_len = swd_seq_swd_to_jtag_len; + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } + + jlink_queue_data_out(s, s_len); + + return ERROR_OK; +} + +static int jlink_swd_run_queue(struct adiv5_dap *dap) +{ + LOG_DEBUG("Executing %d queued transactions", pending_scan_results_length); + int retval; + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); + goto skip; + } + + /* A transaction must be followed by another transaction or at least 8 idle cycles to + * ensure that data is clocked through the AP. */ + jlink_queue_data_out(NULL, 8); + + size_t byte_length = DIV_ROUND_UP(tap_length, 8); + + /* There's a comment in jlink_tap_execute saying JLink returns + * an extra NULL in packet when size of incoming message is a + * multiple of 64. Someone should verify if that's still the + * case with the current jlink firmware */ + + usb_out_buffer[0] = EMU_CMD_HW_JTAG3; + usb_out_buffer[1] = 0; + usb_out_buffer[2] = (tap_length >> 0) & 0xff; + usb_out_buffer[3] = (tap_length >> 8) & 0xff; + memcpy(usb_out_buffer + 4, tms_buffer, byte_length); + memcpy(usb_out_buffer + 4 + byte_length, tdi_buffer, byte_length); + + retval = jlink_usb_message(jlink_handle, 4 + 2 * byte_length, + byte_length + 1); + if (retval != ERROR_OK) { + LOG_ERROR("jlink_swd_run_queue failed USB io (%d)", retval); + goto skip; + } + + retval = usb_in_buffer[byte_length]; + if (retval) { + LOG_ERROR("jlink_swd_run_queue failed, result %d", retval); + goto skip; + } + + for (int i = 0; i < pending_scan_results_length; i++) { + int ack = buf_get_u32(usb_in_buffer, pending_scan_results_buffer[i].first, 3); + + if (ack != SWD_ACK_OK) { + LOG_DEBUG("SWD ack not OK: %d %s", ack, + ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); + queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; + goto skip; + } else if (pending_scan_results_buffer[i].length) { + uint32_t data = buf_get_u32(usb_in_buffer, 3 + pending_scan_results_buffer[i].first, 32); + int parity = buf_get_u32(usb_in_buffer, 3 + 32 + pending_scan_results_buffer[i].first, 1); + + if (parity != parity_u32(data)) { + LOG_ERROR("SWD Read data parity mismatch"); + queued_retval = ERROR_FAIL; + goto skip; + } + + if (pending_scan_results_buffer[i].buffer) + *(uint32_t *)pending_scan_results_buffer[i].buffer = data; + } + } + +skip: + jlink_tap_init(); + retval = queued_retval; + queued_retval = ERROR_OK; + + return retval; +} + +static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data) +{ + uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)]; + if (tap_length + 46 + 8 + dap->memaccess_tck >= sizeof(tdi_buffer) * 8 || + pending_scan_results_length == MAX_PENDING_SCAN_RESULTS) { + /* Not enough room in the queue. Run the queue. */ + queued_retval = jlink_swd_run_queue(dap); + } + + if (queued_retval != ERROR_OK) + return; + + cmd |= SWD_CMD_START | SWD_CMD_PARK; + + jlink_queue_data_out(&cmd, 8); + + pending_scan_results_buffer[pending_scan_results_length].first = tap_length; + + if (cmd & SWD_CMD_RnW) { + /* Queue a read transaction */ + pending_scan_results_buffer[pending_scan_results_length].length = 32; + pending_scan_results_buffer[pending_scan_results_length].buffer = dst; + + jlink_queue_data_in(1 + 3 + 32 + 1 + 1); + } else { + /* Queue a write transaction */ + pending_scan_results_buffer[pending_scan_results_length].length = 0; + jlink_queue_data_in(1 + 3 + 1); + + buf_set_u32(data_parity_trn, 0, 32, data); + buf_set_u32(data_parity_trn, 32, 1, parity_u32(data)); + + jlink_queue_data_out(data_parity_trn, 32 + 1); + } + + pending_scan_results_length++; + + /* Insert idle cycles after AP accesses to avoid WAIT */ + if (cmd & SWD_CMD_APnDP) + jlink_queue_data_out(NULL, dap->memaccess_tck); +} + /*****************************************************************************/ /* JLink USB low-level functions */ static struct jlink *jlink_usb_open() { struct jtag_libusb_device_handle *devh; - if (jtag_libusb_open(vids, pids, &devh) != ERROR_OK) + if (jtag_libusb_open(vids, pids, jlink_serial, &devh) != ERROR_OK) return NULL; /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS @@ -1482,7 +1779,15 @@ static struct jlink *jlink_usb_open() * committing them! */ -#if IS_WIN32 == 0 +/* This entire block can probably be removed. It was a workaround for + * libusb0.1 and old JLink firmware. It has already be removed for + * windows and causing problems (LPC Link-2 with JLink firmware) on + * Linux with libusb1.0. + * + * However, for now the behavior will be left unchanged for non-windows + * platforms using libusb0.1 due to lack of testing. + */ +#if IS_WIN32 == 0 && HAVE_LIBUSB1 == 0 jtag_libusb_reset_device(devh); @@ -1492,7 +1797,7 @@ static struct jlink *jlink_usb_open() /* reopen jlink after usb_reset * on win32 this may take a second or two to re-enumerate */ int retval; - while ((retval = jtag_libusb_open(vids, pids, &devh)) != ERROR_OK) { + while ((retval = jtag_libusb_open(vids, pids, jlink_serial, &devh)) != ERROR_OK) { usleep(1000); timeout--; if (!timeout) @@ -1504,20 +1809,15 @@ static struct jlink *jlink_usb_open() #endif - /* usb_set_configuration required under win32 */ - struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); + /* usb_set_configuration is only required under win32 + * with libusb 0.1 and libusb0.sys. For libusb 1.0 it is a no-op + * since the configuration is already set. */ jtag_libusb_set_configuration(devh, 0); - jtag_libusb_claim_interface(devh, 0); - -#if 0 - /* - * This makes problems under Mac OS X. And is not needed - * under Windows. Hopefully this will not break a linux build - */ - usb_set_altinterface(result->usb_handle, 0); -#endif - jtag_libusb_get_endpoints(udev, &jlink_read_ep, &jlink_write_ep); + jtag_libusb_choose_interface(devh, &jlink_read_ep, &jlink_write_ep, + JLINK_USB_INTERFACE_CLASS, + JLINK_USB_INTERFACE_SUBCLASS, + JLINK_USB_INTERFACE_PROTOCOL); struct jlink *result = malloc(sizeof(struct jlink)); result->usb_handle = devh;