|
- /*******************************************************************************
- * Driver for OpenJTAG Project (www.openjtag.org) *
- * Compatible with libftdi driver. *
- * *
- * Copyright (C) 2010 by Ivan Meleca <mileca@gmail.com> *
- * *
- * Copyright (C) 2013 by Ryan Corbin, GlueLogix Inc. <corbin.ryan@gmail.com> *
- * Updated to work with OpenOCD v0.7.0. Fixed libftdi read speed issue. *
- * *
- * Based on usb_blaster.c *
- * Copyright (C) 2009 Catalin Patulea *
- * Copyright (C) 2006 Kolja Waschk *
- * *
- * And jlink.c *
- * Copyright (C) 2008 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 <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
- /***************************************************************************
- * Version 1.0 Tested on a MCBSTM32 board using a Cortex-M3 (stm32f103x), *
- * GDB and Eclipse under Linux (Ubuntu 10.04) *
- * *
- ***************************************************************************/
-
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
-
- #include <jtag/interface.h>
- #include <jtag/commands.h>
- #include "usb_common.h"
-
- /*
- * OpenJTAG-OpenOCD state conversion
- */
- typedef enum openjtag_tap_state {
- OPENJTAG_TAP_INVALID = -1,
- OPENJTAG_TAP_RESET = 0,
- OPENJTAG_TAP_IDLE = 1,
- OPENJTAG_TAP_SELECT_DR = 2,
- OPENJTAG_TAP_CAPTURE_DR = 3,
- OPENJTAG_TAP_SHIFT_DR = 4,
- OPENJTAG_TAP_EXIT1_DR = 5,
- OPENJTAG_TAP_PAUSE_DR = 6,
- OPENJTAG_TAP_EXIT2_DR = 7,
- OPENJTAG_TAP_UPDATE_DR = 8,
- OPENJTAG_TAP_SELECT_IR = 9,
- OPENJTAG_TAP_CAPURE_IR = 10,
- OPENJTAG_TAP_SHIFT_IR = 11,
- OPENJTAG_TAP_EXIT1_IR = 12,
- OPENJTAG_TAP_PAUSE_IR = 13,
- OPENJTAG_TAP_EXIT2_IR = 14,
- OPENJTAG_TAP_UPDATE_IR = 15,
- } openjtag_tap_state_t;
-
- /* OPENJTAG access library includes */
- #include <ftdi.h>
-
- /* OpenJTAG vid/pid */
- static uint16_t openjtag_vid = 0x0403;
- static uint16_t openjtag_pid = 0x6001;
-
- static char *openjtag_device_desc;
-
- static struct ftdi_context ftdic;
-
- #define OPENJTAG_BUFFER_SIZE 504
- #define OPENJTAG_MAX_PENDING_RESULTS 256
-
- struct openjtag_scan_result {
- uint32_t bits; /* Length in bits*/
- struct scan_command *command; /* Corresponding scan command */
- uint8_t *buffer;
- };
-
- /* USB RX/TX buffers */
- static int usb_tx_buf_offs;
- static uint8_t usb_tx_buf[OPENJTAG_BUFFER_SIZE];
- static uint32_t usb_rx_buf_len;
- static uint8_t usb_rx_buf[OPENJTAG_BUFFER_SIZE];
-
- /* Pending readings */
- 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;
- };
-
- #ifdef _DEBUG_USB_COMMS_
-
- #define DEBUG_TYPE_READ 0
- #define DEBUG_TYPE_WRITE 1
- #define DEBUG_TYPE_OCD_READ 2
- #define DEBUG_TYPE_BUFFER 3
-
- #define LINE_LEN 16
- static void openjtag_debug_buffer(uint8_t *buffer, int length, uint8_t type)
- {
- char line[128];
- char s[4];
- int i;
- int j;
-
- switch (type) {
- case DEBUG_TYPE_READ:
- sprintf(line, "USB READ %d bytes", length);
- break;
- case DEBUG_TYPE_WRITE:
- sprintf(line, "USB WRITE %d bytes", length);
- break;
- case DEBUG_TYPE_OCD_READ:
- sprintf(line, "TO OpenOCD %d bytes", length);
- break;
- case DEBUG_TYPE_BUFFER:
- sprintf(line, "Buffer %d bytes", length);
- break;
- }
-
- LOG_DEBUG("%s", line);
-
- for (i = 0; i < length; i += LINE_LEN) {
- switch (type) {
- case DEBUG_TYPE_READ:
- sprintf(line, "USB READ: %04x", i);
- break;
- case DEBUG_TYPE_WRITE:
- sprintf(line, "USB WRITE: %04x", i);
- break;
- case DEBUG_TYPE_OCD_READ:
- sprintf(line, "TO OpenOCD: %04x", i);
- break;
- case DEBUG_TYPE_BUFFER:
- sprintf(line, "BUFFER: %04x", i);
- break;
- }
-
- for (j = i; j < i + LINE_LEN && j < length; j++) {
- sprintf(s, " %02x", buffer[j]);
- strcat(line, s);
- }
- LOG_DEBUG("%s", line);
- }
-
- }
-
- #endif
-
- static int8_t openjtag_get_tap_state(int8_t state)
- {
-
- switch (state) {
- case TAP_DREXIT2: return OPENJTAG_TAP_EXIT2_DR;
- case TAP_DREXIT1: return OPENJTAG_TAP_EXIT1_DR;
- case TAP_DRSHIFT: return OPENJTAG_TAP_SHIFT_DR;
- case TAP_DRPAUSE: return OPENJTAG_TAP_PAUSE_DR;
- case TAP_IRSELECT: return OPENJTAG_TAP_SELECT_IR;
- case TAP_DRUPDATE: return OPENJTAG_TAP_UPDATE_DR;
- case TAP_DRCAPTURE: return OPENJTAG_TAP_CAPTURE_DR;
- case TAP_DRSELECT: return OPENJTAG_TAP_SELECT_DR;
- case TAP_IREXIT2: return OPENJTAG_TAP_EXIT2_IR;
- case TAP_IREXIT1: return OPENJTAG_TAP_EXIT1_IR;
- case TAP_IRSHIFT: return OPENJTAG_TAP_SHIFT_IR;
- case TAP_IRPAUSE: return OPENJTAG_TAP_PAUSE_IR;
- case TAP_IDLE: return OPENJTAG_TAP_IDLE;
- case TAP_IRUPDATE: return OPENJTAG_TAP_UPDATE_IR;
- case TAP_IRCAPTURE: return OPENJTAG_TAP_CAPURE_IR;
- case TAP_RESET: return OPENJTAG_TAP_RESET;
- case TAP_INVALID:
- default: return OPENJTAG_TAP_INVALID;
- }
- }
-
- static int openjtag_buf_write(
- uint8_t *buf, int size, uint32_t *bytes_written)
- {
- int retval;
- #ifdef _DEBUG_USB_COMMS_
- openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE);
- #endif
-
- retval = ftdi_write_data(&ftdic, buf, size);
- if (retval < 0) {
- *bytes_written = 0;
- LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic));
- return ERROR_JTAG_DEVICE_ERROR;
- }
-
- *bytes_written += retval;
-
- return ERROR_OK;
- }
-
- static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read)
- {
- int retval;
- int timeout = 5;
-
- *bytes_read = 0;
-
- while ((*bytes_read < qty) && timeout--) {
- retval = ftdi_read_data(&ftdic, buf + *bytes_read,
- qty - *bytes_read);
- if (retval < 0) {
- *bytes_read = 0;
- DEBUG_JTAG_IO("ftdi_read_data: %s",
- ftdi_get_error_string(&ftdic));
- return ERROR_JTAG_DEVICE_ERROR;
- }
- *bytes_read += retval;
- }
-
- #ifdef _DEBUG_USB_COMMS_
- openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ);
- #endif
-
- return ERROR_OK;
- }
-
- static int openjtag_sendcommand(uint8_t cmd)
- {
- uint32_t written;
- return openjtag_buf_write(&cmd, 1, &written);
- }
-
- static int openjtag_speed(int speed)
- {
- int clockcmd;
- switch (speed) {
- case 48000:
- clockcmd = 0x00;
- break;
- case 24000:
- clockcmd = 0x20;
- break;
- case 12000:
- clockcmd = 0x40;
- break;
- case 6000:
- clockcmd = 0x60;
- break;
- case 3000:
- clockcmd = 0x80;
- break;
- case 1500:
- clockcmd = 0xA0;
- break;
- case 750:
- clockcmd = 0xC0;
- break;
- case 375:
- clockcmd = 0xE0;
- break;
- default:
- clockcmd = 0xE0;
- LOG_WARNING("adapter speed not recognized, reverting to 375 kHz");
- break;
- }
- openjtag_sendcommand(clockcmd);
-
- return ERROR_OK;
- }
-
- static int openjtag_init(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, "
- "using default 'Open JTAG Project'");
- openjtag_device_desc = "Open JTAG Project";
- }
-
- if (ftdi_init(&ftdic) < 0)
- return ERROR_JTAG_INIT_FAILED;
-
- /* context, vendor id, product id, description, serial id */
- if (ftdi_usb_open_desc(&ftdic, openjtag_vid, openjtag_pid, openjtag_device_desc, NULL) < 0) {
- LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (ftdi_usb_reset(&ftdic) < 0) {
- LOG_ERROR("unable to reset ftdi device");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
- LOG_ERROR("unable to set latency timer");
- return ERROR_JTAG_INIT_FAILED;
- }
-
- if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) {
- LOG_ERROR("unable to get latency timer");
- return ERROR_JTAG_INIT_FAILED;
- }
- LOG_DEBUG("current latency timer: %u", latency_timer);
-
- ftdi_disable_bitbang(&ftdic);
- /* was (3000000 / 4) with a comment about a bug in libftdi when using high baudrate */
- if (ftdi_set_baudrate(&ftdic, 3000000) < 0) {
- LOG_ERROR("Can't set baud rate to max: %s",
- ftdi_get_error_string(&ftdic));
- return ERROR_JTAG_DEVICE_ERROR;
- }
-
- if (ftdi_usb_purge_buffers(&ftdic) < 0) {
- LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
- return ERROR_JTAG_INIT_FAILED;
- }
-
- /* OpenJTAG speed */
- openjtag_sendcommand(0xE0); /*Start at slowest adapter speed*/
-
- /* MSB */
- openjtag_sendcommand(0x75);
-
- return ERROR_OK;
- }
-
- static int openjtag_quit(void)
- {
- ftdi_usb_close(&ftdic);
- ftdi_deinit(&ftdic);
-
- return ERROR_OK;
- }
-
- static void openjtag_write_tap_buffer(void)
- {
- uint32_t written;
-
- openjtag_buf_write(usb_tx_buf, usb_tx_buf_offs, &written);
- openjtag_buf_read(usb_rx_buf, usb_tx_buf_offs, &usb_rx_buf_len);
-
- usb_tx_buf_offs = 0;
- }
-
- static int openjtag_execute_tap_queue(void)
- {
- openjtag_write_tap_buffer();
-
- int res_count = 0;
-
- if (openjtag_scan_result_count && usb_rx_buf_len) {
-
- int count;
- int rx_offs = 0;
- int len;
-
- /* for every pending result */
- while (res_count < openjtag_scan_result_count) {
-
- /* get sent bits */
- len = openjtag_scan_result_buffer[res_count].bits;
-
- count = 0;
-
- 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",
- usb_rx_buf[rx_offs], usb_rx_buf[rx_offs] >> (8 - len));
- buffer[count] = usb_rx_buf[rx_offs] >> (8 - len);
- len = 0;
- } else {
- buffer[count] = usb_rx_buf[rx_offs];
- len -= 8;
- }
-
- rx_offs++;
- count++;
- }
-
- #ifdef _DEBUG_USB_COMMS_
- openjtag_debug_buffer(buffer,
- DIV_ROUND_UP(openjtag_scan_result_buffer[res_count].bits, 8), DEBUG_TYPE_OCD_READ);
- #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);
-
- res_count++;
- }
- }
-
- openjtag_scan_result_count = 0;
-
- return ERROR_OK;
- }
-
- 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);
- openjtag_execute_tap_queue();
- }
-
- usb_tx_buf[usb_tx_buf_offs] = buf;
- usb_tx_buf_offs++;
- }
-
- static void openjtag_add_scan(uint8_t *buffer, int length, struct scan_command *scan_cmd)
- {
-
- /* 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);
- openjtag_execute_tap_queue();
- }
-
- openjtag_scan_result_buffer[openjtag_scan_result_count].bits = length;
- openjtag_scan_result_buffer[openjtag_scan_result_count].command = scan_cmd;
- openjtag_scan_result_buffer[openjtag_scan_result_count].buffer = buffer;
-
- uint8_t command;
- uint8_t bits;
- int count = 0;
- while (length) {
-
- /* write command */
- command = 6;
-
- /* last bits? */
- if (length <= 8) {
- /* tms high */
- command |= (1 << 4);
-
- /* bits to transfer */
- bits = (length - 1);
- command |= bits << 5;
- length = 0;
- } else {
- /* whole byte */
-
- /* bits to transfer */
- bits = 7;
- command |= (7 << 5);
- length -= 8;
- }
-
- openjtag_add_byte(command);
- openjtag_add_byte(buffer[count]);
- count++;
- }
-
- openjtag_scan_result_count++;
- }
-
- static void openjtag_execute_reset(struct jtag_command *cmd)
- {
-
- DEBUG_JTAG_IO("reset trst: %i srst %i",
- cmd->cmd.reset->trst, cmd->cmd.reset->srst);
-
- uint8_t buf = 0x00;
-
- if (cmd->cmd.reset->trst) {
- buf = 0x03;
- } else {
- buf |= 0x04;
- buf |= 0x05 << 4;
- }
-
- openjtag_add_byte(buf);
- }
-
- static void openjtag_execute_sleep(struct jtag_command *cmd)
- {
- jtag_sleep(cmd->cmd.sleep->us);
- }
-
- static void openjtag_set_state(uint8_t openocd_state)
- {
- int8_t state = openjtag_get_tap_state(openocd_state);
-
- uint8_t buf = 0;
- buf = 0x01;
- buf |= state << 4;
-
- openjtag_add_byte(buf);
- }
-
- static void openjtag_execute_statemove(struct jtag_command *cmd)
- {
- DEBUG_JTAG_IO("state move to %i", cmd->cmd.statemove->end_state);
-
- tap_set_end_state(cmd->cmd.statemove->end_state);
-
- openjtag_set_state(cmd->cmd.statemove->end_state);
-
- tap_set_state(tap_get_end_state());
- }
-
-
- 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));
-
- /* get scan info */
- tap_set_end_state(cmd->cmd.scan->end_state);
- scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
-
- #ifdef _DEBUG_USB_COMMS_
- openjtag_debug_buffer(buffer, (scan_size + 7) / 8, DEBUG_TYPE_BUFFER);
- #endif
- /* set state */
- old_state = tap_get_end_state();
- openjtag_set_state(cmd->cmd.scan->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
- tap_set_state(cmd->cmd.scan->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
- tap_set_end_state(old_state);
-
- openjtag_add_scan(buffer, scan_size, cmd->cmd.scan);
-
- openjtag_set_state(cmd->cmd.scan->ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE);
- tap_set_state(cmd->cmd.scan->ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE);
-
- if (tap_get_state() != tap_get_end_state()) {
- openjtag_set_state(tap_get_end_state());
- tap_set_state(tap_get_end_state());
- }
- }
-
- static void openjtag_execute_runtest(struct jtag_command *cmd)
- {
-
- tap_state_t end_state = cmd->cmd.runtest->end_state;
- tap_set_end_state(end_state);
-
- /* only do a state_move when we're not already in IDLE */
- if (tap_get_state() != TAP_IDLE) {
- openjtag_set_state(TAP_IDLE);
- tap_set_state(TAP_IDLE);
- }
-
- 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;
-
- openjtag_add_byte(command);
-
- tap_set_end_state(end_state);
- if (tap_get_end_state() != tap_get_state()) {
- openjtag_set_state(end_state);
- tap_set_state(end_state);
- }
- }
-
- static void openjtag_execute_command(struct jtag_command *cmd)
- {
- DEBUG_JTAG_IO("openjtag_execute_command %i", cmd->type);
- switch (cmd->type) {
- case JTAG_RESET:
- openjtag_execute_reset(cmd);
- break;
- case JTAG_SLEEP:
- openjtag_execute_sleep(cmd);
- break;
- case JTAG_TLR_RESET:
- openjtag_execute_statemove(cmd);
- break;
- case JTAG_SCAN:
- openjtag_execute_scan(cmd);
- break;
- case JTAG_RUNTEST:
- openjtag_execute_runtest(cmd);
- break;
- case JTAG_PATHMOVE:
- /* jlink_execute_pathmove(cmd); break; */
- default:
- LOG_ERROR("BUG: unknown Open JTAG command type encountered");
- exit(-1);
- }
- }
-
- static int openjtag_execute_queue(void)
- {
- struct jtag_command *cmd = jtag_command_queue;
-
- while (cmd != NULL) {
- openjtag_execute_command(cmd);
- cmd = cmd->next;
- }
-
- return openjtag_execute_tap_queue();
- }
-
- static int openjtag_speed_div(int speed, int *khz)
- {
- *khz = speed;
-
- return ERROR_OK;
- }
-
- static int openjtag_khz(int khz, int *jtag_speed)
- {
-
- if (khz >= 48000)
- *jtag_speed = 48000;
- else if (khz >= 24000)
- *jtag_speed = 24000;
- else if (khz >= 12000)
- *jtag_speed = 12000;
- else if (khz >= 6000)
- *jtag_speed = 6000;
- else if (khz >= 3000)
- *jtag_speed = 3000;
- else if (khz >= 1500)
- *jtag_speed = 1500;
- else if (khz >= 750)
- *jtag_speed = 750;
- else
- *jtag_speed = 375;
-
- return ERROR_OK;
- }
-
- COMMAND_HANDLER(openjtag_handle_device_desc_command)
- {
- if (CMD_ARGC == 1)
- openjtag_device_desc = strdup(CMD_ARGV[0]);
- else
- LOG_ERROR("require exactly one argument to "
- "openjtag_device_desc <description>");
- return ERROR_OK;
- }
-
-
- static const struct command_registration openjtag_command_handlers[] = {
- {
- .name = "openjtag_device_desc",
- .handler = openjtag_handle_device_desc_command,
- .mode = COMMAND_CONFIG,
- .help = "set the USB device description of the OpenJTAG",
- .usage = "description-string",
- },
- COMMAND_REGISTRATION_DONE
- };
-
- struct jtag_interface openjtag_interface = {
- .name = "openjtag",
- .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,
- };
-
|