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 <corbin.ryan@gmail.com> Reviewed-on: http://openocd.zylin.com/1406 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
This commit is contained in:
parent
cf8a3c3d70
commit
76b3563860
29
configure.ac
29
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])
|
||||
|
|
|
@ -115,6 +115,10 @@ if SYSFSGPIO
|
|||
DRIVERFILES += sysfsgpio.c
|
||||
endif
|
||||
|
||||
if OPENJTAG
|
||||
DRIVERFILES += openjtag.c
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
bitbang.h \
|
||||
bitq.h \
|
||||
|
|
|
@ -0,0 +1,845 @@
|
|||
/*******************************************************************************
|
||||
* Driver for OpenJTAG Project (www.openjtag.org) *
|
||||
* Compatible with libftdi and ftd2xx drivers. *
|
||||
* *
|
||||
* 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, 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 <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;
|
||||
|
||||
#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 <ftd2xx.h>
|
||||
#elif BUILD_OPENJTAG_LIBFTDI == 1
|
||||
#include <ftdi.h>
|
||||
#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 <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,
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# OpenJTAG
|
||||
#
|
||||
# www.openjtag.org
|
||||
#
|
||||
|
||||
interface openjtag
|
||||
openjtag_device_desc "Open JTAG Project"
|
Loading…
Reference in New Issue