aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>2015-06-02 16:55:42 +0200
committerPaul Fertser <fercerpav@gmail.com>2016-12-08 12:35:23 +0000
commit1d8b6b743416bfda8f82c80aa2278c2d88e2afaa (patch)
treec21d921c314582ec622b90dfdb60df0bf42632e6 /src
parent69ff7354d9c9accf09374772310098f1f00e8ccb (diff)
downloadriscv-openocd-1d8b6b743416bfda8f82c80aa2278c2d88e2afaa.zip
riscv-openocd-1d8b6b743416bfda8f82c80aa2278c2d88e2afaa.tar.gz
riscv-openocd-1d8b6b743416bfda8f82c80aa2278c2d88e2afaa.tar.bz2
jtag/drivers/openjtag: Add support for Cypress CY7C65215
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 <vianney.leclement@essensium.com> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> Reviewed-on: http://openocd.zylin.com/2805 Tested-by: jenkins Reviewed-by: Jiri Kastner <cz172638@gmail.com> Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/jtag/drivers/openjtag.c273
1 files changed, 247 insertions, 26 deletions
diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c
index 5d1084c..bb0ff74 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 *
+ * <vianney.leclement@essensium.com> *
* *
* Copyright (C) 2010 by Ivan Meleca <mileca@gmail.com> *
* *
@@ -41,7 +45,18 @@
#include <jtag/interface.h>
#include <jtag/commands.h>
-#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 <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
};