From 1d8b6b743416bfda8f82c80aa2278c2d88e2afaa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vianney=20le=20Cl=C3=A9ment=20de=20Saint-Marcq?= Date: Tue, 2 Jun 2015 16:55:42 +0200 Subject: [PATCH] jtag/drivers/openjtag: Add support for Cypress CY7C65215 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The Cypress CY7C65215 Dual Channel USB-Serial Bridge Controller [1] understands the OpenJTAG protocol over a proprietary USB interface. This patch adds support for the CY7C65215 to the openjtag interface driver. A new configuration option, `openjtag_variant`, allows to select the transport to use. Libusb (1.x or 0.1) is now a hard dependency of the openjtag driver. This should not be a big issue as libftdi also depends on it. [1] http://www.cypress.com/?rID=82870 Change-Id: I55ffb3fd9e006eb311e405d9fb836bb119644bfd Signed-off-by: Vianney le Clément de Saint-Marcq Signed-off-by: Ricardo Ribalda Delgado Reviewed-on: http://openocd.zylin.com/2805 Tested-by: jenkins Reviewed-by: Jiri Kastner Reviewed-by: Paul Fertser --- configure.ac | 7 + doc/openocd.texi | 21 +++ src/jtag/drivers/openjtag.c | 273 ++++++++++++++++++++++++++++++++---- 3 files changed, 275 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index a47a1841..1e6be141 100644 --- a/configure.ac +++ b/configure.ac @@ -782,6 +782,13 @@ PROCESS_ADAPTERS([USB0_ADAPTERS], [$use_libusb0 = yes], [libusb-0.1]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], [$use_hidapi = yes], [hidapi]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], [$use_libusb1 = yes -a $use_internal_libjaylink = yes -o $HAVE_LIBJAYLINK = yes], [libusb-1.x or libjaylink-0.1]) +if test $build_openjtag = yes; then + if test $use_libusb1 != yes -a $use_libusb0 != yes; then + AC_MSG_ERROR([libusb-1.x or libusb-0.1 is required for the OpenJTAG Programmer]) + build_openjtag=no + fi +fi + if test $enable_stlink != no -o $enable_ti_icdi != no; then AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.]) else diff --git a/doc/openocd.texi b/doc/openocd.texi index 1cca4ab1..7c2152b1 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2912,6 +2912,27 @@ pinout. @end deffn +@deffn {Interface Driver} {openjtag} +OpenJTAG compatible USB adapter. +This defines some driver-specific commands: + +@deffn {Config Command} {openjtag_variant} variant +Specifies the variant of the OpenJTAG adapter (see @uref{http://www.openjtag.org/}). +Currently valid @var{variant} values include: + +@itemize @minus +@item @b{standard} Standard variant (default). +@item @b{cy7c65215} Cypress CY7C65215 Dual Channel USB-Serial Bridge Controller +(see @uref{http://www.cypress.com/?rID=82870}). +@end itemize +@end deffn + +@deffn {Config Command} {openjtag_device_desc} string +The USB device description string of the adapter. +This value is only used with the standard variant. +@end deffn +@end deffn + @section Transport Configuration @cindex Transport As noted earlier, depending on the version of OpenOCD you use, diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 5d1084ce..bb0ff74d 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -1,6 +1,10 @@ /******************************************************************************* * Driver for OpenJTAG Project (www.openjtag.org) * - * Compatible with libftdi driver. * + * Compatible with libftdi and ftd2xx drivers. * + * * + * Cypress CY7C65215 support * + * Copyright (C) 2015 Vianney le Clément de Saint-Marcq, Essensium NV * + * * * * * Copyright (C) 2010 by Ivan Meleca * * * @@ -41,7 +45,18 @@ #include #include -#include "usb_common.h" +#include "libusb_common.h" + +static enum { + OPENJTAG_VARIANT_STANDARD, + OPENJTAG_VARIANT_CY7C65215, +} openjtag_variant = OPENJTAG_VARIANT_STANDARD; + +static const char * const openjtag_variant_names[] = { + "standard", + "cy7c65215", + NULL +}; /* * OpenJTAG-OpenOCD state conversion @@ -96,10 +111,24 @@ static uint8_t usb_rx_buf[OPENJTAG_BUFFER_SIZE]; static struct openjtag_scan_result openjtag_scan_result_buffer[OPENJTAG_MAX_PENDING_RESULTS]; static int openjtag_scan_result_count; -/* Openocd usb handler */ -struct openocd { - struct usb_dev_handle *usb_handle; -}; +static jtag_libusb_device_handle *usbh; + +/* CY7C65215 model only */ +#define CY7C65215_JTAG_REQUEST 0x40 /* bmRequestType: vendor host-to-device */ +#define CY7C65215_JTAG_ENABLE 0xD0 /* bRequest: enable JTAG */ +#define CY7C65215_JTAG_DISABLE 0xD1 /* bRequest: disable JTAG */ +#define CY7C65215_JTAG_READ 0xD2 /* bRequest: read buffer */ +#define CY7C65215_JTAG_WRITE 0xD3 /* bRequest: write buffer */ + +#define CY7C65215_USB_TIMEOUT 100 + +static const uint16_t cy7c65215_vids[] = {0x04b4, 0}; +static const uint16_t cy7c65215_pids[] = {0x0007, 0}; + +#define CY7C65215_JTAG_CLASS 0xff +#define CY7C65215_JTAG_SUBCLASS 0x04 + +static unsigned int ep_in, ep_out; #ifdef _DEBUG_USB_COMMS_ @@ -185,7 +214,7 @@ static int8_t openjtag_get_tap_state(int8_t state) } } -static int openjtag_buf_write( +static int openjtag_buf_write_standard( uint8_t *buf, int size, uint32_t *bytes_written) { int retval; @@ -205,8 +234,54 @@ static int openjtag_buf_write( return ERROR_OK; } -static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read) +static int openjtag_buf_write_cy7c65215( + uint8_t *buf, int size, uint32_t *bytes_written) +{ + int ret; + +#ifdef _DEBUG_USB_COMMS_ + openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE); +#endif + + if (size == 0) { + *bytes_written = 0; + return ERROR_OK; + } + + ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, + CY7C65215_JTAG_WRITE, size, 0, + NULL, 0, CY7C65215_USB_TIMEOUT); + if (ret < 0) { + LOG_ERROR("vendor command failed, error %d", ret); + return ERROR_JTAG_DEVICE_ERROR; + } + + ret = jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size, + CY7C65215_USB_TIMEOUT); + if (ret < 0) { + LOG_ERROR("bulk write failed, error %d", ret); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_written = ret; + + return ERROR_OK; +} + +static int openjtag_buf_write( + uint8_t *buf, int size, uint32_t *bytes_written) +{ + switch (openjtag_variant) { + case OPENJTAG_VARIANT_CY7C65215: + return openjtag_buf_write_cy7c65215(buf, size, bytes_written); + default: + return openjtag_buf_write_standard(buf, size, bytes_written); + } +} + +static int openjtag_buf_read_standard( + uint8_t *buf, uint32_t qty, uint32_t *bytes_read) { + int retval; int timeout = 5; @@ -231,6 +306,50 @@ static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read) return ERROR_OK; } +static int openjtag_buf_read_cy7c65215( + uint8_t *buf, uint32_t qty, uint32_t *bytes_read) +{ + int ret; + + if (qty == 0) { + *bytes_read = 0; + goto out; + } + + ret = jtag_libusb_control_transfer(usbh, CY7C65215_JTAG_REQUEST, + CY7C65215_JTAG_READ, qty, 0, + NULL, 0, CY7C65215_USB_TIMEOUT); + if (ret < 0) { + LOG_ERROR("vendor command failed, error %d", ret); + return ERROR_JTAG_DEVICE_ERROR; + } + + ret = jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty, + CY7C65215_USB_TIMEOUT); + if (ret < 0) { + LOG_ERROR("bulk read failed, error %d", ret); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_read = ret; + +out: +#ifdef _DEBUG_USB_COMMS_ + openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ); +#endif + + return ERROR_OK; +} + +static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read) +{ + switch (openjtag_variant) { + case OPENJTAG_VARIANT_CY7C65215: + return openjtag_buf_read_cy7c65215(buf, qty, bytes_read); + default: + return openjtag_buf_read_standard(buf, qty, bytes_read); + } +} + static int openjtag_sendcommand(uint8_t cmd) { uint32_t written; @@ -275,16 +394,10 @@ static int openjtag_speed(int speed) return ERROR_OK; } -static int openjtag_init(void) +static int openjtag_init_standard(void) { uint8_t latency_timer; - usb_tx_buf_offs = 0; - usb_rx_buf_len = 0; - openjtag_scan_result_count = 0; - - LOG_DEBUG("'openjtag' interface using libftdi"); - /* Open by device description */ if (openjtag_device_desc == NULL) { LOG_WARNING("no openjtag device description specified, " @@ -330,16 +443,70 @@ static int openjtag_init(void) return ERROR_JTAG_INIT_FAILED; } - /* OpenJTAG speed */ - openjtag_sendcommand(0xE0); /*Start at slowest adapter speed*/ + return ERROR_OK; +} + +static int openjtag_init_cy7c65215(void) +{ + int ret; + + usbh = NULL; + ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh); + if (ret != ERROR_OK) { + LOG_ERROR("unable to open cy7c65215 device"); + goto err; + } + + ret = jtag_libusb_choose_interface(usbh, &ep_in, &ep_out, + CY7C65215_JTAG_CLASS, + CY7C65215_JTAG_SUBCLASS, -1); + if (ret != ERROR_OK) { + LOG_ERROR("unable to claim JTAG interface"); + goto err; + } - /* MSB */ - openjtag_sendcommand(0x75); + ret = jtag_libusb_control_transfer(usbh, + CY7C65215_JTAG_REQUEST, + CY7C65215_JTAG_ENABLE, + 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); + if (ret < 0) { + LOG_ERROR("could not enable JTAG module"); + goto err; + } return ERROR_OK; + +err: + if (usbh != NULL) + jtag_libusb_close(usbh); + return ERROR_JTAG_INIT_FAILED; } -static int openjtag_quit(void) +static int openjtag_init(void) +{ + int ret; + + usb_tx_buf_offs = 0; + usb_rx_buf_len = 0; + openjtag_scan_result_count = 0; + + switch (openjtag_variant) { + case OPENJTAG_VARIANT_CY7C65215: + ret = openjtag_init_cy7c65215(); + break; + default: + ret = openjtag_init_standard(); + } + if (ret != ERROR_OK) + return ret; + + openjtag_speed(375); /* Start at slowest adapter speed */ + openjtag_sendcommand(0x75); /* MSB */ + + return ERROR_OK; +} + +static int openjtag_quit_standard(void) { ftdi_usb_close(&ftdic); ftdi_deinit(&ftdic); @@ -347,6 +514,32 @@ static int openjtag_quit(void) return ERROR_OK; } +static int openjtag_quit_cy7c65215(void) +{ + int ret; + + ret = jtag_libusb_control_transfer(usbh, + CY7C65215_JTAG_REQUEST, + CY7C65215_JTAG_DISABLE, + 0, 0, NULL, 0, CY7C65215_USB_TIMEOUT); + if (ret < 0) + LOG_WARNING("could not disable JTAG module"); + + jtag_libusb_close(usbh); + + return ERROR_OK; +} + +static int openjtag_quit(void) +{ + switch (openjtag_variant) { + case OPENJTAG_VARIANT_CY7C65215: + return openjtag_quit_cy7c65215(); + default: + return openjtag_quit_standard(); + } +} + static void openjtag_write_tap_buffer(void) { uint32_t written; @@ -379,8 +572,8 @@ static int openjtag_execute_tap_queue(void) uint8_t *buffer = openjtag_scan_result_buffer[res_count].buffer; - while (len) { - if (len <= 8) { + while (len > 0) { + if (len <= 8 && openjtag_variant != OPENJTAG_VARIANT_CY7C65215) { DEBUG_JTAG_IO("bits < 8 buf = 0x%X, will be 0x%X", usb_rx_buf[rx_offs], usb_rx_buf[rx_offs] >> (8 - len)); buffer[count] = usb_rx_buf[rx_offs] >> (8 - len); @@ -567,11 +760,14 @@ static void openjtag_execute_runtest(struct jtag_command *cmd) if (cmd->cmd.runtest->num_cycles > 16) LOG_WARNING("num_cycles > 16 on run test"); - uint8_t command; - command = 7; - command |= ((cmd->cmd.runtest->num_cycles - 1) & 0x0F) << 4; + if (openjtag_variant != OPENJTAG_VARIANT_CY7C65215 || + cmd->cmd.runtest->num_cycles) { + uint8_t command; + command = 7; + command |= ((cmd->cmd.runtest->num_cycles - 1) & 0x0F) << 4; - openjtag_add_byte(command); + openjtag_add_byte(command); + } tap_set_end_state(end_state); if (tap_get_end_state() != tap_get_state()) { @@ -659,6 +855,24 @@ COMMAND_HANDLER(openjtag_handle_device_desc_command) return ERROR_OK; } +COMMAND_HANDLER(openjtag_handle_variant_command) +{ + if (CMD_ARGC == 1) { + const char * const *name = openjtag_variant_names; + int variant = 0; + for (; *name; name++, variant++) { + if (strcasecmp(CMD_ARGV[0], *name) == 0) { + openjtag_variant = variant; + return ERROR_OK; + } + } + LOG_ERROR("unknown openjtag variant '%s'", CMD_ARGV[0]); + } else { + LOG_ERROR("require exactly one argument to " + "openjtag_variant "); + } + return ERROR_OK; +} static const struct command_registration openjtag_command_handlers[] = { { @@ -668,6 +882,13 @@ static const struct command_registration openjtag_command_handlers[] = { .help = "set the USB device description of the OpenJTAG", .usage = "description-string", }, + { + .name = "openjtag_variant", + .handler = openjtag_handle_variant_command, + .mode = COMMAND_CONFIG, + .help = "set the OpenJTAG variant", + .usage = "variant-string", + }, COMMAND_REGISTRATION_DONE }; -- 2.39.5