From: Spencer Oliver Date: Mon, 12 Nov 2012 15:06:37 +0000 (+0000) Subject: icdi: add TI icdi interface X-Git-Tag: v0.7.0-rc1~127 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=adb8ec32dc7439aa3e34ab19f026e390ec129c10 icdi: add TI icdi interface This is the new proprietary interface replacing the older FTDI based adapters. It is currently fitted to the ek-lm4f232 and Stellaris LaunchPad. Change-Id: I794ad79e31ff61ec8e9f49530aca9308025c0b60 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/922 Tested-by: jenkins --- diff --git a/README b/README index 7b1f4a2af0..08aa4f2a0a 100644 --- a/README +++ b/README @@ -275,6 +275,8 @@ options may be available there: --enable-stlink Enable building support for the ST-Link JTAG Programmer + --enable-ti-icdi Enable building support for the TI/Stellaris ICDI + JTAG Programmer --enable-osbdm Enable building support for the OSBDM (JTAG only) Programmer diff --git a/configure.ac b/configure.ac index 99f39d4fa3..51d43baacd 100644 --- a/configure.ac +++ b/configure.ac @@ -477,7 +477,11 @@ AC_ARG_ENABLE([buspirate], AC_ARG_ENABLE([stlink], AS_HELP_STRING([--enable-stlink], [Enable building support for the ST-Link JTAG Programmer]), - [build_hladapter=$enableval], [build_hladapter=no]) + [build_hladapter_stlink=$enableval], [build_hladapter_stlink=no]) + +AC_ARG_ENABLE([ti-icdi], + AS_HELP_STRING([--enable-ti-icdi], [Enable building support for the TI ICDI JTAG Programmer]), + [build_hladapter_icdi=$enableval], [build_hladapter_icdi=no]) AC_ARG_ENABLE([osbdm], AS_HELP_STRING([--enable-osbdm], [Enable building support for the OSBDM (JTAG only) Programmer]), @@ -790,10 +794,10 @@ else AC_DEFINE([BUILD_BUSPIRATE], [0], [0 if you don't want the Buspirate JTAG driver.]) fi -if test $build_hladapter = yes; then - AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the ST-Link JTAG driver.]) +if test $build_hladapter_stlink = yes -o $build_hladapter_icdi = yes; then + AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.]) else - AC_DEFINE([BUILD_HLADAPTER], [0], [0 if you don't want the ST-Link JTAG driver.]) + AC_DEFINE([BUILD_HLADAPTER], [0], [0 if you don't want the High Level JTAG driver.]) fi if test $build_osbdm = yes; then @@ -1142,8 +1146,8 @@ fi # Check for libusb1 ported drivers. build_usb_ng=no -if test $build_jlink = yes -o $build_hladapter = yes -o $build_osbdm = yes -o \ - $build_opendous = yes -o $build_ftdi = yes +if test $build_jlink = yes -o $build_hladapter_stlink = yes -o $build_osbdm = yes -o \ + $build_opendous = yes -o $build_ftdi = yes -o $build_hladapter_icdi = yes then build_usb_ng=yes fi @@ -1192,7 +1196,7 @@ AM_CONDITIONAL([ULINK], [test $build_ulink = yes]) AM_CONDITIONAL([ARMJTAGEW], [test $build_armjtagew = yes]) AM_CONDITIONAL([REMOTE_BITBANG], [test $build_remote_bitbang = yes]) AM_CONDITIONAL([BUSPIRATE], [test $build_buspirate = yes]) -AM_CONDITIONAL([HLADAPTER], [test $build_hladapter = yes]) +AM_CONDITIONAL([HLADAPTER], [test $build_hladapter_stlink = yes -o $build_hladapter_icdi = yes]) AM_CONDITIONAL([OSBDM], [test $build_osbdm = yes]) AM_CONDITIONAL([OPENDOUS], [test $build_opendous = yes]) AM_CONDITIONAL([SYSFSGPIO], [test $build_sysfsgpio = yes]) diff --git a/contrib/openocd.udev b/contrib/openocd.udev index 5d4e63961c..7065014a30 100644 --- a/contrib/openocd.udev +++ b/contrib/openocd.udev @@ -49,12 +49,15 @@ ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="664", GROUP="plugdev" # Hitex STM32-PerformanceStick ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="664", GROUP="plugdev" -# TI/Luminary Stellaris Evaluation Board (several) +# TI/Luminary Stellaris Evaluation Board FTDI (several) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="664", GROUP="plugdev" -# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board +# TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="664", GROUP="plugdev" +# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board +ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="664", GROUP="plugdev" + # Xverve Signalyzer Tool (DT-USB-ST) ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="664", GROUP="plugdev" diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c index d98fa16212..a90ec7b01e 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -370,3 +370,30 @@ void bit_copy_discard(struct bit_copy_queue *q) free(qe); } } + +int unhexify(char *bin, const char *hex, int count) +{ + int i, tmp; + + for (i = 0; i < count; i++) { + if (sscanf(hex + (2 * i), "%02x", &tmp) != 1) + return i; + bin[i] = tmp; + } + + return i; +} + +int hexify(char *hex, const char *bin, int count, int out_maxlen) +{ + int i, cmd_len = 0; + + /* May use a length, or a null-terminated string as input. */ + if (count == 0) + count = strlen(bin); + + for (i = 0; i < count; i++) + cmd_len += snprintf(hex + cmd_len, out_maxlen - cmd_len, "%02x", bin[i]); + + return cmd_len; +} diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index cc0be57dcf..633ed9e5dc 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -156,4 +156,9 @@ int bit_copy_queued(struct bit_copy_queue *q, uint8_t *dst, unsigned dst_offset, void bit_copy_execute(struct bit_copy_queue *q); void bit_copy_discard(struct bit_copy_queue *q); +/* functions to convert to/from hex encoded buffer + * used in ti-icdi driver and gdb server */ +int unhexify(char *bin, const char *hex, int count); +int hexify(char *hex, const char *bin, int count, int out_maxlen); + #endif /* BINARYBUFFER_H */ diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 6d232d26f6..e064399b5c 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -100,6 +100,7 @@ DRIVERFILES += remote_bitbang.c endif if HLADAPTER DRIVERFILES += stlink_usb.c +DRIVERFILES += ti_icdi_usb.c endif if OSBDM DRIVERFILES += osbdm.c diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c new file mode 100644 index 0000000000..6729522371 --- /dev/null +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -0,0 +1,730 @@ +/*************************************************************************** + * * + * Copyright (C) 2012 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, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* project specific includes */ +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define ICDI_WRITE_ENDPOINT 0x02 +#define ICDI_READ_ENDPOINT 0x83 + +#define ICDI_WRITE_TIMEOUT 1000 +#define ICDI_READ_TIMEOUT 1000 +#define ICDI_PACKET_SIZE 2048 + +#define PACKET_START "$" +#define PACKET_END "#" + +struct icdi_usb_handle_s { + libusb_context *usb_ctx; + libusb_device_handle *usb_dev; + + char *read_buffer; + char *write_buffer; + int max_packet; + int read_count; +}; + +static int icdi_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer); +static int icdi_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer); + +static int remote_escape_output(const char *buffer, int len, char *out_buf, int *out_len, int out_maxlen) +{ + int input_index, output_index; + + output_index = 0; + + for (input_index = 0; input_index < len; input_index++) { + + char b = buffer[input_index]; + + if (b == '$' || b == '#' || b == '}' || b == '*') { + /* These must be escaped. */ + if (output_index + 2 > out_maxlen) + break; + out_buf[output_index++] = '}'; + out_buf[output_index++] = b ^ 0x20; + } else { + if (output_index + 1 > out_maxlen) + break; + out_buf[output_index++] = b; + } + } + + *out_len = input_index; + return output_index; +} + +static int remote_unescape_input(const char *buffer, int len, char *out_buf, int out_maxlen) +{ + int input_index, output_index; + int escaped; + + output_index = 0; + escaped = 0; + + for (input_index = 0; input_index < len; input_index++) { + + char b = buffer[input_index]; + + if (output_index + 1 > out_maxlen) + LOG_ERROR("Received too much data from the target."); + + if (escaped) { + out_buf[output_index++] = b ^ 0x20; + escaped = 0; + } else if (b == '}') + escaped = 1; + else + out_buf[output_index++] = b; + } + + if (escaped) + LOG_ERROR("Unmatched escape character in target response."); + + return output_index; +} + +static int icdi_send_packet(void *handle, int len) +{ + unsigned char cksum = 0; + struct icdi_usb_handle_s *h; + int result, retry = 0; + int transferred = 0; + + assert(handle != NULL); + h = (struct icdi_usb_handle_s *)handle; + + /* check we have a large enough buffer for checksum "#00" */ + if (len + 3 > h->max_packet) { + LOG_ERROR("packet buffer too small"); + return ERROR_FAIL; + } + + /* calculate checksum - offset start of packet */ + for (int i = 1; i < len; i++) + cksum += h->write_buffer[i]; + + len += sprintf(&h->write_buffer[len], PACKET_END "%02x", cksum); + +#ifdef _DEBUG_USB_COMMS_ + char buffer[50]; + char ch = h->write_buffer[1]; + if (ch == 'x' || ch == 'X') + LOG_DEBUG("writing packet: "); + else { + memcpy(buffer, h->write_buffer, len >= 50 ? 50-1 : len); + buffer[len] = 0; + LOG_DEBUG("writing packet: %s", buffer); + } +#endif + + while (1) { + + result = libusb_bulk_transfer(h->usb_dev, ICDI_WRITE_ENDPOINT, (unsigned char *)h->write_buffer, len, + &transferred, ICDI_WRITE_TIMEOUT); + if (result != 0 || transferred != len) { + LOG_DEBUG("Error TX Data %d", result); + return ERROR_FAIL; + } + + /* check that the client got the message ok, or shall we resend */ + result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer, h->max_packet, + &transferred, ICDI_READ_TIMEOUT); + if (result != 0 || transferred < 1) { + LOG_DEBUG("Error RX Data %d", result); + return ERROR_FAIL; + } + +#ifdef _DEBUG_USB_COMMS_ + LOG_DEBUG("received reply: '%c' : count %d", h->read_buffer[0], transferred); +#endif + + if (h->read_buffer[0] == '-') { + LOG_DEBUG("Resending packet %d", ++retry); + } else { + if (h->read_buffer[0] != '+') + LOG_DEBUG("Unexpected Reply from ICDI: %c", h->read_buffer[0]); + break; + } + + if (retry == 3) { + LOG_DEBUG("maximum nack retries attempted"); + return ERROR_FAIL; + } + } + + retry = 0; + h->read_count = transferred; + + while (1) { + + /* read reply from icdi */ + result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer + h->read_count, + h->max_packet - h->read_count, &transferred, ICDI_READ_TIMEOUT); + +#ifdef _DEBUG_USB_COMMS_ + LOG_DEBUG("received data: count %d", transferred); +#endif + + /* check for errors but retry for timeout */ + if (result != 0) { + + if (result == LIBUSB_ERROR_TIMEOUT) { + LOG_DEBUG("Error RX timeout %d", result); + } else { + LOG_DEBUG("Error RX Data %d", result); + return ERROR_FAIL; + } + } + + h->read_count += transferred; + + /* we need to make sure we have a full packet, including checksum */ + if (h->read_count > 5) { + + /* check that we have received an packet delimiter + * we do not validate the checksum + * reply should contain $...#AA - so we check for # */ + if (h->read_buffer[h->read_count - 3] == '#') + return ERROR_OK; + } + + if (retry++ == 3) { + LOG_DEBUG("maximum data retries attempted"); + break; + } + } + + return ERROR_FAIL; +} + +static int icdi_send_cmd(void *handle, const char *cmd) +{ + struct icdi_usb_handle_s *h; + h = (struct icdi_usb_handle_s *)handle; + + int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd); + return icdi_send_packet(handle, cmd_len); +} + +static int icdi_send_remote_cmd(void *handle, const char *data) +{ + struct icdi_usb_handle_s *h; + h = (struct icdi_usb_handle_s *)handle; + + size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,"); + cmd_len += hexify(h->write_buffer + cmd_len, data, 0, h->max_packet - cmd_len); + + return icdi_send_packet(handle, cmd_len); +} + +static int icdi_get_cmd_result(void *handle) +{ + struct icdi_usb_handle_s *h; + int offset = 0; + char ch; + + assert(handle != NULL); + h = (struct icdi_usb_handle_s *)handle; + + do { + ch = h->read_buffer[offset++]; + if (offset > h->read_count) + return ERROR_FAIL; + } while (ch != '$'); + + if (memcmp("OK", h->read_buffer + offset, 2) == 0) + return ERROR_OK; + + if (h->read_buffer[offset] == 'E') { + /* get error code */ + char result; + if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1) + return ERROR_FAIL; + return result; + } + + /* for now we assume everything else is ok */ + return ERROR_OK; +} + +static int icdi_usb_idcode(void *handle, uint32_t *idcode) +{ + return ERROR_OK; +} + +static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) +{ + return icdi_usb_write_mem32(handle, addr, 1, (uint8_t *)&val); +} + +static enum target_state icdi_usb_state(void *handle) +{ + int result; + struct icdi_usb_handle_s *h; + uint32_t dhcsr; + + h = (struct icdi_usb_handle_s *)handle; + + result = icdi_usb_read_mem32(h, DCB_DHCSR, 1, (uint8_t *)&dhcsr); + if (result != ERROR_OK) + return TARGET_UNKNOWN; + + if (dhcsr & S_HALT) + return TARGET_HALTED; + + return TARGET_RUNNING; +} + +static int icdi_usb_version(void *handle) +{ + struct icdi_usb_handle_s *h; + h = (struct icdi_usb_handle_s *)handle; + + char version[20]; + + /* get info about icdi */ + int result = icdi_send_remote_cmd(handle, "version"); + if (result != ERROR_OK) + return result; + + if (h->read_count < 8) { + LOG_ERROR("Invalid Reply Received"); + return ERROR_FAIL; + } + + /* convert reply */ + if (unhexify(version, h->read_buffer + 2, 4) != 4) { + LOG_WARNING("unable to get ICDI version"); + return ERROR_OK; + } + + /* null terminate and print info */ + version[4] = 0; + + LOG_INFO("ICDI Firmware version: %s", version); + + return ERROR_OK; +} + +static int icdi_usb_query(void *handle) +{ + int result; + + struct icdi_usb_handle_s *h; + h = (struct icdi_usb_handle_s *)handle; + + result = icdi_send_cmd(handle, "qSupported"); + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("query supported failed: 0x%x", result); + return ERROR_FAIL; + } + + /* from this we can get the max packet supported */ + + /* query packet buffer size */ + char *offset = strstr(h->read_buffer, "PacketSize"); + if (offset) { + char *separator; + int max_packet; + + max_packet = strtoul(offset + 11, &separator, 16); + if (!max_packet) + LOG_ERROR("invalid max packet, using defaults"); + else + h->max_packet = max_packet; + LOG_DEBUG("max packet supported : %" PRIu32 " bytes", h->max_packet); + } + + + /* if required re allocate packet buffer */ + if (h->max_packet != ICDI_PACKET_SIZE) { + h->read_buffer = realloc(h->read_buffer, h->max_packet); + h->write_buffer = realloc(h->write_buffer, h->max_packet); + if (h->read_buffer == 0 || h->write_buffer == 0) { + LOG_ERROR("unable to reallocate memory"); + return ERROR_FAIL; + } + } + + /* set extended mode */ + result = icdi_send_cmd(handle, "!"); + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("unable to enable extended mode: 0x%x", result); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int icdi_usb_reset(void *handle) +{ + /* we do this in hla_target.c */ + return ERROR_OK; +} + +static int icdi_usb_assert_srst(void *handle, int srst) +{ + /* TODO not supported yet */ + return ERROR_COMMAND_NOTFOUND; +} + +static int icdi_usb_run(void *handle) +{ + int result; + + /* resume target at current address */ + result = icdi_send_cmd(handle, "c"); + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("continue failed: 0x%x", result); + return ERROR_FAIL; + } + + return result; +} + +static int icdi_usb_halt(void *handle) +{ + int result; + + /* this query halts the target ?? */ + result = icdi_send_cmd(handle, "?"); + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("halt failed: 0x%x", result); + return ERROR_FAIL; + } + + return result; +} + +static int icdi_usb_step(void *handle) +{ + int result; + + /* step target at current address */ + result = icdi_send_cmd(handle, "s"); + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("step failed: 0x%x", result); + return ERROR_FAIL; + } + + return result; +} + +static int icdi_usb_read_regs(void *handle) +{ + /* currently unsupported */ + return ERROR_OK; +} + +static int icdi_usb_read_reg(void *handle, int num, uint32_t *val) +{ + int result; + struct icdi_usb_handle_s *h; + char cmd[10]; + + h = (struct icdi_usb_handle_s *)handle; + + snprintf(cmd, sizeof(cmd), "p%x", num); + result = icdi_send_cmd(handle, cmd); + if (result != ERROR_OK) + return result; + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("register read failed: 0x%x", result); + return ERROR_FAIL; + } + + /* convert result */ + if (unhexify((char *)val, h->read_buffer + 2, 4) != 4) { + LOG_ERROR("failed to convert result"); + return ERROR_FAIL; + } + + return result; +} + +static int icdi_usb_write_reg(void *handle, int num, uint32_t val) +{ + int result; + char cmd[20]; + + int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num); + hexify(cmd + cmd_len, (char *)&val, 4, sizeof(cmd)); + + result = icdi_send_cmd(handle, cmd); + if (result != ERROR_OK) + return result; + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("register write failed: 0x%x", result); + return ERROR_FAIL; + } + + return result; +} + +static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer) +{ + int result; + struct icdi_usb_handle_s *h; + char cmd[20]; + + h = (struct icdi_usb_handle_s *)handle; + + snprintf(cmd, sizeof(cmd), "x%x,%x", addr, len); + result = icdi_send_cmd(handle, cmd); + if (result != ERROR_OK) + return result; + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("memory read failed: 0x%x", result); + return ERROR_FAIL; + } + + /* unescape input */ + int read_len = remote_unescape_input(h->read_buffer + 5, h->read_count - 8, (char *)buffer, len); + if (read_len != (int)len) { + LOG_ERROR("read more bytes than expected: actual 0x%" PRIx32 " expected 0x%" PRIx32, read_len, len); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer) +{ + int result; + struct icdi_usb_handle_s *h; + + h = (struct icdi_usb_handle_s *)handle; + + size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%x,%x:", addr, len); + + int out_len; + cmd_len += remote_escape_output((char *)buffer, len, h->write_buffer + cmd_len, + &out_len, h->max_packet - cmd_len); + + if (out_len < (int)len) { + /* for now issue a error as we have no way of allocating a larger buffer */ + LOG_ERROR("memory buffer too small: requires 0x%" PRIx32 " actual 0x%" PRIx32, out_len, len); + return ERROR_FAIL; + } + + result = icdi_send_packet(handle, cmd_len); + if (result != ERROR_OK) + return result; + + /* check result */ + result = icdi_get_cmd_result(handle); + if (result != ERROR_OK) { + LOG_ERROR("memory write failed: 0x%x", result); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int icdi_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) +{ + return icdi_usb_read_mem(handle, addr, len, buffer); +} + +static int icdi_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) +{ + return icdi_usb_write_mem(handle, addr, len, buffer); +} + +static int icdi_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) +{ + return icdi_usb_read_mem(handle, addr, len * 4, buffer); +} + +static int icdi_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) +{ + return icdi_usb_write_mem(handle, addr, len * 4, buffer); +} + +static int icdi_usb_close(void *handle) +{ + struct icdi_usb_handle_s *h; + + h = (struct icdi_usb_handle_s *)handle; + + if (h->usb_dev) + libusb_close(h->usb_dev); + + if (h->usb_ctx) + libusb_exit(h->usb_ctx); + + if (h->read_buffer) + free(h->read_buffer); + + if (h->write_buffer) + free(h->write_buffer); + + free(handle); + + return ERROR_OK; +} + +static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) +{ + int retval; + struct icdi_usb_handle_s *h; + + LOG_DEBUG("icdi_usb_open"); + + h = calloc(1, sizeof(struct icdi_usb_handle_s)); + + if (h == 0) { + LOG_ERROR("unable to allocate memory"); + return ERROR_FAIL; + } + + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport, + param->vid, param->pid); + + if (libusb_init(&h->usb_ctx) != 0) { + LOG_ERROR("libusb init failed"); + goto error_open; + } + + h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid, param->pid); + if (!h->usb_dev) { + LOG_ERROR("open failed"); + goto error_open; + } + + if (libusb_claim_interface(h->usb_dev, 2)) { + LOG_DEBUG("claim interface failed"); + goto error_open; + } + + /* check if mode is supported */ + retval = ERROR_OK; + + switch (param->transport) { +#if 0 + /* TODO place holder as swd is not currently supported */ + case HL_TRANSPORT_SWD: +#endif + case HL_TRANSPORT_JTAG: + break; + default: + retval = ERROR_FAIL; + break; + } + + if (retval != ERROR_OK) { + LOG_ERROR("mode (transport) not supported by device"); + goto error_open; + } + + /* allocate buffer */ + h->read_buffer = malloc(ICDI_PACKET_SIZE); + h->write_buffer = malloc(ICDI_PACKET_SIZE); + h->max_packet = ICDI_PACKET_SIZE; + + if (h->read_buffer == 0 || h->write_buffer == 0) { + LOG_DEBUG("malloc failed"); + goto error_open; + } + + /* query icdi version etc */ + retval = icdi_usb_version(h); + if (retval != ERROR_OK) + goto error_open; + + /* query icdi support */ + retval = icdi_usb_query(h); + if (retval != ERROR_OK) + goto error_open; + + *fd = h; + + /* set the max target read/write buffer in bytes + * as we are using gdb binary packets to transfer memory we have to + * reserve half the buffer for any possible escape chars plus + * at least 64 bytes for the gdb packet header */ + param->max_buffer = (((h->max_packet - 64) / 4) * 4) / 2; + + return ERROR_OK; + +error_open: + icdi_usb_close(h); + + return ERROR_FAIL; +} + +struct hl_layout_api_s icdi_usb_layout_api = { + .open = icdi_usb_open, + .close = icdi_usb_close, + .idcode = icdi_usb_idcode, + .state = icdi_usb_state, + .reset = icdi_usb_reset, + .assert_srst = icdi_usb_assert_srst, + .run = icdi_usb_run, + .halt = icdi_usb_halt, + .step = icdi_usb_step, + .read_regs = icdi_usb_read_regs, + .read_reg = icdi_usb_read_reg, + .write_reg = icdi_usb_write_reg, + .read_mem8 = icdi_usb_read_mem8, + .write_mem8 = icdi_usb_write_mem8, + .read_mem32 = icdi_usb_read_mem32, + .write_mem32 = icdi_usb_write_mem32, + .write_debug_reg = icdi_usb_write_debug_reg +}; diff --git a/src/jtag/hla/hla_layout.c b/src/jtag/hla/hla_layout.c index 55657294c2..54c531401f 100644 --- a/src/jtag/hla/hla_layout.c +++ b/src/jtag/hla/hla_layout.c @@ -71,6 +71,12 @@ static const struct hl_layout hl_layouts[] = { .close = hl_layout_close, .api = &stlink_usb_layout_api, }, + { + .name = "ti-icdi", + .open = hl_layout_open, + .close = hl_layout_close, + .api = &icdi_usb_layout_api, + }, {.name = NULL, /* END OF TABLE */ }, }; diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index 982d71a864..3fd361eace 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -30,6 +30,7 @@ struct hl_interface_param_s; /** */ extern struct hl_layout_api_s stlink_usb_layout_api; +extern struct hl_layout_api_s icdi_usb_layout_api; /** */ struct hl_layout_api_s { diff --git a/tcl/board/ek-lm4f120xl.cfg b/tcl/board/ek-lm4f120xl.cfg new file mode 100644 index 0000000000..aa6935c95c --- /dev/null +++ b/tcl/board/ek-lm4f120xl.cfg @@ -0,0 +1,15 @@ +# +# TI Stellaris Launchpad ek-lm4f120xl Evaluation Kits +# +# http://www.ti.com/tool/ek-lm4f120xl +# + +# +# NOTE: using the bundled ICDI interface is optional! +# This interface is not ftdi based as previous boards were +# +source [find interface/ti-icdi.cfg] + +set WORKAREASIZE 0x8000 +set CHIPNAME lm4f120h5qr +source [find target/stellaris_icdi.cfg] diff --git a/tcl/board/ek-lm4f232.cfg b/tcl/board/ek-lm4f232.cfg index 6e3f8e3192..ebbc01d305 100644 --- a/tcl/board/ek-lm4f232.cfg +++ b/tcl/board/ek-lm4f232.cfg @@ -4,10 +4,12 @@ # http://www.ti.com/tool/ek-lm4f232 # -# NOTE: using the bundled FT2232 JTAG/SWD/SWO interface is optional! -# so is using in JTAG mode, as done here. -source [find interface/luminary-icdi.cfg] +# +# NOTE: using the bundled ICDI interface is optional! +# This interface is not ftdi based as previous boards were +# +source [find interface/ti-icdi.cfg] set WORKAREASIZE 0x8000 set CHIPNAME lm4f23x -source [find target/stellaris.cfg] +source [find target/stellaris_icdi.cfg] diff --git a/tcl/interface/ti-icdi.cfg b/tcl/interface/ti-icdi.cfg new file mode 100644 index 0000000000..16a901e931 --- /dev/null +++ b/tcl/interface/ti-icdi.cfg @@ -0,0 +1,15 @@ +# +# TI Stellaris In-Circuit Debug Interface (ICDI) Board +# +# This is the propriety ICDI interface used on newer boards such as +# LM4F232 Evaluation Kit - http://www.ti.com/tool/ek-lm4f232 +# Stellaris Launchpad - http://www.ti.com/stellaris-launchpad +# http://www.ti.com/tool/ek-lm4f232 +# + +interface hla +hla_layout ti-icdi +hla_vid_pid 0x1cbe 0x00fd + +# unused but set to disable warnings +adapter_khz 1000 diff --git a/tcl/target/stellaris_icdi.cfg b/tcl/target/stellaris_icdi.cfg new file mode 100644 index 0000000000..11d57c26a0 --- /dev/null +++ b/tcl/target/stellaris_icdi.cfg @@ -0,0 +1,34 @@ +# +# lm3s icdi pseudo target +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME lm3s +} + +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +# +# possible value are hla_jtag +# currently swd is not supported +# +transport select hla_jtag + +# do not check id as icdi currently does not support it +hla newtap $_CHIPNAME cpu -expected-id 0 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME hla_target -chain-position $_TARGETNAME + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# flash configuration ... autodetects sizes, autoprobed +flash bank $_CHIPNAME.flash stellaris 0 0 0 0 $_TARGETNAME