X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fcmsis_dap_usb.c;h=d52d698a437263a06552f4fa9b9fffef9a495806;hp=7f335fb5e12f316cca1fb18a0025af44e797d3c3;hb=HEAD;hpb=d0e763ac7ef6aa17b17bd00ccdfbccfb4eacda69 diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c deleted file mode 100644 index 7f335fb5e1..0000000000 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ /dev/null @@ -1,1131 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2014 by Paul Fertser * - * fercerpav@gmail.com * - * * - * Copyright (C) 2013 by mike brown * - * mike@theshedworks.org.uk * - * * - * Copyright (C) 2013 by Spencer Oliver * - * spen@spen-soft.co.uk * - * * - * 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 * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * 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, see . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include - -/* - * See CMSIS-DAP documentation: - * Version 0.01 - Beta. - */ - -/* USB Config */ - -/* Known vid/pid pairs: - * VID 0xc251: Keil Software - * PID 0xf001: LPC-Link-II CMSIS_DAP - * PID 0xf002: OPEN-SDA CMSIS_DAP (Freedom Board) - * PID 0x2722: Keil ULINK2 CMSIS-DAP - * - * VID 0x0d28: mbed Software - * PID 0x0204: MBED CMSIS-DAP - */ - -#define MAX_USB_IDS 8 -/* vid = pid = 0 marks the end of the list */ -static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 }; -static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; -static wchar_t *cmsis_dap_serial; -static bool swd_mode; - -#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */ -#define USB_TIMEOUT 1000 - -/* CMSIS-DAP General Commands */ -#define CMD_DAP_INFO 0x00 -#define CMD_DAP_LED 0x01 -#define CMD_DAP_CONNECT 0x02 -#define CMD_DAP_DISCONNECT 0x03 -#define CMD_DAP_WRITE_ABORT 0x08 -#define CMD_DAP_DELAY 0x09 -#define CMD_DAP_RESET_TARGET 0x0A - -/* CMD_INFO */ -#define INFO_ID_VID 0x00 /* string */ -#define INFO_ID_PID 0x02 /* string */ -#define INFO_ID_SERNUM 0x03 /* string */ -#define INFO_ID_FW_VER 0x04 /* string */ -#define INFO_ID_TD_VEND 0x05 /* string */ -#define INFO_ID_TD_NAME 0x06 /* string */ -#define INFO_ID_CAPS 0xf0 /* byte */ -#define INFO_ID_PKT_CNT 0xfe /* byte */ -#define INFO_ID_PKT_SZ 0xff /* short */ - -#define INFO_CAPS_SWD 0x01 -#define INFO_CAPS_JTAG 0x02 - -/* CMD_LED */ -#define LED_ID_CONNECT 0x00 -#define LED_ID_RUN 0x01 - -#define LED_OFF 0x00 -#define LED_ON 0x01 - -/* CMD_CONNECT */ -#define CONNECT_DEFAULT 0x00 -#define CONNECT_SWD 0x01 -#define CONNECT_JTAG 0x02 - -/* CMSIS-DAP Common SWD/JTAG Commands */ -#define CMD_DAP_DELAY 0x09 -#define CMD_DAP_SWJ_PINS 0x10 -#define CMD_DAP_SWJ_CLOCK 0x11 -#define CMD_DAP_SWJ_SEQ 0x12 - -/* - * PINS - * Bit 0: SWCLK/TCK - * Bit 1: SWDIO/TMS - * Bit 2: TDI - * Bit 3: TDO - * Bit 5: nTRST - * Bit 7: nRESET - */ - -/* CMSIS-DAP SWD Commands */ -#define CMD_DAP_SWD_CONFIGURE 0x13 - -/* CMSIS-DAP JTAG Commands */ -#define CMD_DAP_JTAG_SEQ 0x14 -#define CMD_DAP_JTAG_CONFIGURE 0x15 -#define CMD_DAP_JTAG_IDCODE 0x16 - -/* CMSIS-DAP Transfer Commands */ -#define CMD_DAP_TFER_CONFIGURE 0x04 -#define CMD_DAP_TFER 0x05 -#define CMD_DAP_TFER_BLOCK 0x06 -#define CMD_DAP_TFER_ABORT 0x07 - -/* DAP Status Code */ -#define DAP_OK 0 -#define DAP_ERROR 0xFF - -/* CMSIS-DAP Vendor Commands - * None as yet... */ - -static const char * const info_caps_str[] = { - "SWD Supported", - "JTAG Supported" -}; - -/* max clock speed (kHz) */ -#define DAP_MAX_CLOCK 5000 - -struct cmsis_dap { - hid_device *dev_handle; - uint16_t packet_size; - uint16_t packet_count; - uint8_t *packet_buffer; - uint8_t caps; - uint8_t mode; -}; - -struct pending_transfer_result { - uint8_t cmd; - uint32_t data; - void *buffer; -}; - -static int pending_transfer_count, pending_queue_len; -static struct pending_transfer_result *pending_transfers; - -static int queued_retval; - -static struct cmsis_dap *cmsis_dap_handle; - -static int cmsis_dap_usb_open(void) -{ - hid_device *dev = NULL; - int i; - struct hid_device_info *devs, *cur_dev; - unsigned short target_vid, target_pid; - wchar_t *target_serial = NULL; - - bool found = false; - bool serial_found = false; - - target_vid = 0; - target_pid = 0; - - /* - * The CMSIS-DAP specification stipulates: - * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the - * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer." - */ - devs = hid_enumerate(0x0, 0x0); - cur_dev = devs; - while (NULL != cur_dev) { - if (0 == cmsis_dap_vid[0]) { - if (NULL == cur_dev->product_string) { - LOG_DEBUG("Cannot read product string of device 0x%x:0x%x", - cur_dev->vendor_id, cur_dev->product_id); - } else { - if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) { - /* if the user hasn't specified VID:PID *and* - * product string contains "CMSIS-DAP", pick it - */ - found = true; - } - } - } else { - /* otherwise, exhaustively compare against all VID:PID in list */ - for (i = 0; cmsis_dap_vid[i] || cmsis_dap_pid[i]; i++) { - if ((cmsis_dap_vid[i] == cur_dev->vendor_id) && (cmsis_dap_pid[i] == cur_dev->product_id)) - found = true; - } - - if (cmsis_dap_vid[i] || cmsis_dap_pid[i]) - found = true; - } - - if (found) { - /* we have found an adapter, so exit further checks */ - /* check serial number matches if given */ - if (cmsis_dap_serial != NULL) { - if ((cur_dev->serial_number != NULL) && wcscmp(cmsis_dap_serial, cur_dev->serial_number) == 0) { - serial_found = true; - break; - } - } else - break; - - found = false; - } - - cur_dev = cur_dev->next; - } - - if (NULL != cur_dev) { - target_vid = cur_dev->vendor_id; - target_pid = cur_dev->product_id; - if (serial_found) - target_serial = cmsis_dap_serial; - } - - hid_free_enumeration(devs); - - if (target_vid == 0 && target_pid == 0) { - LOG_ERROR("unable to find CMSIS-DAP device"); - return ERROR_FAIL; - } - - if (hid_init() != 0) { - LOG_ERROR("unable to open HIDAPI"); - return ERROR_FAIL; - } - - dev = hid_open(target_vid, target_pid, target_serial); - - if (dev == NULL) { - LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid); - return ERROR_FAIL; - } - - struct cmsis_dap *dap = malloc(sizeof(struct cmsis_dap)); - if (dap == NULL) { - LOG_ERROR("unable to allocate memory"); - return ERROR_FAIL; - } - - dap->dev_handle = dev; - dap->caps = 0; - dap->mode = 0; - - cmsis_dap_handle = dap; - - /* allocate default packet buffer, may be changed later. - * currently with HIDAPI we have no way of getting the output report length - * without this info we cannot communicate with the adapter. - * For the moment we ahve to hard code the packet size */ - - int packet_size = PACKET_SIZE; - - /* atmel cmsis-dap uses 512 byte reports */ - /* TODO: HID report descriptor should be parsed instead of - * hardcoding a match by VID */ - if (target_vid == 0x03eb) - packet_size = 512 + 1; - - cmsis_dap_handle->packet_buffer = malloc(packet_size); - cmsis_dap_handle->packet_size = packet_size; - - if (cmsis_dap_handle->packet_buffer == NULL) { - LOG_ERROR("unable to allocate memory"); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static void cmsis_dap_usb_close(struct cmsis_dap *dap) -{ - hid_close(dap->dev_handle); - hid_exit(); - - free(cmsis_dap_handle->packet_buffer); - free(cmsis_dap_handle); - cmsis_dap_handle = NULL; - free(cmsis_dap_serial); - cmsis_dap_serial = NULL; - free(pending_transfers); - pending_transfers = NULL; - - return; -} - -/* Send a message and receive the reply */ -static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) -{ - /* Pad the rest of the TX buffer with 0's */ - memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen); - - /* write data to device */ - int retval = hid_write(dap->dev_handle, dap->packet_buffer, dap->packet_size); - if (retval == -1) { - LOG_ERROR("error writing data: %ls", hid_error(dap->dev_handle)); - return ERROR_FAIL; - } - - /* get reply */ - retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT); - if (retval == -1 || retval == 0) { - LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle)); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay, uint8_t *input) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_PINS; - buffer[2] = pins; - buffer[3] = mask; - buffer[4] = delay & 0xff; - buffer[5] = (delay >> 8) & 0xff; - buffer[6] = (delay >> 16) & 0xff; - buffer[7] = (delay >> 24) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 8); - - if (retval != ERROR_OK) { - LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - if (input) - *input = buffer[1]; - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - /* set clock in Hz */ - swj_clock *= 1000; - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_CLOCK; - buffer[2] = swj_clock & 0xff; - buffer[3] = (swj_clock >> 8) & 0xff; - buffer[4] = (swj_clock >> 16) & 0xff; - buffer[5] = (swj_clock >> 24) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 6); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_INFO; - buffer[2] = info; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); - - if (retval != ERROR_OK) { - LOG_ERROR("CMSIS-DAP command CMD_INFO failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - *data = &(buffer[1]); - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_LED(uint8_t leds) -{ - 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; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); - - if (retval != ERROR_OK || buffer[1] != 0x00) { - LOG_ERROR("CMSIS-DAP command CMD_LED failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_Connect(uint8_t mode) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_CONNECT; - buffer[2] = mode; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); - - if (retval != ERROR_OK) { - LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - if (buffer[1] != mode) { - LOG_ERROR("CMSIS-DAP failed to connect in mode (%d)", mode); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_Disconnect(void) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_DISCONNECT; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 2); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count, uint16_t match_retry) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_TFER_CONFIGURE; - buffer[2] = idle; - buffer[3] = retry_count & 0xff; - buffer[4] = (retry_count >> 8) & 0xff; - buffer[5] = match_retry & 0xff; - buffer[6] = (match_retry >> 8) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 7); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWD_CONFIGURE; - buffer[2] = cfg; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -#if 0 -static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us) -{ - int retval; - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_DELAY; - buffer[2] = delay_us & 0xff; - buffer[3] = (delay_us >> 8) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) { - LOG_ERROR("CMSIS-DAP command CMD_Delay failed."); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} -#endif - -static int cmsis_dap_swd_run_queue(void) -{ - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - - LOG_DEBUG("Executing %d queued transactions", pending_transfer_count); - - if (queued_retval != ERROR_OK) { - LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); - goto skip; - } - - if (!pending_transfer_count) - 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; - - for (int i = 0; i < pending_transfer_count; i++) { - uint8_t cmd = pending_transfers[i].cmd; - uint32_t data = pending_transfers[i].data; - - LOG_DEBUG("%s %s reg %x %"PRIx32, - cmd & SWD_CMD_APnDP ? "AP" : "DP", - cmd & SWD_CMD_RnW ? "read" : "write", - (cmd & SWD_CMD_A32) >> 1, data); - - /* When proper WAIT handling is implemented in the - * common SWD framework, this kludge can be - * removed. However, this might lead to minor - * performance degradation as the adapter wouldn't be - * able to automatically retry anything (because ARM - * has forgotten to implement sticky error flags - * clearing). See also comments regarding - * cmsis_dap_cmd_DAP_TFER_Configure() and - * cmsis_dap_cmd_DAP_SWD_Configure() in - * cmsis_dap_init(). - */ - if (!(cmd & SWD_CMD_RnW) && - !(cmd & SWD_CMD_APnDP) && - (cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT && - (data & CORUNDETECT)) { - LOG_DEBUG("refusing to enable sticky overrun detection"); - data &= ~CORUNDETECT; - } - - buffer[idx++] = (cmd >> 1) & 0x0f; - if (!(cmd & SWD_CMD_RnW)) { - buffer[idx++] = (data) & 0xff; - buffer[idx++] = (data >> 8) & 0xff; - buffer[idx++] = (data >> 16) & 0xff; - buffer[idx++] = (data >> 24) & 0xff; - } - } - - queued_retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 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], - 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]) - LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d", - pending_transfer_count, buffer[1]); - - for (int i = 0; i < buffer[1]; i++) { - if (pending_transfers[i].cmd & SWD_CMD_RnW) { - static uint32_t last_read; - uint32_t data = le_to_h_u32(&buffer[idx]); - uint32_t tmp = data; - idx += 4; - - LOG_DEBUG("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)) { - tmp = last_read; - last_read = data; - } - - if (pending_transfers[i].buffer) - *(uint32_t *)pending_transfers[i].buffer = tmp; - } - } - -skip: - pending_transfer_count = 0; - int retval = queued_retval; - queued_retval = ERROR_OK; - - return retval; -} - -static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) -{ - if (pending_transfer_count == pending_queue_len) { - /* Not enough room in the queue. Run the queue. */ - queued_retval = cmsis_dap_swd_run_queue(); - } - - if (queued_retval != ERROR_OK) - return; - - pending_transfers[pending_transfer_count].data = data; - pending_transfers[pending_transfer_count].cmd = cmd; - if (cmd & SWD_CMD_RnW) { - /* Queue a read transaction */ - pending_transfers[pending_transfer_count].buffer = dst; - } - pending_transfer_count++; -} - -static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) -{ - assert(!(cmd & SWD_CMD_RnW)); - cmsis_dap_swd_queue_cmd(cmd, NULL, value); -} - -static void cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) -{ - assert(cmd & SWD_CMD_RnW); - cmsis_dap_swd_queue_cmd(cmd, value, 0); -} - -static int cmsis_dap_get_version_info(void) -{ - uint8_t *data; - - /* INFO_ID_FW_VER - string */ - int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_FW_VER, &data); - if (retval != ERROR_OK) - return retval; - - if (data[0]) /* strlen */ - LOG_INFO("CMSIS-DAP: FW Version = %s", &data[1]); - - return ERROR_OK; -} - -static int cmsis_dap_get_caps_info(void) -{ - uint8_t *data; - - /* INFO_ID_CAPS - byte */ - int retval = cmsis_dap_cmd_DAP_Info(INFO_ID_CAPS, &data); - if (retval != ERROR_OK) - return retval; - - if (data[0] == 1) { - uint8_t caps = data[1]; - - cmsis_dap_handle->caps = caps; - - if (caps & INFO_CAPS_SWD) - LOG_INFO("CMSIS-DAP: %s", info_caps_str[0]); - if (caps & INFO_CAPS_JTAG) - LOG_INFO("CMSIS-DAP: %s", info_caps_str[1]); - } - - return ERROR_OK; -} - -static int cmsis_dap_get_status(void) -{ - uint8_t d; - - int retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, 0, 0, &d); - - if (retval == ERROR_OK) { - LOG_INFO("SWCLK/TCK = %d SWDIO/TMS = %d TDI = %d TDO = %d nTRST = %d nRESET = %d", - (d & (0x01 << 0)) ? 1 : 0, /* Bit 0: SWCLK/TCK */ - (d & (0x01 << 1)) ? 1 : 0, /* Bit 1: SWDIO/TMS */ - (d & (0x01 << 2)) ? 1 : 0, /* Bit 2: TDI */ - (d & (0x01 << 3)) ? 1 : 0, /* Bit 3: TDO */ - (d & (0x01 << 5)) ? 1 : 0, /* Bit 5: nTRST */ - (d & (0x01 << 7)) ? 1 : 0); /* Bit 7: nRESET */ - } - - return retval; -} - -static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) -{ - uint8_t *buffer = cmsis_dap_handle->packet_buffer; - const uint8_t *s; - unsigned int s_len; - int retval; - - /* First disconnect before connecting, Atmel EDBG needs it for SAMD/R/L/C */ - cmsis_dap_cmd_DAP_Disconnect(); - - /* When we are reconnecting, DAP_Connect needs to be rerun, at - * least on Keil ULINK-ME */ - retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ? - CONNECT_SWD : CONNECT_JTAG); - if (retval != ERROR_OK) - return retval; - - 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; - } - - buffer[0] = 0; /* report number */ - buffer[1] = CMD_DAP_SWJ_SEQ; - buffer[2] = s_len; - bit_copy(&buffer[3], 0, s, 0, s_len); - - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3); - - if (retval != ERROR_OK || buffer[1] != DAP_OK) - return ERROR_FAIL; - - return ERROR_OK; -} - -static int cmsis_dap_swd_open(void) -{ - int retval; - - if (cmsis_dap_handle == NULL) { - /* SWD init */ - retval = cmsis_dap_usb_open(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_caps_info(); - if (retval != ERROR_OK) - return retval; - } - - if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) { - LOG_ERROR("CMSIS-DAP: SWD not supported"); - return ERROR_JTAG_DEVICE_ERROR; - } - - retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD); - if (retval != ERROR_OK) - return retval; - - /* Add more setup here.??... */ - - LOG_INFO("CMSIS-DAP: Interface Initialised (SWD)"); - return ERROR_OK; -} - -static int cmsis_dap_init(void) -{ - int retval; - uint8_t *data; - - if (swd_mode) { - retval = cmsis_dap_swd_open(); - if (retval != ERROR_OK) - return retval; - } - - if (cmsis_dap_handle == NULL) { - - /* JTAG init */ - retval = cmsis_dap_usb_open(); - if (retval != ERROR_OK) - return retval; - - retval = cmsis_dap_get_caps_info(); - if (retval != ERROR_OK) - return retval; - - /* Connect in JTAG mode */ - if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) { - LOG_ERROR("CMSIS-DAP: JTAG not supported"); - return ERROR_JTAG_DEVICE_ERROR; - } - - retval = cmsis_dap_cmd_DAP_Connect(CONNECT_JTAG); - if (retval != ERROR_OK) - return retval; - - LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)"); - } - - retval = cmsis_dap_get_version_info(); - if (retval != ERROR_OK) - return retval; - - /* INFO_ID_PKT_SZ - short */ - retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data); - if (retval != ERROR_OK) - return retval; - - if (data[0] == 2) { /* short */ - uint16_t pkt_sz = data[1] + (data[2] << 8); - - /* 4 bytes of command header + 5 bytes per register - * 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 */ - cmsis_dap_handle->packet_size = pkt_sz + 1; - cmsis_dap_handle->packet_buffer = realloc(cmsis_dap_handle->packet_buffer, - cmsis_dap_handle->packet_size); - if (cmsis_dap_handle->packet_buffer == NULL) { - LOG_ERROR("unable to reallocate memory"); - return ERROR_FAIL; - } - } - - LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRId16, pkt_sz); - } - - /* INFO_ID_PKT_CNT - byte */ - retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_CNT, &data); - if (retval != ERROR_OK) - 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); - } - - retval = cmsis_dap_get_status(); - if (retval != ERROR_OK) - return ERROR_FAIL; - - /* Now try to connect to the target - * TODO: This is all SWD only @ present */ - retval = cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz()); - if (retval != ERROR_OK) - return ERROR_FAIL; - - /* Ask CMSIS-DAP to automatically retry on receiving WAIT for - * up to 64 times. This must be changed to 0 if sticky - * overrun detection is enabled. */ - retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0); - if (retval != ERROR_OK) - return ERROR_FAIL; - /* Data Phase (bit 2) must be set to 1 if sticky overrun - * detection is enabled */ - retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ - if (retval != ERROR_OK) - return ERROR_FAIL; - - retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */ - if (retval != ERROR_OK) - return ERROR_FAIL; - - /* support connecting with srst asserted */ - enum reset_types jtag_reset_config = jtag_get_reset_config(); - - 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); - 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; -} - -static int cmsis_dap_swd_init(void) -{ - swd_mode = true; - return ERROR_OK; -} - -static int cmsis_dap_quit(void) -{ - cmsis_dap_cmd_DAP_Disconnect(); - cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */ - - cmsis_dap_usb_close(cmsis_dap_handle); - - return ERROR_OK; -} - -static void cmsis_dap_execute_reset(struct jtag_command *cmd) -{ - int retval = cmsis_dap_cmd_DAP_SWJ_Pins(cmd->cmd.reset->srst ? 0 : (1 << 7), \ - (1 << 7), 0, NULL); - if (retval != ERROR_OK) - LOG_ERROR("CMSIS-DAP: Interface reset failed"); -} - -static void cmsis_dap_execute_sleep(struct jtag_command *cmd) -{ -#if 0 - int retval = cmsis_dap_cmd_DAP_Delay(cmd->cmd.sleep->us); - if (retval != ERROR_OK) -#endif - jtag_sleep(cmd->cmd.sleep->us); -} - -static void cmsis_dap_execute_command(struct jtag_command *cmd) -{ - switch (cmd->type) { - case JTAG_RESET: - cmsis_dap_execute_reset(cmd); - break; - case JTAG_SLEEP: - cmsis_dap_execute_sleep(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); - } -} - -static int cmsis_dap_execute_queue(void) -{ - struct jtag_command *cmd = jtag_command_queue; - - while (cmd != NULL) { - cmsis_dap_execute_command(cmd); - cmd = cmd->next; - } - - return ERROR_OK; -} - -static int cmsis_dap_speed(int speed) -{ - if (speed > DAP_MAX_CLOCK) { - LOG_INFO("reduce speed request: %dkHz to %dkHz maximum", speed, DAP_MAX_CLOCK); - speed = DAP_MAX_CLOCK; - } - - if (speed == 0) { - LOG_INFO("RTCK not supported"); - return ERROR_JTAG_NOT_IMPLEMENTED; - } - - return cmsis_dap_cmd_DAP_SWJ_Clock(speed); -} - -static int cmsis_dap_speed_div(int speed, int *khz) -{ - *khz = speed; - return ERROR_OK; -} - -static int cmsis_dap_khz(int khz, int *jtag_speed) -{ - *jtag_speed = khz; - return ERROR_OK; -} - -static int_least32_t cmsis_dap_swd_frequency(int_least32_t hz) -{ - if (hz > 0) - cmsis_dap_speed(hz / 1000); - - return hz; -} - -COMMAND_HANDLER(cmsis_dap_handle_info_command) -{ - if (cmsis_dap_get_version_info() == ERROR_OK) - cmsis_dap_get_status(); - - return ERROR_OK; -} - -COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command) -{ - if (CMD_ARGC > MAX_USB_IDS * 2) { - LOG_WARNING("ignoring extra IDs in cmsis_dap_vid_pid " - "(maximum is %d pairs)", MAX_USB_IDS); - CMD_ARGC = MAX_USB_IDS * 2; - } - if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { - LOG_WARNING("incomplete cmsis_dap_vid_pid configuration directive"); - if (CMD_ARGC < 2) - return ERROR_COMMAND_SYNTAX_ERROR; - /* remove the incomplete trailing id */ - CMD_ARGC -= 1; - } - - unsigned i; - for (i = 0; i < CMD_ARGC; i += 2) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], cmsis_dap_vid[i >> 1]); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], cmsis_dap_pid[i >> 1]); - } - - /* - * Explicitly terminate, in case there are multiples instances of - * cmsis_dap_vid_pid. - */ - cmsis_dap_vid[i >> 1] = cmsis_dap_pid[i >> 1] = 0; - - return ERROR_OK; -} - -COMMAND_HANDLER(cmsis_dap_handle_serial_command) -{ - if (CMD_ARGC == 1) { - size_t len = mbstowcs(NULL, CMD_ARGV[0], 0); - cmsis_dap_serial = calloc(len + 1, sizeof(wchar_t)); - if (cmsis_dap_serial == NULL) { - LOG_ERROR("unable to allocate memory"); - return ERROR_OK; - } - if (mbstowcs(cmsis_dap_serial, CMD_ARGV[0], len + 1) == (size_t)-1) { - free(cmsis_dap_serial); - cmsis_dap_serial = NULL; - LOG_ERROR("unable to convert serial"); - } - } else { - LOG_ERROR("expected exactly one argument to cmsis_dap_serial "); - } - - return ERROR_OK; -} - -static const struct command_registration cmsis_dap_subcommand_handlers[] = { - { - .name = "info", - .handler = &cmsis_dap_handle_info_command, - .mode = COMMAND_EXEC, - .usage = "", - .help = "show cmsis-dap info", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration cmsis_dap_command_handlers[] = { - { - .name = "cmsis-dap", - .mode = COMMAND_ANY, - .help = "perform CMSIS-DAP management", - .usage = "", - .chain = cmsis_dap_subcommand_handlers, - }, - { - .name = "cmsis_dap_vid_pid", - .handler = &cmsis_dap_handle_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "the vendor ID and product ID of the CMSIS-DAP device", - .usage = "(vid pid)* ", - }, - { - .name = "cmsis_dap_serial", - .handler = &cmsis_dap_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the adapter", - .usage = "serial_string", - }, - COMMAND_REGISTRATION_DONE -}; - -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, - .run = cmsis_dap_swd_run_queue, -}; - -static const char * const cmsis_dap_transport[] = { "swd", NULL }; - -struct jtag_interface cmsis_dap_interface = { - .name = "cmsis-dap", - .commands = cmsis_dap_command_handlers, - .swd = &cmsis_dap_swd_driver, - .transports = cmsis_dap_transport, - - .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, -};