X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fjlink.c;h=6665c7e32005924abe59108739add4294d73a9e1;hp=d6819687652c409ca6d3c0c3042cbd11f050a9c5;hb=a8f1307992277a0ef53819583dad7ad444e29043;hpb=66db8e7bb4bd2f0889054007d346db97dcb619e0 diff --git a/src/jtag/jlink.c b/src/jtag/jlink.c index d681968765..6665c7e320 100644 --- a/src/jtag/jlink.c +++ b/src/jtag/jlink.c @@ -42,8 +42,9 @@ #define JLINK_USB_TIMEOUT 1000 -#define JLINK_IN_BUFFER_SIZE 8192 -#define JLINK_OUT_BUFFER_SIZE 8192 +// See Section 1.3.2 of the Segger JLink USB protocol manual +#define JLINK_IN_BUFFER_SIZE 2048 +#define JLINK_OUT_BUFFER_SIZE 2*2048+4 #define JLINK_EMU_RESULT_BUFFER_SIZE 64 /* Global USB buffers */ @@ -52,14 +53,16 @@ static u8 usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; static u8 usb_emu_result_buffer[JLINK_EMU_RESULT_BUFFER_SIZE]; /* Constants for JLink command */ -#define EMU_CMD_VERSION 0x01 -#define EMU_CMD_SET_SPEED 0x05 -#define EMU_CMD_GET_STATE 0x07 -#define EMU_CMD_HW_JTAG3 0xcf -#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_VERSION 0x01 +#define EMU_CMD_SET_SPEED 0x05 +#define EMU_CMD_GET_STATE 0x07 +#define EMU_CMD_HW_JTAG3 0xcf +#define EMU_CMD_GET_MAX_MEM_BLOCK 0xd4 +#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 /* max speed 12MHz v5.0 jlink */ #define JLINK_MAX_SPEED 12000 @@ -113,6 +116,8 @@ static int jlink_get_version_info(void); static void jlink_debug_buffer(u8 *buffer, int length); #endif +static enum tap_state jlink_last_state = TAP_RESET; + static jlink_jtag_t* jlink_jtag_handle; /***************************************************************************/ @@ -130,95 +135,113 @@ jtag_interface_t jlink_interface = .quit = jlink_quit }; -static int jlink_execute_queue(void) +static void jlink_execute_end_state(jtag_command_t *cmd) +{ + DEBUG_JTAG_IO("end_state: %i", cmd->cmd.end_state->end_state); + + if (cmd->cmd.end_state->end_state != TAP_INVALID) + jlink_end_state(cmd->cmd.end_state->end_state); +} + +static void jlink_execute_runtest(jtag_command_t *cmd) +{ + DEBUG_JTAG_IO("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + + if (cmd->cmd.runtest->end_state != TAP_INVALID) + jlink_end_state(cmd->cmd.runtest->end_state); + + jlink_runtest(cmd->cmd.runtest->num_cycles); +} + +static void jlink_execute_statemove(jtag_command_t *cmd) +{ + DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + + if (cmd->cmd.statemove->end_state != TAP_INVALID) + { + jlink_end_state(cmd->cmd.statemove->end_state); + } + jlink_state_move(); +} + +static void jlink_execute_pathmove(jtag_command_t *cmd) +{ + DEBUG_JTAG_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); +} + +static void jlink_execute_scan(jtag_command_t *cmd) { - jtag_command_t *cmd = jtag_command_queue; int scan_size; enum scan_type type; u8 *buffer; - while (cmd != NULL) - { - switch (cmd->type) - { - case JTAG_END_STATE: - DEBUG_JTAG_IO("end_state: %i", cmd->cmd.end_state->end_state); - - if (cmd->cmd.end_state->end_state != TAP_INVALID) - { - jlink_end_state(cmd->cmd.end_state->end_state); - } - break; - - case JTAG_RUNTEST: - DEBUG_JTAG_IO( "runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, \ - cmd->cmd.runtest->end_state); - - if (cmd->cmd.runtest->end_state != TAP_INVALID) - { - jlink_end_state(cmd->cmd.runtest->end_state); - } - jlink_runtest(cmd->cmd.runtest->num_cycles); - break; - - case JTAG_STATEMOVE: - DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - - if (cmd->cmd.statemove->end_state != TAP_INVALID) - { - jlink_end_state(cmd->cmd.statemove->end_state); - } - jlink_state_move(); - break; - - case JTAG_PATHMOVE: - DEBUG_JTAG_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); - break; - - case JTAG_SCAN: - DEBUG_JTAG_IO("scan end in %i", cmd->cmd.scan->end_state); - - if (cmd->cmd.scan->end_state != TAP_INVALID) - { - jlink_end_state(cmd->cmd.scan->end_state); - } - - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - DEBUG_JTAG_IO("scan input, length = %d", scan_size); + DEBUG_JTAG_IO("scan end in %i", cmd->cmd.scan->end_state); + + if (cmd->cmd.scan->end_state != TAP_INVALID) + jlink_end_state(cmd->cmd.scan->end_state); + + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + DEBUG_JTAG_IO("scan input, length = %d", scan_size); #ifdef _DEBUG_USB_COMMS_ - jlink_debug_buffer(buffer, (scan_size + 7) / 8); + jlink_debug_buffer(buffer, (scan_size + 7) / 8); #endif - type = jtag_scan_type(cmd->cmd.scan); - jlink_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); - break; - - case JTAG_RESET: - DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); - - jlink_tap_execute(); - - if (cmd->cmd.reset->trst == 1) - { - tap_set_state(TAP_RESET); - } - jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - - case JTAG_SLEEP: - DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); - jlink_tap_execute(); - jtag_sleep(cmd->cmd.sleep->us); - break; - - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); - } + type = jtag_scan_type(cmd->cmd.scan); + jlink_scan(cmd->cmd.scan->ir_scan, + type, buffer, scan_size, cmd->cmd.scan); +} + +static void jlink_execute_reset(jtag_command_t *cmd) +{ + DEBUG_JTAG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, cmd->cmd.reset->srst); + + jlink_tap_execute(); + + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + + jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); +} + +static void jlink_execute_sleep(jtag_command_t *cmd) +{ + DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); + jlink_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); +} + +static void jlink_execute_command(jtag_command_t *cmd) +{ + switch (cmd->type) + { + case JTAG_END_STATE: jlink_execute_end_state(cmd); break; + case JTAG_RUNTEST: jlink_execute_runtest(cmd); break; + case JTAG_STATEMOVE: jlink_execute_statemove(cmd); break; + case JTAG_PATHMOVE: jlink_execute_pathmove(cmd); break; + 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); + } +} + +static int jlink_execute_queue(void) +{ + jtag_command_t *cmd = jtag_command_queue; + + while (cmd != NULL) + { + jlink_execute_command(cmd); cmd = cmd->next; } @@ -310,6 +333,7 @@ static int jlink_init(void) jlink_reset(0, 0); jlink_tap_init(); + jlink_speed(jtag_speed); return ERROR_OK; } @@ -444,6 +468,8 @@ static void jlink_reset(int trst, int srst) if (srst == 0) { jlink_simple_command(EMU_CMD_HW_RESET1); + jlink_end_state(TAP_RESET); + jlink_state_move(); } else if (srst == 1) { @@ -453,6 +479,8 @@ static void jlink_reset(int trst, int srst) if (trst == 0) { jlink_simple_command(EMU_CMD_HW_TRST1); + jlink_end_state(TAP_RESET); + jlink_state_move(); } else if (trst == 1) { @@ -504,6 +532,7 @@ static int jlink_get_version_info(void) { int result; int len; + u32 jlink_caps, jlink_max_size; /* query hardware version */ jlink_simple_command(EMU_CMD_VERSION); @@ -511,8 +540,7 @@ static int jlink_get_version_info(void) result = jlink_usb_read(jlink_jtag_handle, 2); if (2 != result) { - LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", - result); + LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", result); return ERROR_JTAG_DEVICE_ERROR; } @@ -520,14 +548,41 @@ static int jlink_get_version_info(void) result = jlink_usb_read(jlink_jtag_handle, len); if (result != len) { - LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", - result); + LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", result); return ERROR_JTAG_DEVICE_ERROR; } usb_in_buffer[result] = 0; LOG_INFO("%s", (char *)usb_in_buffer); + /* query hardware capabilities */ + jlink_simple_command(EMU_CMD_GET_CAPS); + + result = jlink_usb_read(jlink_jtag_handle, 4); + if (4 != result) + { + LOG_ERROR("J-Link command EMU_CMD_GET_CAPS failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + jlink_caps = buf_get_u32(usb_in_buffer, 0, 32); + LOG_INFO("JLink caps 0x%x", jlink_caps); + + + /* query hardware maximum memory block */ + jlink_simple_command(EMU_CMD_GET_MAX_MEM_BLOCK); + + result = jlink_usb_read(jlink_jtag_handle, 4); + if (4 != result) + { + LOG_ERROR("J-Link command EMU_CMD_GET_MAX_MEM_BLOCK failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + jlink_max_size = buf_get_u32(usb_in_buffer, 0, 32); + LOG_INFO("JLink max mem block %i", jlink_max_size); + + return ERROR_OK; } @@ -599,6 +654,10 @@ static void jlink_tap_append_step(int tms, int tdi) int bit_index = tap_length % 8; u8 bit = 1 << bit_index; + // we do not pad TMS, so be sure to initialize all bits + if (0 == bit_index) + tms_buffer[index] = tdi_buffer[index] = 0; + if (tms) tms_buffer[index] |= bit; else @@ -637,52 +696,34 @@ static void jlink_tap_append_scan(int length, u8 *buffer, scan_command_t *comman static int jlink_tap_execute(void) { int byte_length; - int tms_offset; - int tdi_offset; int i; int result; if (!tap_length) return ERROR_OK; - /* Pad last byte so that tap_length is divisible by 8 */ - while (tap_length % 8 != 0) - { - /* More of the last TMS value keeps us in the same state, - * analogous to free-running JTAG interfaces. */ - jlink_tap_append_step(last_tms, 0); - } - - byte_length = tap_length / 8; + // number of full bytes (plus one if some would be left over) + byte_length = TAP_SCAN_BYTES(tap_length); 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); - tms_offset = 4; - for (i = 0; i < byte_length; i++) - { - usb_out_buffer[tms_offset + i] = tms_buffer[i]; - } - - tdi_offset = tms_offset + byte_length; - for (i = 0; i < byte_length; i++) - { - usb_out_buffer[tdi_offset + i] = tdi_buffer[i]; - } + jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer, + tap_length, jlink_last_state); result = jlink_usb_message(jlink_jtag_handle, 4 + 2 * byte_length, byte_length); - if (result != byte_length) { - LOG_ERROR("jlink_tap_execute, wrong result %d (expected %d)", - result, byte_length); + LOG_ERROR("jlink_tap_execute, wrong result %d (expected %d)", result, byte_length); + jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } - for (i = 0; i < byte_length; i++) - tdo_buffer[i] = usb_in_buffer[i]; + memcpy(tdo_buffer, usb_in_buffer, byte_length); for (i = 0; i < pending_scan_results_length; i++) { @@ -714,7 +755,6 @@ static int jlink_tap_execute(void) } jlink_tap_init(); - return ERROR_OK; } @@ -788,7 +828,7 @@ static int jlink_usb_message(jlink_jtag_t *jlink_jtag, int out_length, int in_le } result = jlink_usb_read(jlink_jtag, in_length); - if ((result != in_length) && (result != in_length + 1)) + if ((result != in_length) && (result != (in_length + 1))) { LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); @@ -846,12 +886,21 @@ static int usb_bulk_with_retries( } return rc; } + +static int wrap_usb_bulk_write(usb_dev_handle *dev, int ep, + char *buff, int size, int timeout) +{ + /* usb_bulk_write() takes const char *buff */ + return usb_bulk_write(dev, ep, buff, size, timeout); +} + static inline int usb_bulk_write_ex(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) { - return usb_bulk_with_retries(&usb_bulk_write, + return usb_bulk_with_retries(&wrap_usb_bulk_write, dev, ep, bytes, size, timeout); } + static inline int usb_bulk_read_ex(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) {