From 76b35638608f26cf7ea10509ecba3032eff90c9d Mon Sep 17 00:00:00 2001 From: Ryan Corbin Date: Wed, 15 May 2013 13:13:50 -0400 Subject: [PATCH] Added OpenJTAG Driver Updated OpenJTAG driver from www.openjtag.org to work with latest version of OpenOCD. Change-Id: I2917f4e5835fb9ca5265e81dc38515fa97ae9503 Signed-off-by: Ryan Corbin Reviewed-on: http://openocd.zylin.com/1406 Tested-by: jenkins Reviewed-by: Spencer Oliver --- configure.ac | 29 +- src/jtag/drivers/Makefile.am | 4 + src/jtag/drivers/openjtag.c | 845 +++++++++++++++++++++++++++++++++++ src/jtag/interfaces.c | 6 + tcl/interface/openjtag.cfg | 8 + 5 files changed, 889 insertions(+), 3 deletions(-) create mode 100644 src/jtag/drivers/openjtag.c create mode 100644 tcl/interface/openjtag.cfg diff --git a/configure.ac b/configure.ac index 7adce9eae..68d6301a9 100644 --- a/configure.ac +++ b/configure.ac @@ -446,6 +446,14 @@ AC_ARG_ENABLE([usbprog], AS_HELP_STRING([--enable-usbprog], [Enable building support for the usbprog JTAG Programmer]), [build_usbprog=$enableval], [build_usbprog=no]) +AC_ARG_ENABLE([openjtag_ftd2xx], + AS_HELP_STRING([--enable-openjtag_ftd2xx], [Enable building support for the OpenJTAG Programmer with ftd2xx driver]), + [build_openjtag_ftd2xx=$enableval], [build_openjtag_ftd2xx=no]) + +AC_ARG_ENABLE([openjtag_ftdi], + AS_HELP_STRING([--enable-openjtag_ftdi], [Enable building support for the OpenJTAG Programmer with ftdi driver]), + [build_openjtag_ftdi=$enableval], [build_openjtag_ftdi=no]) + AC_ARG_ENABLE([oocd_trace], AS_HELP_STRING([--enable-oocd_trace], [Enable building support for some prototype OpenOCD+trace ETM capture hardware]), @@ -754,6 +762,19 @@ else AC_DEFINE([BUILD_USBPROG], [0], [0 if you don't want the usbprog JTAG driver.]) fi +AC_DEFINE([BUILD_OPENJTAG], [0], [0 if you don't want the OpenJTAG driver.]) +AC_DEFINE([BUILD_OPENJTAG_FTD2XX], [0], [0 if you don't want the OpenJTAG driver with FTD2XX driver.]) +AC_DEFINE([BUILD_OPENJTAG_LIBFTDI], [0], [0 if you don't want to build OpenJTAG driver with libftdi.]) + +if test $build_openjtag_ftd2xx = yes; then + AC_DEFINE([BUILD_OPENJTAG], [1], [1 if you want the OpenJTAG driver.]) + AC_DEFINE([BUILD_OPENJTAG_FTD2XX], [1], [1 if you want the OpenJTAG driver with FTD2XX driver.]) +fi +if test $build_openjtag_ftdi = yes; then + AC_DEFINE([BUILD_OPENJTAG], [1], [1 if you want the OpenJTAG drvier.]) + AC_DEFINE([BUILD_OPENJTAG_LIBFTDI], [1], [1 if you want to build OpenJTAG with FTDI driver.]) +fi + if test $build_oocd_trace = yes; then AC_DEFINE([BUILD_OOCD_TRACE], [1], [1 if you want the OpenOCD+trace ETM capture driver.]) else @@ -849,7 +870,7 @@ then AC_MSG_ERROR([The option: with_ftd2xx_linux_tardir is for LINUX only.]) fi -if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then +if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes -o $build_openjtag_ftd2xx = yes; then AC_MSG_CHECKING([for ftd2xx.lib exists (win32)]) # if we are given a zipdir... @@ -919,7 +940,7 @@ then AC_MSG_ERROR([The option: --with-ftd2xx-win32-zipdir is for win32 only]) fi -if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then +if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes -o $build_openjtag_ftd2xx = yes; then # Must be linux if test $host_os != linux-gnu && test $host_os != linux ; then AC_MSG_ERROR([The (linux) ftd2xx library from FTDICHIP.com is linux only. Try --enable-ft2232-libftdi instead]) @@ -1066,7 +1087,8 @@ LDFLAGS=$LDFLAGS_SAVE CFLAGS=$CFLAGS_SAVE fi -if test $build_ft2232_libftdi = yes -o $build_usb_blaster_libftdi = yes; then +if test $build_ft2232_libftdi = yes -o $build_usb_blaster_libftdi = yes -o \ + $build_openjtag_ftdi = yes; then # We assume: the package is preinstalled in the proper place # these present as 2 libraries.. LIBS="$LIBS -lftdi -lusb" @@ -1198,6 +1220,7 @@ AM_CONDITIONAL([GW16012], [test $build_gw16012 = yes]) AM_CONDITIONAL([PRESTO_LIBFTDI], [test $build_presto_libftdi = yes]) AM_CONDITIONAL([PRESTO_DRIVER], [test $build_presto_ftd2xx = yes -o $build_presto_libftdi = yes]) AM_CONDITIONAL([USBPROG], [test $build_usbprog = yes]) +AM_CONDITIONAL([OPENJTAG], [test $build_openjtag_ftd2xx = yes -o $build_openjtag_ftdi = yes]) AM_CONDITIONAL([OOCD_TRACE], [test $build_oocd_trace = yes]) AM_CONDITIONAL([JLINK], [test $build_jlink = yes]) AM_CONDITIONAL([AICE], [test $build_aice = yes]) diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 543615662..65167ea27 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -115,6 +115,10 @@ if SYSFSGPIO DRIVERFILES += sysfsgpio.c endif +if OPENJTAG +DRIVERFILES += openjtag.c +endif + noinst_HEADERS = \ bitbang.h \ bitq.h \ diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c new file mode 100644 index 000000000..85d17938e --- /dev/null +++ b/src/jtag/drivers/openjtag.c @@ -0,0 +1,845 @@ +/******************************************************************************* + * Driver for OpenJTAG Project (www.openjtag.org) * + * Compatible with libftdi and ftd2xx drivers. * + * * + * Copyright (C) 2010 by Ivan Meleca * + * * + * Copyright (C) 2013 by Ryan Corbin, GlueLogix Inc. * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/*************************************************************************** + * 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 +#include +#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; + +#if (BUILD_OPENJTAG_FTD2XX == 1 && BUILD_OPENJTAG_LIBFTDI == 1) +#error "BUILD_OPENJTAG_FTD2XX && BUILD_OPENJTAG_LIBFTDI " + "are mutually exclusive" +#elif (BUILD_OPENJTAG_FTD2XX != 1 && BUILD_OPENJTAG_LIBFTDI != 1) +#error "BUILD_OPENJTAG_FTD2XX || BUILD_OPENJTAG_LIBFTDI must be chosen" +#endif + +/* OPENJTAG access library includes */ +#if BUILD_OPENJTAG_FTD2XX == 1 +#include +#elif BUILD_OPENJTAG_LIBFTDI == 1 +#include +#endif + +/* OpenJTAG vid/pid */ +static uint16_t openjtag_vid = 0x0403; +static uint16_t openjtag_pid = 0x6001; + +static char *openjtag_device_desc; + +#if BUILD_OPENJTAG_FTD2XX == 1 +static FT_HANDLE ftdih; + +#elif BUILD_OPENJTAG_LIBFTDI == 1 +static struct ftdi_context ftdic; +#endif + +#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) +{ +#if BUILD_OPENJTAG_FTD2XX == 1 + FT_STATUS status; + DWORD dw_bytes_written; + +#ifdef _DEBUG_USB_COMMS_ + openjtag_debug_buffer(buf, size, DEBUG_TYPE_WRITE); +#endif + + status = FT_Write(ftdih, buf, size, &dw_bytes_written); + if (status != FT_OK) { + *bytes_written = dw_bytes_written; + LOG_ERROR("FT_Write returned: %u", status); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_written = dw_bytes_written; + return ERROR_OK; +#elif BUILD_OPENJTAG_LIBFTDI == 1 + 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; +#endif +} + +static int openjtag_buf_read(uint8_t *buf, uint32_t qty, uint32_t *bytes_read) +{ + +#if BUILD_OPENJTAG_FTD2XX == 1 + DWORD dw_bytes_read; + FT_STATUS status; + int timeout = 50; + + *bytes_read = 0; + while (qty && (*bytes_read < qty) && timeout--) { + + status = FT_Read(ftdih, buf + *bytes_read, + qty - *bytes_read, &dw_bytes_read); + if (status != FT_OK) { + *bytes_read = dw_bytes_read; + LOG_ERROR("FT_Read returned: %u", status); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_read += dw_bytes_read; + } + +#ifdef _DEBUG_USB_COMMS_ + openjtag_debug_buffer(buf, *bytes_read, DEBUG_TYPE_READ); +#endif + + return ERROR_OK; +#elif BUILD_OPENJTAG_LIBFTDI == 1 + 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 + +#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; + +#if BUILD_OPENJTAG_FTD2XX == 1 + FT_STATUS status; +#endif + +usb_tx_buf_offs = 0; +usb_rx_buf_len = 0; +openjtag_scan_result_count = 0; + +#if BUILD_OPENJTAG_FTD2XX == 1 + LOG_DEBUG("'openjtag' interface using FTD2XX"); +#elif BUILD_OPENJTAG_LIBFTDI == 1 + LOG_DEBUG("'openjtag' interface using libftdi"); +#endif + +/* 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 BUILD_OPENJTAG_FTD2XX == 1 + +#if IS_WIN32 == 0 + /* Add non-standard Vid/Pid to the linux driver */ + status = FT_SetVIDPID(openjtag_vid, openjtag_pid); + if (status != FT_OK) { + LOG_WARNING("couldn't add %4.4x:%4.4x", + openjtag_vid, openjtag_pid); + } +#endif + + status = FT_OpenEx(openjtag_device_desc, FT_OPEN_BY_DESCRIPTION, + &ftdih); + if (status != FT_OK) { + DWORD num_devices; + + LOG_ERROR("unable to open ftdi device: %u", status); + status = FT_ListDevices(&num_devices, NULL, + FT_LIST_NUMBER_ONLY); + if (status == FT_OK) { + char **desc_array = malloc(sizeof(char *) + * (num_devices + 1)); + unsigned int i; + + for (i = 0; i < num_devices; i++) + desc_array[i] = malloc(64); + desc_array[num_devices] = NULL; + + status = FT_ListDevices(desc_array, &num_devices, + FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION); + + if (status == FT_OK) { + LOG_ERROR("ListDevices: %u\n", num_devices); + for (i = 0; i < num_devices; i++) + LOG_ERROR("%i: %s", i, desc_array[i]); + } + + for (i = 0; i < num_devices; i++) + free(desc_array[i]); + free(desc_array); + } else { + LOG_ERROR("ListDevices: NONE\n"); + } + return ERROR_JTAG_INIT_FAILED; + } + + status = FT_SetLatencyTimer(ftdih, 2); + if (status != FT_OK) { + LOG_ERROR("unable to set latency timer: %u", status); + return ERROR_JTAG_INIT_FAILED; + } + + status = FT_GetLatencyTimer(ftdih, &latency_timer); + if (status != FT_OK) { + LOG_ERROR("unable to get latency timer: %u", status); + return ERROR_JTAG_INIT_FAILED; + } + LOG_DEBUG("current latency timer: %i", latency_timer); + + status = FT_SetBitMode(ftdih, 0x00, 0x40); + if (status != FT_OK) { + LOG_ERROR("unable to disable bit i/o mode: %u", status); + return ERROR_JTAG_INIT_FAILED; + } + + status = FT_SetTimeouts(ftdih, 50, 0); + if (status != FT_OK) { + LOG_ERROR("unable to set timeouts: %u", status); + return ERROR_JTAG_INIT_FAILED; + } + + status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX); + if (status != FT_OK) { + LOG_ERROR("unable to FT_Purge() %u", status); + return ERROR_JTAG_INIT_FAILED; + } + +#elif BUILD_OPENJTAG_LIBFTDI == 1 + 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; + }; +#endif + +#if BUILD_OPENJTAG_FTD2XX == 1 + status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX); + if (status != FT_OK) + return ERROR_JTAG_INIT_FAILED; +#elif BUILD_OPENJTAG_LIBFTDI == 1 + if (ftdi_usb_purge_buffers(&ftdic) < 0) { + LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); + return ERROR_JTAG_INIT_FAILED; + } +#endif + + /* OpenJTAG speed */ + openjtag_sendcommand(0xE0); /*Start at slowest adapter speed*/ + + /* MSB */ + openjtag_sendcommand(0x75); + + return ERROR_OK; +} + +static int openjtag_quit(void) +{ +#if BUILD_OPENJTAG_FTD2XX == 1 + FT_Close(ftdih); +#elif BUILD_OPENJTAG_LIBFTDI == 1 + ftdi_usb_close(&ftdic); + ftdi_deinit(&ftdic); +#endif + + 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 "); + 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, +}; + + diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 8cf09a3c0..4579da0f8 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -83,6 +83,9 @@ extern struct jtag_interface presto_interface; #if BUILD_USBPROG == 1 extern struct jtag_interface usbprog_interface; #endif +#if BUILD_OPENJTAG == 1 +extern struct jtag_interface openjtag_interface; +#endif #if BUILD_JLINK == 1 extern struct jtag_interface jlink_interface; #endif @@ -170,6 +173,9 @@ struct jtag_interface *jtag_interfaces[] = { #if BUILD_USBPROG == 1 &usbprog_interface, #endif +#if BUILD_OPENJTAG == 1 + &openjtag_interface, +#endif #if BUILD_JLINK == 1 &jlink_interface, #endif diff --git a/tcl/interface/openjtag.cfg b/tcl/interface/openjtag.cfg new file mode 100644 index 000000000..b20c22b6c --- /dev/null +++ b/tcl/interface/openjtag.cfg @@ -0,0 +1,8 @@ +# +# OpenJTAG +# +# www.openjtag.org +# + +interface openjtag +openjtag_device_desc "Open JTAG Project" \ No newline at end of file