X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fcmsis_dap_usb.c;h=ee1cb533c050a730a880350b53b793be5287e304;hp=a0922d4651ea479b8bce1992acea44877a4195ed;hb=3883e769f43fe85d1d499c8ac7ae2ed781bf137d;hpb=5aceec24122bc222896cfcfd91f7f082f630ac83 diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index a0922d4651..ee1cb533c0 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -77,8 +77,8 @@ static bool swd_mode; #define CMD_DAP_RESET_TARGET 0x0A /* CMD_INFO */ -#define INFO_ID_VID 0x00 /* string */ -#define INFO_ID_PID 0x02 /* string */ +#define INFO_ID_VENDOR 0x01 /* string */ +#define INFO_ID_PRODUCT 0x02 /* string */ #define INFO_ID_SERNUM 0x03 /* string */ #define INFO_ID_FW_VER 0x04 /* string */ #define INFO_ID_TD_VEND 0x05 /* string */ @@ -166,7 +166,7 @@ static const char * const info_caps_str[] = { struct cmsis_dap { hid_device *dev_handle; uint16_t packet_size; - uint16_t packet_count; + int packet_count; uint8_t *packet_buffer; uint8_t caps; uint8_t mode; @@ -178,6 +178,11 @@ struct pending_transfer_result { void *buffer; }; +struct pending_request_block { + struct pending_transfer_result *transfers; + int transfer_count; +}; + struct pending_scan_result { /** Offset in bytes in the CMD_DAP_JTAG_SEQ response buffer. */ unsigned first; @@ -189,8 +194,16 @@ struct pending_scan_result { unsigned buffer_offset; }; -static int pending_transfer_count, pending_queue_len; -static struct pending_transfer_result *pending_transfers; +/* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued + * until the first response arrives */ +#define MAX_PENDING_REQUESTS 3 + +/* Pending requests are organized as a FIFO - circular buffer */ +/* Each block in FIFO can contain up to pending_queue_len transfers */ +static int pending_queue_len; +static struct pending_request_block pending_fifo[MAX_PENDING_REQUESTS]; +static int pending_fifo_put_idx, pending_fifo_get_idx; +static int pending_fifo_block_count; /* pointers to buffers that will receive jtag scan results on the next flush */ #define MAX_PENDING_SCAN_RESULTS 256 @@ -346,14 +359,14 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap) cmsis_dap_handle = NULL; free(cmsis_dap_serial); cmsis_dap_serial = NULL; - free(pending_transfers); - pending_transfers = NULL; - return; + for (int i = 0; i < MAX_PENDING_REQUESTS; i++) { + free(pending_fifo[i].transfers); + pending_fifo[i].transfers = NULL; + } } -/* Send a message and receive the reply */ -static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) +static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen) { #ifdef CMSIS_DAP_JTAG_DEBUG LOG_DEBUG("cmsis-dap usb xfer cmd=%02X", dap->packet_buffer[1]); @@ -368,6 +381,26 @@ static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) return ERROR_FAIL; } + return ERROR_OK; +} + +/* Send a message and receive the reply */ +static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) +{ + if (pending_fifo_block_count) { + LOG_ERROR("pending %d blocks, flushing", pending_fifo_block_count); + while (pending_fifo_block_count) { + hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, 10); + pending_fifo_block_count--; + } + pending_fifo_put_idx = 0; + pending_fifo_get_idx = 0; + } + + int retval = cmsis_dap_usb_write(dap, txlen); + if (retval != ERROR_OK) + return retval; + /* get reply */ retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT); if (retval == -1 || retval == 0) { @@ -474,15 +507,15 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data) return ERROR_OK; } -static int cmsis_dap_cmd_DAP_LED(uint8_t leds) +static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state) { int retval; uint8_t *buffer = cmsis_dap_handle->packet_buffer; buffer[0] = 0; /* report number */ buffer[1] = CMD_DAP_LED; - buffer[2] = 0x00; - buffer[3] = leds; + buffer[2] = led; + buffer[3] = state; retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); if (retval != ERROR_OK || buffer[1] != 0x00) { @@ -594,29 +627,31 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us) } #endif -static int cmsis_dap_swd_run_queue(void) +static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) { - uint8_t *buffer = cmsis_dap_handle->packet_buffer; + uint8_t *buffer = dap->packet_buffer; + struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; - LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count); + LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); goto skip; } - if (!pending_transfer_count) + if (block->transfer_count == 0) goto skip; size_t idx = 0; buffer[idx++] = 0; /* report number */ buffer[idx++] = CMD_DAP_TFER; buffer[idx++] = 0x00; /* DAP Index */ - buffer[idx++] = pending_transfer_count; + buffer[idx++] = block->transfer_count; - for (int i = 0; i < pending_transfer_count; i++) { - uint8_t cmd = pending_transfers[i].cmd; - uint32_t data = pending_transfers[i].data; + for (int i = 0; i < block->transfer_count; i++) { + struct pending_transfer_result *transfer = &(block->transfers[i]); + uint8_t cmd = transfer->cmd; + uint32_t data = transfer->data; LOG_DEBUG_IO("%s %s reg %x %"PRIx32, cmd & SWD_CMD_APnDP ? "AP" : "DP", @@ -651,26 +686,62 @@ static int cmsis_dap_swd_run_queue(void) } } - queued_retval = cmsis_dap_usb_xfer(cmsis_dap_handle, idx); + queued_retval = cmsis_dap_usb_write(dap, idx); if (queued_retval != ERROR_OK) goto skip; - idx = 2; - uint8_t ack = buffer[idx] & 0x07; - if (ack != SWD_ACK_OK || (buffer[idx] & 0x08)) { - LOG_DEBUG("SWD ack not OK: %d %s", buffer[idx-1], + pending_fifo_put_idx = (pending_fifo_put_idx + 1) % dap->packet_count; + pending_fifo_block_count++; + if (pending_fifo_block_count > dap->packet_count) + LOG_ERROR("too much pending writes %d", pending_fifo_block_count); + + return; + +skip: + block->transfer_count = 0; +} + +static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) +{ + uint8_t *buffer = dap->packet_buffer; + struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx]; + + if (pending_fifo_block_count == 0) + LOG_ERROR("no pending write"); + + /* get reply */ + int retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms); + if (retval == 0 && timeout_ms < USB_TIMEOUT) + return; + + if (retval == -1 || retval == 0) { + LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle)); + queued_retval = ERROR_FAIL; + goto skip; + } + + if (buffer[2] & 0x08) { + LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", buffer[1]); + queued_retval = ERROR_FAIL; + goto skip; + } + uint8_t ack = buffer[2] & 0x07; + if (ack != SWD_ACK_OK) { + LOG_DEBUG("SWD ack not OK @ %d %s", buffer[1], ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; goto skip; } - idx++; - if (pending_transfer_count != buffer[1]) + if (block->transfer_count != buffer[1]) LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d", - pending_transfer_count, buffer[1]); + block->transfer_count, buffer[1]); + LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", buffer[1], pending_fifo_get_idx); + size_t idx = 3; for (int i = 0; i < buffer[1]; i++) { - if (pending_transfers[i].cmd & SWD_CMD_RnW) { + struct pending_transfer_result *transfer = &(block->transfers[i]); + if (transfer->cmd & SWD_CMD_RnW) { static uint32_t last_read; uint32_t data = le_to_h_u32(&buffer[idx]); uint32_t tmp = data; @@ -679,19 +750,36 @@ static int cmsis_dap_swd_run_queue(void) LOG_DEBUG_IO("Read result: %"PRIx32, data); /* Imitate posted AP reads */ - if ((pending_transfers[i].cmd & SWD_CMD_APnDP) || - ((pending_transfers[i].cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) { + if ((transfer->cmd & SWD_CMD_APnDP) || + ((transfer->cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) { tmp = last_read; last_read = data; } - if (pending_transfers[i].buffer) - *(uint32_t *)pending_transfers[i].buffer = tmp; + if (transfer->buffer) + *(uint32_t *)(transfer->buffer) = tmp; } } skip: - pending_transfer_count = 0; + block->transfer_count = 0; + pending_fifo_get_idx = (pending_fifo_get_idx + 1) % dap->packet_count; + pending_fifo_block_count--; +} + +static int cmsis_dap_swd_run_queue(void) +{ + if (pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, 0); + + cmsis_dap_swd_write_from_queue(cmsis_dap_handle); + + while (pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); + + pending_fifo_put_idx = 0; + pending_fifo_get_idx = 0; + int retval = queued_retval; queued_retval = ERROR_OK; @@ -700,21 +788,29 @@ skip: static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) { - if (pending_transfer_count == pending_queue_len) { + if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len) { + if (pending_fifo_block_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, 0); + /* Not enough room in the queue. Run the queue. */ - queued_retval = cmsis_dap_swd_run_queue(); + cmsis_dap_swd_write_from_queue(cmsis_dap_handle); + + if (pending_fifo_block_count >= cmsis_dap_handle->packet_count) + cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); } if (queued_retval != ERROR_OK) return; - pending_transfers[pending_transfer_count].data = data; - pending_transfers[pending_transfer_count].cmd = cmd; + struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx]; + struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]); + transfer->data = data; + transfer->cmd = cmd; if (cmd & SWD_CMD_RnW) { /* Queue a read transaction */ - pending_transfers[pending_transfer_count].buffer = dst; + transfer->buffer = dst; } - pending_transfer_count++; + block->transfer_count++; } static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) @@ -729,6 +825,20 @@ static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del cmsis_dap_swd_queue_cmd(cmd, value, 0); } +static int cmsis_dap_get_serial_info(void) +{ + uint8_t *data; + + int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_SERNUM, &data); + if (retval != ERROR_OK) + return retval; + + if (data[0]) /* strlen */ + LOG_INFO("CMSIS-DAP: Serial# = %s", &data[1]); + + return ERROR_OK; +} + static int cmsis_dap_get_version_info(void) { uint8_t *data; @@ -869,13 +979,19 @@ static int cmsis_dap_init(void) if (retval != ERROR_OK) return retval; + retval = cmsis_dap_get_version_info(); + if (retval != ERROR_OK) + return retval; + + retval = cmsis_dap_get_serial_info(); + if (retval != ERROR_OK) + return retval; + if (swd_mode) { retval = cmsis_dap_swd_open(); if (retval != ERROR_OK) return retval; - } - - if (cmsis_dap_handle == NULL) { + } else { /* Connect in JTAG mode */ if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { LOG_ERROR("CMSIS-DAP: JTAG not supported"); @@ -889,9 +1005,10 @@ static int cmsis_dap_init(void) LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); } - retval = cmsis_dap_get_version_info(); - if (retval != ERROR_OK) - return retval; + /* Be conservative and supress submiting multiple HID requests + * until we get packet count info from the adaptor */ + cmsis_dap_handle->packet_count = 1; + pending_queue_len = 12; /* INFO_ID_PKT_SZ - short */ retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data); @@ -905,11 +1022,6 @@ static int cmsis_dap_init(void) * write. For bulk read sequences just 4 bytes are * needed per transfer, so this is suboptimal. */ pending_queue_len = (pkt_sz - 4) / 5; - pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers)); - if (!pending_transfers) { - LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue"); - return ERROR_FAIL; - } if (cmsis_dap_handle->packet_size != pkt_sz + 1) { /* reallocate buffer */ @@ -931,11 +1043,23 @@ static int cmsis_dap_init(void) return retval; if (data[0] == 1) { /* byte */ - uint16_t pkt_cnt = data[1]; - cmsis_dap_handle->packet_count = pkt_cnt; - LOG_DEBUG("CMSIS-DAP: Packet Count = %" PRId16, pkt_cnt); + int pkt_cnt = data[1]; + if (pkt_cnt > 1) + cmsis_dap_handle->packet_count = MIN(MAX_PENDING_REQUESTS, pkt_cnt); + + LOG_DEBUG("CMSIS-DAP: Packet Count = %d", pkt_cnt); + } + + LOG_DEBUG("Allocating FIFO for %d pending HID requests", cmsis_dap_handle->packet_count); + for (int i = 0; i < cmsis_dap_handle->packet_count; i++) { + pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result)); + if (!pending_fifo[i].transfers) { + LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue"); + return ERROR_FAIL; + } } + retval = cmsis_dap_get_status(); if (retval != ERROR_OK) return ERROR_FAIL; @@ -960,8 +1084,12 @@ static int cmsis_dap_init(void) if (retval != ERROR_OK) return ERROR_FAIL; } + /* Both LEDs on */ + retval = cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_ON); + if (retval != ERROR_OK) + return ERROR_FAIL; - retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */ + retval = cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_ON); if (retval != ERROR_OK) return ERROR_FAIL; @@ -970,15 +1098,12 @@ static int cmsis_dap_init(void) if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) { - retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, (1 << 7), 0, NULL); + retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, SWJ_PIN_SRST, 0, NULL); if (retval != ERROR_OK) return ERROR_FAIL; LOG_INFO("Connecting under reset"); } } - - cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */ - LOG_INFO("CMSIS-DAP: Interface ready"); return ERROR_OK; @@ -993,28 +1118,31 @@ static int cmsis_dap_swd_init(void) static int cmsis_dap_quit(void) { cmsis_dap_cmd_DAP_Disconnect(); - cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */ + /* Both LEDs off */ + cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_OFF); + cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_OFF); cmsis_dap_usb_close(cmsis_dap_handle); return ERROR_OK; } -static void cmsis_dap_execute_reset(struct jtag_command *cmd) +static int cmsis_dap_reset(int trst, int srst) { /* Set both TRST and SRST even if they're not enabled as * there's no way to tristate them */ output_pins = 0; - if (!cmd->cmd.reset->srst) + if (!srst) output_pins |= SWJ_PIN_SRST; - if (!cmd->cmd.reset->trst) + if (!trst) output_pins |= SWJ_PIN_TRST; int retval = cmsis_dap_cmd_DAP_SWJ_Pins(output_pins, SWJ_PIN_TRST | SWJ_PIN_SRST, 0, NULL); if (retval != ERROR_OK) LOG_ERROR("CMSIS-DAP: Interface reset failed"); + return retval; } static void cmsis_dap_execute_sleep(struct jtag_command *cmd) @@ -1120,7 +1248,7 @@ static void cmsis_dap_flush(void) if (!queued_seq_count) return; - DEBUG_JTAG_IO("Flushing %d queued sequences (%d bytes) with %d pending scan results to capture", + LOG_DEBUG_IO("Flushing %d queued sequences (%d bytes) with %d pending scan results to capture", queued_seq_count, queued_seq_buf_end, pending_scan_result_count); /* prep CMSIS-DAP packet */ @@ -1142,7 +1270,7 @@ static void cmsis_dap_flush(void) } #ifdef CMSIS_DAP_JTAG_DEBUG - DEBUG_JTAG_IO("USB response buf:"); + LOG_DEBUG_IO("USB response buf:"); for (int c = 0; c < queued_seq_buf_end + 3; ++c) printf("%02X ", buffer[c]); printf("\n"); @@ -1151,7 +1279,7 @@ static void cmsis_dap_flush(void) /* copy scan results into client buffers */ for (int i = 0; i < pending_scan_result_count; ++i) { struct pending_scan_result *scan = &pending_scan_results[i]; - DEBUG_JTAG_IO("Copying pending_scan_result %d/%d: %d bits from byte %d -> buffer + %d bits", + LOG_DEBUG_IO("Copying pending_scan_result %d/%d: %d bits from byte %d -> buffer + %d bits", i, pending_scan_result_count, scan->length, scan->first + 2, scan->buffer_offset); #ifdef CMSIS_DAP_JTAG_DEBUG for (uint32_t b = 0; b < DIV_ROUND_UP(scan->length, 8); ++b) @@ -1176,7 +1304,7 @@ static void cmsis_dap_flush(void) static void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int s_offset, bool tms, uint8_t *tdo_buffer, int tdo_buffer_offset) { - DEBUG_JTAG_IO("[at %d] %d bits, tms %s, seq offset %d, tdo buf %p, tdo offset %d", + LOG_DEBUG_IO("[at %d] %d bits, tms %s, seq offset %d, tdo buf %p, tdo offset %d", queued_seq_buf_end, s_len, tms ? "HIGH" : "LOW", s_offset, tdo_buffer, tdo_buffer_offset); @@ -1184,12 +1312,12 @@ static void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int return; if (s_len > 64) { - DEBUG_JTAG_IO("START JTAG SEQ SPLIT"); + LOG_DEBUG_IO("START JTAG SEQ SPLIT"); for (int offset = 0; offset < s_len; offset += 64) { int len = s_len - offset; if (len > 64) len = 64; - DEBUG_JTAG_IO("Splitting long jtag sequence: %d-bit chunk starting at offset %d", len, offset); + LOG_DEBUG_IO("Splitting long jtag sequence: %d-bit chunk starting at offset %d", len, offset); cmsis_dap_add_jtag_sequence( len, sequence, @@ -1199,7 +1327,7 @@ static void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int tdo_buffer == NULL ? 0 : (tdo_buffer_offset + offset) ); } - DEBUG_JTAG_IO("END JTAG SEQ SPLIT"); + LOG_DEBUG_IO("END JTAG SEQ SPLIT"); return; } @@ -1236,7 +1364,7 @@ static void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int /* queue a sequence of bits to clock out TMS, executing if the buffer is full */ static void cmsis_dap_add_tms_sequence(const uint8_t *sequence, int s_len) { - DEBUG_JTAG_IO("%d bits: %02X", s_len, *sequence); + LOG_DEBUG_IO("%d bits: %02X", s_len, *sequence); /* we use a series of CMD_DAP_JTAG_SEQ commands to toggle TMS, because even though it seems ridiculously inefficient, it allows us to combine TMS and scan sequences into the same @@ -1257,7 +1385,7 @@ static void cmsis_dap_state_move(void) 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()); - DEBUG_JTAG_IO("state move from %s to %s: %d clocks, %02X on tms", + LOG_DEBUG_IO("state move from %s to %s: %d clocks, %02X on tms", tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state()), tms_scan_bits, tms_scan); cmsis_dap_add_tms_sequence(&tms_scan, tms_scan_bits); @@ -1269,7 +1397,7 @@ static void cmsis_dap_state_move(void) /* Execute a JTAG scan operation by queueing TMS and TDI/TDO sequences */ static void cmsis_dap_execute_scan(struct jtag_command *cmd) { - DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", + LOG_DEBUG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", jtag_scan_type(cmd->cmd.scan)); /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ @@ -1303,7 +1431,7 @@ static void cmsis_dap_execute_scan(struct jtag_command *cmd) for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; - DEBUG_JTAG_IO("%s%s field %d/%d %d bits", + LOG_DEBUG_IO("%s%s field %d/%d %d bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, @@ -1311,7 +1439,7 @@ static void cmsis_dap_execute_scan(struct jtag_command *cmd) field->num_bits); if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { - DEBUG_JTAG_IO("Last field and have to move out of SHIFT state"); + LOG_DEBUG_IO("Last field and have to move out of SHIFT 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. */ cmsis_dap_add_jtag_sequence( @@ -1345,7 +1473,7 @@ static void cmsis_dap_execute_scan(struct jtag_command *cmd) 0); tap_set_state(tap_state_transition(tap_get_state(), 0)); } else { - DEBUG_JTAG_IO("Internal field, staying in SHIFT state afterwards"); + LOG_DEBUG_IO("Internal field, staying in SHIFT state afterwards"); /* Clocking part of a sequence into DR or IR with TMS=0, leaving TMS=0 at the end so we can continue later */ cmsis_dap_add_jtag_sequence( @@ -1363,7 +1491,7 @@ static void cmsis_dap_execute_scan(struct jtag_command *cmd) cmsis_dap_state_move(); } - DEBUG_JTAG_IO("%s scan, %i bits, end in %s", + 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())); } @@ -1393,7 +1521,7 @@ static void cmsis_dap_pathmove(int num_states, tap_state_t *path) static void cmsis_dap_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]); @@ -1431,7 +1559,7 @@ static void cmsis_dap_runtest(int num_cycles) static void cmsis_dap_execute_runtest(struct jtag_command *cmd) { - DEBUG_JTAG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, + LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); cmsis_dap_end_state(cmd->cmd.runtest->end_state); @@ -1440,19 +1568,21 @@ static void cmsis_dap_execute_runtest(struct jtag_command *cmd) static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd) { - DEBUG_JTAG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); + LOG_DEBUG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles); } +static void cmsis_dap_execute_tms(struct jtag_command *cmd) +{ + LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); + cmsis_dap_cmd_DAP_SWJ_Sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); +} + /* TODO: Is there need to call cmsis_dap_flush() for the JTAG_PATHMOVE, * JTAG_RUNTEST, JTAG_STABLECLOCKS? */ static void cmsis_dap_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_RESET: - cmsis_dap_flush(); - cmsis_dap_execute_reset(cmd); - break; case JTAG_SLEEP: cmsis_dap_flush(); cmsis_dap_execute_sleep(cmd); @@ -1474,6 +1604,8 @@ static void cmsis_dap_execute_command(struct jtag_command *cmd) cmsis_dap_execute_stableclocks(cmd); break; case JTAG_TMS: + cmsis_dap_execute_tms(cmd); + break; default: LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); exit(-1); @@ -1497,10 +1629,10 @@ static int cmsis_dap_execute_queue(void) static int cmsis_dap_speed(int speed) { if (speed > DAP_MAX_CLOCK) - LOG_INFO("High speed (adapter_khz %d) may be limited by adapter firmware.", speed); + LOG_INFO("High speed (adapter speed %d) may be limited by adapter firmware.", speed); if (speed == 0) { - LOG_ERROR("RTCK not supported. Set nonzero adapter_khz."); + LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\"."); return ERROR_JTAG_NOT_IMPLEMENTED; } @@ -1519,19 +1651,34 @@ static int cmsis_dap_khz(int khz, int *jtag_speed) return ERROR_OK; } -static int_least32_t cmsis_dap_swd_frequency(int_least32_t hz) +COMMAND_HANDLER(cmsis_dap_handle_info_command) { - if (hz > 0) - cmsis_dap_speed(hz / 1000); + if (cmsis_dap_get_version_info() == ERROR_OK) + cmsis_dap_get_status(); - return hz; + return ERROR_OK; } - -COMMAND_HANDLER(cmsis_dap_handle_info_command) +COMMAND_HANDLER(cmsis_dap_handle_cmd_command) { - if (cmsis_dap_get_version_info() == ERROR_OK) - cmsis_dap_get_status(); + int retval; + unsigned i; + uint8_t *buffer = cmsis_dap_handle->packet_buffer; + + buffer[0] = 0; /* report number */ + + for (i = 0; i < CMD_ARGC; i++) + buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16); + + retval = cmsis_dap_usb_xfer(cmsis_dap_handle, CMD_ARGC + 1); + + if (retval != ERROR_OK) { + LOG_ERROR("CMSIS-DAP command failed."); + return ERROR_JTAG_DEVICE_ERROR; + } + + LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8, + buffer[1], buffer[2], buffer[3], buffer[4]); return ERROR_OK; } @@ -1595,6 +1742,13 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = { .usage = "", .help = "show cmsis-dap info", }, + { + .name = "cmd", + .handler = &cmsis_dap_handle_cmd_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "issue cmsis-dap command", + }, COMMAND_REGISTRATION_DONE }; @@ -1625,7 +1779,6 @@ static const struct command_registration cmsis_dap_command_handlers[] = { static const struct swd_driver cmsis_dap_swd_driver = { .init = cmsis_dap_swd_init, - .frequency = cmsis_dap_swd_frequency, .switch_seq = cmsis_dap_swd_switch_seq, .read_reg = cmsis_dap_swd_read_reg, .write_reg = cmsis_dap_swd_write_reg, @@ -1634,16 +1787,23 @@ static const struct swd_driver cmsis_dap_swd_driver = { static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; -struct jtag_interface cmsis_dap_interface = { +static struct jtag_interface cmsis_dap_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = cmsis_dap_execute_queue, +}; + +struct adapter_driver cmsis_dap_adapter_driver = { .name = "cmsis-dap", - .commands = cmsis_dap_command_handlers, - .swd = &cmsis_dap_swd_driver, .transports = cmsis_dap_transport, + .commands = cmsis_dap_command_handlers, - .execute_queue = cmsis_dap_execute_queue, - .speed = cmsis_dap_speed, - .speed_div = cmsis_dap_speed_div, - .khz = cmsis_dap_khz, .init = cmsis_dap_init, .quit = cmsis_dap_quit, + .reset = cmsis_dap_reset, + .speed = cmsis_dap_speed, + .khz = cmsis_dap_khz, + .speed_div = cmsis_dap_speed_div, + + .jtag_ops = &cmsis_dap_interface, + .swd_ops = &cmsis_dap_swd_driver, };