move jtag drivers to src/jtag/drivers
Moves JTAG interface drivers to src/jtag/drivers/, Adds src/jtag/drivers/Makefile.am. Builds libocdjtagdrivers.la. Flattens the rlink driver files into the drivers/ directory, adding the 'rlink_' prefix or '.rlink' suffix as appropriate.
This commit is contained in:
74
src/jtag/drivers/Makefile.am
Normal file
74
src/jtag/drivers/Makefile.am
Normal file
@@ -0,0 +1,74 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/helper \
|
||||
-I$(top_srcdir)/src/jtag
|
||||
|
||||
noinst_LTLIBRARIES = libocdjtagdrivers.la
|
||||
|
||||
libocdjtagdrivers_la_SOURCES = \
|
||||
$(DRIVERFILES)
|
||||
|
||||
DRIVERFILES =
|
||||
|
||||
# Standard Driver: common files
|
||||
DRIVERFILES += driver.c
|
||||
|
||||
if USB
|
||||
DRIVERFILES += usb_common.c
|
||||
endif
|
||||
|
||||
if BITBANG
|
||||
DRIVERFILES += bitbang.c
|
||||
endif
|
||||
if PARPORT
|
||||
DRIVERFILES += parport.c
|
||||
endif
|
||||
if DUMMY
|
||||
DRIVERFILES += dummy.c
|
||||
endif
|
||||
if FT2232_DRIVER
|
||||
DRIVERFILES += ft2232.c
|
||||
endif
|
||||
if AMTJTAGACCEL
|
||||
DRIVERFILES += amt_jtagaccel.c
|
||||
endif
|
||||
if EP93XX
|
||||
DRIVERFILES += ep93xx.c
|
||||
endif
|
||||
if AT91RM9200
|
||||
DRIVERFILES += at91rm9200.c
|
||||
endif
|
||||
if GW16012
|
||||
DRIVERFILES += gw16012.c
|
||||
endif
|
||||
if BITQ
|
||||
DRIVERFILES += bitq.c
|
||||
endif
|
||||
if PRESTO_DRIVER
|
||||
DRIVERFILES += presto.c
|
||||
endif
|
||||
if USBPROG
|
||||
DRIVERFILES += usbprog.c
|
||||
endif
|
||||
if JLINK
|
||||
DRIVERFILES += jlink.c
|
||||
endif
|
||||
if RLINK
|
||||
DRIVERFILES += rlink.c rlink_speed_table.c
|
||||
endif
|
||||
if VSLLINK
|
||||
DRIVERFILES += vsllink.c
|
||||
endif
|
||||
if ARMJTAGEW
|
||||
DRIVERFILES += arm-jtag-ew.c
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
bitbang.h \
|
||||
bitq.h \
|
||||
rlink.h \
|
||||
rlink_dtc_cmd.h \
|
||||
rlink_ep1_cmd.h \
|
||||
rlink_st7.h \
|
||||
usb_common.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
73
src/jtag/drivers/Makefile.rlink
Normal file
73
src/jtag/drivers/Makefile.rlink
Normal file
@@ -0,0 +1,73 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (C) 2008 Lou Deluxe *
|
||||
#* lou.openocd012@fixit.nospammail.net *
|
||||
#* *
|
||||
#* 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., *
|
||||
#* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
#***************************************************************************
|
||||
|
||||
TOP = ../../..
|
||||
INTERFACE_NAME = rlink
|
||||
|
||||
PERL = perl
|
||||
M4 = m4
|
||||
|
||||
TARGETDIR = ${TOP}/src/target
|
||||
TOOLSDIR = ${TOP}/tools
|
||||
|
||||
MAKE_SPEED_TABLE = ${TOOLSDIR}/rlink_make_speed_table/rlink_make_speed_table
|
||||
ST7_DTC_AS = ${TOOLSDIR}/st7_dtc_as/st7_dtc_as
|
||||
|
||||
OPENOCD = ${TOP}/src/openocd
|
||||
OPENOCD_CONFIG = -s ${TARGETDIR}
|
||||
OPENOCD_CONFIG += -f interface/rlink.cfg
|
||||
OPENOCD_CONFIG += -f board/stm32f10x_128k_eval.cfg
|
||||
|
||||
PATCHFILE = /tmp/openocd_${INTERFACE_NAME}.diff.gz
|
||||
|
||||
# relative to ${TOP}
|
||||
SVNADDFILES =
|
||||
SVNADDFILES += src/target/interface/rlink.cfg
|
||||
SVNADDFILES += src/jtag/${INTERFACE_NAME}.c
|
||||
SVNADDFILES += src/jtag/${INTERFACE_NAME}
|
||||
|
||||
PRESCALERS = 64 11 8 2
|
||||
|
||||
DTCFILES =
|
||||
DTCFILES += $(addsuffix _init.dtc, ${PRESCALERS})
|
||||
DTCFILES += $(addsuffix _call.dtc, ${PRESCALERS})
|
||||
|
||||
default: rlink_speed_table.c clean
|
||||
|
||||
%_init.fsm: init.m4
|
||||
${M4} -P -DSHIFTER_PRESCALER=`echo "$@" | sed -e's/_.*//'` $< > $@
|
||||
|
||||
%_call.fsm: call.m4
|
||||
${M4} -P -DSHIFTER_PRESCALER=`echo "$@" | sed -e's/_.*//'` $< > $@
|
||||
|
||||
%.dtc: %.fsm
|
||||
${ST7_DTC_AS} -b -o $@ -i $< > /dev/null
|
||||
|
||||
rlink_speed_table.c: ${DTCFILES}
|
||||
${MAKE_SPEED_TABLE} ${PRESCALERS} > $@ || rm $@
|
||||
|
||||
clean:
|
||||
-rm *.dtc *.fsm
|
||||
|
||||
distclean: clean
|
||||
|
||||
test: default
|
||||
(cd ${TOP} && (rm src/jtag/${INTERFACE_NAME}.o; ${MAKE}))
|
||||
${OPENOCD} -d0 ${OPENOCD_CONFIG} -c init -c 'poll off'
|
||||
568
src/jtag/drivers/amt_jtagaccel.c
Normal file
568
src/jtag/drivers/amt_jtagaccel.c
Normal file
@@ -0,0 +1,568 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "commands.h"
|
||||
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
#include <linux/parport.h>
|
||||
#include <linux/ppdev.h>
|
||||
#include <sys/ioctl.h>
|
||||
#else /* not PARPORT_USE_PPDEV */
|
||||
#ifndef _WIN32
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
#if IS_CYGWIN == 1
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* configuration */
|
||||
static uint16_t amt_jtagaccel_port;
|
||||
|
||||
/* interface variables
|
||||
*/
|
||||
static uint8_t aw_control_rst = 0x00;
|
||||
static uint8_t aw_control_fsm = 0x10;
|
||||
static uint8_t aw_control_baudrate = 0x20;
|
||||
|
||||
static int rtck_enabled = 0;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
static int device_handle;
|
||||
|
||||
static int addr_mode = IEEE1284_MODE_EPP | IEEE1284_ADDR ;
|
||||
#define AMT_AW(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); write(device_handle, &val, 1); } while (0)
|
||||
#define AMT_AR(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); read(device_handle, &val, 1); } while (0)
|
||||
|
||||
static int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA ;
|
||||
#define AMT_DW(val) do { ioctl(device_handle, PPSETMODE, &data_mode); write(device_handle, &val, 1); } while (0)
|
||||
#define AMT_DR(val) do { ioctl(device_handle, PPSETMODE, &data_mode); read(device_handle, &val, 1); } while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define AMT_AW(val) do { outb(val, amt_jtagaccel_port + 3); } while (0)
|
||||
#define AMT_AR(val) do { val = inb(amt_jtagaccel_port + 3); } while (0)
|
||||
#define AMT_DW(val) do { outb(val, amt_jtagaccel_port + 4); } while (0)
|
||||
#define AMT_DR(val) do { val = inb(amt_jtagaccel_port + 4); } while (0)
|
||||
|
||||
#endif // PARPORT_USE_PPDEV
|
||||
|
||||
/* tap_move[i][j]: tap movement command to go from state i to state j
|
||||
* 0: Test-Logic-Reset
|
||||
* 1: Run-Test/Idle
|
||||
* 2: Shift-DR
|
||||
* 3: Pause-DR
|
||||
* 4: Shift-IR
|
||||
* 5: Pause-IR
|
||||
*/
|
||||
static uint8_t amt_jtagaccel_tap_move[6][6][2] =
|
||||
{
|
||||
/* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */
|
||||
{{0x1f, 0x00}, {0x0f, 0x00}, {0x05, 0x00}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00}}, /* RESET */
|
||||
{{0x1f, 0x00}, {0x00, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x0b, 0x00}}, /* IDLE */
|
||||
{{0x1f, 0x00}, {0x0d, 0x00}, {0x00, 0x00}, {0x01, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* DRSHIFT */
|
||||
{{0x1f, 0x00}, {0x0c, 0x00}, {0x08, 0x00}, {0x00, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* DRPAUSE */
|
||||
{{0x1f, 0x00}, {0x0d, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x00, 0x00}, {0x01, 0x00}}, /* IRSHIFT */
|
||||
{{0x1f, 0x00}, {0x0c, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x08, 0x00}, {0x00, 0x00}}, /* IRPAUSE */
|
||||
};
|
||||
|
||||
|
||||
static void amt_jtagaccel_reset(int trst, int srst)
|
||||
{
|
||||
if (trst == 1)
|
||||
aw_control_rst |= 0x4;
|
||||
else if (trst == 0)
|
||||
aw_control_rst &= ~0x4;
|
||||
|
||||
if (srst == 1)
|
||||
aw_control_rst |= 0x1;
|
||||
else if (srst == 0)
|
||||
aw_control_rst &= ~0x1;
|
||||
|
||||
AMT_AW(aw_control_rst);
|
||||
}
|
||||
|
||||
static int amt_jtagaccel_speed(int speed)
|
||||
{
|
||||
aw_control_baudrate &= 0xf0;
|
||||
aw_control_baudrate |= speed & 0x0f;
|
||||
AMT_AW(aw_control_baudrate);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void amt_jtagaccel_end_state(tap_state_t state)
|
||||
{
|
||||
if (tap_is_state_stable(state))
|
||||
tap_set_end_state(state);
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %i is not a valid end state", state);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void amt_wait_scan_busy(void)
|
||||
{
|
||||
int timeout = 4096;
|
||||
uint8_t ar_status;
|
||||
|
||||
AMT_AR(ar_status);
|
||||
while (((ar_status) & 0x80) && (timeout-- > 0))
|
||||
AMT_AR(ar_status);
|
||||
|
||||
if (ar_status & 0x80)
|
||||
{
|
||||
LOG_ERROR("amt_jtagaccel timed out while waiting for end of scan, rtck was %s, last AR_STATUS: 0x%2.2x", (rtck_enabled) ? "enabled" : "disabled", ar_status);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void amt_jtagaccel_state_move(void)
|
||||
{
|
||||
uint8_t aw_scan_tms_5;
|
||||
uint8_t tms_scan[2];
|
||||
|
||||
tap_state_t cur_state = tap_get_state();
|
||||
tap_state_t end_state = tap_get_end_state();
|
||||
|
||||
tms_scan[0] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][0];
|
||||
tms_scan[1] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][1];
|
||||
|
||||
aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f);
|
||||
AMT_AW(aw_scan_tms_5);
|
||||
int jtag_speed = jtag_get_speed();
|
||||
if (jtag_speed > 3 || rtck_enabled)
|
||||
amt_wait_scan_busy();
|
||||
|
||||
if (tms_scan[0] & 0x80)
|
||||
{
|
||||
aw_scan_tms_5 = 0x40 | (tms_scan[1] & 0x1f);
|
||||
AMT_AW(aw_scan_tms_5);
|
||||
if (jtag_speed > 3 || rtck_enabled)
|
||||
amt_wait_scan_busy();
|
||||
}
|
||||
|
||||
tap_set_state(end_state);
|
||||
}
|
||||
|
||||
static void amt_jtagaccel_runtest(int num_cycles)
|
||||
{
|
||||
int i = 0;
|
||||
uint8_t aw_scan_tms_5;
|
||||
uint8_t aw_scan_tms_1to4;
|
||||
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
|
||||
/* only do a state_move when we're not already in IDLE */
|
||||
if (tap_get_state() != TAP_IDLE)
|
||||
{
|
||||
amt_jtagaccel_end_state(TAP_IDLE);
|
||||
amt_jtagaccel_state_move();
|
||||
}
|
||||
|
||||
while (num_cycles - i >= 5)
|
||||
{
|
||||
aw_scan_tms_5 = 0x40;
|
||||
AMT_AW(aw_scan_tms_5);
|
||||
i += 5;
|
||||
}
|
||||
|
||||
if (num_cycles - i > 0)
|
||||
{
|
||||
aw_scan_tms_1to4 = 0x80 | ((num_cycles - i - 1) & 0x3) << 4;
|
||||
AMT_AW(aw_scan_tms_1to4);
|
||||
}
|
||||
|
||||
amt_jtagaccel_end_state(saved_end_state);
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
amt_jtagaccel_state_move();
|
||||
}
|
||||
|
||||
static void amt_jtagaccel_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
|
||||
{
|
||||
int bits_left = scan_size;
|
||||
int bit_count = 0;
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
uint8_t aw_tdi_option;
|
||||
uint8_t dw_tdi_scan;
|
||||
uint8_t dr_tdo;
|
||||
uint8_t aw_tms_scan;
|
||||
uint8_t tms_scan[2];
|
||||
int jtag_speed = jtag_get_speed();
|
||||
|
||||
if (ir_scan)
|
||||
amt_jtagaccel_end_state(TAP_IRSHIFT);
|
||||
else
|
||||
amt_jtagaccel_end_state(TAP_DRSHIFT);
|
||||
|
||||
amt_jtagaccel_state_move();
|
||||
amt_jtagaccel_end_state(saved_end_state);
|
||||
|
||||
/* handle unaligned bits at the beginning */
|
||||
if ((scan_size - 1) % 8)
|
||||
{
|
||||
aw_tdi_option = 0x30 | (((scan_size - 1) % 8) - 1);
|
||||
AMT_AW(aw_tdi_option);
|
||||
|
||||
dw_tdi_scan = buf_get_u32(buffer, bit_count, (scan_size - 1) % 8) & 0xff;
|
||||
AMT_DW(dw_tdi_scan);
|
||||
if (jtag_speed > 3 || rtck_enabled)
|
||||
amt_wait_scan_busy();
|
||||
|
||||
if ((type == SCAN_IN) || (type == SCAN_IO))
|
||||
{
|
||||
AMT_DR(dr_tdo);
|
||||
dr_tdo = dr_tdo >> (8 - ((scan_size - 1) % 8));
|
||||
buf_set_u32(buffer, bit_count, (scan_size - 1) % 8, dr_tdo);
|
||||
}
|
||||
|
||||
bit_count += (scan_size - 1) % 8;
|
||||
bits_left -= (scan_size - 1) % 8;
|
||||
}
|
||||
|
||||
while (bits_left - 1 >= 8)
|
||||
{
|
||||
dw_tdi_scan = buf_get_u32(buffer, bit_count, 8) & 0xff;
|
||||
AMT_DW(dw_tdi_scan);
|
||||
if (jtag_speed > 3 || rtck_enabled)
|
||||
amt_wait_scan_busy();
|
||||
|
||||
if ((type == SCAN_IN) || (type == SCAN_IO))
|
||||
{
|
||||
AMT_DR(dr_tdo);
|
||||
buf_set_u32(buffer, bit_count, 8, dr_tdo);
|
||||
}
|
||||
|
||||
bit_count += 8;
|
||||
bits_left -= 8;
|
||||
}
|
||||
|
||||
tms_scan[0] = amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][0];
|
||||
tms_scan[1] = amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][1];
|
||||
aw_tms_scan = 0x40 | (tms_scan[0] & 0x1f) | (buf_get_u32(buffer, bit_count, 1) << 5);
|
||||
AMT_AW(aw_tms_scan);
|
||||
if (jtag_speed > 3 || rtck_enabled)
|
||||
amt_wait_scan_busy();
|
||||
|
||||
if ((type == SCAN_IN) || (type == SCAN_IO))
|
||||
{
|
||||
AMT_DR(dr_tdo);
|
||||
dr_tdo = dr_tdo >> 7;
|
||||
buf_set_u32(buffer, bit_count, 1, dr_tdo);
|
||||
}
|
||||
|
||||
if (tms_scan[0] & 0x80)
|
||||
{
|
||||
aw_tms_scan = 0x40 | (tms_scan[1] & 0x1f);
|
||||
AMT_AW(aw_tms_scan);
|
||||
if (jtag_speed > 3 || rtck_enabled)
|
||||
amt_wait_scan_busy();
|
||||
}
|
||||
tap_set_state(tap_get_end_state());
|
||||
}
|
||||
|
||||
static int amt_jtagaccel_execute_queue(void)
|
||||
{
|
||||
struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
|
||||
int scan_size;
|
||||
enum scan_type type;
|
||||
uint8_t *buffer;
|
||||
int retval;
|
||||
|
||||
/* return ERROR_OK, unless a jtag_read_buffer returns a failed check
|
||||
* that wasn't handled by a caller-provided error handler
|
||||
*/
|
||||
retval = ERROR_OK;
|
||||
|
||||
while (cmd)
|
||||
{
|
||||
switch (cmd->type)
|
||||
{
|
||||
case JTAG_RESET:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
#endif
|
||||
if (cmd->cmd.reset->trst == 1)
|
||||
{
|
||||
tap_set_state(TAP_RESET);
|
||||
}
|
||||
amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
break;
|
||||
case JTAG_RUNTEST:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
|
||||
#endif
|
||||
amt_jtagaccel_end_state(cmd->cmd.runtest->end_state);
|
||||
amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles);
|
||||
break;
|
||||
case JTAG_STATEMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
|
||||
#endif
|
||||
amt_jtagaccel_end_state(cmd->cmd.statemove->end_state);
|
||||
amt_jtagaccel_state_move();
|
||||
break;
|
||||
case JTAG_SCAN:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("scan end in %i", cmd->cmd.scan->end_state);
|
||||
#endif
|
||||
amt_jtagaccel_end_state(cmd->cmd.scan->end_state);
|
||||
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
|
||||
retval = ERROR_JTAG_QUEUE_FAILED;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("sleep %" PRIi32, cmd->cmd.sleep->us);
|
||||
#endif
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
int amt_jtagaccel_get_giveio_access(void)
|
||||
{
|
||||
HANDLE h;
|
||||
OSVERSIONINFO version;
|
||||
|
||||
version.dwOSVersionInfoSize = sizeof version;
|
||||
if (!GetVersionEx(&version)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
||||
return 0;
|
||||
|
||||
h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int amt_jtagaccel_init(void)
|
||||
{
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
char buffer[256];
|
||||
int i = 0;
|
||||
uint8_t control_port;
|
||||
#else
|
||||
uint8_t status_port;
|
||||
#endif
|
||||
uint8_t ar_status;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
if (device_handle > 0)
|
||||
{
|
||||
LOG_ERROR("device is already opened");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
snprintf(buffer, 256, "/dev/parport%d", amt_jtagaccel_port);
|
||||
device_handle = open(buffer, O_RDWR);
|
||||
|
||||
if (device_handle < 0)
|
||||
{
|
||||
LOG_ERROR("cannot open device. check it exists and that user read and write rights are set");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
i = ioctl(device_handle, PPCLAIM);
|
||||
if (i < 0)
|
||||
{
|
||||
LOG_ERROR("cannot claim device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
i = IEEE1284_MODE_EPP;
|
||||
i = ioctl(device_handle, PPSETMODE, & i);
|
||||
if (i < 0)
|
||||
{
|
||||
LOG_ERROR(" cannot set compatible mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
control_port = 0x00;
|
||||
i = ioctl(device_handle, PPWCONTROL, &control_port);
|
||||
|
||||
control_port = 0x04;
|
||||
i = ioctl(device_handle, PPWCONTROL, &control_port);
|
||||
|
||||
#else
|
||||
if (amt_jtagaccel_port == 0)
|
||||
{
|
||||
amt_jtagaccel_port = 0x378;
|
||||
LOG_WARNING("No parport port specified, using default '0x378' (LPT1)");
|
||||
}
|
||||
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
if (amt_jtagaccel_get_giveio_access() != 0) {
|
||||
#else /* PARPORT_USE_GIVEIO */
|
||||
if (ioperm(amt_jtagaccel_port, 5, 1) != 0) {
|
||||
#endif /* PARPORT_USE_GIVEIO */
|
||||
LOG_ERROR("missing privileges for direct i/o");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* prepare epp port */
|
||||
/* clear timeout */
|
||||
status_port = inb(amt_jtagaccel_port + 1);
|
||||
outb(status_port | 0x1, amt_jtagaccel_port + 1);
|
||||
|
||||
/* reset epp port */
|
||||
outb(0x00, amt_jtagaccel_port + 2);
|
||||
outb(0x04, amt_jtagaccel_port + 2);
|
||||
#endif
|
||||
|
||||
if (rtck_enabled)
|
||||
{
|
||||
/* set RTCK enable bit */
|
||||
aw_control_fsm |= 0x02;
|
||||
}
|
||||
|
||||
/* enable JTAG port */
|
||||
aw_control_fsm |= 0x04;
|
||||
AMT_AW(aw_control_fsm);
|
||||
|
||||
amt_jtagaccel_speed(jtag_get_speed());
|
||||
|
||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||
if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
|
||||
aw_control_rst &= ~0x8;
|
||||
else
|
||||
aw_control_rst |= 0x8;
|
||||
|
||||
if (jtag_reset_config & RESET_SRST_PUSH_PULL)
|
||||
aw_control_rst &= ~0x2;
|
||||
else
|
||||
aw_control_rst |= 0x2;
|
||||
|
||||
amt_jtagaccel_reset(0, 0);
|
||||
|
||||
/* read status register */
|
||||
AMT_AR(ar_status);
|
||||
LOG_DEBUG("AR_STATUS: 0x%2.2x", ar_status);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int amt_jtagaccel_quit(void)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(amt_jtagaccel_handle_parport_port_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
{
|
||||
/* only if the port wasn't overwritten by cmdline */
|
||||
if (amt_jtagaccel_port == 0)
|
||||
{
|
||||
uint16_t port;
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
|
||||
amt_jtagaccel_port = port;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("The parport port was already configured!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "parport port = %u", amt_jtagaccel_port);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(amt_jtagaccel_handle_rtck_command)
|
||||
{
|
||||
if (CMD_ARGC == 0)
|
||||
{
|
||||
command_print(CMD_CTX, "amt_jtagaccel RTCK feature %s", (rtck_enabled) ? "enabled" : "disabled");
|
||||
return ERROR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp(CMD_ARGV[0], "enabled") == 0)
|
||||
{
|
||||
rtck_enabled = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtck_enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration amtjtagaccel_command_handlers[] = {
|
||||
{
|
||||
.name = "parport_port",
|
||||
.handler = &amt_jtagaccel_handle_parport_port_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "configure the parallel port to use",
|
||||
.usage = "<port_num>",
|
||||
},
|
||||
{
|
||||
.name = "parport_port",
|
||||
.handler = &amt_jtagaccel_handle_rtck_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "enable RTCK",
|
||||
.usage = "<enable|disable>",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface amt_jtagaccel_interface = {
|
||||
.name = "amt_jtagaccel",
|
||||
.commands = amtjtagaccel_command_handlers,
|
||||
.init = &amt_jtagaccel_init,
|
||||
.quit = &amt_jtagaccel_quit,
|
||||
.speed = &amt_jtagaccel_speed,
|
||||
.execute_queue = &amt_jtagaccel_execute_queue,
|
||||
};
|
||||
837
src/jtag/drivers/arm-jtag-ew.c
Normal file
837
src/jtag/drivers/arm-jtag-ew.c
Normal file
@@ -0,0 +1,837 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Dimitar Dimitrov <dinuxbg@gmail.com> *
|
||||
* based on Dominic Rath's and Benedikt Sauter's usbprog.c *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "commands.h"
|
||||
#include <usb.h>
|
||||
#include "usb_common.h"
|
||||
|
||||
|
||||
#define USB_VID 0x15ba
|
||||
#define USB_PID 0x001e
|
||||
|
||||
#define ARMJTAGEW_EPT_BULK_OUT 0x01u
|
||||
#define ARMJTAGEW_EPT_BULK_IN 0x82u
|
||||
|
||||
#define ARMJTAGEW_USB_TIMEOUT 2000
|
||||
|
||||
#define ARMJTAGEW_IN_BUFFER_SIZE (4*1024)
|
||||
#define ARMJTAGEW_OUT_BUFFER_SIZE (4*1024)
|
||||
|
||||
|
||||
/* USB command request codes. */
|
||||
#define CMD_GET_VERSION 0x00
|
||||
#define CMD_SELECT_DPIMPL 0x10
|
||||
#define CMD_SET_TCK_FREQUENCY 0x11
|
||||
#define CMD_GET_TCK_FREQUENCY 0x12
|
||||
#define CMD_MEASURE_MAX_TCK_FREQ 0x15
|
||||
#define CMD_MEASURE_RTCK_RESPONSE 0x16
|
||||
#define CMD_TAP_SHIFT 0x17
|
||||
#define CMD_SET_TAPHW_STATE 0x20
|
||||
#define CMD_GET_TAPHW_STATE 0x21
|
||||
#define CMD_TGPWR_SETUP 0x22
|
||||
|
||||
/* Global USB buffers */
|
||||
static uint8_t usb_in_buffer[ARMJTAGEW_IN_BUFFER_SIZE];
|
||||
static uint8_t usb_out_buffer[ARMJTAGEW_OUT_BUFFER_SIZE];
|
||||
|
||||
/* Queue command functions */
|
||||
static void armjtagew_end_state(tap_state_t state);
|
||||
static void armjtagew_state_move(void);
|
||||
static void armjtagew_path_move(int num_states, tap_state_t *path);
|
||||
static void armjtagew_runtest(int num_cycles);
|
||||
static void armjtagew_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command);
|
||||
static void armjtagew_reset(int trst, int srst);
|
||||
//static void armjtagew_simple_command(uint8_t command);
|
||||
static int armjtagew_get_status(void);
|
||||
|
||||
/* tap buffer functions */
|
||||
static void armjtagew_tap_init(void);
|
||||
static int armjtagew_tap_execute(void);
|
||||
static void armjtagew_tap_ensure_space(int scans, int bits);
|
||||
static void armjtagew_tap_append_step(int tms, int tdi);
|
||||
static void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command);
|
||||
|
||||
/* ARM-JTAG-EW lowlevel functions */
|
||||
struct armjtagew {
|
||||
struct usb_dev_handle* usb_handle;
|
||||
};
|
||||
|
||||
static struct armjtagew *armjtagew_usb_open(void);
|
||||
static void armjtagew_usb_close(struct armjtagew *armjtagew);
|
||||
static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, int in_length);
|
||||
static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length);
|
||||
static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length);
|
||||
|
||||
/* helper functions */
|
||||
static int armjtagew_get_version_info(void);
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
static void armjtagew_debug_buffer(uint8_t *buffer, int length);
|
||||
#endif
|
||||
|
||||
static struct armjtagew* armjtagew_handle;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* External interface implementation */
|
||||
|
||||
static int armjtagew_execute_queue(void)
|
||||
{
|
||||
struct jtag_command *cmd = jtag_command_queue;
|
||||
int scan_size;
|
||||
enum scan_type type;
|
||||
uint8_t *buffer;
|
||||
|
||||
while (cmd != NULL)
|
||||
{
|
||||
switch (cmd->type)
|
||||
{
|
||||
case JTAG_RUNTEST:
|
||||
DEBUG_JTAG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, \
|
||||
cmd->cmd.runtest->end_state);
|
||||
|
||||
armjtagew_end_state(cmd->cmd.runtest->end_state);
|
||||
armjtagew_runtest(cmd->cmd.runtest->num_cycles);
|
||||
break;
|
||||
|
||||
case JTAG_STATEMOVE:
|
||||
DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state);
|
||||
|
||||
armjtagew_end_state(cmd->cmd.statemove->end_state);
|
||||
armjtagew_state_move();
|
||||
break;
|
||||
|
||||
case JTAG_PATHMOVE:
|
||||
DEBUG_JTAG_IO("pathmove: %i states, end in %i", \
|
||||
cmd->cmd.pathmove->num_states, \
|
||||
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
|
||||
|
||||
armjtagew_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path);
|
||||
break;
|
||||
|
||||
case JTAG_SCAN:
|
||||
DEBUG_JTAG_IO("scan end in %i", cmd->cmd.scan->end_state);
|
||||
|
||||
armjtagew_end_state(cmd->cmd.scan->end_state);
|
||||
|
||||
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||
DEBUG_JTAG_IO("scan input, length = %d", scan_size);
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
armjtagew_debug_buffer(buffer, (scan_size + 7) / 8);
|
||||
#endif
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
armjtagew_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan);
|
||||
break;
|
||||
|
||||
case JTAG_RESET:
|
||||
DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
|
||||
armjtagew_tap_execute();
|
||||
|
||||
if (cmd->cmd.reset->trst == 1)
|
||||
{
|
||||
tap_set_state(TAP_RESET);
|
||||
}
|
||||
armjtagew_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
break;
|
||||
|
||||
case JTAG_SLEEP:
|
||||
DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us);
|
||||
armjtagew_tap_execute();
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
return armjtagew_tap_execute();
|
||||
}
|
||||
|
||||
|
||||
/* Sets speed in kHz. */
|
||||
static int armjtagew_speed(int speed)
|
||||
{
|
||||
int result;
|
||||
int speed_real;
|
||||
|
||||
|
||||
usb_out_buffer[0] = CMD_SET_TCK_FREQUENCY;
|
||||
buf_set_u32(usb_out_buffer + 1, 0, 32, speed);
|
||||
|
||||
result = armjtagew_usb_message(armjtagew_handle, 4, 4);
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
LOG_ERROR("ARM-JTAG-EW setting speed failed (%d)", result);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
usb_out_buffer[0] = CMD_GET_TCK_FREQUENCY;
|
||||
result = armjtagew_usb_message(armjtagew_handle, 1, 4);
|
||||
speed_real = (int)buf_get_u32(usb_in_buffer,0,32);
|
||||
if (result < 0)
|
||||
{
|
||||
LOG_ERROR("ARM-JTAG-EW getting speed failed (%d)", result);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO("Requested speed %dkHz, emulator reported %dkHz.", speed, speed_real);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
static int armjtagew_khz(int khz, int *jtag_speed)
|
||||
{
|
||||
*jtag_speed = khz;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int armjtagew_init(void)
|
||||
{
|
||||
int check_cnt;
|
||||
|
||||
armjtagew_handle = armjtagew_usb_open();
|
||||
|
||||
if (armjtagew_handle == 0)
|
||||
{
|
||||
LOG_ERROR("Cannot find ARM-JTAG-EW Interface! Please check connection and permissions.");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
check_cnt = 0;
|
||||
while (check_cnt < 3)
|
||||
{
|
||||
if (armjtagew_get_version_info() == ERROR_OK)
|
||||
{
|
||||
/* attempt to get status */
|
||||
armjtagew_get_status();
|
||||
break;
|
||||
}
|
||||
|
||||
check_cnt++;
|
||||
}
|
||||
|
||||
if (check_cnt == 3)
|
||||
{
|
||||
LOG_INFO("ARM-JTAG-EW initial read failed, don't worry");
|
||||
}
|
||||
|
||||
LOG_INFO("ARM-JTAG-EW JTAG Interface ready");
|
||||
|
||||
armjtagew_reset(0, 0);
|
||||
armjtagew_tap_init();
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int armjtagew_quit(void)
|
||||
{
|
||||
armjtagew_usb_close(armjtagew_handle);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* Queue command implementations */
|
||||
|
||||
static void armjtagew_end_state(tap_state_t state)
|
||||
{
|
||||
if (tap_is_state_stable(state))
|
||||
{
|
||||
tap_set_end_state(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %i is not a valid end state", state);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Goes to the end state. */
|
||||
static void armjtagew_state_move(void)
|
||||
{
|
||||
int i;
|
||||
int tms = 0;
|
||||
uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
|
||||
int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
|
||||
|
||||
for (i = 0; i < tms_count; i++)
|
||||
{
|
||||
tms = (tms_scan >> i) & 1;
|
||||
armjtagew_tap_append_step(tms, 0);
|
||||
}
|
||||
|
||||
tap_set_state(tap_get_end_state());
|
||||
}
|
||||
|
||||
static void armjtagew_path_move(int num_states, tap_state_t *path)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_states; i++)
|
||||
{
|
||||
/*
|
||||
* TODO: The ARM-JTAG-EW hardware delays TDI with 3 TCK cycles when in RTCK mode.
|
||||
* Either handle that here, or update the documentation with examples
|
||||
* how to fix that in the configuration files.
|
||||
*/
|
||||
if (path[i] == tap_state_transition(tap_get_state(), false))
|
||||
{
|
||||
armjtagew_tap_append_step(0, 0);
|
||||
}
|
||||
else if (path[i] == tap_state_transition(tap_get_state(), true))
|
||||
{
|
||||
armjtagew_tap_append_step(1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i]));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tap_set_state(path[i]);
|
||||
}
|
||||
|
||||
tap_set_end_state(tap_get_state());
|
||||
}
|
||||
|
||||
static void armjtagew_runtest(int num_cycles)
|
||||
{
|
||||
int i;
|
||||
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
|
||||
/* only do a state_move when we're not already in IDLE */
|
||||
if (tap_get_state() != TAP_IDLE)
|
||||
{
|
||||
armjtagew_end_state(TAP_IDLE);
|
||||
armjtagew_state_move();
|
||||
}
|
||||
|
||||
/* execute num_cycles */
|
||||
for (i = 0; i < num_cycles; i++)
|
||||
{
|
||||
armjtagew_tap_append_step(0, 0);
|
||||
}
|
||||
|
||||
/* finish in end_state */
|
||||
armjtagew_end_state(saved_end_state);
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
{
|
||||
armjtagew_state_move();
|
||||
}
|
||||
}
|
||||
|
||||
static void armjtagew_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command)
|
||||
{
|
||||
tap_state_t saved_end_state;
|
||||
|
||||
armjtagew_tap_ensure_space(1, scan_size + 8);
|
||||
|
||||
saved_end_state = tap_get_end_state();
|
||||
|
||||
/* Move to appropriate scan state */
|
||||
armjtagew_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT);
|
||||
|
||||
armjtagew_state_move();
|
||||
armjtagew_end_state(saved_end_state);
|
||||
|
||||
/* Scan */
|
||||
armjtagew_tap_append_scan(scan_size, buffer, command);
|
||||
|
||||
/* We are in Exit1, go to Pause */
|
||||
armjtagew_tap_append_step(0, 0);
|
||||
|
||||
tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE);
|
||||
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
{
|
||||
armjtagew_state_move();
|
||||
}
|
||||
}
|
||||
|
||||
static void armjtagew_reset(int trst, int srst)
|
||||
{
|
||||
const uint8_t trst_mask = (1u << 5);
|
||||
const uint8_t srst_mask = (1u << 6);
|
||||
uint8_t val = 0;
|
||||
uint8_t outp_en = 0;
|
||||
uint8_t change_mask = 0;
|
||||
int result;
|
||||
|
||||
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
|
||||
|
||||
if (srst == 0)
|
||||
{
|
||||
val |= srst_mask;
|
||||
outp_en &= ~srst_mask; /* tristate */
|
||||
change_mask |= srst_mask;
|
||||
}
|
||||
else if (srst == 1)
|
||||
{
|
||||
val &= ~srst_mask;
|
||||
outp_en |= srst_mask;
|
||||
change_mask |= srst_mask;
|
||||
}
|
||||
|
||||
if (trst == 0)
|
||||
{
|
||||
val |= trst_mask;
|
||||
outp_en &= ~trst_mask; /* tristate */
|
||||
change_mask |= trst_mask;
|
||||
}
|
||||
else if (trst == 1)
|
||||
{
|
||||
val &= ~trst_mask;
|
||||
outp_en |= trst_mask;
|
||||
change_mask |= trst_mask;
|
||||
}
|
||||
|
||||
usb_out_buffer[0] = CMD_SET_TAPHW_STATE;
|
||||
usb_out_buffer[1] = val;
|
||||
usb_out_buffer[2] = outp_en;
|
||||
usb_out_buffer[3] = change_mask;
|
||||
result = armjtagew_usb_write(armjtagew_handle, 4);
|
||||
if (result != 4)
|
||||
{
|
||||
LOG_ERROR("ARM-JTAG-EW TRST/SRST pin set failed failed (%d)", result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int armjtagew_get_status(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
usb_out_buffer[0] = CMD_GET_TAPHW_STATE;
|
||||
result = armjtagew_usb_message(armjtagew_handle, 1, 12);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
unsigned int u_tg = buf_get_u32(usb_in_buffer, 0, 16);
|
||||
LOG_INFO("U_tg = %d mV, U_aux = %d mV, U_tgpwr = %d mV, I_tgpwr = %d mA, D1 = %d, Target power %s %s\n",
|
||||
(int)(buf_get_u32(usb_in_buffer + 0, 0, 16)),
|
||||
(int)(buf_get_u32(usb_in_buffer + 2, 0, 16)),
|
||||
(int)(buf_get_u32(usb_in_buffer + 4, 0, 16)),
|
||||
(int)(buf_get_u32(usb_in_buffer + 6, 0, 16)),
|
||||
usb_in_buffer[9],
|
||||
usb_in_buffer[11] ? "OVERCURRENT" : "OK",
|
||||
usb_in_buffer[10] ? "enabled" : "disabled");
|
||||
|
||||
if (u_tg < 1500)
|
||||
{
|
||||
LOG_ERROR("Vref too low. Check Target Power\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("ARM-JTAG-EW command CMD_GET_TAPHW_STATE failed (%d)\n", result);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int armjtagew_get_version_info(void)
|
||||
{
|
||||
int result;
|
||||
char sn[16];
|
||||
char auxinfo[257];
|
||||
|
||||
/* query hardware version */
|
||||
usb_out_buffer[0] = CMD_GET_VERSION;
|
||||
result = armjtagew_usb_message(armjtagew_handle, 1, 4 + 15 + 256);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
LOG_ERROR("ARM-JTAG-EW command CMD_GET_VERSION failed (%d)\n", result);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
memcpy(sn, usb_in_buffer + 4, 15);
|
||||
sn[15] = '\0';
|
||||
memcpy(auxinfo, usb_in_buffer + 4+15, 256);
|
||||
auxinfo[256] = '\0';
|
||||
|
||||
LOG_INFO("ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s", \
|
||||
usb_in_buffer[1], usb_in_buffer[0], \
|
||||
isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X', \
|
||||
sn, auxinfo);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(armjtagew_handle_armjtagew_info_command)
|
||||
{
|
||||
if (armjtagew_get_version_info() == ERROR_OK)
|
||||
{
|
||||
/* attempt to get status */
|
||||
armjtagew_get_status();
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration armjtagew_command_handlers[] = {
|
||||
{
|
||||
.name = "armjtagew_info",
|
||||
.handler = &armjtagew_handle_armjtagew_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "query armjtagew info",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface armjtagew_interface = {
|
||||
.name = "arm-jtag-ew",
|
||||
|
||||
.commands = armjtagew_command_handlers,
|
||||
|
||||
.execute_queue = &armjtagew_execute_queue,
|
||||
.speed = &armjtagew_speed,
|
||||
.khz = &armjtagew_khz,
|
||||
|
||||
.init = &armjtagew_init,
|
||||
.quit = &armjtagew_quit,
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
/* ARM-JTAG-EW tap functions */
|
||||
|
||||
/* 2048 is the max value we can use here */
|
||||
#define ARMJTAGEW_TAP_BUFFER_SIZE 2048
|
||||
|
||||
static int tap_length;
|
||||
static uint8_t tms_buffer[ARMJTAGEW_TAP_BUFFER_SIZE];
|
||||
static uint8_t tdi_buffer[ARMJTAGEW_TAP_BUFFER_SIZE];
|
||||
static uint8_t tdo_buffer[ARMJTAGEW_TAP_BUFFER_SIZE];
|
||||
|
||||
struct pending_scan_result {
|
||||
int first; /* First bit position in tdo_buffer to read */
|
||||
int length; /* Number of bits to read */
|
||||
struct scan_command *command; /* Corresponding scan command */
|
||||
uint8_t *buffer;
|
||||
};
|
||||
|
||||
#define MAX_PENDING_SCAN_RESULTS 256
|
||||
|
||||
static int pending_scan_results_length;
|
||||
static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS];
|
||||
|
||||
static int last_tms;
|
||||
|
||||
static void armjtagew_tap_init(void)
|
||||
{
|
||||
tap_length = 0;
|
||||
pending_scan_results_length = 0;
|
||||
}
|
||||
|
||||
static void armjtagew_tap_ensure_space(int scans, int bits)
|
||||
{
|
||||
int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length;
|
||||
int available_bits = ARMJTAGEW_TAP_BUFFER_SIZE * 8 - tap_length;
|
||||
|
||||
if (scans > available_scans || bits > available_bits)
|
||||
{
|
||||
armjtagew_tap_execute();
|
||||
}
|
||||
}
|
||||
|
||||
static void armjtagew_tap_append_step(int tms, int tdi)
|
||||
{
|
||||
last_tms = tms;
|
||||
int index = tap_length / 8;
|
||||
|
||||
if (index < ARMJTAGEW_TAP_BUFFER_SIZE)
|
||||
{
|
||||
int bit_index = tap_length % 8;
|
||||
uint8_t bit = 1 << bit_index;
|
||||
|
||||
if (tms)
|
||||
{
|
||||
tms_buffer[index] |= bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
tms_buffer[index] &= ~bit;
|
||||
}
|
||||
|
||||
if (tdi)
|
||||
{
|
||||
tdi_buffer[index] |= bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
tdi_buffer[index] &= ~bit;
|
||||
}
|
||||
|
||||
tap_length++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("armjtagew_tap_append_step, overflow");
|
||||
}
|
||||
}
|
||||
|
||||
void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command)
|
||||
{
|
||||
struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length];
|
||||
int i;
|
||||
|
||||
pending_scan_result->first = tap_length;
|
||||
pending_scan_result->length = length;
|
||||
pending_scan_result->command = command;
|
||||
pending_scan_result->buffer = buffer;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
armjtagew_tap_append_step((i < length-1 ? 0 : 1), (buffer[i/8] >> (i%8)) & 1);
|
||||
}
|
||||
pending_scan_results_length++;
|
||||
}
|
||||
|
||||
/* Pad and send a tap sequence to the device, and receive the answer.
|
||||
* For the purpose of padding we assume that we are in idle or pause state. */
|
||||
static int armjtagew_tap_execute(void)
|
||||
{
|
||||
int byte_length;
|
||||
int tms_offset;
|
||||
int tdi_offset;
|
||||
int i;
|
||||
int result;
|
||||
|
||||
if (tap_length > 0)
|
||||
{
|
||||
/* Pad last byte so that tap_length is divisible by 8 */
|
||||
while (tap_length % 8 != 0)
|
||||
{
|
||||
/* More of the last TMS value keeps us in the same state,
|
||||
* analogous to free-running JTAG interfaces. */
|
||||
armjtagew_tap_append_step(last_tms, 0);
|
||||
}
|
||||
|
||||
byte_length = tap_length / 8;
|
||||
|
||||
usb_out_buffer[0] = CMD_TAP_SHIFT;
|
||||
buf_set_u32(usb_out_buffer + 1, 0, 16, byte_length);
|
||||
|
||||
tms_offset = 3;
|
||||
for (i = 0; i < byte_length; i++)
|
||||
{
|
||||
usb_out_buffer[tms_offset + i] = flip_u32(tms_buffer[i],8);
|
||||
}
|
||||
|
||||
tdi_offset = tms_offset + byte_length;
|
||||
for (i = 0; i < byte_length; i++)
|
||||
{
|
||||
usb_out_buffer[tdi_offset + i] = flip_u32(tdi_buffer[i],8);
|
||||
}
|
||||
|
||||
result = armjtagew_usb_message(armjtagew_handle, 3 + 2 * byte_length, byte_length + 4);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
int stat;
|
||||
|
||||
stat = (int)buf_get_u32(usb_in_buffer + byte_length, 0, 32);
|
||||
if (stat) {
|
||||
LOG_ERROR("armjtagew_tap_execute, emulator returned error code %d for a CMD_TAP_SHIFT command", stat);
|
||||
return ERROR_JTAG_QUEUE_FAILED;
|
||||
}
|
||||
|
||||
for (i = 0; i < byte_length; i++)
|
||||
{
|
||||
tdo_buffer[i] = flip_u32(usb_in_buffer[i],8);
|
||||
}
|
||||
|
||||
for (i = 0; i < pending_scan_results_length; i++)
|
||||
{
|
||||
struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i];
|
||||
uint8_t *buffer = pending_scan_result->buffer;
|
||||
int length = pending_scan_result->length;
|
||||
int first = pending_scan_result->first;
|
||||
struct scan_command *command = pending_scan_result->command;
|
||||
|
||||
/* Copy to buffer */
|
||||
buf_set_buf(tdo_buffer, first, buffer, 0, length);
|
||||
|
||||
DEBUG_JTAG_IO("pending scan result, length = %d", length);
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
armjtagew_debug_buffer(buffer, byte_length);
|
||||
#endif
|
||||
|
||||
if (jtag_read_buffer(buffer, command) != ERROR_OK)
|
||||
{
|
||||
armjtagew_tap_init();
|
||||
return ERROR_JTAG_QUEUE_FAILED;
|
||||
}
|
||||
|
||||
if (pending_scan_result->buffer != NULL)
|
||||
{
|
||||
free(pending_scan_result->buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("armjtagew_tap_execute, wrong result %d, expected %d", result, byte_length);
|
||||
return ERROR_JTAG_QUEUE_FAILED;
|
||||
}
|
||||
|
||||
armjtagew_tap_init();
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* JLink USB low-level functions */
|
||||
|
||||
static struct armjtagew* armjtagew_usb_open()
|
||||
{
|
||||
usb_init();
|
||||
|
||||
const uint16_t vids[] = { USB_VID, 0 };
|
||||
const uint16_t pids[] = { USB_PID, 0 };
|
||||
struct usb_dev_handle *dev;
|
||||
if (jtag_usb_open(vids, pids, &dev) != ERROR_OK)
|
||||
return NULL;
|
||||
|
||||
struct armjtagew *result = malloc(sizeof(struct armjtagew));
|
||||
result->usb_handle = dev;
|
||||
|
||||
#if 0
|
||||
/* usb_set_configuration required under win32 */
|
||||
usb_set_configuration(dev, dev->config[0].bConfigurationValue);
|
||||
#endif
|
||||
usb_claim_interface(dev, 0);
|
||||
#if 0
|
||||
/*
|
||||
* This makes problems under Mac OS X. And is not needed
|
||||
* under Windows. Hopefully this will not break a linux build
|
||||
*/
|
||||
usb_set_altinterface(dev, 0);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static void armjtagew_usb_close(struct armjtagew *armjtagew)
|
||||
{
|
||||
usb_close(armjtagew->usb_handle);
|
||||
free(armjtagew);
|
||||
}
|
||||
|
||||
/* Send a message and receive the reply. */
|
||||
static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, int in_length)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = armjtagew_usb_write(armjtagew, out_length);
|
||||
if (result == out_length)
|
||||
{
|
||||
result = armjtagew_usb_read(armjtagew, in_length);
|
||||
if (result != in_length)
|
||||
{
|
||||
LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write data from out_buffer to USB. */
|
||||
static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (out_length > ARMJTAGEW_OUT_BUFFER_SIZE)
|
||||
{
|
||||
LOG_ERROR("armjtagew_write illegal out_length=%d (max=%d)", out_length, ARMJTAGEW_OUT_BUFFER_SIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, \
|
||||
(char*)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT);
|
||||
|
||||
DEBUG_JTAG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result);
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
armjtagew_debug_buffer(usb_out_buffer, out_length);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Read data from USB into in_buffer. */
|
||||
static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length)
|
||||
{
|
||||
int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, \
|
||||
(char*)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT);
|
||||
|
||||
DEBUG_JTAG_IO("armjtagew_usb_read, result = %d", result);
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
armjtagew_debug_buffer(usb_in_buffer, result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _DEBUG_USB_COMMS_
|
||||
#define BYTES_PER_LINE 16
|
||||
|
||||
static void armjtagew_debug_buffer(uint8_t *buffer, int length)
|
||||
{
|
||||
char line[81];
|
||||
char s[4];
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < length; i += BYTES_PER_LINE)
|
||||
{
|
||||
snprintf(line, 5, "%04x", i);
|
||||
for (j = i; j < i + BYTES_PER_LINE && j < length; j++)
|
||||
{
|
||||
snprintf(s, 4, " %02x", buffer[j]);
|
||||
strcat(line, s);
|
||||
}
|
||||
LOG_DEBUG("%s", line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
292
src/jtag/drivers/at91rm9200.c
Normal file
292
src/jtag/drivers/at91rm9200.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Anders Larsen *
|
||||
* al@alarsen.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "bitbang.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
||||
/* AT91RM9200 */
|
||||
#define AT91C_BASE_SYS (0xfffff000)
|
||||
|
||||
/* GPIO assignment */
|
||||
#define PIOA (0 << 7)
|
||||
#define PIOB (1 << 7)
|
||||
#define PIOC (2 << 7)
|
||||
#define PIOD (3 << 7)
|
||||
|
||||
#define PIO_PER (0) /* PIO enable */
|
||||
#define PIO_OER (4) /* output enable */
|
||||
#define PIO_ODR (5) /* output disable */
|
||||
#define PIO_SODR (12) /* set output data */
|
||||
#define PIO_CODR (13) /* clear output data */
|
||||
#define PIO_PDSR (15) /* pin data status */
|
||||
#define PIO_PPUER (25) /* pull-up enable */
|
||||
|
||||
#define NC (0) /* not connected */
|
||||
#define P0 (1 << 0)
|
||||
#define P1 (1 << 1)
|
||||
#define P2 (1 << 2)
|
||||
#define P3 (1 << 3)
|
||||
#define P4 (1 << 4)
|
||||
#define P5 (1 << 5)
|
||||
#define P6 (1 << 6)
|
||||
#define P7 (1 << 7)
|
||||
#define P8 (1 << 8)
|
||||
#define P9 (1 << 9)
|
||||
#define P10 (1 << 10)
|
||||
#define P11 (1 << 11)
|
||||
#define P12 (1 << 12)
|
||||
#define P13 (1 << 13)
|
||||
#define P14 (1 << 14)
|
||||
#define P15 (1 << 15)
|
||||
#define P16 (1 << 16)
|
||||
#define P17 (1 << 17)
|
||||
#define P18 (1 << 18)
|
||||
#define P19 (1 << 19)
|
||||
#define P20 (1 << 20)
|
||||
#define P21 (1 << 21)
|
||||
#define P22 (1 << 22)
|
||||
#define P23 (1 << 23)
|
||||
#define P24 (1 << 24)
|
||||
#define P25 (1 << 25)
|
||||
#define P26 (1 << 26)
|
||||
#define P27 (1 << 27)
|
||||
#define P28 (1 << 28)
|
||||
#define P29 (1 << 29)
|
||||
#define P30 (1 << 30)
|
||||
#define P31 (1 << 31)
|
||||
|
||||
struct device_t
|
||||
{
|
||||
char* name;
|
||||
int TDO_PIO; /* PIO holding TDO */
|
||||
uint32_t TDO_MASK; /* TDO bitmask */
|
||||
int TRST_PIO; /* PIO holding TRST */
|
||||
uint32_t TRST_MASK; /* TRST bitmask */
|
||||
int TMS_PIO; /* PIO holding TMS */
|
||||
uint32_t TMS_MASK; /* TMS bitmask */
|
||||
int TCK_PIO; /* PIO holding TCK */
|
||||
uint32_t TCK_MASK; /* TCK bitmask */
|
||||
int TDI_PIO; /* PIO holding TDI */
|
||||
uint32_t TDI_MASK; /* TDI bitmask */
|
||||
int SRST_PIO; /* PIO holding SRST */
|
||||
uint32_t SRST_MASK; /* SRST bitmask */
|
||||
};
|
||||
|
||||
static struct device_t devices[] =
|
||||
{
|
||||
{ "rea_ecr", PIOD, P27, PIOA, NC, PIOD, P23, PIOD, P24, PIOD, P26, PIOC, P5 },
|
||||
{ .name = NULL },
|
||||
};
|
||||
|
||||
/* configuration */
|
||||
static char* at91rm9200_device;
|
||||
|
||||
/* interface variables
|
||||
*/
|
||||
static struct device_t* device;
|
||||
static int dev_mem_fd;
|
||||
static void *sys_controller;
|
||||
static uint32_t* pio_base;
|
||||
|
||||
/* low level command set
|
||||
*/
|
||||
static int at91rm9200_read(void);
|
||||
static void at91rm9200_write(int tck, int tms, int tdi);
|
||||
static void at91rm9200_reset(int trst, int srst);
|
||||
|
||||
static int at91rm9200_speed(int speed);
|
||||
static int at91rm9200_register_commands(struct command_context *cmd_ctx);
|
||||
static int at91rm9200_init(void);
|
||||
static int at91rm9200_quit(void);
|
||||
|
||||
struct jtag_interface at91rm9200_interface =
|
||||
{
|
||||
.name = "at91rm9200",
|
||||
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
|
||||
.speed = at91rm9200_speed,
|
||||
.register_commands = at91rm9200_register_commands,
|
||||
.init = at91rm9200_init,
|
||||
.quit = at91rm9200_quit,
|
||||
};
|
||||
|
||||
static struct bitbang_interface at91rm9200_bitbang =
|
||||
{
|
||||
.read = at91rm9200_read,
|
||||
.write = at91rm9200_write,
|
||||
.reset = at91rm9200_reset,
|
||||
.blink = 0
|
||||
};
|
||||
|
||||
static int at91rm9200_read(void)
|
||||
{
|
||||
return (pio_base[device->TDO_PIO + PIO_PDSR] & device->TDO_MASK) != 0;
|
||||
}
|
||||
|
||||
static void at91rm9200_write(int tck, int tms, int tdi)
|
||||
{
|
||||
if (tck)
|
||||
pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK;
|
||||
else
|
||||
pio_base[device->TCK_PIO + PIO_CODR] = device->TCK_MASK;
|
||||
|
||||
if (tms)
|
||||
pio_base[device->TMS_PIO + PIO_SODR] = device->TMS_MASK;
|
||||
else
|
||||
pio_base[device->TMS_PIO + PIO_CODR] = device->TMS_MASK;
|
||||
|
||||
if (tdi)
|
||||
pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK;
|
||||
else
|
||||
pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK;
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
static void at91rm9200_reset(int trst, int srst)
|
||||
{
|
||||
if (trst == 0)
|
||||
pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK;
|
||||
else if (trst == 1)
|
||||
pio_base[device->TRST_PIO + PIO_CODR] = device->TRST_MASK;
|
||||
|
||||
if (srst == 0)
|
||||
pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK;
|
||||
else if (srst == 1)
|
||||
pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK;
|
||||
}
|
||||
|
||||
static int at91rm9200_speed(int speed)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91rm9200_handle_device_command(struct command_context *cmd_ctx, char *cmd, char **CMD_ARGV, int argc)
|
||||
{
|
||||
if (CMD_ARGC == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
/* only if the device name wasn't overwritten by cmdline */
|
||||
if (at91rm9200_device == 0)
|
||||
{
|
||||
at91rm9200_device = malloc(strlen(CMD_ARGV[0]) + sizeof(char));
|
||||
strcpy(at91rm9200_device, CMD_ARGV[0]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration at91rm9200_command_handlers[] = {
|
||||
{
|
||||
.name = "at91rm9200_device",
|
||||
.handler = &at91rm9200_handle_device_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "query armjtagew info",
|
||||
},
|
||||
};
|
||||
|
||||
static int at91rm9200_register_commands(struct command_context *cmd_ctx)
|
||||
{
|
||||
return register_commands(cmd_ctx, NULL, at91rm9200_command_handlers);
|
||||
}
|
||||
|
||||
static int at91rm9200_init(void)
|
||||
{
|
||||
struct device_t *cur_device;
|
||||
|
||||
cur_device = devices;
|
||||
|
||||
if (at91rm9200_device == NULL || at91rm9200_device[0] == 0)
|
||||
{
|
||||
at91rm9200_device = "rea_ecr";
|
||||
LOG_WARNING("No at91rm9200 device specified, using default 'rea_ecr'");
|
||||
}
|
||||
|
||||
while (cur_device->name)
|
||||
{
|
||||
if (strcmp(cur_device->name, at91rm9200_device) == 0)
|
||||
{
|
||||
device = cur_device;
|
||||
break;
|
||||
}
|
||||
cur_device++;
|
||||
}
|
||||
|
||||
if (!device)
|
||||
{
|
||||
LOG_ERROR("No matching device found for %s", at91rm9200_device);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
bitbang_interface = &at91rm9200_bitbang;
|
||||
|
||||
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (dev_mem_fd < 0) {
|
||||
perror("open");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
sys_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, dev_mem_fd, AT91C_BASE_SYS);
|
||||
if (sys_controller == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(dev_mem_fd);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
pio_base = (uint32_t*)sys_controller + 0x100;
|
||||
|
||||
/*
|
||||
* Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
|
||||
* as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
|
||||
*/
|
||||
pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK;
|
||||
pio_base[device->TDI_PIO + PIO_OER] = device->TDI_MASK;
|
||||
pio_base[device->TDI_PIO + PIO_PER] = device->TDI_MASK;
|
||||
pio_base[device->TCK_PIO + PIO_CODR] = device->TCK_MASK;
|
||||
pio_base[device->TCK_PIO + PIO_OER] = device->TCK_MASK;
|
||||
pio_base[device->TCK_PIO + PIO_PER] = device->TCK_MASK;
|
||||
pio_base[device->TMS_PIO + PIO_SODR] = device->TMS_MASK;
|
||||
pio_base[device->TMS_PIO + PIO_OER] = device->TMS_MASK;
|
||||
pio_base[device->TMS_PIO + PIO_PER] = device->TMS_MASK;
|
||||
pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK;
|
||||
pio_base[device->TRST_PIO + PIO_OER] = device->TRST_MASK;
|
||||
pio_base[device->TRST_PIO + PIO_PER] = device->TRST_MASK;
|
||||
pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK;
|
||||
pio_base[device->SRST_PIO + PIO_OER] = device->SRST_MASK;
|
||||
pio_base[device->SRST_PIO + PIO_PER] = device->SRST_MASK;
|
||||
pio_base[device->TDO_PIO + PIO_ODR] = device->TDO_MASK;
|
||||
pio_base[device->TDO_PIO + PIO_PPUER] = device->TDO_MASK;
|
||||
pio_base[device->TDO_PIO + PIO_PER] = device->TDO_MASK;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int at91rm9200_quit(void)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
325
src/jtag/drivers/bitbang.c
Normal file
325
src/jtag/drivers/bitbang.c
Normal file
@@ -0,0 +1,325 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "bitbang.h"
|
||||
#include "interface.h"
|
||||
#include "commands.h"
|
||||
|
||||
/**
|
||||
* Function bitbang_stableclocks
|
||||
* issues a number of clock cycles while staying in a stable state.
|
||||
* Because the TMS value required to stay in the RESET state is a 1, whereas
|
||||
* the TMS value required to stay in any of the other stable states is a 0,
|
||||
* this function checks the current stable state to decide on the value of TMS
|
||||
* to use.
|
||||
*/
|
||||
static void bitbang_stableclocks(int num_cycles);
|
||||
|
||||
|
||||
struct bitbang_interface *bitbang_interface;
|
||||
|
||||
/* DANGER!!!! clock absolutely *MUST* be 0 in idle or reset won't work!
|
||||
*
|
||||
* Set this to 1 and str912 reset halt will fail.
|
||||
*
|
||||
* If someone can submit a patch with an explanation it will be greatly
|
||||
* appreciated, but as far as I can tell (ØH) DCLK is generated upon
|
||||
* clk = 0 in TAP_IDLE. Good luck deducing that from the ARM documentation!
|
||||
* The ARM documentation uses the term "DCLK is asserted while in the TAP_IDLE
|
||||
* state". With hardware there is no such thing as *while* in a state. There
|
||||
* are only edges. So clk => 0 is in fact a very subtle state transition that
|
||||
* happens *while* in the TAP_IDLE state. "#&¤"#¤&"#&"#&
|
||||
*
|
||||
* For "reset halt" the last thing that happens before srst is asserted
|
||||
* is that the breakpoint is set up. If DCLK is not wiggled one last
|
||||
* time before the reset, then the breakpoint is not set up and
|
||||
* "reset halt" will fail to halt.
|
||||
*
|
||||
*/
|
||||
#define CLOCK_IDLE() 0
|
||||
|
||||
|
||||
/* The bitbang driver leaves the TCK 0 when in idle */
|
||||
static void bitbang_end_state(tap_state_t state)
|
||||
{
|
||||
if (tap_is_state_stable(state))
|
||||
tap_set_end_state(state);
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %i is not a valid end state", state);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void bitbang_state_move(int skip)
|
||||
{
|
||||
int i = 0, tms = 0;
|
||||
uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
|
||||
int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
|
||||
|
||||
for (i = skip; i < tms_count; i++)
|
||||
{
|
||||
tms = (tms_scan >> i) & 1;
|
||||
bitbang_interface->write(0, tms, 0);
|
||||
bitbang_interface->write(1, tms, 0);
|
||||
}
|
||||
bitbang_interface->write(CLOCK_IDLE(), tms, 0);
|
||||
|
||||
tap_set_state(tap_get_end_state());
|
||||
}
|
||||
|
||||
static void bitbang_path_move(struct pathmove_command *cmd)
|
||||
{
|
||||
int num_states = cmd->num_states;
|
||||
int state_count;
|
||||
int tms = 0;
|
||||
|
||||
state_count = 0;
|
||||
while (num_states)
|
||||
{
|
||||
if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count])
|
||||
{
|
||||
tms = 0;
|
||||
}
|
||||
else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count])
|
||||
{
|
||||
tms = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count]));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
bitbang_interface->write(0, tms, 0);
|
||||
bitbang_interface->write(1, tms, 0);
|
||||
|
||||
tap_set_state(cmd->path[state_count]);
|
||||
state_count++;
|
||||
num_states--;
|
||||
}
|
||||
|
||||
bitbang_interface->write(CLOCK_IDLE(), tms, 0);
|
||||
|
||||
tap_set_end_state(tap_get_state());
|
||||
}
|
||||
|
||||
static void bitbang_runtest(int num_cycles)
|
||||
{
|
||||
int i;
|
||||
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
|
||||
/* only do a state_move when we're not already in IDLE */
|
||||
if (tap_get_state() != TAP_IDLE)
|
||||
{
|
||||
bitbang_end_state(TAP_IDLE);
|
||||
bitbang_state_move(0);
|
||||
}
|
||||
|
||||
/* execute num_cycles */
|
||||
for (i = 0; i < num_cycles; i++)
|
||||
{
|
||||
bitbang_interface->write(0, 0, 0);
|
||||
bitbang_interface->write(1, 0, 0);
|
||||
}
|
||||
bitbang_interface->write(CLOCK_IDLE(), 0, 0);
|
||||
|
||||
/* finish in end_state */
|
||||
bitbang_end_state(saved_end_state);
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
bitbang_state_move(0);
|
||||
}
|
||||
|
||||
|
||||
static void bitbang_stableclocks(int num_cycles)
|
||||
{
|
||||
int tms = (tap_get_state() == TAP_RESET ? 1 : 0);
|
||||
int i;
|
||||
|
||||
/* send num_cycles clocks onto the cable */
|
||||
for (i = 0; i < num_cycles; i++)
|
||||
{
|
||||
bitbang_interface->write(1, tms, 0);
|
||||
bitbang_interface->write(0, tms, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
|
||||
{
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
int bit_cnt;
|
||||
|
||||
if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT))))
|
||||
{
|
||||
if (ir_scan)
|
||||
bitbang_end_state(TAP_IRSHIFT);
|
||||
else
|
||||
bitbang_end_state(TAP_DRSHIFT);
|
||||
|
||||
bitbang_state_move(0);
|
||||
bitbang_end_state(saved_end_state);
|
||||
}
|
||||
|
||||
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++)
|
||||
{
|
||||
int val = 0;
|
||||
int tms = (bit_cnt == scan_size-1) ? 1 : 0;
|
||||
int tdi;
|
||||
int bytec = bit_cnt/8;
|
||||
int bcval = 1 << (bit_cnt % 8);
|
||||
|
||||
/* if we're just reading the scan, but don't care about the output
|
||||
* default to outputting 'low', this also makes valgrind traces more readable,
|
||||
* as it removes the dependency on an uninitialised value
|
||||
*/
|
||||
tdi = 0;
|
||||
if ((type != SCAN_IN) && (buffer[bytec] & bcval))
|
||||
tdi = 1;
|
||||
|
||||
bitbang_interface->write(0, tms, tdi);
|
||||
|
||||
if (type != SCAN_OUT)
|
||||
val = bitbang_interface->read();
|
||||
|
||||
bitbang_interface->write(1, tms, tdi);
|
||||
|
||||
if (type != SCAN_OUT)
|
||||
{
|
||||
if (val)
|
||||
buffer[bytec] |= bcval;
|
||||
else
|
||||
buffer[bytec] &= ~bcval;
|
||||
}
|
||||
}
|
||||
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
{
|
||||
/* we *KNOW* the above loop transitioned out of
|
||||
* the shift state, so we skip the first state
|
||||
* and move directly to the end state.
|
||||
*/
|
||||
bitbang_state_move(1);
|
||||
}
|
||||
}
|
||||
|
||||
int bitbang_execute_queue(void)
|
||||
{
|
||||
struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
|
||||
int scan_size;
|
||||
enum scan_type type;
|
||||
uint8_t *buffer;
|
||||
int retval;
|
||||
|
||||
if (!bitbang_interface)
|
||||
{
|
||||
LOG_ERROR("BUG: Bitbang interface called, but not yet initialized");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* return ERROR_OK, unless a jtag_read_buffer returns a failed check
|
||||
* that wasn't handled by a caller-provided error handler
|
||||
*/
|
||||
retval = ERROR_OK;
|
||||
|
||||
if (bitbang_interface->blink)
|
||||
bitbang_interface->blink(1);
|
||||
|
||||
while (cmd)
|
||||
{
|
||||
switch (cmd->type)
|
||||
{
|
||||
case JTAG_RESET:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
#endif
|
||||
if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
|
||||
{
|
||||
tap_set_state(TAP_RESET);
|
||||
}
|
||||
bitbang_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
break;
|
||||
case JTAG_RUNTEST:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state));
|
||||
#endif
|
||||
bitbang_end_state(cmd->cmd.runtest->end_state);
|
||||
bitbang_runtest(cmd->cmd.runtest->num_cycles);
|
||||
break;
|
||||
|
||||
case JTAG_STABLECLOCKS:
|
||||
/* this is only allowed while in a stable state. A check for a stable
|
||||
* state was done in jtag_add_clocks()
|
||||
*/
|
||||
bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles);
|
||||
break;
|
||||
|
||||
case JTAG_STATEMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state));
|
||||
#endif
|
||||
bitbang_end_state(cmd->cmd.statemove->end_state);
|
||||
bitbang_state_move(0);
|
||||
break;
|
||||
case JTAG_PATHMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states,
|
||||
tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
|
||||
#endif
|
||||
bitbang_path_move(cmd->cmd.pathmove);
|
||||
break;
|
||||
case JTAG_SCAN:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", tap_state_name(cmd->cmd.scan->end_state));
|
||||
#endif
|
||||
bitbang_end_state(cmd->cmd.scan->end_state);
|
||||
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
|
||||
retval = ERROR_JTAG_QUEUE_FAILED;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("sleep %" PRIi32, cmd->cmd.sleep->us);
|
||||
#endif
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
if (bitbang_interface->blink)
|
||||
bitbang_interface->blink(0);
|
||||
|
||||
return retval;
|
||||
}
|
||||
39
src/jtag/drivers/bitbang.h
Normal file
39
src/jtag/drivers/bitbang.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef BITBANG_H
|
||||
#define BITBANG_H
|
||||
|
||||
struct bitbang_interface {
|
||||
/* low level callbacks (for bitbang)
|
||||
*/
|
||||
int (*read)(void);
|
||||
void (*write)(int tck, int tms, int tdi);
|
||||
void (*reset)(int trst, int srst);
|
||||
void (*blink)(int on);
|
||||
};
|
||||
|
||||
int bitbang_execute_queue(void);
|
||||
|
||||
extern struct bitbang_interface *bitbang_interface;
|
||||
|
||||
#endif /* BITBANG_H */
|
||||
397
src/jtag/drivers/bitq.c
Normal file
397
src/jtag/drivers/bitq.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Pavel Chromy *
|
||||
* chromy@asix.cz *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "bitq.h"
|
||||
#include "interface.h"
|
||||
|
||||
|
||||
struct bitq_interface* bitq_interface; /* low level bit queue interface */
|
||||
|
||||
/* state of input queue */
|
||||
struct bitq_state {
|
||||
struct jtag_command *cmd; /* command currently processed */
|
||||
int field_idx; /* index of field currently being processed */
|
||||
int bit_pos; /* position of bit curently being processed */
|
||||
int status; /* processing status */
|
||||
};
|
||||
static struct bitq_state bitq_in_state;
|
||||
|
||||
static uint8_t* bitq_in_buffer; /* buffer dynamically reallocated as needed */
|
||||
static int bitq_in_bufsize = 32; /* min. buffer size */
|
||||
|
||||
/*
|
||||
* input queue processing does not use jtag_read_buffer() to avoid unnecessary overhead
|
||||
* also the buffer for incomming data is reallocated only if necessary
|
||||
* no parameters, makes use of stored state information
|
||||
*/
|
||||
void bitq_in_proc(void)
|
||||
{
|
||||
/* static information preserved between calls to increase performance */
|
||||
static uint8_t* in_buff; /* pointer to buffer for scanned data */
|
||||
static int in_idx; /* index of byte being scanned */
|
||||
static uint8_t in_mask; /* mask of next bit to be scanned */
|
||||
|
||||
struct scan_field* field;
|
||||
int tdo;
|
||||
|
||||
/* loop through the queue */
|
||||
while (bitq_in_state.cmd)
|
||||
{
|
||||
/* only JTAG_SCAN command may return data */
|
||||
if (bitq_in_state.cmd->type == JTAG_SCAN)
|
||||
{
|
||||
/* loop through the fields */
|
||||
while (bitq_in_state.field_idx < bitq_in_state.cmd->cmd.scan->num_fields)
|
||||
{
|
||||
field = &bitq_in_state.cmd->cmd.scan->fields[bitq_in_state.field_idx];
|
||||
if (field->in_value)
|
||||
{
|
||||
if (bitq_in_state.bit_pos == 0)
|
||||
{
|
||||
/* initialize field scanning */
|
||||
in_mask = 0x01;
|
||||
in_idx = 0;
|
||||
if (field->in_value)
|
||||
in_buff = field->in_value;
|
||||
else
|
||||
{
|
||||
/* buffer reallocation needed? */
|
||||
if (field->num_bits > bitq_in_bufsize * 8)
|
||||
{
|
||||
/* buffer previously allocated? */
|
||||
if (bitq_in_buffer != NULL)
|
||||
{
|
||||
/* free it */
|
||||
free(bitq_in_buffer);
|
||||
bitq_in_buffer = NULL;
|
||||
}
|
||||
/* double the buffer size until it fits */
|
||||
while (field->num_bits > bitq_in_bufsize * 8)
|
||||
bitq_in_bufsize *= 2;
|
||||
}
|
||||
/* if necessary, allocate buffer and check for malloc error */
|
||||
if (bitq_in_buffer == NULL && (bitq_in_buffer = malloc(bitq_in_bufsize)) == NULL)
|
||||
{
|
||||
LOG_ERROR("malloc error");
|
||||
exit(-1);
|
||||
}
|
||||
in_buff = (void*) bitq_in_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* field scanning */
|
||||
while (bitq_in_state.bit_pos < field->num_bits)
|
||||
{
|
||||
if ((tdo = bitq_interface->in()) < 0)
|
||||
{
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("bitq in EOF");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (in_mask == 0x01)
|
||||
in_buff[in_idx] = 0;
|
||||
if (tdo)
|
||||
in_buff[in_idx] |= in_mask;
|
||||
if (in_mask == 0x80)
|
||||
{
|
||||
in_mask = 0x01;
|
||||
in_idx++;
|
||||
}
|
||||
else
|
||||
in_mask <<= 1;
|
||||
bitq_in_state.bit_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
bitq_in_state.field_idx++; /* advance to next field */
|
||||
bitq_in_state.bit_pos = 0; /* start next field from the first bit */
|
||||
}
|
||||
}
|
||||
bitq_in_state.cmd = bitq_in_state.cmd->next; /* advance to next command */
|
||||
bitq_in_state.field_idx = 0; /* preselect first field */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bitq_io(int tms, int tdi, int tdo_req)
|
||||
{
|
||||
bitq_interface->out(tms, tdi, tdo_req);
|
||||
/* check and process the input queue */
|
||||
if (bitq_interface->in_rdy())
|
||||
bitq_in_proc();
|
||||
}
|
||||
|
||||
|
||||
void bitq_end_state(tap_state_t state)
|
||||
{
|
||||
if (!tap_is_state_stable(state))
|
||||
{
|
||||
LOG_ERROR("BUG: %i is not a valid end state", state);
|
||||
exit(-1);
|
||||
}
|
||||
tap_set_end_state(state);
|
||||
}
|
||||
|
||||
|
||||
void bitq_state_move(tap_state_t new_state)
|
||||
{
|
||||
int i = 0;
|
||||
uint8_t tms_scan;
|
||||
|
||||
if (!tap_is_state_stable(tap_get_state()) || !tap_is_state_stable(new_state))
|
||||
{
|
||||
LOG_ERROR("TAP move from or to unstable state");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tms_scan = tap_get_tms_path(tap_get_state(), new_state);
|
||||
int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
|
||||
|
||||
for (i = 0; i < tms_count; i++)
|
||||
{
|
||||
bitq_io(tms_scan & 1, 0, 0);
|
||||
tms_scan >>= 1;
|
||||
}
|
||||
|
||||
tap_set_state(new_state);
|
||||
}
|
||||
|
||||
|
||||
void bitq_path_move(struct pathmove_command* cmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= cmd->num_states; i++)
|
||||
{
|
||||
if (tap_state_transition(tap_get_state(), false) == cmd->path[i])
|
||||
bitq_io(0, 0, 0);
|
||||
else if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
|
||||
bitq_io(1, 0, 0);
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(
|
||||
tap_get_state()), tap_state_name(cmd->path[i]));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tap_set_state(cmd->path[i]);
|
||||
}
|
||||
|
||||
tap_set_end_state(tap_get_state());
|
||||
}
|
||||
|
||||
|
||||
void bitq_runtest(int num_cycles)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* only do a state_move when we're not already in IDLE */
|
||||
if (tap_get_state() != TAP_IDLE)
|
||||
bitq_state_move(TAP_IDLE);
|
||||
|
||||
/* execute num_cycles */
|
||||
for (i = 0; i < num_cycles; i++)
|
||||
bitq_io(0, 0, 0);
|
||||
|
||||
/* finish in end_state */
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
bitq_state_move(tap_get_end_state());
|
||||
}
|
||||
|
||||
|
||||
void bitq_scan_field(struct scan_field* field, int pause)
|
||||
{
|
||||
int bit_cnt;
|
||||
int tdo_req;
|
||||
|
||||
uint8_t* out_ptr;
|
||||
uint8_t out_mask;
|
||||
|
||||
if (field->in_value)
|
||||
tdo_req = 1;
|
||||
else
|
||||
tdo_req = 0;
|
||||
|
||||
if (field->out_value == NULL)
|
||||
{
|
||||
/* just send zeros and request data from TDO */
|
||||
for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--)
|
||||
bitq_io(0, 0, tdo_req);
|
||||
|
||||
bitq_io(pause, 0, tdo_req);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send data, and optionally request TDO */
|
||||
out_mask = 0x01;
|
||||
out_ptr = field->out_value;
|
||||
for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--)
|
||||
{
|
||||
bitq_io(0, ((*out_ptr) & out_mask) != 0, tdo_req);
|
||||
if (out_mask == 0x80)
|
||||
{
|
||||
out_mask = 0x01;
|
||||
out_ptr++;
|
||||
}
|
||||
else
|
||||
out_mask <<= 1;
|
||||
}
|
||||
|
||||
bitq_io(pause, ((*out_ptr) & out_mask) != 0, tdo_req);
|
||||
}
|
||||
|
||||
if (pause)
|
||||
{
|
||||
bitq_io(0, 0, 0);
|
||||
if (tap_get_state() == TAP_IRSHIFT)
|
||||
tap_set_state(TAP_IRPAUSE);
|
||||
else if (tap_get_state() == TAP_DRSHIFT)
|
||||
tap_set_state(TAP_DRPAUSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bitq_scan(struct scan_command* cmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cmd->ir_scan)
|
||||
bitq_state_move(TAP_IRSHIFT);
|
||||
else
|
||||
bitq_state_move(TAP_DRSHIFT);
|
||||
|
||||
for (i = 0; i < cmd->num_fields - 1; i++)
|
||||
bitq_scan_field(&cmd->fields[i], 0);
|
||||
|
||||
bitq_scan_field(&cmd->fields[i], 1);
|
||||
}
|
||||
|
||||
|
||||
int bitq_execute_queue(void)
|
||||
{
|
||||
struct jtag_command* cmd = jtag_command_queue; /* currently processed command */
|
||||
|
||||
bitq_in_state.cmd = jtag_command_queue;
|
||||
bitq_in_state.field_idx = 0;
|
||||
bitq_in_state.bit_pos = 0;
|
||||
bitq_in_state.status = ERROR_OK;
|
||||
|
||||
while (cmd)
|
||||
{
|
||||
switch (cmd->type)
|
||||
{
|
||||
case JTAG_RESET:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
#endif
|
||||
if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
|
||||
{
|
||||
tap_set_state(TAP_RESET);
|
||||
}
|
||||
bitq_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
if (bitq_interface->in_rdy())
|
||||
bitq_in_proc();
|
||||
break;
|
||||
|
||||
case JTAG_RUNTEST:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
|
||||
#endif
|
||||
bitq_end_state(cmd->cmd.runtest->end_state);
|
||||
bitq_runtest(cmd->cmd.runtest->num_cycles);
|
||||
break;
|
||||
|
||||
case JTAG_STATEMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
|
||||
#endif
|
||||
bitq_end_state(cmd->cmd.statemove->end_state);
|
||||
bitq_state_move(tap_get_end_state()); /* uncoditional TAP move */
|
||||
break;
|
||||
|
||||
case JTAG_PATHMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states,
|
||||
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
|
||||
#endif
|
||||
bitq_path_move(cmd->cmd.pathmove);
|
||||
break;
|
||||
|
||||
case JTAG_SCAN:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("scan end in %i", cmd->cmd.scan->end_state);
|
||||
if (cmd->cmd.scan->ir_scan)
|
||||
LOG_DEBUG("scan ir");
|
||||
else
|
||||
LOG_DEBUG("scan dr");
|
||||
#endif
|
||||
bitq_end_state(cmd->cmd.scan->end_state);
|
||||
bitq_scan(cmd->cmd.scan);
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
bitq_state_move(tap_get_end_state());
|
||||
break;
|
||||
|
||||
case JTAG_SLEEP:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("sleep %i", cmd->cmd.sleep->us);
|
||||
#endif
|
||||
bitq_interface->sleep(cmd->cmd.sleep->us);
|
||||
if (bitq_interface->in_rdy())
|
||||
bitq_in_proc();
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
bitq_interface->flush();
|
||||
bitq_in_proc();
|
||||
|
||||
if (bitq_in_state.cmd)
|
||||
{
|
||||
LOG_ERROR("missing data from bitq interface");
|
||||
return ERROR_JTAG_QUEUE_FAILED;
|
||||
}
|
||||
if (bitq_interface->in() >= 0)
|
||||
{
|
||||
LOG_ERROR("extra data from bitq interface");
|
||||
return ERROR_JTAG_QUEUE_FAILED;
|
||||
}
|
||||
|
||||
return bitq_in_state.status;
|
||||
}
|
||||
|
||||
|
||||
void bitq_cleanup(void)
|
||||
{
|
||||
if (bitq_in_buffer != NULL)
|
||||
{
|
||||
free(bitq_in_buffer);
|
||||
bitq_in_buffer = NULL;
|
||||
}
|
||||
}
|
||||
46
src/jtag/drivers/bitq.h
Normal file
46
src/jtag/drivers/bitq.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Pavel Chromy *
|
||||
* chromy@asix.cz *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifndef BITQ_H
|
||||
#define BITQ_H
|
||||
|
||||
#include "commands.h"
|
||||
|
||||
struct bitq_interface {
|
||||
// function to enqueueing low level IO requests
|
||||
int (*out)(int tms, int tdi, int tdo_req);
|
||||
int (*flush)(void);
|
||||
|
||||
int (*sleep)(unsigned long us);
|
||||
int (*reset)(int trst, int srst);
|
||||
|
||||
/* delayed read of requested TDO data,
|
||||
* the input shall be checked after call to any enqueuing function
|
||||
*/
|
||||
int (*in_rdy)(void);
|
||||
int (*in)(void);
|
||||
};
|
||||
|
||||
extern struct bitq_interface *bitq_interface;
|
||||
|
||||
int bitq_execute_queue(void);
|
||||
|
||||
void bitq_cleanup(void);
|
||||
|
||||
#endif /* BITQ_H */
|
||||
527
src/jtag/drivers/driver.c
Normal file
527
src/jtag/drivers/driver.c
Normal file
@@ -0,0 +1,527 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2009 SoftPLC Corporation *
|
||||
* http://softplc.com *
|
||||
* dick@softplc.com *
|
||||
* *
|
||||
* Copyright (C) 2009 Zachary T Welch *
|
||||
* zw@superlucidity.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "minidriver.h"
|
||||
#include "command.h"
|
||||
|
||||
struct jtag_callback_entry
|
||||
{
|
||||
struct jtag_callback_entry *next;
|
||||
|
||||
jtag_callback_t callback;
|
||||
jtag_callback_data_t data0;
|
||||
jtag_callback_data_t data1;
|
||||
jtag_callback_data_t data2;
|
||||
jtag_callback_data_t data3;
|
||||
};
|
||||
|
||||
static struct jtag_callback_entry *jtag_callback_queue_head = NULL;
|
||||
static struct jtag_callback_entry *jtag_callback_queue_tail = NULL;
|
||||
|
||||
static void jtag_callback_queue_reset(void)
|
||||
{
|
||||
jtag_callback_queue_head = NULL;
|
||||
jtag_callback_queue_tail = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a struct scan_field for insertion into the queue.
|
||||
*
|
||||
* This allocates a new copy of out_value using cmd_queue_alloc.
|
||||
*/
|
||||
static void cmd_queue_scan_field_clone(struct scan_field * dst, const struct scan_field * src)
|
||||
{
|
||||
dst->tap = src->tap;
|
||||
dst->num_bits = src->num_bits;
|
||||
dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits);
|
||||
dst->in_value = src->in_value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* see jtag_add_ir_scan()
|
||||
*
|
||||
*/
|
||||
int interface_jtag_add_ir_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
|
||||
{
|
||||
size_t num_taps = jtag_tap_count_enabled();
|
||||
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
|
||||
struct scan_field * out_fields = cmd_queue_alloc(num_taps * sizeof(struct scan_field));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_SCAN;
|
||||
cmd->cmd.scan = scan;
|
||||
|
||||
scan->ir_scan = true;
|
||||
scan->num_fields = num_taps; /* one field per device */
|
||||
scan->fields = out_fields;
|
||||
scan->end_state = state;
|
||||
|
||||
|
||||
struct scan_field * field = out_fields; /* keep track where we insert data */
|
||||
|
||||
/* loop over all enabled TAPs */
|
||||
|
||||
for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
|
||||
{
|
||||
/* search the input field list for fields for the current TAP */
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (int j = 0; j < in_num_fields; j++)
|
||||
{
|
||||
if (tap != in_fields[j].tap)
|
||||
continue;
|
||||
|
||||
/* if TAP is listed in input fields, copy the value */
|
||||
|
||||
found = true;
|
||||
|
||||
tap->bypass = 0;
|
||||
|
||||
assert(in_fields[j].num_bits == tap->ir_length); /* input fields must have the same length as the TAP's IR */
|
||||
|
||||
cmd_queue_scan_field_clone(field, in_fields + j);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
/* if a TAP isn't listed in input fields, set it to BYPASS */
|
||||
|
||||
tap->bypass = 1;
|
||||
|
||||
field->tap = tap;
|
||||
field->num_bits = tap->ir_length;
|
||||
field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length);
|
||||
field->in_value = NULL; /* do not collect input for tap's in bypass */
|
||||
}
|
||||
|
||||
/* update device information */
|
||||
buf_cpy(field->out_value, tap->cur_instr, tap->ir_length);
|
||||
|
||||
field++;
|
||||
}
|
||||
|
||||
assert(field == out_fields + num_taps); /* paranoia: jtag_tap_count_enabled() and jtag_tap_next_enabled() not in sync */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* see jtag_add_plain_ir_scan()
|
||||
*
|
||||
*/
|
||||
int interface_jtag_add_plain_ir_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
|
||||
{
|
||||
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
|
||||
struct scan_field * out_fields = cmd_queue_alloc(in_num_fields * sizeof(struct scan_field));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_SCAN;
|
||||
cmd->cmd.scan = scan;
|
||||
|
||||
scan->ir_scan = true;
|
||||
scan->num_fields = in_num_fields;
|
||||
scan->fields = out_fields;
|
||||
scan->end_state = state;
|
||||
|
||||
for (int i = 0; i < in_num_fields; i++)
|
||||
cmd_queue_scan_field_clone(out_fields + i, in_fields + i);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* see jtag_add_dr_scan()
|
||||
*
|
||||
*/
|
||||
int interface_jtag_add_dr_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
|
||||
{
|
||||
/* count devices in bypass */
|
||||
|
||||
size_t bypass_devices = 0;
|
||||
|
||||
for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
|
||||
{
|
||||
if (tap->bypass)
|
||||
bypass_devices++;
|
||||
}
|
||||
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
|
||||
struct scan_field * out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_SCAN;
|
||||
cmd->cmd.scan = scan;
|
||||
|
||||
scan->ir_scan = false;
|
||||
scan->num_fields = in_num_fields + bypass_devices;
|
||||
scan->fields = out_fields;
|
||||
scan->end_state = state;
|
||||
|
||||
|
||||
struct scan_field * field = out_fields; /* keep track where we insert data */
|
||||
|
||||
/* loop over all enabled TAPs */
|
||||
|
||||
for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
|
||||
{
|
||||
/* if TAP is not bypassed insert matching input fields */
|
||||
|
||||
if (!tap->bypass)
|
||||
{
|
||||
struct scan_field * start_field = field; /* keep initial position for assert() */
|
||||
|
||||
for (int j = 0; j < in_num_fields; j++)
|
||||
{
|
||||
if (tap != in_fields[j].tap)
|
||||
continue;
|
||||
|
||||
cmd_queue_scan_field_clone(field, in_fields + j);
|
||||
|
||||
field++;
|
||||
}
|
||||
|
||||
assert(field > start_field); /* must have at least one input field per not bypassed TAP */
|
||||
}
|
||||
|
||||
/* if a TAP is bypassed, generated a dummy bit*/
|
||||
else
|
||||
{
|
||||
field->tap = tap;
|
||||
field->num_bits = 1;
|
||||
field->out_value = NULL;
|
||||
field->in_value = NULL;
|
||||
|
||||
field++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate a DR SCAN using the array of output values passed to the function
|
||||
*
|
||||
* This function assumes that the parameter target_tap specifies the one TAP
|
||||
* that is not bypassed. All other TAPs must be bypassed and the function will
|
||||
* generate a dummy 1bit field for them.
|
||||
*
|
||||
* For the target_tap a sequence of output-only fields will be generated where
|
||||
* each field has the size num_bits and the field's values are taken from
|
||||
* the array value.
|
||||
*
|
||||
* The bypass status of TAPs is set by jtag_add_ir_scan().
|
||||
*
|
||||
*/
|
||||
void interface_jtag_add_dr_out(struct jtag_tap *target_tap,
|
||||
int in_num_fields,
|
||||
const int *num_bits,
|
||||
const uint32_t *value,
|
||||
tap_state_t end_state)
|
||||
{
|
||||
/* count devices in bypass */
|
||||
|
||||
size_t bypass_devices = 0;
|
||||
|
||||
for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
|
||||
{
|
||||
if (tap->bypass)
|
||||
bypass_devices++;
|
||||
}
|
||||
|
||||
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
|
||||
struct scan_field * out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_SCAN;
|
||||
cmd->cmd.scan = scan;
|
||||
|
||||
scan->ir_scan = false;
|
||||
scan->num_fields = in_num_fields + bypass_devices;
|
||||
scan->fields = out_fields;
|
||||
scan->end_state = end_state;
|
||||
|
||||
|
||||
bool target_tap_match = false;
|
||||
|
||||
struct scan_field * field = out_fields; /* keep track where we insert data */
|
||||
|
||||
/* loop over all enabled TAPs */
|
||||
|
||||
for (struct jtag_tap * tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap))
|
||||
{
|
||||
/* if TAP is not bypassed insert matching input fields */
|
||||
|
||||
if (!tap->bypass)
|
||||
{
|
||||
assert(tap == target_tap); /* target_tap must match the one not bypassed TAP */
|
||||
|
||||
target_tap_match = true;
|
||||
|
||||
for (int j = 0; j < in_num_fields; j++)
|
||||
{
|
||||
uint8_t out_value[4];
|
||||
size_t scan_size = num_bits[j];
|
||||
buf_set_u32(out_value, 0, scan_size, value[j]);
|
||||
|
||||
field->tap = tap;
|
||||
field->num_bits = scan_size;
|
||||
field->out_value = buf_cpy(out_value, cmd_queue_alloc(DIV_ROUND_UP(scan_size, 8)), scan_size);
|
||||
field->in_value = NULL;
|
||||
|
||||
field++;
|
||||
}
|
||||
}
|
||||
|
||||
/* if a TAP is bypassed, generated a dummy bit*/
|
||||
else
|
||||
{
|
||||
|
||||
field->tap = tap;
|
||||
field->num_bits = 1;
|
||||
field->out_value = NULL;
|
||||
field->in_value = NULL;
|
||||
|
||||
field++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(target_tap_match); /* target_tap should be enabled and not bypassed */
|
||||
}
|
||||
|
||||
/**
|
||||
* see jtag_add_plain_dr_scan()
|
||||
*
|
||||
*/
|
||||
int interface_jtag_add_plain_dr_scan(int in_num_fields, const struct scan_field *in_fields, tap_state_t state)
|
||||
{
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
struct scan_command * scan = cmd_queue_alloc(sizeof(struct scan_command));
|
||||
struct scan_field * out_fields = cmd_queue_alloc(in_num_fields * sizeof(struct scan_field));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_SCAN;
|
||||
cmd->cmd.scan = scan;
|
||||
|
||||
scan->ir_scan = false;
|
||||
scan->num_fields = in_num_fields;
|
||||
scan->fields = out_fields;
|
||||
scan->end_state = state;
|
||||
|
||||
for (int i = 0; i < in_num_fields; i++)
|
||||
cmd_queue_scan_field_clone(out_fields + i, in_fields + i);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int interface_jtag_add_tlr(void)
|
||||
{
|
||||
tap_state_t state = TAP_RESET;
|
||||
|
||||
/* allocate memory for a new list member */
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_STATEMOVE;
|
||||
|
||||
cmd->cmd.statemove = cmd_queue_alloc(sizeof(struct statemove_command));
|
||||
cmd->cmd.statemove->end_state = state;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
|
||||
{
|
||||
/* allocate memory for a new list member */
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_PATHMOVE;
|
||||
|
||||
cmd->cmd.pathmove = cmd_queue_alloc(sizeof(struct pathmove_command));
|
||||
cmd->cmd.pathmove->num_states = num_states;
|
||||
cmd->cmd.pathmove->path = cmd_queue_alloc(sizeof(tap_state_t) * num_states);
|
||||
|
||||
for (int i = 0; i < num_states; i++)
|
||||
cmd->cmd.pathmove->path[i] = path[i];
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
|
||||
{
|
||||
/* allocate memory for a new list member */
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_RUNTEST;
|
||||
|
||||
cmd->cmd.runtest = cmd_queue_alloc(sizeof(struct runtest_command));
|
||||
cmd->cmd.runtest->num_cycles = num_cycles;
|
||||
cmd->cmd.runtest->end_state = state;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int interface_jtag_add_clocks(int num_cycles)
|
||||
{
|
||||
/* allocate memory for a new list member */
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_STABLECLOCKS;
|
||||
|
||||
cmd->cmd.stableclocks = cmd_queue_alloc(sizeof(struct stableclocks_command));
|
||||
cmd->cmd.stableclocks->num_cycles = num_cycles;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int interface_jtag_add_reset(int req_trst, int req_srst)
|
||||
{
|
||||
/* allocate memory for a new list member */
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_RESET;
|
||||
|
||||
cmd->cmd.reset = cmd_queue_alloc(sizeof(struct reset_command));
|
||||
cmd->cmd.reset->trst = req_trst;
|
||||
cmd->cmd.reset->srst = req_srst;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int interface_jtag_add_sleep(uint32_t us)
|
||||
{
|
||||
/* allocate memory for a new list member */
|
||||
struct jtag_command * cmd = cmd_queue_alloc(sizeof(struct jtag_command));
|
||||
|
||||
jtag_queue_command(cmd);
|
||||
|
||||
cmd->type = JTAG_SLEEP;
|
||||
|
||||
cmd->cmd.sleep = cmd_queue_alloc(sizeof(struct sleep_command));
|
||||
cmd->cmd.sleep->us = us;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* add callback to end of queue */
|
||||
void interface_jtag_add_callback4(jtag_callback_t callback, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
|
||||
{
|
||||
struct jtag_callback_entry *entry = cmd_queue_alloc(sizeof(struct jtag_callback_entry));
|
||||
|
||||
entry->next = NULL;
|
||||
entry->callback = callback;
|
||||
entry->data0 = data0;
|
||||
entry->data1 = data1;
|
||||
entry->data2 = data2;
|
||||
entry->data3 = data3;
|
||||
|
||||
if (jtag_callback_queue_head == NULL)
|
||||
{
|
||||
jtag_callback_queue_head = entry;
|
||||
jtag_callback_queue_tail = entry;
|
||||
} else
|
||||
{
|
||||
jtag_callback_queue_tail->next = entry;
|
||||
jtag_callback_queue_tail = entry;
|
||||
}
|
||||
}
|
||||
|
||||
int interface_jtag_execute_queue(void)
|
||||
{
|
||||
static int reentry = 0;
|
||||
|
||||
assert(reentry==0);
|
||||
reentry++;
|
||||
|
||||
int retval = default_interface_jtag_execute_queue();
|
||||
if (retval == ERROR_OK)
|
||||
{
|
||||
struct jtag_callback_entry *entry;
|
||||
for (entry = jtag_callback_queue_head; entry != NULL; entry = entry->next)
|
||||
{
|
||||
retval = entry->callback(entry->data0, entry->data1, entry->data2, entry->data3);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
jtag_command_queue_reset();
|
||||
jtag_callback_queue_reset();
|
||||
|
||||
reentry--;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int jtag_convert_to_callback4(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
|
||||
{
|
||||
((jtag_callback1_t)data1)(data0);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void interface_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0)
|
||||
{
|
||||
jtag_add_callback4(jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0);
|
||||
}
|
||||
|
||||
177
src/jtag/drivers/dummy.c
Normal file
177
src/jtag/drivers/dummy.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "bitbang.h"
|
||||
#include "../hello.h"
|
||||
|
||||
|
||||
/* my private tap controller state, which tracks state for calling code */
|
||||
static tap_state_t dummy_state = TAP_RESET;
|
||||
|
||||
static int dummy_clock; /* edge detector */
|
||||
|
||||
static int clock_count; /* count clocks in any stable state, only stable states */
|
||||
|
||||
static uint32_t dummy_data;
|
||||
|
||||
|
||||
static int dummy_read(void)
|
||||
{
|
||||
int data = 1 & dummy_data;
|
||||
dummy_data = (dummy_data >> 1) | (1 << 31);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
static void dummy_write(int tck, int tms, int tdi)
|
||||
{
|
||||
/* TAP standard: "state transitions occur on rising edge of clock" */
|
||||
if (tck != dummy_clock)
|
||||
{
|
||||
if (tck)
|
||||
{
|
||||
tap_state_t old_state = dummy_state;
|
||||
dummy_state = tap_state_transition(old_state, tms);
|
||||
|
||||
if (old_state != dummy_state)
|
||||
{
|
||||
if (clock_count)
|
||||
{
|
||||
LOG_DEBUG("dummy_tap: %d stable clocks", clock_count);
|
||||
clock_count = 0;
|
||||
}
|
||||
|
||||
LOG_DEBUG("dummy_tap: %s", tap_state_name(dummy_state));
|
||||
|
||||
#if defined(DEBUG)
|
||||
if (dummy_state == TAP_DRCAPTURE)
|
||||
dummy_data = 0x01255043;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this is a stable state clock edge, no change of state here,
|
||||
* simply increment clock_count for subsequent logging
|
||||
*/
|
||||
++clock_count;
|
||||
}
|
||||
}
|
||||
dummy_clock = tck;
|
||||
}
|
||||
}
|
||||
|
||||
static void dummy_reset(int trst, int srst)
|
||||
{
|
||||
dummy_clock = 0;
|
||||
|
||||
if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
|
||||
dummy_state = TAP_RESET;
|
||||
|
||||
LOG_DEBUG("reset to: %s", tap_state_name(dummy_state));
|
||||
}
|
||||
|
||||
static void dummy_led(int on)
|
||||
{
|
||||
}
|
||||
|
||||
static struct bitbang_interface dummy_bitbang = {
|
||||
.read = &dummy_read,
|
||||
.write = &dummy_write,
|
||||
.reset = &dummy_reset,
|
||||
.blink = &dummy_led,
|
||||
};
|
||||
|
||||
|
||||
static int dummy_khz(int khz, int *jtag_speed)
|
||||
{
|
||||
if (khz == 0)
|
||||
{
|
||||
*jtag_speed = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*jtag_speed = 64000/khz;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dummy_speed_div(int speed, int *khz)
|
||||
{
|
||||
if (speed == 0)
|
||||
{
|
||||
*khz = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*khz = 64000/speed;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dummy_speed(int speed)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dummy_init(void)
|
||||
{
|
||||
bitbang_interface = &dummy_bitbang;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dummy_quit(void)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration dummy_command_handlers[] = {
|
||||
{
|
||||
.name = "dummy",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "dummy interface driver commands",
|
||||
|
||||
.chain = hello_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE,
|
||||
};
|
||||
|
||||
/* The dummy driver is used to easily check the code path
|
||||
* where the target is unresponsive.
|
||||
*/
|
||||
struct jtag_interface dummy_interface = {
|
||||
.name = "dummy",
|
||||
|
||||
.commands = dummy_command_handlers,
|
||||
|
||||
.execute_queue = &bitbang_execute_queue,
|
||||
|
||||
.speed = &dummy_speed,
|
||||
.khz = &dummy_khz,
|
||||
.speed_div = &dummy_speed_div,
|
||||
|
||||
.init = &dummy_init,
|
||||
.quit = &dummy_quit,
|
||||
};
|
||||
230
src/jtag/drivers/ep93xx.c
Normal file
230
src/jtag/drivers/ep93xx.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "bitbang.h"
|
||||
|
||||
#define TDO_BIT 1
|
||||
#define TDI_BIT 2
|
||||
#define TCK_BIT 4
|
||||
#define TMS_BIT 8
|
||||
#define TRST_BIT 16
|
||||
#define SRST_BIT 32
|
||||
#define VCC_BIT 64
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
static uint8_t output_value = 0x0;
|
||||
static int dev_mem_fd;
|
||||
static void *gpio_controller;
|
||||
static volatile uint8_t *gpio_data_register;
|
||||
static volatile uint8_t *gpio_data_direction_register;
|
||||
|
||||
/* low level command set
|
||||
*/
|
||||
static int ep93xx_read(void);
|
||||
static void ep93xx_write(int tck, int tms, int tdi);
|
||||
static void ep93xx_reset(int trst, int srst);
|
||||
|
||||
static int ep93xx_speed(int speed);
|
||||
static int ep93xx_register_commands(struct command_context *cmd_ctx);
|
||||
static int ep93xx_init(void);
|
||||
static int ep93xx_quit(void);
|
||||
|
||||
struct timespec ep93xx_zzzz;
|
||||
|
||||
struct jtag_interface ep93xx_interface =
|
||||
{
|
||||
.name = "ep93xx",
|
||||
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
|
||||
.speed = ep93xx_speed,
|
||||
.register_commands = ep93xx_register_commands,
|
||||
.init = ep93xx_init,
|
||||
.quit = ep93xx_quit,
|
||||
};
|
||||
|
||||
static struct bitbang_interface ep93xx_bitbang =
|
||||
{
|
||||
.read = ep93xx_read,
|
||||
.write = ep93xx_write,
|
||||
.reset = ep93xx_reset,
|
||||
.blink = 0,
|
||||
};
|
||||
|
||||
static int ep93xx_read(void)
|
||||
{
|
||||
return !!(*gpio_data_register & TDO_BIT);
|
||||
}
|
||||
|
||||
static void ep93xx_write(int tck, int tms, int tdi)
|
||||
{
|
||||
if (tck)
|
||||
output_value |= TCK_BIT;
|
||||
else
|
||||
output_value &= ~TCK_BIT;
|
||||
|
||||
if (tms)
|
||||
output_value |= TMS_BIT;
|
||||
else
|
||||
output_value &= ~TMS_BIT;
|
||||
|
||||
if (tdi)
|
||||
output_value |= TDI_BIT;
|
||||
else
|
||||
output_value &= ~TDI_BIT;
|
||||
|
||||
*gpio_data_register = output_value;
|
||||
nanosleep(&ep93xx_zzzz, NULL);
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
static void ep93xx_reset(int trst, int srst)
|
||||
{
|
||||
if (trst == 0)
|
||||
output_value |= TRST_BIT;
|
||||
else if (trst == 1)
|
||||
output_value &= ~TRST_BIT;
|
||||
|
||||
if (srst == 0)
|
||||
output_value |= SRST_BIT;
|
||||
else if (srst == 1)
|
||||
output_value &= ~SRST_BIT;
|
||||
|
||||
*gpio_data_register = output_value;
|
||||
nanosleep(&ep93xx_zzzz, NULL);
|
||||
}
|
||||
|
||||
static int ep93xx_speed(int speed)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ep93xx_register_commands(struct command_context *cmd_ctx)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int set_gonk_mode(void)
|
||||
{
|
||||
void *syscon;
|
||||
uint32_t devicecfg;
|
||||
|
||||
syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, dev_mem_fd, 0x80930000);
|
||||
if (syscon == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
devicecfg = *((volatile int *)(syscon + 0x80));
|
||||
*((volatile int *)(syscon + 0xc0)) = 0xaa;
|
||||
*((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000;
|
||||
|
||||
munmap(syscon, 4096);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ep93xx_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bitbang_interface = &ep93xx_bitbang;
|
||||
|
||||
ep93xx_zzzz.tv_sec = 0;
|
||||
ep93xx_zzzz.tv_nsec = 10000000;
|
||||
|
||||
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (dev_mem_fd < 0) {
|
||||
perror("open");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, dev_mem_fd, 0x80840000);
|
||||
if (gpio_controller == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(dev_mem_fd);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
ret = set_gonk_mode();
|
||||
if (ret != ERROR_OK) {
|
||||
munmap(gpio_controller, 4096);
|
||||
close(dev_mem_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Use GPIO port A. */
|
||||
gpio_data_register = gpio_controller + 0x00;
|
||||
gpio_data_direction_register = gpio_controller + 0x10;
|
||||
|
||||
|
||||
/* Use GPIO port B. */
|
||||
gpio_data_register = gpio_controller + 0x04;
|
||||
gpio_data_direction_register = gpio_controller + 0x14;
|
||||
|
||||
/* Use GPIO port C. */
|
||||
gpio_data_register = gpio_controller + 0x08;
|
||||
gpio_data_direction_register = gpio_controller + 0x18;
|
||||
|
||||
/* Use GPIO port D. */
|
||||
gpio_data_register = gpio_controller + 0x0c;
|
||||
gpio_data_direction_register = gpio_controller + 0x1c;
|
||||
#endif
|
||||
|
||||
/* Use GPIO port C. */
|
||||
gpio_data_register = gpio_controller + 0x08;
|
||||
gpio_data_direction_register = gpio_controller + 0x18;
|
||||
|
||||
LOG_INFO("gpio_data_register = %p\n", gpio_data_register);
|
||||
LOG_INFO("gpio_data_direction_reg = %p\n", gpio_data_direction_register);
|
||||
/*
|
||||
* Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK
|
||||
* TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and
|
||||
* TMS/TRST/SRST high.
|
||||
*/
|
||||
output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
|
||||
*gpio_data_register = output_value;
|
||||
nanosleep(&ep93xx_zzzz, NULL);
|
||||
|
||||
/*
|
||||
* Configure the direction register. 1 = output, 0 = input.
|
||||
*/
|
||||
*gpio_data_direction_register =
|
||||
TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
|
||||
|
||||
nanosleep(&ep93xx_zzzz, NULL);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int ep93xx_quit(void)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
4021
src/jtag/drivers/ft2232.c
Normal file
4021
src/jtag/drivers/ft2232.c
Normal file
File diff suppressed because it is too large
Load Diff
583
src/jtag/drivers/gw16012.c
Normal file
583
src/jtag/drivers/gw16012.c
Normal file
@@ -0,0 +1,583 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "commands.h"
|
||||
|
||||
|
||||
#if 1
|
||||
#define _DEBUG_GW16012_IO_
|
||||
#endif
|
||||
|
||||
/* system includes */
|
||||
/* -ino: 060521-1036 */
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
#include <machine/sysarch.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#define ioperm(startport,length,enable)\
|
||||
i386_set_ioperm((startport), (length), (enable))
|
||||
|
||||
#else
|
||||
|
||||
#endif /* __FreeBSD__, __FreeBSD_kernel__ */
|
||||
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <dev/ppbus/ppi.h>
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#define PPRSTATUS PPIGSTATUS
|
||||
#define PPWDATA PPISDATA
|
||||
#else
|
||||
#include <linux/parport.h>
|
||||
#include <linux/ppdev.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#else /* not PARPORT_USE_PPDEV */
|
||||
#ifndef _WIN32
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* configuration */
|
||||
uint16_t gw16012_port;
|
||||
|
||||
/* interface variables
|
||||
*/
|
||||
static uint8_t gw16012_msb = 0x0;
|
||||
static uint8_t gw16012_control_value = 0x0;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
static int device_handle;
|
||||
#endif
|
||||
|
||||
static void gw16012_data(uint8_t value)
|
||||
{
|
||||
value = (value & 0x7f) | gw16012_msb;
|
||||
gw16012_msb ^= 0x80; /* toggle MSB */
|
||||
|
||||
#ifdef _DEBUG_GW16012_IO_
|
||||
LOG_DEBUG("%2.2x", value);
|
||||
#endif
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPWDATA, &value);
|
||||
#else
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
outb(gw16012_port, value);
|
||||
#else
|
||||
outb(value, gw16012_port);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gw16012_control(uint8_t value)
|
||||
{
|
||||
if (value != gw16012_control_value)
|
||||
{
|
||||
gw16012_control_value = value;
|
||||
|
||||
#ifdef _DEBUG_GW16012_IO_
|
||||
LOG_DEBUG("%2.2x", gw16012_control_value);
|
||||
#endif
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPWCONTROL, &gw16012_control_value);
|
||||
#else
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
outb(gw16012_port + 2, gw16012_control_value);
|
||||
#else
|
||||
outb(gw16012_control_value, gw16012_port + 2);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void gw16012_input(uint8_t *value)
|
||||
{
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPRSTATUS, value);
|
||||
#else
|
||||
*value = inb(gw16012_port + 1);
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG_GW16012_IO_
|
||||
LOG_DEBUG("%2.2x", *value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
static void gw16012_reset(int trst, int srst)
|
||||
{
|
||||
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
|
||||
|
||||
if (trst == 0)
|
||||
gw16012_control(0x0d);
|
||||
else if (trst == 1)
|
||||
gw16012_control(0x0c);
|
||||
|
||||
if (srst == 0)
|
||||
gw16012_control(0x0a);
|
||||
else if (srst == 1)
|
||||
gw16012_control(0x0b);
|
||||
}
|
||||
|
||||
static int gw16012_speed(int speed)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static void gw16012_end_state(tap_state_t state)
|
||||
{
|
||||
if (tap_is_state_stable(state))
|
||||
tap_set_end_state(state);
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %i is not a valid end state", state);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void gw16012_state_move(void)
|
||||
{
|
||||
int i = 0, tms = 0;
|
||||
uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
|
||||
int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
|
||||
|
||||
gw16012_control(0x0); /* single-bit mode */
|
||||
|
||||
for (i = 0; i < tms_count; i++)
|
||||
{
|
||||
tms = (tms_scan >> i) & 1;
|
||||
gw16012_data(tms << 1); /* output next TMS bit */
|
||||
}
|
||||
|
||||
tap_set_state(tap_get_end_state());
|
||||
}
|
||||
|
||||
static void gw16012_path_move(struct pathmove_command *cmd)
|
||||
{
|
||||
int num_states = cmd->num_states;
|
||||
int state_count;
|
||||
|
||||
state_count = 0;
|
||||
while (num_states)
|
||||
{
|
||||
gw16012_control(0x0); /* single-bit mode */
|
||||
if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count])
|
||||
{
|
||||
gw16012_data(0x0); /* TCK cycle with TMS low */
|
||||
}
|
||||
else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count])
|
||||
{
|
||||
gw16012_data(0x2); /* TCK cycle with TMS high */
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count]));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tap_set_state(cmd->path[state_count]);
|
||||
state_count++;
|
||||
num_states--;
|
||||
}
|
||||
|
||||
tap_set_end_state(tap_get_state());
|
||||
}
|
||||
|
||||
static void gw16012_runtest(int num_cycles)
|
||||
{
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
int i;
|
||||
|
||||
/* only do a state_move when we're not already in IDLE */
|
||||
if (tap_get_state() != TAP_IDLE)
|
||||
{
|
||||
gw16012_end_state(TAP_IDLE);
|
||||
gw16012_state_move();
|
||||
}
|
||||
|
||||
for (i = 0; i < num_cycles; i++)
|
||||
{
|
||||
gw16012_control(0x0); /* single-bit mode */
|
||||
gw16012_data(0x0); /* TMS cycle with TMS low */
|
||||
}
|
||||
|
||||
gw16012_end_state(saved_end_state);
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
gw16012_state_move();
|
||||
}
|
||||
|
||||
static void gw16012_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
|
||||
{
|
||||
int bits_left = scan_size;
|
||||
int bit_count = 0;
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
uint8_t scan_out, scan_in;
|
||||
|
||||
/* only if we're not already in the correct Shift state */
|
||||
if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT))))
|
||||
{
|
||||
if (ir_scan)
|
||||
gw16012_end_state(TAP_IRSHIFT);
|
||||
else
|
||||
gw16012_end_state(TAP_DRSHIFT);
|
||||
|
||||
gw16012_state_move();
|
||||
gw16012_end_state(saved_end_state);
|
||||
}
|
||||
|
||||
while (type == SCAN_OUT && ((bits_left - 1) > 7))
|
||||
{
|
||||
gw16012_control(0x2); /* seven-bit mode */
|
||||
scan_out = buf_get_u32(buffer, bit_count, 7);
|
||||
gw16012_data(scan_out);
|
||||
bit_count += 7;
|
||||
bits_left -= 7;
|
||||
}
|
||||
|
||||
gw16012_control(0x0); /* single-bit mode */
|
||||
while (bits_left-- > 0)
|
||||
{
|
||||
uint8_t tms = 0;
|
||||
|
||||
scan_out = buf_get_u32(buffer, bit_count, 1);
|
||||
|
||||
if (bits_left == 0) /* last bit */
|
||||
{
|
||||
if ((ir_scan && (tap_get_end_state() == TAP_IRSHIFT))
|
||||
|| (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT)))
|
||||
{
|
||||
tms = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tms = 2;
|
||||
}
|
||||
}
|
||||
|
||||
gw16012_data(scan_out | tms);
|
||||
|
||||
if (type != SCAN_OUT)
|
||||
{
|
||||
gw16012_input(&scan_in);
|
||||
buf_set_u32(buffer, bit_count, 1, ((scan_in & 0x08) >> 3));
|
||||
}
|
||||
|
||||
bit_count++;
|
||||
}
|
||||
|
||||
if (!((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) ||
|
||||
(!ir_scan && (tap_get_end_state() == TAP_DRSHIFT))))
|
||||
{
|
||||
gw16012_data(0x0);
|
||||
if (ir_scan)
|
||||
tap_set_state(TAP_IRPAUSE);
|
||||
else
|
||||
tap_set_state(TAP_DRPAUSE);
|
||||
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
gw16012_state_move();
|
||||
}
|
||||
}
|
||||
|
||||
static int gw16012_execute_queue(void)
|
||||
{
|
||||
struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
|
||||
int scan_size;
|
||||
enum scan_type type;
|
||||
uint8_t *buffer;
|
||||
int retval;
|
||||
|
||||
/* return ERROR_OK, unless a jtag_read_buffer returns a failed check
|
||||
* that wasn't handled by a caller-provided error handler
|
||||
*/
|
||||
retval = ERROR_OK;
|
||||
|
||||
while (cmd)
|
||||
{
|
||||
switch (cmd->type)
|
||||
{
|
||||
case JTAG_RESET:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
#endif
|
||||
if (cmd->cmd.reset->trst == 1)
|
||||
{
|
||||
tap_set_state(TAP_RESET);
|
||||
}
|
||||
gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
break;
|
||||
case JTAG_RUNTEST:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
|
||||
#endif
|
||||
gw16012_end_state(cmd->cmd.runtest->end_state);
|
||||
gw16012_runtest(cmd->cmd.runtest->num_cycles);
|
||||
break;
|
||||
case JTAG_STATEMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
|
||||
#endif
|
||||
gw16012_end_state(cmd->cmd.statemove->end_state);
|
||||
gw16012_state_move();
|
||||
break;
|
||||
case JTAG_PATHMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
|
||||
#endif
|
||||
gw16012_path_move(cmd->cmd.pathmove);
|
||||
break;
|
||||
case JTAG_SCAN:
|
||||
gw16012_end_state(cmd->cmd.scan->end_state);
|
||||
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr",
|
||||
type, scan_size, cmd->cmd.scan->end_state);
|
||||
#endif
|
||||
gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
|
||||
retval = ERROR_JTAG_QUEUE_FAILED;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("sleep %i", cmd->cmd.sleep->us);
|
||||
#endif
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
static int gw16012_get_giveio_access(void)
|
||||
{
|
||||
HANDLE h;
|
||||
OSVERSIONINFO version;
|
||||
|
||||
version.dwOSVersionInfoSize = sizeof version;
|
||||
if (!GetVersionEx(&version)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
||||
return 0;
|
||||
|
||||
h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
#define GW16012_PPDEV_NAME "ppi"
|
||||
|
||||
static int gw16012_init_ioctls(void)
|
||||
{
|
||||
int temp = 0;
|
||||
temp = ioctl(device_handle, PPCLAIM);
|
||||
if (temp < 0)
|
||||
{
|
||||
LOG_ERROR("cannot claim device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
temp = PARPORT_MODE_COMPAT;
|
||||
temp = ioctl(device_handle, PPSETMODE, &temp);
|
||||
if (temp < 0)
|
||||
{
|
||||
LOG_ERROR(" cannot set compatible mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
temp = IEEE1284_MODE_COMPAT;
|
||||
temp = ioctl(device_handle, PPNEGOT, &temp);
|
||||
if (temp < 0)
|
||||
{
|
||||
LOG_ERROR("cannot set compatible 1284 mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
#else
|
||||
|
||||
#define GW16012_PPDEV_NAME "parport"
|
||||
|
||||
static int gw16012_init_ioctls(void)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#endif // defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
static int gw16012_init_device(void)
|
||||
{
|
||||
const char *device_name = GW16012_PPDEV_NAME;
|
||||
char buffer[256];
|
||||
|
||||
if (device_handle > 0)
|
||||
{
|
||||
LOG_ERROR("device is already opened");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
snprintf(buffer, 256, "/dev/%s%d", device_name, gw16012_port);
|
||||
LOG_DEBUG("opening %s...", buffer);
|
||||
|
||||
device_handle = open(buffer, O_WRONLY);
|
||||
if (device_handle < 0)
|
||||
{
|
||||
LOG_ERROR("cannot open device. check it exists and that user read and write rights are set");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("...open");
|
||||
|
||||
if (gw16012_init_ioctls() != ERROR_OK)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#else // PARPORT_USE_PPDEV
|
||||
|
||||
static int gw16012_init_device(void)
|
||||
{
|
||||
if (gw16012_port == 0)
|
||||
{
|
||||
gw16012_port = 0x378;
|
||||
LOG_WARNING("No gw16012 port specified, using default '0x378' (LPT1)");
|
||||
}
|
||||
|
||||
LOG_DEBUG("requesting privileges for parallel port 0x%lx...", (long unsigned)(gw16012_port));
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
if (gw16012_get_giveio_access() != 0)
|
||||
#else /* PARPORT_USE_GIVEIO */
|
||||
if (ioperm(gw16012_port, 3, 1) != 0)
|
||||
#endif /* PARPORT_USE_GIVEIO */
|
||||
{
|
||||
LOG_ERROR("missing privileges for direct i/o");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
LOG_DEBUG("...privileges granted");
|
||||
|
||||
/* make sure parallel port is in right mode (clear tristate and interrupt */
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
outb(gw16012_port + 2, 0x0);
|
||||
#else
|
||||
outb(0x0, gw16012_port + 2);
|
||||
#endif
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#endif // PARPORT_USE_PPDEV
|
||||
|
||||
static int gw16012_init(void)
|
||||
{
|
||||
uint8_t status_port;
|
||||
|
||||
if (gw16012_init_device() != ERROR_OK)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
gw16012_input(&status_port);
|
||||
gw16012_msb = (status_port & 0x80) ^ 0x80;
|
||||
|
||||
gw16012_speed(jtag_get_speed());
|
||||
gw16012_reset(0, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int gw16012_quit(void)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(gw16012_handle_parport_port_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
{
|
||||
/* only if the port wasn't overwritten by cmdline */
|
||||
if (gw16012_port == 0)
|
||||
{
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], gw16012_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("The parport port was already configured!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "parport port = %u", gw16012_port);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration gw16012_command_handlers[] = {
|
||||
{
|
||||
.name = "parport_port",
|
||||
.handler = &gw16012_handle_parport_port_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "configure the parallel port to use",
|
||||
.usage = "<port_num>",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface gw16012_interface = {
|
||||
.name = "gw16012",
|
||||
.commands = gw16012_command_handlers,
|
||||
.init = &gw16012_init,
|
||||
.quit = &gw16012_quit,
|
||||
.speed = &gw16012_speed,
|
||||
.execute_queue = &gw16012_execute_queue,
|
||||
};
|
||||
1085
src/jtag/drivers/jlink.c
Normal file
1085
src/jtag/drivers/jlink.c
Normal file
File diff suppressed because it is too large
Load Diff
533
src/jtag/drivers/parport.c
Normal file
533
src/jtag/drivers/parport.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "bitbang.h"
|
||||
|
||||
/* -ino: 060521-1036 */
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <machine/sysarch.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#define ioperm(startport,length,enable)\
|
||||
i386_set_ioperm((startport), (length), (enable))
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <dev/ppbus/ppi.h>
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#define PPRSTATUS PPIGSTATUS
|
||||
#define PPWDATA PPISDATA
|
||||
#else
|
||||
#include <linux/parport.h>
|
||||
#include <linux/ppdev.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#else /* not PARPORT_USE_PPDEV */
|
||||
#ifndef _WIN32
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* parallel port cable description
|
||||
*/
|
||||
struct cable {
|
||||
char* name;
|
||||
uint8_t TDO_MASK; /* status port bit containing current TDO value */
|
||||
uint8_t TRST_MASK; /* data port bit for TRST */
|
||||
uint8_t TMS_MASK; /* data port bit for TMS */
|
||||
uint8_t TCK_MASK; /* data port bit for TCK */
|
||||
uint8_t TDI_MASK; /* data port bit for TDI */
|
||||
uint8_t SRST_MASK; /* data port bit for SRST */
|
||||
uint8_t OUTPUT_INVERT; /* data port bits that should be inverted */
|
||||
uint8_t INPUT_INVERT; /* status port that should be inverted */
|
||||
uint8_t PORT_INIT; /* initialize data port with this value */
|
||||
uint8_t PORT_EXIT; /* de-initialize data port with this value */
|
||||
uint8_t LED_MASK; /* data port bit for LED */
|
||||
};
|
||||
|
||||
static struct cable cables[] =
|
||||
{
|
||||
/* name tdo trst tms tck tdi srst o_inv i_inv init exit led */
|
||||
{ "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 },
|
||||
{ "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 },
|
||||
{ "wiggler_ntrst_inverted",
|
||||
0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 },
|
||||
{ "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 },
|
||||
{ "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 },
|
||||
{ "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
|
||||
{ "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 },
|
||||
{ "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
|
||||
{ "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 },
|
||||
{ "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 },
|
||||
/* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows:
|
||||
HARD TCK - Target TCK
|
||||
HARD TMS - Target TMS
|
||||
HARD TDI - Target TDI
|
||||
HARD TDO - Target TDO
|
||||
SOFT TCK - Target TRST
|
||||
SOFT TDI - Target SRST
|
||||
*/
|
||||
{ "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 },
|
||||
{ NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
/* configuration */
|
||||
static char* parport_cable = NULL;
|
||||
static uint16_t parport_port;
|
||||
static bool parport_exit = 0;
|
||||
static uint32_t parport_toggling_time_ns = 1000;
|
||||
static int wait_states;
|
||||
|
||||
/* interface variables
|
||||
*/
|
||||
static struct cable* cable;
|
||||
static uint8_t dataport_value = 0x0;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
static int device_handle;
|
||||
#else
|
||||
static unsigned long dataport;
|
||||
static unsigned long statusport;
|
||||
#endif
|
||||
|
||||
static int parport_read(void)
|
||||
{
|
||||
int data = 0;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPRSTATUS, & data);
|
||||
#else
|
||||
data = inb(statusport);
|
||||
#endif
|
||||
|
||||
if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline__ void parport_write_data(void)
|
||||
{
|
||||
uint8_t output;
|
||||
output = dataport_value ^ cable->OUTPUT_INVERT;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPWDATA, &output);
|
||||
#else
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
outb(dataport, output);
|
||||
#else
|
||||
outb(output, dataport);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parport_write(int tck, int tms, int tdi)
|
||||
{
|
||||
int i = wait_states + 1;
|
||||
|
||||
if (tck)
|
||||
dataport_value |= cable->TCK_MASK;
|
||||
else
|
||||
dataport_value &= ~cable->TCK_MASK;
|
||||
|
||||
if (tms)
|
||||
dataport_value |= cable->TMS_MASK;
|
||||
else
|
||||
dataport_value &= ~cable->TMS_MASK;
|
||||
|
||||
if (tdi)
|
||||
dataport_value |= cable->TDI_MASK;
|
||||
else
|
||||
dataport_value &= ~cable->TDI_MASK;
|
||||
|
||||
while (i-- > 0)
|
||||
parport_write_data();
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
static void parport_reset(int trst, int srst)
|
||||
{
|
||||
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
|
||||
|
||||
if (trst == 0)
|
||||
dataport_value |= cable->TRST_MASK;
|
||||
else if (trst == 1)
|
||||
dataport_value &= ~cable->TRST_MASK;
|
||||
|
||||
if (srst == 0)
|
||||
dataport_value |= cable->SRST_MASK;
|
||||
else if (srst == 1)
|
||||
dataport_value &= ~cable->SRST_MASK;
|
||||
|
||||
parport_write_data();
|
||||
}
|
||||
|
||||
/* turn LED on parport adapter on (1) or off (0) */
|
||||
static void parport_led(int on)
|
||||
{
|
||||
if (on)
|
||||
dataport_value |= cable->LED_MASK;
|
||||
else
|
||||
dataport_value &= ~cable->LED_MASK;
|
||||
|
||||
parport_write_data();
|
||||
}
|
||||
|
||||
static int parport_speed(int speed)
|
||||
{
|
||||
wait_states = speed;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int parport_khz(int khz, int* jtag_speed)
|
||||
{
|
||||
if (khz == 0) {
|
||||
LOG_DEBUG("RCLK not supported");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
*jtag_speed = 499999 / (khz * parport_toggling_time_ns);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int parport_speed_div(int speed, int* khz)
|
||||
{
|
||||
uint32_t denominator = (speed + 1) * parport_toggling_time_ns;
|
||||
|
||||
*khz = (499999 + denominator) / denominator;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
static int parport_get_giveio_access(void)
|
||||
{
|
||||
HANDLE h;
|
||||
OSVERSIONINFO version;
|
||||
|
||||
version.dwOSVersionInfoSize = sizeof version;
|
||||
if (!GetVersionEx(&version)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
||||
return 0;
|
||||
|
||||
h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct bitbang_interface parport_bitbang = {
|
||||
.read = &parport_read,
|
||||
.write = &parport_write,
|
||||
.reset = &parport_reset,
|
||||
.blink = &parport_led,
|
||||
};
|
||||
|
||||
static int parport_init(void)
|
||||
{
|
||||
struct cable *cur_cable;
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
char buffer[256];
|
||||
int i = 0;
|
||||
#endif
|
||||
|
||||
cur_cable = cables;
|
||||
|
||||
if ((parport_cable == NULL) || (parport_cable[0] == 0))
|
||||
{
|
||||
parport_cable = "wiggler";
|
||||
LOG_WARNING("No parport cable specified, using default 'wiggler'");
|
||||
}
|
||||
|
||||
while (cur_cable->name)
|
||||
{
|
||||
if (strcmp(cur_cable->name, parport_cable) == 0)
|
||||
{
|
||||
cable = cur_cable;
|
||||
break;
|
||||
}
|
||||
cur_cable++;
|
||||
}
|
||||
|
||||
if (!cable)
|
||||
{
|
||||
LOG_ERROR("No matching cable found for %s", parport_cable);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
dataport_value = cable->PORT_INIT;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
if (device_handle > 0)
|
||||
{
|
||||
LOG_ERROR("device is already opened");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
LOG_DEBUG("opening /dev/ppi%d...", parport_port);
|
||||
|
||||
snprintf(buffer, 256, "/dev/ppi%d", parport_port);
|
||||
device_handle = open(buffer, O_WRONLY);
|
||||
#else /* not __FreeBSD__, __FreeBSD_kernel__ */
|
||||
LOG_DEBUG("opening /dev/parport%d...", parport_port);
|
||||
|
||||
snprintf(buffer, 256, "/dev/parport%d", parport_port);
|
||||
device_handle = open(buffer, O_WRONLY);
|
||||
#endif /* __FreeBSD__, __FreeBSD_kernel__ */
|
||||
|
||||
if (device_handle < 0)
|
||||
{
|
||||
int err = errno;
|
||||
LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("...open");
|
||||
|
||||
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
|
||||
i = ioctl(device_handle, PPCLAIM);
|
||||
if (i < 0)
|
||||
{
|
||||
LOG_ERROR("cannot claim device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
i = PARPORT_MODE_COMPAT;
|
||||
i= ioctl(device_handle, PPSETMODE, & i);
|
||||
if (i < 0)
|
||||
{
|
||||
LOG_ERROR(" cannot set compatible mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
i = IEEE1284_MODE_COMPAT;
|
||||
i = ioctl(device_handle, PPNEGOT, & i);
|
||||
if (i < 0)
|
||||
{
|
||||
LOG_ERROR("cannot set compatible 1284 mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
#endif /* not __FreeBSD__, __FreeBSD_kernel__ */
|
||||
|
||||
#else /* not PARPORT_USE_PPDEV */
|
||||
if (parport_port == 0)
|
||||
{
|
||||
parport_port = 0x378;
|
||||
LOG_WARNING("No parport port specified, using default '0x378' (LPT1)");
|
||||
}
|
||||
|
||||
dataport = parport_port;
|
||||
statusport = parport_port + 1;
|
||||
|
||||
LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport);
|
||||
#if PARPORT_USE_GIVEIO == 1
|
||||
if (parport_get_giveio_access() != 0)
|
||||
#else /* PARPORT_USE_GIVEIO */
|
||||
if (ioperm(dataport, 3, 1) != 0)
|
||||
#endif /* PARPORT_USE_GIVEIO */
|
||||
{
|
||||
LOG_ERROR("missing privileges for direct i/o");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
LOG_DEBUG("...privileges granted");
|
||||
|
||||
/* make sure parallel port is in right mode (clear tristate and interrupt */
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
outb(parport_port + 2, 0x0);
|
||||
#else
|
||||
outb(0x0, parport_port + 2);
|
||||
#endif
|
||||
|
||||
#endif /* PARPORT_USE_PPDEV */
|
||||
|
||||
parport_reset(0, 0);
|
||||
parport_write(0, 0, 0);
|
||||
parport_led(1);
|
||||
|
||||
bitbang_interface = &parport_bitbang;
|
||||
|
||||
wait_states = jtag_get_speed();
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int parport_quit(void)
|
||||
{
|
||||
parport_led(0);
|
||||
|
||||
if (parport_exit)
|
||||
{
|
||||
dataport_value = cable->PORT_EXIT;
|
||||
parport_write_data();
|
||||
}
|
||||
|
||||
if (parport_cable)
|
||||
{
|
||||
free(parport_cable);
|
||||
parport_cable = NULL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(parport_handle_parport_port_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
{
|
||||
/* only if the port wasn't overwritten by cmdline */
|
||||
if (parport_port == 0)
|
||||
{
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("The parport port was already configured!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "parport port = %u", parport_port);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(parport_handle_parport_cable_command)
|
||||
{
|
||||
if (CMD_ARGC == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
/* only if the cable name wasn't overwritten by cmdline */
|
||||
if (parport_cable == 0)
|
||||
{
|
||||
parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char));
|
||||
strcpy(parport_cable, CMD_ARGV[0]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(parport_handle_write_on_exit_command)
|
||||
{
|
||||
if (CMD_ARGC != 1)
|
||||
{
|
||||
command_print(CMD_CTX, "usage: parport_write_on_exit <on | off>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(parport_handle_parport_toggling_time_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
uint32_t ns;
|
||||
int retval = parse_u32(CMD_ARGV[0], &ns);
|
||||
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if (ns == 0) {
|
||||
LOG_ERROR("0 ns is not a valid parport toggling time");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
parport_toggling_time_ns = ns;
|
||||
wait_states = jtag_get_speed();
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "parport toggling time = %" PRIu32 " ns",
|
||||
parport_toggling_time_ns);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration parport_command_handlers[] = {
|
||||
{
|
||||
.name = "parport_port",
|
||||
.handler = &parport_handle_parport_port_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "either the address of the I/O port "
|
||||
"or the number of the '/dev/parport' device",
|
||||
.usage = "[<port|devname>]",
|
||||
},
|
||||
{
|
||||
.name = "parport_cable",
|
||||
.handler = &parport_handle_parport_cable_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "the layout of the parallel port cable "
|
||||
"used to connect to the target",
|
||||
.usage = "[<layout>]",
|
||||
},
|
||||
{
|
||||
.name = "parport_write_on_exit",
|
||||
.handler = &parport_handle_write_on_exit_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "configure the parallel driver to write "
|
||||
"a known value to the parallel interface",
|
||||
.usage = "[<on|off>]",
|
||||
},
|
||||
{
|
||||
.name = "parport_toggling_time",
|
||||
.handler = &parport_handle_parport_toggling_time_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "time <ns> it takes for the hardware to toggle TCK",
|
||||
.usage = "[<ns>]",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct jtag_interface parport_interface = {
|
||||
.name = "parport",
|
||||
|
||||
.commands = parport_command_handlers,
|
||||
|
||||
.init = &parport_init,
|
||||
.quit = &parport_quit,
|
||||
|
||||
.khz = &parport_khz,
|
||||
.speed_div = &parport_speed_div,
|
||||
.speed = &parport_speed,
|
||||
|
||||
.execute_queue = &bitbang_execute_queue,
|
||||
};
|
||||
800
src/jtag/drivers/presto.c
Normal file
800
src/jtag/drivers/presto.c
Normal file
@@ -0,0 +1,800 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Pavel Chromy *
|
||||
* chromy@asix.cz *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if IS_CYGWIN == 1
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "time_support.h"
|
||||
#include "bitq.h"
|
||||
|
||||
|
||||
/* PRESTO access library includes */
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
#include <ftd2xx.h>
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
#include <ftdi.h>
|
||||
#else
|
||||
#error "BUG: either FTD2XX and LIBFTDI has to be used"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define FT_DEVICE_NAME_LEN 64
|
||||
#define FT_DEVICE_SERNUM_LEN 64
|
||||
|
||||
#define PRESTO_VID_PID 0x0403f1a0
|
||||
#define PRESTO_VID (0x0403)
|
||||
#define PRESTO_PID (0xf1a0)
|
||||
|
||||
#define BUFFER_SIZE (64*62)
|
||||
|
||||
struct presto {
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
FT_HANDLE handle;
|
||||
FT_STATUS status;
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
struct ftdi_context ftdic;
|
||||
int retval;
|
||||
#endif
|
||||
|
||||
char serial[FT_DEVICE_SERNUM_LEN];
|
||||
|
||||
uint8_t buff_out[BUFFER_SIZE];
|
||||
int buff_out_pos;
|
||||
|
||||
uint8_t buff_in[BUFFER_SIZE];
|
||||
int buff_in_exp; /* expected in buffer length */
|
||||
int buff_in_len; /* length of data received */
|
||||
int buff_in_pos;
|
||||
|
||||
unsigned long total_out;
|
||||
unsigned long total_in;
|
||||
|
||||
int jtag_tms; /* last tms state */
|
||||
int jtag_tck; /* last tck state */
|
||||
int jtag_rst; /* last trst state */
|
||||
|
||||
int jtag_tdi_data;
|
||||
int jtag_tdi_count;
|
||||
|
||||
int jtag_speed;
|
||||
};
|
||||
|
||||
static struct presto presto_state;
|
||||
static struct presto *presto = &presto_state;
|
||||
|
||||
static uint8_t presto_init_seq[] =
|
||||
{
|
||||
0x80, 0xA0, 0xA8, 0xB0, 0xC0, 0xE0
|
||||
};
|
||||
|
||||
static int presto_write(uint8_t *buf, uint32_t size)
|
||||
{
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
DWORD ftbytes;
|
||||
if ((presto->status = FT_Write(presto->handle, buf, size, &ftbytes)) != FT_OK)
|
||||
{
|
||||
LOG_ERROR("FT_Write returned: %lu", presto->status);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
uint32_t ftbytes;
|
||||
if ((presto->retval = ftdi_write_data(&presto->ftdic, buf, size)) < 0)
|
||||
{
|
||||
LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&presto->ftdic));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
ftbytes = presto->retval;
|
||||
#endif
|
||||
|
||||
if (ftbytes != size)
|
||||
{
|
||||
LOG_ERROR("couldn't write the requested number of bytes to PRESTO (%u < %u)",
|
||||
(unsigned)ftbytes, (unsigned)size);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int presto_read(uint8_t* buf, uint32_t size)
|
||||
{
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
DWORD ftbytes;
|
||||
if ((presto->status = FT_Read(presto->handle, buf, size, &ftbytes)) != FT_OK)
|
||||
{
|
||||
LOG_ERROR("FT_Read returned: %lu", presto->status);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
uint32_t ftbytes = 0;
|
||||
|
||||
struct timeval timeout, now;
|
||||
gettimeofday(&timeout, NULL);
|
||||
timeval_add_time(&timeout, 1, 0); /* one second timeout */
|
||||
|
||||
while (ftbytes < size)
|
||||
{
|
||||
if ((presto->retval = ftdi_read_data(&presto->ftdic, buf + ftbytes, size - ftbytes)) < 0)
|
||||
{
|
||||
LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&presto->ftdic));
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
ftbytes += presto->retval;
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec)))
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ftbytes != size)
|
||||
{
|
||||
/* this is just a warning, there might have been timeout when detecting PRESTO, which is not fatal */
|
||||
LOG_WARNING("couldn't read the requested number of bytes from PRESTO (%u < %u)",
|
||||
(unsigned)ftbytes, (unsigned)size);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
static int presto_open_ftd2xx(char *req_serial)
|
||||
{
|
||||
uint32_t i;
|
||||
DWORD numdevs;
|
||||
DWORD vidpid;
|
||||
char devname[FT_DEVICE_NAME_LEN];
|
||||
FT_DEVICE device;
|
||||
|
||||
BYTE presto_data;
|
||||
DWORD ftbytes;
|
||||
|
||||
presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE;
|
||||
|
||||
#if IS_WIN32 == 0
|
||||
/* Add non-standard Vid/Pid to the linux driver */
|
||||
if ((presto->status = FT_SetVIDPID(PRESTO_VID, PRESTO_PID)) != FT_OK)
|
||||
{
|
||||
LOG_ERROR("couldn't add PRESTO VID/PID");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((presto->status = FT_ListDevices(&numdevs, NULL, FT_LIST_NUMBER_ONLY)) != FT_OK)
|
||||
{
|
||||
LOG_ERROR("FT_ListDevices failed: %i", (int)presto->status);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
LOG_DEBUG("FTDI devices available: %lu", numdevs);
|
||||
for (i = 0; i < numdevs; i++)
|
||||
{
|
||||
if ((presto->status = FT_Open(i, &(presto->handle))) != FT_OK)
|
||||
{
|
||||
/* this is not fatal, the device may be legitimately open by other process, hence debug message only */
|
||||
LOG_DEBUG("FT_Open failed: %i", (int)presto->status);
|
||||
continue;
|
||||
}
|
||||
LOG_DEBUG("FTDI device %i open", (int)i);
|
||||
|
||||
if ((presto->status = FT_GetDeviceInfo(presto->handle, &device, &vidpid,
|
||||
presto->serial, devname, NULL)) == FT_OK)
|
||||
{
|
||||
if (vidpid == PRESTO_VID_PID
|
||||
&& (req_serial == NULL || !strcmp(presto->serial, req_serial)))
|
||||
break;
|
||||
}
|
||||
else
|
||||
LOG_DEBUG("FT_GetDeviceInfo failed: %lu", presto->status);
|
||||
|
||||
LOG_DEBUG("FTDI device %i does not match, closing", (int)i);
|
||||
FT_Close(presto->handle);
|
||||
presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (presto->handle == (FT_HANDLE)INVALID_HANDLE_VALUE)
|
||||
return ERROR_JTAG_DEVICE_ERROR; /* presto not open, return */
|
||||
|
||||
if ((presto->status = FT_SetLatencyTimer(presto->handle, 1)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
|
||||
if ((presto->status = FT_SetTimeouts(presto->handle, 100, 0)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if ((presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto_data = 0xD0;
|
||||
if ((presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
/* delay between first write/read turnaround (after purge?) necessary under Linux for unknown reason,
|
||||
probably a bug in library threading */
|
||||
usleep(100000);
|
||||
if ((presto->status = FT_Read(presto->handle, &presto_data, 1, &ftbytes)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if (ftbytes != 1)
|
||||
{
|
||||
LOG_DEBUG("PRESTO reset");
|
||||
|
||||
if ((presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
if ((presto->status = FT_SetBitMode(presto->handle, 0x80, 1)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
if ((presto->status = FT_SetBaudRate(presto->handle, 9600)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto_data = 0;
|
||||
for (i = 0; i < 4 * 62; i++)
|
||||
if ((presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
usleep(100000);
|
||||
|
||||
if ((presto->status = FT_SetBitMode(presto->handle, 0x00, 0)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if ((presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto_data = 0xD0;
|
||||
if ((presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
/* delay between first write/read turnaround (after purge?) necessary under Linux for unknown reason,
|
||||
probably a bug in library threading */
|
||||
usleep(100000);
|
||||
if ((presto->status = FT_Read(presto->handle, &presto_data, 1, &ftbytes)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if (ftbytes != 1)
|
||||
{
|
||||
LOG_DEBUG("PRESTO not responding");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if ((presto->status = FT_SetTimeouts(presto->handle, 0, 0)) != FT_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
|
||||
presto->status = FT_Write(presto->handle, &presto_init_seq, sizeof(presto_init_seq), &ftbytes);
|
||||
if (presto->status != FT_OK || ftbytes != sizeof(presto_init_seq))
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
static int presto_open_libftdi(char *req_serial)
|
||||
{
|
||||
uint8_t presto_data;
|
||||
|
||||
LOG_DEBUG("searching for PRESTO using libftdi");
|
||||
|
||||
/* initialize FTDI context structure */
|
||||
if (ftdi_init(&presto->ftdic) < 0)
|
||||
{
|
||||
LOG_ERROR("unable to init libftdi: %s", presto->ftdic.error_str);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
/* context, vendor id, product id */
|
||||
if (ftdi_usb_open_desc(&presto->ftdic, PRESTO_VID, PRESTO_PID, NULL, req_serial) < 0)
|
||||
{
|
||||
LOG_ERROR("unable to open PRESTO: %s", presto->ftdic.error_str);
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (ftdi_usb_reset(&presto->ftdic) < 0)
|
||||
{
|
||||
LOG_ERROR("unable to reset PRESTO device");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (ftdi_set_latency_timer(&presto->ftdic, 1) < 0)
|
||||
{
|
||||
LOG_ERROR("unable to set latency timer");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (ftdi_usb_purge_buffers(&presto->ftdic) < 0)
|
||||
{
|
||||
LOG_ERROR("unable to purge PRESTO buffers");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
presto_data = 0xD0;
|
||||
if (presto_write(&presto_data, 1) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error writing to PRESTO");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (presto_read(&presto_data, 1) != ERROR_OK)
|
||||
{
|
||||
LOG_DEBUG("no response from PRESTO, retrying");
|
||||
|
||||
if (ftdi_usb_purge_buffers(&presto->ftdic) < 0)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto_data = 0xD0;
|
||||
if (presto_write(&presto_data, 1) != ERROR_OK)
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if (presto_read(&presto_data, 1) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("no response from PRESTO, giving up");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (presto_write(presto_init_seq, sizeof(presto_init_seq)) != ERROR_OK)
|
||||
{
|
||||
LOG_ERROR("error writing PRESTO init sequence");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
#endif /* BUILD_PRESTO_LIBFTDI == 1 */
|
||||
|
||||
static int presto_open(char *req_serial)
|
||||
{
|
||||
presto->buff_out_pos = 0;
|
||||
presto->buff_in_pos = 0;
|
||||
presto->buff_in_len = 0;
|
||||
presto->buff_in_exp = 0;
|
||||
|
||||
presto->total_out = 0;
|
||||
presto->total_in = 0;
|
||||
|
||||
presto->jtag_tms = 0;
|
||||
presto->jtag_tck = 0;
|
||||
presto->jtag_rst = 0;
|
||||
presto->jtag_tdi_data = 0;
|
||||
presto->jtag_tdi_count = 0;
|
||||
|
||||
presto->jtag_speed = 0;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
return presto_open_ftd2xx(req_serial);
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
return presto_open_libftdi(req_serial);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int presto_close(void)
|
||||
{
|
||||
|
||||
int result = ERROR_OK;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
unsigned long ftbytes;
|
||||
|
||||
if (presto->handle == (FT_HANDLE)INVALID_HANDLE_VALUE)
|
||||
return result;
|
||||
|
||||
presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX);
|
||||
if (presto->status != FT_OK)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
presto->status = FT_Write(presto->handle, &presto_init_seq, sizeof(presto_init_seq), &ftbytes);
|
||||
if (presto->status != FT_OK || ftbytes != sizeof(presto_init_seq))
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if ((presto->status = FT_SetLatencyTimer(presto->handle, 16)) != FT_OK)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if ((presto->status = FT_Close(presto->handle)) != FT_OK)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
else
|
||||
presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE;
|
||||
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
|
||||
if ((presto->retval = ftdi_write_data(&presto->ftdic, presto_init_seq, sizeof(presto_init_seq))) != sizeof(presto_init_seq))
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if ((presto->retval = ftdi_set_latency_timer(&presto->ftdic, 16)) < 0)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
if ((presto->retval = ftdi_usb_close(&presto->ftdic)) < 0)
|
||||
result = ERROR_JTAG_DEVICE_ERROR;
|
||||
else
|
||||
ftdi_deinit(&presto->ftdic);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int presto_flush(void)
|
||||
{
|
||||
if (presto->buff_out_pos == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
if (presto->status != FT_OK)
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
if (presto->retval < 0)
|
||||
#endif
|
||||
{
|
||||
LOG_DEBUG("error in previous communication, canceling I/O operation");
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (presto_write(presto->buff_out, presto->buff_out_pos) != ERROR_OK)
|
||||
{
|
||||
presto->buff_out_pos = 0;
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
presto->total_out += presto->buff_out_pos;
|
||||
presto->buff_out_pos = 0;
|
||||
|
||||
if (presto->buff_in_exp == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
presto->buff_in_pos = 0;
|
||||
presto->buff_in_len = 0;
|
||||
|
||||
if (presto_read(presto->buff_in, presto->buff_in_exp) != ERROR_OK)
|
||||
{
|
||||
presto->buff_in_exp = 0;
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
presto->total_in += presto->buff_in_exp;
|
||||
presto->buff_in_len = presto->buff_in_exp;
|
||||
presto->buff_in_exp = 0;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int presto_sendbyte(int data)
|
||||
{
|
||||
if (data == EOF) return presto_flush();
|
||||
|
||||
if (presto->buff_out_pos < BUFFER_SIZE)
|
||||
{
|
||||
presto->buff_out[presto->buff_out_pos++] = (uint8_t)data;
|
||||
if (((data & 0xC0) == 0x40) || ((data & 0xD0)== 0xD0))
|
||||
presto->buff_in_exp++;
|
||||
}
|
||||
else
|
||||
return ERROR_JTAG_DEVICE_ERROR;
|
||||
|
||||
#if BUILD_PRESTO_FTD2XX == 1
|
||||
if (presto->buff_out_pos >= BUFFER_SIZE)
|
||||
#elif BUILD_PRESTO_LIBFTDI == 1
|
||||
/* libftdi does not do background read, be sure that USB IN buffer does not overflow (128 bytes only!) */
|
||||
if (presto->buff_out_pos >= BUFFER_SIZE || presto->buff_in_exp == 128)
|
||||
#endif
|
||||
return presto_flush();
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int presto_getbyte(void)
|
||||
{
|
||||
if (presto->buff_in_pos < presto->buff_in_len)
|
||||
return presto->buff_in[presto->buff_in_pos++];
|
||||
|
||||
if (presto->buff_in_exp == 0)
|
||||
return -1;
|
||||
|
||||
if (presto_flush() != ERROR_OK)
|
||||
return -1;
|
||||
|
||||
if (presto->buff_in_pos < presto->buff_in_len)
|
||||
return presto->buff_in[presto->buff_in_pos++];
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int presto_tdi_flush(void)
|
||||
{
|
||||
if (presto->jtag_tdi_count == 0)
|
||||
return 0;
|
||||
|
||||
if (presto->jtag_tck == 0)
|
||||
{
|
||||
LOG_ERROR("BUG: unexpected TAP condition, TCK low");
|
||||
return -1;
|
||||
}
|
||||
|
||||
presto->jtag_tdi_data |= (presto->jtag_tdi_count - 1) << 4;
|
||||
presto_sendbyte(presto->jtag_tdi_data);
|
||||
presto->jtag_tdi_count = 0;
|
||||
presto->jtag_tdi_data = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int presto_tck_idle(void)
|
||||
{
|
||||
if (presto->jtag_tck == 1)
|
||||
{
|
||||
presto_sendbyte(0xCA);
|
||||
presto->jtag_tck = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int presto_bitq_out(int tms, int tdi, int tdo_req)
|
||||
{
|
||||
int i;
|
||||
unsigned char cmd;
|
||||
|
||||
if (presto->jtag_tck == 0)
|
||||
{
|
||||
presto_sendbyte(0xA4); /* LED idicator - JTAG active */
|
||||
}
|
||||
else if (presto->jtag_speed == 0 && !tdo_req && tms == presto->jtag_tms)
|
||||
{
|
||||
presto->jtag_tdi_data |= (tdi != 0) << presto->jtag_tdi_count;
|
||||
|
||||
if (++presto->jtag_tdi_count == 4)
|
||||
presto_tdi_flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
presto_tdi_flush();
|
||||
|
||||
cmd = tdi ? 0xCB : 0xCA;
|
||||
presto_sendbyte(cmd);
|
||||
|
||||
if (tms != presto->jtag_tms)
|
||||
{
|
||||
presto_sendbyte((tms ? 0xEC : 0xE8) | (presto->jtag_rst ? 0x02 : 0));
|
||||
presto->jtag_tms = tms;
|
||||
}
|
||||
|
||||
/* delay with TCK low */
|
||||
for (i = presto->jtag_speed; i > 1; i--)
|
||||
presto_sendbyte(cmd);
|
||||
|
||||
cmd |= 0x04;
|
||||
presto_sendbyte(cmd | (tdo_req ? 0x10 : 0));
|
||||
|
||||
/* delay with TCK high */
|
||||
for (i = presto->jtag_speed; i > 1; i--)
|
||||
presto_sendbyte(cmd);
|
||||
|
||||
presto->jtag_tck = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int presto_bitq_flush(void)
|
||||
{
|
||||
presto_tdi_flush();
|
||||
presto_tck_idle();
|
||||
|
||||
presto_sendbyte(0xA0); /* LED idicator - JTAG idle */
|
||||
|
||||
return presto_flush();
|
||||
}
|
||||
|
||||
static int presto_bitq_in_rdy(void)
|
||||
{
|
||||
if (presto->buff_in_pos >= presto->buff_in_len)
|
||||
return 0;
|
||||
return presto->buff_in_len-presto->buff_in_pos;
|
||||
}
|
||||
|
||||
static int presto_bitq_in(void)
|
||||
{
|
||||
if (presto->buff_in_pos >= presto->buff_in_len)
|
||||
return -1;
|
||||
if (presto->buff_in[presto->buff_in_pos++]&0x08) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int presto_bitq_sleep(unsigned long us)
|
||||
{
|
||||
long waits;
|
||||
|
||||
presto_tdi_flush();
|
||||
presto_tck_idle();
|
||||
|
||||
if (us > 100000)
|
||||
{
|
||||
presto_bitq_flush();
|
||||
jtag_sleep(us);
|
||||
return 0;
|
||||
}
|
||||
|
||||
waits = us / 170 + 2;
|
||||
while (waits--)
|
||||
presto_sendbyte(0x80);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int presto_bitq_reset(int trst, int srst)
|
||||
{
|
||||
presto_tdi_flush();
|
||||
presto_tck_idle();
|
||||
|
||||
/* add a delay after possible TCK transition */
|
||||
presto_sendbyte(0x80);
|
||||
presto_sendbyte(0x80);
|
||||
|
||||
presto->jtag_rst = trst || srst;
|
||||
presto_sendbyte((presto->jtag_rst ? 0xEA : 0xE8) | (presto->jtag_tms ? 0x04 : 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bitq_interface presto_bitq = {
|
||||
.out = &presto_bitq_out,
|
||||
.flush = &presto_bitq_flush,
|
||||
.sleep = &presto_bitq_sleep,
|
||||
.reset = &presto_bitq_reset,
|
||||
.in_rdy = &presto_bitq_in_rdy,
|
||||
.in = &presto_bitq_in,
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int presto_jtag_khz(int khz, int *jtag_speed)
|
||||
{
|
||||
if (khz < 0)
|
||||
{
|
||||
*jtag_speed = 0;
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (khz >= 3000) *jtag_speed = 0;
|
||||
else *jtag_speed = (1000 + khz-1)/khz;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int presto_jtag_speed_div(int speed, int *khz)
|
||||
{
|
||||
if ((speed < 0) || (speed > 1000))
|
||||
{
|
||||
*khz = 0;
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (speed == 0) *khz = 3000;
|
||||
else *khz = 1000/speed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int presto_jtag_speed(int speed)
|
||||
{
|
||||
int khz;
|
||||
|
||||
if (presto_jtag_speed_div(speed, &khz))
|
||||
{
|
||||
return ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
presto->jtag_speed = speed;
|
||||
|
||||
if (khz%1000 == 0)
|
||||
LOG_INFO("setting speed to %d, max. TCK freq. is %d MHz", speed, khz/1000);
|
||||
else
|
||||
LOG_INFO("setting speed to %d, max. TCK freq. is %d kHz", speed, khz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *presto_serial;
|
||||
|
||||
COMMAND_HANDLER(presto_handle_serial_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
{
|
||||
if (presto_serial)
|
||||
free(presto_serial);
|
||||
presto_serial = strdup(CMD_ARGV[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("expected exactly one argument to presto_serial <serial-number>");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration presto_command_handlers[] = {
|
||||
{
|
||||
.name = "presto_serial",
|
||||
.handler = &presto_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "configure serial port",
|
||||
.usage = "<devname>",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static int presto_jtag_init(void)
|
||||
{
|
||||
if (presto_open(presto_serial) != ERROR_OK)
|
||||
{
|
||||
presto_close();
|
||||
if (presto_serial != NULL)
|
||||
LOG_ERROR("Cannot open PRESTO, serial number '%s'", presto_serial);
|
||||
else
|
||||
LOG_ERROR("Cannot open PRESTO");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
LOG_INFO("PRESTO open, serial number '%s'", presto->serial);
|
||||
|
||||
/* use JTAG speed setting from configuration file */
|
||||
presto_jtag_speed(jtag_get_speed());
|
||||
|
||||
bitq_interface = &presto_bitq;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int presto_jtag_quit(void)
|
||||
{
|
||||
bitq_cleanup();
|
||||
presto_close();
|
||||
LOG_INFO("PRESTO closed");
|
||||
|
||||
if (presto_serial)
|
||||
{
|
||||
free(presto_serial);
|
||||
presto_serial = NULL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct jtag_interface presto_interface = {
|
||||
.name = "presto",
|
||||
|
||||
.commands = presto_command_handlers,
|
||||
|
||||
.execute_queue = &bitq_execute_queue,
|
||||
.speed = &presto_jtag_speed,
|
||||
.khz = &presto_jtag_khz,
|
||||
.speed_div = &presto_jtag_speed_div,
|
||||
|
||||
.init = &presto_jtag_init,
|
||||
.quit = &presto_jtag_quit,
|
||||
};
|
||||
1812
src/jtag/drivers/rlink.c
Normal file
1812
src/jtag/drivers/rlink.c
Normal file
File diff suppressed because it is too large
Load Diff
31
src/jtag/drivers/rlink.h
Normal file
31
src/jtag/drivers/rlink.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 Lou Deluxe *
|
||||
* lou.openocd012@fixit.nospammail.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct rlink_speed_table {
|
||||
uint8_t const *dtc;
|
||||
uint16_t dtc_size;
|
||||
uint16_t khz;
|
||||
uint8_t prescaler;
|
||||
};
|
||||
|
||||
extern const struct rlink_speed_table rlink_speed_table[];
|
||||
extern const size_t rlink_speed_table_size;
|
||||
485
src/jtag/drivers/rlink_call.m4
Normal file
485
src/jtag/drivers/rlink_call.m4
Normal file
@@ -0,0 +1,485 @@
|
||||
m4_divert(`-1')
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 Lou Deluxe *
|
||||
* lou.openocd012@fixit.nospammail.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
m4_dnl Setup and hold times depend on SHIFTER_PRESCALER
|
||||
m4_define(`SETUP_DELAY_CYCLES', m4_eval(`('SHIFTER_PRESCALER` + 1) / 2'))
|
||||
m4_define(`HOLD_DELAY_CYCLES', m4_eval(`'SHIFTER_PRESCALER` / 2'))
|
||||
|
||||
m4_dnl Some macros to make nybble handling a little easier
|
||||
m4_define(`m4_high_nybble', `m4_eval(`(($1) >> 4) & 0xf')')
|
||||
m4_define(`m4_low_nybble', `m4_eval(`($1) & 0xf')')
|
||||
|
||||
m4_dnl A macro to generate a number of NOPs depending on the argument
|
||||
m4_define(`m4_0_to_5_nops', `m4_ifelse(m4_eval(`($1) >= 1'), 1, ` NOP
|
||||
'm4_ifelse(m4_eval(`($1) >= 2'), 1, ` NOP
|
||||
'm4_ifelse(m4_eval(`($1) >= 3'), 1, ` NOP
|
||||
'm4_ifelse(m4_eval(`($1) >= 4'), 1, ` NOP
|
||||
'm4_ifelse(m4_eval(`($1) >= 5'), 1, ` NOP
|
||||
')))))')
|
||||
|
||||
|
||||
m4_dnl Some macros to facilitate bit-banging delays.
|
||||
m4_dnl There are 3 of them. One for self-contained delays, and two for those which must be split between setup and loop to keep from disturbing A at delay time.
|
||||
m4_dnl The argument passed to any of them is the number of cycles which the delay should consume.
|
||||
|
||||
m4_dnl This one is self-contained.
|
||||
|
||||
m4_define(`m4_delay',
|
||||
`; delay (m4_eval($1) cycles)'
|
||||
`m4_ifelse(m4_eval(`('$1`) < 6'), 1,
|
||||
m4_0_to_5_nops($1)
|
||||
,
|
||||
m4_ifelse(m4_eval(`(('$1`) - 3) % 2'), 1, ` NOP')
|
||||
A.H = m4_high_nybble(`(('$1`) - 3) / 2')
|
||||
A.L = m4_low_nybble(`(('$1`) - 3) / 2')
|
||||
Y = A
|
||||
DECY
|
||||
JP -1
|
||||
)')
|
||||
|
||||
|
||||
m4_dnl These are the setup and loop parts of the split delay.
|
||||
m4_dnl The argument passed to both must match for the result to make sense.
|
||||
m4_dnl The setup does not figure into the delay. It takes 3 cycles when a loop is used and none if nops are used.
|
||||
|
||||
m4_define(`m4_delay_setup',
|
||||
`; delay setup (m4_eval($1) cycles)'
|
||||
`m4_ifelse(m4_eval(`('$1`) < 6'), 0, ` '
|
||||
A.H = m4_high_nybble(`('$1`) / 2')
|
||||
A.L = m4_low_nybble(`('$1`) / 2')
|
||||
Y = A
|
||||
)')
|
||||
|
||||
m4_define(`m4_delay_loop',
|
||||
`; delay loop (m4_eval($1) cycles)'
|
||||
`m4_ifelse(m4_eval(`('$1`) < 6'), 1,
|
||||
m4_0_to_5_nops($1)
|
||||
,
|
||||
m4_ifelse(m4_eval(`('$1`) % 2'), 1, ` NOP')
|
||||
DECY
|
||||
JP -1
|
||||
)')
|
||||
|
||||
m4_dnl These are utility macros for use with delays. Specifically, there is code below which needs some predictability in code size for relative jumps to reach. The m4_delay macro generates an extra NOP when an even delay is needed, and the m4_delay_loop macro generates an extra NOP when an odd delay is needed. Using this for the argument to the respective macro rounds up the argument so that the extra NOP will not be generated. There is also logic built in to cancel the rounding when the result is small enough that a loop would not be generated.
|
||||
|
||||
m4_define(`m4_delay_loop_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) + 1) / 2 * 2'))')
|
||||
m4_define(`m4_delay_round_up', `m4_ifelse(m4_eval($1` < 6'), 1, $1, m4_eval(`(('$1`) / 2 * 2) + 1'))')
|
||||
|
||||
|
||||
m4_divert(`0')m4_dnl
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:opcode_error
|
||||
; This is at address 0x00 in case of empty LUT entries
|
||||
STATUS STOP ERROR
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Command interpreter at address 0x01 because it is branched to a lot and having it be 0x01 means we can use X for it, which is already used for other purposes which want it to be 1.
|
||||
; Assumes X is 1
|
||||
; Assumes ADR_BUFFER0 points to the next command byte
|
||||
; Stores the current command byte in CMP01
|
||||
|
||||
:command_interpreter
|
||||
A = DATA_BUFFER0
|
||||
ADR_BUFFER0 += X
|
||||
CMP01 = A ; store the current command for later
|
||||
|
||||
EXCHANGE ; put MSN into LSN
|
||||
A.H = 0xc ; lookup table at 0x1550 + 0xc0 = 0x1610
|
||||
|
||||
; branch to address in lookup table
|
||||
Y = A
|
||||
A = <Y>
|
||||
BRANCH
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; LUT for high nybble
|
||||
|
||||
;LUT; c0 opcode_error
|
||||
;LUT; c1 opcode_shift_tdi_andor_tms_bytes
|
||||
;LUT; c2 opcode_shift_tdi_andor_tms_bytes
|
||||
;LUT; c3 opcode_shift_tdi_andor_tms_bytes
|
||||
;LUT; c4 opcode_shift_tdo_bytes
|
||||
;LUT; c5 opcode_error
|
||||
;LUT; c6 opcode_shift_tdio_bytes
|
||||
;LUT; c7 opcode_error
|
||||
;LUT; c8 opcode_shift_tms_tdi_bit_pair
|
||||
;LUT; c9 opcode_shift_tms_bits
|
||||
;LUT; ca opcode_error
|
||||
;LUT; cb opcode_error
|
||||
;LUT; cc opcode_error
|
||||
;LUT; cd opcode_error
|
||||
;LUT; ce opcode_shift_tdio_bits
|
||||
;LUT; cf opcode_stop
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; USB/buffer handling
|
||||
;
|
||||
|
||||
;ENTRY; download entry_download
|
||||
|
||||
opcode_stop:
|
||||
opcode_next_buffer:
|
||||
; pointer to completion flag
|
||||
A.H = 0xf
|
||||
A.L = 0xf
|
||||
Y = A
|
||||
|
||||
A = OR_MPEG ; buffer indicator from previous iteration
|
||||
<Y> = A ; either indicator will have bit 0 set
|
||||
BSET 1 ; was buffer 1 previously current?
|
||||
; A.H = 0 ; already zero from OR_MPEG
|
||||
JP opcode_next_buffer_0
|
||||
|
||||
opcode_next_buffer_1:
|
||||
A.L = 0x1 ; ack buffer 0
|
||||
BUFFER_MNGT = A
|
||||
; A.H = 0x0 ; already zero from BUFFER_MNGT
|
||||
A.L = 0x3 ; Input buffer 1 = 0x1850 (0x0300)
|
||||
JP +4
|
||||
|
||||
opcode_next_buffer_0:
|
||||
A.L = 0x2 ; ack buffer 1
|
||||
BUFFER_MNGT = A
|
||||
entry_download:
|
||||
A = X ; Input buffer 0 = 0x1650 (0x0100)
|
||||
|
||||
ADR_BUFFER01 = A
|
||||
OR_MPEG = A ; store for next iteration
|
||||
|
||||
A.L = 0x0
|
||||
BUFFER_MNGT = A ; finish acking previous buffer
|
||||
Y = A
|
||||
ADR_BUFFER00 = A
|
||||
ADR_BUFFER11 = A
|
||||
|
||||
A.H = 0x4 ; Output buffer = 0x1590 (0x0040)
|
||||
ADR_BUFFER10 = A
|
||||
|
||||
EXCHANGE ; 0x04
|
||||
X = A ; for the spin loop below
|
||||
|
||||
; pointer to status in shared memory
|
||||
DECY ; setting to 0 above and decrementing here saves a byte
|
||||
|
||||
; wait until a command buffer is available
|
||||
A = BUFFER_MNGT ; spin while neither of bits 2 or 3 are set
|
||||
CP A<X ; this is slightly faster and smaller than trying to AND and compare the result, and it lets us just use the nybble-swapped 0x40 from the output buffer setup.
|
||||
JP -2
|
||||
<Y> = A ; update status once done spinning
|
||||
|
||||
; restore X, since we used it
|
||||
; A.H = 0 ; high nybble of BUFFER_MNGT will always be 0 the way we use it
|
||||
A.L = 1
|
||||
X = A
|
||||
|
||||
; go to command interpreter
|
||||
BRANCH
|
||||
|
||||
|
||||
;;------------------------------------------------------------------------------
|
||||
;:opcode_stop
|
||||
;;
|
||||
;
|
||||
; ; Ack buffer 0 in download mode
|
||||
; A.L = 0x1
|
||||
; BUFFER_MNGT = A
|
||||
;
|
||||
; STATUS STOP
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:opcode_shift_tdi_andor_tms_bytes
|
||||
;
|
||||
|
||||
A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
|
||||
A.H = 0
|
||||
Y = A ; loop counter
|
||||
|
||||
A = CMP01
|
||||
EXCHANGE
|
||||
CMP01 = A ; we're interested in bits in the high nybble
|
||||
|
||||
opcode_shift_tdi_andor_tms_bytes__loop:
|
||||
|
||||
; set tdi to supplied byte or zero
|
||||
A = CMP01
|
||||
BSET 1
|
||||
JP +4
|
||||
A.H = 0
|
||||
A.L = 0
|
||||
JP +3
|
||||
A = DATA_BUFFER0
|
||||
ADR_BUFFER0 += X
|
||||
SHIFT_MPEG = A
|
||||
|
||||
; set tms to supplied byte or zero
|
||||
A = CMP01
|
||||
BCLR 0
|
||||
JP +5
|
||||
A = DATA_BUFFER0
|
||||
ADR_BUFFER0 += X
|
||||
SHIFT_CARD = A
|
||||
SHIFT CARD OUT=>PIN0
|
||||
|
||||
; run both shifters as nearly simultaneously as possible
|
||||
SHIFT MPEG OUT=>PIN1
|
||||
|
||||
A = CTRL_FCI
|
||||
EXCHANGE
|
||||
BCLR 3
|
||||
JP -3
|
||||
|
||||
DECY
|
||||
JP opcode_shift_tdi_andor_tms_bytes__loop
|
||||
|
||||
A = X
|
||||
BRANCH
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:opcode_shift_tdo_bytes
|
||||
;
|
||||
|
||||
A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
|
||||
A.H = 0
|
||||
Y = A ; loop counter
|
||||
|
||||
opcode_shift_tdo_bytes__loop:
|
||||
SHIFT MPEG PIN0=>IN
|
||||
|
||||
A = CTRL_FCI
|
||||
EXCHANGE
|
||||
BCLR 3
|
||||
JP -3
|
||||
|
||||
; put shifted byte into output buffer
|
||||
A = SHIFT_MPEG
|
||||
DATA_BUFFER1 = A
|
||||
ADR_BUFFER1 += X
|
||||
|
||||
DECY
|
||||
JP opcode_shift_tdo_bytes__loop
|
||||
|
||||
A = X
|
||||
BRANCH
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:opcode_shift_tdio_bytes
|
||||
;
|
||||
|
||||
A = CMP01 ; bits 3..0 contain the number of bytes to shift - 1
|
||||
A.H = 0
|
||||
CMP10 = A ; byte loop counter
|
||||
|
||||
A.H = opcode_shift_tdio_bytes__sub_return
|
||||
A.L = opcode_shift_tdio_bytes__sub_return
|
||||
CMP00 = A ; return address
|
||||
|
||||
opcode_shift_tdio_bytes__loop:
|
||||
A.H = 0
|
||||
A.L = 7
|
||||
CMP11 = A ; always use 8 bits
|
||||
|
||||
JP sub_shift_tdio_bits
|
||||
opcode_shift_tdio_bytes__sub_return:
|
||||
|
||||
A = CMP10 ; byte loop counter
|
||||
CP A=>X
|
||||
CLC
|
||||
A -= X
|
||||
CMP10 = A
|
||||
JP opcode_shift_tdio_bytes__loop
|
||||
|
||||
A = X
|
||||
;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
|
||||
BRANCH
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:opcode_shift_tdio_bits
|
||||
;
|
||||
|
||||
A = CMP01 ; bits 2..0 contain the number of bits to shift - 1
|
||||
A.H = 0
|
||||
BCLR 3 ; set TMS=1 if bit 3 was set
|
||||
CMP11 = A ; bit loop counter
|
||||
|
||||
A.H = opcode_shift_tdio_bits__sub_return
|
||||
A.L = opcode_shift_tdio_bits__sub_return
|
||||
CMP00 = A ; return address
|
||||
|
||||
JP sub_shift_tdio_bits
|
||||
A.L = 0x1 ; TMS=1
|
||||
DR_CARD = A
|
||||
JP sub_shift_tdio_bits
|
||||
opcode_shift_tdio_bits__sub_return:
|
||||
|
||||
A = X
|
||||
;DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
|
||||
BRANCH
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:sub_shift_tdio_bits
|
||||
;
|
||||
|
||||
A = DATA_BUFFER0 ; get byte from input buffer
|
||||
ADR_BUFFER0 += X
|
||||
MASK = A ; put it in MASK where bit routine will use it
|
||||
|
||||
:sub_shift_tdio_bits__loop
|
||||
m4_delay_setup(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
|
||||
|
||||
A = MASK ; shift TDO into and TDI out of MASK via carry
|
||||
A += MASK
|
||||
MASK = A
|
||||
|
||||
; shifting out TDI
|
||||
A.L = 0x2 ; TCK=0, TDI=1
|
||||
CP CARRY
|
||||
JP +2
|
||||
A.L = 0x0 ; TCK=0, TDI=0
|
||||
DR_MPEG = A
|
||||
|
||||
m4_delay_loop(m4_delay_loop_round_up(SETUP_DELAY_CYCLES - 1))
|
||||
|
||||
BSET 2 ; TCK high
|
||||
DR_MPEG = A
|
||||
|
||||
A = DR_MPEG ; set carry bit to TDO
|
||||
CLC
|
||||
BCLR 0
|
||||
JP +2
|
||||
SEC
|
||||
|
||||
m4_delay(HOLD_DELAY_CYCLES - 10)
|
||||
|
||||
A = CMP11 ; bit loop counter
|
||||
Y = A ; use Y to avoid corrupting carry bit with subtract
|
||||
DECY
|
||||
A = Y
|
||||
CMP11 = A
|
||||
JP :sub_shift_tdio_bits__loop
|
||||
|
||||
; shift last TDO bit into result
|
||||
A = MASK
|
||||
A += MASK
|
||||
DATA_BUFFER1 = A
|
||||
ADR_BUFFER1 += X
|
||||
|
||||
A = CMP00 ; return to caller
|
||||
BRANCH
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:opcode_shift_tms_tdi_bit_pair
|
||||
;
|
||||
|
||||
; set TMS line manually
|
||||
A = CMP01 ; bits 3..0 contain TDI and TMS bits and whether to return TDO
|
||||
BSET 0 ; TMS bit
|
||||
A.L = 0x1 ; TMS=1
|
||||
JP +2
|
||||
A.L = 0x0 ; TMS=0
|
||||
DR_CARD = A
|
||||
|
||||
; stuff command buffer with bitmap of single TDI bit
|
||||
A = CMP01
|
||||
BSET 1 ; TDI bit
|
||||
A.H = 0x8 ; TDI=1
|
||||
JP +2
|
||||
A.H = 0x0 ; TDI=0
|
||||
ADR_BUFFER0 -= X
|
||||
DATA_BUFFER0 = A
|
||||
|
||||
A.H = 0
|
||||
A.L = 0
|
||||
CMP11 = A ; bit loop counter (only doing one bit)
|
||||
|
||||
A.H = opcode_shift_tms_tdi_bit_pair__sub_return
|
||||
A.L = opcode_shift_tms_tdi_bit_pair__sub_return
|
||||
CMP00 = A ; return address
|
||||
|
||||
; jump this way due to relative jump range issues
|
||||
A.H = sub_shift_tdio_bits
|
||||
A.L = sub_shift_tdio_bits
|
||||
BRANCH
|
||||
opcode_shift_tms_tdi_bit_pair__sub_return:
|
||||
|
||||
A = CMP01
|
||||
BSET 3 ; bit says whether to return TDO
|
||||
JP +2
|
||||
ADR_BUFFER1 -= X ; subroutine returns it, so undo that
|
||||
|
||||
A = X
|
||||
DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
|
||||
BRANCH
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
:opcode_shift_tms_bits
|
||||
;
|
||||
|
||||
A = CMP01 ; bits 3..0 contain the number of bits to shift - 1 (only 1-8 bits is valid... no checking, just improper operation)
|
||||
A.H = 0
|
||||
CMP11 = A ; bit loop counter
|
||||
|
||||
A = DATA_BUFFER0 ; get byte from input buffer
|
||||
ADR_BUFFER0 += X
|
||||
MASK = A ; The byte we'll be shifting
|
||||
|
||||
:opcode_shift_tms_bits__loop
|
||||
m4_delay_setup(SETUP_DELAY_CYCLES - 1)
|
||||
|
||||
A = MASK ; shift TMS out of MASK via carry
|
||||
A += MASK
|
||||
MASK = A
|
||||
|
||||
; shifting out TMS
|
||||
A.L = 0x1 ; TCK=0, TDI=0, TMS=1
|
||||
CP CARRY
|
||||
JP +2
|
||||
A.L = 0x0 ; TCK=0, TDI=0, TMS=0
|
||||
DR_CARD = A
|
||||
DR_MPEG = A
|
||||
|
||||
m4_delay_loop(SETUP_DELAY_CYCLES - 1)
|
||||
|
||||
BSET 2 ; TCK high
|
||||
DR_MPEG = A
|
||||
|
||||
m4_delay(HOLD_DELAY_CYCLES - 10)
|
||||
|
||||
A = CMP11 ; bit loop counter
|
||||
CP A=>X
|
||||
CLC
|
||||
A -= X
|
||||
CMP11 = A
|
||||
JP :opcode_shift_tms_bits__loop
|
||||
|
||||
A = X
|
||||
DR_MPEG = A ; return TCK low, as str912 reset halt seems to require it
|
||||
BRANCH
|
||||
|
||||
|
||||
66
src/jtag/drivers/rlink_dtc_cmd.h
Normal file
66
src/jtag/drivers/rlink_dtc_cmd.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 Lou Deluxe *
|
||||
* lou.openocd012@fixit.nospammail.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
/* A command position with the high nybble of 0x0 is reserved for an error condition. If executed, it stops the DTC and raises the ERROR flag */
|
||||
|
||||
#define DTC_CMD_SHIFT_TMS_BYTES(bytes) ((0x1 << 4) | ((bytes) - 1))
|
||||
/* Shift 1-16 bytes out TMS. TDI is 0. */
|
||||
/* Bytes to shift follow. */
|
||||
|
||||
#define DTC_CMD_SHIFT_TDI_BYTES(bytes) ((0x2 << 4) | ((bytes) - 1))
|
||||
/* Shift 1-16 bytes out TDI. TMS is 0. */
|
||||
/* Bytes to shift follow. */
|
||||
|
||||
#define DTC_CMD_SHIFT_TDI_AND_TMS_BYTES(bytes) ((0x3 << 4) | ((bytes) - 1))
|
||||
/* Shift 1-16 byte pairs out TDI and TMS. */
|
||||
/* Byte pairs to shift follow in TDI, TMS order. */
|
||||
|
||||
#define DTC_CMD_SHIFT_TDO_BYTES(bytes) ((0x4 << 4) | ((bytes) - 1))
|
||||
/* Shift 1-16 bytes in TDO. TMS is unaffected. */
|
||||
/* Reply buffer contains bytes shifted in. */
|
||||
|
||||
#define DTC_CMD_SHIFT_TDIO_BYTES(bytes) ((0x6 << 4) | ((bytes) - 1))
|
||||
/* Shift 1-16 bytes out TDI and in TDO. TMS is unaffected. */
|
||||
|
||||
#define DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(tms, tdi, tdo) ((0x8 << 4) | (\
|
||||
(tms) ? (1 << 0) : 0 \
|
||||
) | (\
|
||||
(tdi) ? (1 << 1) : 0 \
|
||||
) | (\
|
||||
(tdo) ? (1 << 3) : 0 \
|
||||
))
|
||||
/* Single bit shift. */
|
||||
/* tms and tdi are the levels shifted out on TMS and TDI, respectively. */
|
||||
/* tdo indicates whether a byte will be returned in the reply buffer with its least significant bit set to reflect TDO */
|
||||
/* Care should be taken when tdo is zero, as the underlying code actually does put that byte in the reply buffer. Setting tdo to zero just moves the pointer back. The result is that if this command is executed when the reply buffer is already full, a byte will be written erroneously to memory not belonging to the reply buffer. This could be worked around at the expense of DTC code space and speed. */
|
||||
|
||||
#define DTC_CMD_SHIFT_TMS_BITS(bits) ((0x9 << 4) | ((bits) - 1))
|
||||
/* Shift 1-8 bits out TMS. */
|
||||
/* Bits to be shifted out are left justified in the following byte. */
|
||||
|
||||
#define DTC_CMD_SHIFT_TDIO_BITS(bits) ((0xe << 4) | ((bits) - 1))
|
||||
/* Shift 1-8 bits out TDI and in TDO, TMS is unaffected. */
|
||||
/* Bits to be shifted out are left justified in the following byte. */
|
||||
/* Bits shifted in are right justified in the byte placed in the reply buffer. */
|
||||
|
||||
|
||||
#define DTC_CMD_STOP (0xf << 4)
|
||||
/* Stop processing the command buffer and wait for the next one. */
|
||||
/* A shared status byte is updated with bit 0 set when this has happened, and it is cleared when a new command buffer becomes ready. The host can poll that byte to see when it is safe to read a reply. */
|
||||
57
src/jtag/drivers/rlink_ep1_cmd.h
Normal file
57
src/jtag/drivers/rlink_ep1_cmd.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 Lou Deluxe *
|
||||
* lou.openocd012@fixit.nospammail.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Command opcodes that can be sent over endpoint 1.
|
||||
* This codifies information provided by Rob Brown <rob@cobbleware.com>.
|
||||
* The buffer can contain several of these, but only one which returns data.
|
||||
* Some of these opcodes have arguments, which follow immediately.
|
||||
* If shorter than the packet size, trailing positions should be zero-filled.
|
||||
*/
|
||||
|
||||
/* LED update enables:
|
||||
* When enabled, each LED is updated automatically.
|
||||
* When not enabled, each LED can be controlled manually with EP1_CMD_SET_PORTD_LEDS.
|
||||
*/
|
||||
#define EP1_CMD_LEDUE_BOTH (0x05)
|
||||
/* EP1_CMD_LEDUE_NONE has the side effect of turning the LEDs on */
|
||||
#define EP1_CMD_LEDUE_NONE (0x06)
|
||||
#define EP1_CMD_LEDUE_ERROR (0x17)
|
||||
#define EP1_CMD_LEDUE_BUSY (0x18)
|
||||
|
||||
#define EP1_CMD_DTC_STOP (0x0b)
|
||||
#define EP1_CMD_DTC_LOAD (0x0c)
|
||||
#define EP1_CMD_DTC_CALL (0x0d)
|
||||
#define EP1_CMD_SET_UPLOAD (0x0f)
|
||||
#define EP1_CMD_SET_DOWNLOAD (0x10)
|
||||
#define EP1_CMD_DTC_WAIT (0x12)
|
||||
#define EP1_CMD_DTC_GET_STATUS (0x15)
|
||||
/* a quick way to just read back one byte */
|
||||
#define EP1_CMD_DTC_GET_CACHED_STATUS (0x16)
|
||||
|
||||
/* Writes upper 2 bits (SHDN and SEL) of port D with argument */
|
||||
#define EP1_CMD_SET_PORTD_VPP (0x19)
|
||||
/* Writes lower 2 bits (BUSY and ERROR) of port D with argument */
|
||||
#define EP1_CMD_SET_PORTD_LEDS (0x1a)
|
||||
|
||||
#define EP1_CMD_MEMORY_READ (0x28)
|
||||
#define EP1_CMD_MEMORY_WRITE (0x29)
|
||||
#define EP1_CMD_GET_FWREV (0xfe)
|
||||
#define EP1_CMD_GET_SERIAL (0xff)
|
||||
74
src/jtag/drivers/rlink_init.m4
Normal file
74
src/jtag/drivers/rlink_init.m4
Normal file
@@ -0,0 +1,74 @@
|
||||
m4_divert(`-1')
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 Lou Deluxe *
|
||||
* lou.openocd012@fixit.nospammail.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
m4_undefine(`CTRL_MPEG_L')
|
||||
m4_undefine(`CTRL_CARD_L')
|
||||
|
||||
m4_ifelse(SHIFTER_PRESCALER, 1, `
|
||||
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x0')')
|
||||
')
|
||||
m4_ifelse(SHIFTER_PRESCALER, 2, `
|
||||
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x2')')
|
||||
m4_define(`CTRL_CARD_L', `m4_eval(`0x8 | 0x1')')
|
||||
')
|
||||
m4_ifelse(SHIFTER_PRESCALER, 8, `
|
||||
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x3')')
|
||||
')
|
||||
m4_ifelse(SHIFTER_PRESCALER, 11, `
|
||||
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x4')')
|
||||
')
|
||||
m4_ifelse(SHIFTER_PRESCALER, 64, `
|
||||
m4_define(`CTRL_MPEG_L', `m4_eval(`0x8 | 0x7')')
|
||||
')
|
||||
|
||||
m4_ifdef(`CTRL_MPEG_L',,`
|
||||
m4_errprint(`SHIFTER_PRESCALER was not defined with a supported value
|
||||
') m4_m4exit(`1')
|
||||
')
|
||||
|
||||
m4_divert(`0')m4_dnl
|
||||
|
||||
init:
|
||||
A.H = 0
|
||||
|
||||
A.L = 0
|
||||
|
||||
DR_MPEG = A ; TDI and TCK start out low
|
||||
DR_CARD = A ; TMS starts out low
|
||||
|
||||
A.L = 0x6
|
||||
|
||||
CTRL_FCI = A ; MPEG and CARD driven by FCI
|
||||
DDR_MPEG = A ; TDI and TCK are outputs
|
||||
|
||||
A.L = 0x1
|
||||
|
||||
X = A ; X == 1
|
||||
DDR_CARD = A ; TMS is output
|
||||
|
||||
A.L = CTRL_MPEG_L
|
||||
CTRL_MPEG = A
|
||||
m4_ifdef(`CTRL_CARD_L',
|
||||
` A.L = 'CTRL_CARD_L`
|
||||
')m4_dnl
|
||||
CTRL_CARD = A
|
||||
|
||||
STATUS STOP
|
||||
101
src/jtag/drivers/rlink_speed_table.c
Normal file
101
src/jtag/drivers/rlink_speed_table.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/* This file was created automatically by ../../../tools/rlink_make_speed_table/rlink_make_speed_table.pl. */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "rlink.h"
|
||||
#include "rlink_st7.h"
|
||||
|
||||
static const uint8_t dtc_64[] = {
|
||||
0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
|
||||
191, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42,
|
||||
42, 73, 0, 88, 0, 160, 189, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119,
|
||||
110, 108, 111, 97, 100, 2, 226, 7, 219, 39, 137, 51, 172, 130, 192, 96,
|
||||
175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133,
|
||||
153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177,
|
||||
129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39,
|
||||
154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193,
|
||||
96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96,
|
||||
201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105,
|
||||
193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219,
|
||||
39, 131, 161, 176, 130, 195, 53, 131, 178, 10, 66, 176, 151, 60, 97, 58,
|
||||
151, 215, 2, 40, 66, 1, 0, 160, 185, 130, 60, 97, 203, 130, 60, 194, 139,
|
||||
127, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168,
|
||||
66, 160, 38, 155, 160, 176, 139, 171, 182, 136, 167, 183, 96, 201, 59,
|
||||
66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 160, 191, 130, 195,
|
||||
53, 131, 177, 10, 66, 176, 147, 151, 0, 60, 97, 58, 151, 0, 160, 185, 130,
|
||||
60, 97, 203, 8, 2, 36, 139, 124, 193, 151, 96
|
||||
};
|
||||
|
||||
static const uint8_t dtc_11[] = {
|
||||
0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
|
||||
188, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42,
|
||||
42, 73, 0, 88, 0, 154, 183, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119,
|
||||
110, 108, 111, 97, 100, 2, 213, 7, 219, 39, 137, 51, 172, 130, 192, 96,
|
||||
175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133,
|
||||
153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177,
|
||||
129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39,
|
||||
154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193,
|
||||
96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96,
|
||||
201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105,
|
||||
193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219,
|
||||
39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 0, 0, 58, 151, 215,
|
||||
2, 40, 66, 1, 203, 130, 60, 194, 139, 121, 195, 53, 156, 47, 200, 96, 201,
|
||||
56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 171,
|
||||
176, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219,
|
||||
39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 0, 0, 58, 151,
|
||||
203, 8, 2, 36, 139, 117, 193, 151, 96
|
||||
};
|
||||
|
||||
static const uint8_t dtc_8[] = {
|
||||
0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
|
||||
187, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42,
|
||||
42, 73, 0, 88, 0, 152, 181, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119,
|
||||
110, 108, 111, 97, 100, 2, 209, 7, 219, 39, 137, 51, 172, 130, 192, 96,
|
||||
175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133,
|
||||
153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177,
|
||||
129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39,
|
||||
154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193,
|
||||
96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96,
|
||||
201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105,
|
||||
193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219,
|
||||
39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 58, 151, 215, 2,
|
||||
40, 66, 1, 203, 130, 60, 194, 139, 119, 195, 53, 156, 47, 200, 96, 201,
|
||||
56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170,
|
||||
190, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219,
|
||||
39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 58, 151, 203,
|
||||
8, 2, 36, 139, 115, 193, 151, 96
|
||||
};
|
||||
|
||||
static const uint8_t dtc_2[] = {
|
||||
0, 2, 68, 84, 67, 2, 14, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148,
|
||||
186, 143, 185, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0,
|
||||
42, 42, 42, 73, 0, 88, 0, 149, 178, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100,
|
||||
111, 119, 110, 108, 111, 97, 100, 2, 203, 7, 219, 39, 137, 51, 172, 130,
|
||||
192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159,
|
||||
193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9,
|
||||
98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176,
|
||||
67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60,
|
||||
118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105,
|
||||
193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36,
|
||||
138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67,
|
||||
193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 58, 151, 215,
|
||||
2, 40, 66, 1, 203, 130, 60, 194, 139, 116, 195, 53, 156, 47, 200, 96, 201,
|
||||
56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170,
|
||||
187, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219,
|
||||
39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 58, 151, 203, 8, 2,
|
||||
36, 139, 112, 193, 151, 96
|
||||
};
|
||||
|
||||
const struct rlink_speed_table rlink_speed_table[] = {{
|
||||
dtc_64, sizeof(dtc_64), (ST7_FOSC * 2) / (1000 * 64), 64
|
||||
}, {
|
||||
dtc_11, sizeof(dtc_11), (ST7_FOSC * 2) / (1000 * 11), 11
|
||||
}, {
|
||||
dtc_8, sizeof(dtc_8), (ST7_FOSC * 2) / (1000 * 8), 8
|
||||
}, {
|
||||
dtc_2, sizeof(dtc_2), (ST7_FOSC * 2) / (1000 * 2), 2
|
||||
}};
|
||||
|
||||
const size_t rlink_speed_table_size = ARRAY_SIZE(rlink_speed_table);
|
||||
|
||||
114
src/jtag/drivers/rlink_st7.h
Normal file
114
src/jtag/drivers/rlink_st7.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 Lou Deluxe *
|
||||
* lou.openocd012@fixit.nospammail.net *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#define ST7_FOSC (12 * 1000000)
|
||||
|
||||
/* This is not a complete enumeration of ST7 registers, but it is sufficient for this interface driver. */
|
||||
|
||||
#define ST7_PADR (0x0000)
|
||||
#define ST7_PADDR (ST7_PADR + 1)
|
||||
#define ST7_PAOR (ST7_PADR + 2)
|
||||
#define ST7_PBDR (0x0003)
|
||||
#define ST7_PBDDR (ST7_PBDR + 1)
|
||||
#define ST7_PCDR (0x0006)
|
||||
#define ST7_PCDDR (ST7_PCDR + 1)
|
||||
#define ST7_PCOR (ST7_PCDR + 2)
|
||||
#define ST7_PDDR (0x0009)
|
||||
#define ST7_PDDDR (ST7_PDDR + 1)
|
||||
#define ST7_PDOR (ST7_PDDR + 2)
|
||||
#define ST7_PEDR (0x000c)
|
||||
#define ST7_PEDDR (ST7_PEDR + 1)
|
||||
#define ST7_PEOR (ST7_PEDR + 2)
|
||||
#define ST7_PFDR (0x000f)
|
||||
#define ST7_PFDDR (ST7_PFDR + 1)
|
||||
|
||||
#define ST7_ADCDR (0x0012)
|
||||
#define ST7_ADCCSR (ST7_ADCDR + 1)
|
||||
|
||||
#define ST7_EP2TXR (0x003e)
|
||||
#define ST7_EP2TXR_STAT_TX0 (1 << 0)
|
||||
#define ST7_EP2TXR_STAT_TX1 (1 << 1)
|
||||
#define ST7_EP2TXR_STAT_DISABLED (0)
|
||||
#define ST7_EP2TXR_STAT_STALL (ST7_EP2TXR_STAT_TX0)
|
||||
#define ST7_EP2TXR_STAT_VALID (ST7_EP2TXR_STAT_TX1 | ST7_EP2TXR_STAT_TX0)
|
||||
#define ST7_EP2TXR_STAT_NAK (ST7_EP2TXR_STAT_TX1)
|
||||
#define ST7_EP2TXR_DTOG_TX (1 << 2)
|
||||
#define ST7_EP2TXR_CTR_TX (1 << 3)
|
||||
|
||||
#define ST7_USB_BUF_EP0OUT (0x1550)
|
||||
#define ST7_USB_BUF_EP0IN (0x1560)
|
||||
#define ST7_USB_BUF_EP1OUT (0x1570)
|
||||
#define ST7_USB_BUF_EP1IN (0x1580)
|
||||
#define ST7_USB_BUF_EP2UODI (0x1590)
|
||||
#define ST7_USB_BUF_EP2UIDO (0x1650)
|
||||
|
||||
#define ST7_PA0 (1 << 0)
|
||||
#define ST7_PA1 (1 << 1)
|
||||
#define ST7_PA2 (1 << 2)
|
||||
#define ST7_PA3 (1 << 3)
|
||||
#define ST7_PA4 (1 << 4)
|
||||
#define ST7_PA5 (1 << 5)
|
||||
#define ST7_PA6 (1 << 6)
|
||||
#define ST7_PA7 (1 << 7)
|
||||
|
||||
#define ST7_PB0 (1 << 0)
|
||||
#define ST7_PB1 (1 << 1)
|
||||
#define ST7_PB2 (1 << 2)
|
||||
#define ST7_PB3 (1 << 3)
|
||||
#define ST7_PB4 (1 << 4)
|
||||
#define ST7_PB5 (1 << 5)
|
||||
#define ST7_PB6 (1 << 6)
|
||||
#define ST7_PB7 (1 << 7)
|
||||
|
||||
#define ST7_PC0 (1 << 0)
|
||||
#define ST7_PC1 (1 << 1)
|
||||
#define ST7_PC2 (1 << 2)
|
||||
#define ST7_PC3 (1 << 3)
|
||||
#define ST7_PC4 (1 << 4)
|
||||
#define ST7_PC5 (1 << 5)
|
||||
#define ST7_PC6 (1 << 6)
|
||||
#define ST7_PC7 (1 << 7)
|
||||
|
||||
#define ST7_PD0 (1 << 0)
|
||||
#define ST7_PD1 (1 << 1)
|
||||
#define ST7_PD2 (1 << 2)
|
||||
#define ST7_PD3 (1 << 3)
|
||||
#define ST7_PD4 (1 << 4)
|
||||
#define ST7_PD5 (1 << 5)
|
||||
#define ST7_PD6 (1 << 6)
|
||||
#define ST7_PD7 (1 << 7)
|
||||
|
||||
#define ST7_PE0 (1 << 0)
|
||||
#define ST7_PE1 (1 << 1)
|
||||
#define ST7_PE2 (1 << 2)
|
||||
#define ST7_PE3 (1 << 3)
|
||||
#define ST7_PE4 (1 << 4)
|
||||
#define ST7_PE5 (1 << 5)
|
||||
#define ST7_PE6 (1 << 6)
|
||||
#define ST7_PE7 (1 << 7)
|
||||
|
||||
#define ST7_PF0 (1 << 0)
|
||||
#define ST7_PF1 (1 << 1)
|
||||
#define ST7_PF2 (1 << 2)
|
||||
#define ST7_PF3 (1 << 3)
|
||||
#define ST7_PF4 (1 << 4)
|
||||
#define ST7_PF5 (1 << 5)
|
||||
#define ST7_PF6 (1 << 6)
|
||||
#define ST7_PF7 (1 << 7)
|
||||
61
src/jtag/drivers/usb_common.c
Normal file
61
src/jtag/drivers/usb_common.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "usb_common.h"
|
||||
|
||||
|
||||
static bool jtag_usb_match(struct usb_device *dev,
|
||||
const uint16_t vids[], const uint16_t pids[])
|
||||
{
|
||||
for (unsigned i = 0; vids[i] && pids[i]; i++)
|
||||
{
|
||||
if (dev->descriptor.idVendor == vids[i] &&
|
||||
dev->descriptor.idProduct == pids[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int jtag_usb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
struct usb_dev_handle **out)
|
||||
{
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
|
||||
struct usb_bus *busses = usb_get_busses();
|
||||
for (struct usb_bus *bus = busses; bus; bus = bus->next)
|
||||
{
|
||||
for (struct usb_device *dev = bus->devices; dev; dev = dev->next)
|
||||
{
|
||||
if (!jtag_usb_match(dev, vids, pids))
|
||||
continue;
|
||||
|
||||
*out = usb_open(dev);
|
||||
if (NULL == *out)
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
30
src/jtag/drivers/usb_common.h
Normal file
30
src/jtag/drivers/usb_common.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef JTAG_USB_COMMON_H
|
||||
#define JTAG_USB_COMMON_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include <usb.h>
|
||||
|
||||
int jtag_usb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
struct usb_dev_handle **out);
|
||||
|
||||
#endif // JTAG_USB_COMMON_H
|
||||
660
src/jtag/drivers/usbprog.c
Normal file
660
src/jtag/drivers/usbprog.c
Normal file
@@ -0,0 +1,660 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Benedikt Sauter *
|
||||
* sauter@ixbat.de *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* This file is based on Dominic Rath's amt_jtagaccel.c.
|
||||
*
|
||||
* usbprog is a free programming adapter. You can easily install
|
||||
* different firmware versions from an "online pool" over USB.
|
||||
* The adapter can be used for programming and debugging AVR and ARM
|
||||
* processors, as USB to RS232 converter, as JTAG interface or as
|
||||
* simple I/O interface (5 lines).
|
||||
*
|
||||
* http://www.embedded-projects.net/usbprog
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "interface.h"
|
||||
#include "commands.h"
|
||||
#include "usb_common.h"
|
||||
|
||||
|
||||
#define VID 0x1781
|
||||
#define PID 0x0c63
|
||||
|
||||
/* Pins at usbprog */
|
||||
#define TDO_BIT 0
|
||||
#define TDI_BIT 3
|
||||
#define TCK_BIT 2
|
||||
#define TMS_BIT 1
|
||||
|
||||
static void usbprog_end_state(tap_state_t state);
|
||||
static void usbprog_state_move(void);
|
||||
static void usbprog_path_move(struct pathmove_command *cmd);
|
||||
static void usbprog_runtest(int num_cycles);
|
||||
static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size);
|
||||
|
||||
#define UNKOWN_COMMAND 0x00
|
||||
#define PORT_DIRECTION 0x01
|
||||
#define PORT_SET 0x02
|
||||
#define PORT_GET 0x03
|
||||
#define PORT_SETBIT 0x04
|
||||
#define PORT_GETBIT 0x05
|
||||
#define WRITE_TDI 0x06
|
||||
#define READ_TDO 0x07
|
||||
#define WRITE_AND_READ 0x08
|
||||
#define WRITE_TMS 0x09
|
||||
#define WRITE_TMS_CHAIN 0x0A
|
||||
|
||||
struct usbprog_jtag
|
||||
{
|
||||
struct usb_dev_handle* usb_handle;
|
||||
};
|
||||
|
||||
static struct usbprog_jtag * usbprog_jtag_handle;
|
||||
|
||||
static struct usbprog_jtag* usbprog_jtag_open(void);
|
||||
//static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag);
|
||||
static void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag);
|
||||
static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen);
|
||||
|
||||
static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
|
||||
static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
|
||||
static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
|
||||
static void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan);
|
||||
|
||||
static char tms_chain[64];
|
||||
static int tms_chain_index;
|
||||
|
||||
static void usbprog_jtag_tms_collect(char tms_scan);
|
||||
static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag);
|
||||
|
||||
static void usbprog_write(int tck, int tms, int tdi);
|
||||
static void usbprog_reset(int trst, int srst);
|
||||
|
||||
static void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction);
|
||||
static void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value);
|
||||
//static unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag);
|
||||
static void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value);
|
||||
//static int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit);
|
||||
|
||||
static int usbprog_speed(int speed)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int usbprog_execute_queue(void)
|
||||
{
|
||||
struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
|
||||
int scan_size;
|
||||
enum scan_type type;
|
||||
uint8_t *buffer;
|
||||
|
||||
while (cmd)
|
||||
{
|
||||
switch (cmd->type)
|
||||
{
|
||||
case JTAG_RESET:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
#endif
|
||||
if (cmd->cmd.reset->trst == 1)
|
||||
{
|
||||
tap_set_state(TAP_RESET);
|
||||
}
|
||||
usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
|
||||
break;
|
||||
case JTAG_RUNTEST:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
|
||||
#endif
|
||||
usbprog_end_state(cmd->cmd.runtest->end_state);
|
||||
usbprog_runtest(cmd->cmd.runtest->num_cycles);
|
||||
break;
|
||||
case JTAG_STATEMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
|
||||
#endif
|
||||
usbprog_end_state(cmd->cmd.statemove->end_state);
|
||||
usbprog_state_move();
|
||||
break;
|
||||
case JTAG_PATHMOVE:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states,
|
||||
cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]);
|
||||
#endif
|
||||
usbprog_path_move(cmd->cmd.pathmove);
|
||||
break;
|
||||
case JTAG_SCAN:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("scan end in %i", cmd->cmd.scan->end_state);
|
||||
#endif
|
||||
usbprog_end_state(cmd->cmd.scan->end_state);
|
||||
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
|
||||
return ERROR_JTAG_QUEUE_FAILED;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("sleep %i", cmd->cmd.sleep->us);
|
||||
#endif
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int usbprog_init(void)
|
||||
{
|
||||
usbprog_jtag_handle = usbprog_jtag_open();
|
||||
|
||||
tms_chain_index = 0;
|
||||
if (usbprog_jtag_handle == 0)
|
||||
{
|
||||
LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions.");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
LOG_INFO("USB JTAG Interface ready!");
|
||||
|
||||
usbprog_jtag_init(usbprog_jtag_handle);
|
||||
usbprog_reset(0, 0);
|
||||
usbprog_write(0, 0, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int usbprog_quit(void)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*************** jtag execute commands **********************/
|
||||
static void usbprog_end_state(tap_state_t state)
|
||||
{
|
||||
if (tap_is_state_stable(state))
|
||||
tap_set_end_state(state);
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %i is not a valid end state", state);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void usbprog_state_move(void)
|
||||
{
|
||||
int i = 0, tms = 0;
|
||||
uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state());
|
||||
int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
|
||||
|
||||
usbprog_jtag_write_tms(usbprog_jtag_handle, (char)tms_scan);
|
||||
for (i = 0; i < tms_count; i++)
|
||||
{
|
||||
tms = (tms_scan >> i) & 1;
|
||||
}
|
||||
|
||||
tap_set_state(tap_get_end_state());
|
||||
}
|
||||
|
||||
static void usbprog_path_move(struct pathmove_command *cmd)
|
||||
{
|
||||
int num_states = cmd->num_states;
|
||||
int state_count;
|
||||
|
||||
/* There may be queued transitions, and before following a specified
|
||||
path, we must flush those queued transitions */
|
||||
usbprog_jtag_tms_send(usbprog_jtag_handle);
|
||||
|
||||
state_count = 0;
|
||||
while (num_states)
|
||||
{
|
||||
if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count])
|
||||
{
|
||||
/* LOG_INFO("1"); */
|
||||
usbprog_write(0, 0, 0);
|
||||
usbprog_write(1, 0, 0);
|
||||
}
|
||||
else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count])
|
||||
{
|
||||
/* LOG_INFO("2"); */
|
||||
usbprog_write(0, 1, 0);
|
||||
usbprog_write(1, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count]));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tap_set_state(cmd->path[state_count]);
|
||||
state_count++;
|
||||
num_states--;
|
||||
}
|
||||
|
||||
tap_set_end_state(tap_get_state());
|
||||
}
|
||||
|
||||
static void usbprog_runtest(int num_cycles)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* only do a state_move when we're not already in IDLE */
|
||||
if (tap_get_state() != TAP_IDLE)
|
||||
{
|
||||
usbprog_end_state(TAP_IDLE);
|
||||
usbprog_state_move();
|
||||
}
|
||||
|
||||
/* execute num_cycles */
|
||||
if (num_cycles > 0)
|
||||
{
|
||||
usbprog_jtag_tms_send(usbprog_jtag_handle);
|
||||
usbprog_write(0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
usbprog_jtag_tms_send(usbprog_jtag_handle);
|
||||
/* LOG_INFO("NUM CYCLES %i",num_cycles); */
|
||||
}
|
||||
|
||||
for (i = 0; i < num_cycles; i++)
|
||||
{
|
||||
usbprog_write(1, 0, 0);
|
||||
usbprog_write(0, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_JTAG_IO_
|
||||
LOG_DEBUG("runtest: cur_state %s end_state %s", tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state()));
|
||||
#endif
|
||||
|
||||
/* finish in end_state */
|
||||
/*
|
||||
usbprog_end_state(saved_end_state);
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
usbprog_state_move();
|
||||
*/
|
||||
}
|
||||
|
||||
static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size)
|
||||
{
|
||||
tap_state_t saved_end_state = tap_get_end_state();
|
||||
|
||||
if (ir_scan)
|
||||
usbprog_end_state(TAP_IRSHIFT);
|
||||
else
|
||||
usbprog_end_state(TAP_DRSHIFT);
|
||||
|
||||
/* Only move if we're not already there */
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
usbprog_state_move();
|
||||
|
||||
usbprog_end_state(saved_end_state);
|
||||
|
||||
usbprog_jtag_tms_send(usbprog_jtag_handle);
|
||||
|
||||
void (*f)(struct usbprog_jtag *usbprog_jtag, char * buffer, int size);
|
||||
switch (type) {
|
||||
case SCAN_OUT: f = &usbprog_jtag_write_tdi; break;
|
||||
case SCAN_IN: f = &usbprog_jtag_read_tdo; break;
|
||||
case SCAN_IO: f = &usbprog_jtag_write_and_read; break;
|
||||
default:
|
||||
LOG_ERROR("unknown scan type: %i", type);
|
||||
exit(-1);
|
||||
}
|
||||
f(usbprog_jtag_handle, (char *)buffer, scan_size);
|
||||
|
||||
/* The adapter does the transition to PAUSE internally */
|
||||
if (ir_scan)
|
||||
tap_set_state(TAP_IRPAUSE);
|
||||
else
|
||||
tap_set_state(TAP_DRPAUSE);
|
||||
|
||||
if (tap_get_state() != tap_get_end_state())
|
||||
usbprog_state_move();
|
||||
}
|
||||
|
||||
/*************** jtag wrapper functions *********************/
|
||||
|
||||
static void usbprog_write(int tck, int tms, int tdi)
|
||||
{
|
||||
unsigned char output_value = 0x00;
|
||||
|
||||
if (tms)
|
||||
output_value |= (1 << TMS_BIT);
|
||||
if (tdi)
|
||||
output_value |= (1 << TDI_BIT);
|
||||
if (tck)
|
||||
output_value |= (1 << TCK_BIT);
|
||||
|
||||
usbprog_jtag_write_slice(usbprog_jtag_handle,output_value);
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
static void usbprog_reset(int trst, int srst)
|
||||
{
|
||||
LOG_DEBUG("trst: %i, srst: %i", trst, srst);
|
||||
|
||||
if (trst)
|
||||
usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 0);
|
||||
else
|
||||
usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 1);
|
||||
|
||||
if (srst)
|
||||
usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 0);
|
||||
else
|
||||
usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 1);
|
||||
}
|
||||
|
||||
/*************** jtag lowlevel functions ********************/
|
||||
|
||||
struct usb_bus *busses;
|
||||
|
||||
struct usbprog_jtag* usbprog_jtag_open(void)
|
||||
{
|
||||
usb_set_debug(10);
|
||||
usb_init();
|
||||
|
||||
const uint16_t vids[] = { VID, 0 };
|
||||
const uint16_t pids[] = { PID, 0 };
|
||||
struct usb_dev_handle *dev;
|
||||
if (jtag_usb_open(vids, pids, &dev) != ERROR_OK)
|
||||
return NULL;
|
||||
|
||||
struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag));
|
||||
tmp->usb_handle = dev;
|
||||
|
||||
usb_set_configuration(dev, 1);
|
||||
usb_claim_interface(dev, 0);
|
||||
usb_set_altinterface(dev, 0);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag)
|
||||
{
|
||||
usb_close(usbprog_jtag->usb_handle);
|
||||
free(usbprog_jtag);
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen)
|
||||
{
|
||||
int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg,msglen, 100);
|
||||
if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \
|
||||
(msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9))
|
||||
return 1;
|
||||
if (res == msglen)
|
||||
{
|
||||
/* LOG_INFO("HALLLLOOO %i",(int)msg[0]); */
|
||||
res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100);
|
||||
if (res > 0)
|
||||
return (unsigned char)msg[1];
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag)
|
||||
{
|
||||
usbprog_jtag_set_direction(usbprog_jtag, 0xFE);
|
||||
}
|
||||
|
||||
static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
|
||||
{
|
||||
char tmp[64]; /* fastes packet size for usb controller */
|
||||
int send_bits, bufindex = 0, fillindex = 0, i, loops;
|
||||
|
||||
char swap;
|
||||
/* 61 byte can be transfered (488 bit) */
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
if (size > 488)
|
||||
{
|
||||
send_bits = 488;
|
||||
size = size - 488;
|
||||
loops = 61;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_bits = size;
|
||||
loops = size / 8;
|
||||
loops++;
|
||||
size = 0;
|
||||
}
|
||||
tmp[0] = WRITE_AND_READ;
|
||||
tmp[1] = (char)(send_bits >> 8); /* high */
|
||||
tmp[2] = (char)(send_bits); /* low */
|
||||
i = 0;
|
||||
|
||||
for (i = 0; i < loops; i++)
|
||||
{
|
||||
tmp[3 + i] = buffer[bufindex];
|
||||
bufindex++;
|
||||
}
|
||||
|
||||
if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64)
|
||||
{
|
||||
/* LOG_INFO("HALLLLOOO2 %i",(int)tmp[0]); */
|
||||
usleep(1);
|
||||
int timeout = 0;
|
||||
while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1)
|
||||
{
|
||||
timeout++;
|
||||
if (timeout > 10)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < loops; i++)
|
||||
{
|
||||
swap = tmp[3 + i];
|
||||
buffer[fillindex++] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
|
||||
{
|
||||
char tmp[64]; /* fastes packet size for usb controller */
|
||||
int send_bits, fillindex = 0, i, loops;
|
||||
|
||||
char swap;
|
||||
/* 61 byte can be transfered (488 bit) */
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
if (size > 488)
|
||||
{
|
||||
send_bits = 488;
|
||||
size = size - 488;
|
||||
loops = 61;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_bits = size;
|
||||
loops = size / 8;
|
||||
loops++;
|
||||
size = 0;
|
||||
}
|
||||
tmp[0] = WRITE_AND_READ;
|
||||
tmp[1] = (char)(send_bits >> 8); /* high */
|
||||
tmp[2] = (char)(send_bits); /* low */
|
||||
|
||||
usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000);
|
||||
|
||||
/* LOG_INFO("HALLLLOOO3 %i",(int)tmp[0]); */
|
||||
int timeout = 0;
|
||||
usleep(1);
|
||||
while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1)
|
||||
{
|
||||
timeout++;
|
||||
if (timeout > 10)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < loops; i++)
|
||||
{
|
||||
swap = tmp[3 + i];
|
||||
buffer[fillindex++] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char * buffer, int size)
|
||||
{
|
||||
char tmp[64]; /* fastes packet size for usb controller */
|
||||
int send_bits, bufindex = 0, i, loops;
|
||||
|
||||
/* 61 byte can be transfered (488 bit) */
|
||||
while (size > 0)
|
||||
{
|
||||
if (size > 488)
|
||||
{
|
||||
send_bits = 488;
|
||||
size = size - 488;
|
||||
loops = 61;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_bits = size;
|
||||
loops = size/8;
|
||||
/* if (loops == 0) */
|
||||
loops++;
|
||||
size = 0;
|
||||
}
|
||||
tmp[0] = WRITE_TDI;
|
||||
tmp[1] = (char)(send_bits >> 8); /* high */
|
||||
tmp[2] = (char)(send_bits); /* low */
|
||||
i = 0;
|
||||
|
||||
for (i = 0; i < loops; i++)
|
||||
{
|
||||
tmp[3 + i] = buffer[bufindex];
|
||||
bufindex++;
|
||||
}
|
||||
usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
static void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan)
|
||||
{
|
||||
usbprog_jtag_tms_collect(tms_scan);
|
||||
}
|
||||
|
||||
static void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction)
|
||||
{
|
||||
char tmp[2];
|
||||
tmp[0] = PORT_DIRECTION;
|
||||
tmp[1] = (char)direction;
|
||||
usbprog_jtag_message(usbprog_jtag, tmp, 2);
|
||||
}
|
||||
|
||||
static void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag,unsigned char value)
|
||||
{
|
||||
char tmp[2];
|
||||
tmp[0] = PORT_SET;
|
||||
tmp[1] = (char)value;
|
||||
usbprog_jtag_message(usbprog_jtag, tmp, 2);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag)
|
||||
{
|
||||
char tmp[2];
|
||||
tmp[0] = PORT_GET;
|
||||
tmp[1] = 0x00;
|
||||
return usbprog_jtag_message(usbprog_jtag, tmp, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag,int bit, int value)
|
||||
{
|
||||
char tmp[3];
|
||||
tmp[0] = PORT_SETBIT;
|
||||
tmp[1] = (char)bit;
|
||||
if (value == 1)
|
||||
tmp[2] = 0x01;
|
||||
else
|
||||
tmp[2] = 0x00;
|
||||
usbprog_jtag_message(usbprog_jtag, tmp, 3);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit)
|
||||
{
|
||||
char tmp[2];
|
||||
tmp[0] = PORT_GETBIT;
|
||||
tmp[1] = (char)bit;
|
||||
|
||||
if (usbprog_jtag_message(usbprog_jtag, tmp, 2) > 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usbprog_jtag_tms_collect(char tms_scan)
|
||||
{
|
||||
tms_chain[tms_chain_index] = tms_scan;
|
||||
tms_chain_index++;
|
||||
}
|
||||
|
||||
static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag)
|
||||
{
|
||||
int i;
|
||||
/* LOG_INFO("TMS SEND"); */
|
||||
if (tms_chain_index > 0)
|
||||
{
|
||||
char tmp[tms_chain_index + 2];
|
||||
tmp[0] = WRITE_TMS_CHAIN;
|
||||
tmp[1] = (char)(tms_chain_index);
|
||||
for (i = 0; i < tms_chain_index + 1; i++)
|
||||
tmp[2 + i] = tms_chain[i];
|
||||
usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000);
|
||||
tms_chain_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct jtag_interface usbprog_interface = {
|
||||
.name = "usbprog",
|
||||
.execute_queue = &usbprog_execute_queue,
|
||||
.speed = &usbprog_speed,
|
||||
.init = &usbprog_init,
|
||||
.quit = &usbprog_quit
|
||||
};
|
||||
1903
src/jtag/drivers/vsllink.c
Normal file
1903
src/jtag/drivers/vsllink.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user