X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fjlink.c;h=fdf4ae778ddeb7c97ef9bdf0c02236316130066a;hp=40665c3e788e3d47c7d6963fafece1a7330dfb38;hb=ad18c1a47fb8f3eaae66a7314700a1f186391359;hpb=fb9277191b715566c82b633a474a5c7c78fcfe1a diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 40665c3e78..fdf4ae778d 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -8,6 +8,12 @@ * Copyright (C) 2011 by Jean-Christophe PLAGNIOL-VIILARD * * plagnioj@jcrosoft.com * * * + * Copyright (C) 2015 by Marc Schink * + * openocd-dev@marcschink.de * + * * + * Copyright (C) 2015 by Paul Fertser * + * fercerpav@gmail.com * + * * * 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 * @@ -19,257 +25,54 @@ * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include +#include + #include #include #include -#include "libusb_common.h" - -/* See Segger's public documentation: - * Reference manual for J-Link USB Protocol - * Document RM08001-R6 Date: June 16, 2009 - * (Or newer, with some SWD information). - * http://www.segger.com/cms/admin/uploads/productDocs/RM08001_JLinkUSBProtocol.pdf - */ - -/* - * The default pid of the segger is 0x0101 - * But when you change the USB Address it will also - * - * pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address) - */ - -#define JLINK_USB_INTERFACE_CLASS 0xff -#define JLINK_USB_INTERFACE_SUBCLASS 0xff -#define JLINK_USB_INTERFACE_PROTOCOL 0xff - -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 - -/* See Section 3.3.2 of the Segger JLink USB protocol manual */ -/* 2048 is the max value we can use here */ -#define JLINK_TAP_BUFFER_SIZE 2048 -/*#define JLINK_TAP_BUFFER_SIZE 256*/ -/*#define JLINK_TAP_BUFFER_SIZE 384*/ - -#define JLINK_IN_BUFFER_SIZE (2048 + 1) -#define JLINK_OUT_BUFFER_SIZE (2*2048 + 4) - -/* Global USB buffers */ -static uint8_t usb_in_buffer[JLINK_IN_BUFFER_SIZE]; -static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; - -/* Constants for JLink command */ -#define EMU_CMD_VERSION 0x01 -#define EMU_CMD_RESET_TRST 0x02 -#define EMU_CMD_RESET_TARGET 0x03 -#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 -#define EMU_CMD_SELECT_IF 0xc7 -#define EMU_CMD_HW_CLOCK 0xc8 -#define EMU_CMD_HW_TMS0 0xc9 -#define EMU_CMD_HW_TMS1 0xca -#define EMU_CMD_HW_DATA0 0xcb -#define EMU_CMD_HW_DATA1 0xcc -#define EMU_CMD_HW_JTAG 0xcd -#define EMU_CMD_HW_JTAG2 0xce -#define EMU_CMD_HW_JTAG3 0xcf -#define EMU_CMD_HW_RELEASE_RESET_STOP_EX 0xd0 -#define EMU_CMD_HW_RELEASE_RESET_STOP_TIMED 0xd1 -#define EMU_CMD_GET_MAX_MEM_BLOCK 0xd4 -#define EMU_CMD_HW_JTAG_WRITE 0xd5 -#define EMU_CMD_HW_JTAG_GET_RESULT 0xd6 -#define EMU_CMD_HW_RESET0 0xdc -#define EMU_CMD_HW_RESET1 0xdd -#define EMU_CMD_HW_TRST0 0xde -#define EMU_CMD_HW_TRST1 0xdf -#define EMU_CMD_GET_CAPS 0xe8 -#define EMU_CMD_GET_CPU_CAPS 0xe9 -#define EMU_CMD_EXEC_CPU_CMD 0xea -#define EMU_CMD_GET_CAPS_EX 0xed -#define EMU_CMD_GET_HW_VERSION 0xf0 -#define EMU_CMD_WRITE_DCC 0xf1 -#define EMU_CMD_READ_CONFIG 0xf2 -#define EMU_CMD_WRITE_CONFIG 0xf3 -#define EMU_CMD_WRITE_MEM 0xf4 -#define EMU_CMD_READ_MEM 0xf5 -#define EMU_CMD_MEASURE_RTCK_REACT 0xf6 -#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 -#define EMU_CAP_WRITE_DCC 2 -#define EMU_CAP_ADAPTIVE_CLOCKING 3 -#define EMU_CAP_READ_CONFIG 4 -#define EMU_CAP_WRITE_CONFIG 5 -#define EMU_CAP_TRACE 6 -#define EMU_CAP_WRITE_MEM 7 -#define EMU_CAP_READ_MEM 8 -#define EMU_CAP_SPEED_INFO 9 -#define EMU_CAP_EXEC_CODE 10 -#define EMU_CAP_GET_MAX_BLOCK_SIZE 11 -#define EMU_CAP_GET_HW_INFO 12 -#define EMU_CAP_SET_KS_POWER 13 -#define EMU_CAP_RESET_STOP_TIMED 14 -#define EMU_CAP_RESERVED_2 15 -#define EMU_CAP_MEASURE_RTCK_REACT 16 -#define EMU_CAP_SELECT_IF 17 -#define EMU_CAP_RW_MEM_ARM79 18 -#define EMU_CAP_GET_COUNTERS 19 -#define EMU_CAP_READ_DCC 20 -#define EMU_CAP_GET_CPU_CAPS 21 -#define EMU_CAP_EXEC_CPU_CMD 22 -#define EMU_CAP_SWO 23 -#define EMU_CAP_WRITE_DCC_EX 24 -#define EMU_CAP_UPDATE_FIRMWARE_EX 25 -#define EMU_CAP_FILE_IO 26 -#define EMU_CAP_REGISTER 27 -#define EMU_CAP_INDICATORS 28 -#define EMU_CAP_TEST_NET_SPEED 29 -#define EMU_CAP_RAWTRACE 30 -#define EMU_CAP_RESERVED_3 31 - -static const char * const jlink_cap_str[] = { - "Always 1.", - "Supports command EMU_CMD_GET_HARDWARE_VERSION", - "Supports command EMU_CMD_WRITE_DCC", - "Supports adaptive clocking", - "Supports command EMU_CMD_READ_CONFIG", - "Supports command EMU_CMD_WRITE_CONFIG", - "Supports trace commands", - "Supports command EMU_CMD_WRITE_MEM", - "Supports command EMU_CMD_READ_MEM", - "Supports command EMU_CMD_GET_SPEED", - "Supports command EMU_CMD_CODE_...", - "Supports command EMU_CMD_GET_MAX_BLOCK_SIZE", - "Supports command EMU_CMD_GET_HW_INFO", - "Supports command EMU_CMD_SET_KS_POWER", - "Supports command EMU_CMD_HW_RELEASE_RESET_STOP_TIMED", - "Reserved", - "Supports command EMU_CMD_MEASURE_RTCK_REACT", - "Supports command EMU_CMD_HW_SELECT_IF", - "Supports command EMU_CMD_READ/WRITE_MEM_ARM79", - "Supports command EMU_CMD_GET_COUNTERS", - "Supports command EMU_CMD_READ_DCC", - "Supports command EMU_CMD_GET_CPU_CAPS", - "Supports command EMU_CMD_EXEC_CPU_CMD", - "Supports command EMU_CMD_SWO", - "Supports command EMU_CMD_WRITE_DCC_EX", - "Supports command EMU_CMD_UPDATE_FIRMWARE_EX", - "Supports command EMU_CMD_FILE_IO", - "Supports command EMU_CMD_REGISTER", - "Supports command EMU_CMD_INDICATORS", - "Supports command EMU_CMD_TEST_NET_SPEED", - "Supports command EMU_CMD_RAWTRACE", - "Reserved", -}; - -/* max speed 12MHz v5.0 jlink */ -#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_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); -static void jlink_state_move(void); -static void jlink_path_move(int num_states, tap_state_t *path); -static void jlink_runtest(int num_cycles); -static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, - int scan_size, struct scan_command *command); -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); -static int jlink_tap_execute(void); -static void jlink_tap_ensure_space(int scans, int bits); -static void jlink_tap_append_step(int tms, int tdi); -static void jlink_tap_append_scan(int length, uint8_t *buffer, - struct scan_command *command); - -/* Jlink lowlevel functions */ -struct jlink { - struct jtag_libusb_device_handle *usb_handle; -}; - -static struct jlink *jlink_usb_open(void); -static void jlink_usb_close(struct jlink *jlink); -static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length); -static int jlink_usb_io(struct jlink *jlink, int out_length, int in_length); -static int jlink_usb_write(struct jlink *jlink, int out_length); -static int jlink_usb_read(struct jlink *jlink, int expected_size); - -/* helper functions */ -static int jlink_get_version_info(void); - -#ifdef _DEBUG_USB_COMMS_ -static void jlink_debug_buffer(uint8_t *buffer, int length); -#else -static inline void jlink_debug_buffer(uint8_t *buffer, int length) -{ -} -#endif +#include +#include +#include -static enum tap_state jlink_last_state = TAP_RESET; +#include -static struct jlink *jlink_handle; +static struct jaylink_context *jayctx; +static struct jaylink_device_handle *devh; +static struct jaylink_connection conn; +static struct jaylink_connection connlist[JAYLINK_MAX_CONNECTIONS]; +static enum jaylink_jtag_version jtag_command_version; +static uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE]; -/* pid could be specified at runtime */ -static uint16_t vids[] = { 0x1366, 0x1366, 0x1366, 0x1366, 0x1366, 0 }; -static uint16_t pids[] = { 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0 }; +static uint32_t serial_number; +static bool use_serial_number; +static bool use_usb_location; +static enum jaylink_usb_address usb_address; +static bool use_usb_address; +static enum jaylink_target_interface iface = JAYLINK_TIF_JTAG; +static bool trace_enabled; -static char *jlink_serial; +#define JLINK_MAX_SPEED 12000 +#define JLINK_TAP_BUFFER_SIZE 2048 -static uint32_t jlink_caps; -static uint32_t jlink_hw_type; +static unsigned int swd_buffer_size = JLINK_TAP_BUFFER_SIZE; -static int queued_retval; -static bool swd_mode; +/* Maximum SWO frequency deviation. */ +#define SWO_MAX_FREQ_DEV 0.03 /* 256 byte non-volatile memory */ -struct jlink_config { +struct device_config { uint8_t usb_address; /* 0ffset 0x01 to 0x03 */ uint8_t reserved_1[3]; - uint32_t kickstart_power_on_jtag_pin_19; + uint32_t target_power; /* 0ffset 0x08 to 0x1f */ uint8_t reserved_2[24]; /* IP only for J-Link Pro */ @@ -281,25 +84,68 @@ struct jlink_config { /* 0ffset 0x36 to 0xff */ uint8_t reserved_4[202]; } __attribute__ ((packed)); -struct jlink_config jlink_cfg; + +static struct device_config config; +static struct device_config tmp_config; + +/* Queue command functions */ +static void jlink_end_state(tap_state_t state); +static void jlink_state_move(void); +static void jlink_path_move(int num_states, tap_state_t *path); +static void jlink_stableclocks(int num_cycles); +static void jlink_runtest(int num_cycles); +static void jlink_reset(int trst, int srst); +static int jlink_reset_safe(int trst, int srst); +static int jlink_swd_run_queue(void); +static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk); +static int jlink_swd_switch_seq(enum swd_special_seq seq); + +/* J-Link tap buffer functions */ +static void jlink_tap_init(void); +static int jlink_flush(void); +/** + * Queue data to go out and in, flushing the queue as many times as + * necessary. + * + * @param out A pointer to TDI data, if NULL, old stale data will be used. + * @param out_offset A bit offset for TDI data. + * @param tms_out A pointer to TMS data, if NULL, zeroes will be emitted. + * @param tms_offset A bit offset for TMS data. + * @param in A pointer to store TDO data to, if NULL the data will be discarded. + * @param in_offset A bit offset for TDO data. + * @param length Amount of bits to transfer out and in. + * + * @retval This function doesn't return any value. + */ +static void jlink_clock_data(const uint8_t *out, unsigned out_offset, + const uint8_t *tms_out, unsigned tms_offset, + uint8_t *in, unsigned in_offset, + unsigned length); + +static enum tap_state jlink_last_state = TAP_RESET; +static int queued_retval; /***************************************************************************/ /* External interface implementation */ +static void jlink_execute_stableclocks(struct jtag_command *cmd) +{ + LOG_DEBUG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); + jlink_stableclocks(cmd->cmd.runtest->num_cycles); +} + static void jlink_execute_runtest(struct jtag_command *cmd) { - DEBUG_JTAG_IO("runtest %i cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); + LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); jlink_end_state(cmd->cmd.runtest->end_state); - jlink_runtest(cmd->cmd.runtest->num_cycles); } static void jlink_execute_statemove(struct jtag_command *cmd) { - DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); jlink_end_state(cmd->cmd.statemove->end_state); jlink_state_move(); @@ -307,53 +153,119 @@ static void jlink_execute_statemove(struct jtag_command *cmd) static void jlink_execute_pathmove(struct jtag_command *cmd) { - DEBUG_JTAG_IO("pathmove: %i states, end in %i", + LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - jlink_path_move(cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path); + jlink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); } static void jlink_execute_scan(struct jtag_command *cmd) { - int scan_size; - enum scan_type type; - uint8_t *buffer; + LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", + jtag_scan_type(cmd->cmd.scan)); - DEBUG_JTAG_IO("scan end in %s", tap_state_name(cmd->cmd.scan->end_state)); + /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ + while (cmd->cmd.scan->num_fields > 0 + && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { + cmd->cmd.scan->num_fields--; + LOG_DEBUG("discarding trailing empty field"); + } - jlink_end_state(cmd->cmd.scan->end_state); + if (cmd->cmd.scan->num_fields == 0) { + LOG_DEBUG("empty scan, doing nothing"); + return; + } - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - DEBUG_JTAG_IO("scan input, length = %d", scan_size); + if (cmd->cmd.scan->ir_scan) { + if (tap_get_state() != TAP_IRSHIFT) { + jlink_end_state(TAP_IRSHIFT); + jlink_state_move(); + } + } else { + if (tap_get_state() != TAP_DRSHIFT) { + jlink_end_state(TAP_DRSHIFT); + jlink_state_move(); + } + } - jlink_debug_buffer(buffer, (scan_size + 7) / 8); - type = jtag_scan_type(cmd->cmd.scan); - jlink_scan(cmd->cmd.scan->ir_scan, - type, buffer, scan_size, cmd->cmd.scan); -} + jlink_end_state(cmd->cmd.scan->end_state); -static void jlink_execute_reset(struct jtag_command *cmd) -{ - DEBUG_JTAG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); + struct scan_field *field = cmd->cmd.scan->fields; + unsigned scan_size = 0; + + for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { + scan_size += field->num_bits; + LOG_DEBUG_IO("%s%s field %d/%d %d bits", + field->in_value ? "in" : "", + field->out_value ? "out" : "", + i, + cmd->cmd.scan->num_fields, + field->num_bits); + + if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { + /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap + * movement. This last field can't have length zero, it was checked above. */ + jlink_clock_data(field->out_value, + 0, + NULL, + 0, + field->in_value, + 0, + field->num_bits - 1); + uint8_t last_bit = 0; + if (field->out_value) + bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); + uint8_t tms_bits = 0x01; + jlink_clock_data(&last_bit, + 0, + &tms_bits, + 0, + field->in_value, + field->num_bits - 1, + 1); + tap_set_state(tap_state_transition(tap_get_state(), 1)); + jlink_clock_data(NULL, + 0, + &tms_bits, + 1, + NULL, + 0, + 1); + tap_set_state(tap_state_transition(tap_get_state(), 0)); + } else + jlink_clock_data(field->out_value, + 0, + NULL, + 0, + field->in_value, + 0, + field->num_bits); + } + + if (tap_get_state() != tap_get_end_state()) { + jlink_end_state(tap_get_end_state()); + jlink_state_move(); + } - jlink_tap_execute(); - jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - jlink_tap_execute(); + LOG_DEBUG_IO("%s scan, %i bits, end in %s", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, + tap_state_name(tap_get_end_state())); } static void jlink_execute_sleep(struct jtag_command *cmd) { - DEBUG_JTAG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us); - jlink_tap_execute(); + LOG_DEBUG_IO("sleep %" PRIu32 "", cmd->cmd.sleep->us); + jlink_flush(); jtag_sleep(cmd->cmd.sleep->us); } -static void jlink_execute_command(struct jtag_command *cmd) +static int jlink_execute_command(struct jtag_command *cmd) { switch (cmd->type) { + case JTAG_STABLECLOCKS: + jlink_execute_stableclocks(cmd); + break; case JTAG_RUNTEST: jlink_execute_runtest(cmd); break; @@ -366,52 +278,73 @@ static void jlink_execute_command(struct jtag_command *cmd) case JTAG_SCAN: jlink_execute_scan(cmd); break; - case JTAG_RESET: - jlink_execute_reset(cmd); - break; case JTAG_SLEEP: jlink_execute_sleep(cmd); break; default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + LOG_ERROR("BUG: Unknown JTAG command type encountered"); + return ERROR_JTAG_QUEUE_FAILED; } + + return ERROR_OK; } static int jlink_execute_queue(void) { + int ret; struct jtag_command *cmd = jtag_command_queue; - while (cmd != NULL) { - jlink_execute_command(cmd); + while (cmd) { + ret = jlink_execute_command(cmd); + + if (ret != ERROR_OK) + return ret; + cmd = cmd->next; } - return jlink_tap_execute(); + return jlink_flush(); } -/* Sets speed in kHz. */ static int jlink_speed(int speed) { - int result; + int ret; + struct jaylink_speed tmp; + int max_speed; + + if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) { + ret = jaylink_get_speeds(devh, &tmp); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_speeds() failed: %s", + jaylink_strerror(ret)); + return ERROR_JTAG_DEVICE_ERROR; + } - if (speed > JLINK_MAX_SPEED) { - LOG_INFO("reduce speed request: %dkHz to %dkHz maximum", - speed, JLINK_MAX_SPEED); - speed = JLINK_MAX_SPEED; + tmp.freq /= 1000; + max_speed = tmp.freq / tmp.div; + } else { + max_speed = JLINK_MAX_SPEED; } - /* check for RTCK setting */ - if (speed == 0) - speed = -1; + if (!speed) { + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING)) { + LOG_ERROR("Adaptive clocking is not supported by the device"); + return ERROR_JTAG_NOT_IMPLEMENTED; + } + + speed = JAYLINK_SPEED_ADAPTIVE_CLOCKING; + } else if (speed > max_speed) { + LOG_INFO("Reduced speed from %d kHz to %d kHz (maximum)", speed, + max_speed); + speed = max_speed; + } - usb_out_buffer[0] = EMU_CMD_SET_SPEED; - usb_out_buffer[1] = (speed >> 0) & 0xff; - usb_out_buffer[2] = (speed >> 8) & 0xff; + ret = jaylink_set_speed(devh, speed); - result = jlink_usb_write(jlink_handle, 3); - if (result != 3) { - LOG_ERROR("J-Link setting speed failed (%d)", result); + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_set_speed() failed: %s", + jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } @@ -432,929 +365,1578 @@ static int jlink_khz(int khz, int *jtag_speed) return ERROR_OK; } -static int jlink_register(void) +static bool read_device_config(struct device_config *cfg) { - 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); + int ret; - result = jlink_usb_write(jlink_handle, 14); - if (result != 14) { - LOG_ERROR("J-Link register write failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; - } + ret = jaylink_read_raw_config(devh, (uint8_t *)cfg); - /* 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; + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_read_raw_config() failed: %s", + jaylink_strerror(ret)); + return false; } - return ERROR_OK; + if (cfg->usb_address == 0xff) + cfg->usb_address = 0x00; + + if (cfg->target_power == 0xffffffff) + cfg->target_power = 0; + + return true; } -/* - * select transport interface - * - * @param iface [0..31] currently: 0=JTAG, 1=SWD - * @returns ERROR_OK or ERROR_ code - * - * @pre jlink_handle must be opened - * @pre function may be called only for devices, that have - * EMU_CAP_SELECT_IF capability enabled - */ -static int jlink_select_interface(int iface) -{ - /* According to Segger's document RM08001-R7 Date: October 8, 2010, - * http://www.segger.com/admin/uploads/productDocs/RM08001_JLinkUSBProtocol.pdf - * section 5.5.3 EMU_CMD_SELECT_IF - * > SubCmd 1..31 to select interface (0..31) - * - * The table below states: - * 0 TIF_JTAG - * 1 TIF_SWD - * - * This obviosly means that to select TIF_JTAG one should write SubCmd = 1. - * - * In fact, JTAG interface operates when SubCmd=0 - * - * It looks like a typo in documentation, because interfaces 0..31 could not - * be selected by 1..31 range command. - */ - assert(iface >= 0 && iface < 32); - int result; +static int select_interface(void) +{ + int ret; + uint32_t interfaces; - /* get available interfaces */ - usb_out_buffer[0] = EMU_CMD_SELECT_IF; - usb_out_buffer[1] = 0xff; + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SELECT_TIF)) { + if (iface != JAYLINK_TIF_JTAG) { + LOG_ERROR("Device supports JTAG transport only"); + return ERROR_JTAG_INIT_FAILED; + } - result = jlink_usb_io(jlink_handle, 2, 4); - if (result != ERROR_OK) { - LOG_ERROR("J-Link query interface failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; + return ERROR_OK; } - uint32_t iface_mask = buf_get_u32(usb_in_buffer, 0, 32); + ret = jaylink_get_available_interfaces(devh, &interfaces); - if (!(iface_mask & (1<> i) & 1; - jlink_tap_append_step(tms, 0); + tmp = MIN(JLINK_TAP_BUFFER_SIZE, (tmp - 16) / 2); + + if (tmp != swd_buffer_size) { + swd_buffer_size = tmp; + LOG_DEBUG("Adjusted SWD transaction buffer size to %u bytes", + swd_buffer_size); } - tap_set_state(tap_get_end_state()); + return true; } -static void jlink_path_move(int num_states, tap_state_t *path) +static int jaylink_log_handler(const struct jaylink_context *ctx, + enum jaylink_log_level level, const char *format, va_list args, + void *user_data) { - int i; - - for (i = 0; i < num_states; i++) { - if (path[i] == tap_state_transition(tap_get_state(), false)) - jlink_tap_append_step(0, 0); - else if (path[i] == tap_state_transition(tap_get_state(), true)) - jlink_tap_append_step(1, 0); - else { - LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", - tap_state_name(tap_get_state()), tap_state_name(path[i])); - exit(-1); - } + enum log_levels tmp; - tap_set_state(path[i]); + switch (level) { + case JAYLINK_LOG_LEVEL_ERROR: + tmp = LOG_LVL_ERROR; + break; + case JAYLINK_LOG_LEVEL_WARNING: + tmp = LOG_LVL_WARNING; + break; + /* + * Forward info messages to the debug output because they are more verbose + * than info messages of OpenOCD. + */ + case JAYLINK_LOG_LEVEL_INFO: + case JAYLINK_LOG_LEVEL_DEBUG: + tmp = LOG_LVL_DEBUG; + break; + case JAYLINK_LOG_LEVEL_DEBUG_IO: + tmp = LOG_LVL_DEBUG_IO; + break; + default: + tmp = LOG_LVL_WARNING; } - tap_set_end_state(tap_get_state()); + log_vprintf_lf(tmp, __FILE__, __LINE__, __func__, format, args); + + return 0; } -static void jlink_runtest(int num_cycles) +static bool jlink_usb_location_equal(struct jaylink_device *dev) { - int i; - - tap_state_t saved_end_state = tap_get_end_state(); + int retval; + uint8_t bus; + uint8_t *ports; + size_t num_ports; + bool equal = false; - jlink_tap_ensure_space(1, num_cycles + 16); + retval = jaylink_device_get_usb_bus_ports(dev, &bus, &ports, &num_ports); - /* only do a state_move when we're not already in IDLE */ - if (tap_get_state() != TAP_IDLE) { - jlink_end_state(TAP_IDLE); - jlink_state_move(); - /* num_cycles--; */ + if (retval == JAYLINK_ERR_NOT_SUPPORTED) { + return false; + } else if (retval != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_usb_bus_ports() failed: %s", + jaylink_strerror(retval)); + return false; } - /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) - jlink_tap_append_step(0, 0); + equal = adapter_usb_location_equal(bus, ports, num_ports); + free(ports); - /* finish in end_state */ - jlink_end_state(saved_end_state); - if (tap_get_state() != tap_get_end_state()) - jlink_state_move(); + return equal; } -static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, - int scan_size, struct scan_command *command) -{ - tap_state_t saved_end_state; - jlink_tap_ensure_space(1, scan_size + 16); +static int jlink_open_device(uint32_t ifaces, bool *found_device) +{ + int ret = jaylink_discovery_scan(jayctx, ifaces); + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_discovery_scan() failed: %s", jaylink_strerror(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } - saved_end_state = tap_get_end_state(); + size_t num_devices; + struct jaylink_device **devs; + ret = jaylink_get_devices(jayctx, &devs, &num_devices); - /* Move to appropriate scan state */ - jlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_devices() failed: %s", jaylink_strerror(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } - /* Only move if we're not already there */ - if (tap_get_state() != tap_get_end_state()) - jlink_state_move(); + use_usb_location = !!adapter_usb_get_location(); - jlink_end_state(saved_end_state); + if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) { + LOG_ERROR("Multiple devices found, specify the desired device"); + jaylink_free_devices(devs, true); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } - /* Scan */ - jlink_tap_append_scan(scan_size, buffer, command); + *found_device = false; - /* We are in Exit1, go to Pause */ - jlink_tap_append_step(0, 0); + for (size_t i = 0; devs[i]; i++) { + struct jaylink_device *dev = devs[i]; - tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); + if (use_serial_number) { + uint32_t tmp; + ret = jaylink_device_get_serial_number(dev, &tmp); - if (tap_get_state() != tap_get_end_state()) - jlink_state_move(); -} + if (ret == JAYLINK_ERR_NOT_AVAILABLE) { + continue; + } else if (ret != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_serial_number() failed: %s", + jaylink_strerror(ret)); + continue; + } -static void jlink_reset(int trst, int srst) -{ - LOG_DEBUG("trst: %i, srst: %i", trst, srst); + if (serial_number != tmp) + continue; + } - /* Signals are active low */ - if (srst == 0) - jlink_simple_command(EMU_CMD_HW_RESET1); + if (use_usb_address) { + enum jaylink_usb_address address; + ret = jaylink_device_get_usb_address(dev, &address); - if (srst == 1) - jlink_simple_command(EMU_CMD_HW_RESET0); + if (ret == JAYLINK_ERR_NOT_SUPPORTED) { + continue; + } else if (ret != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_usb_address() failed: %s", + jaylink_strerror(ret)); + continue; + } - if (trst == 1) - jlink_simple_command(EMU_CMD_HW_TRST0); + if (usb_address != address) + continue; + } - if (trst == 0) - jlink_simple_command(EMU_CMD_HW_TRST1); -} + if (use_usb_location && !jlink_usb_location_equal(dev)) + continue; -static void jlink_simple_command(uint8_t command) -{ - int result; + ret = jaylink_open(dev, &devh); - DEBUG_JTAG_IO("0x%02x", command); + if (ret == JAYLINK_OK) { + *found_device = true; + break; + } - usb_out_buffer[0] = command; - result = jlink_usb_write(jlink_handle, 1); + LOG_ERROR("Failed to open device: %s", jaylink_strerror(ret)); + } - if (result != 1) - LOG_ERROR("J-Link command 0x%02x failed (%d)", command, result); + jaylink_free_devices(devs, true); + return ERROR_OK; } -static int jlink_get_status(void) + +static int jlink_init(void) { - int result; + int ret; + char *firmware_version; + struct jaylink_hardware_version hwver; + struct jaylink_hardware_status hwstatus; + size_t length; - jlink_simple_command(EMU_CMD_GET_STATE); + LOG_DEBUG("Using libjaylink %s (compiled with %s)", + jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); - result = jlink_usb_read(jlink_handle, 8); - if (result != 8) { - LOG_ERROR("J-Link command EMU_CMD_GET_STATE failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; + if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) { + LOG_ERROR("J-Link driver does not support USB devices"); + return ERROR_JTAG_INIT_FAILED; } - int vref = usb_in_buffer[0] + (usb_in_buffer[1] << 8); - LOG_INFO("Vref = %d.%d TCK = %d TDI = %d TDO = %d TMS = %d SRST = %d TRST = %d", \ - vref / 1000, vref % 1000, \ - usb_in_buffer[2], usb_in_buffer[3], usb_in_buffer[4], \ - usb_in_buffer[5], usb_in_buffer[6], usb_in_buffer[7]); + ret = jaylink_init(&jayctx); - if (vref < 1500) - LOG_ERROR("Vref too low. Check Target Power"); - - return ERROR_OK; -} + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_init() failed: %s", jaylink_strerror(ret)); + return ERROR_JTAG_INIT_FAILED; + } -#define jlink_dump_printf(context, expr ...) \ - do { \ - if (context) \ - command_print(context, expr); \ - else \ - LOG_INFO(expr); \ - } while (0); + ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL); -static void jlink_caps_dump(struct command_context *ctx) -{ - int i; + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_log_set_callback() failed: %s", + jaylink_strerror(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } - jlink_dump_printf(ctx, "J-Link Capabilities"); + const char *serial = adapter_get_required_serial(); + if (serial) { + ret = jaylink_parse_serial_number(serial, &serial_number); + if (ret == JAYLINK_ERR) { + LOG_ERROR("Invalid serial number: %s", serial); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_parse_serial_number() failed: %s", jaylink_strerror(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + use_serial_number = true; + use_usb_address = false; + } - for (i = 1; i < 31; i++) - if (jlink_caps & (1 << i)) - jlink_dump_printf(ctx, "%s", jlink_cap_str[i]); -} + bool found_device; + ret = jlink_open_device(JAYLINK_HIF_USB, &found_device); + if (ret != ERROR_OK) + return ret; -static void jlink_config_usb_address_dump(struct command_context *ctx, struct jlink_config *cfg) -{ - if (!cfg) - return; + if (!found_device && use_serial_number) { + ret = jlink_open_device(JAYLINK_HIF_TCP, &found_device); + if (ret != ERROR_OK) + return ret; + } - jlink_dump_printf(ctx, "USB-Address: 0x%x", cfg->usb_address); -} + if (!found_device) { + LOG_ERROR("No J-Link device found"); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } -static void jlink_config_kickstart_dump(struct command_context *ctx, struct jlink_config *cfg) -{ - if (!cfg) - return; + /* + * Be careful with changing the following initialization sequence because + * some devices are known to be sensitive regarding the order. + */ - jlink_dump_printf(ctx, "Kickstart power on JTAG-pin 19: 0x%" PRIx32, - cfg->kickstart_power_on_jtag_pin_19); -} + ret = jaylink_get_firmware_version(devh, &firmware_version, &length); -static void jlink_config_mac_address_dump(struct command_context *ctx, struct jlink_config *cfg) -{ - if (!cfg) - return; + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_firmware_version() failed: %s", + jaylink_strerror(ret)); + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } else if (length > 0) { + LOG_INFO("%s", firmware_version); + free(firmware_version); + } else { + LOG_WARNING("Device responds empty firmware version string"); + } + + memset(caps, 0, JAYLINK_DEV_EXT_CAPS_SIZE); + ret = jaylink_get_caps(devh, caps); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_caps() failed: %s", jaylink_strerror(ret)); + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_EXT_CAPS)) { + ret = jaylink_get_extended_caps(devh, caps); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_extended_caps() failed: %s", + jaylink_strerror(ret)); + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + } + + jtag_command_version = JAYLINK_JTAG_VERSION_2; + + if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_HW_VERSION)) { + ret = jaylink_get_hardware_version(devh, &hwver); + + if (ret != JAYLINK_OK) { + LOG_ERROR("Failed to retrieve hardware version: %s", + jaylink_strerror(ret)); + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("Hardware version: %u.%02u", hwver.major, hwver.minor); + + if (hwver.major >= 5) + jtag_command_version = JAYLINK_JTAG_VERSION_3; + } + + if (iface == JAYLINK_TIF_SWD) { + /* + * Adjust the SWD transaction buffer size in case there is already + * allocated memory on the device. This happens for example if the + * memory for SWO capturing is still allocated because the software + * which used the device before has not been shut down properly. + */ + if (!adjust_swd_buffer_size()) { + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + } + + if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { + if (!read_device_config(&config)) { + LOG_ERROR("Failed to read device configuration data"); + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + memcpy(&tmp_config, &config, sizeof(struct device_config)); + } + + ret = jaylink_get_hardware_status(devh, &hwstatus); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_hardware_status() failed: %s", + jaylink_strerror(ret)); + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("VTarget = %u.%03u V", hwstatus.target_voltage / 1000, + hwstatus.target_voltage % 1000); + + conn.handle = 0; + conn.pid = 0; + strcpy(conn.hid, "0.0.0.0"); + conn.iid = 0; + conn.cid = 0; - jlink_dump_printf(ctx, "MAC Address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x", - cfg->mac_address[5], cfg->mac_address[4], - cfg->mac_address[3], cfg->mac_address[2], - cfg->mac_address[1], cfg->mac_address[0]); + ret = jlink_register(); + + if (ret != ERROR_OK) { + jaylink_close(devh); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + ret = select_interface(); + + if (ret != ERROR_OK) { + jaylink_close(devh); + jaylink_exit(jayctx); + return ret; + } + + jlink_reset(0, 0); + jtag_sleep(3000); + jlink_tap_init(); + + jlink_speed(adapter_get_speed_khz()); + + if (iface == JAYLINK_TIF_JTAG) { + /* + * J-Link devices with firmware version v5 and v6 seems to have an issue + * if the first tap move is not divisible by 8, so we send a TLR on + * first power up. + */ + uint8_t tms = 0xff; + jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 8); + + jlink_flush(); + } + + return ERROR_OK; } -static void jlink_config_ip_dump(struct command_context *ctx, struct jlink_config *cfg) +static int jlink_quit(void) { - if (!cfg) - return; + int ret; + size_t count; - jlink_dump_printf(ctx, "IP Address: %d.%d.%d.%d", - cfg->ip_address[3], cfg->ip_address[2], - cfg->ip_address[1], cfg->ip_address[0]); - jlink_dump_printf(ctx, "Subnet Mask: %d.%d.%d.%d", - cfg->subnet_mask[3], cfg->subnet_mask[2], - cfg->subnet_mask[1], cfg->subnet_mask[0]); + if (trace_enabled) { + ret = jaylink_swo_stop(devh); + + if (ret != JAYLINK_OK) + LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret)); + } + + if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) { + ret = jaylink_unregister(devh, &conn, connlist, &count); + + if (ret != JAYLINK_OK) + LOG_ERROR("jaylink_unregister() failed: %s", + jaylink_strerror(ret)); + } + + jaylink_close(devh); + jaylink_exit(jayctx); + + return ERROR_OK; } -static void jlink_config_dump(struct command_context *ctx, struct jlink_config *cfg) +/***************************************************************************/ +/* Queue command implementations */ + +static void jlink_end_state(tap_state_t state) { - if (!cfg) - return; + if (tap_is_state_stable(state)) + tap_set_end_state(state); + else { + LOG_ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} - jlink_dump_printf(ctx, "J-Link configuration"); - jlink_config_usb_address_dump(ctx, cfg); - jlink_config_kickstart_dump(ctx, cfg); +/* Goes to the end state. */ +static void jlink_state_move(void) +{ + uint8_t tms_scan; + uint8_t tms_scan_bits; - if (jlink_hw_type == JLINK_HW_TYPE_JLINK_PRO) { - jlink_config_ip_dump(ctx, cfg); - jlink_config_mac_address_dump(ctx, cfg); - } + tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + jlink_clock_data(NULL, 0, &tms_scan, 0, NULL, 0, tms_scan_bits); + + tap_set_state(tap_get_end_state()); } -static int jlink_get_config(struct jlink_config *cfg) +static void jlink_path_move(int num_states, tap_state_t *path) { - int result; - int size = sizeof(struct jlink_config); + int i; + uint8_t tms = 0xff; - usb_out_buffer[0] = EMU_CMD_READ_CONFIG; - result = jlink_usb_io(jlink_handle, 1, size); + for (i = 0; i < num_states; i++) { + if (path[i] == tap_state_transition(tap_get_state(), false)) + jlink_clock_data(NULL, 0, NULL, 0, NULL, 0, 1); + else if (path[i] == tap_state_transition(tap_get_state(), true)) + jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1); + else { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", + tap_state_name(tap_get_state()), tap_state_name(path[i])); + exit(-1); + } - if (result != ERROR_OK) { - LOG_ERROR("jlink_usb_read failed (requested=%d, result=%d)", size, result); - return ERROR_FAIL; + tap_set_state(path[i]); } - memcpy(cfg, usb_in_buffer, size); - return ERROR_OK; + tap_set_end_state(tap_get_state()); } -static int jlink_set_config(struct jlink_config *cfg) +static void jlink_stableclocks(int num_cycles) { - int result; - int size = sizeof(struct jlink_config); + int i; - jlink_simple_command(EMU_CMD_WRITE_CONFIG); + uint8_t tms = tap_get_state() == TAP_RESET; + /* Execute num_cycles. */ + for (i = 0; i < num_cycles; i++) + jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1); +} - memcpy(usb_out_buffer, cfg, size); +static void jlink_runtest(int num_cycles) +{ + tap_state_t saved_end_state = tap_get_end_state(); - result = jlink_usb_write(jlink_handle, size); - if (result != size) { - LOG_ERROR("jlink_usb_write failed (requested=%d, result=%d)", 256, result); - return ERROR_FAIL; + /* Only do a state_move when we're not already in IDLE. */ + if (tap_get_state() != TAP_IDLE) { + jlink_end_state(TAP_IDLE); + jlink_state_move(); + /* num_cycles--; */ } - return ERROR_OK; + jlink_stableclocks(num_cycles); + + /* Finish in end_state. */ + jlink_end_state(saved_end_state); + + if (tap_get_state() != tap_get_end_state()) + jlink_state_move(); } -/* - * List of unsupported version string markers. - * - * The firmware versions does not correspond directly with - * "Software and documentation pack for Windows", it may be - * distinguished by the "compile" date in the information string. - * - * For example, version string is: - * "J-Link ARM V8 compiled May 3 2012 18:36:22" - * Marker sould be: - * "May 3 2012" - * - * The list must be terminated by NULL string. - */ -static const char * const unsupported_versions[] = { - "Jan 31 2011", - "JAN 31 2011", - NULL /* End of list */ -}; +static void jlink_reset(int trst, int srst) +{ + LOG_DEBUG("TRST: %i, SRST: %i", trst, srst); + + /* Signals are active low. */ + if (srst == 0) + jaylink_set_reset(devh); + + if (srst == 1) + jaylink_clear_reset(devh); -static void jlink_check_supported(const char *str) + if (trst == 1) + jaylink_jtag_clear_trst(devh); + + if (trst == 0) + jaylink_jtag_set_trst(devh); +} + +static int jlink_reset_safe(int trst, int srst) { - const char * const *p = unsupported_versions; - while (*p) { - if (NULL != strstr(str, *p)) { - LOG_WARNING( - "Unsupported J-Link firmware version.\n" - " Please check http://www.segger.com/j-link-older-versions.html for updates"); - return; - } - p++; - } + jlink_flush(); + jlink_reset(trst, srst); + return jlink_flush(); } -static int jlink_get_version_info(void) +COMMAND_HANDLER(jlink_usb_command) { - int result; - int len; - uint32_t jlink_max_size; + int tmp; - /* query hardware version */ - jlink_simple_command(EMU_CMD_VERSION); + if (CMD_ARGC != 1) { + command_print(CMD, "Need exactly one argument for jlink usb"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - result = jlink_usb_read(jlink_handle, 2); - if (2 != result) { - LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; + if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { + command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); + return ERROR_FAIL; } - len = buf_get_u32(usb_in_buffer, 0, 16); - if (len > JLINK_IN_BUFFER_SIZE) { - LOG_ERROR("J-Link command EMU_CMD_VERSION impossible return length 0x%0x", len); - len = JLINK_IN_BUFFER_SIZE; + if (tmp < JAYLINK_USB_ADDRESS_0 || tmp > JAYLINK_USB_ADDRESS_3) { + command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); + return ERROR_FAIL; } - result = jlink_usb_read(jlink_handle, len); - if (result != len) { - LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; + usb_address = tmp; + + use_usb_address = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(jlink_handle_hwstatus_command) +{ + int ret; + struct jaylink_hardware_status status; + + ret = jaylink_get_hardware_status(devh, &status); + + if (ret != JAYLINK_OK) { + command_print(CMD, "jaylink_get_hardware_status() failed: %s", + jaylink_strerror(ret)); + return ERROR_FAIL; } - usb_in_buffer[result] = 0; - LOG_INFO("%s", (char *)usb_in_buffer); - jlink_check_supported((char *)usb_in_buffer); + command_print(CMD, "VTarget = %u.%03u V", + status.target_voltage / 1000, status.target_voltage % 1000); - /* query hardware capabilities */ - jlink_simple_command(EMU_CMD_GET_CAPS); + command_print(CMD, "TCK = %u TDI = %u TDO = %u TMS = %u SRST = %u " + "TRST = %u", status.tck, status.tdi, status.tdo, status.tms, + status.tres, status.trst); - result = jlink_usb_read(jlink_handle, 4); - if (4 != result) { - LOG_ERROR("J-Link command EMU_CMD_GET_CAPS failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; + if (status.target_voltage < 1500) + command_print(CMD, "Target voltage too low. Check target power"); + + return ERROR_OK; +} + +COMMAND_HANDLER(jlink_handle_free_memory_command) +{ + int ret; + uint32_t tmp; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) { + command_print(CMD, "Retrieval of free memory is not supported by " + "the device"); + return ERROR_OK; } - jlink_caps = buf_get_u32(usb_in_buffer, 0, 32); - LOG_INFO("J-Link caps 0x%x", (unsigned)jlink_caps); + ret = jaylink_get_free_memory(devh, &tmp); - if (jlink_caps & (1 << EMU_CAP_GET_HW_VERSION)) { - /* query hardware version */ - jlink_simple_command(EMU_CMD_GET_HW_VERSION); + if (ret != JAYLINK_OK) { + command_print(CMD, "jaylink_get_free_memory() failed: %s", + jaylink_strerror(ret)); + return ERROR_FAIL; + } - result = jlink_usb_read(jlink_handle, 4); - if (4 != result) { - LOG_ERROR("J-Link command EMU_CMD_GET_HW_VERSION failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; - } + command_print(CMD, "Device has %" PRIu32 " bytes of free memory", tmp); - uint32_t jlink_hw_version = buf_get_u32(usb_in_buffer, 0, 32); - uint32_t major_revision = (jlink_hw_version / 10000) % 100; - jlink_hw_type = (jlink_hw_version / 1000000) % 100; - if (major_revision >= 5) - jlink_hw_jtag_version = 3; + return ERROR_OK; +} - LOG_INFO("J-Link hw version %i", (int)jlink_hw_version); +COMMAND_HANDLER(jlink_handle_jlink_jtag_command) +{ + int tmp; + int version; - switch (jlink_hw_type) { - case JLINK_HW_TYPE_JLINK: - LOG_INFO("J-Link hw type J-Link"); + if (!CMD_ARGC) { + switch (jtag_command_version) { + case JAYLINK_JTAG_VERSION_2: + version = 2; break; - case JLINK_HW_TYPE_JTRACE: - LOG_INFO("J-Link hw type J-Trace"); + case JAYLINK_JTAG_VERSION_3: + version = 3; 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"); + default: + return ERROR_FAIL; + } + + command_print(CMD, "JTAG command version: %i", version); + } else if (CMD_ARGC == 1) { + if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + switch (tmp) { + case 2: + jtag_command_version = JAYLINK_JTAG_VERSION_2; break; - case JLINK_HW_TYPE_LPCLINK2: - LOG_INFO("J-Link hw type J-Link on LPC-Link2"); + case 3: + jtag_command_version = JAYLINK_JTAG_VERSION_3; break; default: - LOG_INFO("J-Link hw type unknown 0x%" PRIx32, jlink_hw_type); - break; + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; } + } else { + command_print(CMD, "Need exactly one argument for jlink jtag"); + return ERROR_COMMAND_SYNTAX_ERROR; } - if (jlink_caps & (1 << EMU_CAP_GET_MAX_BLOCK_SIZE)) { - /* query hardware maximum memory block */ - jlink_simple_command(EMU_CMD_GET_MAX_MEM_BLOCK); + return ERROR_OK; +} - result = jlink_usb_read(jlink_handle, 4); - if (4 != result) { - LOG_ERROR("J-Link command EMU_CMD_GET_MAX_MEM_BLOCK failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; - } +COMMAND_HANDLER(jlink_handle_target_power_command) +{ + int ret; + int enable; + + if (CMD_ARGC != 1) { + command_print(CMD, "Need exactly one argument for jlink targetpower"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - jlink_max_size = buf_get_u32(usb_in_buffer, 0, 32); - LOG_INFO("J-Link max mem block %i", (int)jlink_max_size); + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) { + command_print(CMD, "Target power supply is not supported by the " + "device"); + return ERROR_OK; } - if (jlink_caps & (1 << EMU_CAP_READ_CONFIG)) { - if (jlink_get_config(&jlink_cfg) != ERROR_OK) - return ERROR_JTAG_DEVICE_ERROR; + if (!strcmp(CMD_ARGV[0], "on")) { + enable = true; + } else if (!strcmp(CMD_ARGV[0], "off")) { + enable = false; + } else { + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + return ERROR_FAIL; + } + + ret = jaylink_set_target_power(devh, enable); - jlink_config_dump(NULL, &jlink_cfg); + if (ret != JAYLINK_OK) { + command_print(CMD, "jaylink_set_target_power() failed: %s", + jaylink_strerror(ret)); + return ERROR_FAIL; } return ERROR_OK; } -COMMAND_HANDLER(jlink_pid_command) +static void show_config_usb_address(struct command_invocation *cmd) { - if (CMD_ARGC != 1) { - LOG_ERROR("Need exactly one argument to jlink_pid"); + if (config.usb_address != tmp_config.usb_address) + command_print(cmd, "USB address: %u [%u]", config.usb_address, + tmp_config.usb_address); + else + command_print(cmd, "USB address: %u", config.usb_address); +} + +static void show_config_ip_address(struct command_invocation *cmd) +{ + if (!memcmp(config.ip_address, tmp_config.ip_address, 4)) + command_print(cmd, "IP address: %d.%d.%d.%d", + config.ip_address[3], config.ip_address[2], + config.ip_address[1], config.ip_address[0]); + else + command_print(cmd, "IP address: %d.%d.%d.%d [%d.%d.%d.%d]", + config.ip_address[3], config.ip_address[2], + config.ip_address[1], config.ip_address[0], + tmp_config.ip_address[3], tmp_config.ip_address[2], + tmp_config.ip_address[1], tmp_config.ip_address[0]); + + if (!memcmp(config.subnet_mask, tmp_config.subnet_mask, 4)) + command_print(cmd, "Subnet mask: %d.%d.%d.%d", + config.subnet_mask[3], config.subnet_mask[2], + config.subnet_mask[1], config.subnet_mask[0]); + else + command_print(cmd, "Subnet mask: %d.%d.%d.%d [%d.%d.%d.%d]", + config.subnet_mask[3], config.subnet_mask[2], + config.subnet_mask[1], config.subnet_mask[0], + tmp_config.subnet_mask[3], tmp_config.subnet_mask[2], + tmp_config.subnet_mask[1], tmp_config.subnet_mask[0]); +} + +static void show_config_mac_address(struct command_invocation *cmd) +{ + if (!memcmp(config.mac_address, tmp_config.mac_address, 6)) + command_print(cmd, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x", + config.mac_address[5], config.mac_address[4], + config.mac_address[3], config.mac_address[2], + config.mac_address[1], config.mac_address[0]); + else + command_print(cmd, "MAC address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x " + "[%.02x:%.02x:%.02x:%.02x:%.02x:%.02x]", + config.mac_address[5], config.mac_address[4], + config.mac_address[3], config.mac_address[2], + config.mac_address[1], config.mac_address[0], + tmp_config.mac_address[5], tmp_config.mac_address[4], + tmp_config.mac_address[3], tmp_config.mac_address[2], + tmp_config.mac_address[1], tmp_config.mac_address[0]); +} + +static void show_config_target_power(struct command_invocation *cmd) +{ + const char *target_power; + const char *current_target_power; + + if (!config.target_power) + target_power = "off"; + else + target_power = "on"; + + if (!tmp_config.target_power) + current_target_power = "off"; + else + current_target_power = "on"; + + if (config.target_power != tmp_config.target_power) + command_print(cmd, "Target power supply: %s [%s]", target_power, + current_target_power); + else + command_print(cmd, "Target power supply: %s", target_power); +} + +static void show_config(struct command_invocation *cmd) +{ + command_print(cmd, "J-Link device configuration:"); + + show_config_usb_address(cmd); + + if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) + show_config_target_power(cmd); + + if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { + show_config_ip_address(cmd); + show_config_mac_address(cmd); + } +} + +static int poll_trace(uint8_t *buf, size_t *size) +{ + int ret; + uint32_t length; + + length = *size; + + ret = jaylink_swo_read(devh, buf, &length); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_swo_read() failed: %s", jaylink_strerror(ret)); return ERROR_FAIL; } - pids[0] = strtoul(CMD_ARGV[0], NULL, 16); - pids[1] = 0; - vids[1] = 0; + *size = length; return ERROR_OK; } -COMMAND_HANDLER(jlink_serial_command) +static uint32_t calculate_trace_buffer_size(void) { - if (CMD_ARGC != 1) { - LOG_ERROR("Need exactly one argument to jlink_serial"); + int ret; + uint32_t tmp; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_FREE_MEMORY)) + return 0; + + ret = jaylink_get_free_memory(devh, &tmp); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_free_memory() failed: %s", + jaylink_strerror(ret)); return ERROR_FAIL; } - if (jlink_serial) - free(jlink_serial); - jlink_serial = strdup(CMD_ARGV[0]); - return ERROR_OK; + if (tmp > 0x3fff || tmp <= 0x600) + tmp = tmp >> 1; + else + tmp = tmp - 0x400; + + return tmp & 0xffffff00; +} + +static bool calculate_swo_prescaler(unsigned int traceclkin_freq, + uint32_t trace_freq, uint16_t *prescaler) +{ + unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq; + if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) + return false; + + /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ + unsigned int max_deviation = (traceclkin_freq * 3) / 100; + if (presc * trace_freq < traceclkin_freq - max_deviation || + presc * trace_freq > traceclkin_freq + max_deviation) + return false; + + *prescaler = presc; + + return true; } -COMMAND_HANDLER(jlink_handle_jlink_info_command) +static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed, + unsigned int traceclkin_freq, unsigned int *trace_freq, + uint16_t *prescaler) { - if (jlink_get_version_info() == ERROR_OK) { - /* attempt to get status */ - jlink_get_status(); + uint32_t divider; + unsigned int presc; + double deviation; + + for (divider = speed.min_div; divider <= speed.max_div; divider++) { + *trace_freq = speed.freq / divider; + presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1; + + if (presc > TPIU_ACPR_MAX_SWOSCALER + 1) + break; + + deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq)); + + if (deviation <= SWO_MAX_FREQ_DEV) { + *prescaler = presc; + return true; + } } - return ERROR_OK; + return false; } -COMMAND_HANDLER(jlink_handle_jlink_caps_command) +static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, + uint32_t port_size, unsigned int *trace_freq, + unsigned int traceclkin_freq, uint16_t *prescaler) { - jlink_caps_dump(CMD_CTX); + int ret; + uint32_t buffer_size; + struct jaylink_swo_speed speed; + uint32_t divider; + uint32_t min_freq; + uint32_t max_freq; + + trace_enabled = enabled; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) { + if (!enabled) + return ERROR_OK; + + LOG_ERROR("Trace capturing is not supported by the device"); + return ERROR_FAIL; + } + + ret = jaylink_swo_stop(devh); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_swo_stop() failed: %s", jaylink_strerror(ret)); + return ERROR_FAIL; + } + + if (!enabled) { + /* + * Adjust the SWD transaction buffer size as stopping SWO capturing + * deallocates device internal memory. + */ + if (!adjust_swd_buffer_size()) + return ERROR_FAIL; + + return ERROR_OK; + } + + if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) { + LOG_ERROR("Selected pin protocol is not supported"); + return ERROR_FAIL; + } + + buffer_size = calculate_trace_buffer_size(); + + if (!buffer_size) { + LOG_ERROR("Not enough free device memory to start trace capturing"); + return ERROR_FAIL; + } + + ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &speed); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_swo_get_speeds() failed: %s", + jaylink_strerror(ret)); + return ERROR_FAIL; + } + + if (*trace_freq > 0) { + divider = speed.freq / *trace_freq; + min_freq = speed.freq / speed.max_div; + max_freq = speed.freq / speed.min_div; + + if (*trace_freq > max_freq) { + LOG_INFO("Given SWO frequency too high, using %" PRIu32 " Hz instead", + max_freq); + *trace_freq = max_freq; + } else if (*trace_freq < min_freq) { + LOG_INFO("Given SWO frequency too low, using %" PRIu32 " Hz instead", + min_freq); + *trace_freq = min_freq; + } else if (*trace_freq != speed.freq / divider) { + *trace_freq = speed.freq / divider; + + LOG_INFO("Given SWO frequency is not supported by the device, " + "using %u Hz instead", *trace_freq); + } + + if (!calculate_swo_prescaler(traceclkin_freq, *trace_freq, + prescaler)) { + LOG_ERROR("SWO frequency is not suitable. Please choose a " + "different frequency or use auto-detection"); + return ERROR_FAIL; + } + } else { + LOG_INFO("Trying to auto-detect SWO frequency"); + + if (!detect_swo_freq_and_prescaler(speed, traceclkin_freq, trace_freq, + prescaler)) { + LOG_ERROR("Maximum permitted frequency deviation of %.02f %% " + "could not be achieved", SWO_MAX_FREQ_DEV); + LOG_ERROR("Auto-detection of SWO frequency failed"); + return ERROR_FAIL; + } + + LOG_INFO("Using SWO frequency of %u Hz", *trace_freq); + } + + ret = jaylink_swo_start(devh, JAYLINK_SWO_MODE_UART, *trace_freq, + buffer_size); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_start_swo() failed: %s", jaylink_strerror(ret)); + return ERROR_FAIL; + } + + LOG_DEBUG("Using %" PRIu32 " bytes device memory for trace capturing", + buffer_size); + + /* + * Adjust the SWD transaction buffer size as starting SWO capturing + * allocates device internal memory. + */ + if (!adjust_swd_buffer_size()) + return ERROR_FAIL; return ERROR_OK; } -COMMAND_HANDLER(jlink_handle_jlink_hw_jtag_command) +COMMAND_HANDLER(jlink_handle_config_usb_address_command) { - switch (CMD_ARGC) { - case 0: - command_print(CMD_CTX, "J-Link hw jtag %i", jlink_hw_jtag_version); - break; - case 1: { - int request_version = atoi(CMD_ARGV[0]); - switch (request_version) { - case 2: - case 3: - jlink_hw_jtag_version = request_version; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - break; + uint8_t tmp; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { + command_print(CMD, "Reading configuration is not supported by the " + "device"); + return ERROR_OK; + } + + if (!CMD_ARGC) { + show_config_usb_address(CMD); + } else if (CMD_ARGC == 1) { + if (sscanf(CMD_ARGV[0], "%" SCNd8, &tmp) != 1) { + command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); + return ERROR_FAIL; } - default: - return ERROR_COMMAND_SYNTAX_ERROR; + + if (tmp > JAYLINK_USB_ADDRESS_3) { + command_print(CMD, "Invalid USB address: %u", tmp); + return ERROR_FAIL; + } + + tmp_config.usb_address = tmp; + } else { + command_print(CMD, "Need exactly one argument for jlink config usb"); + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } -COMMAND_HANDLER(jlink_handle_jlink_kickstart_command) +COMMAND_HANDLER(jlink_handle_config_target_power_command) { - uint32_t kickstart; + int enable; - if (CMD_ARGC < 1) { - jlink_config_kickstart_dump(CMD_CTX, &jlink_cfg); + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { + command_print(CMD, "Reading configuration is not supported by the " + "device"); return ERROR_OK; } - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], kickstart); + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) { + command_print(CMD, "Target power supply is not supported by the " + "device"); + return ERROR_OK; + } + + if (!CMD_ARGC) { + show_config_target_power(CMD); + } else if (CMD_ARGC == 1) { + if (!strcmp(CMD_ARGV[0], "on")) { + enable = true; + } else if (!strcmp(CMD_ARGV[0], "off")) { + enable = false; + } else { + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + return ERROR_FAIL; + } + + tmp_config.target_power = enable; + } else { + command_print(CMD, "Need exactly one argument for jlink config " + "targetpower"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - jlink_cfg.kickstart_power_on_jtag_pin_19 = kickstart; return ERROR_OK; } -COMMAND_HANDLER(jlink_handle_jlink_mac_address_command) +COMMAND_HANDLER(jlink_handle_config_mac_address_command) { uint8_t addr[6]; int i; char *e; const char *str; - if (CMD_ARGC < 1) { - jlink_config_mac_address_dump(CMD_CTX, &jlink_cfg); + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { + command_print(CMD, "Reading configuration is not supported by the " + "device"); return ERROR_OK; } - str = CMD_ARGV[0]; - - if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || str[8] != ':' || - str[11] != ':' || str[14] != ':')) { - command_print(CMD_CTX, "ethaddr miss format ff:ff:ff:ff:ff:ff"); - return ERROR_COMMAND_SYNTAX_ERROR; + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { + command_print(CMD, "Ethernet connectivity is not supported by the " + "device"); + return ERROR_OK; } - for (i = 5; i >= 0; i--) { - addr[i] = strtoul(str, &e, 16); - str = e + 1; - } + if (!CMD_ARGC) { + show_config_mac_address(CMD); + } else if (CMD_ARGC == 1) { + str = CMD_ARGV[0]; - if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) { - command_print(CMD_CTX, "invalid it's zero mac_address"); - return ERROR_COMMAND_SYNTAX_ERROR; - } + if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || + str[8] != ':' || str[11] != ':' || str[14] != ':')) { + command_print(CMD, "Invalid MAC address format"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + for (i = 5; i >= 0; i--) { + addr[i] = strtoul(str, &e, 16); + str = e + 1; + } - if (!(0x01 & addr[0])) { - command_print(CMD_CTX, "invalid it's a multicat mac_address"); + if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) { + command_print(CMD, "Invalid MAC address: zero address"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (!(0x01 & addr[0])) { + command_print(CMD, "Invalid MAC address: multicast address"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + memcpy(tmp_config.mac_address, addr, sizeof(addr)); + } else { + command_print(CMD, "Need exactly one argument for jlink config mac"); return ERROR_COMMAND_SYNTAX_ERROR; } - memcpy(jlink_cfg.mac_address, addr, sizeof(addr)); - return ERROR_OK; } -static int string_to_ip(const char *s, uint8_t *ip, int *pos) +static bool string_to_ip(const char *s, uint8_t *ip, int *pos) { uint8_t lip[4]; char *e; const char *s_save = s; int i; - if (!s) - return -EINVAL; + if (!s) + return false; + + for (i = 0; i < 4; i++) { + lip[i] = strtoul(s, &e, 10); + + if (*e != '.' && i != 3) + return false; + + s = e + 1; + } + + *pos = e - s_save; + memcpy(ip, lip, sizeof(lip)); + + return true; +} + +static void cpy_ip(uint8_t *dst, uint8_t *src) +{ + int i, j; + + for (i = 0, j = 3; i < 4; i++, j--) + dst[i] = src[j]; +} + +COMMAND_HANDLER(jlink_handle_config_ip_address_command) +{ + uint8_t ip_address[4]; + uint32_t subnet_mask = 0; + int i, len; + uint8_t subnet_bits = 24; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { + command_print(CMD, "Reading configuration is not supported by the " + "device"); + return ERROR_OK; + } + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_ETHERNET)) { + command_print(CMD, "Ethernet connectivity is not supported by the " + "device"); + return ERROR_OK; + } + + if (!CMD_ARGC) { + show_config_ip_address(CMD); + } else { + if (!string_to_ip(CMD_ARGV[0], ip_address, &i)) + return ERROR_COMMAND_SYNTAX_ERROR; + + len = strlen(CMD_ARGV[0]); + + /* Check for format A.B.C.D/E. */ + if (i < len) { + if (CMD_ARGV[0][i] != '/') + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0] + i + 1, subnet_bits); + } else if (CMD_ARGC > 1) { + if (!string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i)) + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (!subnet_mask) + subnet_mask = (uint32_t)(subnet_bits < 32 ? + ((1ULL << subnet_bits) - 1) : 0xffffffff); + + cpy_ip(tmp_config.ip_address, ip_address); + cpy_ip(tmp_config.subnet_mask, (uint8_t *)&subnet_mask); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(jlink_handle_config_reset_command) +{ + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) + return ERROR_OK; + + memcpy(&tmp_config, &config, sizeof(struct device_config)); + + return ERROR_OK; +} + + +COMMAND_HANDLER(jlink_handle_config_write_command) +{ + int ret; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { + command_print(CMD, "Reading configuration is not supported by the " + "device"); + return ERROR_OK; + } + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_WRITE_CONFIG)) { + command_print(CMD, "Writing configuration is not supported by the " + "device"); + return ERROR_OK; + } + + if (!memcmp(&config, &tmp_config, sizeof(struct device_config))) { + command_print(CMD, "Operation not performed due to no changes in " + "the configuration"); + return ERROR_OK; + } + + ret = jaylink_write_raw_config(devh, (const uint8_t *)&tmp_config); - for (i = 0; i < 4; i++) { - lip[i] = strtoul(s, &e, 10); + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_write_raw_config() failed: %s", + jaylink_strerror(ret)); + return ERROR_FAIL; + } - if (*e != '.' && i != 3) - return -EINVAL; + if (!read_device_config(&config)) { + LOG_ERROR("Failed to read device configuration for verification"); + return ERROR_FAIL; + } - s = e + 1; + if (memcmp(&config, &tmp_config, sizeof(struct device_config))) { + LOG_ERROR("Verification of device configuration failed. Please check " + "your device"); + return ERROR_FAIL; } - *pos = e - s_save; + memcpy(&tmp_config, &config, sizeof(struct device_config)); + command_print(CMD, "The new device configuration applies after power " + "cycling the J-Link device"); - memcpy(ip, lip, sizeof(lip)); return ERROR_OK; } -static void cpy_ip(uint8_t *dst, uint8_t *src) +COMMAND_HANDLER(jlink_handle_config_command) { - int i, j; + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { + command_print(CMD, "Device doesn't support reading configuration"); + return ERROR_OK; + } - for (i = 0, j = 3; i < 4; i++, j--) - dst[i] = src[j]; + if (CMD_ARGC == 0) + show_config(CMD); + + return ERROR_OK; } -COMMAND_HANDLER(jlink_handle_jlink_ip_command) +COMMAND_HANDLER(jlink_handle_emucom_write_command) { - uint32_t ip_address; - uint32_t subnet_mask = 0; - int i, len; int ret; - uint8_t subnet_bits = 24; + size_t tmp; + uint32_t channel; + uint32_t length; + uint8_t *buf; + size_t dummy; - if (CMD_ARGC < 1) { - jlink_config_ip_dump(CMD_CTX, &jlink_cfg); - return ERROR_OK; + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { + LOG_ERROR("Device does not support EMUCOM"); + return ERROR_FAIL; } - ret = string_to_ip(CMD_ARGV[0], (uint8_t *)&ip_address, &i); - if (ret != ERROR_OK) - return ret; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel); - len = strlen(CMD_ARGV[0]); + tmp = strlen(CMD_ARGV[1]); - /* check for this format A.B.C.D/E */ + if (tmp % 2 != 0) { + LOG_ERROR("Data must be encoded as hexadecimal pairs"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - if (i < len) { - if (CMD_ARGV[0][i] != '/') - return ERROR_COMMAND_SYNTAX_ERROR; + buf = malloc(tmp / 2); - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0] + i + 1, subnet_bits); - } else { - if (CMD_ARGC > 1) { - ret = string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i); - if (ret != ERROR_OK) - return ret; - } + if (!buf) { + LOG_ERROR("Failed to allocate buffer"); + return ERROR_FAIL; } - if (!subnet_mask) - subnet_mask = (uint32_t)(subnet_bits < 32 ? - ((1ULL << subnet_bits) - 1) : 0xffffffff); + dummy = unhexify(buf, CMD_ARGV[1], tmp / 2); - cpy_ip(jlink_cfg.ip_address, (uint8_t *)&ip_address); - cpy_ip(jlink_cfg.subnet_mask, (uint8_t *)&subnet_mask); + if (dummy != (tmp / 2)) { + LOG_ERROR("Data must be encoded as hexadecimal pairs"); + free(buf); + return ERROR_COMMAND_ARGUMENT_INVALID; + } - return ERROR_OK; -} + length = tmp / 2; + ret = jaylink_emucom_write(devh, channel, buf, &length); -COMMAND_HANDLER(jlink_handle_jlink_reset_command) -{ - memset(&jlink_cfg, 0xff, sizeof(jlink_cfg)); - return ERROR_OK; -} + free(buf); -COMMAND_HANDLER(jlink_handle_jlink_save_command) -{ - if (!(jlink_caps & (1 << EMU_CAP_WRITE_CONFIG))) { - command_print(CMD_CTX, "J-Link write emulator configuration not supported"); - return ERROR_OK; + if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { + LOG_ERROR("Channel not supported by the device"); + return ERROR_FAIL; + } else if (ret != JAYLINK_OK) { + LOG_ERROR("Failed to write to channel: %s", jaylink_strerror(ret)); + return ERROR_FAIL; } - command_print(CMD_CTX, "The J-Link need to be unpluged and repluged ta have the config effective"); - return jlink_set_config(&jlink_cfg); + if (length != (tmp / 2)) + LOG_WARNING("Only %" PRIu32 " bytes written to the channel", length); + + return ERROR_OK; } -COMMAND_HANDLER(jlink_handle_jlink_usb_address_command) +COMMAND_HANDLER(jlink_handle_emucom_read_command) { - uint32_t address; + int ret; + uint32_t channel; + uint32_t length; + uint8_t *buf; + size_t tmp; - if (CMD_ARGC < 1) { - jlink_config_usb_address_dump(CMD_CTX, &jlink_cfg); - return ERROR_OK; + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { + LOG_ERROR("Device does not support EMUCOM"); + return ERROR_FAIL; } - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - if (address > 0x3 && address != 0xff) { - command_print(CMD_CTX, "USB Address must be between 0x00 and 0x03 or 0xff"); - return ERROR_COMMAND_SYNTAX_ERROR; - } + buf = malloc(length * 3 + 1); - jlink_cfg.usb_address = address; - return ERROR_OK; -} + if (!buf) { + LOG_ERROR("Failed to allocate buffer"); + return ERROR_FAIL; + } -COMMAND_HANDLER(jlink_handle_jlink_config_command) -{ - struct jlink_config cfg; - int ret = ERROR_OK; + ret = jaylink_emucom_read(devh, channel, buf, &length); - if (CMD_ARGC == 0) { - if (!(jlink_caps & (1 << EMU_CAP_READ_CONFIG))) { - command_print(CMD_CTX, "J-Link read emulator configuration not supported"); - goto exit; - } + if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { + LOG_ERROR("Channel is not supported by the device"); + free(buf); + return ERROR_FAIL; + } else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) { + LOG_ERROR("Channel is not available for the requested amount of data. " + "%" PRIu32 " bytes are available", length); + free(buf); + return ERROR_FAIL; + } else if (ret != JAYLINK_OK) { + LOG_ERROR("Failed to read from channel: %s", jaylink_strerror(ret)); + free(buf); + return ERROR_FAIL; + } - ret = jlink_get_config(&cfg); + tmp = hexify((char *)buf + length, buf, length, 2 * length + 1); - if (ret != ERROR_OK) - command_print(CMD_CTX, "J-Link read emulator configuration failled"); - else - jlink_config_dump(CMD_CTX, &jlink_cfg); + if (tmp != 2 * length) { + LOG_ERROR("Failed to convert data into hexadecimal string"); + free(buf); + return ERROR_FAIL; } -exit: - return ret; + command_print(CMD, "%s", buf + length); + free(buf); + + return ERROR_OK; } static const struct command_registration jlink_config_subcommand_handlers[] = { { - .name = "kickstart", - .handler = &jlink_handle_jlink_kickstart_command, + .name = "usb", + .handler = &jlink_handle_config_usb_address_command, + .mode = COMMAND_EXEC, + .help = "set the USB address", + .usage = "[0-3]", + }, + { + .name = "targetpower", + .handler = &jlink_handle_config_target_power_command, .mode = COMMAND_EXEC, - .help = "set Kickstart power on JTAG-pin 19.", - .usage = "[val]", + .help = "set the target power supply", + .usage = "[on|off]" }, { - .name = "mac_address", - .handler = &jlink_handle_jlink_mac_address_command, + .name = "mac", + .handler = &jlink_handle_config_mac_address_command, .mode = COMMAND_EXEC, .help = "set the MAC Address", .usage = "[ff:ff:ff:ff:ff:ff]", }, { .name = "ip", - .handler = &jlink_handle_jlink_ip_command, + .handler = &jlink_handle_config_ip_address_command, .mode = COMMAND_EXEC, - .help = "set the ip address of the J-Link Pro, " - "where A.B.C.D is the ip, " - "E the bit of the subnet mask, " - "F.G.H.I the subnet mask", + .help = "set the IP address, where A.B.C.D is the IP address, " + "E the bit of the subnet mask, F.G.H.I the subnet mask", .usage = "[A.B.C.D[/E] [F.G.H.I]]", }, { .name = "reset", - .handler = &jlink_handle_jlink_reset_command, + .handler = &jlink_handle_config_reset_command, + .mode = COMMAND_EXEC, + .help = "undo configuration changes", + .usage = "", + }, + { + .name = "write", + .handler = &jlink_handle_config_write_command, .mode = COMMAND_EXEC, - .help = "reset the current config", + .help = "write configuration to the device", + .usage = "", }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration jlink_emucom_subcommand_handlers[] = { { - .name = "save", - .handler = &jlink_handle_jlink_save_command, + .name = "write", + .handler = &jlink_handle_emucom_write_command, .mode = COMMAND_EXEC, - .help = "save the current config", + .help = "write to a channel", + .usage = " ", }, { - .name = "usb_address", - .handler = &jlink_handle_jlink_usb_address_command, + .name = "read", + .handler = &jlink_handle_emucom_read_command, .mode = COMMAND_EXEC, - .help = "set the USB-Address, " - "This will change the product id", - .usage = "[0x00 to 0x03 or 0xff]", + .help = "read from a channel", + .usage = " " }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jlink_subcommand_handlers[] = { { - .name = "caps", - .handler = &jlink_handle_jlink_caps_command, + .name = "jtag", + .handler = &jlink_handle_jlink_jtag_command, .mode = COMMAND_EXEC, - .help = "show jlink capabilities", + .help = "select the JTAG command version", + .usage = "[2|3]", }, { - .name = "info", - .handler = &jlink_handle_jlink_info_command, + .name = "targetpower", + .handler = &jlink_handle_target_power_command, .mode = COMMAND_EXEC, - .help = "show jlink info", + .help = "set the target power supply", + .usage = "" }, { - .name = "hw_jtag", - .handler = &jlink_handle_jlink_hw_jtag_command, + .name = "freemem", + .handler = &jlink_handle_free_memory_command, .mode = COMMAND_EXEC, - .help = "access J-Link HW JTAG command version", - .usage = "[2|3]", + .help = "show free device memory", + .usage = "", }, { - .name = "config", - .handler = &jlink_handle_jlink_config_command, + .name = "hwstatus", + .handler = &jlink_handle_hwstatus_command, .mode = COMMAND_EXEC, - .help = "access J-Link configuration, " - "if no argument this will dump the config", - .chain = jlink_config_subcommand_handlers, + .help = "show the hardware status", + .usage = "", }, { - .name = "pid", - .handler = &jlink_pid_command, + .name = "usb", + .handler = &jlink_usb_command, .mode = COMMAND_CONFIG, - .help = "set the pid of the interface we want to use", + .help = "set the USB address of the device that should be used", + .usage = "<0-3>" }, { - .name = "serial", - .handler = &jlink_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the J-Link adapter we want to use" + .name = "config", + .handler = &jlink_handle_config_command, + .mode = COMMAND_EXEC, + .help = "access the device configuration. If no argument is given " + "this will show the device configuration", + .chain = jlink_config_subcommand_handlers, + .usage = "[]", + }, + { + .name = "emucom", + .mode = COMMAND_EXEC, + .help = "access EMUCOM channel", + .chain = jlink_emucom_subcommand_handlers, + .usage = "", }, COMMAND_REGISTRATION_DONE }; @@ -1365,67 +1947,33 @@ static const struct command_registration jlink_command_handlers[] = { .mode = COMMAND_ANY, .help = "perform jlink management", .chain = jlink_subcommand_handlers, + .usage = "", }, COMMAND_REGISTRATION_DONE }; static int jlink_swd_init(void) { - LOG_INFO("JLink SWD mode enabled"); - swd_mode = true; + iface = JAYLINK_TIF_SWD; 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) +static void jlink_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { - assert(cmd & SWD_CMD_RnW); - jlink_swd_queue_cmd(dap, cmd, value, 0); + assert(!(cmd & SWD_CMD_RNW)); + jlink_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); } -static int_least32_t jlink_swd_frequency(struct adiv5_dap *dap, int_least32_t hz) +static void jlink_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { - if (hz > 0) - jlink_speed(hz / 1000); - - return hz; + assert(cmd & SWD_CMD_RNW); + jlink_swd_queue_cmd(cmd, value, 0, ap_delay_clk); } -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 = jlink_transports, - .swd = &jlink_swd, - - .execute_queue = jlink_execute_queue, - .speed = jlink_speed, - .speed_div = jlink_speed_div, - .khz = jlink_khz, - .init = jlink_init, - .quit = jlink_quit, -}; - /***************************************************************************/ /* J-Link tap functions */ - static unsigned tap_length; /* In SWD mode use tms buffer for direction control */ static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE]; @@ -1433,10 +1981,14 @@ static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[JLINK_TAP_BUFFER_SIZE]; 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 */ + /** First bit position in tdo_buffer to read. */ + unsigned first; + /** Number of bits to read. */ + unsigned length; + /** Location to store the result */ void *buffer; + /** Offset in the destination buffer */ + unsigned buffer_offset; }; #define MAX_PENDING_SCAN_RESULTS 256 @@ -1448,136 +2000,83 @@ static void jlink_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; + memset(tms_buffer, 0, sizeof(tms_buffer)); + memset(tdi_buffer, 0, sizeof(tdi_buffer)); } -static void jlink_tap_ensure_space(int scans, int bits) -{ - int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; - int available_bits = JLINK_TAP_BUFFER_SIZE * 8 - tap_length - 32; - - if (scans > available_scans || bits > available_bits) - jlink_tap_execute(); -} - -static void jlink_tap_append_step(int tms, int tdi) +static void jlink_clock_data(const uint8_t *out, unsigned out_offset, + const uint8_t *tms_out, unsigned tms_offset, + uint8_t *in, unsigned in_offset, + unsigned length) { - int index_var = tap_length / 8; - - assert(index_var < JLINK_TAP_BUFFER_SIZE); - - int bit_index = tap_length % 8; - uint8_t bit = 1 << bit_index; + do { + unsigned available_length = JLINK_TAP_BUFFER_SIZE - tap_length / 8; - /* we do not pad TMS, so be sure to initialize all bits */ - if (0 == bit_index) - tms_buffer[index_var] = tdi_buffer[index_var] = 0; - - if (tms) - tms_buffer[index_var] |= bit; - else - tms_buffer[index_var] &= ~bit; + if (!available_length || + (in && pending_scan_results_length == MAX_PENDING_SCAN_RESULTS)) { + if (jlink_flush() != ERROR_OK) + return; + available_length = JLINK_TAP_BUFFER_SIZE; + } - if (tdi) - tdi_buffer[index_var] |= bit; - else - tdi_buffer[index_var] &= ~bit; + struct pending_scan_result *pending_scan_result = + &pending_scan_results_buffer[pending_scan_results_length]; - tap_length++; -} + unsigned scan_length = length > available_length ? + available_length : length; -static void jlink_tap_append_scan(int length, uint8_t *buffer, - struct scan_command *command) -{ - struct pending_scan_result *pending_scan_result = - &pending_scan_results_buffer[pending_scan_results_length]; - int i; + if (out) + buf_set_buf(out, out_offset, tdi_buffer, tap_length, scan_length); + if (tms_out) + buf_set_buf(tms_out, tms_offset, tms_buffer, tap_length, scan_length); - pending_scan_result->first = tap_length; - pending_scan_result->length = length; - pending_scan_result->command = command; - pending_scan_result->buffer = buffer; + if (in) { + pending_scan_result->first = tap_length; + pending_scan_result->length = scan_length; + pending_scan_result->buffer = in; + pending_scan_result->buffer_offset = in_offset; + pending_scan_results_length++; + } - for (i = 0; i < length; i++) { - int tms = (i < (length - 1)) ? 0 : 1; - int tdi = (buffer[i / 8] & (1 << (i % 8))) != 0; - jlink_tap_append_step(tms, tdi); - } - pending_scan_results_length++; + tap_length += scan_length; + out_offset += scan_length; + tms_offset += scan_length; + in_offset += scan_length; + length -= scan_length; + } while (length > 0); } -/* Pad and send a tap sequence to the device, and receive the answer. - * For the purpose of padding we assume that we are in idle or pause state. */ -static int jlink_tap_execute(void) +static int jlink_flush(void) { - int byte_length; int i; - int result; + int ret; if (!tap_length) return ERROR_OK; - /* JLink returns an extra NULL in packet when size of incoming - * message is a multiple of 64, creates problems with USB comms. - * WARNING: This will interfere with tap state counting. */ - while ((DIV_ROUND_UP(tap_length, 8) % 64) == 0) - jlink_tap_append_step((tap_get_state() == TAP_RESET) ? 1 : 0, 0); - - /* number of full bytes (plus one if some would be left over) */ - byte_length = DIV_ROUND_UP(tap_length, 8); - - bool use_jtag3 = jlink_hw_jtag_version >= 3; - usb_out_buffer[0] = use_jtag3 ? EMU_CMD_HW_JTAG3 : EMU_CMD_HW_JTAG2; - 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); - jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer, - tap_length, jlink_last_state); + tap_length, jlink_last_state); - result = jlink_usb_message(jlink_handle, 4 + 2 * byte_length, - use_jtag3 ? byte_length + 1 : byte_length); - if (result != ERROR_OK) { - LOG_ERROR("jlink_tap_execute failed USB io (%d)", result); - jlink_tap_init(); - return ERROR_JTAG_QUEUE_FAILED; - } + ret = jaylink_jtag_io(devh, tms_buffer, tdi_buffer, tdo_buffer, + tap_length, jtag_command_version); - result = use_jtag3 ? usb_in_buffer[byte_length] : 0; - if (result != 0) { - LOG_ERROR("jlink_tap_execute failed, result %d (%s)", result, - result == 1 ? "adaptive clocking timeout" : "unknown"); + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_jtag_io() failed: %s", jaylink_strerror(ret)); jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } - memcpy(tdo_buffer, usb_in_buffer, byte_length); - for (i = 0; i < pending_scan_results_length; i++) { - struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; - uint8_t *buffer = pending_scan_result->buffer; - int length = pending_scan_result->length; - int first = pending_scan_result->first; - struct scan_command *command = pending_scan_result->command; - - /* Copy to buffer */ - buf_set_buf(tdo_buffer, first, buffer, 0, length); - - DEBUG_JTAG_IO("pending scan result, length = %d", length); + struct pending_scan_result *p = &pending_scan_results_buffer[i]; - jlink_debug_buffer(buffer, DIV_ROUND_UP(length, 8)); + buf_set_buf(tdo_buffer, p->first, p->buffer, + p->buffer_offset, p->length); - if (jtag_read_buffer(buffer, command) != ERROR_OK) { - jlink_tap_init(); - return ERROR_JTAG_QUEUE_FAILED; - } - - if (pending_scan_result->buffer != NULL) - free(pending_scan_result->buffer); + LOG_DEBUG_IO("Pending scan result, length = %d", p->length); } jlink_tap_init(); + return ERROR_OK; } @@ -1590,6 +2089,7 @@ static void fill_buffer(uint8_t *buf, uint32_t val, uint32_t len) len -= 32; tap_pos += 32; } + if (len) buf_set_u32(buf, tap_pos, len, val); } @@ -1602,6 +2102,7 @@ static void jlink_queue_data_out(const uint8_t *data, uint32_t len) 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; } @@ -1614,30 +2115,50 @@ static void jlink_queue_data_in(uint32_t len) tap_length += len; } -static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq) +static int jlink_swd_switch_seq(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; + 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 JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + s = swd_seq_jtag_to_dormant; + s_len = swd_seq_jtag_to_dormant_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; + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + s = swd_seq_swd_to_dormant; + s_len = swd_seq_swd_to_dormant_len; + break; + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + s = swd_seq_dormant_to_swd; + s_len = swd_seq_dormant_to_swd_len; + break; + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + s = swd_seq_dormant_to_jtag; + s_len = swd_seq_dormant_to_jtag_len; + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; } jlink_queue_data_out(s, s_len); @@ -1645,49 +2166,33 @@ static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq) return ERROR_OK; } -static int jlink_swd_run_queue(struct adiv5_dap *dap) +static int jlink_swd_run_queue(void) { + int i; + int ret; + 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. */ + /* + * 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; - } + ret = jaylink_swd_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length); - retval = usb_in_buffer[byte_length]; - if (retval) { - LOG_ERROR("jlink_swd_run_queue failed, result %d", retval); + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_swd_io() failed: %s", jaylink_strerror(ret)); 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); + for (i = 0; i < pending_scan_results_length; i++) { + int ack = buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3); if (ack != SWD_ACK_OK) { LOG_DEBUG("SWD ack not OK: %d %s", ack, @@ -1695,11 +2200,11 @@ static int jlink_swd_run_queue(struct adiv5_dap *dap) 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); + uint32_t data = buf_get_u32(tdo_buffer, 3 + pending_scan_results_buffer[i].first, 32); + int parity = buf_get_u32(tdo_buffer, 3 + 32 + pending_scan_results_buffer[i].first, 1); if (parity != parity_u32(data)) { - LOG_ERROR("SWD Read data parity mismatch"); + LOG_ERROR("SWD: Read data parity mismatch"); queued_retval = ERROR_FAIL; goto skip; } @@ -1711,19 +2216,19 @@ static int jlink_swd_run_queue(struct adiv5_dap *dap) skip: jlink_tap_init(); - retval = queued_retval; + ret = queued_retval; queued_retval = ERROR_OK; - return retval; + return ret; } -static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data) +static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) { uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)]; - if (tap_length + 46 + 8 + dap->memaccess_tck >= sizeof(tdi_buffer) * 8 || + if (tap_length + 46 + 8 + ap_delay_clk >= swd_buffer_size * 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); + queued_retval = jlink_swd_run_queue(); } if (queued_retval != ERROR_OK) @@ -1735,14 +2240,14 @@ static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *ds pending_scan_results_buffer[pending_scan_results_length].first = tap_length; - if (cmd & SWD_CMD_RnW) { - /* Queue a read transaction */ + 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 */ + /* Queue a write transaction. */ pending_scan_results_buffer[pending_scan_results_length].length = 0; jlink_queue_data_in(1 + 3 + 1); @@ -1754,235 +2259,39 @@ static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *ds 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, jlink_serial, &devh) != ERROR_OK) - return NULL; - - /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS - * AREA!!!!!!!!!!! The behavior of libusb is not completely - * consistent across Windows, Linux, and Mac OS X platforms. - * The actions taken in the following compiler conditionals may - * not agree with published documentation for libusb, but were - * found to be necessary through trials and tribulations. Even - * little tweaks can break one or more platforms, so if you do - * make changes test them carefully on all platforms before - * committing them! - */ - -/* 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); - -#if IS_DARWIN == 0 - - int timeout = 5; - /* 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, jlink_serial, &devh)) != ERROR_OK) { - usleep(1000); - timeout--; - if (!timeout) - break; - } - if (ERROR_OK != retval) - return NULL; -#endif - -#endif - - /* 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_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; - return result; -} - -static void jlink_usb_close(struct jlink *jlink) -{ - jtag_libusb_close(jlink->usb_handle); - free(jlink); -} - -/* Send a message and receive the reply. */ -static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length) -{ - int result; - - result = jlink_usb_write(jlink, out_length); - if (result != out_length) { - LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", - out_length, result); - return ERROR_JTAG_DEVICE_ERROR; - } - - result = jlink_usb_read(jlink, in_length); - if (result != in_length) { - LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", - in_length, result); - return ERROR_JTAG_DEVICE_ERROR; - } - return ERROR_OK; -} - -/* calls the given usb_bulk_* function, allowing for the data to - * trickle in with some timeouts */ -static int usb_bulk_with_retries( - int (*f)(jtag_libusb_device_handle *, int, char *, int, int), - jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - int tries = 3, count = 0; - - while (tries && (count < size)) { - int result = f(dev, ep, bytes + count, size - count, timeout); - if (result > 0) - count += result; - else if ((-ETIMEDOUT != result) || !--tries) - return result; - } - return count; -} - -static int wrap_usb_bulk_write(jtag_libusb_device_handle *dev, int ep, - char *buff, int size, int timeout) -{ - /* usb_bulk_write() takes const char *buff */ - return jtag_libusb_bulk_write(dev, ep, buff, size, timeout); -} - -static inline int usb_bulk_write_ex(jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - return usb_bulk_with_retries(&wrap_usb_bulk_write, - dev, ep, bytes, size, timeout); -} - -static inline int usb_bulk_read_ex(jtag_libusb_device_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - return usb_bulk_with_retries(&jtag_libusb_bulk_read, - dev, ep, bytes, size, timeout); -} - -/* Write data from out_buffer to USB. */ -static int jlink_usb_write(struct jlink *jlink, int out_length) -{ - int result; - - if (out_length > JLINK_OUT_BUFFER_SIZE) { - LOG_ERROR("jlink_write illegal out_length=%d (max=%d)", - out_length, JLINK_OUT_BUFFER_SIZE); - return -1; - } - - result = usb_bulk_write_ex(jlink->usb_handle, jlink_write_ep, - (char *)usb_out_buffer, out_length, JLINK_USB_TIMEOUT); - - DEBUG_JTAG_IO("jlink_usb_write, out_length = %d, result = %d", - out_length, result); - - jlink_debug_buffer(usb_out_buffer, out_length); - return result; -} - -/* Read data from USB into in_buffer. */ -static int jlink_usb_read(struct jlink *jlink, int expected_size) -{ - int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, - (char *)usb_in_buffer, expected_size, JLINK_USB_TIMEOUT); - - DEBUG_JTAG_IO("jlink_usb_read, result = %d", result); - - jlink_debug_buffer(usb_in_buffer, result); - return result; + /* Insert idle cycles after AP accesses to avoid WAIT. */ + if (cmd & SWD_CMD_APNDP) + jlink_queue_data_out(NULL, ap_delay_clk); } -/* - * Send a message and receive the reply - simple messages. - * - * @param jlink pointer to driver data - * @param out_length data length in @c usb_out_buffer - * @param in_length data length to be read to @c usb_in_buffer - */ -static int jlink_usb_io(struct jlink *jlink, int out_length, int in_length) -{ - int result; - - result = jlink_usb_write(jlink, out_length); - if (result != out_length) { - LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", - out_length, result); - return ERROR_JTAG_DEVICE_ERROR; - } - - result = jlink_usb_read(jlink, in_length); - if (result != in_length) { - LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", - in_length, result); - return ERROR_JTAG_DEVICE_ERROR; - } +static const struct swd_driver jlink_swd = { + .init = &jlink_swd_init, + .switch_seq = &jlink_swd_switch_seq, + .read_reg = &jlink_swd_read_reg, + .write_reg = &jlink_swd_write_reg, + .run = &jlink_swd_run_queue, +}; - /* - * Section 4.2.4 IN-transaction: - * read dummy 0-byte packet if transaction size is - * multiple of 64 bytes but not max. size of 0x8000 - */ - if ((in_length % 64) == 0 && in_length != 0x8000) { - char dummy_buffer; - result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, - &dummy_buffer, 1, JLINK_USB_TIMEOUT); - if (result != 0) { - LOG_ERROR("dummy byte read failed"); - return ERROR_JTAG_DEVICE_ERROR; - } - } - return ERROR_OK; -} +static const char * const jlink_transports[] = { "jtag", "swd", NULL }; -#ifdef _DEBUG_USB_COMMS_ -#define BYTES_PER_LINE 16 +static struct jtag_interface jlink_interface = { + .execute_queue = &jlink_execute_queue, +}; -static void jlink_debug_buffer(uint8_t *buffer, int length) -{ - char line[81]; - char s[4]; - int i; - int j; +struct adapter_driver jlink_adapter_driver = { + .name = "jlink", + .transports = jlink_transports, + .commands = jlink_command_handlers, - for (i = 0; i < length; i += BYTES_PER_LINE) { - snprintf(line, 5, "%04x", i); - for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { - snprintf(s, 4, " %02x", buffer[j]); - strcat(line, s); - } - LOG_DEBUG("%s", line); - } -} -#endif + .init = &jlink_init, + .quit = &jlink_quit, + .reset = &jlink_reset_safe, + .speed = &jlink_speed, + .khz = &jlink_khz, + .speed_div = &jlink_speed_div, + .config_trace = &config_trace, + .poll_trace = &poll_trace, + + .jtag_ops = &jlink_interface, + .swd_ops = &jlink_swd, +};