X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjtag%2Fdrivers%2Fopenjtag.c;h=123134f51338095b0db525fdd6675b1a0fbbc460;hb=b421d2a4c52b3fe4d939c6f41327b6a5370e09c0;hp=5d1084cebcb9d0d4c2997c5af1bebf21f3f8ab89;hpb=bcaf775fc10d88d2c63c06bafada141895318b34;p=fw%2Fopenocd diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 5d1084ceb..123134f51 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_helper.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 @@ -67,7 +82,7 @@ typedef enum openjtag_tap_state { } openjtag_tap_state_t; /* OPENJTAG access library includes */ -#include +#include "libftdi_helper.h" /* OpenJTAG vid/pid */ static uint16_t openjtag_vid = 0x0403; @@ -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 struct 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; @@ -200,13 +229,58 @@ static int openjtag_buf_write( return ERROR_JTAG_DEVICE_ERROR; } - *bytes_written += retval; + *bytes_written = retval; 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; + } + + if (jtag_libusb_bulk_write(usbh, ep_out, (char *)buf, size, + CY7C65215_USB_TIMEOUT, &ret)) { + LOG_ERROR("bulk write failed, error"); + 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; @@ -217,7 +291,7 @@ static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read) qty - *bytes_read); if (retval < 0) { *bytes_read = 0; - DEBUG_JTAG_IO("ftdi_read_data: %s", + LOG_DEBUG_IO("ftdi_read_data: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } @@ -231,6 +305,49 @@ 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; + } + + if (jtag_libusb_bulk_read(usbh, ep_in, (char *)buf, qty, + CY7C65215_USB_TIMEOUT, &ret)) { + LOG_ERROR("bulk read failed, error"); + 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,18 +392,12 @@ 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) { + if (!openjtag_device_desc) { LOG_WARNING("no openjtag device description specified, " "using default 'Open JTAG Project'"); openjtag_device_desc = "Open JTAG Project"; @@ -325,21 +436,75 @@ static int openjtag_init(void) return ERROR_JTAG_DEVICE_ERROR; } - if (ftdi_usb_purge_buffers(&ftdic) < 0) { - LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); + if (ftdi_tcioflush(&ftdic) < 0) { + LOG_ERROR("ftdi flush: %s", ftdic.error_str); 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, NULL); + 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, LIBUSB_TRANSFER_TYPE_BULK); + 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) + 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 +512,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,9 +570,9 @@ static int openjtag_execute_tap_queue(void) uint8_t *buffer = openjtag_scan_result_buffer[res_count].buffer; - while (len) { - if (len <= 8) { - DEBUG_JTAG_IO("bits < 8 buf = 0x%X, will be 0x%X", + while (len > 0) { + if (len <= 8 && openjtag_variant != OPENJTAG_VARIANT_CY7C65215) { + LOG_DEBUG_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); len = 0; @@ -400,8 +591,7 @@ static int openjtag_execute_tap_queue(void) #endif jtag_read_buffer(buffer, openjtag_scan_result_buffer[res_count].command); - if (openjtag_scan_result_buffer[res_count].buffer) - free(openjtag_scan_result_buffer[res_count].buffer); + free(openjtag_scan_result_buffer[res_count].buffer); res_count++; } @@ -416,8 +606,8 @@ static void openjtag_add_byte(char buf) { if (usb_tx_buf_offs == OPENJTAG_BUFFER_SIZE) { - DEBUG_JTAG_IO("Forcing execute_tap_queue"); - DEBUG_JTAG_IO("TX Buff offs=%d", usb_tx_buf_offs); + LOG_DEBUG_IO("Forcing execute_tap_queue"); + LOG_DEBUG_IO("TX Buff offs=%d", usb_tx_buf_offs); openjtag_execute_tap_queue(); } @@ -431,8 +621,8 @@ static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command * /* Ensure space to send long chains */ /* We add two byte for each eight (or less) bits, one for command, one for data */ if (usb_tx_buf_offs + (DIV_ROUND_UP(length, 8) * 2) >= OPENJTAG_BUFFER_SIZE) { - DEBUG_JTAG_IO("Forcing execute_tap_queue from scan"); - DEBUG_JTAG_IO("TX Buff offs=%d len=%d", usb_tx_buf_offs, DIV_ROUND_UP(length, 8) * 2); + LOG_DEBUG_IO("Forcing execute_tap_queue from scan"); + LOG_DEBUG_IO("TX Buff offs=%d len=%d", usb_tx_buf_offs, DIV_ROUND_UP(length, 8) * 2); openjtag_execute_tap_queue(); } @@ -461,7 +651,6 @@ static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command * /* whole byte */ /* bits to transfer */ - bits = 7; command |= (7 << 5); length -= 8; } @@ -477,7 +666,7 @@ static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command * static void openjtag_execute_reset(struct jtag_command *cmd) { - DEBUG_JTAG_IO("reset trst: %i srst %i", + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); uint8_t buf = 0x00; @@ -499,7 +688,7 @@ static void openjtag_execute_sleep(struct jtag_command *cmd) static void openjtag_set_state(uint8_t openocd_state) { - int8_t state = openjtag_get_tap_state(openocd_state); + uint8_t state = openjtag_get_tap_state(openocd_state); uint8_t buf = 0; buf = 0x01; @@ -510,7 +699,7 @@ static void openjtag_set_state(uint8_t openocd_state) static void openjtag_execute_statemove(struct jtag_command *cmd) { - DEBUG_JTAG_IO("state move to %i", cmd->cmd.statemove->end_state); + LOG_DEBUG_IO("state move to %i", cmd->cmd.statemove->end_state); tap_set_end_state(cmd->cmd.statemove->end_state); @@ -526,7 +715,7 @@ static void openjtag_execute_scan(struct jtag_command *cmd) int scan_size, old_state; uint8_t *buffer; - DEBUG_JTAG_IO("scan ends in %s", tap_state_name(cmd->cmd.scan->end_state)); + LOG_DEBUG_IO("scan ends in %s", tap_state_name(cmd->cmd.scan->end_state)); /* get scan info */ tap_set_end_state(cmd->cmd.scan->end_state); @@ -567,11 +756,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()) { @@ -582,7 +774,7 @@ static void openjtag_execute_runtest(struct jtag_command *cmd) static void openjtag_execute_command(struct jtag_command *cmd) { - DEBUG_JTAG_IO("openjtag_execute_command %i", cmd->type); + LOG_DEBUG_IO("openjtag_execute_command %i", cmd->type); switch (cmd->type) { case JTAG_RESET: openjtag_execute_reset(cmd); @@ -611,7 +803,7 @@ static int openjtag_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; - while (cmd != NULL) { + while (cmd) { openjtag_execute_command(cmd); cmd = cmd->next; } @@ -659,28 +851,68 @@ 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[] = { +static const struct command_registration openjtag_subcommand_handlers[] = { { - .name = "openjtag_device_desc", + .name = "device_desc", .handler = openjtag_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the OpenJTAG", .usage = "description-string", }, + { + .name = "variant", + .handler = openjtag_handle_variant_command, + .mode = COMMAND_CONFIG, + .help = "set the OpenJTAG variant", + .usage = "variant-string", + }, COMMAND_REGISTRATION_DONE }; -struct jtag_interface openjtag_interface = { +static const struct command_registration openjtag_command_handlers[] = { + { + .name = "openjtag", + .mode = COMMAND_ANY, + .help = "perform openjtag management", + .chain = openjtag_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface openjtag_interface = { + .execute_queue = openjtag_execute_queue, +}; + +struct adapter_driver openjtag_adapter_driver = { .name = "openjtag", + .transports = jtag_only, .commands = openjtag_command_handlers, - .execute_queue = openjtag_execute_queue, - .speed = openjtag_speed, - .speed_div = openjtag_speed_div, - .khz = openjtag_khz, .init = openjtag_init, .quit = openjtag_quit, -}; - + .speed = openjtag_speed, + .khz = openjtag_khz, + .speed_div = openjtag_speed_div, + .jtag_ops = &openjtag_interface, +};