From 865efd828a267992db0f2a92a731c5ce23a34236 Mon Sep 17 00:00:00 2001 From: Zachary T Welch Date: Wed, 2 Dec 2009 17:18:05 -0800 Subject: 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. --- src/jtag/Makefile.am | 68 +- src/jtag/amt_jtagaccel.c | 568 ----- src/jtag/arm-jtag-ew.c | 837 ------- src/jtag/at91rm9200.c | 292 --- src/jtag/bitbang.c | 325 --- src/jtag/bitbang.h | 39 - src/jtag/bitq.c | 397 ---- src/jtag/bitq.h | 46 - src/jtag/driver.c | 527 ----- src/jtag/drivers/Makefile.am | 74 + src/jtag/drivers/Makefile.rlink | 73 + src/jtag/drivers/amt_jtagaccel.c | 568 +++++ src/jtag/drivers/arm-jtag-ew.c | 837 +++++++ src/jtag/drivers/at91rm9200.c | 292 +++ src/jtag/drivers/bitbang.c | 325 +++ src/jtag/drivers/bitbang.h | 39 + src/jtag/drivers/bitq.c | 397 ++++ src/jtag/drivers/bitq.h | 46 + src/jtag/drivers/driver.c | 527 +++++ src/jtag/drivers/dummy.c | 177 ++ src/jtag/drivers/ep93xx.c | 230 ++ src/jtag/drivers/ft2232.c | 4021 ++++++++++++++++++++++++++++++++++ src/jtag/drivers/gw16012.c | 583 +++++ src/jtag/drivers/jlink.c | 1085 +++++++++ src/jtag/drivers/parport.c | 533 +++++ src/jtag/drivers/presto.c | 800 +++++++ src/jtag/drivers/rlink.c | 1812 +++++++++++++++ src/jtag/drivers/rlink.h | 31 + src/jtag/drivers/rlink_call.m4 | 485 ++++ src/jtag/drivers/rlink_dtc_cmd.h | 66 + src/jtag/drivers/rlink_ep1_cmd.h | 57 + src/jtag/drivers/rlink_init.m4 | 74 + src/jtag/drivers/rlink_speed_table.c | 101 + src/jtag/drivers/rlink_st7.h | 114 + src/jtag/drivers/usb_common.c | 61 + src/jtag/drivers/usb_common.h | 30 + src/jtag/drivers/usbprog.c | 660 ++++++ src/jtag/drivers/vsllink.c | 1903 ++++++++++++++++ src/jtag/dummy.c | 177 -- src/jtag/ep93xx.c | 230 -- src/jtag/ft2232.c | 4021 ---------------------------------- src/jtag/gw16012.c | 583 ----- src/jtag/jlink.c | 1085 --------- src/jtag/parport.c | 533 ----- src/jtag/presto.c | 800 ------- src/jtag/rlink/Makefile | 73 - src/jtag/rlink/call.m4 | 485 ---- src/jtag/rlink/dtc_cmd.h | 66 - src/jtag/rlink/ep1_cmd.h | 57 - src/jtag/rlink/init.m4 | 74 - src/jtag/rlink/rlink.c | 1812 --------------- src/jtag/rlink/rlink.h | 31 - src/jtag/rlink/rlink_speed_table.c | 101 - src/jtag/rlink/st7.h | 114 - src/jtag/usb_common.c | 61 - src/jtag/usb_common.h | 30 - src/jtag/usbprog.c | 660 ------ src/jtag/vsllink.c | 1903 ---------------- 58 files changed, 16008 insertions(+), 15988 deletions(-) delete mode 100644 src/jtag/amt_jtagaccel.c delete mode 100644 src/jtag/arm-jtag-ew.c delete mode 100644 src/jtag/at91rm9200.c delete mode 100644 src/jtag/bitbang.c delete mode 100644 src/jtag/bitbang.h delete mode 100644 src/jtag/bitq.c delete mode 100644 src/jtag/bitq.h delete mode 100644 src/jtag/driver.c create mode 100644 src/jtag/drivers/Makefile.am create mode 100644 src/jtag/drivers/Makefile.rlink create mode 100644 src/jtag/drivers/amt_jtagaccel.c create mode 100644 src/jtag/drivers/arm-jtag-ew.c create mode 100644 src/jtag/drivers/at91rm9200.c create mode 100644 src/jtag/drivers/bitbang.c create mode 100644 src/jtag/drivers/bitbang.h create mode 100644 src/jtag/drivers/bitq.c create mode 100644 src/jtag/drivers/bitq.h create mode 100644 src/jtag/drivers/driver.c create mode 100644 src/jtag/drivers/dummy.c create mode 100644 src/jtag/drivers/ep93xx.c create mode 100644 src/jtag/drivers/ft2232.c create mode 100644 src/jtag/drivers/gw16012.c create mode 100644 src/jtag/drivers/jlink.c create mode 100644 src/jtag/drivers/parport.c create mode 100644 src/jtag/drivers/presto.c create mode 100644 src/jtag/drivers/rlink.c create mode 100644 src/jtag/drivers/rlink.h create mode 100644 src/jtag/drivers/rlink_call.m4 create mode 100644 src/jtag/drivers/rlink_dtc_cmd.h create mode 100644 src/jtag/drivers/rlink_ep1_cmd.h create mode 100644 src/jtag/drivers/rlink_init.m4 create mode 100644 src/jtag/drivers/rlink_speed_table.c create mode 100644 src/jtag/drivers/rlink_st7.h create mode 100644 src/jtag/drivers/usb_common.c create mode 100644 src/jtag/drivers/usb_common.h create mode 100644 src/jtag/drivers/usbprog.c create mode 100644 src/jtag/drivers/vsllink.c delete mode 100644 src/jtag/dummy.c delete mode 100644 src/jtag/ep93xx.c delete mode 100644 src/jtag/ft2232.c delete mode 100644 src/jtag/gw16012.c delete mode 100644 src/jtag/jlink.c delete mode 100644 src/jtag/parport.c delete mode 100644 src/jtag/presto.c delete mode 100644 src/jtag/rlink/Makefile delete mode 100644 src/jtag/rlink/call.m4 delete mode 100644 src/jtag/rlink/dtc_cmd.h delete mode 100644 src/jtag/rlink/ep1_cmd.h delete mode 100644 src/jtag/rlink/init.m4 delete mode 100644 src/jtag/rlink/rlink.c delete mode 100644 src/jtag/rlink/rlink.h delete mode 100644 src/jtag/rlink/rlink_speed_table.c delete mode 100644 src/jtag/rlink/st7.h delete mode 100644 src/jtag/usb_common.c delete mode 100644 src/jtag/usb_common.h delete mode 100644 src/jtag/usbprog.c delete mode 100644 src/jtag/vsllink.c (limited to 'src') diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am index 5254a2b5..c735897e 100644 --- a/src/jtag/Makefile.am +++ b/src/jtag/Makefile.am @@ -5,7 +5,9 @@ AM_CPPFLAGS = \ METASOURCES = AUTO noinst_LTLIBRARIES = libjtag.la +SUBDIRS = DRIVERFILES = +libjtag_la_LIBADD = if MINIDRIVER @@ -20,63 +22,14 @@ endif else -# Standard Driver: common files -DRIVERFILES += driver.c commands.c +DRIVERFILES += commands.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/rlink.c rlink/rlink_speed_table.c -endif -if VSLLINK -DRIVERFILES += vsllink.c -endif -if ARMJTAGEW -DRIVERFILES += arm-jtag-ew.c -endif +SUBDIRS += drivers +libjtag_la_LIBADD += $(top_builddir)/src/jtag/drivers/libocdjtagdrivers.la endif # endif // MINIDRIVER - libjtag_la_SOURCES = \ core.c \ interface.c \ @@ -85,19 +38,12 @@ libjtag_la_SOURCES = \ $(DRIVERFILES) noinst_HEADERS = \ + commands.h \ interface.h \ interfaces.h \ - commands.h \ minidriver.h \ - bitbang.h \ jtag.h \ - bitq.h \ - rlink/dtc_cmd.h \ - rlink/ep1_cmd.h \ - rlink/rlink.h \ - rlink/st7.h \ - minidummy/jtag_minidriver.h \ - usb_common.h + minidummy/jtag_minidriver.h EXTRA_DIST = startup.tcl diff --git a/src/jtag/amt_jtagaccel.c b/src/jtag/amt_jtagaccel.c deleted file mode 100644 index d26482a6..00000000 --- a/src/jtag/amt_jtagaccel.c +++ /dev/null @@ -1,568 +0,0 @@ -/*************************************************************************** - * 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 -#include -#include -#else /* not PARPORT_USE_PPDEV */ -#ifndef _WIN32 -#include -#endif -#endif - -#if PARPORT_USE_GIVEIO == 1 -#if IS_CYGWIN == 1 -#include -#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 = "", - }, - { - .name = "parport_port", - .handler = &amt_jtagaccel_handle_rtck_command, - .mode = COMMAND_CONFIG, - .help = "enable RTCK", - .usage = "", - }, - 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, - }; diff --git a/src/jtag/arm-jtag-ew.c b/src/jtag/arm-jtag-ew.c deleted file mode 100644 index 46c31070..00000000 --- a/src/jtag/arm-jtag-ew.c +++ /dev/null @@ -1,837 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Dimitar Dimitrov * - * 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 -#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 - diff --git a/src/jtag/at91rm9200.c b/src/jtag/at91rm9200.c deleted file mode 100644 index ff9f7a41..00000000 --- a/src/jtag/at91rm9200.c +++ /dev/null @@ -1,292 +0,0 @@ -/*************************************************************************** - * 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 - - -/* 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; -} diff --git a/src/jtag/bitbang.c b/src/jtag/bitbang.c deleted file mode 100644 index 69c17298..00000000 --- a/src/jtag/bitbang.c +++ /dev/null @@ -1,325 +0,0 @@ -/*************************************************************************** - * 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; -} diff --git a/src/jtag/bitbang.h b/src/jtag/bitbang.h deleted file mode 100644 index db5c4cb8..00000000 --- a/src/jtag/bitbang.h +++ /dev/null @@ -1,39 +0,0 @@ -/*************************************************************************** - * 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 */ diff --git a/src/jtag/bitq.c b/src/jtag/bitq.c deleted file mode 100644 index 74555d2b..00000000 --- a/src/jtag/bitq.c +++ /dev/null @@ -1,397 +0,0 @@ -/*************************************************************************** -* 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; - } -} diff --git a/src/jtag/bitq.h b/src/jtag/bitq.h deleted file mode 100644 index 48b47db7..00000000 --- a/src/jtag/bitq.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************** - * 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 */ diff --git a/src/jtag/driver.c b/src/jtag/driver.c deleted file mode 100644 index cadd88e8..00000000 --- a/src/jtag/driver.c +++ /dev/null @@ -1,527 +0,0 @@ -/*************************************************************************** - * 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); -} - diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am new file mode 100644 index 00000000..0a007b4c --- /dev/null +++ b/src/jtag/drivers/Makefile.am @@ -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 diff --git a/src/jtag/drivers/Makefile.rlink b/src/jtag/drivers/Makefile.rlink new file mode 100644 index 00000000..94c53f50 --- /dev/null +++ b/src/jtag/drivers/Makefile.rlink @@ -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' diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c new file mode 100644 index 00000000..d26482a6 --- /dev/null +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -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 +#include +#include +#else /* not PARPORT_USE_PPDEV */ +#ifndef _WIN32 +#include +#endif +#endif + +#if PARPORT_USE_GIVEIO == 1 +#if IS_CYGWIN == 1 +#include +#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 = "", + }, + { + .name = "parport_port", + .handler = &amt_jtagaccel_handle_rtck_command, + .mode = COMMAND_CONFIG, + .help = "enable RTCK", + .usage = "", + }, + 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, + }; diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c new file mode 100644 index 00000000..46c31070 --- /dev/null +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -0,0 +1,837 @@ +/*************************************************************************** + * Copyright (C) 2009 by Dimitar Dimitrov * + * 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 +#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 + diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c new file mode 100644 index 00000000..ff9f7a41 --- /dev/null +++ b/src/jtag/drivers/at91rm9200.c @@ -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 + + +/* 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; +} diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c new file mode 100644 index 00000000..69c17298 --- /dev/null +++ b/src/jtag/drivers/bitbang.c @@ -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; +} diff --git a/src/jtag/drivers/bitbang.h b/src/jtag/drivers/bitbang.h new file mode 100644 index 00000000..db5c4cb8 --- /dev/null +++ b/src/jtag/drivers/bitbang.h @@ -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 */ diff --git a/src/jtag/drivers/bitq.c b/src/jtag/drivers/bitq.c new file mode 100644 index 00000000..74555d2b --- /dev/null +++ b/src/jtag/drivers/bitq.c @@ -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; + } +} diff --git a/src/jtag/drivers/bitq.h b/src/jtag/drivers/bitq.h new file mode 100644 index 00000000..48b47db7 --- /dev/null +++ b/src/jtag/drivers/bitq.h @@ -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 */ diff --git a/src/jtag/drivers/driver.c b/src/jtag/drivers/driver.c new file mode 100644 index 00000000..cadd88e8 --- /dev/null +++ b/src/jtag/drivers/driver.c @@ -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); +} + diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c new file mode 100644 index 00000000..c2beb092 --- /dev/null +++ b/src/jtag/drivers/dummy.c @@ -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, + }; diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c new file mode 100644 index 00000000..c679b216 --- /dev/null +++ b/src/jtag/drivers/ep93xx.c @@ -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 + +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; +} diff --git a/src/jtag/drivers/ft2232.c b/src/jtag/drivers/ft2232.c new file mode 100644 index 00000000..29b6389c --- /dev/null +++ b/src/jtag/drivers/ft2232.c @@ -0,0 +1,4021 @@ +/*************************************************************************** +* Copyright (C) 2009 by Øyvind Harboe * +* Øyvind Harboe * +* * +* Copyright (C) 2009 by SoftPLC Corporation. http://softplc.com * +* Dick Hollenbeck * +* * +* Copyright (C) 2004, 2006 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. * +***************************************************************************/ + +/* This code uses information contained in the MPSSE specification which was + * found here: + * http://www.ftdichip.com/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf + * Hereafter this is called the "MPSSE Spec". + * + * The datasheet for the ftdichip.com's FT2232D part is here: + * http://www.ftdichip.com/Documents/DataSheets/DS_FT2232D.pdf + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* project specific includes */ +#include "interface.h" +#include "commands.h" +#include "time_support.h" + +#if IS_CYGWIN == 1 +#include +#endif + +#include + +#if (BUILD_FT2232_FTD2XX == 1 && BUILD_FT2232_LIBFTDI == 1) +#error "BUILD_FT2232_FTD2XX && BUILD_FT2232_LIBFTDI are mutually exclusive" +#elif (BUILD_FT2232_FTD2XX != 1 && BUILD_FT2232_LIBFTDI != 1) +#error "BUILD_FT2232_FTD2XX || BUILD_FT2232_LIBFTDI must be chosen" +#endif + +/* FT2232 access library includes */ +#if BUILD_FT2232_FTD2XX == 1 +#include +#elif BUILD_FT2232_LIBFTDI == 1 +#include +#endif + +/* max TCK for the high speed devices 30000 kHz */ +#define FTDI_2232H_4232H_MAX_TCK 30000 +/* max TCK for the full speed devices 6000 kHz */ +#define FTDI_2232C_MAX_TCK 6000 +/* this speed value tells that RTCK is requested */ +#define RTCK_SPEED -1 + +/* + * On my Athlon XP 1900+ EHCI host with FT2232H JTAG dongle I get read timeout + * errors with a retry count of 100. Increasing it solves the problem for me. + * - Dimitar + * + * FIXME There's likely an issue with the usb_read_timeout from libftdi. + * Fix that (libusb? kernel? libftdi? here?) and restore the retry count + * to something sane. + */ +#define LIBFTDI_READ_RETRY_COUNT 2000 + +#ifndef BUILD_FT2232_HIGHSPEED + #if BUILD_FT2232_FTD2XX == 1 + enum { FT_DEVICE_2232H = 6, FT_DEVICE_4232H }; + #elif BUILD_FT2232_LIBFTDI == 1 + enum { TYPE_2232H = 4, TYPE_4232H = 5 }; + #endif +#endif + +/** + * Send out \a num_cycles on the TCK line while the TAP(s) are in a + * stable state. Calling code must ensure that current state is stable, + * that verification is not done in here. + * + * @param num_cycles The number of clocks cycles to send. + * @param cmd The command to send. + * + * @returns ERROR_OK on success, or ERROR_JTAG_QUEUE_FAILED on failure. + */ +static int ft2232_stableclocks(int num_cycles, struct jtag_command* cmd); + +static char * ft2232_device_desc_A = NULL; +static char* ft2232_device_desc = NULL; +static char* ft2232_serial = NULL; +static char* ft2232_layout = NULL; +static uint8_t ft2232_latency = 2; +static unsigned ft2232_max_tck = FTDI_2232C_MAX_TCK; + +#define MAX_USB_IDS 8 +/* vid = pid = 0 marks the end of the list */ +static uint16_t ft2232_vid[MAX_USB_IDS + 1] = { 0x0403, 0 }; +static uint16_t ft2232_pid[MAX_USB_IDS + 1] = { 0x6010, 0 }; + +struct ft2232_layout { + char* name; + int (*init)(void); + void (*reset)(int trst, int srst); + void (*blink)(void); +}; + +/* init procedures for supported layouts */ +static int usbjtag_init(void); +static int jtagkey_init(void); +static int olimex_jtag_init(void); +static int flyswatter_init(void); +static int turtle_init(void); +static int comstick_init(void); +static int stm32stick_init(void); +static int axm0432_jtag_init(void); +static int sheevaplug_init(void); +static int icebear_jtag_init(void); +static int cortino_jtag_init(void); +static int signalyzer_h_init(void); +static int ktlink_init(void); + +/* reset procedures for supported layouts */ +static void usbjtag_reset(int trst, int srst); +static void jtagkey_reset(int trst, int srst); +static void olimex_jtag_reset(int trst, int srst); +static void flyswatter_reset(int trst, int srst); +static void turtle_reset(int trst, int srst); +static void comstick_reset(int trst, int srst); +static void stm32stick_reset(int trst, int srst); +static void axm0432_jtag_reset(int trst, int srst); +static void sheevaplug_reset(int trst, int srst); +static void icebear_jtag_reset(int trst, int srst); +static void signalyzer_h_reset(int trst, int srst); +static void ktlink_reset(int trst, int srst); + +/* blink procedures for layouts that support a blinking led */ +static void olimex_jtag_blink(void); +static void flyswatter_jtag_blink(void); +static void turtle_jtag_blink(void); +static void signalyzer_h_blink(void); +static void ktlink_blink(void); + +static const struct ft2232_layout ft2232_layouts[] = +{ + { "usbjtag", usbjtag_init, usbjtag_reset, NULL }, + { "jtagkey", jtagkey_init, jtagkey_reset, NULL }, + { "jtagkey_prototype_v1", jtagkey_init, jtagkey_reset, NULL }, + { "oocdlink", jtagkey_init, jtagkey_reset, NULL }, + { "signalyzer", usbjtag_init, usbjtag_reset, NULL }, + { "evb_lm3s811", usbjtag_init, usbjtag_reset, NULL }, + { "luminary_icdi", usbjtag_init, usbjtag_reset, NULL }, + { "olimex-jtag", olimex_jtag_init, olimex_jtag_reset, olimex_jtag_blink }, + { "flyswatter", flyswatter_init, flyswatter_reset, flyswatter_jtag_blink }, + { "turtelizer2", turtle_init, turtle_reset, turtle_jtag_blink }, + { "comstick", comstick_init, comstick_reset, NULL }, + { "stm32stick", stm32stick_init, stm32stick_reset, NULL }, + { "axm0432_jtag", axm0432_jtag_init, axm0432_jtag_reset, NULL }, + { "sheevaplug", sheevaplug_init, sheevaplug_reset, NULL }, + { "icebear", icebear_jtag_init, icebear_jtag_reset, NULL }, + { "cortino", cortino_jtag_init, comstick_reset, NULL }, + { "signalyzer-h", signalyzer_h_init, signalyzer_h_reset, signalyzer_h_blink }, + { "ktlink", ktlink_init, ktlink_reset, ktlink_blink }, + { NULL, NULL, NULL, NULL }, +}; + +static uint8_t nTRST, nTRSTnOE, nSRST, nSRSTnOE; + +static const struct ft2232_layout *layout; +static uint8_t low_output = 0x0; +static uint8_t low_direction = 0x0; +static uint8_t high_output = 0x0; +static uint8_t high_direction = 0x0; + +#if BUILD_FT2232_FTD2XX == 1 +static FT_HANDLE ftdih = NULL; +static FT_DEVICE ftdi_device = 0; +#elif BUILD_FT2232_LIBFTDI == 1 +static struct ftdi_context ftdic; +static enum ftdi_chip_type ftdi_device; +#endif + +static struct jtag_command* first_unsent; /* next command that has to be sent */ +static int require_send; + +/* http://urjtag.wiki.sourceforge.net/Cable + FT2232 says: + + "There is a significant difference between libftdi and libftd2xx. The latter + one allows to schedule up to 64*64 bytes of result data while libftdi fails + with more than 4*64. As a consequence, the FT2232 driver is forced to + perform around 16x more USB transactions for long command streams with TDO + capture when running with libftdi." + + No idea how we get + #define FT2232_BUFFER_SIZE 131072 + a comment would have been nice. +*/ + +#define FT2232_BUFFER_SIZE 131072 + +static uint8_t* ft2232_buffer = NULL; +static int ft2232_buffer_size = 0; +static int ft2232_read_pointer = 0; +static int ft2232_expect_read = 0; + +/** + * Function buffer_write + * writes a byte into the byte buffer, "ft2232_buffer", which must be sent later. + * @param val is the byte to send. + */ +static inline void buffer_write(uint8_t val) +{ + assert(ft2232_buffer); + assert((unsigned) ft2232_buffer_size < (unsigned) FT2232_BUFFER_SIZE); + ft2232_buffer[ft2232_buffer_size++] = val; +} + +/** + * Function buffer_read + * returns a byte from the byte buffer. + */ +static inline uint8_t buffer_read(void) +{ + assert(ft2232_buffer); + assert(ft2232_read_pointer < ft2232_buffer_size); + return ft2232_buffer[ft2232_read_pointer++]; +} + +/** + * Clocks out \a bit_count bits on the TMS line, starting with the least + * significant bit of tms_bits and progressing to more significant bits. + * Rigorous state transition logging is done here via tap_set_state(). + * + * @param mpsse_cmd One of the MPSSE TMS oriented commands such as + * 0x4b or 0x6b. See the MPSSE spec referenced above for their + * functionality. The MPSSE command "Clock Data to TMS/CS Pin (no Read)" + * is often used for this, 0x4b. + * + * @param tms_bits Holds the sequence of bits to send. + * @param tms_count Tells how many bits in the sequence. + * @param tdi_bit A single bit to pass on to TDI before the first TCK + * cycle and held static for the duration of TMS clocking. + * + * See the MPSSE spec referenced above. + */ +static void clock_tms(uint8_t mpsse_cmd, int tms_bits, int tms_count, bool tdi_bit) +{ + uint8_t tms_byte; + int i; + int tms_ndx; /* bit index into tms_byte */ + + assert(tms_count > 0); + + DEBUG_JTAG_IO("mpsse cmd=%02x, tms_bits = 0x%08x, bit_count=%d", + mpsse_cmd, tms_bits, tms_count); + + for (tms_byte = tms_ndx = i = 0; i < tms_count; ++i, tms_bits>>=1) + { + bool bit = tms_bits & 1; + + if (bit) + tms_byte |= (1 << tms_ndx); + + /* always do state transitions in public view */ + tap_set_state(tap_state_transition(tap_get_state(), bit)); + + /* we wrote a bit to tms_byte just above, increment bit index. if bit was zero + also increment. + */ + ++tms_ndx; + + if (tms_ndx == 7 || i == tms_count-1) + { + buffer_write(mpsse_cmd); + buffer_write(tms_ndx - 1); + + /* Bit 7 of the byte is passed on to TDI/DO before the first TCK/SK of + TMS/CS and is held static for the duration of TMS/CS clocking. + */ + buffer_write(tms_byte | (tdi_bit << 7)); + } + } +} + +/** + * Function get_tms_buffer_requirements + * returns what clock_tms() will consume if called with + * same \a bit_count. + */ +static inline int get_tms_buffer_requirements(int bit_count) +{ + return ((bit_count + 6)/7) * 3; +} + +/** + * Function move_to_state + * moves the TAP controller from the current state to a + * \a goal_state through a path given by tap_get_tms_path(). State transition + * logging is performed by delegation to clock_tms(). + * + * @param goal_state is the destination state for the move. + */ +static void move_to_state(tap_state_t goal_state) +{ + tap_state_t start_state = tap_get_state(); + + /* goal_state is 1/2 of a tuple/pair of states which allow convenient + lookup of the required TMS pattern to move to this state from the + start state. + */ + + /* do the 2 lookups */ + int tms_bits = tap_get_tms_path(start_state, goal_state); + int tms_count = tap_get_tms_path_len(start_state, goal_state); + + DEBUG_JTAG_IO("start=%s goal=%s", tap_state_name(start_state), tap_state_name(goal_state)); + + clock_tms(0x4b, tms_bits, tms_count, 0); +} + +static int ft2232_write(uint8_t* buf, int size, uint32_t* bytes_written) +{ +#if BUILD_FT2232_FTD2XX == 1 + FT_STATUS status; + DWORD dw_bytes_written; + if ((status = FT_Write(ftdih, buf, size, &dw_bytes_written)) != FT_OK) + { + *bytes_written = dw_bytes_written; + LOG_ERROR("FT_Write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + else + { + *bytes_written = dw_bytes_written; + return ERROR_OK; + } +#elif BUILD_FT2232_LIBFTDI == 1 + int retval; + if ((retval = ftdi_write_data(&ftdic, buf, size)) < 0) + { + *bytes_written = 0; + LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + else + { + *bytes_written = retval; + return ERROR_OK; + } +#endif +} + +static int ft2232_read(uint8_t* buf, uint32_t size, uint32_t* bytes_read) +{ +#if BUILD_FT2232_FTD2XX == 1 + DWORD dw_bytes_read; + FT_STATUS status; + int timeout = 5; + *bytes_read = 0; + + while ((*bytes_read < size) && timeout--) + { + if ((status = FT_Read(ftdih, buf + *bytes_read, size - + *bytes_read, &dw_bytes_read)) != FT_OK) + { + *bytes_read = 0; + LOG_ERROR("FT_Read returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_read += dw_bytes_read; + } + +#elif BUILD_FT2232_LIBFTDI == 1 + int retval; + int timeout = LIBFTDI_READ_RETRY_COUNT; + *bytes_read = 0; + + while ((*bytes_read < size) && timeout--) + { + if ((retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read)) < 0) + { + *bytes_read = 0; + LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + *bytes_read += retval; + } + +#endif + + if (*bytes_read < size) + { + LOG_ERROR("couldn't read enough bytes from " + "FT2232 device (%i < %i)", + (unsigned)*bytes_read, + (unsigned)size); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static bool ft2232_device_is_highspeed(void) +{ +#if BUILD_FT2232_FTD2XX == 1 + return (ftdi_device == FT_DEVICE_2232H) || (ftdi_device == FT_DEVICE_4232H); +#elif BUILD_FT2232_LIBFTDI == 1 + return (ftdi_device == TYPE_2232H || ftdi_device == TYPE_4232H); +#endif +} + +/* + * Commands that only apply to the FT2232H and FT4232H devices. + * See chapter 6 in http://www.ftdichip.com/Documents/AppNotes/ + * AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf + */ + +static int ft2232h_ft4232h_adaptive_clocking(bool enable) +{ + uint8_t buf = enable ? 0x96 : 0x97; + LOG_DEBUG("%2.2x", buf); + + uint32_t bytes_written; + int retval = ft2232_write(&buf, 1, &bytes_written); + if ((ERROR_OK != retval) || (bytes_written != 1)) + { + LOG_ERROR("couldn't write command to %s adaptive clocking" + , enable ? "enable" : "disable"); + return retval; + } + + return ERROR_OK; +} + +/** + * Enable/disable the clk divide by 5 of the 60MHz master clock. + * This result in a JTAG clock speed range of 91.553Hz-6MHz + * respective 457.763Hz-30MHz. + */ +static int ft2232h_ft4232h_clk_divide_by_5(bool enable) +{ + uint32_t bytes_written; + uint8_t buf = enable ? 0x8b : 0x8a; + int retval = ft2232_write(&buf, 1, &bytes_written); + if ((ERROR_OK != retval) || (bytes_written != 1)) + { + LOG_ERROR("couldn't write command to %s clk divide by 5" + , enable ? "enable" : "disable"); + return ERROR_JTAG_INIT_FAILED; + } + ft2232_max_tck = enable ? FTDI_2232C_MAX_TCK : FTDI_2232H_4232H_MAX_TCK; + LOG_INFO("max TCK change to: %u kHz", ft2232_max_tck); + + return ERROR_OK; +} + +static int ft2232_speed(int speed) +{ + uint8_t buf[3]; + int retval; + uint32_t bytes_written; + + retval = ERROR_OK; + bool enable_adaptive_clocking = (RTCK_SPEED == speed); + if (ft2232_device_is_highspeed()) + retval = ft2232h_ft4232h_adaptive_clocking(enable_adaptive_clocking); + else if (enable_adaptive_clocking) + { + LOG_ERROR("ft2232 device %lu does not support RTCK" + , (long unsigned int)ftdi_device); + return ERROR_FAIL; + } + + if ((enable_adaptive_clocking) || (ERROR_OK != retval)) + return retval; + + buf[0] = 0x86; /* command "set divisor" */ + buf[1] = speed & 0xff; /* valueL (0 = 6MHz, 1 = 3MHz, 2 = 2.0MHz, ...*/ + buf[2] = (speed >> 8) & 0xff; /* valueH */ + + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + if (((retval = ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't set FT2232 TCK speed"); + return retval; + } + + return ERROR_OK; +} + +static int ft2232_speed_div(int speed, int* khz) +{ + /* Take a look in the FT2232 manual, + * AN2232C-01 Command Processor for + * MPSSE and MCU Host Bus. Chapter 3.8 */ + + *khz = (RTCK_SPEED == speed) ? 0 : ft2232_max_tck / (1 + speed); + + return ERROR_OK; +} + +static int ft2232_khz(int khz, int* jtag_speed) +{ + if (khz == 0) + { + if (ft2232_device_is_highspeed()) + { + *jtag_speed = RTCK_SPEED; + return ERROR_OK; + } + else + { + LOG_DEBUG("RCLK not supported"); + return ERROR_FAIL; + } + } + + /* Take a look in the FT2232 manual, + * AN2232C-01 Command Processor for + * MPSSE and MCU Host Bus. Chapter 3.8 + * + * We will calc here with a multiplier + * of 10 for better rounding later. */ + + /* Calc speed, (ft2232_max_tck / khz) - 1 */ + /* Use 65000 for better rounding */ + *jtag_speed = ((ft2232_max_tck*10) / khz) - 10; + + /* Add 0.9 for rounding */ + *jtag_speed += 9; + + /* Calc real speed */ + *jtag_speed = *jtag_speed / 10; + + /* Check if speed is greater than 0 */ + if (*jtag_speed < 0) + { + *jtag_speed = 0; + } + + /* Check max value */ + if (*jtag_speed > 0xFFFF) + { + *jtag_speed = 0xFFFF; + } + + return ERROR_OK; +} + +static void ft2232_end_state(tap_state_t state) +{ + if (tap_is_state_stable(state)) + tap_set_end_state(state); + else + { + LOG_ERROR("BUG: %s is not a stable end state", tap_state_name(state)); + exit(-1); + } +} + +static void ft2232_read_scan(enum scan_type type, uint8_t* buffer, int scan_size) +{ + int num_bytes = (scan_size + 7) / 8; + int bits_left = scan_size; + int cur_byte = 0; + + while (num_bytes-- > 1) + { + buffer[cur_byte++] = buffer_read(); + bits_left -= 8; + } + + buffer[cur_byte] = 0x0; + + /* There is one more partial byte left from the clock data in/out instructions */ + if (bits_left > 1) + { + buffer[cur_byte] = buffer_read() >> 1; + } + /* This shift depends on the length of the clock data to tms instruction, insterted at end of the scan, now fixed to a two step transition in ft2232_add_scan */ + buffer[cur_byte] = (buffer[cur_byte] | (((buffer_read()) << 1) & 0x80)) >> (8 - bits_left); +} + +static void ft2232_debug_dump_buffer(void) +{ + int i; + char line[256]; + char* line_p = line; + + for (i = 0; i < ft2232_buffer_size; i++) + { + line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ft2232_buffer[i]); + if (i % 16 == 15) + { + LOG_DEBUG("%s", line); + line_p = line; + } + } + + if (line_p != line) + LOG_DEBUG("%s", line); +} + +static int ft2232_send_and_recv(struct jtag_command* first, struct jtag_command* last) +{ + struct jtag_command* cmd; + uint8_t* buffer; + int scan_size; + enum scan_type type; + int retval; + uint32_t bytes_written = 0; + uint32_t bytes_read = 0; + +#ifdef _DEBUG_USB_IO_ + struct timeval start, inter, inter2, end; + struct timeval d_inter, d_inter2, d_end; +#endif + +#ifdef _DEBUG_USB_COMMS_ + LOG_DEBUG("write buffer (size %i):", ft2232_buffer_size); + ft2232_debug_dump_buffer(); +#endif + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&start, NULL); +#endif + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + LOG_ERROR("couldn't write MPSSE commands to FT2232"); + return retval; + } + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&inter, NULL); +#endif + + if (ft2232_expect_read) + { + /* FIXME this "timeout" is never changed ... */ + int timeout = LIBFTDI_READ_RETRY_COUNT; + ft2232_buffer_size = 0; + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&inter2, NULL); +#endif + + if ((retval = ft2232_read(ft2232_buffer, ft2232_expect_read, &bytes_read)) != ERROR_OK) + { + LOG_ERROR("couldn't read from FT2232"); + return retval; + } + +#ifdef _DEBUG_USB_IO_ + gettimeofday(&end, NULL); + + timeval_subtract(&d_inter, &inter, &start); + timeval_subtract(&d_inter2, &inter2, &start); + timeval_subtract(&d_end, &end, &start); + + LOG_INFO("inter: %u.%06u, inter2: %u.%06u end: %u.%06u", + (unsigned)d_inter.tv_sec, (unsigned)d_inter.tv_usec, + (unsigned)d_inter2.tv_sec, (unsigned)d_inter2.tv_usec, + (unsigned)d_end.tv_sec, (unsigned)d_end.tv_usec); +#endif + + ft2232_buffer_size = bytes_read; + + if (ft2232_expect_read != ft2232_buffer_size) + { + LOG_ERROR("ft2232_expect_read (%i) != " + "ft2232_buffer_size (%i) " + "(%i retries)", + ft2232_expect_read, + ft2232_buffer_size, + LIBFTDI_READ_RETRY_COUNT - timeout); + ft2232_debug_dump_buffer(); + + exit(-1); + } + +#ifdef _DEBUG_USB_COMMS_ + LOG_DEBUG("read buffer (%i retries): %i bytes", + LIBFTDI_READ_RETRY_COUNT - timeout, + ft2232_buffer_size); + ft2232_debug_dump_buffer(); +#endif + } + + ft2232_expect_read = 0; + ft2232_read_pointer = 0; + + /* 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; + + cmd = first; + while (cmd != last) + { + switch (cmd->type) + { + case JTAG_SCAN: + type = jtag_scan_type(cmd->cmd.scan); + if (type != SCAN_OUT) + { + scan_size = jtag_scan_size(cmd->cmd.scan); + buffer = calloc(DIV_ROUND_UP(scan_size, 8), 1); + ft2232_read_scan(type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + } + break; + + default: + break; + } + + cmd = cmd->next; + } + + ft2232_buffer_size = 0; + + return retval; +} + +/** + * Function ft2232_add_pathmove + * moves the TAP controller from the current state to a new state through the + * given path, where path is an array of tap_state_t's. + * + * @param path is an array of tap_stat_t which gives the states to traverse through + * ending with the last state at path[num_states-1] + * @param num_states is the count of state steps to move through + */ +static void ft2232_add_pathmove(tap_state_t* path, int num_states) +{ + int state_count = 0; + + assert((unsigned) num_states <= 32u); /* tms_bits only holds 32 bits */ + + DEBUG_JTAG_IO("-"); + + /* this loop verifies that the path is legal and logs each state in the path */ + while (num_states) + { + unsigned char tms_byte = 0; /* zero this on each MPSSE batch */ + int bit_count = 0; + int num_states_batch = num_states > 7 ? 7 : num_states; + + /* command "Clock Data to TMS/CS Pin (no Read)" */ + buffer_write(0x4b); + + /* number of states remaining */ + buffer_write(num_states_batch - 1); + + while (num_states_batch--) { + /* either TMS=0 or TMS=1 must work ... */ + if (tap_state_transition(tap_get_state(), false) + == path[state_count]) + buf_set_u32(&tms_byte, bit_count++, 1, 0x0); + else if (tap_state_transition(tap_get_state(), true) + == path[state_count]) + buf_set_u32(&tms_byte, bit_count++, 1, 0x1); + + /* ... or else the caller goofed BADLY */ + else { + LOG_ERROR("BUG: %s -> %s isn't a valid " + "TAP state transition", + tap_state_name(tap_get_state()), + tap_state_name(path[state_count])); + exit(-1); + } + + tap_set_state(path[state_count]); + state_count++; + num_states--; + } + + buffer_write(tms_byte); + } + tap_set_end_state(tap_get_state()); +} + +static void ft2232_add_scan(bool ir_scan, enum scan_type type, uint8_t* buffer, int scan_size) +{ + int num_bytes = (scan_size + 7) / 8; + int bits_left = scan_size; + int cur_byte = 0; + int last_bit; + + if (!ir_scan) + { + if (tap_get_state() != TAP_DRSHIFT) + { + move_to_state(TAP_DRSHIFT); + } + } + else + { + if (tap_get_state() != TAP_IRSHIFT) + { + move_to_state(TAP_IRSHIFT); + } + } + + /* add command for complete bytes */ + while (num_bytes > 1) + { + int thisrun_bytes; + if (type == SCAN_IO) + { + /* Clock Data Bytes In and Out LSB First */ + buffer_write(0x39); + /* LOG_DEBUG("added TDI bytes (io %i)", num_bytes); */ + } + else if (type == SCAN_OUT) + { + /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ + buffer_write(0x19); + /* LOG_DEBUG("added TDI bytes (o)"); */ + } + else if (type == SCAN_IN) + { + /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ + buffer_write(0x28); + /* LOG_DEBUG("added TDI bytes (i %i)", num_bytes); */ + } + + thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); + num_bytes -= thisrun_bytes; + + buffer_write((uint8_t) (thisrun_bytes - 1)); + buffer_write((uint8_t) ((thisrun_bytes - 1) >> 8)); + + if (type != SCAN_IN) + { + /* add complete bytes */ + while (thisrun_bytes-- > 0) + { + buffer_write(buffer[cur_byte++]); + bits_left -= 8; + } + } + else /* (type == SCAN_IN) */ + { + bits_left -= 8 * (thisrun_bytes); + } + } + + /* the most signifcant bit is scanned during TAP movement */ + if (type != SCAN_IN) + last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; + else + last_bit = 0; + + /* process remaining bits but the last one */ + if (bits_left > 1) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + buffer_write(0x3b); + /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + buffer_write(0x1b); + /* LOG_DEBUG("added TDI bits (o)"); */ + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + buffer_write(0x2a); + /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ + } + + buffer_write(bits_left - 2); + if (type != SCAN_IN) + buffer_write(buffer[cur_byte]); + } + + if ((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) + || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT))) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + buffer_write(0x3b); + /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + buffer_write(0x1b); + /* LOG_DEBUG("added TDI bits (o)"); */ + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + buffer_write(0x2a); + /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ + } + buffer_write(0x0); + buffer_write(last_bit); + } + else + { + int tms_bits; + int tms_count; + uint8_t mpsse_cmd; + + /* move from Shift-IR/DR to end state */ + if (type != SCAN_OUT) + { + /* We always go to the PAUSE state in two step at the end of an IN or IO scan */ + /* This must be coordinated with the bit shifts in ft2232_read_scan */ + tms_bits = 0x01; + tms_count = 2; + /* Clock Data to TMS/CS Pin with Read */ + mpsse_cmd = 0x6b; + } + else + { + tms_bits = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + /* Clock Data to TMS/CS Pin (no Read) */ + mpsse_cmd = 0x4b; + } + + DEBUG_JTAG_IO("finish %s", (type == SCAN_OUT) ? "without read" : "via PAUSE"); + clock_tms(mpsse_cmd, tms_bits, tms_count, last_bit); + } + + if (tap_get_state() != tap_get_end_state()) + { + move_to_state(tap_get_end_state()); + } +} + +static int ft2232_large_scan(struct scan_command* cmd, enum scan_type type, uint8_t* buffer, int scan_size) +{ + int num_bytes = (scan_size + 7) / 8; + int bits_left = scan_size; + int cur_byte = 0; + int last_bit; + uint8_t* receive_buffer = malloc(DIV_ROUND_UP(scan_size, 8)); + uint8_t* receive_pointer = receive_buffer; + uint32_t bytes_written; + uint32_t bytes_read; + int retval; + int thisrun_read = 0; + + if (cmd->ir_scan) + { + LOG_ERROR("BUG: large IR scans are not supported"); + exit(-1); + } + + if (tap_get_state() != TAP_DRSHIFT) + { + move_to_state(TAP_DRSHIFT); + } + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + LOG_ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", + ft2232_buffer_size, (int)bytes_written); + ft2232_buffer_size = 0; + + /* add command for complete bytes */ + while (num_bytes > 1) + { + int thisrun_bytes; + + if (type == SCAN_IO) + { + /* Clock Data Bytes In and Out LSB First */ + buffer_write(0x39); + /* LOG_DEBUG("added TDI bytes (io %i)", num_bytes); */ + } + else if (type == SCAN_OUT) + { + /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ + buffer_write(0x19); + /* LOG_DEBUG("added TDI bytes (o)"); */ + } + else if (type == SCAN_IN) + { + /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ + buffer_write(0x28); + /* LOG_DEBUG("added TDI bytes (i %i)", num_bytes); */ + } + + thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); + thisrun_read = thisrun_bytes; + num_bytes -= thisrun_bytes; + buffer_write((uint8_t) (thisrun_bytes - 1)); + buffer_write((uint8_t) ((thisrun_bytes - 1) >> 8)); + + if (type != SCAN_IN) + { + /* add complete bytes */ + while (thisrun_bytes-- > 0) + { + buffer_write(buffer[cur_byte]); + cur_byte++; + bits_left -= 8; + } + } + else /* (type == SCAN_IN) */ + { + bits_left -= 8 * (thisrun_bytes); + } + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + LOG_ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", + ft2232_buffer_size, + (int)bytes_written); + ft2232_buffer_size = 0; + + if (type != SCAN_OUT) + { + if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) + { + LOG_ERROR("couldn't read from FT2232"); + exit(-1); + } + LOG_DEBUG("thisrun_read: %i, bytes_read: %i", + thisrun_read, + (int)bytes_read); + receive_pointer += bytes_read; + } + } + + thisrun_read = 0; + + /* the most signifcant bit is scanned during TAP movement */ + if (type != SCAN_IN) + last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; + else + last_bit = 0; + + /* process remaining bits but the last one */ + if (bits_left > 1) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + buffer_write(0x3b); + /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + buffer_write(0x1b); + /* LOG_DEBUG("added TDI bits (o)"); */ + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + buffer_write(0x2a); + /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ + } + buffer_write(bits_left - 2); + if (type != SCAN_IN) + buffer_write(buffer[cur_byte]); + + if (type != SCAN_OUT) + thisrun_read += 2; + } + + if (tap_get_end_state() == TAP_DRSHIFT) + { + if (type == SCAN_IO) + { + /* Clock Data Bits In and Out LSB First */ + buffer_write(0x3b); + /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ + } + else if (type == SCAN_OUT) + { + /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ + buffer_write(0x1b); + /* LOG_DEBUG("added TDI bits (o)"); */ + } + else if (type == SCAN_IN) + { + /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ + buffer_write(0x2a); + /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ + } + buffer_write(0x0); + buffer_write(last_bit); + } + else + { + int tms_bits = 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()); + uint8_t mpsse_cmd; + + /* move from Shift-IR/DR to end state */ + if (type != SCAN_OUT) + { + /* Clock Data to TMS/CS Pin with Read */ + mpsse_cmd = 0x6b; + /* LOG_DEBUG("added TMS scan (read)"); */ + } + else + { + /* Clock Data to TMS/CS Pin (no Read) */ + mpsse_cmd = 0x4b; + /* LOG_DEBUG("added TMS scan (no read)"); */ + } + + DEBUG_JTAG_IO("finish, %s", (type == SCAN_OUT) ? "no read" : "read"); + clock_tms(mpsse_cmd, tms_bits, tms_count, last_bit); + } + + if (type != SCAN_OUT) + thisrun_read += 1; + + if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) + { + LOG_ERROR("couldn't write MPSSE commands to FT2232"); + exit(-1); + } + LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", + ft2232_buffer_size, + (int)bytes_written); + ft2232_buffer_size = 0; + + if (type != SCAN_OUT) + { + if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) + { + LOG_ERROR("couldn't read from FT2232"); + exit(-1); + } + LOG_DEBUG("thisrun_read: %i, bytes_read: %i", + thisrun_read, + (int)bytes_read); + receive_pointer += bytes_read; + } + + return ERROR_OK; +} + +static int ft2232_predict_scan_out(int scan_size, enum scan_type type) +{ + int predicted_size = 3; + int num_bytes = (scan_size - 1) / 8; + + if (tap_get_state() != TAP_DRSHIFT) + predicted_size += get_tms_buffer_requirements(tap_get_tms_path_len(tap_get_state(), TAP_DRSHIFT)); + + if (type == SCAN_IN) /* only from device to host */ + { + /* complete bytes */ + predicted_size += DIV_ROUND_UP(num_bytes, 65536) * 3; + + /* remaining bits - 1 (up to 7) */ + predicted_size += ((scan_size - 1) % 8) ? 2 : 0; + } + else /* host to device, or bidirectional */ + { + /* complete bytes */ + predicted_size += num_bytes + DIV_ROUND_UP(num_bytes, 65536) * 3; + + /* remaining bits -1 (up to 7) */ + predicted_size += ((scan_size - 1) % 8) ? 3 : 0; + } + + return predicted_size; +} + +static int ft2232_predict_scan_in(int scan_size, enum scan_type type) +{ + int predicted_size = 0; + + if (type != SCAN_OUT) + { + /* complete bytes */ + predicted_size += (DIV_ROUND_UP(scan_size, 8) > 1) ? (DIV_ROUND_UP(scan_size, 8) - 1) : 0; + + /* remaining bits - 1 */ + predicted_size += ((scan_size - 1) % 8) ? 1 : 0; + + /* last bit (from TMS scan) */ + predicted_size += 1; + } + + /* LOG_DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size); */ + + return predicted_size; +} + +static void usbjtag_reset(int trst, int srst) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (trst == 1) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + low_direction |= nTRSTnOE; /* switch to output pin (output is low) */ + else + low_output &= ~nTRST; /* switch output low */ + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal and external pullup) */ + else + low_output |= nTRST; /* switch output high */ + } + + if (srst == 1) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + low_output &= ~nSRST; /* switch output low */ + else + low_direction |= nSRSTnOE; /* switch to output pin (output is low) */ + } + else if (srst == 0) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + low_output |= nSRST; /* switch output high */ + else + low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */ + } + + /* command "set data bits low byte" */ + buffer_write(0x80); + buffer_write(low_output); + buffer_write(low_direction); +} + +static void jtagkey_reset(int trst, int srst) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (trst == 1) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output &= ~nTRSTnOE; + else + high_output &= ~nTRST; + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output |= nTRSTnOE; + else + high_output |= nTRST; + } + + if (srst == 1) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output &= ~nSRST; + else + high_output &= ~nSRSTnOE; + } + else if (srst == 0) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output |= nSRST; + else + high_output |= nSRSTnOE; + } + + /* command "set data bits high byte" */ + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); + LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, + high_direction); +} + +static void olimex_jtag_reset(int trst, int srst) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (trst == 1) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output &= ~nTRSTnOE; + else + high_output &= ~nTRST; + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output |= nTRSTnOE; + else + high_output |= nTRST; + } + + if (srst == 1) + { + high_output |= nSRST; + } + else if (srst == 0) + { + high_output &= ~nSRST; + } + + /* command "set data bits high byte" */ + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); + LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, + high_direction); +} + +static void axm0432_jtag_reset(int trst, int srst) +{ + if (trst == 1) + { + tap_set_state(TAP_RESET); + high_output &= ~nTRST; + } + else if (trst == 0) + { + high_output |= nTRST; + } + + if (srst == 1) + { + high_output &= ~nSRST; + } + else if (srst == 0) + { + high_output |= nSRST; + } + + /* command "set data bits low byte" */ + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); + LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, + high_direction); +} + +static void flyswatter_reset(int trst, int srst) +{ + if (trst == 1) + { + low_output &= ~nTRST; + } + else if (trst == 0) + { + low_output |= nTRST; + } + + if (srst == 1) + { + low_output |= nSRST; + } + else if (srst == 0) + { + low_output &= ~nSRST; + } + + /* command "set data bits low byte" */ + buffer_write(0x80); + buffer_write(low_output); + buffer_write(low_direction); + LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); +} + +static void turtle_reset(int trst, int srst) +{ + trst = trst; + + if (srst == 1) + { + low_output |= nSRST; + } + else if (srst == 0) + { + low_output &= ~nSRST; + } + + /* command "set data bits low byte" */ + buffer_write(0x80); + buffer_write(low_output); + buffer_write(low_direction); + LOG_DEBUG("srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", srst, low_output, low_direction); +} + +static void comstick_reset(int trst, int srst) +{ + if (trst == 1) + { + high_output &= ~nTRST; + } + else if (trst == 0) + { + high_output |= nTRST; + } + + if (srst == 1) + { + high_output &= ~nSRST; + } + else if (srst == 0) + { + high_output |= nSRST; + } + + /* command "set data bits high byte" */ + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); + LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, + high_direction); +} + +static void stm32stick_reset(int trst, int srst) +{ + if (trst == 1) + { + high_output &= ~nTRST; + } + else if (trst == 0) + { + high_output |= nTRST; + } + + if (srst == 1) + { + low_output &= ~nSRST; + } + else if (srst == 0) + { + low_output |= nSRST; + } + + /* command "set data bits low byte" */ + buffer_write(0x80); + buffer_write(low_output); + buffer_write(low_direction); + + /* command "set data bits high byte" */ + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); + LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, + high_direction); +} + +static void sheevaplug_reset(int trst, int srst) +{ + if (trst == 1) + high_output &= ~nTRST; + else if (trst == 0) + high_output |= nTRST; + + if (srst == 1) + high_output &= ~nSRSTnOE; + else if (srst == 0) + high_output |= nSRSTnOE; + + /* command "set data bits high byte" */ + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); + LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); +} + +static int ft2232_execute_runtest(struct jtag_command *cmd) +{ + int retval; + int i; + int predicted_size = 0; + retval = ERROR_OK; + + DEBUG_JTAG_IO("runtest %i cycles, end in %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 0; + if (tap_get_state() != TAP_IDLE) + predicted_size += 3; + predicted_size += 3 * DIV_ROUND_UP(cmd->cmd.runtest->num_cycles, 7); + if (cmd->cmd.runtest->end_state != TAP_IDLE) + predicted_size += 3; + if (tap_get_end_state() != TAP_IDLE) + predicted_size += 3; + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + if (tap_get_state() != TAP_IDLE) + { + move_to_state(TAP_IDLE); + require_send = 1; + } + i = cmd->cmd.runtest->num_cycles; + while (i > 0) + { + /* there are no state transitions in this code, so omit state tracking */ + + /* command "Clock Data to TMS/CS Pin (no Read)" */ + buffer_write(0x4b); + + /* scan 7 bits */ + buffer_write((i > 7) ? 6 : (i - 1)); + + /* TMS data bits */ + buffer_write(0x0); + + i -= (i > 7) ? 7 : i; + /* LOG_DEBUG("added TMS scan (no read)"); */ + } + + ft2232_end_state(cmd->cmd.runtest->end_state); + + if (tap_get_state() != tap_get_end_state()) + { + move_to_state(tap_get_end_state()); + } + + require_send = 1; + DEBUG_JTAG_IO("runtest: %i, end in %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(tap_get_end_state())); + return retval; +} + +static int ft2232_execute_statemove(struct jtag_command *cmd) +{ + int predicted_size = 0; + int retval = ERROR_OK; + + DEBUG_JTAG_IO("statemove end in %s", + tap_state_name(cmd->cmd.statemove->end_state)); + + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 3; + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + ft2232_end_state(cmd->cmd.statemove->end_state); + + /* For TAP_RESET, ignore the current recorded state. It's often + * wrong at server startup, and this transation is critical whenever + * it's requested. + */ + if (tap_get_end_state() == TAP_RESET) { + clock_tms(0x4b, 0xff, 5, 0); + require_send = 1; + + /* shortest-path move to desired end state */ + } else if (tap_get_state() != tap_get_end_state()) + { + move_to_state(tap_get_end_state()); + require_send = 1; + } + + return retval; +} + +static int ft2232_execute_pathmove(struct jtag_command *cmd) +{ + int predicted_size = 0; + int retval = ERROR_OK; + + tap_state_t* path = cmd->cmd.pathmove->path; + int num_states = cmd->cmd.pathmove->num_states; + + DEBUG_JTAG_IO("pathmove: %i states, current: %s end: %s", num_states, + tap_state_name(tap_get_state()), + tap_state_name(path[num_states-1])); + + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 3 * DIV_ROUND_UP(num_states, 7); + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + + require_send = 0; + first_unsent = cmd; + } + + ft2232_add_pathmove(path, num_states); + require_send = 1; + + return retval; +} + +static int ft2232_execute_scan(struct jtag_command *cmd) +{ + uint8_t* buffer; + int scan_size; /* size of IR or DR scan */ + int predicted_size = 0; + int retval = ERROR_OK; + + enum scan_type type = jtag_scan_type(cmd->cmd.scan); + + DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", type); + + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + + predicted_size = ft2232_predict_scan_out(scan_size, type); + if ((predicted_size + 1) > FT2232_BUFFER_SIZE) + { + LOG_DEBUG("oversized ft2232 scan (predicted_size > FT2232_BUFFER_SIZE)"); + /* unsent commands before this */ + if (first_unsent != cmd) + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + + /* current command */ + ft2232_end_state(cmd->cmd.scan->end_state); + ft2232_large_scan(cmd->cmd.scan, type, buffer, scan_size); + require_send = 0; + first_unsent = cmd->next; + if (buffer) + free(buffer); + return retval; + } + else if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + LOG_DEBUG("ft2232 buffer size reached, sending queued commands (first_unsent: %p, cmd: %p)", + first_unsent, + cmd); + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + ft2232_expect_read += ft2232_predict_scan_in(scan_size, type); + /* LOG_DEBUG("new read size: %i", ft2232_expect_read); */ + ft2232_end_state(cmd->cmd.scan->end_state); + ft2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + require_send = 1; + if (buffer) + free(buffer); + DEBUG_JTAG_IO("%s scan, %i bits, end in %s", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, + tap_state_name(tap_get_end_state())); + return retval; + +} + +static int ft2232_execute_reset(struct jtag_command *cmd) +{ + int retval; + int predicted_size = 0; + retval = ERROR_OK; + + DEBUG_JTAG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, cmd->cmd.reset->srst); + + /* only send the maximum buffer size that FT2232C can handle */ + predicted_size = 3; + if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + require_send = 0; + first_unsent = cmd; + } + + if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) + { + tap_set_state(TAP_RESET); + } + + layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + require_send = 1; + + DEBUG_JTAG_IO("trst: %i, srst: %i", + cmd->cmd.reset->trst, cmd->cmd.reset->srst); + return retval; +} + +static int ft2232_execute_sleep(struct jtag_command *cmd) +{ + int retval; + retval = ERROR_OK; + + DEBUG_JTAG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); + + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + first_unsent = cmd->next; + jtag_sleep(cmd->cmd.sleep->us); + DEBUG_JTAG_IO("sleep %" PRIi32 " usec while in %s", + cmd->cmd.sleep->us, + tap_state_name(tap_get_state())); + return retval; +} + +static int ft2232_execute_stableclocks(struct jtag_command *cmd) +{ + int retval; + retval = ERROR_OK; + + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + if (ft2232_stableclocks(cmd->cmd.stableclocks->num_cycles, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + DEBUG_JTAG_IO("clocks %i while in %s", + cmd->cmd.stableclocks->num_cycles, + tap_state_name(tap_get_state())); + return retval; +} + +static int ft2232_execute_command(struct jtag_command *cmd) +{ + int retval; + retval = ERROR_OK; + + switch (cmd->type) + { + case JTAG_RESET: retval = ft2232_execute_reset(cmd); break; + case JTAG_RUNTEST: retval = ft2232_execute_runtest(cmd); break; + case JTAG_STATEMOVE: retval = ft2232_execute_statemove(cmd); break; + case JTAG_PATHMOVE: retval = ft2232_execute_pathmove(cmd); break; + case JTAG_SCAN: retval = ft2232_execute_scan(cmd); break; + case JTAG_SLEEP: retval = ft2232_execute_sleep(cmd); break; + case JTAG_STABLECLOCKS: retval = ft2232_execute_stableclocks(cmd); break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + return retval; +} + +static int ft2232_execute_queue(void) +{ + struct jtag_command* cmd = jtag_command_queue; /* currently processed command */ + int retval; + + first_unsent = cmd; /* next command that has to be sent */ + require_send = 0; + + /* return ERROR_OK, unless ft2232_send_and_recv reports a failed check + * that wasn't handled by a caller-provided error handler + */ + retval = ERROR_OK; + + ft2232_buffer_size = 0; + ft2232_expect_read = 0; + + /* blink, if the current layout has that feature */ + if (layout->blink) + layout->blink(); + + while (cmd) + { + if (ft2232_execute_command(cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + /* Start reading input before FT2232 TX buffer fills up */ + cmd = cmd->next; + if (ft2232_expect_read > 256) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + first_unsent = cmd; + } + } + + if (require_send > 0) + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + + return retval; +} + +#if BUILD_FT2232_FTD2XX == 1 +static int ft2232_init_ftd2xx(uint16_t vid, uint16_t pid, int more, int* try_more) +{ + FT_STATUS status; + DWORD deviceID; + char SerialNumber[16]; + char Description[64]; + DWORD openex_flags = 0; + char* openex_string = NULL; + uint8_t latency_timer; + + LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", ft2232_layout, vid, pid); + +#if IS_WIN32 == 0 + /* Add non-standard Vid/Pid to the linux driver */ + if ((status = FT_SetVIDPID(vid, pid)) != FT_OK) + { + LOG_WARNING("couldn't add %4.4x:%4.4x", vid, pid); + } +#endif + + if (ft2232_device_desc && ft2232_serial) + { + LOG_WARNING("can't open by device description and serial number, giving precedence to serial"); + ft2232_device_desc = NULL; + } + + if (ft2232_device_desc) + { + openex_string = ft2232_device_desc; + openex_flags = FT_OPEN_BY_DESCRIPTION; + } + else if (ft2232_serial) + { + openex_string = ft2232_serial; + openex_flags = FT_OPEN_BY_SERIAL_NUMBER; + } + else + { + LOG_ERROR("neither device description nor serial number specified"); + LOG_ERROR("please add \"ft2232_device_desc \" or \"ft2232_serial \" to your .cfg file"); + + return ERROR_JTAG_INIT_FAILED; + } + + status = FT_OpenEx(openex_string, openex_flags, &ftdih); + if (status != FT_OK) { + /* under Win32, the FTD2XX driver appends an "A" to the end + * of the description, if we tried by the desc, then + * try by the alternate "A" description. */ + if (openex_string == ft2232_device_desc) { + /* Try the alternate method. */ + openex_string = ft2232_device_desc_A; + status = FT_OpenEx(openex_string, openex_flags, &ftdih); + if (status == FT_OK) { + /* yea, the "alternate" method worked! */ + } else { + /* drat, give the user a meaningfull message. + * telling the use we tried *BOTH* methods. */ + LOG_WARNING("Unable to open FTDI Device tried: '%s' and '%s'\n", + ft2232_device_desc, + ft2232_device_desc_A); + } + } + } + + if (status != FT_OK) + { + DWORD num_devices; + + if (more) + { + LOG_WARNING("unable to open ftdi device (trying more): %lu", status); + *try_more = 1; + return ERROR_JTAG_INIT_FAILED; + } + LOG_ERROR("unable to open ftdi device: %lu", status); + status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY); + if (status == FT_OK) + { + char** desc_array = malloc(sizeof(char*) * (num_devices + 1)); + uint32_t i; + + for (i = 0; i < num_devices; i++) + desc_array[i] = malloc(64); + + desc_array[num_devices] = NULL; + + status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | openex_flags); + + if (status == FT_OK) + { + LOG_ERROR("ListDevices: %lu\n", num_devices); + for (i = 0; i < num_devices; i++) + LOG_ERROR("%" PRIu32 ": \"%s\"", i, desc_array[i]); + } + + for (i = 0; i < num_devices; i++) + free(desc_array[i]); + + free(desc_array); + } + else + { + LOG_ERROR("ListDevices: NONE\n"); + } + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_SetLatencyTimer(ftdih, ft2232_latency)) != FT_OK) + { + LOG_ERROR("unable to set latency timer: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK) + { + LOG_ERROR("unable to get latency timer: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + else + { + LOG_DEBUG("current latency timer: %i", latency_timer); + } + + if ((status = FT_SetTimeouts(ftdih, 5000, 5000)) != FT_OK) + { + LOG_ERROR("unable to set timeouts: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_SetBitMode(ftdih, 0x0b, 2)) != FT_OK) + { + LOG_ERROR("unable to enable bit i/o mode: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + if ((status = FT_GetDeviceInfo(ftdih, &ftdi_device, &deviceID, SerialNumber, Description, NULL)) != FT_OK) + { + LOG_ERROR("unable to get FT_GetDeviceInfo: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + else + { + static const char* type_str[] = + {"BM", "AM", "100AX", "UNKNOWN", "2232C", "232R", "2232H", "4232H"}; + unsigned no_of_known_types = ARRAY_SIZE(type_str) - 1; + unsigned type_index = ((unsigned)ftdi_device <= no_of_known_types) + ? ftdi_device : FT_DEVICE_UNKNOWN; + LOG_INFO("device: %lu \"%s\"", ftdi_device, type_str[type_index]); + LOG_INFO("deviceID: %lu", deviceID); + LOG_INFO("SerialNumber: %s", SerialNumber); + LOG_INFO("Description: %s", Description); + } + + return ERROR_OK; +} + +static int ft2232_purge_ftd2xx(void) +{ + FT_STATUS status; + + if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK) + { + LOG_ERROR("error purging ftd2xx device: %lu", status); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +#endif /* BUILD_FT2232_FTD2XX == 1 */ + +#if BUILD_FT2232_LIBFTDI == 1 +static int ft2232_init_libftdi(uint16_t vid, uint16_t pid, int more, int* try_more) +{ + uint8_t latency_timer; + + LOG_DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)", + ft2232_layout, vid, pid); + + if (ftdi_init(&ftdic) < 0) + return ERROR_JTAG_INIT_FAILED; + + if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0) + { + LOG_ERROR("unable to select FT2232 channel A: %s", ftdic.error_str); + return ERROR_JTAG_INIT_FAILED; + } + + /* context, vendor id, product id */ + if (ftdi_usb_open_desc(&ftdic, vid, pid, ft2232_device_desc, + ft2232_serial) < 0) + { + if (more) + LOG_WARNING("unable to open ftdi device (trying more): %s", + ftdic.error_str); + else + LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); + *try_more = 1; + return ERROR_JTAG_INIT_FAILED; + } + + /* There is already a reset in ftdi_usb_open_desc, this should be redundant */ + if (ftdi_usb_reset(&ftdic) < 0) + { + LOG_ERROR("unable to reset ftdi device"); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_set_latency_timer(&ftdic, ft2232_latency) < 0) + { + LOG_ERROR("unable to set latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + + if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) + { + LOG_ERROR("unable to get latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + else + { + LOG_DEBUG("current latency timer: %i", latency_timer); + } + + ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */ + + ftdi_device = ftdic.type; + static const char* type_str[] = + {"AM", "BM", "2232C", "R", "2232H", "4232H", "Unknown"}; + unsigned no_of_known_types = ARRAY_SIZE(type_str) - 1; + unsigned type_index = ((unsigned)ftdi_device < no_of_known_types) + ? ftdi_device : no_of_known_types; + LOG_DEBUG("FTDI chip type: %i \"%s\"", (int)ftdi_device, type_str[type_index]); + return ERROR_OK; +} + +static int ft2232_purge_libftdi(void) +{ + if (ftdi_usb_purge_buffers(&ftdic) < 0) + { + LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +#endif /* BUILD_FT2232_LIBFTDI == 1 */ + +static int ft2232_init(void) +{ + uint8_t buf[1]; + int retval; + uint32_t bytes_written; + const struct ft2232_layout* cur_layout = ft2232_layouts; + int i; + + if (tap_get_tms_path_len(TAP_IRPAUSE,TAP_IRPAUSE) == 7) + { + LOG_DEBUG("ft2232 interface using 7 step jtag state transitions"); + } + else + { + LOG_DEBUG("ft2232 interface using shortest path jtag state transitions"); + + } + if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0)) + { + ft2232_layout = "usbjtag"; + LOG_WARNING("No ft2232 layout specified, using default 'usbjtag'"); + } + + while (cur_layout->name) + { + if (strcmp(cur_layout->name, ft2232_layout) == 0) + { + layout = cur_layout; + break; + } + cur_layout++; + } + + if (!layout) + { + LOG_ERROR("No matching layout found for %s", ft2232_layout); + return ERROR_JTAG_INIT_FAILED; + } + + for (i = 0; 1; i++) + { + /* + * "more indicates that there are more IDs to try, so we should + * not print an error for an ID mismatch (but for anything + * else, we should). + * + * try_more indicates that the error code returned indicates an + * ID mismatch (and nothing else) and that we should proceeed + * with the next ID pair. + */ + int more = ft2232_vid[i + 1] || ft2232_pid[i + 1]; + int try_more = 0; + +#if BUILD_FT2232_FTD2XX == 1 + retval = ft2232_init_ftd2xx(ft2232_vid[i], ft2232_pid[i], + more, &try_more); +#elif BUILD_FT2232_LIBFTDI == 1 + retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i], + more, &try_more); +#endif + if (retval >= 0) + break; + if (!more || !try_more) + return retval; + } + + ft2232_buffer_size = 0; + ft2232_buffer = malloc(FT2232_BUFFER_SIZE); + + if (layout->init() != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + + if (ft2232_device_is_highspeed()) + { +#ifndef BUILD_FT2232_HIGHSPEED + #if BUILD_FT2232_FTD2XX == 1 + LOG_WARNING("High Speed device found - You need a newer FTD2XX driver (version 2.04.16 or later)"); + #elif BUILD_FT2232_LIBFTDI == 1 + LOG_WARNING("High Speed device found - You need a newer libftdi version (0.16 or later)"); + #endif +#endif + /* make sure the legacy mode is disabled */ + if (ft2232h_ft4232h_clk_divide_by_5(false) != ERROR_OK) + return ERROR_JTAG_INIT_FAILED; + } + + ft2232_speed(jtag_get_speed()); + + buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */ + if (((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) || (bytes_written != 1)) + { + LOG_ERROR("couldn't write to FT2232 to disable loopback"); + return ERROR_JTAG_INIT_FAILED; + } + +#if BUILD_FT2232_FTD2XX == 1 + return ft2232_purge_ftd2xx(); +#elif BUILD_FT2232_LIBFTDI == 1 + return ft2232_purge_libftdi(); +#endif + + return ERROR_OK; +} + +static int usbjtag_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x0b; + + if (strcmp(ft2232_layout, "usbjtag") == 0) + { + nTRST = 0x10; + nTRSTnOE = 0x10; + nSRST = 0x40; + nSRSTnOE = 0x40; + } + else if (strcmp(ft2232_layout, "signalyzer") == 0) + { + nTRST = 0x10; + nTRSTnOE = 0x10; + nSRST = 0x20; + nSRSTnOE = 0x20; + } + else if (strcmp(ft2232_layout, "evb_lm3s811") == 0) + { + nTRST = 0x0; + nTRSTnOE = 0x00; + nSRST = 0x20; + nSRSTnOE = 0x20; + low_output = 0x88; + low_direction = 0x8b; + } + else if (strcmp(ft2232_layout, "luminary_icdi") == 0) + { + nTRST = 0x0; + nTRSTnOE = 0x00; + nSRST = 0x20; + nSRSTnOE = 0x20; + low_output = 0x88; + low_direction = 0xcb; + } + else + { + LOG_ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout); + return ERROR_JTAG_INIT_FAILED; + } + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + low_direction &= ~nTRSTnOE; /* nTRST input */ + low_output &= ~nTRST; /* nTRST = 0 */ + } + else + { + low_direction |= nTRSTnOE; /* nTRST output */ + low_output |= nTRST; /* nTRST = 1 */ + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + low_direction |= nSRSTnOE; /* nSRST output */ + low_output |= nSRST; /* nSRST = 1 */ + } + else + { + low_direction &= ~nSRSTnOE; /* nSRST input */ + low_output &= ~nSRST; /* nSRST = 0 */ + } + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, xRST high) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'USBJTAG' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int axm0432_jtag_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x2b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + if (strcmp(layout->name, "axm0432_jtag") == 0) + { + nTRST = 0x08; + nTRSTnOE = 0x0; /* No output enable for TRST*/ + nSRST = 0x04; + nSRSTnOE = 0x0; /* No output enable for SRST*/ + } + else + { + LOG_ERROR("BUG: axm0432_jtag_init called for non axm0432 layout"); + exit(-1); + } + + high_output = 0x0; + high_direction = 0x0c; + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + LOG_ERROR("can't set nTRSTOE to push-pull on the Dicarlo jtag"); + } + else + { + high_output |= nTRST; + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + LOG_ERROR("can't set nSRST to push-pull on the Dicarlo jtag"); + } + else + { + high_output |= nSRST; + } + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'Dicarlo' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int jtagkey_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x1b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + if (strcmp(layout->name, "jtagkey") == 0) + { + nTRST = 0x01; + nTRSTnOE = 0x4; + nSRST = 0x02; + nSRSTnOE = 0x08; + } + else if ((strcmp(layout->name, "jtagkey_prototype_v1") == 0) + || (strcmp(layout->name, "oocdlink") == 0)) + { + nTRST = 0x02; + nTRSTnOE = 0x1; + nSRST = 0x08; + nSRSTnOE = 0x04; + } + else + { + LOG_ERROR("BUG: jtagkey_init called for non jtagkey layout"); + exit(-1); + } + + high_output = 0x0; + high_direction = 0x0f; + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + high_output |= nTRSTnOE; + high_output &= ~nTRST; + } + else + { + high_output &= ~nTRSTnOE; + high_output |= nTRST; + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + high_output &= ~nSRSTnOE; + high_output |= nSRST; + } + else + { + high_output |= nSRSTnOE; + high_output &= ~nSRST; + } + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int olimex_jtag_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x1b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nTRSTnOE = 0x4; + nSRST = 0x02; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x0; + high_direction = 0x0f; + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + high_output |= nTRSTnOE; + high_output &= ~nTRST; + } + else + { + high_output &= ~nTRSTnOE; + high_output |= nTRST; + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + LOG_ERROR("can't set nSRST to push-pull on the Olimex ARM-USB-OCD"); + } + else + { + high_output &= ~nSRST; + } + + /* turn red LED on */ + high_output |= 0x08; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int flyswatter_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x18; + low_direction = 0xfb; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE[12]=out, n[ST]srst = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x10; + nTRSTnOE = 0x0; /* not output enable for nTRST */ + nSRST = 0x20; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x00; + high_direction = 0x0c; + + /* turn red LED3 on, LED2 off */ + high_output |= 0x08; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int turtle_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x5b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nSRST = 0x40; + + high_output = 0x00; + high_direction = 0x0C; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; + buf[2] = high_direction; + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int comstick_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x0b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nTRSTnOE = 0x00; /* no output enable for nTRST */ + nSRST = 0x02; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x03; + high_direction = 0x03; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; + buf[2] = high_direction; + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int stm32stick_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x88; + low_direction = 0x8b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nTRSTnOE = 0x00; /* no output enable for nTRST */ + nSRST = 0x80; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x01; + high_direction = 0x03; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; + buf[2] = high_direction; + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int sheevaplug_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x1b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRSTnOE = 0x1; + nTRST = 0x02; + nSRSTnOE = 0x4; + nSRST = 0x08; + + high_output = 0x0; + high_direction = 0x0f; + + /* nTRST is always push-pull */ + high_output &= ~nTRSTnOE; + high_output |= nTRST; + + /* nSRST is always open-drain */ + high_output |= nSRSTnOE; + high_output &= ~nSRST; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs - xRST */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int cortino_jtag_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + + low_output = 0x08; + low_direction = 0x1b; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ + buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'cortino' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nTRSTnOE = 0x00; /* no output enable for nTRST */ + nSRST = 0x02; + nSRSTnOE = 0x00; /* no output enable for nSRST */ + + high_output = 0x03; + high_direction = 0x03; + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; + buf[2] = high_direction; + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static void olimex_jtag_blink(void) +{ + /* Olimex ARM-USB-OCD has a LED connected to ACBUS3 + * ACBUS3 is bit 3 of the GPIOH port + */ + if (high_output & 0x08) + { + /* set port pin high */ + high_output &= 0x07; + } + else + { + /* set port pin low */ + high_output |= 0x08; + } + + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); +} + +static void flyswatter_jtag_blink(void) +{ + /* + * Flyswatter has two LEDs connected to ACBUS2 and ACBUS3 + */ + high_output ^= 0x0c; + + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); +} + +static void turtle_jtag_blink(void) +{ + /* + * Turtelizer2 has two LEDs connected to ACBUS2 and ACBUS3 + */ + if (high_output & 0x08) + { + high_output = 0x04; + } + else + { + high_output = 0x08; + } + + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); +} + +static int ft2232_quit(void) +{ +#if BUILD_FT2232_FTD2XX == 1 + FT_STATUS status; + + status = FT_Close(ftdih); +#elif BUILD_FT2232_LIBFTDI == 1 + ftdi_usb_close(&ftdic); + + ftdi_deinit(&ftdic); +#endif + + free(ft2232_buffer); + ft2232_buffer = NULL; + + return ERROR_OK; +} + +COMMAND_HANDLER(ft2232_handle_device_desc_command) +{ + char *cp; + char buf[200]; + if (CMD_ARGC == 1) + { + ft2232_device_desc = strdup(CMD_ARGV[0]); + cp = strchr(ft2232_device_desc, 0); + /* under Win32, the FTD2XX driver appends an "A" to the end + * of the description, this examines the given desc + * and creates the 'missing' _A or non_A variable. */ + if ((cp[-1] == 'A') && (cp[-2]==' ')) { + /* it was, so make this the "A" version. */ + ft2232_device_desc_A = ft2232_device_desc; + /* and *CREATE* the non-A version. */ + strcpy(buf, ft2232_device_desc); + cp = strchr(buf, 0); + cp[-2] = 0; + ft2232_device_desc = strdup(buf); + } else { + /* A not defined + * so create it */ + sprintf(buf, "%s A", ft2232_device_desc); + ft2232_device_desc_A = strdup(buf); + } + } + else + { + LOG_ERROR("expected exactly one argument to ft2232_device_desc "); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(ft2232_handle_serial_command) +{ + if (CMD_ARGC == 1) + { + ft2232_serial = strdup(CMD_ARGV[0]); + } + else + { + LOG_ERROR("expected exactly one argument to ft2232_serial "); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(ft2232_handle_layout_command) +{ + if (CMD_ARGC == 0) + return ERROR_OK; + + ft2232_layout = malloc(strlen(CMD_ARGV[0]) + 1); + strcpy(ft2232_layout, CMD_ARGV[0]); + + return ERROR_OK; +} + +COMMAND_HANDLER(ft2232_handle_vid_pid_command) +{ + if (CMD_ARGC > MAX_USB_IDS * 2) + { + LOG_WARNING("ignoring extra IDs in ft2232_vid_pid " + "(maximum is %d pairs)", MAX_USB_IDS); + CMD_ARGC = MAX_USB_IDS * 2; + } + if (CMD_ARGC < 2 || (CMD_ARGC & 1)) + { + LOG_WARNING("incomplete ft2232_vid_pid configuration directive"); + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + /* remove the incomplete trailing id */ + CMD_ARGC -= 1; + } + + unsigned i; + for (i = 0; i < CMD_ARGC; i += 2) + { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], ft2232_vid[i >> 1]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], ft2232_pid[i >> 1]); + } + + /* + * Explicitly terminate, in case there are multiples instances of + * ft2232_vid_pid. + */ + ft2232_vid[i >> 1] = ft2232_pid[i >> 1] = 0; + + return ERROR_OK; +} + +COMMAND_HANDLER(ft2232_handle_latency_command) +{ + if (CMD_ARGC == 1) + { + ft2232_latency = atoi(CMD_ARGV[0]); + } + else + { + LOG_ERROR("expected exactly one argument to ft2232_latency "); + } + + return ERROR_OK; +} + +static int ft2232_stableclocks(int num_cycles, struct jtag_command* cmd) +{ + int retval = 0; + + /* 7 bits of either ones or zeros. */ + uint8_t tms = (tap_get_state() == TAP_RESET ? 0x7F : 0x00); + + while (num_cycles > 0) + { + /* the command 0x4b, "Clock Data to TMS/CS Pin (no Read)" handles + * at most 7 bits per invocation. Here we invoke it potentially + * several times. + */ + int bitcount_per_command = (num_cycles > 7) ? 7 : num_cycles; + + if (ft2232_buffer_size + 3 >= FT2232_BUFFER_SIZE) + { + if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + + first_unsent = cmd; + } + + /* there are no state transitions in this code, so omit state tracking */ + + /* command "Clock Data to TMS/CS Pin (no Read)" */ + buffer_write(0x4b); + + /* scan 7 bit */ + buffer_write(bitcount_per_command - 1); + + /* TMS data bits are either all zeros or ones to stay in the current stable state */ + buffer_write(tms); + + require_send = 1; + + num_cycles -= bitcount_per_command; + } + + return retval; +} + +/* --------------------------------------------------------------------- + * Support for IceBear JTAG adapter from Section5: + * http://section5.ch/icebear + * + * Author: Sten, debian@sansys-electronic.com + */ + +/* Icebear pin layout + * + * ADBUS5 (nEMU) nSRST | 2 1| GND (10k->VCC) + * GND GND | 4 3| n.c. + * ADBUS3 TMS | 6 5| ADBUS6 VCC + * ADBUS0 TCK | 8 7| ADBUS7 (GND) + * ADBUS4 nTRST |10 9| ACBUS0 (GND) + * ADBUS1 TDI |12 11| ACBUS1 (GND) + * ADBUS2 TDO |14 13| GND GND + * + * ADBUS0 O L TCK ACBUS0 GND + * ADBUS1 O L TDI ACBUS1 GND + * ADBUS2 I TDO ACBUS2 n.c. + * ADBUS3 O H TMS ACBUS3 n.c. + * ADBUS4 O H nTRST + * ADBUS5 O H nSRST + * ADBUS6 - VCC + * ADBUS7 - GND + */ +static int icebear_jtag_init(void) { + uint8_t buf[3]; + uint32_t bytes_written; + + low_direction = 0x0b; /* output: TCK TDI TMS; input: TDO */ + low_output = 0x08; /* high: TMS; low: TCK TDI */ + nTRST = 0x10; + nSRST = 0x20; + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if ((jtag_reset_config & RESET_TRST_OPEN_DRAIN) != 0) { + low_direction &= ~nTRST; /* nTRST high impedance */ + } + else { + low_direction |= nTRST; + low_output |= nTRST; + } + + low_direction |= nSRST; + low_output |= nSRST; + + /* initialize low byte for jtag */ + buf[0] = 0x80; /* command "set data bits low byte" */ + buf[1] = low_output; + buf[2] = low_direction; + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) { + LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (low)"); + return ERROR_JTAG_INIT_FAILED; + } + + high_output = 0x0; + high_direction = 0x00; + + + /* initialize high port */ + buf[0] = 0x82; /* command "set data bits high byte" */ + buf[1] = high_output; /* value */ + buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) { + LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (high)"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static void icebear_jtag_reset(int trst, int srst) { + + if (trst == 1) { + low_direction |= nTRST; + low_output &= ~nTRST; + } + else if (trst == 0) { + enum reset_types jtag_reset_config = jtag_get_reset_config(); + if ((jtag_reset_config & RESET_TRST_OPEN_DRAIN) != 0) + low_direction &= ~nTRST; + else + low_output |= nTRST; + } + + if (srst == 1) { + low_output &= ~nSRST; + } + else if (srst == 0) { + low_output |= nSRST; + } + + /* command "set data bits low byte" */ + buffer_write(0x80); + buffer_write(low_output); + buffer_write(low_direction); + + LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); +} + +/* --------------------------------------------------------------------- + * Support for Signalyzer H2 and Signalyzer H4 + * JTAG adapter from Xverve Technologies Inc. + * http://www.signalyzer.com or http://www.xverve.com + * + * Author: Oleg Seiljus, oleg@signalyzer.com + */ +static unsigned char signalyzer_h_side; +static unsigned int signalyzer_h_adapter_type; + +static int signalyzer_h_ctrl_write(int address, unsigned short value); + +#if BUILD_FT2232_FTD2XX == 1 +static int signalyzer_h_ctrl_read(int address, unsigned short *value); +#endif + +#define SIGNALYZER_COMMAND_ADDR 128 +#define SIGNALYZER_DATA_BUFFER_ADDR 129 + +#define SIGNALYZER_COMMAND_VERSION 0x41 +#define SIGNALYZER_COMMAND_RESET 0x42 +#define SIGNALYZER_COMMAND_POWERCONTROL_GET 0x50 +#define SIGNALYZER_COMMAND_POWERCONTROL_SET 0x51 +#define SIGNALYZER_COMMAND_PWM_SET 0x52 +#define SIGNALYZER_COMMAND_LED_SET 0x53 +#define SIGNALYZER_COMMAND_ADC 0x54 +#define SIGNALYZER_COMMAND_GPIO_STATE 0x55 +#define SIGNALYZER_COMMAND_GPIO_MODE 0x56 +#define SIGNALYZER_COMMAND_GPIO_PORT 0x57 +#define SIGNALYZER_COMMAND_I2C 0x58 + +#define SIGNALYZER_CHAN_A 1 +#define SIGNALYZER_CHAN_B 2 +/* LEDS use channel C */ +#define SIGNALYZER_CHAN_C 4 + +#define SIGNALYZER_LED_GREEN 1 +#define SIGNALYZER_LED_RED 2 + +#define SIGNALYZER_MODULE_TYPE_EM_LT16_A 0x0301 +#define SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG 0x0302 +#define SIGNALYZER_MODULE_TYPE_EM_JTAG 0x0303 +#define SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P 0x0304 +#define SIGNALYZER_MODULE_TYPE_EM_JTAG_P 0x0305 + + +static int signalyzer_h_ctrl_write(int address, unsigned short value) +{ +#if BUILD_FT2232_FTD2XX == 1 + return FT_WriteEE(ftdih, address, value); +#elif BUILD_FT2232_LIBFTDI == 1 + return 0; +#endif +} + +#if BUILD_FT2232_FTD2XX == 1 +static int signalyzer_h_ctrl_read(int address, unsigned short *value) +{ + return FT_ReadEE(ftdih, address, value); +} +#endif + +static int signalyzer_h_led_set(unsigned char channel, unsigned char led, + int on_time_ms, int off_time_ms, unsigned char cycles) +{ + unsigned char on_time; + unsigned char off_time; + + if (on_time_ms < 0xFFFF) + on_time = (unsigned char)(on_time_ms / 62); + else + on_time = 0xFF; + + off_time = (unsigned char)(off_time_ms / 62); + +#if BUILD_FT2232_FTD2XX == 1 + FT_STATUS status; + + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, + ((uint32_t)(channel << 8) | led))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + (SIGNALYZER_DATA_BUFFER_ADDR + 1), + ((uint32_t)(on_time << 8) | off_time))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + (SIGNALYZER_DATA_BUFFER_ADDR + 2), + ((uint32_t)cycles))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_LED_SET)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +#elif BUILD_FT2232_LIBFTDI == 1 + int retval; + + if ((retval = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, + ((uint32_t)(channel << 8) | led))) < 0) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %s", + ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((retval = signalyzer_h_ctrl_write( + (SIGNALYZER_DATA_BUFFER_ADDR + 1), + ((uint32_t)(on_time << 8) | off_time))) < 0) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %s", + ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((retval = signalyzer_h_ctrl_write( + (SIGNALYZER_DATA_BUFFER_ADDR + 2), + (uint32_t)cycles)) < 0) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %s", + ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((retval = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_LED_SET)) < 0) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %s", + ftdi_get_error_string(&ftdic)); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +#endif +} + +static int signalyzer_h_init(void) +{ +#if BUILD_FT2232_FTD2XX == 1 + FT_STATUS status; + int i; +#endif + + char *end_of_desc; + + uint16_t read_buf[12] = { 0 }; + uint8_t buf[3]; + uint32_t bytes_written; + + /* turn on center green led */ + signalyzer_h_led_set(SIGNALYZER_CHAN_C, SIGNALYZER_LED_GREEN, + 0xFFFF, 0x00, 0x00); + + /* determine what channel config wants to open + * TODO: change me... current implementation is made to work + * with openocd description parsing. + */ + end_of_desc = strrchr(ft2232_device_desc, 0x00); + + if (end_of_desc) + { + signalyzer_h_side = *(end_of_desc - 1); + if (signalyzer_h_side == 'B') + signalyzer_h_side = SIGNALYZER_CHAN_B; + else + signalyzer_h_side = SIGNALYZER_CHAN_A; + } + else + { + LOG_ERROR("No Channel was specified"); + return ERROR_FAIL; + } + + signalyzer_h_led_set(signalyzer_h_side, SIGNALYZER_LED_GREEN, + 1000, 1000, 0xFF); + +#if BUILD_FT2232_FTD2XX == 1 + /* read signalyzer versionining information */ + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_VERSION)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + for (i = 0; i < 10; i++) + { + if ((status = signalyzer_h_ctrl_read( + (SIGNALYZER_DATA_BUFFER_ADDR + i), + &read_buf[i])) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_read returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + LOG_INFO("Signalyzer: ID info: { %.4x %.4x %.4x %.4x %.4x %.4x %.4x }", + read_buf[0], read_buf[1], read_buf[2], read_buf[3], + read_buf[4], read_buf[5], read_buf[6]); + + /* set gpio register */ + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, + (uint32_t)(signalyzer_h_side << 8))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR + 1, + 0x0404)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_GPIO_STATE)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* read adapter type information */ + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, + ((uint32_t)(signalyzer_h_side << 8) | 0x01))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + (SIGNALYZER_DATA_BUFFER_ADDR + 1), 0xA000)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + (SIGNALYZER_DATA_BUFFER_ADDR + 2), 0x0008)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_I2C)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + usleep(100000); + + if ((status = signalyzer_h_ctrl_read(SIGNALYZER_COMMAND_ADDR, + &read_buf[0])) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_read returned: %lu", status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (read_buf[0] != 0x0498) + signalyzer_h_adapter_type = 0x0000; + else + { + for (i = 0; i < 4; i++) + { + if ((status = signalyzer_h_ctrl_read( + (SIGNALYZER_DATA_BUFFER_ADDR + i), + &read_buf[i])) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_read returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + signalyzer_h_adapter_type = read_buf[0]; + } + +#elif BUILD_FT2232_LIBFTDI == 1 + /* currently libftdi does not allow reading individual eeprom + * locations, therefore adapter type cannot be detected. + * override with most common type + */ + signalyzer_h_adapter_type = SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG; +#endif + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + /* ADAPTOR: EM_LT16_A */ + if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_LT16_A) + { + LOG_INFO("Signalyzer: EM-LT (16-channel level translator) " + "detected. (HW: %2x).", (read_buf[1] >> 8)); + + nTRST = 0x10; + nTRSTnOE = 0x10; + nSRST = 0x20; + nSRSTnOE = 0x20; + + low_output = 0x08; + low_direction = 0x1b; + + high_output = 0x0; + high_direction = 0x0; + + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + low_direction &= ~nTRSTnOE; /* nTRST input */ + low_output &= ~nTRST; /* nTRST = 0 */ + } + else + { + low_direction |= nTRSTnOE; /* nTRST output */ + low_output |= nTRST; /* nTRST = 1 */ + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + low_direction |= nSRSTnOE; /* nSRST output */ + low_output |= nSRST; /* nSRST = 1 */ + } + else + { + low_direction &= ~nSRSTnOE; /* nSRST input */ + low_output &= ~nSRST; /* nSRST = 0 */ + } + +#if BUILD_FT2232_FTD2XX == 1 + /* enable power to the module */ + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR, + ((uint32_t)(signalyzer_h_side << 8) | 0x01))) + != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_POWERCONTROL_SET)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* set gpio mode register */ + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR, + (uint32_t)(signalyzer_h_side << 8))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0000)) + != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_GPIO_MODE)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* set gpio register */ + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR, + (uint32_t)(signalyzer_h_side << 8))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x4040)) + != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_GPIO_STATE)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } +#endif + } + + /* ADAPTOR: EM_ARM_JTAG, EM_ARM_JTAG_P, EM_JTAG, EM_JTAG_P */ + else if ((signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) || + (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) || + (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG) || + (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG_P)) + { + if (signalyzer_h_adapter_type + == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) + LOG_INFO("Signalyzer: EM-ARM-JTAG (ARM JTAG) " + "detected. (HW: %2x).", (read_buf[1] >> 8)); + else if (signalyzer_h_adapter_type + == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) + LOG_INFO("Signalyzer: EM-ARM-JTAG_P " + "(ARM JTAG with PSU) detected. (HW: %2x).", + (read_buf[1] >> 8)); + else if (signalyzer_h_adapter_type + == SIGNALYZER_MODULE_TYPE_EM_JTAG) + LOG_INFO("Signalyzer: EM-JTAG (Generic JTAG) " + "detected. (HW: %2x).", (read_buf[1] >> 8)); + else if (signalyzer_h_adapter_type + == SIGNALYZER_MODULE_TYPE_EM_JTAG_P) + LOG_INFO("Signalyzer: EM-JTAG-P " + "(Generic JTAG with PSU) detected. (HW: %2x).", + (read_buf[1] >> 8)); + + nTRST = 0x02; + nTRSTnOE = 0x04; + nSRST = 0x08; + nSRSTnOE = 0x10; + + low_output = 0x08; + low_direction = 0x1b; + + high_output = 0x0; + high_direction = 0x1f; + + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + high_output |= nTRSTnOE; + high_output &= ~nTRST; + } + else + { + high_output &= ~nTRSTnOE; + high_output |= nTRST; + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + high_output &= ~nSRSTnOE; + high_output |= nSRST; + } + else + { + high_output |= nSRSTnOE; + high_output &= ~nSRST; + } + +#if BUILD_FT2232_FTD2XX == 1 + /* enable power to the module */ + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR, + ((uint32_t)(signalyzer_h_side << 8) | 0x01))) + != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_POWERCONTROL_SET)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* set gpio mode register (IO_16 and IO_17 set as analog + * inputs, other is gpio) + */ + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR, + (uint32_t)(signalyzer_h_side << 8))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0060)) + != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_GPIO_MODE)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* set gpio register (all inputs, for -P modules, + * PSU will be turned off) + */ + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR, + (uint32_t)(signalyzer_h_side << 8))) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0000)) + != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } + + if ((status = signalyzer_h_ctrl_write( + SIGNALYZER_COMMAND_ADDR, + SIGNALYZER_COMMAND_GPIO_STATE)) != FT_OK) + { + LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", + status); + return ERROR_JTAG_DEVICE_ERROR; + } +#endif + } + + else if (signalyzer_h_adapter_type == 0x0000) + { + LOG_INFO("Signalyzer: No external modules were detected."); + + nTRST = 0x10; + nTRSTnOE = 0x10; + nSRST = 0x20; + nSRSTnOE = 0x20; + + low_output = 0x08; + low_direction = 0x1b; + + high_output = 0x0; + high_direction = 0x0; + + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + { + low_direction &= ~nTRSTnOE; /* nTRST input */ + low_output &= ~nTRST; /* nTRST = 0 */ + } + else + { + low_direction |= nTRSTnOE; /* nTRST output */ + low_output |= nTRST; /* nTRST = 1 */ + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + { + low_direction |= nSRSTnOE; /* nSRST output */ + low_output |= nSRST; /* nSRST = 1 */ + } + else + { + low_direction &= ~nSRSTnOE; /* nSRST input */ + low_output &= ~nSRST; /* nSRST = 0 */ + } + } + else + { + LOG_ERROR("Unknown module type is detected: %.4x", + signalyzer_h_adapter_type); + return ERROR_JTAG_DEVICE_ERROR; + } + + /* initialize low byte of controller for jtag operation */ + buf[0] = 0x80; + buf[1] = low_output; + buf[2] = low_direction; + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) + || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize Signalyzer-H layout"); + return ERROR_JTAG_INIT_FAILED; + } + +#if BUILD_FT2232_FTD2XX == 1 + if (ftdi_device == FT_DEVICE_2232H) + { + /* initialize high byte of controller for jtag operation */ + buf[0] = 0x82; + buf[1] = high_output; + buf[2] = high_direction; + + if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK) + || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize Signalyzer-H layout"); + return ERROR_JTAG_INIT_FAILED; + } + } +#elif BUILD_FT2232_LIBFTDI == 1 + if (ftdi_device == TYPE_2232H) + { + /* initialize high byte of controller for jtag operation */ + buf[0] = 0x82; + buf[1] = high_output; + buf[2] = high_direction; + + if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK) + || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize Signalyzer-H layout"); + return ERROR_JTAG_INIT_FAILED; + } + } +#endif + return ERROR_OK; +} + +static void signalyzer_h_reset(int trst, int srst) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + /* ADAPTOR: EM_LT16_A */ + if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_LT16_A) + { + if (trst == 1) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + /* switch to output pin (output is low) */ + low_direction |= nTRSTnOE; + else + /* switch output low */ + low_output &= ~nTRST; + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + /* switch to input pin (high-Z + internal + * and external pullup) */ + low_direction &= ~nTRSTnOE; + else + /* switch output high */ + low_output |= nTRST; + } + + if (srst == 1) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + /* switch output low */ + low_output &= ~nSRST; + else + /* switch to output pin (output is low) */ + low_direction |= nSRSTnOE; + } + else if (srst == 0) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + /* switch output high */ + low_output |= nSRST; + else + /* switch to input pin (high-Z) */ + low_direction &= ~nSRSTnOE; + } + + /* command "set data bits low byte" */ + buffer_write(0x80); + buffer_write(low_output); + buffer_write(low_direction); + LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, " + "low_direction: 0x%2.2x", + trst, srst, low_output, low_direction); + } + /* ADAPTOR: EM_ARM_JTAG, EM_ARM_JTAG_P, EM_JTAG, EM_JTAG_P */ + else if ((signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) || + (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) || + (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG) || + (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG_P)) + { + if (trst == 1) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output &= ~nTRSTnOE; + else + high_output &= ~nTRST; + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output |= nTRSTnOE; + else + high_output |= nTRST; + } + + if (srst == 1) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output &= ~nSRST; + else + high_output &= ~nSRSTnOE; + } + else if (srst == 0) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output |= nSRST; + else + high_output |= nSRSTnOE; + } + + /* command "set data bits high byte" */ + buffer_write(0x82); + buffer_write(high_output); + buffer_write(high_direction); + LOG_INFO("trst: %i, srst: %i, high_output: 0x%2.2x, " + "high_direction: 0x%2.2x", + trst, srst, high_output, high_direction); + } + else if (signalyzer_h_adapter_type == 0x0000) + { + if (trst == 1) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + /* switch to output pin (output is low) */ + low_direction |= nTRSTnOE; + else + /* switch output low */ + low_output &= ~nTRST; + } + else if (trst == 0) + { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + /* switch to input pin (high-Z + internal + * and external pullup) */ + low_direction &= ~nTRSTnOE; + else + /* switch output high */ + low_output |= nTRST; + } + + if (srst == 1) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + /* switch output low */ + low_output &= ~nSRST; + else + /* switch to output pin (output is low) */ + low_direction |= nSRSTnOE; + } + else if (srst == 0) + { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + /* switch output high */ + low_output |= nSRST; + else + /* switch to input pin (high-Z) */ + low_direction &= ~nSRSTnOE; + } + + /* command "set data bits low byte" */ + buffer_write(0x80); + buffer_write(low_output); + buffer_write(low_direction); + LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, " + "low_direction: 0x%2.2x", + trst, srst, low_output, low_direction); + } +} + +static void signalyzer_h_blink(void) +{ + signalyzer_h_led_set(signalyzer_h_side, SIGNALYZER_LED_RED, 100, 0, 1); +} + +/******************************************************************** + * Support for KT-LINK + * JTAG adapter from KRISTECH + * http://www.kristech.eu + *******************************************************************/ +static int ktlink_init(void) +{ + uint8_t buf[3]; + uint32_t bytes_written; + uint8_t swd_en = 0x20; //0x20 SWD disable, 0x00 SWD enable (ADBUS5) + + low_output = 0x08 | swd_en; // value; TMS=1,TCK=0,TDI=0,SWD=swd_en + low_direction = 0x3B; // out=1; TCK/TDI/TMS=out,TDO=in,SWD=out,RTCK=in,SRSTIN=in + + // initialize low port + buf[0] = 0x80; // command "set data bits low byte" + buf[1] = low_output; + buf[2] = low_direction; + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + nTRST = 0x01; + nSRST = 0x02; + nTRSTnOE = 0x04; + nSRSTnOE = 0x08; + + high_output = 0x80; // turn LED on + high_direction = 0xFF; // all outputs + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { + high_output |= nTRSTnOE; + high_output &= ~nTRST; + } else { + high_output &= ~nTRSTnOE; + high_output |= nTRST; + } + + if (jtag_reset_config & RESET_SRST_PUSH_PULL) { + high_output &= ~nSRSTnOE; + high_output |= nSRST; + } else { + high_output |= nSRSTnOE; + high_output &= ~nSRST; + } + + // initialize high port + buf[0] = 0x82; // command "set data bits high byte" + buf[1] = high_output; // value + buf[2] = high_direction; + LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); + + if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) + { + LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static void ktlink_reset(int trst, int srst) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (trst == 1) { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output &= ~nTRSTnOE; + else + high_output &= ~nTRST; + } else if (trst == 0) { + if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) + high_output |= nTRSTnOE; + else + high_output |= nTRST; + } + + if (srst == 1) { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output &= ~nSRST; + else + high_output &= ~nSRSTnOE; + } else if (srst == 0) { + if (jtag_reset_config & RESET_SRST_PUSH_PULL) + high_output |= nSRST; + else + high_output |= nSRSTnOE; + } + + buffer_write(0x82); // command "set data bits high byte" + buffer_write(high_output); + buffer_write(high_direction); + LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output,high_direction); +} + +static void ktlink_blink(void) +{ + /* LED connected to ACBUS7 */ + if (high_output & 0x80) + high_output &= 0x7F; + else + high_output |= 0x80; + + buffer_write(0x82); // command "set data bits high byte" + buffer_write(high_output); + buffer_write(high_direction); +} + +static const struct command_registration ft2232_command_handlers[] = { + { + .name = "ft2232_device_desc", + .handler = &ft2232_handle_device_desc_command, + .mode = COMMAND_CONFIG, + .help = "set the USB device description of the FTDI FT2232 device", + .usage = "", + }, + { + .name = "ft2232_serial", + .handler = &ft2232_handle_serial_command, + .mode = COMMAND_CONFIG, + .help = "set the serial number of the FTDI FT2232 device", + .usage = "", + }, + { + .name = "ft2232_layout", + .handler = &ft2232_handle_layout_command, + .mode = COMMAND_CONFIG, + .help = "set the layout of the FT2232 GPIO signals used " + "to control output-enables and reset signals", + .usage = "", + }, + { + .name = "ft2232_vid_pid", + .handler = &ft2232_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "the vendor ID and product ID of the FTDI FT2232 device", + .usage = " [...]", + }, + { + .name = "ft2232_latency", + .handler = &ft2232_handle_latency_command, + .mode = COMMAND_CONFIG, + .help = "set the FT2232 latency timer to a new value", + .usage = " [...]", + }, + COMMAND_REGISTRATION_DONE +}; + +struct jtag_interface ft2232_interface = { + .name = "ft2232", + .commands = ft2232_command_handlers, + .init = &ft2232_init, + .quit = &ft2232_quit, + .speed = &ft2232_speed, + .speed_div = &ft2232_speed_div, + .khz = &ft2232_khz, + .execute_queue = &ft2232_execute_queue, + }; diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c new file mode 100644 index 00000000..b827fd53 --- /dev/null +++ b/src/jtag/drivers/gw16012.c @@ -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 +#include +#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 +#include +#define PPRSTATUS PPIGSTATUS +#define PPWDATA PPISDATA +#else +#include +#include +#endif +#include +#include +#else /* not PARPORT_USE_PPDEV */ +#ifndef _WIN32 +#include +#endif +#endif + +#if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 +#include +#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 = "", + }, + 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, + }; diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c new file mode 100644 index 00000000..9b2326bd --- /dev/null +++ b/src/jtag/drivers/jlink.c @@ -0,0 +1,1085 @@ +/*************************************************************************** + * Copyright (C) 2007 by Juergen Stuber * + * based on Dominic Rath's and Benedikt Sauter's usbprog.c * + * * + * Copyright (C) 2008 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 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_common.h" + + +#define VID 0x1366 +#define PID 0x0101 + +#define JLINK_WRITE_ENDPOINT 0x02 +#define JLINK_READ_ENDPOINT 0x81 + +static unsigned int jlink_write_ep = JLINK_WRITE_ENDPOINT; +static unsigned int jlink_read_ep = JLINK_READ_ENDPOINT; +static unsigned int jlink_hw_jtag_version = 2; + +#define JLINK_USB_TIMEOUT 1000 + +// See Section 1.3.2 of the Segger JLink USB protocol manual +/* 2048 is the max value we can use here */ +//#define JLINK_TAP_BUFFER_SIZE 2048 +#define JLINK_TAP_BUFFER_SIZE 256 +//#define JLINK_TAP_BUFFER_SIZE 384 + +#define JLINK_IN_BUFFER_SIZE 2048 +#define JLINK_OUT_BUFFER_SIZE 2*2048 + 4 +#define JLINK_EMU_RESULT_BUFFER_SIZE 64 + +/* Global USB buffers */ +static uint8_t usb_in_buffer[JLINK_IN_BUFFER_SIZE]; +static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; +static uint8_t usb_emu_result_buffer[JLINK_EMU_RESULT_BUFFER_SIZE]; + +/* Constants for JLink command */ +#define EMU_CMD_VERSION 0x01 +#define EMU_CMD_SET_SPEED 0x05 +#define EMU_CMD_GET_STATE 0x07 +#define EMU_CMD_HW_CLOCK 0xc8 +#define EMU_CMD_HW_TMS0 0xc9 +#define EMU_CMD_HW_TMS1 0xca +#define EMU_CMD_HW_JTAG2 0xce +#define EMU_CMD_HW_JTAG3 0xcf +#define EMU_CMD_GET_MAX_MEM_BLOCK 0xd4 +#define EMU_CMD_HW_RESET0 0xdc +#define EMU_CMD_HW_RESET1 0xdd +#define EMU_CMD_HW_TRST0 0xde +#define EMU_CMD_HW_TRST1 0xdf +#define EMU_CMD_GET_CAPS 0xe8 +#define EMU_CMD_GET_HW_VERSION 0xf0 + +/* bits return from EMU_CMD_GET_CAPS */ +#define EMU_CAP_GET_HW_VERSION 1 +#define EMU_CAP_GET_MAX_BLOCK_SIZE 11 + +/* max speed 12MHz v5.0 jlink */ +#define JLINK_MAX_SPEED 12000 + +/* Queue command functions */ +static void jlink_end_state(tap_state_t state); +static void jlink_state_move(void); +static void jlink_path_move(int num_states, tap_state_t *path); +static void jlink_runtest(int num_cycles); +static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); +static void jlink_reset(int trst, int srst); +static void jlink_simple_command(uint8_t command); +static int jlink_get_status(void); + +/* J-Link tap buffer functions */ +static void jlink_tap_init(void); +static int jlink_tap_execute(void); +static void jlink_tap_ensure_space(int scans, int bits); +static void jlink_tap_append_step(int tms, int tdi); +static void jlink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); + +/* Jlink lowlevel functions */ +struct jlink { + struct usb_dev_handle* usb_handle; +}; + +static struct jlink *jlink_usb_open(void); +static void jlink_usb_close(struct jlink *jlink); +static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length); +static int jlink_usb_write(struct jlink *jlink, int out_length); +static int jlink_usb_read(struct jlink *jlink, int expected_size); +static int jlink_usb_read_emu_result(struct jlink *jlink); + +/* helper functions */ +static int jlink_get_version_info(void); + +#ifdef _DEBUG_USB_COMMS_ +static void jlink_debug_buffer(uint8_t *buffer, int length); +#endif + +static enum tap_state jlink_last_state = TAP_RESET; + +static struct jlink* jlink_handle; + +/***************************************************************************/ +/* External interface implementation */ + +static void jlink_execute_runtest(struct jtag_command *cmd) +{ + DEBUG_JTAG_IO("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + + jlink_end_state(cmd->cmd.runtest->end_state); + + jlink_runtest(cmd->cmd.runtest->num_cycles); +} + +static void jlink_execute_statemove(struct jtag_command *cmd) +{ + DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + + jlink_end_state(cmd->cmd.statemove->end_state); + jlink_state_move(); +} + +static void jlink_execute_pathmove(struct jtag_command *cmd) +{ + DEBUG_JTAG_IO("pathmove: %i states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + + jlink_path_move(cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path); +} + +static void jlink_execute_scan(struct jtag_command *cmd) +{ + int scan_size; + enum scan_type type; + uint8_t *buffer; + + DEBUG_JTAG_IO("scan end in %s", tap_state_name(cmd->cmd.scan->end_state)); + + jlink_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_ + jlink_debug_buffer(buffer, (scan_size + 7) / 8); +#endif + type = jtag_scan_type(cmd->cmd.scan); + jlink_scan(cmd->cmd.scan->ir_scan, + type, buffer, scan_size, cmd->cmd.scan); +} + +static void jlink_execute_reset(struct jtag_command *cmd) +{ + DEBUG_JTAG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, cmd->cmd.reset->srst); + + jlink_tap_execute(); + jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + jlink_tap_execute(); +} + +static void jlink_execute_sleep(struct jtag_command *cmd) +{ + DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); + jlink_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); +} + +static void jlink_execute_command(struct jtag_command *cmd) +{ + switch (cmd->type) + { + case JTAG_RUNTEST: jlink_execute_runtest(cmd); break; + case JTAG_STATEMOVE: jlink_execute_statemove(cmd); break; + case JTAG_PATHMOVE: jlink_execute_pathmove(cmd); break; + case JTAG_SCAN: jlink_execute_scan(cmd); break; + case JTAG_RESET: jlink_execute_reset(cmd); break; + case JTAG_SLEEP: jlink_execute_sleep(cmd); break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } +} + +static int jlink_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; + + while (cmd != NULL) + { + jlink_execute_command(cmd); + cmd = cmd->next; + } + + return jlink_tap_execute(); +} + +/* Sets speed in kHz. */ +static int jlink_speed(int speed) +{ + int result; + + if (speed > JLINK_MAX_SPEED) + { + LOG_INFO("Ignoring speed request: %dkHz exceeds %dkHz maximum", + speed, JLINK_MAX_SPEED); + return ERROR_OK; + } + + /* check for RTCK setting */ + if (speed == 0) + speed = -1; + + usb_out_buffer[0] = EMU_CMD_SET_SPEED; + usb_out_buffer[1] = (speed >> 0) & 0xff; + usb_out_buffer[2] = (speed >> 8) & 0xff; + + result = jlink_usb_write(jlink_handle, 3); + if (result != 3) + { + LOG_ERROR("J-Link setting speed failed (%d)", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int jlink_speed_div(int speed, int* khz) +{ + *khz = speed; + + return ERROR_OK; +} + +static int jlink_khz(int khz, int *jtag_speed) +{ + *jtag_speed = khz; + + return ERROR_OK; +} + +static int jlink_init(void) +{ + int i; + + jlink_handle = jlink_usb_open(); + + if (jlink_handle == 0) + { + LOG_ERROR("Cannot find jlink Interface! Please check connection and permissions."); + return ERROR_JTAG_INIT_FAILED; + } + + /* + * The next three instructions were added after discovering a problem while using an oscilloscope. For the V8 + * SAM-ICE dongle (and likely other j-link device variants), the reset line to the target microprocessor was found to + * cycle only intermittently during emulator startup (even after encountering the downstream reset instruction later + * in the code). This was found to create two issues: 1) In general it is a bad practice to not reset a CPU to a known + * state when starting an emulator and 2) something critical happens inside the dongle when it does the first read + * following a new USB session. Keeping the processor in reset during the first read collecting version information + * seems to prevent errant "J-Link command EMU_CMD_VERSION failed" issues. + */ + + LOG_INFO("J-Link initialization started / target CPU reset initiated"); + jlink_simple_command(EMU_CMD_HW_TRST0); + jlink_simple_command(EMU_CMD_HW_RESET0); + usleep(1000); + + jlink_hw_jtag_version = 2; + + if (jlink_get_version_info() == ERROR_OK) + { + /* attempt to get status */ + jlink_get_status(); + } + + LOG_INFO("J-Link JTAG Interface ready"); + + jlink_reset(0, 0); + jtag_sleep(3000); + jlink_tap_init(); + jlink_speed(jtag_get_speed()); + + /* v5/6 jlink seems to have an issue if the first tap move + * is not divisible by 8, so we send a TLR on first power up */ + for (i = 0; i < 8; i++) { + jlink_tap_append_step(1, 0); + } + jlink_tap_execute(); + + return ERROR_OK; +} + +static int jlink_quit(void) +{ + jlink_usb_close(jlink_handle); + return ERROR_OK; +} + +/***************************************************************************/ +/* Queue command implementations */ + +static void jlink_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 jlink_state_move(void) +{ + int i; + int tms = 0; + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + for (i = 0; i < tms_scan_bits; i++) + { + tms = (tms_scan >> i) & 1; + jlink_tap_append_step(tms, 0); + } + + tap_set_state(tap_get_end_state()); +} + +static void jlink_path_move(int num_states, tap_state_t *path) +{ + int i; + + for (i = 0; i < num_states; i++) + { + if (path[i] == tap_state_transition(tap_get_state(), false)) + { + jlink_tap_append_step(0, 0); + } + else if (path[i] == tap_state_transition(tap_get_state(), true)) + { + jlink_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 jlink_runtest(int num_cycles) +{ + int i; + + tap_state_t saved_end_state = tap_get_end_state(); + + jlink_tap_ensure_space(1,num_cycles + 16); + + /* only do a state_move when we're not already in IDLE */ + if (tap_get_state() != TAP_IDLE) + { + jlink_end_state(TAP_IDLE); + jlink_state_move(); +// num_cycles--; + } + + /* execute num_cycles */ + for (i = 0; i < num_cycles; i++) + { + jlink_tap_append_step(0, 0); + } + + /* finish in end_state */ + jlink_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) + { + jlink_state_move(); + } +} + +static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) +{ + tap_state_t saved_end_state; + + jlink_tap_ensure_space(1, scan_size + 16); + + saved_end_state = tap_get_end_state(); + + /* Move to appropriate scan state */ + jlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); + + /* Only move if we're not already there */ + if (tap_get_state() != tap_get_end_state()) + jlink_state_move(); + + jlink_end_state(saved_end_state); + + /* Scan */ + jlink_tap_append_scan(scan_size, buffer, command); + + /* We are in Exit1, go to Pause */ + jlink_tap_append_step(0, 0); + + tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); + + if (tap_get_state() != tap_get_end_state()) + { + jlink_state_move(); + } +} + +static void jlink_reset(int trst, int srst) +{ + LOG_DEBUG("trst: %i, srst: %i", trst, srst); + + /* Signals are active low */ + if (srst == 0) + { + jlink_simple_command(EMU_CMD_HW_RESET1); + } + if (srst == 1) + { + jlink_simple_command(EMU_CMD_HW_RESET0); + } + + if (trst == 1) + { + jlink_simple_command(EMU_CMD_HW_TRST0); + } + + if (trst == 0) + { + jlink_simple_command(EMU_CMD_HW_TRST1); + } +} + +static void jlink_simple_command(uint8_t command) +{ + int result; + + DEBUG_JTAG_IO("0x%02x", command); + + usb_out_buffer[0] = command; + result = jlink_usb_write(jlink_handle, 1); + + if (result != 1) + { + LOG_ERROR("J-Link command 0x%02x failed (%d)", command, result); + } +} + +static int jlink_get_status(void) +{ + int result; + + jlink_simple_command(EMU_CMD_GET_STATE); + + result = jlink_usb_read(jlink_handle, 8); + if (result != 8) + { + LOG_ERROR("J-Link command EMU_CMD_GET_STATE failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + int vref = usb_in_buffer[0] + (usb_in_buffer[1] << 8); + LOG_INFO("Vref = %d.%d TCK = %d TDI = %d TDO = %d TMS = %d SRST = %d TRST = %d\n", \ + vref / 1000, vref % 1000, \ + usb_in_buffer[2], usb_in_buffer[3], usb_in_buffer[4], \ + usb_in_buffer[5], usb_in_buffer[6], usb_in_buffer[7]); + + if (vref < 1500) + LOG_ERROR("Vref too low. Check Target Power\n"); + + return ERROR_OK; +} + +static int jlink_get_version_info(void) +{ + int result; + int len; + uint32_t jlink_caps, jlink_max_size; + + /* query hardware version */ + jlink_simple_command(EMU_CMD_VERSION); + + result = jlink_usb_read(jlink_handle, 2); + if (2 != result) + { + LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + len = buf_get_u32(usb_in_buffer, 0, 16); + if (len > JLINK_IN_BUFFER_SIZE) + { + LOG_ERROR("J-Link command EMU_CMD_VERSION impossible return length 0x%0x", len); + len = JLINK_IN_BUFFER_SIZE; + } + + result = jlink_usb_read(jlink_handle, len); + if (result != len) + { + LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + usb_in_buffer[result] = 0; + LOG_INFO("%s", (char *)usb_in_buffer); + + /* query hardware capabilities */ + jlink_simple_command(EMU_CMD_GET_CAPS); + + result = jlink_usb_read(jlink_handle, 4); + if (4 != result) + { + LOG_ERROR("J-Link command EMU_CMD_GET_CAPS failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + jlink_caps = buf_get_u32(usb_in_buffer, 0, 32); + LOG_INFO("JLink caps 0x%x", (unsigned)jlink_caps); + + if (jlink_caps & (1 << EMU_CAP_GET_HW_VERSION)) + { + /* query hardware version */ + jlink_simple_command(EMU_CMD_GET_HW_VERSION); + + result = jlink_usb_read(jlink_handle, 4); + if (4 != result) + { + LOG_ERROR("J-Link command EMU_CMD_GET_HW_VERSION failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + uint32_t jlink_hw_version = buf_get_u32(usb_in_buffer, 0, 32); + uint32_t major_revision = (jlink_hw_version / 10000) % 100; + if (major_revision >= 5) + jlink_hw_jtag_version = 3; + + LOG_INFO("JLink hw version %i", (int)jlink_hw_version); + } + + if (jlink_caps & (1 << EMU_CAP_GET_MAX_BLOCK_SIZE)) + { + /* query hardware maximum memory block */ + jlink_simple_command(EMU_CMD_GET_MAX_MEM_BLOCK); + + result = jlink_usb_read(jlink_handle, 4); + if (4 != result) + { + LOG_ERROR("J-Link command EMU_CMD_GET_MAX_MEM_BLOCK failed (%d)\n", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + jlink_max_size = buf_get_u32(usb_in_buffer, 0, 32); + LOG_INFO("JLink max mem block %i", (int)jlink_max_size); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(jlink_handle_jlink_info_command) +{ + if (jlink_get_version_info() == ERROR_OK) + { + /* attempt to get status */ + jlink_get_status(); + } + + return ERROR_OK; +} + +COMMAND_HANDLER(jlink_handle_jlink_hw_jtag_command) +{ + switch (CMD_ARGC) { + case 0: + command_print(CMD_CTX, "jlink hw jtag %i", jlink_hw_jtag_version); + break; + case 1: { + int request_version = atoi(CMD_ARGV[0]); + switch (request_version) { + case 2: case 3: + jlink_hw_jtag_version = request_version; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + break; + } + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return ERROR_OK; +} + +static const struct command_registration jlink_command_handlers[] = { + { + .name = "jlink_info", + .handler = &jlink_handle_jlink_info_command, + .mode = COMMAND_EXEC, + .help = "show jlink info", + }, + { + .name = "jlink_hw_jtag", + .handler = &jlink_handle_jlink_hw_jtag_command, + .mode = COMMAND_EXEC, + .help = "access J-Link HW JTAG command version", + .usage = "[2|3]", + }, + COMMAND_REGISTRATION_DONE +}; + +struct jtag_interface jlink_interface = { + .name = "jlink", + + .commands = jlink_command_handlers, + + .execute_queue = &jlink_execute_queue, + .speed = &jlink_speed, + .speed_div = &jlink_speed_div, + .khz = &jlink_khz, + + .init = &jlink_init, + .quit = &jlink_quit, + }; + +/***************************************************************************/ +/* J-Link tap functions */ + + +static unsigned tap_length = 0; +static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE]; +static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE]; +static uint8_t tdo_buffer[JLINK_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 void jlink_tap_init(void) +{ + tap_length = 0; + pending_scan_results_length = 0; +} + +static void jlink_tap_ensure_space(int scans, int bits) +{ + int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; + int available_bits = JLINK_TAP_BUFFER_SIZE * 8 - tap_length - 32; + + if (scans > available_scans || bits > available_bits) + { + jlink_tap_execute(); + } +} + +static void jlink_tap_append_step(int tms, int tdi) +{ + int index = tap_length / 8; + + if (index >= JLINK_TAP_BUFFER_SIZE) + { + LOG_ERROR("jlink_tap_append_step: overflow"); + *(uint32_t *)0xFFFFFFFF = 0; + exit(-1); + } + + int bit_index = tap_length % 8; + uint8_t bit = 1 << bit_index; + + // we do not pad TMS, so be sure to initialize all bits + if (0 == bit_index) + { + tms_buffer[index] = tdi_buffer[index] = 0; + } + + if (tms) + tms_buffer[index] |= bit; + else + tms_buffer[index] &= ~bit; + + if (tdi) + tdi_buffer[index] |= bit; + else + tdi_buffer[index] &= ~bit; + + tap_length++; +} + +static void jlink_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++) + { + int tms = (i < (length - 1)) ? 0 : 1; + int tdi = (buffer[i / 8] & (1 << (i % 8))) != 0; + jlink_tap_append_step(tms, tdi); + } + 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 jlink_tap_execute(void) +{ + int byte_length; + int i; + int result; + + if (!tap_length) + return ERROR_OK; + + /* JLink returns an extra NULL in packet when size of incoming + * message is a multiple of 64, creates problems with USB comms. + * WARNING: This will interfere with tap state counting. */ + while ((DIV_ROUND_UP(tap_length, 8) % 64) == 0) + { + jlink_tap_append_step((tap_get_state() == TAP_RESET)?1:0, 0); + } + + // number of full bytes (plus one if some would be left over) + byte_length = DIV_ROUND_UP(tap_length, 8); + + bool use_jtag3 = jlink_hw_jtag_version >= 3; + usb_out_buffer[0] = use_jtag3 ? EMU_CMD_HW_JTAG3 : EMU_CMD_HW_JTAG2; + usb_out_buffer[1] = 0; + usb_out_buffer[2] = (tap_length >> 0) & 0xff; + usb_out_buffer[3] = (tap_length >> 8) & 0xff; + memcpy(usb_out_buffer + 4, tms_buffer, byte_length); + memcpy(usb_out_buffer + 4 + byte_length, tdi_buffer, byte_length); + + jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer, + tap_length, jlink_last_state); + + result = jlink_usb_message(jlink_handle, 4 + 2 * byte_length, byte_length); + if (result != byte_length) + { + LOG_ERROR("jlink_tap_execute, wrong result %d (expected %d)", result, byte_length); + jlink_tap_init(); + return ERROR_JTAG_QUEUE_FAILED; + } + + memcpy(tdo_buffer, usb_in_buffer, byte_length); + + 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_ + jlink_debug_buffer(buffer, DIV_ROUND_UP(length, 8)); +#endif + + if (jtag_read_buffer(buffer, command) != ERROR_OK) + { + jlink_tap_init(); + return ERROR_JTAG_QUEUE_FAILED; + } + + if (pending_scan_result->buffer != NULL) + { + free(pending_scan_result->buffer); + } + } + + jlink_tap_init(); + return ERROR_OK; +} + +/*****************************************************************************/ +/* JLink USB low-level functions */ + +static struct jlink* jlink_usb_open() +{ + 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; + + /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS + * AREA!!!!!!!!!!! The behavior of libusb is not completely + * consistent across Windows, Linux, and Mac OS X platforms. + * The actions taken in the following compiler conditionals may + * not agree with published documentation for libusb, but were + * found to be necessary through trials and tribulations. Even + * little tweaks can break one or more platforms, so if you do + * make changes test them carefully on all platforms before + * committing them! + */ + +#if IS_WIN32 == 0 + + usb_reset(dev); + +#if IS_DARWIN == 0 + + int timeout = 5; + /* reopen jlink after usb_reset + * on win32 this may take a second or two to re-enumerate */ + int retval; + while ((retval = jtag_usb_open(vids, pids, &dev)) != ERROR_OK) + { + usleep(1000); + timeout--; + if (!timeout) { + break; + } + } + if (ERROR_OK != retval) + return NULL; +#endif + +#endif + + /* usb_set_configuration required under win32 */ + struct usb_device *udev = usb_device(dev); + usb_set_configuration(dev, udev->config[0].bConfigurationValue); + 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(result->usb_handle, 0); +#endif + struct usb_interface *iface = udev->config->interface; + struct usb_interface_descriptor *desc = iface->altsetting; + for (int i = 0; i < desc->bNumEndpoints; i++) + { + uint8_t epnum = desc->endpoint[i].bEndpointAddress; + bool is_input = epnum & 0x80; + LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum); + if (is_input) + jlink_read_ep = epnum; + else + jlink_write_ep = epnum; + } + + struct jlink *result = malloc(sizeof(struct jlink)); + result->usb_handle = dev; + return result; +} + +static void jlink_usb_close(struct jlink *jlink) +{ + usb_close(jlink->usb_handle); + free(jlink); +} + +/* Send a message and receive the reply. */ +static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length) +{ + int result; + + result = jlink_usb_write(jlink, out_length); + if (result != out_length) + { + LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", + out_length, result); + return ERROR_JTAG_DEVICE_ERROR; + } + + result = jlink_usb_read(jlink, in_length); + if ((result != in_length) && (result != (in_length + 1))) + { + LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", + in_length, result); + return ERROR_JTAG_DEVICE_ERROR; + } + + if (jlink_hw_jtag_version < 3) + return result; + + int result2 = ERROR_OK; + if (result == in_length) + { + /* Must read the result from the EMU too */ + result2 = jlink_usb_read_emu_result(jlink); + if (1 != result2) + { + LOG_ERROR("jlink_usb_read_emu_result retried requested = 1, result=%d, in_length=%i", result2,in_length); + /* Try again once, should only happen if (in_length%64 == 0) */ + result2 = jlink_usb_read_emu_result(jlink); + if (1 != result2) + { + LOG_ERROR("jlink_usb_read_emu_result failed " + "(requested = 1, result=%d)", result2); + return ERROR_JTAG_DEVICE_ERROR; + } + } + + /* Check the result itself */ + result2 = usb_emu_result_buffer[0]; + } + else + { + /* Save the result, then remove it from return value */ + result2 = usb_in_buffer[result--]; + } + + if (result2) + { + LOG_ERROR("jlink_usb_message failed with result=%d)", result2); + return ERROR_JTAG_DEVICE_ERROR; + } + + return result; +} + +/* calls the given usb_bulk_* function, allowing for the data to trickle in with some timeouts */ +static int usb_bulk_with_retries( + int (*f)(usb_dev_handle *, int, char *, int, int), + usb_dev_handle *dev, int ep, + char *bytes, int size, int timeout) +{ + int tries = 3, count = 0; + + while (tries && (count < size)) + { + int result = f(dev, ep, bytes + count, size - count, timeout); + if (result > 0) + count += result; + else if ((-ETIMEDOUT != result) || !--tries) + return result; + } + return count; +} + +static int wrap_usb_bulk_write(usb_dev_handle *dev, int ep, + char *buff, int size, int timeout) +{ + /* usb_bulk_write() takes const char *buff */ + return usb_bulk_write(dev, ep, buff, size, timeout); +} + +static inline int usb_bulk_write_ex(usb_dev_handle *dev, int ep, + char *bytes, int size, int timeout) +{ + return usb_bulk_with_retries(&wrap_usb_bulk_write, + dev, ep, bytes, size, timeout); +} + +static inline int usb_bulk_read_ex(usb_dev_handle *dev, int ep, + char *bytes, int size, int timeout) +{ + return usb_bulk_with_retries(&usb_bulk_read, + dev, ep, bytes, size, timeout); +} + +/* Write data from out_buffer to USB. */ +static int jlink_usb_write(struct jlink *jlink, int out_length) +{ + int result; + + if (out_length > JLINK_OUT_BUFFER_SIZE) + { + LOG_ERROR("jlink_write illegal out_length=%d (max=%d)", out_length, JLINK_OUT_BUFFER_SIZE); + return -1; + } + + result = usb_bulk_write_ex(jlink->usb_handle, jlink_write_ep, + (char *)usb_out_buffer, out_length, JLINK_USB_TIMEOUT); + + DEBUG_JTAG_IO("jlink_usb_write, out_length = %d, result = %d", out_length, result); + +#ifdef _DEBUG_USB_COMMS_ + jlink_debug_buffer(usb_out_buffer, out_length); +#endif + return result; +} + +/* Read data from USB into in_buffer. */ +static int jlink_usb_read(struct jlink *jlink, int expected_size) +{ + int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, + (char *)usb_in_buffer, expected_size, JLINK_USB_TIMEOUT); + + DEBUG_JTAG_IO("jlink_usb_read, result = %d", result); + +#ifdef _DEBUG_USB_COMMS_ + jlink_debug_buffer(usb_in_buffer, result); +#endif + return result; +} + +/* Read the result from the previous EMU cmd into result_buffer. */ +static int jlink_usb_read_emu_result(struct jlink *jlink) +{ + int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, + (char *)usb_emu_result_buffer, 1 /* JLINK_EMU_RESULT_BUFFER_SIZE */, + JLINK_USB_TIMEOUT); + + DEBUG_JTAG_IO("jlink_usb_read_result, result = %d", result); + +#ifdef _DEBUG_USB_COMMS_ + jlink_debug_buffer(usb_emu_result_buffer, result); +#endif + return result; +} + +#ifdef _DEBUG_USB_COMMS_ +#define BYTES_PER_LINE 16 + +static void jlink_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 + diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c new file mode 100644 index 00000000..e5f56113 --- /dev/null +++ b/src/jtag/drivers/parport.c @@ -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 +#include +#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 +#include +#define PPRSTATUS PPIGSTATUS +#define PPWDATA PPISDATA +#else +#include +#include +#endif +#include +#else /* not PARPORT_USE_PPDEV */ +#ifndef _WIN32 +#include +#endif +#endif + +#if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 +#include +#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 "); + 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 = "[]", + }, + { + .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 = "[]", + }, + { + .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 = "[]", + }, + { + .name = "parport_toggling_time", + .handler = &parport_handle_parport_toggling_time_command, + .mode = COMMAND_CONFIG, + .help = "time it takes for the hardware to toggle TCK", + .usage = "[]", + }, + 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, + }; diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c new file mode 100644 index 00000000..f4e689c2 --- /dev/null +++ b/src/jtag/drivers/presto.c @@ -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 +#elif BUILD_PRESTO_LIBFTDI == 1 +#include +#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 "); + } + + 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 = "", + }, + 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, + }; diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c new file mode 100644 index 00000000..a039080e --- /dev/null +++ b/src/jtag/drivers/rlink.c @@ -0,0 +1,1812 @@ +/*************************************************************************** + * Copyright (C) 2005 by Dominic Rath * + * Dominic.Rath@gmx.de * + * * + * Copyright (C) 2007,2008 Øyvind Harboe * + * oyvind.harboe@zylin.com * + * * + * Copyright (C) 2008 Rob Brown, Lou Deluxe * + * rob@cobbleware.com, 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* project specific includes */ +#include "interface.h" +#include "commands.h" +#include "rlink.h" +#include "rlink_st7.h" +#include "rlink_ep1_cmd.h" +#include "rlink_dtc_cmd.h" +#include "usb_common.h" + + +/* This feature is made useless by running the DTC all the time. When automatic, the LED is on whenever the DTC is running. Otherwise, USB messages are sent to turn it on and off. */ +#undef AUTOMATIC_BUSY_LED + +/* This feature may require derating the speed due to reduced hold time. */ +#undef USE_HARDWARE_SHIFTER_FOR_TMS + + +#define INTERFACE_NAME "RLink" + +#define USB_IDVENDOR (0x138e) +#define USB_IDPRODUCT (0x9000) + +#define USB_EP1OUT_ADDR (0x01) +#define USB_EP1OUT_SIZE (16) +#define USB_EP1IN_ADDR (USB_EP1OUT_ADDR | 0x80) +#define USB_EP1IN_SIZE (USB_EP1OUT_SIZE) + +#define USB_EP2OUT_ADDR (0x02) +#define USB_EP2OUT_SIZE (64) +#define USB_EP2IN_ADDR (USB_EP2OUT_ADDR | 0x80) +#define USB_EP2IN_SIZE (USB_EP2OUT_SIZE) +#define USB_EP2BANK_SIZE (512) + +#define USB_TIMEOUT_MS (3 * 1000) + +#define DTC_STATUS_POLL_BYTE (ST7_USB_BUF_EP0OUT + 0xff) + + +#define ST7_PD_NBUSY_LED ST7_PD0 +#define ST7_PD_NRUN_LED ST7_PD1 +/* low enables VPP at adapter header, high connects it to GND instead */ +#define ST7_PD_VPP_SEL ST7_PD6 +/* low: VPP = 12v, high: VPP <= 5v */ +#define ST7_PD_VPP_SHDN ST7_PD7 + +/* These pins are connected together */ +#define ST7_PE_ADAPTER_SENSE_IN ST7_PE3 +#define ST7_PE_ADAPTER_SENSE_OUT ST7_PE4 + +/* Symbolic mapping between port pins and numbered IO lines */ +#define ST7_PA_IO1 ST7_PA1 +#define ST7_PA_IO2 ST7_PA2 +#define ST7_PA_IO4 ST7_PA4 +#define ST7_PA_IO8 ST7_PA6 +#define ST7_PA_IO10 ST7_PA7 +#define ST7_PB_IO5 ST7_PB5 +#define ST7_PC_IO9 ST7_PC1 +#define ST7_PC_IO3 ST7_PC2 +#define ST7_PC_IO7 ST7_PC3 +#define ST7_PE_IO6 ST7_PE5 + +/* Symbolic mapping between numbered IO lines and adapter signals */ +#define ST7_PA_RTCK ST7_PA_IO0 +#define ST7_PA_NTRST ST7_PA_IO1 +#define ST7_PC_TDI ST7_PC_IO3 +#define ST7_PA_DBGRQ ST7_PA_IO4 +#define ST7_PB_NSRST ST7_PB_IO5 +#define ST7_PE_TMS ST7_PE_IO6 +#define ST7_PC_TCK ST7_PC_IO7 +#define ST7_PC_TDO ST7_PC_IO9 +#define ST7_PA_DBGACK ST7_PA_IO10 + +static usb_dev_handle *pHDev; + + +/* + * ep1 commands are up to USB_EP1OUT_SIZE bytes in length. + * This function takes care of zeroing the unused bytes before sending the packet. + * Any reply packet is not handled by this function. + */ +static +int +ep1_generic_commandl( + usb_dev_handle *pHDev, + size_t length, + ... +) { + uint8_t usb_buffer[USB_EP1OUT_SIZE]; + uint8_t *usb_buffer_p; + va_list ap; + int usb_ret; + + if (length > sizeof(usb_buffer)) { + length = sizeof(usb_buffer); + } + + usb_buffer_p = usb_buffer; + + va_start(ap, length); + while (length > 0) { + *usb_buffer_p++ = va_arg(ap, int); + length--; + } + + memset( + usb_buffer_p, + 0, + sizeof(usb_buffer) - (usb_buffer_p - usb_buffer) +); + + usb_ret = usb_bulk_write( + pHDev, + USB_EP1OUT_ADDR, + (char *)usb_buffer, sizeof(usb_buffer), + USB_TIMEOUT_MS +); + + return(usb_ret); +} + + + +#if 0 +static +ssize_t +ep1_memory_read( + usb_dev_handle *pHDev, + uint16_t addr, + size_t length, + uint8_t *buffer +) { + uint8_t usb_buffer[USB_EP1OUT_SIZE]; + int usb_ret; + size_t remain; + ssize_t count; + + usb_buffer[0] = EP1_CMD_MEMORY_READ; + memset( + usb_buffer + 4, + 0, + sizeof(usb_buffer) - 4 +); + + remain = length; + count = 0; + + while (remain) { + if (remain > sizeof(usb_buffer)) { + length = sizeof(usb_buffer); + } else { + length = remain; + } + + usb_buffer[1] = addr >> 8; + usb_buffer[2] = addr; + usb_buffer[3] = length; + + usb_ret = usb_bulk_write( + pHDev, USB_EP1OUT_ADDR, + usb_buffer, sizeof(usb_buffer), + USB_TIMEOUT_MS +); + + if (usb_ret < sizeof(usb_buffer)) { + break; + } + + usb_ret = usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + buffer, length, + USB_TIMEOUT_MS +); + + if (usb_ret < length) { + break; + } + + addr += length; + buffer += length; + count += length; + remain -= length; + } + + return(count); +} +#endif + + + +static +ssize_t +ep1_memory_write( + usb_dev_handle *pHDev, + uint16_t addr, + size_t length, + uint8_t const *buffer +) { + uint8_t usb_buffer[USB_EP1OUT_SIZE]; + int usb_ret; + size_t remain; + ssize_t count; + + usb_buffer[0] = EP1_CMD_MEMORY_WRITE; + + remain = length; + count = 0; + + while (remain) { + if (remain > (sizeof(usb_buffer) - 4)) { + length = (sizeof(usb_buffer) - 4); + } else { + length = remain; + } + + usb_buffer[1] = addr >> 8; + usb_buffer[2] = addr; + usb_buffer[3] = length; + memcpy( + usb_buffer + 4, + buffer, + length +); + memset( + usb_buffer + 4 + length, + 0, + sizeof(usb_buffer) - 4 - length +); + + usb_ret = usb_bulk_write( + pHDev, USB_EP1OUT_ADDR, + (char *)usb_buffer, sizeof(usb_buffer), + USB_TIMEOUT_MS +); + + if ((size_t)usb_ret < sizeof(usb_buffer)) { + break; + } + + addr += length; + buffer += length; + count += length; + remain -= length; + } + + return(count); +} + + +#if 0 +static +ssize_t +ep1_memory_writel( + usb_dev_handle *pHDev, + uint16_t addr, + size_t length, + ... +) { + uint8_t buffer[USB_EP1OUT_SIZE - 4]; + uint8_t *buffer_p; + va_list ap; + size_t remain; + + if (length > sizeof(buffer)) { + length = sizeof(buffer); + } + + remain = length; + buffer_p = buffer; + + va_start(ap, length); + while (remain > 0) { + *buffer_p++ = va_arg(ap, int); + remain--; + } + + return(ep1_memory_write(pHDev, addr, length, buffer)); +} +#endif + + +#define DTCLOAD_COMMENT (0) +#define DTCLOAD_ENTRY (1) +#define DTCLOAD_LOAD (2) +#define DTCLOAD_RUN (3) +#define DTCLOAD_LUT_START (4) +#define DTCLOAD_LUT (5) + +#define DTC_LOAD_BUFFER ST7_USB_BUF_EP2UIDO + +/* This gets set by the DTC loader */ +static uint8_t dtc_entry_download; + + +/* The buffer is specially formatted to represent a valid image to load into the DTC. */ +static +int +dtc_load_from_buffer( + usb_dev_handle *pHDev, + const uint8_t *buffer, + size_t length +) { + struct header_s { + uint8_t type; + uint8_t length; + }; + + int usb_err; + struct header_s *header; + uint8_t lut_start = 0xc0; + + dtc_entry_download = 0; + + /* Stop the DTC before loading anything. */ + usb_err = ep1_generic_commandl( + pHDev, 1, + EP1_CMD_DTC_STOP +); + if (usb_err < 0) return(usb_err); + + while (length) { + if (length < sizeof(*header)) { + LOG_ERROR("Malformed DTC image\n"); + exit(1); + } + + header = (struct header_s *)buffer; + buffer += sizeof(*header); + length -= sizeof(*header); + + if (length < (size_t)header->length + 1) { + LOG_ERROR("Malformed DTC image\n"); + exit(1); + } + + switch (header->type) { + case DTCLOAD_COMMENT: + break; + + case DTCLOAD_ENTRY: + /* store entry addresses somewhere */ + if (!strncmp("download", (char *)buffer + 1, 8)) { + dtc_entry_download = buffer[0]; + } + break; + + case DTCLOAD_LOAD: + /* Send the DTC program to ST7 RAM. */ + usb_err = ep1_memory_write( + pHDev, + DTC_LOAD_BUFFER, + header->length + 1, buffer +); + if (usb_err < 0) return(usb_err); + + /* Load it into the DTC. */ + usb_err = ep1_generic_commandl( + pHDev, 3, + EP1_CMD_DTC_LOAD, + (DTC_LOAD_BUFFER >> 8), + DTC_LOAD_BUFFER +); + if (usb_err < 0) return(usb_err); + + break; + + case DTCLOAD_RUN: + usb_err = ep1_generic_commandl( + pHDev, 3, + EP1_CMD_DTC_CALL, + buffer[0], + EP1_CMD_DTC_WAIT +); + if (usb_err < 0) return(usb_err); + + break; + + case DTCLOAD_LUT_START: + lut_start = buffer[0]; + break; + + case DTCLOAD_LUT: + usb_err = ep1_memory_write( + pHDev, + ST7_USB_BUF_EP0OUT + lut_start, + header->length + 1, buffer +); + if (usb_err < 0) return(usb_err); + break; + + default: + LOG_ERROR("Invalid DTC image record type: 0x%02x\n", header->type); + exit(1); + break; + } + + buffer += (header->length + 1); + length -= (header->length + 1); + } + + return(0); +} + + +/* + * Start the DTC running in download mode (waiting for 512 byte command packets on ep2). + */ +static +int +dtc_start_download(void) { + int usb_err; + uint8_t ep2txr; + + /* set up for download mode and make sure EP2 is set up to transmit */ + usb_err = ep1_generic_commandl( + pHDev, 7, + + EP1_CMD_DTC_STOP, + EP1_CMD_SET_UPLOAD, + EP1_CMD_SET_DOWNLOAD, + EP1_CMD_MEMORY_READ, /* read EP2TXR for its data toggle */ + ST7_EP2TXR >> 8, + ST7_EP2TXR, + 1 +); + if (usb_err < 0) return(usb_err); + + /* read back ep2txr */ + usb_err = usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)&ep2txr, 1, + USB_TIMEOUT_MS +); + if (usb_err < 0) return(usb_err); + + usb_err = ep1_generic_commandl( + pHDev, 13, + + EP1_CMD_MEMORY_WRITE, /* preinitialize poll byte */ + DTC_STATUS_POLL_BYTE >> 8, + DTC_STATUS_POLL_BYTE, + 1, + 0x00, + EP1_CMD_MEMORY_WRITE, /* set EP2IN to return data */ + ST7_EP2TXR >> 8, + ST7_EP2TXR, + 1, + (ep2txr & ST7_EP2TXR_DTOG_TX) | ST7_EP2TXR_STAT_VALID, + EP1_CMD_DTC_CALL, /* start running the DTC */ + dtc_entry_download, + EP1_CMD_DTC_GET_CACHED_STATUS +); + if (usb_err < 0) return(usb_err); + + /* wait for completion */ + usb_err = usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)&ep2txr, 1, + USB_TIMEOUT_MS +); + + return(usb_err); +} + + +static +int +dtc_run_download( + usb_dev_handle *pHDev, + uint8_t *command_buffer, + int command_buffer_size, + uint8_t *reply_buffer, + int reply_buffer_size +) { + uint8_t ep2_buffer[USB_EP2IN_SIZE]; + int usb_err; + int i; + + LOG_DEBUG(": %d/%d\n", command_buffer_size, reply_buffer_size); + + usb_err = usb_bulk_write( + pHDev, + USB_EP2OUT_ADDR, + (char *)command_buffer, USB_EP2BANK_SIZE, + USB_TIMEOUT_MS +); + if (usb_err < 0) return(usb_err); + + + /* Wait for DTC to finish running command buffer */ + for (i = 10;;) { + usb_err = ep1_generic_commandl( + pHDev, 4, + + EP1_CMD_MEMORY_READ, + DTC_STATUS_POLL_BYTE >> 8, + DTC_STATUS_POLL_BYTE, + 1 +); + if (usb_err < 0) return(usb_err); + + usb_err = usb_bulk_read( + pHDev, + USB_EP1IN_ADDR, + (char *)ep2_buffer, 1, + USB_TIMEOUT_MS +); + if (usb_err < 0) return(usb_err); + + if (ep2_buffer[0] & 0x01) break; + + if (!--i) { + LOG_ERROR("%s, %d: too many retries waiting for DTC status\n", + __FILE__, __LINE__ +); + return(-ETIMEDOUT); + } + } + + + if (!reply_buffer) reply_buffer_size = 0; + if (reply_buffer_size) { + usb_err = usb_bulk_read( + pHDev, + USB_EP2IN_ADDR, + (char *)ep2_buffer, sizeof(ep2_buffer), + USB_TIMEOUT_MS +); + + if (usb_err < (int)sizeof(ep2_buffer)) { + LOG_ERROR("%s, %d: Read of endpoint 2 returned %d\n", + __FILE__, __LINE__, usb_err +); + return(usb_err); + } + + memcpy(reply_buffer, ep2_buffer, reply_buffer_size); + + } + + return(usb_err); +} + + +/* + * The dtc reply queue is a singly linked list that describes what to do with the reply packet that comes from the DTC. Only SCAN_IN and SCAN_IO generate these entries. + */ + +struct dtc_reply_queue_entry { + struct dtc_reply_queue_entry *next; + struct jtag_command *cmd; /* the command that resulted in this entry */ + + struct { + uint8_t *buffer; /* the scan buffer */ + int size; /* size of the scan buffer in bits */ + int offset; /* how many bits were already done before this? */ + int length; /* how many bits are processed in this operation? */ + enum scan_type type; /* SCAN_IN/SCAN_OUT/SCAN_IO */ + } scan; +}; + + +/* + * The dtc_queue consists of a buffer of pending commands and a reply queue. + * rlink_scan and tap_state_run add to the command buffer and maybe to the reply queue. + */ + +static +struct { + struct dtc_reply_queue_entry *rq_head; + struct dtc_reply_queue_entry *rq_tail; + uint32_t cmd_index; + uint32_t reply_index; + uint8_t cmd_buffer[USB_EP2BANK_SIZE]; +} dtc_queue; + + +/* + * The tap state queue is for accumulating TAP state changes wiithout needlessly flushing the dtc_queue. When it fills or is run, it adds the accumulated bytes to the dtc_queue. + */ + +static +struct { + uint32_t length; + uint32_t buffer; +} tap_state_queue; + + + +static +int +dtc_queue_init(void) { + dtc_queue.rq_head = NULL; + dtc_queue.rq_tail = NULL; + dtc_queue.cmd_index = 0; + dtc_queue.reply_index = 0; + return(0); +} + + +static +inline +struct dtc_reply_queue_entry * +dtc_queue_enqueue_reply( + enum scan_type type, + uint8_t *buffer, + int size, + int offset, + int length, + struct jtag_command *cmd +) { + struct dtc_reply_queue_entry *rq_entry; + + rq_entry = malloc(sizeof(struct dtc_reply_queue_entry)); + if (rq_entry != NULL) { + rq_entry->scan.type = type; + rq_entry->scan.buffer = buffer; + rq_entry->scan.size = size; + rq_entry->scan.offset = offset; + rq_entry->scan.length = length; + rq_entry->cmd = cmd; + rq_entry->next = NULL; + + if (dtc_queue.rq_head == NULL) + dtc_queue.rq_head = rq_entry; + else + dtc_queue.rq_tail->next = rq_entry; + + dtc_queue.rq_tail = rq_entry; + } + + return(rq_entry); +} + + +/* + * Running the queue means that any pending command buffer is run and any reply data dealt with. The command buffer is then cleared for subsequent processing. + * The queue is automatically run by append when it is necessary to get space for the append. +*/ + +static +int +dtc_queue_run(void) { + struct dtc_reply_queue_entry *rq_p, *rq_next; + int retval; + int usb_err; + int bit_cnt; + int x; + uint8_t *dtc_p, *tdo_p; + uint8_t dtc_mask, tdo_mask; + uint8_t reply_buffer[USB_EP2IN_SIZE]; + + retval = ERROR_OK; + + if (dtc_queue.cmd_index < 1) return(retval); + + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_STOP; + + /* run the cmd */ + if (dtc_queue.rq_head == NULL) { + usb_err = dtc_run_download(pHDev, + dtc_queue.cmd_buffer, dtc_queue.cmd_index, + NULL, 0 +); + if (usb_err < 0) { + LOG_ERROR("dtc_run_download: %s\n", usb_strerror()); + exit(1); + } + } else { + usb_err = dtc_run_download(pHDev, + dtc_queue.cmd_buffer, dtc_queue.cmd_index, + reply_buffer, dtc_queue.reply_index +); + if (usb_err < 0) { + LOG_ERROR("dtc_run_download: %s\n", usb_strerror()); + exit(1); + } else { + /* process the reply, which empties the reply queue and frees its entries */ + dtc_p = reply_buffer; + + /* The rigamarole with the masks and doing it bit-by-bit is due to the fact that the scan buffer is LSb-first and the DTC code is MSb-first for hardware reasons. It was that or craft a function to do the reversal, and that wouldn't work with bit-stuffing (supplying extra bits to use mostly byte operations), or any other scheme which would throw the byte alignment off. */ + + for ( + rq_p = dtc_queue.rq_head; + rq_p != NULL; + rq_p = rq_next +) { + tdo_p = rq_p->scan.buffer + (rq_p->scan.offset / 8); + tdo_mask = 1 << (rq_p->scan.offset % 8); + + + bit_cnt = rq_p->scan.length; + if (bit_cnt >= 8) { + /* bytes */ + + dtc_mask = 1 << (8 - 1); + + for ( + ; + bit_cnt; + bit_cnt-- +) { + if (*dtc_p & dtc_mask) { + *tdo_p |= tdo_mask; + } else { + *tdo_p &=~ tdo_mask; + } + + dtc_mask >>= 1; + if (dtc_mask == 0) { + dtc_p++; + dtc_mask = 1 << (8 - 1); + } + + tdo_mask <<= 1; + if (tdo_mask == 0) { + tdo_p++; + tdo_mask = 1; + } + } + } else { + /* extra bits or last bit */ + + x = *dtc_p++; + if (( + rq_p->scan.type == SCAN_IN +) && ( + rq_p->scan.offset != rq_p->scan.size - 1 +)) { + /* extra bits were sent as a full byte with padding on the end */ + dtc_mask = 1 << (8 - 1); + } else { + dtc_mask = 1 << (bit_cnt - 1); + } + + for ( + ; + bit_cnt; + bit_cnt-- +) { + if (x & dtc_mask) { + *tdo_p |= tdo_mask; + } else { + *tdo_p &=~ tdo_mask; + } + + dtc_mask >>= 1; + + tdo_mask <<= 1; + if (tdo_mask == 0) { + tdo_p++; + tdo_mask = 1; + } + + } + } + + if ((rq_p->scan.offset + rq_p->scan.length) >= rq_p->scan.size) { + /* feed scan buffer back into openocd and free it */ + if (jtag_read_buffer(rq_p->scan.buffer, rq_p->cmd->cmd.scan) != ERROR_OK) { + retval = ERROR_JTAG_QUEUE_FAILED; + } + free(rq_p->scan.buffer); + } + + rq_next = rq_p->next; + free(rq_p); + } + dtc_queue.rq_head = NULL; + dtc_queue.rq_tail = NULL; + } + + } + + + /* reset state for new appends */ + dtc_queue.cmd_index = 0; + dtc_queue.reply_index = 0; + + return(retval); +} + + + +static +int +tap_state_queue_init(void) { + tap_state_queue.length = 0; + tap_state_queue.buffer = 0; + return(0); +} + + +static +int +tap_state_queue_run(void) { + int i; + int bits; + uint8_t byte; + int retval; + + retval = 0; + if (!tap_state_queue.length) return(retval); + bits = 1; + byte = 0; + for (i = tap_state_queue.length; i--;) { + + byte <<= 1; + if (tap_state_queue.buffer & 1) { + byte |= 1; + } + if ((bits >= 8) || !i) { + byte <<= (8 - bits); + + /* make sure there's room for stop, byte op, and one byte */ + if (dtc_queue.cmd_index >= (sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1))) { + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_STOP; + dtc_queue_run(); + } + +#ifdef USE_HARDWARE_SHIFTER_FOR_TMS + if (bits == 8) { + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_SHIFT_TMS_BYTES(1); + } else { +#endif + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_SHIFT_TMS_BITS(bits); +#ifdef USE_HARDWARE_SHIFTER_FOR_TMS + } +#endif + + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + byte; + + byte = 0; + bits = 1; + } else { + bits++; + } + + tap_state_queue.buffer >>= 1; + } + retval = tap_state_queue_init(); + return(retval); +} + + +static +int +tap_state_queue_append( + uint8_t tms +) { + int retval; + + if (tap_state_queue.length >= sizeof(tap_state_queue.buffer) * 8) { + retval = tap_state_queue_run(); + if (retval != 0) return(retval); + } + + if (tms) { + tap_state_queue.buffer |= (1 << tap_state_queue.length); + } + tap_state_queue.length++; + + return(0); +} + + +static +void rlink_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 rlink_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()); + + for (i = 0; i < tms_count; i++) + { + tms = (tms_scan >> i) & 1; + tap_state_queue_append(tms); + } + + tap_set_state(tap_get_end_state()); +} + +static +void rlink_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); + } + + tap_state_queue_append(tms); + + tap_set_state(cmd->path[state_count]); + state_count++; + num_states--; + } + + tap_set_end_state(tap_get_state()); +} + + +static +void rlink_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 RTI */ + if (tap_get_state() != TAP_IDLE) + { + rlink_end_state(TAP_IDLE); + rlink_state_move(); + } + + /* execute num_cycles */ + for (i = 0; i < num_cycles; i++) + { + tap_state_queue_append(0); + } + + /* finish in end_state */ + rlink_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) + rlink_state_move(); +} + + +/* (1) assert or (0) deassert reset lines */ +static +void rlink_reset(int trst, int srst) +{ + uint8_t bitmap; + int usb_err; + + /* Read port A for bit op */ + usb_err = ep1_generic_commandl( + pHDev, 4, + EP1_CMD_MEMORY_READ, + ST7_PADR >> 8, + ST7_PADR, + 1 +); + if (usb_err < 0) { + LOG_ERROR("%s", usb_strerror()); + exit(1); + } + + usb_err = usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)&bitmap, 1, + USB_TIMEOUT_MS +); + if (usb_err < 1) { + LOG_ERROR("%s", usb_strerror()); + exit(1); + } + + if (trst) { + bitmap &= ~ST7_PA_NTRST; + } else { + bitmap |= ST7_PA_NTRST; + } + + /* Write port A and read port B for bit op */ + /* port B has no OR, and we want to emulate open drain on NSRST, so we initialize DR to 0 and assert NSRST by setting DDR to 1. */ + usb_err = ep1_generic_commandl( + pHDev, 9, + EP1_CMD_MEMORY_WRITE, + ST7_PADR >> 8, + ST7_PADR, + 1, + bitmap, + EP1_CMD_MEMORY_READ, + ST7_PBDDR >> 8, + ST7_PBDDR, + 1 +); + if (usb_err < 0) { + LOG_ERROR("%s", usb_strerror()); + exit(1); + } + + usb_err = usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)&bitmap, 1, + USB_TIMEOUT_MS +); + if (usb_err < 1) { + LOG_ERROR("%s", usb_strerror()); + exit(1); + } + + if (srst) { + bitmap |= ST7_PB_NSRST; + } else { + bitmap &= ~ST7_PB_NSRST; + } + + /* write port B and read dummy to ensure completion before returning */ + usb_err = ep1_generic_commandl( + pHDev, 6, + EP1_CMD_MEMORY_WRITE, + ST7_PBDDR >> 8, + ST7_PBDDR, + 1, + bitmap, + EP1_CMD_DTC_GET_CACHED_STATUS +); + if (usb_err < 0) { + LOG_ERROR("%s", usb_strerror()); + exit(1); + } + + usb_err = usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)&bitmap, 1, + USB_TIMEOUT_MS +); + if (usb_err < 1) { + LOG_ERROR("%s", usb_strerror()); + exit(1); + } +} + + +static +int +rlink_scan( + struct jtag_command *cmd, + enum scan_type type, + uint8_t *buffer, + int scan_size +) { + bool ir_scan; + tap_state_t saved_end_state; + int byte_bits; + int extra_bits; + int chunk_bits; + int chunk_bytes; + int x; + + int tdi_bit_offset; + uint8_t tdi_mask, *tdi_p; + uint8_t dtc_mask; + + if (scan_size < 1) { + LOG_ERROR("scan_size cannot be less than 1 bit\n"); + exit(1); + } + + ir_scan = cmd->cmd.scan->ir_scan; + + /* Move to the proper state before starting to shift TDI/TDO. */ + if (!( + (!ir_scan && (tap_get_state() == TAP_DRSHIFT)) + || + (ir_scan && (tap_get_state() == TAP_IRSHIFT)) +)) { + saved_end_state = tap_get_end_state(); + rlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); + rlink_state_move(); + rlink_end_state(saved_end_state); + } + + tap_state_queue_run(); + + +#if 0 + printf("scan_size = %d, type = 0x%x\n", scan_size, type); + { + int i; + + /* clear unused bits in scan buffer for ease of debugging */ + /* (it makes diffing output easier) */ + buffer[scan_size / 8] &= ((1 << ((scan_size - 1) % 8) + 1) - 1); + + printf("before scan:"); + for (i = 0; i < (scan_size + 7) / 8; i++) { + printf(" %02x", buffer[i]); + } + printf("\n"); + } +#endif + + /* The number of bits that can be shifted as complete bytes */ + byte_bits = (int)(scan_size - 1) / 8 * 8; + /* The number of bits left over, not counting the last bit */ + extra_bits = (scan_size - 1) - byte_bits; + + tdi_bit_offset = 0; + tdi_p = buffer; + tdi_mask = 1; + + if (extra_bits && (type == SCAN_OUT)) { + /* Schedule any extra bits into the DTC command buffer, padding as needed */ + /* For SCAN_OUT, this comes before the full bytes so the (leading) padding bits will fall off the end */ + /* make sure there's room for stop, byte op, and one byte */ + if ( + (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1)) +) { + dtc_queue_run(); + } + + x = 0; + dtc_mask = 1 << (extra_bits - 1); + + while (extra_bits--) { + if (*tdi_p & tdi_mask) { + x |= dtc_mask; + } + + dtc_mask >>= 1; + + tdi_mask <<= 1; + if (tdi_mask == 0) { + tdi_p++; + tdi_mask = 1; + } + } + + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_SHIFT_TDI_BYTES(1); + + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; + } + + /* Loop scheduling full bytes into the DTC command buffer */ + while (byte_bits) { + if (type == SCAN_IN) { + /* make sure there's room for stop and byte op */ + x = (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1)); + } else { + /* make sure there's room for stop, byte op, and at least one byte */ + x = (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1)); + } + + if (type != SCAN_OUT) { + /* make sure there's room for at least one reply byte */ + x |= (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1)); + } + + if (x) { + dtc_queue_run(); + } + + chunk_bits = byte_bits; + /* we can only use up to 16 bytes at a time */ + if (chunk_bits > (16 * 8)) chunk_bits = (16 * 8); + + if (type != SCAN_IN) { + /* how much is there room for, considering stop and byte op? */ + x = (sizeof(dtc_queue.cmd_buffer) - (dtc_queue.cmd_index + 1 + 1)) * 8; + if (chunk_bits > x) chunk_bits = x; + } + + if (type != SCAN_OUT) { + /* how much is there room for in the reply buffer? */ + x = (USB_EP2IN_SIZE - dtc_queue.reply_index) * 8; + if (chunk_bits > x) chunk_bits = x; + } + + /* so the loop will end */ + byte_bits -= chunk_bits; + + if (type != SCAN_OUT) { + if (dtc_queue_enqueue_reply( + type, buffer, scan_size, tdi_bit_offset, + chunk_bits, + cmd +) == NULL) { + LOG_ERROR("enqueuing DTC reply entry: %s\n", strerror(errno)); + exit(1); + } + + tdi_bit_offset += chunk_bits; + } + + /* chunk_bits is a multiple of 8, so there are no rounding issues. */ + chunk_bytes = chunk_bits / 8; + + switch (type) { + case SCAN_IN: + x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); + break; + case SCAN_OUT: + x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); + break; + default: + x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); + break; + } + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; + + if (type != SCAN_IN) { + x = 0; + dtc_mask = 1 << (8 - 1); + + while (chunk_bits--) { + if (*tdi_p & tdi_mask) { + x |= dtc_mask; + } + + dtc_mask >>= 1; + if (dtc_mask == 0) { + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; + dtc_queue.reply_index++; + x = 0; + dtc_mask = 1 << (8 - 1); + } + + tdi_mask <<= 1; + if (tdi_mask == 0) { + tdi_p++; + tdi_mask = 1; + } + } + } + } + + if (extra_bits && (type != SCAN_OUT)) { + /* Schedule any extra bits into the DTC command buffer */ + /* make sure there's room for stop, byte op, and one byte */ + if ( + (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1)) + || + (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1)) +) { + dtc_queue_run(); + } + + if (dtc_queue_enqueue_reply( + type, buffer, scan_size, tdi_bit_offset, + extra_bits, + cmd +) == NULL) { + LOG_ERROR("enqueuing DTC reply entry: %s\n", strerror(errno)); + exit(1); + } + + tdi_bit_offset += extra_bits; + + if (type == SCAN_IN) { + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_SHIFT_TDO_BYTES(1); + + } else { + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_SHIFT_TDIO_BITS(extra_bits); + + x = 0; + dtc_mask = 1 << (8 - 1); + + while (extra_bits--) { + if (*tdi_p & tdi_mask) { + x |= dtc_mask; + } + + dtc_mask >>= 1; + + tdi_mask <<= 1; + if (tdi_mask == 0) { + tdi_p++; + tdi_mask = 1; + } + } + + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; + } + + dtc_queue.reply_index++; + } + + /* Schedule the last bit into the DTC command buffer */ + { + /* make sure there's room for stop, and bit pair command */ + if ( + (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1)) + || + (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1)) +) { + dtc_queue_run(); + } + + if (type == SCAN_OUT) { + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 0); + + } else { + if (dtc_queue_enqueue_reply( + type, buffer, scan_size, tdi_bit_offset, + 1, + cmd +) == NULL) { + LOG_ERROR("enqueuing DTC reply entry: %s\n", strerror(errno)); + exit(1); + } + + dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = + DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 1); + + dtc_queue.reply_index++; + } + } + + /* Move to pause state */ + tap_state_queue_append(0); + tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); + if (tap_get_state() != tap_get_end_state()) rlink_state_move(); + + return(0); +} + + +static +int rlink_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, tmp_retval; + + /* return ERROR_OK, unless something goes wrong */ + retval = ERROR_OK; + +#ifndef AUTOMATIC_BUSY_LED + /* turn LED on */ + ep1_generic_commandl(pHDev, 2, + EP1_CMD_SET_PORTD_LEDS, + ~(ST7_PD_NBUSY_LED) +); +#endif + + while (cmd) + { + switch (cmd->type) + { + case JTAG_RUNTEST: + case JTAG_STATEMOVE: + case JTAG_PATHMOVE: + case JTAG_SCAN: + break; + + default: + /* some events, such as resets, need a queue flush to ensure consistency */ + tap_state_queue_run(); + dtc_queue_run(); + break; + } + + 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); + } + rlink_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 + if (cmd->cmd.runtest->end_state != -1) + rlink_end_state(cmd->cmd.runtest->end_state); + rlink_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 + if (cmd->cmd.statemove->end_state != -1) + rlink_end_state(cmd->cmd.statemove->end_state); + rlink_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 + rlink_path_move(cmd->cmd.pathmove); + break; + case JTAG_SCAN: +#ifdef _DEBUG_JTAG_IO_ + LOG_DEBUG("%s scan end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", cmd->cmd.scan->end_state); +#endif + if (cmd->cmd.scan->end_state != -1) + rlink_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) { + retval = ERROR_FAIL; + } + 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; + } + + /* Flush the DTC queue to make sure any pending reads have been done before exiting this function */ + tap_state_queue_run(); + tmp_retval = dtc_queue_run(); + if (tmp_retval != ERROR_OK) { + retval = tmp_retval; + } + +#ifndef AUTOMATIC_BUSY_LED + /* turn LED onff */ + ep1_generic_commandl(pHDev, 2, + EP1_CMD_SET_PORTD_LEDS, + ~0 +); +#endif + + return retval; +} + + +/* Using an unindexed table because it is infrequently accessed and it is short. The table must be in order of ascending speed (and descending prescaler), as it is scanned in reverse. */ + +static +int rlink_speed(int speed) +{ + int i; + + if (speed == 0) { + /* fastest speed */ + speed = rlink_speed_table[rlink_speed_table_size - 1].prescaler; + } + + for (i = rlink_speed_table_size; i--;) { + if (rlink_speed_table[i].prescaler == speed) { + if (dtc_load_from_buffer(pHDev, rlink_speed_table[i].dtc, rlink_speed_table[i].dtc_size) != 0) { + LOG_ERROR("An error occurred while trying to load DTC code for speed \"%d\".\n", speed); + exit(1); + } + + if (dtc_start_download() < 0) { + LOG_ERROR("%s, %d: starting DTC: %s", + __FILE__, __LINE__, + usb_strerror() +); + exit(1); + } + + return ERROR_OK; + } + } + + LOG_ERROR("%d is not a supported speed", speed); + return(ERROR_FAIL); +} + + +static +int rlink_speed_div( + int speed, + int *khz +) { + int i; + + for (i = rlink_speed_table_size; i--;) { + if (rlink_speed_table[i].prescaler == speed) { + *khz = rlink_speed_table[i].khz; + return(ERROR_OK); + } + } + + LOG_ERROR("%d is not a supported speed", speed); + return(ERROR_FAIL); +} + + +static +int rlink_khz( + int khz, + int *speed +) { + int i; + + if (khz == 0) { + LOG_ERROR("RCLK not supported"); + return ERROR_FAIL; + } + + for (i = rlink_speed_table_size; i--;) { + if (rlink_speed_table[i].khz <= khz) { + *speed = rlink_speed_table[i].prescaler; + return(ERROR_OK); + } + } + + LOG_WARNING("The lowest supported JTAG speed is %d KHz", rlink_speed_table[0].khz); + *speed = rlink_speed_table[0].prescaler; + return(ERROR_OK); +} + + +static +int rlink_init(void) +{ + int i, j, retries; + uint8_t reply_buffer[USB_EP1IN_SIZE]; + + usb_init(); + const uint16_t vids[] = { USB_IDVENDOR, 0 }; + const uint16_t pids[] = { USB_IDPRODUCT, 0 }; + if (jtag_usb_open(vids, pids, &pHDev) != ERROR_OK) + return ERROR_FAIL; + + struct usb_device *dev = usb_device(pHDev); + if (dev->descriptor.bNumConfigurations > 1) + { + LOG_ERROR("Whoops! NumConfigurations is not 1, don't know what to do...\n"); + return ERROR_FAIL; + } + if (dev->config->bNumInterfaces > 1) + { + LOG_ERROR("Whoops! NumInterfaces is not 1, don't know what to do...\n"); + return ERROR_FAIL; + } + + LOG_DEBUG("Opened device, pHDev = %p\n", pHDev); + + /* usb_set_configuration required under win32 */ + usb_set_configuration(pHDev, dev->config[0].bConfigurationValue); + + retries = 3; + do + { + i = usb_claim_interface(pHDev,0); + if (i) + { + LOG_ERROR("usb_claim_interface: %s", usb_strerror()); +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + j = usb_detach_kernel_driver_np(pHDev, 0); + if (j) + LOG_ERROR("detach kernel driver: %s", usb_strerror()); +#endif + } + else + { + LOG_DEBUG("interface claimed!\n"); + break; + } + } while (--retries); + + if (i) + { + LOG_ERROR("Initialisation failed."); + return ERROR_FAIL; + } + if (usb_set_altinterface(pHDev,0) != 0) + { + LOG_ERROR("Failed to set interface.\n"); + return ERROR_FAIL; + } + + /* The device starts out in an unknown state on open. As such, + * result reads time out, and it's not even known whether the + * command was accepted. So, for this first command, we issue + * it repeatedly until its response doesn't time out. Also, if + * sending a command is going to time out, we find that out here. + * + * It must be possible to open the device in such a way that + * this special magic isn't needed, but, so far, it escapes us. + */ + for (i = 0; i < 5; i++) { + j = ep1_generic_commandl( + pHDev, 1, + EP1_CMD_GET_FWREV +); + if (j < USB_EP1OUT_SIZE) { + LOG_ERROR("USB write error: %s", usb_strerror()); + return(ERROR_FAIL); + } + j = usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)reply_buffer, sizeof(reply_buffer), + 200 +); + if (j != -ETIMEDOUT) break; + } + + if (j < (int)sizeof(reply_buffer)) { + LOG_ERROR("USB read error: %s", usb_strerror()); + return(ERROR_FAIL); + } + LOG_DEBUG(INTERFACE_NAME" firmware version: %d.%d.%d\n", reply_buffer[0], reply_buffer[1], reply_buffer[2]); + + if ((reply_buffer[0] != 0) || (reply_buffer[1] != 0) || (reply_buffer[2] != 3)) { + LOG_WARNING("The rlink device is not of the version that the developers have played with. It may or may not work.\n"); + } + + /* Probe port E for adapter presence */ + ep1_generic_commandl( + pHDev, 16, + EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 0 */ + ST7_PEDR >> 8, + ST7_PEDR, + 3, + 0x00, /* DR */ + ST7_PE_ADAPTER_SENSE_OUT, /* DDR */ + ST7_PE_ADAPTER_SENSE_OUT, /* OR */ + EP1_CMD_MEMORY_READ, /* Read back */ + ST7_PEDR >> 8, + ST7_PEDR, + 1, + EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 1 */ + ST7_PEDR >> 8, + ST7_PEDR, + 1, + ST7_PE_ADAPTER_SENSE_OUT +); + + usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)reply_buffer, 1, + USB_TIMEOUT_MS +); + + if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) != 0) { + LOG_WARNING("target detection problem\n"); + } + + ep1_generic_commandl( + pHDev, 11, + EP1_CMD_MEMORY_READ, /* Read back */ + ST7_PEDR >> 8, + ST7_PEDR, + 1, + EP1_CMD_MEMORY_WRITE, /* float port E */ + ST7_PEDR >> 8, + ST7_PEDR, + 3, + 0x00, /* DR */ + 0x00, /* DDR */ + 0x00 /* OR */ +); + + usb_bulk_read( + pHDev, USB_EP1IN_ADDR, + (char *)reply_buffer, 1, + USB_TIMEOUT_MS +); + + + if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) == 0) { + LOG_WARNING("target not plugged in\n"); + } + + /* float ports A and B */ + ep1_generic_commandl( + pHDev, 11, + EP1_CMD_MEMORY_WRITE, + ST7_PADDR >> 8, + ST7_PADDR, + 2, + 0x00, + 0x00, + EP1_CMD_MEMORY_WRITE, + ST7_PBDDR >> 8, + ST7_PBDDR, + 1, + 0x00 +); + + /* make sure DTC is stopped, set VPP control, set up ports A and B */ + ep1_generic_commandl( + pHDev, 14, + EP1_CMD_DTC_STOP, + EP1_CMD_SET_PORTD_VPP, + ~(ST7_PD_VPP_SHDN), + EP1_CMD_MEMORY_WRITE, + ST7_PADR >> 8, + ST7_PADR, + 2, + ((~(0)) & (ST7_PA_NTRST)), + (ST7_PA_NTRST), + /* port B has no OR, and we want to emulate open drain on NSRST, so we set DR to 0 here and later assert NSRST by setting DDR bit to 1. */ + EP1_CMD_MEMORY_WRITE, + ST7_PBDR >> 8, + ST7_PBDR, + 1, + 0x00 +); + + /* set LED updating mode and make sure they're unlit */ + ep1_generic_commandl( + pHDev, 3, +#ifdef AUTOMATIC_BUSY_LED + EP1_CMD_LEDUE_BUSY, +#else + EP1_CMD_LEDUE_NONE, +#endif + EP1_CMD_SET_PORTD_LEDS, + ~0 +); + + tap_state_queue_init(); + dtc_queue_init(); + rlink_speed(jtag_get_speed()); + rlink_reset(0, 0); + + return ERROR_OK; +} + + +static +int rlink_quit(void) +{ + /* stop DTC and make sure LEDs are off */ + ep1_generic_commandl( + pHDev, 6, + EP1_CMD_DTC_STOP, + EP1_CMD_LEDUE_NONE, + EP1_CMD_SET_PORTD_LEDS, + ~0, + EP1_CMD_SET_PORTD_VPP, + ~0 +); + + usb_release_interface(pHDev,0); + usb_close(pHDev); + + + return ERROR_OK; +} + + +struct jtag_interface rlink_interface = +{ + .name = "rlink", + .init = rlink_init, + .quit = rlink_quit, + .speed = rlink_speed, + .speed_div = rlink_speed_div, + .khz = rlink_khz, + .execute_queue = rlink_execute_queue, +}; diff --git a/src/jtag/drivers/rlink.h b/src/jtag/drivers/rlink.h new file mode 100644 index 00000000..b53be5ce --- /dev/null +++ b/src/jtag/drivers/rlink.h @@ -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; diff --git a/src/jtag/drivers/rlink_call.m4 b/src/jtag/drivers/rlink_call.m4 new file mode 100644 index 00000000..0139c7c2 --- /dev/null +++ b/src/jtag/drivers/rlink_call.m4 @@ -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 = + 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 + = 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 = 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 + + diff --git a/src/jtag/drivers/rlink_dtc_cmd.h b/src/jtag/drivers/rlink_dtc_cmd.h new file mode 100644 index 00000000..98975098 --- /dev/null +++ b/src/jtag/drivers/rlink_dtc_cmd.h @@ -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. */ diff --git a/src/jtag/drivers/rlink_ep1_cmd.h b/src/jtag/drivers/rlink_ep1_cmd.h new file mode 100644 index 00000000..b30e1bb1 --- /dev/null +++ b/src/jtag/drivers/rlink_ep1_cmd.h @@ -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 . + * 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) diff --git a/src/jtag/drivers/rlink_init.m4 b/src/jtag/drivers/rlink_init.m4 new file mode 100644 index 00000000..3e64523c --- /dev/null +++ b/src/jtag/drivers/rlink_init.m4 @@ -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 diff --git a/src/jtag/drivers/rlink_speed_table.c b/src/jtag/drivers/rlink_speed_table.c new file mode 100644 index 00000000..fa40fe8c --- /dev/null +++ b/src/jtag/drivers/rlink_speed_table.c @@ -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); + diff --git a/src/jtag/drivers/rlink_st7.h b/src/jtag/drivers/rlink_st7.h new file mode 100644 index 00000000..5f337ef1 --- /dev/null +++ b/src/jtag/drivers/rlink_st7.h @@ -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) diff --git a/src/jtag/drivers/usb_common.c b/src/jtag/drivers/usb_common.c new file mode 100644 index 00000000..463f1af9 --- /dev/null +++ b/src/jtag/drivers/usb_common.c @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2009 by Zachary T Welch * + * * + * 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; +} diff --git a/src/jtag/drivers/usb_common.h b/src/jtag/drivers/usb_common.h new file mode 100644 index 00000000..da395add --- /dev/null +++ b/src/jtag/drivers/usb_common.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2009 by Zachary T Welch * + * * + * 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 + +int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], + struct usb_dev_handle **out); + +#endif // JTAG_USB_COMMON_H diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c new file mode 100644 index 00000000..204d0e2e --- /dev/null +++ b/src/jtag/drivers/usbprog.c @@ -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 + }; diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c new file mode 100644 index 00000000..cc3308f5 --- /dev/null +++ b/src/jtag/drivers/vsllink.c @@ -0,0 +1,1903 @@ +/*************************************************************************** + * Copyright (C) 2009 by Simon Qian * + * * + * 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. * + ***************************************************************************/ + +/* Versaloon is a programming tool for multiple MCUs. + * OpenOCD and MSP430 supports are distributed under GPLv2. + * You can find it at http://www.SimonQian.com/en/Versaloon. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "interface.h" +#include "commands.h" +#include "usb_common.h" + +//#define _VSLLINK_IN_DEBUG_MODE_ + +#define VSLLINK_MODE_NORMAL 0 +#define VSLLINK_MODE_DMA 1 + +static uint16_t vsllink_usb_vid; +static uint16_t vsllink_usb_pid; +static uint8_t vsllink_usb_bulkout; +static uint8_t vsllink_usb_bulkin; +static uint8_t vsllink_usb_interface; +static uint8_t vsllink_mode = VSLLINK_MODE_NORMAL; +static int VSLLINK_USB_TIMEOUT = 10000; + +static int VSLLINK_BufferSize = 1024; + +/* Global USB buffers */ +static int vsllink_usb_out_buffer_idx; +static int vsllink_usb_in_want_length; +static uint8_t* vsllink_usb_in_buffer = NULL; +static uint8_t* vsllink_usb_out_buffer = NULL; + +/* Constants for VSLLink command */ +#define VSLLINK_CMD_CONN 0x80 +#define VSLLINK_CMD_DISCONN 0x81 +#define VSLLINK_CMD_SET_SPEED 0x82 +#define VSLLINK_CMD_SET_PORT 0x90 +#define VSLLINK_CMD_GET_PORT 0x91 +#define VSLLINK_CMD_SET_PORTDIR 0x92 +#define VSLLINK_CMD_HW_JTAGSEQCMD 0xA0 +#define VSLLINK_CMD_HW_JTAGHLCMD 0xA1 +#define VSLLINK_CMD_HW_SWDCMD 0xA2 +#define VSLLINK_CMD_HW_JTAGRAWCMD 0xA3 + +#define VSLLINK_CMDJTAGSEQ_TMSBYTE 0x00 +#define VSLLINK_CMDJTAGSEQ_TMSCLOCK 0x40 +#define VSLLINK_CMDJTAGSEQ_SCAN 0x80 + +#define VSLLINK_CMDJTAGSEQ_CMDMSK 0xC0 +#define VSLLINK_CMDJTAGSEQ_LENMSK 0x3F + +#define JTAG_PINMSK_SRST (1 << 0) +#define JTAG_PINMSK_TRST (1 << 1) +#define JTAG_PINMSK_USR1 (1 << 2) +#define JTAG_PINMSK_USR2 (1 << 3) +#define JTAG_PINMSK_TCK (1 << 4) +#define JTAG_PINMSK_TMS (1 << 5) +#define JTAG_PINMSK_TDI (1 << 6) +#define JTAG_PINMSK_TDO (1 << 7) + + +#define VSLLINK_TAP_MOVE(from, to) VSLLINK_tap_move[tap_move_ndx(from)][tap_move_ndx(to)] + +/* VSLLINK_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 + * + * SD->SD and SI->SI have to be caught in interface specific code + */ +static uint8_t VSLLINK_tap_move[6][6] = +{ +/* TLR RTI SD PD SI PI */ + {0xff, 0x7f, 0x2f, 0x0a, 0x37, 0x16}, /* TLR */ + {0xff, 0x00, 0x45, 0x05, 0x4b, 0x0b}, /* RTI */ + {0xff, 0x61, 0x00, 0x01, 0x0f, 0x2f}, /* SD */ + {0xfe, 0x60, 0x40, 0x5c, 0x3c, 0x5e}, /* PD */ + {0xff, 0x61, 0x07, 0x17, 0x00, 0x01}, /* SI */ + {0xfe, 0x60, 0x38, 0x5c, 0x40, 0x5e} /* PI */ +}; + +struct insert_insignificant_operation { + unsigned char insert_value; + unsigned char insert_position; +}; + +static struct insert_insignificant_operation VSLLINK_TAP_MOVE_INSERT_INSIGNIFICANT[6][6] = +{ +/* stuff offset */ + {/* TLR */ + {1, 0,}, /* TLR */ + {1, 0,}, /* RTI */ + {1, 0,}, /* SD */ + {1, 0,}, /* PD */ + {1, 0,}, /* SI */ + {1, 0,}}, /* PI */ + {/* RTI */ + {1, 0,}, /* TLR */ + {0, 0,}, /* RTI */ + {0, 4,}, /* SD */ + {0, 7,}, /* PD */ + {0, 5,}, /* SI */ + {0, 7,}}, /* PI */ + {/* SD */ + {0, 0,}, /* TLR */ + {0, 0,}, /* RTI */ + {0, 0,}, /* SD */ + {0, 0,}, /* PD */ + {0, 0,}, /* SI */ + {0, 0,}}, /* PI */ + {/* PD */ + {0, 0,}, /* TLR */ + {0, 0,}, /* RTI */ + {0, 0,}, /* SD */ + {0, 0,}, /* PD */ + {0, 0,}, /* SI */ + {0, 0,}}, /* PI */ + {/* SI */ + {0, 0,}, /* TLR */ + {0, 0,}, /* RTI */ + {0, 0,}, /* SD */ + {0, 0,}, /* PD */ + {0, 0,}, /* SI */ + {0, 0,}}, /* PI */ + {/* PI */ + {0, 0,}, /* TLR */ + {0, 0,}, /* RTI */ + {0, 0,}, /* SD */ + {0, 0,}, /* PD */ + {0, 0,}, /* SI */ + {0, 0,}}, /* PI */ +}; + +static uint8_t VSLLINK_BIT_MSK[8] = +{ + 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f +}; + +struct pending_scan_result { + int offset; + 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]; + +/* Queue command functions */ +static void vsllink_end_state(tap_state_t state); +static void vsllink_state_move_dma(void); +static void vsllink_state_move_normal(void); +static void (*vsllink_state_move)(void); +static void vsllink_path_move_dma(int num_states, tap_state_t *path); +static void vsllink_path_move_normal(int num_states, tap_state_t *path); +static void (*vsllink_path_move)(int num_states, tap_state_t *path); +static void vsllink_runtest(int num_cycles); +static void vsllink_stableclocks_dma(int num_cycles, int tms); +static void vsllink_stableclocks_normal(int num_cycles, int tms); +static void (*vsllink_stableclocks)(int num_cycles, int tms); +static void vsllink_scan_dma(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); +static void vsllink_scan_normal(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); +static void (*vsllink_scan)(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); +static void vsllink_reset(int trst, int srst); +static void vsllink_simple_command(uint8_t command); +static int vsllink_connect(void); +static int vsllink_disconnect(void); + +/* VSLLink tap buffer functions */ +static void vsllink_tap_append_step(int tms, int tdi); +static void vsllink_tap_init_dma(void); +static void vsllink_tap_init_normal(void); +static void (*vsllink_tap_init)(void); +static int vsllink_tap_execute_dma(void); +static int vsllink_tap_execute_normal(void); +static int (*vsllink_tap_execute)(void); +static void vsllink_tap_ensure_space_dma(int scans, int length); +static void vsllink_tap_ensure_space_normal(int scans, int length); +static void (*vsllink_tap_ensure_space)(int scans, int length); +static void vsllink_tap_append_scan_dma(int length, uint8_t *buffer, struct scan_command *command); +static void vsllink_tap_append_scan_normal(int length, uint8_t *buffer, struct scan_command *command, int offset); + +/* VSLLink lowlevel functions */ +struct vsllink { + struct usb_dev_handle* usb_handle; +}; + +static struct vsllink *vsllink_usb_open(void); +static void vsllink_usb_close(struct vsllink *vsllink); +static int vsllink_usb_message(struct vsllink *vsllink, int out_length, int in_length); +static int vsllink_usb_write(struct vsllink *vsllink, int out_length); +static int vsllink_usb_read(struct vsllink *vsllink); + +#if defined _DEBUG_USB_COMMS_ || defined _DEBUG_JTAG_IO_ +static void vsllink_debug_buffer(uint8_t *buffer, int length); +#endif + +static int vsllink_tms_data_len = 0; +static uint8_t* vsllink_tms_cmd_pos; + +static int tap_length = 0; +static int tap_buffer_size = 0; +static uint8_t *tms_buffer = NULL; +static uint8_t *tdi_buffer = NULL; +static uint8_t *tdo_buffer = NULL; +static int last_tms; + +static struct vsllink* vsllink_handle = NULL; + +static void reset_command_pointer(void) +{ + if (vsllink_mode == VSLLINK_MODE_NORMAL) + { + vsllink_usb_out_buffer[0] = VSLLINK_CMD_HW_JTAGSEQCMD; + vsllink_usb_out_buffer_idx = 3; + } + else + { + tap_length = 0; + } +} + +static int vsllink_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; + int scan_size; + enum scan_type type; + uint8_t *buffer; + + DEBUG_JTAG_IO("--------------------------------- vsllink -------------------------------------"); + + reset_command_pointer(); + while (cmd != NULL) + { + switch (cmd->type) + { + case JTAG_RUNTEST: + DEBUG_JTAG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, \ + tap_state_name(cmd->cmd.runtest->end_state)); + + vsllink_end_state(cmd->cmd.runtest->end_state); + vsllink_runtest(cmd->cmd.runtest->num_cycles); + break; + + case JTAG_STATEMOVE: + DEBUG_JTAG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); + + vsllink_end_state(cmd->cmd.statemove->end_state); + vsllink_state_move(); + break; + + case JTAG_PATHMOVE: + DEBUG_JTAG_IO("pathmove: %i states, end in %s", \ + cmd->cmd.pathmove->num_states, \ + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + + vsllink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); + break; + + case JTAG_SCAN: + vsllink_end_state(cmd->cmd.scan->end_state); + + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + if (cmd->cmd.scan->ir_scan) + { + DEBUG_JTAG_IO("JTAG Scan write IR(%d bits), end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); + } + else + { + DEBUG_JTAG_IO("JTAG Scan write DR(%d bits), end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); + } + +#ifdef _DEBUG_JTAG_IO_ + vsllink_debug_buffer(buffer, (scan_size + 7) >> 3); +#endif + + type = jtag_scan_type(cmd->cmd.scan); + + vsllink_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); + + vsllink_tap_execute(); + + if (cmd->cmd.reset->trst == 1) + { + tap_set_state(TAP_RESET); + } + vsllink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + + case JTAG_SLEEP: + DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); + vsllink_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); + break; + + case JTAG_STABLECLOCKS: + DEBUG_JTAG_IO("add %d clocks", cmd->cmd.stableclocks->num_cycles); + switch (tap_get_state()) + { + case TAP_RESET: + // tms should be '1' to stay in TAP_RESET mode + scan_size = 1; + break; + case TAP_DRSHIFT: + case TAP_IDLE: + case TAP_DRPAUSE: + case TAP_IRSHIFT: + case TAP_IRPAUSE: + // in other mode, tms should be '0' + scan_size = 0; + break; /* above stable states are OK */ + default: + LOG_ERROR("jtag_add_clocks() was called with TAP in non-stable state \"%s\"", + tap_state_name(tap_get_state())); + exit(-1); + } + vsllink_stableclocks(cmd->cmd.stableclocks->num_cycles, scan_size); + break; + + default: + LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); + exit(-1); + } + cmd = cmd->next; + } + + return vsllink_tap_execute(); +} + +static int vsllink_speed(int speed) +{ + int result; + + vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_SPEED; + vsllink_usb_out_buffer[1] = (speed >> 0) & 0xff; + vsllink_usb_out_buffer[2] = (speed >> 8) & 0xFF; + + result = vsllink_usb_write(vsllink_handle, 3); + + if (result == 3) + { + return ERROR_OK; + } + else + { + LOG_ERROR("VSLLink setting speed failed (%d)", result); + return ERROR_JTAG_DEVICE_ERROR; + } + + return ERROR_OK; +} + +static int vsllink_khz(int khz, int *jtag_speed) +{ + *jtag_speed = khz; + + return ERROR_OK; +} + +static int vsllink_speed_div(int jtag_speed, int *khz) +{ + *khz = jtag_speed; + + return ERROR_OK; +} + +static int vsllink_init(void) +{ + int check_cnt, to_tmp; + int result; + char version_str[100]; + + vsllink_usb_in_buffer = malloc(VSLLINK_BufferSize); + vsllink_usb_out_buffer = malloc(VSLLINK_BufferSize); + if ((vsllink_usb_in_buffer == NULL) || (vsllink_usb_out_buffer == NULL)) + { + LOG_ERROR("Not enough memory"); + exit(-1); + } + + vsllink_handle = vsllink_usb_open(); + + if (vsllink_handle == 0) + { + LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); + return ERROR_JTAG_INIT_FAILED; + } + LOG_DEBUG("vsllink found on %04X:%04X", vsllink_usb_vid, vsllink_usb_pid); + + to_tmp = VSLLINK_USB_TIMEOUT; + VSLLINK_USB_TIMEOUT = 100; + check_cnt = 0; + while (check_cnt < 5) + { + vsllink_simple_command(0x00); + result = vsllink_usb_read(vsllink_handle); + + if (result > 2) + { + vsllink_usb_in_buffer[result] = 0; + VSLLINK_BufferSize = vsllink_usb_in_buffer[0] + (vsllink_usb_in_buffer[1] << 8); + strncpy(version_str, (char *)vsllink_usb_in_buffer + 2, sizeof(version_str)); + LOG_INFO("%s", version_str); + + // free the pre-alloc memroy + free(vsllink_usb_in_buffer); + free(vsllink_usb_out_buffer); + vsllink_usb_in_buffer = NULL; + vsllink_usb_out_buffer = NULL; + + // alloc new memory + vsllink_usb_in_buffer = malloc(VSLLINK_BufferSize); + vsllink_usb_out_buffer = malloc(VSLLINK_BufferSize); + if ((vsllink_usb_in_buffer == NULL) || (vsllink_usb_out_buffer == NULL)) + { + LOG_ERROR("Not enough memory"); + exit(-1); + } + else + { + LOG_INFO("buffer size for USB is %d bytes", VSLLINK_BufferSize); + } + // alloc memory for dma mode + if (vsllink_mode == VSLLINK_MODE_DMA) + { + tap_buffer_size = (VSLLINK_BufferSize - 3) / 2; + tms_buffer = (uint8_t*)malloc(tap_buffer_size); + tdi_buffer = (uint8_t*)malloc(tap_buffer_size); + tdo_buffer = (uint8_t*)malloc(tap_buffer_size); + if ((tms_buffer == NULL) || (tdi_buffer == NULL) || (tdo_buffer == NULL)) + { + LOG_ERROR("Not enough memory"); + exit(-1); + } + } + break; + } + vsllink_simple_command(VSLLINK_CMD_DISCONN); + check_cnt++; + } + if (check_cnt == 3) + { + // It's dangerout to proced + LOG_ERROR("VSLLink initial failed"); + exit(-1); + } + VSLLINK_USB_TIMEOUT = to_tmp; + + // connect to vsllink + vsllink_connect(); + // initialize function pointers + if (vsllink_mode == VSLLINK_MODE_NORMAL) + { + // normal mode + vsllink_state_move = vsllink_state_move_normal; + vsllink_path_move = vsllink_path_move_normal; + vsllink_stableclocks = vsllink_stableclocks_normal; + vsllink_scan = vsllink_scan_normal; + + vsllink_tap_init = vsllink_tap_init_normal; + vsllink_tap_execute = vsllink_tap_execute_normal; + vsllink_tap_ensure_space = vsllink_tap_ensure_space_normal; + + LOG_INFO("vsllink run in NORMAL mode"); + } + else + { + // dma mode + vsllink_state_move = vsllink_state_move_dma; + vsllink_path_move = vsllink_path_move_dma; + vsllink_stableclocks = vsllink_stableclocks_dma; + vsllink_scan = vsllink_scan_dma; + + vsllink_tap_init = vsllink_tap_init_dma; + vsllink_tap_execute = vsllink_tap_execute_dma; + vsllink_tap_ensure_space = vsllink_tap_ensure_space_dma; + + LOG_INFO("vsllink run in DMA mode"); + } + + // Set SRST and TRST to output, Set USR1 and USR2 to input + vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_PORTDIR; + vsllink_usb_out_buffer[1] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST | JTAG_PINMSK_USR1 | JTAG_PINMSK_USR2; + vsllink_usb_out_buffer[2] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST; + if (vsllink_usb_write(vsllink_handle, 3) != 3) + { + LOG_ERROR("VSLLink USB send data error"); + exit(-1); + } + + vsllink_reset(0, 0); + + LOG_INFO("VSLLink JTAG Interface ready"); + + vsllink_tap_init(); + + return ERROR_OK; +} + +static int vsllink_quit(void) +{ + if ((vsllink_usb_in_buffer != NULL) && (vsllink_usb_out_buffer != NULL)) + { + // Set all pins to input + vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_PORTDIR; + vsllink_usb_out_buffer[1] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST | JTAG_PINMSK_USR1 | JTAG_PINMSK_USR2; + vsllink_usb_out_buffer[2] = 0; + if (vsllink_usb_write(vsllink_handle, 3) != 3) + { + LOG_ERROR("VSLLink USB send data error"); + exit(-1); + } + + // disconnect + vsllink_disconnect(); + vsllink_usb_close(vsllink_handle); + vsllink_handle = NULL; + } + + if (vsllink_usb_in_buffer != NULL) + { + free(vsllink_usb_in_buffer); + vsllink_usb_in_buffer = NULL; + } + if (vsllink_usb_out_buffer != NULL) + { + free(vsllink_usb_out_buffer); + vsllink_usb_out_buffer = NULL; + } + + return ERROR_OK; +} + +/***************************************************************************/ +/* Queue command implementations */ +static int vsllink_disconnect(void) +{ + vsllink_simple_command(VSLLINK_CMD_DISCONN); + return ERROR_OK; +} + +static int vsllink_connect(void) +{ + char vsllink_str[100]; + + vsllink_usb_out_buffer[0] = VSLLINK_CMD_CONN; + vsllink_usb_out_buffer[1] = vsllink_mode; + vsllink_usb_message(vsllink_handle, 2, 0); + if (vsllink_usb_read(vsllink_handle) > 2) + { + strncpy(vsllink_str, (char *)vsllink_usb_in_buffer + 2, sizeof(vsllink_str)); + LOG_INFO("%s", vsllink_str); + } + + return ERROR_OK; +} + +// when vsllink_tms_data_len > 0, vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] is the byte that need to be appended. +// length of VSLLINK_CMDJTAGSEQ_TMSBYTE has been set, no need to set it here. +static void vsllink_append_tms(void) +{ + uint8_t tms_scan = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); + uint16_t tms2; + struct insert_insignificant_operation *insert = \ + &VSLLINK_TAP_MOVE_INSERT_INSIGNIFICANT[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())]; + + if (((tap_get_state() != TAP_RESET) && (tap_get_state() != TAP_IDLE) && (tap_get_state() != TAP_DRPAUSE) && (tap_get_state() != TAP_IRPAUSE)) || \ + (vsllink_tms_data_len <= 0) || (vsllink_tms_data_len >= 8) || \ + (vsllink_tms_cmd_pos == NULL)) + { + LOG_ERROR("There MUST be some bugs in the driver"); + exit(-1); + } + + tms2 = (tms_scan & VSLLINK_BIT_MSK[insert->insert_position]) << \ + vsllink_tms_data_len; + if (insert->insert_value == 1) + { + tms2 |= VSLLINK_BIT_MSK[8 - vsllink_tms_data_len] << \ + (vsllink_tms_data_len + insert->insert_position); + } + tms2 |= (tms_scan >> insert->insert_position) << \ + (8 + insert->insert_position); + + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (tms2 >> 0) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms2 >> 8) & 0xff; + + vsllink_tms_data_len = 0; + vsllink_tms_cmd_pos = NULL; +} + +static void vsllink_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 vsllink_state_move_normal(void) +{ + if (vsllink_tms_data_len > 0) + { + vsllink_append_tms(); + } + else + { + vsllink_tap_ensure_space(0, 2); + + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); + } + + tap_set_state(tap_get_end_state()); +} +static void vsllink_state_move_dma(void) +{ + int i, insert_length = (tap_length % 8) ? (8 - (tap_length % 8)) : 0; + struct insert_insignificant_operation *insert = \ + &VSLLINK_TAP_MOVE_INSERT_INSIGNIFICANT[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())]; + uint8_t tms_scan = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); + + if (tap_get_state() == TAP_RESET) + { + vsllink_tap_ensure_space(0, 8); + + for (i = 0; i < 8; i++) + { + vsllink_tap_append_step(1, 0); + } + } + + if (insert_length > 0) + { + vsllink_tap_ensure_space(0, 16); + + for (i = 0; i < insert->insert_position; i++) + { + vsllink_tap_append_step((tms_scan >> i) & 1, 0); + } + for (i = 0; i < insert_length; i++) + { + vsllink_tap_append_step(insert->insert_value, 0); + } + for (i = insert->insert_position; i < 8; i++) + { + vsllink_tap_append_step((tms_scan >> i) & 1, 0); + } + } + else + { + vsllink_tap_ensure_space(0, 8); + + for (i = 0; i < 8; i++) + { + vsllink_tap_append_step((tms_scan >> i) & 1, 0); + } + } + + tap_set_state(tap_get_end_state()); +} + +// write tms from current vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] +static void vsllink_add_path(int start, int num, tap_state_t *path) +{ + int i; + + for (i = start; i < (start + num); i++) + { + if ((i & 7) == 0) + { + if (i > 0) + { + vsllink_usb_out_buffer_idx++; + } + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = 0; + } + + if (path[i - start] == tap_state_transition(tap_get_state(), true)) + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] |= 1 << (i & 7); + } + else if (path[i - start] == tap_state_transition(tap_get_state(), false)) + { + // nothing to do + } + 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 - start]); + } + if ((i > 0) && ((i & 7) == 0)) + { + vsllink_usb_out_buffer_idx++; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = 0; + } + + tap_set_end_state(tap_get_state()); +} + +static void vsllink_path_move_normal(int num_states, tap_state_t *path) +{ + int i, tms_len, tms_cmd_pos, path_idx = 0; + + if (vsllink_tms_data_len > 0) + { + // there are vsllink_tms_data_len more tms bits to be shifted + // so there are vsllink_tms_data_len + num_states tms bits in all + tms_len = vsllink_tms_data_len + num_states; + if (tms_len <= 16) + { + // merge into last tms shift + if (tms_len < 8) + { + // just append tms data to the last tms byte + vsllink_add_path(vsllink_tms_data_len, num_states, path); + } + else if (tms_len == 8) + { + // end last tms shift command + (*vsllink_tms_cmd_pos)--; + vsllink_add_path(vsllink_tms_data_len, num_states, path); + } + else if (tms_len < 16) + { + if ((*vsllink_tms_cmd_pos & VSLLINK_CMDJTAGSEQ_LENMSK) < VSLLINK_CMDJTAGSEQ_LENMSK) + { + // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most + // there is enought tms length in the current tms shift command + (*vsllink_tms_cmd_pos)++; + vsllink_add_path(vsllink_tms_data_len, num_states, path); + } + else + { + // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most + // not enough tms length in the current tms shift command + // so a new command should be added + // first decrease byte length of last tms shift command + (*vsllink_tms_cmd_pos)--; + // append tms data to the last tms byte + vsllink_add_path(vsllink_tms_data_len, 8 - vsllink_tms_data_len, path); + path += 8 - vsllink_tms_data_len; + // add new command(3 bytes) + vsllink_tap_ensure_space(0, 3); + vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; + vsllink_add_path(0, num_states - (8 - vsllink_tms_data_len), path); + } + } + else if (tms_len == 16) + { + // end last tms shift command + vsllink_add_path(vsllink_tms_data_len, num_states, path); + } + + vsllink_tms_data_len = (vsllink_tms_data_len + num_states) & 7; + if (vsllink_tms_data_len == 0) + { + vsllink_tms_cmd_pos = NULL; + } + num_states = 0; + } + else + { + vsllink_add_path(vsllink_tms_data_len, 16 - vsllink_tms_data_len, path); + + path += 16 - vsllink_tms_data_len; + num_states -= 16 - vsllink_tms_data_len; + vsllink_tms_data_len = 0; + vsllink_tms_cmd_pos = NULL; + } + } + + if (num_states > 0) + { + // Normal operation, don't need to append tms data + vsllink_tms_data_len = num_states & 7; + + while (num_states > 0) + { + if (num_states > ((VSLLINK_CMDJTAGSEQ_LENMSK + 1) * 8)) + { + i = (VSLLINK_CMDJTAGSEQ_LENMSK + 1) * 8; + } + else + { + i = num_states; + } + tms_len = (i + 7) >> 3; + vsllink_tap_ensure_space(0, tms_len + 2); + tms_cmd_pos = vsllink_usb_out_buffer_idx; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | (tms_len - 1); + + vsllink_add_path(0, i, path + path_idx); + + path_idx += i; + num_states -= i; + } + + if (vsllink_tms_data_len > 0) + { + if (tms_len < (VSLLINK_CMDJTAGSEQ_LENMSK + 1)) + { + vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[tms_cmd_pos]; + (*vsllink_tms_cmd_pos)++; + } + else + { + vsllink_usb_out_buffer[tms_cmd_pos]--; + + tms_len = vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; + vsllink_tap_ensure_space(0, 3); + vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = tms_len; + } + } + } +} +static void vsllink_path_move_dma(int num_states, tap_state_t *path) +{ + int i, j = 0; + + if (tap_length & 7) + { + if ((8 - (tap_length & 7)) < num_states) + { + j = 8 - (tap_length & 7); + } + else + { + j = num_states; + } + for (i = 0; i < j; i++) + { + if (path[i] == tap_state_transition(tap_get_state(), false)) + { + vsllink_tap_append_step(0, 0); + } + else if (path[i] == tap_state_transition(tap_get_state(), true)) + { + vsllink_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]); + } + num_states -= j; + } + + if (num_states > 0) + { + vsllink_tap_ensure_space(0, num_states); + + for (i = 0; i < num_states; i++) + { + if (path[j + i] == tap_state_transition(tap_get_state(), false)) + { + vsllink_tap_append_step(0, 0); + } + else if (path[j + i] == tap_state_transition(tap_get_state(), true)) + { + vsllink_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[j + i]); + } + } + + tap_set_end_state(tap_get_state()); +} + +static void vsllink_stableclocks_normal(int num_cycles, int tms) +{ + int tms_len; + uint16_t tms_append_byte; + + if (vsllink_tms_data_len > 0) + { + // there are vsllink_tms_data_len more tms bits to be shifted + // so there are vsllink_tms_data_len + num_cycles tms bits in all + tms_len = vsllink_tms_data_len + num_cycles; + if (tms > 0) + { + // append '1' for tms + tms_append_byte = (uint16_t)((((1 << num_cycles) - 1) << vsllink_tms_data_len) & 0xFFFF); + } + else + { + // append '0' for tms + tms_append_byte = 0; + } + if (tms_len <= 16) + { + // merge into last tms shift + if (tms_len < 8) + { + // just add to vsllink_tms_data_len + // same result if tun through + //vsllink_tms_data_len += num_cycles; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] |= (uint8_t)(tms_append_byte & 0xFF); + } + else if (tms_len == 8) + { + // end last tms shift command + // just reduce it, and append last tms byte + (*vsllink_tms_cmd_pos)--; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); + } + else if (tms_len < 16) + { + if ((*vsllink_tms_cmd_pos & VSLLINK_CMDJTAGSEQ_LENMSK) < VSLLINK_CMDJTAGSEQ_LENMSK) + { + // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most + // there is enought tms length in the current tms shift command + // increase the tms byte length by 1 and set the last byte to 0 + (*vsllink_tms_cmd_pos)++; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = (uint8_t)(tms_append_byte >> 8); + } + else + { + // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most + // not enough tms length in the current tms shift command + // so a new command should be added + // first decrease byte length of last tms shift command + (*vsllink_tms_cmd_pos)--; + // append last tms byte and move the command pointer to the next empty position + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); + // add new command(3 bytes) + vsllink_tap_ensure_space(0, 3); + vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = (uint8_t)(tms_append_byte >> 8); + } + } + else if (tms_len == 16) + { + // end last tms shift command + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (uint8_t)(tms_append_byte >> 8); + } + + vsllink_tms_data_len = tms_len & 7; + if (vsllink_tms_data_len == 0) + { + vsllink_tms_cmd_pos = NULL; + } + num_cycles = 0; + } + else + { + // more shifts will be needed + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (uint8_t)(tms_append_byte >> 8); + + num_cycles -= 16 - vsllink_tms_data_len; + vsllink_tms_data_len = 0; + vsllink_tms_cmd_pos = NULL; + } + } + // from here vsllink_tms_data_len == 0 or num_cycles == 0 + + if (vsllink_tms_data_len > 0) + { + // num_cycles == 0 + // no need to shift + if (num_cycles > 0) + { + LOG_ERROR("There MUST be some bugs in the driver"); + exit(-1); + } + } + else + { + // get number of bytes left to be sent + tms_len = num_cycles >> 3; + if (tms_len > 0) + { + vsllink_tap_ensure_space(1, 5); + // if tms_len > 0, vsllink_tms_data_len == 0 + // so just add new command + // LSB of the command byte is the tms value when do the shifting + if (tms > 0) + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSCLOCK | 1; + } + else + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSCLOCK; + } + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 0) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 8) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 16) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 24) & 0xff; + + vsllink_usb_in_want_length += 1; + pending_scan_results_buffer[pending_scan_results_length].buffer = NULL; + pending_scan_results_length++; + + if (tms_len > 0xFFFF) + { + vsllink_tap_execute(); + } + } + + // post-process + vsllink_tms_data_len = num_cycles & 7; + if (vsllink_tms_data_len > 0) + { + vsllink_tap_ensure_space(0, 3); + vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; + if (tms > 0) + { + // append '1' for tms + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = (1 << vsllink_tms_data_len) - 1; + } + else + { + // append '0' for tms + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = 0x00; + } + } + } +} +static void vsllink_stableclocks_dma(int num_cycles, int tms) +{ + int i, cur_cycles; + + if (tap_length & 7) + { + if ((8 - (tap_length & 7)) < num_cycles) + { + cur_cycles = 8 - (tap_length & 7); + } + else + { + cur_cycles = num_cycles; + } + for (i = 0; i < cur_cycles; i++) + { + vsllink_tap_append_step(tms, 0); + } + num_cycles -= cur_cycles; + } + + while (num_cycles > 0) + { + if (num_cycles > 8 * tap_buffer_size) + { + cur_cycles = 8 * tap_buffer_size; + } + else + { + cur_cycles = num_cycles; + } + + vsllink_tap_ensure_space(0, cur_cycles); + + for (i = 0; i < cur_cycles; i++) + { + vsllink_tap_append_step(tms, 0); + } + + num_cycles -= cur_cycles; + } +} + +static void vsllink_runtest(int num_cycles) +{ + tap_state_t saved_end_state = tap_get_end_state(); + + if (tap_get_state() != TAP_IDLE) + { + // enter into IDLE state + vsllink_end_state(TAP_IDLE); + vsllink_state_move(); + } + + vsllink_stableclocks(num_cycles, 0); + + // post-process + // set end_state + vsllink_end_state(saved_end_state); + tap_set_state(TAP_IDLE); + if (tap_get_end_state() != TAP_IDLE) + { + vsllink_state_move(); + } +} + +static void vsllink_scan_normal(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) +{ + tap_state_t saved_end_state; + uint8_t bits_left, tms_tmp, tdi_len; + int i; + + if (0 == scan_size) + { + return; + } + + tdi_len = ((scan_size + 7) >> 3); + if ((tdi_len + 7) > VSLLINK_BufferSize) + { + LOG_ERROR("Your implementation of VSLLink has not enough buffer"); + exit(-1); + } + + saved_end_state = tap_get_end_state(); + + /* Move to appropriate scan state */ + vsllink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); + + if (vsllink_tms_data_len > 0) + { + if (tap_get_state() == tap_get_end_state()) + { + // already in IRSHIFT or DRSHIFT state + // merge tms data in the last tms shift command into next scan command + if (*vsllink_tms_cmd_pos < 1) + { + LOG_ERROR("There MUST be some bugs in the driver"); + exit(-1); + } + else if (*vsllink_tms_cmd_pos < 2) + { + tms_tmp = vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; + vsllink_usb_out_buffer_idx--; + } + else + { + tms_tmp = vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; + *vsllink_tms_cmd_pos -= 2; + } + + vsllink_tap_ensure_space(1, tdi_len + 7); + // VSLLINK_CMDJTAGSEQ_SCAN ored by 1 means that tms_before is valid + // which is merged from the last tms shift command + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_SCAN | 1; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1) >> 0) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1) >> 8) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = tms_tmp; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = buffer[0] << (8 - vsllink_tms_data_len); + + for (i = 0; i < tdi_len; i++) + { + buffer[i] >>= 8 - vsllink_tms_data_len; + if (i != tdi_len) + { + buffer[i] += buffer[i + 1] << vsllink_tms_data_len; + } + } + + vsllink_tap_append_scan_normal(scan_size - vsllink_tms_data_len, buffer, command, vsllink_tms_data_len); + scan_size -= 8 - vsllink_tms_data_len; + vsllink_tms_data_len = 0; + } + else + { + vsllink_state_move(); + vsllink_tap_ensure_space(1, tdi_len + 5); + + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_SCAN; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tdi_len >> 0) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tdi_len >> 8) & 0xff; + + vsllink_tap_append_scan_normal(scan_size, buffer, command, 0); + } + } + else + { + vsllink_tap_ensure_space(1, tdi_len + 7); + + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_SCAN | 1; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1) >> 0) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1)>> 8) & 0xff; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0; + + vsllink_tap_append_scan_normal(scan_size, buffer, command, 8); + } + vsllink_end_state(saved_end_state); + + bits_left = scan_size & 0x07; + tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); + + if (bits_left > 0) + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 1 << (bits_left - 1); + } + else + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 1 << 7; + } + + if (tap_get_state() != tap_get_end_state()) + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); + } + else + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0; + } + + tap_set_state(tap_get_end_state()); +} +static void vsllink_scan_dma(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) +{ + tap_state_t saved_end_state; + + saved_end_state = tap_get_end_state(); + + /* Move to appropriate scan state */ + vsllink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); + + vsllink_state_move(); + vsllink_end_state(saved_end_state); + + /* Scan */ + vsllink_tap_append_scan_dma(scan_size, buffer, command); + + tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); + while (tap_length % 8 != 0) + { + // more 0s in Pause + vsllink_tap_append_step(0, 0); + } + + if (tap_get_state() != tap_get_end_state()) + { + vsllink_state_move(); + } +} + +static void vsllink_reset(int trst, int srst) +{ + int result; + + LOG_DEBUG("trst: %i, srst: %i", trst, srst); + + /* Signals are active low */ + vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_PORT; + vsllink_usb_out_buffer[1] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST; + vsllink_usb_out_buffer[2] = 0; + if (srst == 0) + { + vsllink_usb_out_buffer[2] |= JTAG_PINMSK_SRST; + } + if (trst == 0) + { + vsllink_usb_out_buffer[2] |= JTAG_PINMSK_TRST; + } + + result = vsllink_usb_write(vsllink_handle, 3); + if (result != 3) + { + LOG_ERROR("VSLLink command VSLLINK_CMD_SET_PORT failed (%d)", result); + } +} + +static void vsllink_simple_command(uint8_t command) +{ + int result; + + DEBUG_JTAG_IO("0x%02x", command); + + vsllink_usb_out_buffer[0] = command; + result = vsllink_usb_write(vsllink_handle, 1); + + if (result != 1) + { + LOG_ERROR("VSLLink command 0x%02x failed (%d)", command, result); + } +} + +COMMAND_HANDLER(vsllink_handle_mode_command) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("parameter error, should be one parameter for VID"); + return ERROR_FAIL; + } + + if (!strcmp(CMD_ARGV[0], "normal")) + { + vsllink_mode = VSLLINK_MODE_NORMAL; + } + else if (!strcmp(CMD_ARGV[0], "dma")) + { + vsllink_mode = VSLLINK_MODE_DMA; + } + else + { + LOG_ERROR("invalid vsllink_mode: %s", CMD_ARGV[0]); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(vsllink_handle_usb_vid_command) +{ + if (CMD_ARGC != 1) + { + LOG_ERROR("parameter error, should be one parameter for VID"); + return ERROR_OK; + } + + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], vsllink_usb_vid); + return ERROR_OK; +} + +COMMAND_HANDLER(vsllink_handle_usb_pid_command) +{ + if (CMD_ARGC != 1) + { + LOG_ERROR("parameter error, should be one parameter for PID"); + return ERROR_OK; + } + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], vsllink_usb_pid); + return ERROR_OK; +} + +COMMAND_HANDLER(vsllink_handle_usb_bulkin_command) +{ + if (CMD_ARGC != 1) + { + LOG_ERROR("parameter error, should be one parameter for BULKIN endpoint"); + return ERROR_OK; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], vsllink_usb_bulkin); + + vsllink_usb_bulkin |= 0x80; + + return ERROR_OK; +} + +COMMAND_HANDLER(vsllink_handle_usb_bulkout_command) +{ + if (CMD_ARGC != 1) + { + LOG_ERROR("parameter error, should be one parameter for BULKOUT endpoint"); + return ERROR_OK; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], vsllink_usb_bulkout); + + vsllink_usb_bulkout &= ~0x80; + + return ERROR_OK; +} + +COMMAND_HANDLER(vsllink_handle_usb_interface_command) +{ + if (CMD_ARGC != 1) + { + LOG_ERROR("parameter error, should be one parameter for interface number"); + return ERROR_OK; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], vsllink_usb_interface); + return ERROR_OK; +} + +/***************************************************************************/ +/* VSLLink tap functions */ + +static void vsllink_tap_init_normal(void) +{ + vsllink_usb_out_buffer_idx = 0; + vsllink_usb_in_want_length = 0; + pending_scan_results_length = 0; +} +static void vsllink_tap_init_dma(void) +{ + tap_length = 0; + pending_scan_results_length = 0; +} + +static void vsllink_tap_ensure_space_normal(int scans, int length) +{ + int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; + int available_bytes = VSLLINK_BufferSize - vsllink_usb_out_buffer_idx; + + if (scans > available_scans || length > available_bytes) + { + vsllink_tap_execute(); + } +} +static void vsllink_tap_ensure_space_dma(int scans, int length) +{ + int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; + int available_bytes = tap_buffer_size * 8 - tap_length; + + if (scans > available_scans || length > available_bytes) + { + vsllink_tap_execute(); + } +} + +static void vsllink_tap_append_step(int tms, int tdi) +{ + last_tms = tms; + int index = tap_length / 8; + + if (index < 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("buffer overflow, tap_length=%d", tap_length); + } +} + +static void vsllink_tap_append_scan_normal(int length, uint8_t *buffer, struct scan_command *command, int offset) +{ + struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; + int i; + + if (offset > 0) + { + vsllink_usb_in_want_length += ((length + 7) >> 3) + 1; + } + else + { + vsllink_usb_in_want_length += (length + 7) >> 3; + } + pending_scan_result->length = length; + pending_scan_result->offset = offset; + pending_scan_result->command = command; + pending_scan_result->buffer = buffer; + + for (i = 0; i < ((length + 7) >> 3); i++) + { + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = buffer[i]; + } + + pending_scan_results_length++; +} +static void vsllink_tap_append_scan_dma(int length, uint8_t *buffer, struct scan_command *command) +{ + struct pending_scan_result *pending_scan_result; + int len_tmp, len_all, i; + + len_all = 0; + while (len_all < length) + { + if ((length - len_all) > tap_buffer_size * 8) + { + len_tmp = tap_buffer_size * 8; + } + else + { + len_tmp = length - len_all; + } + + vsllink_tap_ensure_space(1, (len_tmp + 7) & ~7); + + pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; + pending_scan_result->offset = tap_length; + pending_scan_result->length = len_tmp; + pending_scan_result->command = command; + pending_scan_result->buffer = buffer + len_all / 8; + + for (i = 0; i < len_tmp; i++) + { + vsllink_tap_append_step(((len_all + i) < length-1 ? 0 : 1), (buffer[(len_all + i)/8] >> ((len_all + i)%8)) & 1); + } + + pending_scan_results_length++; + len_all += len_tmp; + } +} + +/* Pad and send a tap sequence to the device, and receive the answer. + * For the purpose of padding we assume that we are in reset or idle or pause state. */ +static int vsllink_tap_execute_normal(void) +{ + int i; + int result; + int first = 0; + + if (vsllink_tms_data_len > 0) + { + if ((tap_get_state() != TAP_RESET) && (tap_get_state() != TAP_IDLE) && (tap_get_state() != TAP_IRPAUSE) && (tap_get_state() != TAP_DRPAUSE)) + { + LOG_WARNING("%s is not in RESET or IDLE or PAUSR state", tap_state_name(tap_get_state())); + } + + if (vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] & (1 << (vsllink_tms_data_len - 1))) + { + // last tms bit is '1' + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= 0xFF << vsllink_tms_data_len; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0xFF; + vsllink_tms_data_len = 0; + } + else + { + // last tms bit is '0' + vsllink_usb_out_buffer_idx++; + vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0; + vsllink_tms_data_len = 0; + } + } + + if (vsllink_usb_out_buffer_idx > 3) + { + if (vsllink_usb_out_buffer[0] == VSLLINK_CMD_HW_JTAGSEQCMD) + { + vsllink_usb_out_buffer[1] = (vsllink_usb_out_buffer_idx >> 0) & 0xff; + vsllink_usb_out_buffer[2] = (vsllink_usb_out_buffer_idx >> 8) & 0xff; + } + + result = vsllink_usb_message(vsllink_handle, vsllink_usb_out_buffer_idx, vsllink_usb_in_want_length); + + if (result == vsllink_usb_in_want_length) + { + 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 offset = pending_scan_result->offset; + struct scan_command *command = pending_scan_result->command; + + if (buffer != NULL) + { + // IRSHIFT or DRSHIFT + buf_set_buf(vsllink_usb_in_buffer, first * 8 + offset, buffer, 0, length); + first += (length + offset + 7) >> 3; + + DEBUG_JTAG_IO("JTAG scan read(%d bits):", length); +#ifdef _DEBUG_JTAG_IO_ + vsllink_debug_buffer(buffer, (length + 7) >> 3); +#endif + + if (jtag_read_buffer(buffer, command) != ERROR_OK) + { + vsllink_tap_init(); + return ERROR_JTAG_QUEUE_FAILED; + } + + free(pending_scan_result->buffer); + pending_scan_result->buffer = NULL; + } + else + { + first++; + } + } + } + else + { + LOG_ERROR("vsllink_tap_execute, wrong result %d, expected %d", result, vsllink_usb_in_want_length); + return ERROR_JTAG_QUEUE_FAILED; + } + + vsllink_tap_init(); + } + reset_command_pointer(); + + return ERROR_OK; +} +static int vsllink_tap_execute_dma(void) +{ + int byte_length; + 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. */ + vsllink_tap_append_step(last_tms, 0); + } + byte_length = tap_length / 8; + + vsllink_usb_out_buffer[0] = VSLLINK_CMD_HW_JTAGRAWCMD; + vsllink_usb_out_buffer[1] = ((byte_length * 2 + 3) >> 0) & 0xff; // package size + vsllink_usb_out_buffer[2] = ((byte_length * 2 + 3) >> 8) & 0xff; + + memcpy(&vsllink_usb_out_buffer[3], tdi_buffer, byte_length); + memcpy(&vsllink_usb_out_buffer[3 + byte_length], tms_buffer, byte_length); + + result = vsllink_usb_message(vsllink_handle, 3 + 2 * byte_length, byte_length); + if (result == byte_length) + { + 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->offset; + + struct scan_command *command = pending_scan_result->command; + buf_set_buf(vsllink_usb_in_buffer, first, buffer, 0, length); + + DEBUG_JTAG_IO("JTAG scan read(%d bits, from %d bits):", length, first); +#ifdef _DEBUG_JTAG_IO_ + vsllink_debug_buffer(buffer, (length + 7) >> 3); +#endif + + if (jtag_read_buffer(buffer, command) != ERROR_OK) + { + vsllink_tap_init(); + return ERROR_JTAG_QUEUE_FAILED; + } + + if (pending_scan_result->buffer != NULL) + { + free(pending_scan_result->buffer); + } + } + } + else + { + LOG_ERROR("vsllink_tap_execute, wrong result %d, expected %d", result, byte_length); + return ERROR_JTAG_QUEUE_FAILED; + } + + vsllink_tap_init(); + } + + return ERROR_OK; +} + +/*****************************************************************************/ +/* VSLLink USB low-level functions */ + +static struct vsllink* vsllink_usb_open(void) +{ + usb_init(); + + const uint16_t vids[] = { vsllink_usb_vid, 0 }; + const uint16_t pids[] = { vsllink_usb_pid, 0 }; + struct usb_dev_handle *dev; + if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) + return NULL; + + /* usb_set_configuration required under win32 */ + struct usb_device *udev = usb_device(dev); + int ret = usb_set_configuration(dev, udev->config[0].bConfigurationValue); + if (ret != 0) + { + LOG_ERROR("fail to set configuration to %d (error %d)." + "Not enough permissions for the device?", + udev->config[0].bConfigurationValue, ret); + return NULL; + } + ret = usb_claim_interface(dev, vsllink_usb_interface); + if (ret != 0) + { + LOG_ERROR("fail to claim interface %d, %d returned", + vsllink_usb_interface, ret); + return NULL; + } +#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 + + struct vsllink *result = malloc(sizeof(struct vsllink)); + result->usb_handle = dev; + return result; +} + +static void vsllink_usb_close(struct vsllink *vsllink) +{ + int ret; + + ret = usb_release_interface(vsllink->usb_handle, vsllink_usb_interface); + if (ret != 0) + { + LOG_ERROR("fail to release interface %d, %d returned", vsllink_usb_interface, ret); + exit(-1); + } + + ret = usb_close(vsllink->usb_handle); + if (ret != 0) + { + LOG_ERROR("fail to close usb, %d returned", ret); + exit(-1); + } + + free(vsllink); +} + +/* Send a message and receive the reply. */ +static int vsllink_usb_message(struct vsllink *vsllink, int out_length, int in_length) +{ + int result; + + result = vsllink_usb_write(vsllink, out_length); + if (result == out_length) + { + if (in_length > 0) + { + result = vsllink_usb_read(vsllink); + if (result == in_length) + { + return result; + } + else + { + LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); + return -1; + } + } + return 0; + } + else + { + LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); + return -1; + } +} + +/* Write data from out_buffer to USB. */ +static int vsllink_usb_write(struct vsllink *vsllink, int out_length) +{ + int result; + + if (out_length > VSLLINK_BufferSize) + { + LOG_ERROR("vsllink_write illegal out_length=%d (max=%d)", out_length, VSLLINK_BufferSize); + return -1; + } + + result = usb_bulk_write(vsllink->usb_handle, vsllink_usb_bulkout, \ + (char *)vsllink_usb_out_buffer, out_length, VSLLINK_USB_TIMEOUT); + + DEBUG_JTAG_IO("vsllink_usb_write, out_length = %d, result = %d", out_length, result); + +#ifdef _DEBUG_USB_COMMS_ + LOG_DEBUG("USB out:"); + vsllink_debug_buffer(vsllink_usb_out_buffer, out_length); +#endif + +#ifdef _VSLLINK_IN_DEBUG_MODE_ + usleep(100000); +#endif + + return result; +} + +/* Read data from USB into in_buffer. */ +static int vsllink_usb_read(struct vsllink *vsllink) +{ + int result = usb_bulk_read(vsllink->usb_handle, vsllink_usb_bulkin, \ + (char *)vsllink_usb_in_buffer, VSLLINK_BufferSize, VSLLINK_USB_TIMEOUT); + + DEBUG_JTAG_IO("vsllink_usb_read, result = %d", result); + +#ifdef _DEBUG_USB_COMMS_ + LOG_DEBUG("USB in:"); + vsllink_debug_buffer(vsllink_usb_in_buffer, result); +#endif + return result; +} + +#define BYTES_PER_LINE 16 + +#if defined _DEBUG_USB_COMMS_ || defined _DEBUG_JTAG_IO_ +static void vsllink_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 // _DEBUG_USB_COMMS_ || _DEBUG_JTAG_IO_ + +static const struct command_registration vsllink_command_handlers[] = { + { + .name = "vsllink_usb_vid", + .handler = &vsllink_handle_usb_vid_command, + .mode = COMMAND_CONFIG, + }, + { + .name = "vsllink_usb_pid", + .handler = &vsllink_handle_usb_pid_command, + .mode = COMMAND_CONFIG, + }, + { + .name = "vsllink_usb_bulkin", + .handler = &vsllink_handle_usb_bulkin_command, + .mode = COMMAND_CONFIG, + }, + { + .name = "vsllink_usb_bulkout", + .handler = &vsllink_handle_usb_bulkout_command, + .mode = COMMAND_CONFIG, + }, + { + .name = "vsllink_usb_interface", + .handler = &vsllink_handle_usb_interface_command, + .mode = COMMAND_CONFIG, + }, + { + .name = "vsllink_mode", + .handler = &vsllink_handle_mode_command, + .mode = COMMAND_CONFIG, + }, + COMMAND_REGISTRATION_DONE +}; + +struct jtag_interface vsllink_interface = { + .name = "vsllink", + .commands = vsllink_command_handlers, + + .init = &vsllink_init, + .quit = &vsllink_quit, + .khz = &vsllink_khz, + .speed = &vsllink_speed, + .speed_div = &vsllink_speed_div, + .execute_queue = &vsllink_execute_queue, + }; diff --git a/src/jtag/dummy.c b/src/jtag/dummy.c deleted file mode 100644 index c2beb092..00000000 --- a/src/jtag/dummy.c +++ /dev/null @@ -1,177 +0,0 @@ -/*************************************************************************** - * 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, - }; diff --git a/src/jtag/ep93xx.c b/src/jtag/ep93xx.c deleted file mode 100644 index c679b216..00000000 --- a/src/jtag/ep93xx.c +++ /dev/null @@ -1,230 +0,0 @@ -/*************************************************************************** - * 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 - -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; -} diff --git a/src/jtag/ft2232.c b/src/jtag/ft2232.c deleted file mode 100644 index 29b6389c..00000000 --- a/src/jtag/ft2232.c +++ /dev/null @@ -1,4021 +0,0 @@ -/*************************************************************************** -* Copyright (C) 2009 by Øyvind Harboe * -* Øyvind Harboe * -* * -* Copyright (C) 2009 by SoftPLC Corporation. http://softplc.com * -* Dick Hollenbeck * -* * -* Copyright (C) 2004, 2006 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. * -***************************************************************************/ - -/* This code uses information contained in the MPSSE specification which was - * found here: - * http://www.ftdichip.com/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf - * Hereafter this is called the "MPSSE Spec". - * - * The datasheet for the ftdichip.com's FT2232D part is here: - * http://www.ftdichip.com/Documents/DataSheets/DS_FT2232D.pdf - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* project specific includes */ -#include "interface.h" -#include "commands.h" -#include "time_support.h" - -#if IS_CYGWIN == 1 -#include -#endif - -#include - -#if (BUILD_FT2232_FTD2XX == 1 && BUILD_FT2232_LIBFTDI == 1) -#error "BUILD_FT2232_FTD2XX && BUILD_FT2232_LIBFTDI are mutually exclusive" -#elif (BUILD_FT2232_FTD2XX != 1 && BUILD_FT2232_LIBFTDI != 1) -#error "BUILD_FT2232_FTD2XX || BUILD_FT2232_LIBFTDI must be chosen" -#endif - -/* FT2232 access library includes */ -#if BUILD_FT2232_FTD2XX == 1 -#include -#elif BUILD_FT2232_LIBFTDI == 1 -#include -#endif - -/* max TCK for the high speed devices 30000 kHz */ -#define FTDI_2232H_4232H_MAX_TCK 30000 -/* max TCK for the full speed devices 6000 kHz */ -#define FTDI_2232C_MAX_TCK 6000 -/* this speed value tells that RTCK is requested */ -#define RTCK_SPEED -1 - -/* - * On my Athlon XP 1900+ EHCI host with FT2232H JTAG dongle I get read timeout - * errors with a retry count of 100. Increasing it solves the problem for me. - * - Dimitar - * - * FIXME There's likely an issue with the usb_read_timeout from libftdi. - * Fix that (libusb? kernel? libftdi? here?) and restore the retry count - * to something sane. - */ -#define LIBFTDI_READ_RETRY_COUNT 2000 - -#ifndef BUILD_FT2232_HIGHSPEED - #if BUILD_FT2232_FTD2XX == 1 - enum { FT_DEVICE_2232H = 6, FT_DEVICE_4232H }; - #elif BUILD_FT2232_LIBFTDI == 1 - enum { TYPE_2232H = 4, TYPE_4232H = 5 }; - #endif -#endif - -/** - * Send out \a num_cycles on the TCK line while the TAP(s) are in a - * stable state. Calling code must ensure that current state is stable, - * that verification is not done in here. - * - * @param num_cycles The number of clocks cycles to send. - * @param cmd The command to send. - * - * @returns ERROR_OK on success, or ERROR_JTAG_QUEUE_FAILED on failure. - */ -static int ft2232_stableclocks(int num_cycles, struct jtag_command* cmd); - -static char * ft2232_device_desc_A = NULL; -static char* ft2232_device_desc = NULL; -static char* ft2232_serial = NULL; -static char* ft2232_layout = NULL; -static uint8_t ft2232_latency = 2; -static unsigned ft2232_max_tck = FTDI_2232C_MAX_TCK; - -#define MAX_USB_IDS 8 -/* vid = pid = 0 marks the end of the list */ -static uint16_t ft2232_vid[MAX_USB_IDS + 1] = { 0x0403, 0 }; -static uint16_t ft2232_pid[MAX_USB_IDS + 1] = { 0x6010, 0 }; - -struct ft2232_layout { - char* name; - int (*init)(void); - void (*reset)(int trst, int srst); - void (*blink)(void); -}; - -/* init procedures for supported layouts */ -static int usbjtag_init(void); -static int jtagkey_init(void); -static int olimex_jtag_init(void); -static int flyswatter_init(void); -static int turtle_init(void); -static int comstick_init(void); -static int stm32stick_init(void); -static int axm0432_jtag_init(void); -static int sheevaplug_init(void); -static int icebear_jtag_init(void); -static int cortino_jtag_init(void); -static int signalyzer_h_init(void); -static int ktlink_init(void); - -/* reset procedures for supported layouts */ -static void usbjtag_reset(int trst, int srst); -static void jtagkey_reset(int trst, int srst); -static void olimex_jtag_reset(int trst, int srst); -static void flyswatter_reset(int trst, int srst); -static void turtle_reset(int trst, int srst); -static void comstick_reset(int trst, int srst); -static void stm32stick_reset(int trst, int srst); -static void axm0432_jtag_reset(int trst, int srst); -static void sheevaplug_reset(int trst, int srst); -static void icebear_jtag_reset(int trst, int srst); -static void signalyzer_h_reset(int trst, int srst); -static void ktlink_reset(int trst, int srst); - -/* blink procedures for layouts that support a blinking led */ -static void olimex_jtag_blink(void); -static void flyswatter_jtag_blink(void); -static void turtle_jtag_blink(void); -static void signalyzer_h_blink(void); -static void ktlink_blink(void); - -static const struct ft2232_layout ft2232_layouts[] = -{ - { "usbjtag", usbjtag_init, usbjtag_reset, NULL }, - { "jtagkey", jtagkey_init, jtagkey_reset, NULL }, - { "jtagkey_prototype_v1", jtagkey_init, jtagkey_reset, NULL }, - { "oocdlink", jtagkey_init, jtagkey_reset, NULL }, - { "signalyzer", usbjtag_init, usbjtag_reset, NULL }, - { "evb_lm3s811", usbjtag_init, usbjtag_reset, NULL }, - { "luminary_icdi", usbjtag_init, usbjtag_reset, NULL }, - { "olimex-jtag", olimex_jtag_init, olimex_jtag_reset, olimex_jtag_blink }, - { "flyswatter", flyswatter_init, flyswatter_reset, flyswatter_jtag_blink }, - { "turtelizer2", turtle_init, turtle_reset, turtle_jtag_blink }, - { "comstick", comstick_init, comstick_reset, NULL }, - { "stm32stick", stm32stick_init, stm32stick_reset, NULL }, - { "axm0432_jtag", axm0432_jtag_init, axm0432_jtag_reset, NULL }, - { "sheevaplug", sheevaplug_init, sheevaplug_reset, NULL }, - { "icebear", icebear_jtag_init, icebear_jtag_reset, NULL }, - { "cortino", cortino_jtag_init, comstick_reset, NULL }, - { "signalyzer-h", signalyzer_h_init, signalyzer_h_reset, signalyzer_h_blink }, - { "ktlink", ktlink_init, ktlink_reset, ktlink_blink }, - { NULL, NULL, NULL, NULL }, -}; - -static uint8_t nTRST, nTRSTnOE, nSRST, nSRSTnOE; - -static const struct ft2232_layout *layout; -static uint8_t low_output = 0x0; -static uint8_t low_direction = 0x0; -static uint8_t high_output = 0x0; -static uint8_t high_direction = 0x0; - -#if BUILD_FT2232_FTD2XX == 1 -static FT_HANDLE ftdih = NULL; -static FT_DEVICE ftdi_device = 0; -#elif BUILD_FT2232_LIBFTDI == 1 -static struct ftdi_context ftdic; -static enum ftdi_chip_type ftdi_device; -#endif - -static struct jtag_command* first_unsent; /* next command that has to be sent */ -static int require_send; - -/* http://urjtag.wiki.sourceforge.net/Cable + FT2232 says: - - "There is a significant difference between libftdi and libftd2xx. The latter - one allows to schedule up to 64*64 bytes of result data while libftdi fails - with more than 4*64. As a consequence, the FT2232 driver is forced to - perform around 16x more USB transactions for long command streams with TDO - capture when running with libftdi." - - No idea how we get - #define FT2232_BUFFER_SIZE 131072 - a comment would have been nice. -*/ - -#define FT2232_BUFFER_SIZE 131072 - -static uint8_t* ft2232_buffer = NULL; -static int ft2232_buffer_size = 0; -static int ft2232_read_pointer = 0; -static int ft2232_expect_read = 0; - -/** - * Function buffer_write - * writes a byte into the byte buffer, "ft2232_buffer", which must be sent later. - * @param val is the byte to send. - */ -static inline void buffer_write(uint8_t val) -{ - assert(ft2232_buffer); - assert((unsigned) ft2232_buffer_size < (unsigned) FT2232_BUFFER_SIZE); - ft2232_buffer[ft2232_buffer_size++] = val; -} - -/** - * Function buffer_read - * returns a byte from the byte buffer. - */ -static inline uint8_t buffer_read(void) -{ - assert(ft2232_buffer); - assert(ft2232_read_pointer < ft2232_buffer_size); - return ft2232_buffer[ft2232_read_pointer++]; -} - -/** - * Clocks out \a bit_count bits on the TMS line, starting with the least - * significant bit of tms_bits and progressing to more significant bits. - * Rigorous state transition logging is done here via tap_set_state(). - * - * @param mpsse_cmd One of the MPSSE TMS oriented commands such as - * 0x4b or 0x6b. See the MPSSE spec referenced above for their - * functionality. The MPSSE command "Clock Data to TMS/CS Pin (no Read)" - * is often used for this, 0x4b. - * - * @param tms_bits Holds the sequence of bits to send. - * @param tms_count Tells how many bits in the sequence. - * @param tdi_bit A single bit to pass on to TDI before the first TCK - * cycle and held static for the duration of TMS clocking. - * - * See the MPSSE spec referenced above. - */ -static void clock_tms(uint8_t mpsse_cmd, int tms_bits, int tms_count, bool tdi_bit) -{ - uint8_t tms_byte; - int i; - int tms_ndx; /* bit index into tms_byte */ - - assert(tms_count > 0); - - DEBUG_JTAG_IO("mpsse cmd=%02x, tms_bits = 0x%08x, bit_count=%d", - mpsse_cmd, tms_bits, tms_count); - - for (tms_byte = tms_ndx = i = 0; i < tms_count; ++i, tms_bits>>=1) - { - bool bit = tms_bits & 1; - - if (bit) - tms_byte |= (1 << tms_ndx); - - /* always do state transitions in public view */ - tap_set_state(tap_state_transition(tap_get_state(), bit)); - - /* we wrote a bit to tms_byte just above, increment bit index. if bit was zero - also increment. - */ - ++tms_ndx; - - if (tms_ndx == 7 || i == tms_count-1) - { - buffer_write(mpsse_cmd); - buffer_write(tms_ndx - 1); - - /* Bit 7 of the byte is passed on to TDI/DO before the first TCK/SK of - TMS/CS and is held static for the duration of TMS/CS clocking. - */ - buffer_write(tms_byte | (tdi_bit << 7)); - } - } -} - -/** - * Function get_tms_buffer_requirements - * returns what clock_tms() will consume if called with - * same \a bit_count. - */ -static inline int get_tms_buffer_requirements(int bit_count) -{ - return ((bit_count + 6)/7) * 3; -} - -/** - * Function move_to_state - * moves the TAP controller from the current state to a - * \a goal_state through a path given by tap_get_tms_path(). State transition - * logging is performed by delegation to clock_tms(). - * - * @param goal_state is the destination state for the move. - */ -static void move_to_state(tap_state_t goal_state) -{ - tap_state_t start_state = tap_get_state(); - - /* goal_state is 1/2 of a tuple/pair of states which allow convenient - lookup of the required TMS pattern to move to this state from the - start state. - */ - - /* do the 2 lookups */ - int tms_bits = tap_get_tms_path(start_state, goal_state); - int tms_count = tap_get_tms_path_len(start_state, goal_state); - - DEBUG_JTAG_IO("start=%s goal=%s", tap_state_name(start_state), tap_state_name(goal_state)); - - clock_tms(0x4b, tms_bits, tms_count, 0); -} - -static int ft2232_write(uint8_t* buf, int size, uint32_t* bytes_written) -{ -#if BUILD_FT2232_FTD2XX == 1 - FT_STATUS status; - DWORD dw_bytes_written; - if ((status = FT_Write(ftdih, buf, size, &dw_bytes_written)) != FT_OK) - { - *bytes_written = dw_bytes_written; - LOG_ERROR("FT_Write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - else - { - *bytes_written = dw_bytes_written; - return ERROR_OK; - } -#elif BUILD_FT2232_LIBFTDI == 1 - int retval; - if ((retval = ftdi_write_data(&ftdic, buf, size)) < 0) - { - *bytes_written = 0; - LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - else - { - *bytes_written = retval; - return ERROR_OK; - } -#endif -} - -static int ft2232_read(uint8_t* buf, uint32_t size, uint32_t* bytes_read) -{ -#if BUILD_FT2232_FTD2XX == 1 - DWORD dw_bytes_read; - FT_STATUS status; - int timeout = 5; - *bytes_read = 0; - - while ((*bytes_read < size) && timeout--) - { - if ((status = FT_Read(ftdih, buf + *bytes_read, size - - *bytes_read, &dw_bytes_read)) != FT_OK) - { - *bytes_read = 0; - LOG_ERROR("FT_Read returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - *bytes_read += dw_bytes_read; - } - -#elif BUILD_FT2232_LIBFTDI == 1 - int retval; - int timeout = LIBFTDI_READ_RETRY_COUNT; - *bytes_read = 0; - - while ((*bytes_read < size) && timeout--) - { - if ((retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read)) < 0) - { - *bytes_read = 0; - LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - *bytes_read += retval; - } - -#endif - - if (*bytes_read < size) - { - LOG_ERROR("couldn't read enough bytes from " - "FT2232 device (%i < %i)", - (unsigned)*bytes_read, - (unsigned)size); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static bool ft2232_device_is_highspeed(void) -{ -#if BUILD_FT2232_FTD2XX == 1 - return (ftdi_device == FT_DEVICE_2232H) || (ftdi_device == FT_DEVICE_4232H); -#elif BUILD_FT2232_LIBFTDI == 1 - return (ftdi_device == TYPE_2232H || ftdi_device == TYPE_4232H); -#endif -} - -/* - * Commands that only apply to the FT2232H and FT4232H devices. - * See chapter 6 in http://www.ftdichip.com/Documents/AppNotes/ - * AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf - */ - -static int ft2232h_ft4232h_adaptive_clocking(bool enable) -{ - uint8_t buf = enable ? 0x96 : 0x97; - LOG_DEBUG("%2.2x", buf); - - uint32_t bytes_written; - int retval = ft2232_write(&buf, 1, &bytes_written); - if ((ERROR_OK != retval) || (bytes_written != 1)) - { - LOG_ERROR("couldn't write command to %s adaptive clocking" - , enable ? "enable" : "disable"); - return retval; - } - - return ERROR_OK; -} - -/** - * Enable/disable the clk divide by 5 of the 60MHz master clock. - * This result in a JTAG clock speed range of 91.553Hz-6MHz - * respective 457.763Hz-30MHz. - */ -static int ft2232h_ft4232h_clk_divide_by_5(bool enable) -{ - uint32_t bytes_written; - uint8_t buf = enable ? 0x8b : 0x8a; - int retval = ft2232_write(&buf, 1, &bytes_written); - if ((ERROR_OK != retval) || (bytes_written != 1)) - { - LOG_ERROR("couldn't write command to %s clk divide by 5" - , enable ? "enable" : "disable"); - return ERROR_JTAG_INIT_FAILED; - } - ft2232_max_tck = enable ? FTDI_2232C_MAX_TCK : FTDI_2232H_4232H_MAX_TCK; - LOG_INFO("max TCK change to: %u kHz", ft2232_max_tck); - - return ERROR_OK; -} - -static int ft2232_speed(int speed) -{ - uint8_t buf[3]; - int retval; - uint32_t bytes_written; - - retval = ERROR_OK; - bool enable_adaptive_clocking = (RTCK_SPEED == speed); - if (ft2232_device_is_highspeed()) - retval = ft2232h_ft4232h_adaptive_clocking(enable_adaptive_clocking); - else if (enable_adaptive_clocking) - { - LOG_ERROR("ft2232 device %lu does not support RTCK" - , (long unsigned int)ftdi_device); - return ERROR_FAIL; - } - - if ((enable_adaptive_clocking) || (ERROR_OK != retval)) - return retval; - - buf[0] = 0x86; /* command "set divisor" */ - buf[1] = speed & 0xff; /* valueL (0 = 6MHz, 1 = 3MHz, 2 = 2.0MHz, ...*/ - buf[2] = (speed >> 8) & 0xff; /* valueH */ - - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - if (((retval = ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't set FT2232 TCK speed"); - return retval; - } - - return ERROR_OK; -} - -static int ft2232_speed_div(int speed, int* khz) -{ - /* Take a look in the FT2232 manual, - * AN2232C-01 Command Processor for - * MPSSE and MCU Host Bus. Chapter 3.8 */ - - *khz = (RTCK_SPEED == speed) ? 0 : ft2232_max_tck / (1 + speed); - - return ERROR_OK; -} - -static int ft2232_khz(int khz, int* jtag_speed) -{ - if (khz == 0) - { - if (ft2232_device_is_highspeed()) - { - *jtag_speed = RTCK_SPEED; - return ERROR_OK; - } - else - { - LOG_DEBUG("RCLK not supported"); - return ERROR_FAIL; - } - } - - /* Take a look in the FT2232 manual, - * AN2232C-01 Command Processor for - * MPSSE and MCU Host Bus. Chapter 3.8 - * - * We will calc here with a multiplier - * of 10 for better rounding later. */ - - /* Calc speed, (ft2232_max_tck / khz) - 1 */ - /* Use 65000 for better rounding */ - *jtag_speed = ((ft2232_max_tck*10) / khz) - 10; - - /* Add 0.9 for rounding */ - *jtag_speed += 9; - - /* Calc real speed */ - *jtag_speed = *jtag_speed / 10; - - /* Check if speed is greater than 0 */ - if (*jtag_speed < 0) - { - *jtag_speed = 0; - } - - /* Check max value */ - if (*jtag_speed > 0xFFFF) - { - *jtag_speed = 0xFFFF; - } - - return ERROR_OK; -} - -static void ft2232_end_state(tap_state_t state) -{ - if (tap_is_state_stable(state)) - tap_set_end_state(state); - else - { - LOG_ERROR("BUG: %s is not a stable end state", tap_state_name(state)); - exit(-1); - } -} - -static void ft2232_read_scan(enum scan_type type, uint8_t* buffer, int scan_size) -{ - int num_bytes = (scan_size + 7) / 8; - int bits_left = scan_size; - int cur_byte = 0; - - while (num_bytes-- > 1) - { - buffer[cur_byte++] = buffer_read(); - bits_left -= 8; - } - - buffer[cur_byte] = 0x0; - - /* There is one more partial byte left from the clock data in/out instructions */ - if (bits_left > 1) - { - buffer[cur_byte] = buffer_read() >> 1; - } - /* This shift depends on the length of the clock data to tms instruction, insterted at end of the scan, now fixed to a two step transition in ft2232_add_scan */ - buffer[cur_byte] = (buffer[cur_byte] | (((buffer_read()) << 1) & 0x80)) >> (8 - bits_left); -} - -static void ft2232_debug_dump_buffer(void) -{ - int i; - char line[256]; - char* line_p = line; - - for (i = 0; i < ft2232_buffer_size; i++) - { - line_p += snprintf(line_p, 256 - (line_p - line), "%2.2x ", ft2232_buffer[i]); - if (i % 16 == 15) - { - LOG_DEBUG("%s", line); - line_p = line; - } - } - - if (line_p != line) - LOG_DEBUG("%s", line); -} - -static int ft2232_send_and_recv(struct jtag_command* first, struct jtag_command* last) -{ - struct jtag_command* cmd; - uint8_t* buffer; - int scan_size; - enum scan_type type; - int retval; - uint32_t bytes_written = 0; - uint32_t bytes_read = 0; - -#ifdef _DEBUG_USB_IO_ - struct timeval start, inter, inter2, end; - struct timeval d_inter, d_inter2, d_end; -#endif - -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("write buffer (size %i):", ft2232_buffer_size); - ft2232_debug_dump_buffer(); -#endif - -#ifdef _DEBUG_USB_IO_ - gettimeofday(&start, NULL); -#endif - - if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) - { - LOG_ERROR("couldn't write MPSSE commands to FT2232"); - return retval; - } - -#ifdef _DEBUG_USB_IO_ - gettimeofday(&inter, NULL); -#endif - - if (ft2232_expect_read) - { - /* FIXME this "timeout" is never changed ... */ - int timeout = LIBFTDI_READ_RETRY_COUNT; - ft2232_buffer_size = 0; - -#ifdef _DEBUG_USB_IO_ - gettimeofday(&inter2, NULL); -#endif - - if ((retval = ft2232_read(ft2232_buffer, ft2232_expect_read, &bytes_read)) != ERROR_OK) - { - LOG_ERROR("couldn't read from FT2232"); - return retval; - } - -#ifdef _DEBUG_USB_IO_ - gettimeofday(&end, NULL); - - timeval_subtract(&d_inter, &inter, &start); - timeval_subtract(&d_inter2, &inter2, &start); - timeval_subtract(&d_end, &end, &start); - - LOG_INFO("inter: %u.%06u, inter2: %u.%06u end: %u.%06u", - (unsigned)d_inter.tv_sec, (unsigned)d_inter.tv_usec, - (unsigned)d_inter2.tv_sec, (unsigned)d_inter2.tv_usec, - (unsigned)d_end.tv_sec, (unsigned)d_end.tv_usec); -#endif - - ft2232_buffer_size = bytes_read; - - if (ft2232_expect_read != ft2232_buffer_size) - { - LOG_ERROR("ft2232_expect_read (%i) != " - "ft2232_buffer_size (%i) " - "(%i retries)", - ft2232_expect_read, - ft2232_buffer_size, - LIBFTDI_READ_RETRY_COUNT - timeout); - ft2232_debug_dump_buffer(); - - exit(-1); - } - -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("read buffer (%i retries): %i bytes", - LIBFTDI_READ_RETRY_COUNT - timeout, - ft2232_buffer_size); - ft2232_debug_dump_buffer(); -#endif - } - - ft2232_expect_read = 0; - ft2232_read_pointer = 0; - - /* 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; - - cmd = first; - while (cmd != last) - { - switch (cmd->type) - { - case JTAG_SCAN: - type = jtag_scan_type(cmd->cmd.scan); - if (type != SCAN_OUT) - { - scan_size = jtag_scan_size(cmd->cmd.scan); - buffer = calloc(DIV_ROUND_UP(scan_size, 8), 1); - ft2232_read_scan(type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - } - break; - - default: - break; - } - - cmd = cmd->next; - } - - ft2232_buffer_size = 0; - - return retval; -} - -/** - * Function ft2232_add_pathmove - * moves the TAP controller from the current state to a new state through the - * given path, where path is an array of tap_state_t's. - * - * @param path is an array of tap_stat_t which gives the states to traverse through - * ending with the last state at path[num_states-1] - * @param num_states is the count of state steps to move through - */ -static void ft2232_add_pathmove(tap_state_t* path, int num_states) -{ - int state_count = 0; - - assert((unsigned) num_states <= 32u); /* tms_bits only holds 32 bits */ - - DEBUG_JTAG_IO("-"); - - /* this loop verifies that the path is legal and logs each state in the path */ - while (num_states) - { - unsigned char tms_byte = 0; /* zero this on each MPSSE batch */ - int bit_count = 0; - int num_states_batch = num_states > 7 ? 7 : num_states; - - /* command "Clock Data to TMS/CS Pin (no Read)" */ - buffer_write(0x4b); - - /* number of states remaining */ - buffer_write(num_states_batch - 1); - - while (num_states_batch--) { - /* either TMS=0 or TMS=1 must work ... */ - if (tap_state_transition(tap_get_state(), false) - == path[state_count]) - buf_set_u32(&tms_byte, bit_count++, 1, 0x0); - else if (tap_state_transition(tap_get_state(), true) - == path[state_count]) - buf_set_u32(&tms_byte, bit_count++, 1, 0x1); - - /* ... or else the caller goofed BADLY */ - else { - LOG_ERROR("BUG: %s -> %s isn't a valid " - "TAP state transition", - tap_state_name(tap_get_state()), - tap_state_name(path[state_count])); - exit(-1); - } - - tap_set_state(path[state_count]); - state_count++; - num_states--; - } - - buffer_write(tms_byte); - } - tap_set_end_state(tap_get_state()); -} - -static void ft2232_add_scan(bool ir_scan, enum scan_type type, uint8_t* buffer, int scan_size) -{ - int num_bytes = (scan_size + 7) / 8; - int bits_left = scan_size; - int cur_byte = 0; - int last_bit; - - if (!ir_scan) - { - if (tap_get_state() != TAP_DRSHIFT) - { - move_to_state(TAP_DRSHIFT); - } - } - else - { - if (tap_get_state() != TAP_IRSHIFT) - { - move_to_state(TAP_IRSHIFT); - } - } - - /* add command for complete bytes */ - while (num_bytes > 1) - { - int thisrun_bytes; - if (type == SCAN_IO) - { - /* Clock Data Bytes In and Out LSB First */ - buffer_write(0x39); - /* LOG_DEBUG("added TDI bytes (io %i)", num_bytes); */ - } - else if (type == SCAN_OUT) - { - /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ - buffer_write(0x19); - /* LOG_DEBUG("added TDI bytes (o)"); */ - } - else if (type == SCAN_IN) - { - /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ - buffer_write(0x28); - /* LOG_DEBUG("added TDI bytes (i %i)", num_bytes); */ - } - - thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); - num_bytes -= thisrun_bytes; - - buffer_write((uint8_t) (thisrun_bytes - 1)); - buffer_write((uint8_t) ((thisrun_bytes - 1) >> 8)); - - if (type != SCAN_IN) - { - /* add complete bytes */ - while (thisrun_bytes-- > 0) - { - buffer_write(buffer[cur_byte++]); - bits_left -= 8; - } - } - else /* (type == SCAN_IN) */ - { - bits_left -= 8 * (thisrun_bytes); - } - } - - /* the most signifcant bit is scanned during TAP movement */ - if (type != SCAN_IN) - last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; - else - last_bit = 0; - - /* process remaining bits but the last one */ - if (bits_left > 1) - { - if (type == SCAN_IO) - { - /* Clock Data Bits In and Out LSB First */ - buffer_write(0x3b); - /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ - } - else if (type == SCAN_OUT) - { - /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ - buffer_write(0x1b); - /* LOG_DEBUG("added TDI bits (o)"); */ - } - else if (type == SCAN_IN) - { - /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ - buffer_write(0x2a); - /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ - } - - buffer_write(bits_left - 2); - if (type != SCAN_IN) - buffer_write(buffer[cur_byte]); - } - - if ((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) - || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT))) - { - if (type == SCAN_IO) - { - /* Clock Data Bits In and Out LSB First */ - buffer_write(0x3b); - /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ - } - else if (type == SCAN_OUT) - { - /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ - buffer_write(0x1b); - /* LOG_DEBUG("added TDI bits (o)"); */ - } - else if (type == SCAN_IN) - { - /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ - buffer_write(0x2a); - /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ - } - buffer_write(0x0); - buffer_write(last_bit); - } - else - { - int tms_bits; - int tms_count; - uint8_t mpsse_cmd; - - /* move from Shift-IR/DR to end state */ - if (type != SCAN_OUT) - { - /* We always go to the PAUSE state in two step at the end of an IN or IO scan */ - /* This must be coordinated with the bit shifts in ft2232_read_scan */ - tms_bits = 0x01; - tms_count = 2; - /* Clock Data to TMS/CS Pin with Read */ - mpsse_cmd = 0x6b; - } - else - { - tms_bits = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - /* Clock Data to TMS/CS Pin (no Read) */ - mpsse_cmd = 0x4b; - } - - DEBUG_JTAG_IO("finish %s", (type == SCAN_OUT) ? "without read" : "via PAUSE"); - clock_tms(mpsse_cmd, tms_bits, tms_count, last_bit); - } - - if (tap_get_state() != tap_get_end_state()) - { - move_to_state(tap_get_end_state()); - } -} - -static int ft2232_large_scan(struct scan_command* cmd, enum scan_type type, uint8_t* buffer, int scan_size) -{ - int num_bytes = (scan_size + 7) / 8; - int bits_left = scan_size; - int cur_byte = 0; - int last_bit; - uint8_t* receive_buffer = malloc(DIV_ROUND_UP(scan_size, 8)); - uint8_t* receive_pointer = receive_buffer; - uint32_t bytes_written; - uint32_t bytes_read; - int retval; - int thisrun_read = 0; - - if (cmd->ir_scan) - { - LOG_ERROR("BUG: large IR scans are not supported"); - exit(-1); - } - - if (tap_get_state() != TAP_DRSHIFT) - { - move_to_state(TAP_DRSHIFT); - } - - if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) - { - LOG_ERROR("couldn't write MPSSE commands to FT2232"); - exit(-1); - } - LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", - ft2232_buffer_size, (int)bytes_written); - ft2232_buffer_size = 0; - - /* add command for complete bytes */ - while (num_bytes > 1) - { - int thisrun_bytes; - - if (type == SCAN_IO) - { - /* Clock Data Bytes In and Out LSB First */ - buffer_write(0x39); - /* LOG_DEBUG("added TDI bytes (io %i)", num_bytes); */ - } - else if (type == SCAN_OUT) - { - /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ - buffer_write(0x19); - /* LOG_DEBUG("added TDI bytes (o)"); */ - } - else if (type == SCAN_IN) - { - /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ - buffer_write(0x28); - /* LOG_DEBUG("added TDI bytes (i %i)", num_bytes); */ - } - - thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); - thisrun_read = thisrun_bytes; - num_bytes -= thisrun_bytes; - buffer_write((uint8_t) (thisrun_bytes - 1)); - buffer_write((uint8_t) ((thisrun_bytes - 1) >> 8)); - - if (type != SCAN_IN) - { - /* add complete bytes */ - while (thisrun_bytes-- > 0) - { - buffer_write(buffer[cur_byte]); - cur_byte++; - bits_left -= 8; - } - } - else /* (type == SCAN_IN) */ - { - bits_left -= 8 * (thisrun_bytes); - } - - if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) - { - LOG_ERROR("couldn't write MPSSE commands to FT2232"); - exit(-1); - } - LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", - ft2232_buffer_size, - (int)bytes_written); - ft2232_buffer_size = 0; - - if (type != SCAN_OUT) - { - if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) - { - LOG_ERROR("couldn't read from FT2232"); - exit(-1); - } - LOG_DEBUG("thisrun_read: %i, bytes_read: %i", - thisrun_read, - (int)bytes_read); - receive_pointer += bytes_read; - } - } - - thisrun_read = 0; - - /* the most signifcant bit is scanned during TAP movement */ - if (type != SCAN_IN) - last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; - else - last_bit = 0; - - /* process remaining bits but the last one */ - if (bits_left > 1) - { - if (type == SCAN_IO) - { - /* Clock Data Bits In and Out LSB First */ - buffer_write(0x3b); - /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ - } - else if (type == SCAN_OUT) - { - /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ - buffer_write(0x1b); - /* LOG_DEBUG("added TDI bits (o)"); */ - } - else if (type == SCAN_IN) - { - /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ - buffer_write(0x2a); - /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ - } - buffer_write(bits_left - 2); - if (type != SCAN_IN) - buffer_write(buffer[cur_byte]); - - if (type != SCAN_OUT) - thisrun_read += 2; - } - - if (tap_get_end_state() == TAP_DRSHIFT) - { - if (type == SCAN_IO) - { - /* Clock Data Bits In and Out LSB First */ - buffer_write(0x3b); - /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ - } - else if (type == SCAN_OUT) - { - /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ - buffer_write(0x1b); - /* LOG_DEBUG("added TDI bits (o)"); */ - } - else if (type == SCAN_IN) - { - /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ - buffer_write(0x2a); - /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ - } - buffer_write(0x0); - buffer_write(last_bit); - } - else - { - int tms_bits = 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()); - uint8_t mpsse_cmd; - - /* move from Shift-IR/DR to end state */ - if (type != SCAN_OUT) - { - /* Clock Data to TMS/CS Pin with Read */ - mpsse_cmd = 0x6b; - /* LOG_DEBUG("added TMS scan (read)"); */ - } - else - { - /* Clock Data to TMS/CS Pin (no Read) */ - mpsse_cmd = 0x4b; - /* LOG_DEBUG("added TMS scan (no read)"); */ - } - - DEBUG_JTAG_IO("finish, %s", (type == SCAN_OUT) ? "no read" : "read"); - clock_tms(mpsse_cmd, tms_bits, tms_count, last_bit); - } - - if (type != SCAN_OUT) - thisrun_read += 1; - - if ((retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written)) != ERROR_OK) - { - LOG_ERROR("couldn't write MPSSE commands to FT2232"); - exit(-1); - } - LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", - ft2232_buffer_size, - (int)bytes_written); - ft2232_buffer_size = 0; - - if (type != SCAN_OUT) - { - if ((retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read)) != ERROR_OK) - { - LOG_ERROR("couldn't read from FT2232"); - exit(-1); - } - LOG_DEBUG("thisrun_read: %i, bytes_read: %i", - thisrun_read, - (int)bytes_read); - receive_pointer += bytes_read; - } - - return ERROR_OK; -} - -static int ft2232_predict_scan_out(int scan_size, enum scan_type type) -{ - int predicted_size = 3; - int num_bytes = (scan_size - 1) / 8; - - if (tap_get_state() != TAP_DRSHIFT) - predicted_size += get_tms_buffer_requirements(tap_get_tms_path_len(tap_get_state(), TAP_DRSHIFT)); - - if (type == SCAN_IN) /* only from device to host */ - { - /* complete bytes */ - predicted_size += DIV_ROUND_UP(num_bytes, 65536) * 3; - - /* remaining bits - 1 (up to 7) */ - predicted_size += ((scan_size - 1) % 8) ? 2 : 0; - } - else /* host to device, or bidirectional */ - { - /* complete bytes */ - predicted_size += num_bytes + DIV_ROUND_UP(num_bytes, 65536) * 3; - - /* remaining bits -1 (up to 7) */ - predicted_size += ((scan_size - 1) % 8) ? 3 : 0; - } - - return predicted_size; -} - -static int ft2232_predict_scan_in(int scan_size, enum scan_type type) -{ - int predicted_size = 0; - - if (type != SCAN_OUT) - { - /* complete bytes */ - predicted_size += (DIV_ROUND_UP(scan_size, 8) > 1) ? (DIV_ROUND_UP(scan_size, 8) - 1) : 0; - - /* remaining bits - 1 */ - predicted_size += ((scan_size - 1) % 8) ? 1 : 0; - - /* last bit (from TMS scan) */ - predicted_size += 1; - } - - /* LOG_DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size); */ - - return predicted_size; -} - -static void usbjtag_reset(int trst, int srst) -{ - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if (trst == 1) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - low_direction |= nTRSTnOE; /* switch to output pin (output is low) */ - else - low_output &= ~nTRST; /* switch output low */ - } - else if (trst == 0) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal and external pullup) */ - else - low_output |= nTRST; /* switch output high */ - } - - if (srst == 1) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - low_output &= ~nSRST; /* switch output low */ - else - low_direction |= nSRSTnOE; /* switch to output pin (output is low) */ - } - else if (srst == 0) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - low_output |= nSRST; /* switch output high */ - else - low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */ - } - - /* command "set data bits low byte" */ - buffer_write(0x80); - buffer_write(low_output); - buffer_write(low_direction); -} - -static void jtagkey_reset(int trst, int srst) -{ - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if (trst == 1) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output &= ~nTRSTnOE; - else - high_output &= ~nTRST; - } - else if (trst == 0) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output |= nTRSTnOE; - else - high_output |= nTRST; - } - - if (srst == 1) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - high_output &= ~nSRST; - else - high_output &= ~nSRSTnOE; - } - else if (srst == 0) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - high_output |= nSRST; - else - high_output |= nSRSTnOE; - } - - /* command "set data bits high byte" */ - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); - LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, - high_direction); -} - -static void olimex_jtag_reset(int trst, int srst) -{ - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if (trst == 1) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output &= ~nTRSTnOE; - else - high_output &= ~nTRST; - } - else if (trst == 0) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output |= nTRSTnOE; - else - high_output |= nTRST; - } - - if (srst == 1) - { - high_output |= nSRST; - } - else if (srst == 0) - { - high_output &= ~nSRST; - } - - /* command "set data bits high byte" */ - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); - LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, - high_direction); -} - -static void axm0432_jtag_reset(int trst, int srst) -{ - if (trst == 1) - { - tap_set_state(TAP_RESET); - high_output &= ~nTRST; - } - else if (trst == 0) - { - high_output |= nTRST; - } - - if (srst == 1) - { - high_output &= ~nSRST; - } - else if (srst == 0) - { - high_output |= nSRST; - } - - /* command "set data bits low byte" */ - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); - LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, - high_direction); -} - -static void flyswatter_reset(int trst, int srst) -{ - if (trst == 1) - { - low_output &= ~nTRST; - } - else if (trst == 0) - { - low_output |= nTRST; - } - - if (srst == 1) - { - low_output |= nSRST; - } - else if (srst == 0) - { - low_output &= ~nSRST; - } - - /* command "set data bits low byte" */ - buffer_write(0x80); - buffer_write(low_output); - buffer_write(low_direction); - LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); -} - -static void turtle_reset(int trst, int srst) -{ - trst = trst; - - if (srst == 1) - { - low_output |= nSRST; - } - else if (srst == 0) - { - low_output &= ~nSRST; - } - - /* command "set data bits low byte" */ - buffer_write(0x80); - buffer_write(low_output); - buffer_write(low_direction); - LOG_DEBUG("srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", srst, low_output, low_direction); -} - -static void comstick_reset(int trst, int srst) -{ - if (trst == 1) - { - high_output &= ~nTRST; - } - else if (trst == 0) - { - high_output |= nTRST; - } - - if (srst == 1) - { - high_output &= ~nSRST; - } - else if (srst == 0) - { - high_output |= nSRST; - } - - /* command "set data bits high byte" */ - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); - LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, - high_direction); -} - -static void stm32stick_reset(int trst, int srst) -{ - if (trst == 1) - { - high_output &= ~nTRST; - } - else if (trst == 0) - { - high_output |= nTRST; - } - - if (srst == 1) - { - low_output &= ~nSRST; - } - else if (srst == 0) - { - low_output |= nSRST; - } - - /* command "set data bits low byte" */ - buffer_write(0x80); - buffer_write(low_output); - buffer_write(low_direction); - - /* command "set data bits high byte" */ - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); - LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, - high_direction); -} - -static void sheevaplug_reset(int trst, int srst) -{ - if (trst == 1) - high_output &= ~nTRST; - else if (trst == 0) - high_output |= nTRST; - - if (srst == 1) - high_output &= ~nSRSTnOE; - else if (srst == 0) - high_output |= nSRSTnOE; - - /* command "set data bits high byte" */ - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); - LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); -} - -static int ft2232_execute_runtest(struct jtag_command *cmd) -{ - int retval; - int i; - int predicted_size = 0; - retval = ERROR_OK; - - DEBUG_JTAG_IO("runtest %i cycles, end in %s", - cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - - /* only send the maximum buffer size that FT2232C can handle */ - predicted_size = 0; - if (tap_get_state() != TAP_IDLE) - predicted_size += 3; - predicted_size += 3 * DIV_ROUND_UP(cmd->cmd.runtest->num_cycles, 7); - if (cmd->cmd.runtest->end_state != TAP_IDLE) - predicted_size += 3; - if (tap_get_end_state() != TAP_IDLE) - predicted_size += 3; - if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) - { - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - require_send = 0; - first_unsent = cmd; - } - if (tap_get_state() != TAP_IDLE) - { - move_to_state(TAP_IDLE); - require_send = 1; - } - i = cmd->cmd.runtest->num_cycles; - while (i > 0) - { - /* there are no state transitions in this code, so omit state tracking */ - - /* command "Clock Data to TMS/CS Pin (no Read)" */ - buffer_write(0x4b); - - /* scan 7 bits */ - buffer_write((i > 7) ? 6 : (i - 1)); - - /* TMS data bits */ - buffer_write(0x0); - - i -= (i > 7) ? 7 : i; - /* LOG_DEBUG("added TMS scan (no read)"); */ - } - - ft2232_end_state(cmd->cmd.runtest->end_state); - - if (tap_get_state() != tap_get_end_state()) - { - move_to_state(tap_get_end_state()); - } - - require_send = 1; - DEBUG_JTAG_IO("runtest: %i, end in %s", - cmd->cmd.runtest->num_cycles, - tap_state_name(tap_get_end_state())); - return retval; -} - -static int ft2232_execute_statemove(struct jtag_command *cmd) -{ - int predicted_size = 0; - int retval = ERROR_OK; - - DEBUG_JTAG_IO("statemove end in %s", - tap_state_name(cmd->cmd.statemove->end_state)); - - /* only send the maximum buffer size that FT2232C can handle */ - predicted_size = 3; - if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) - { - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - require_send = 0; - first_unsent = cmd; - } - ft2232_end_state(cmd->cmd.statemove->end_state); - - /* For TAP_RESET, ignore the current recorded state. It's often - * wrong at server startup, and this transation is critical whenever - * it's requested. - */ - if (tap_get_end_state() == TAP_RESET) { - clock_tms(0x4b, 0xff, 5, 0); - require_send = 1; - - /* shortest-path move to desired end state */ - } else if (tap_get_state() != tap_get_end_state()) - { - move_to_state(tap_get_end_state()); - require_send = 1; - } - - return retval; -} - -static int ft2232_execute_pathmove(struct jtag_command *cmd) -{ - int predicted_size = 0; - int retval = ERROR_OK; - - tap_state_t* path = cmd->cmd.pathmove->path; - int num_states = cmd->cmd.pathmove->num_states; - - DEBUG_JTAG_IO("pathmove: %i states, current: %s end: %s", num_states, - tap_state_name(tap_get_state()), - tap_state_name(path[num_states-1])); - - /* only send the maximum buffer size that FT2232C can handle */ - predicted_size = 3 * DIV_ROUND_UP(num_states, 7); - if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) - { - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - - require_send = 0; - first_unsent = cmd; - } - - ft2232_add_pathmove(path, num_states); - require_send = 1; - - return retval; -} - -static int ft2232_execute_scan(struct jtag_command *cmd) -{ - uint8_t* buffer; - int scan_size; /* size of IR or DR scan */ - int predicted_size = 0; - int retval = ERROR_OK; - - enum scan_type type = jtag_scan_type(cmd->cmd.scan); - - DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", type); - - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - - predicted_size = ft2232_predict_scan_out(scan_size, type); - if ((predicted_size + 1) > FT2232_BUFFER_SIZE) - { - LOG_DEBUG("oversized ft2232 scan (predicted_size > FT2232_BUFFER_SIZE)"); - /* unsent commands before this */ - if (first_unsent != cmd) - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - - /* current command */ - ft2232_end_state(cmd->cmd.scan->end_state); - ft2232_large_scan(cmd->cmd.scan, type, buffer, scan_size); - require_send = 0; - first_unsent = cmd->next; - if (buffer) - free(buffer); - return retval; - } - else if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) - { - LOG_DEBUG("ft2232 buffer size reached, sending queued commands (first_unsent: %p, cmd: %p)", - first_unsent, - cmd); - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - require_send = 0; - first_unsent = cmd; - } - ft2232_expect_read += ft2232_predict_scan_in(scan_size, type); - /* LOG_DEBUG("new read size: %i", ft2232_expect_read); */ - ft2232_end_state(cmd->cmd.scan->end_state); - ft2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - require_send = 1; - if (buffer) - free(buffer); - DEBUG_JTAG_IO("%s scan, %i bits, end in %s", - (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, - tap_state_name(tap_get_end_state())); - return retval; - -} - -static int ft2232_execute_reset(struct jtag_command *cmd) -{ - int retval; - int predicted_size = 0; - retval = ERROR_OK; - - DEBUG_JTAG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); - - /* only send the maximum buffer size that FT2232C can handle */ - predicted_size = 3; - if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) - { - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - require_send = 0; - first_unsent = cmd; - } - - if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) - { - tap_set_state(TAP_RESET); - } - - layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - require_send = 1; - - DEBUG_JTAG_IO("trst: %i, srst: %i", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); - return retval; -} - -static int ft2232_execute_sleep(struct jtag_command *cmd) -{ - int retval; - retval = ERROR_OK; - - DEBUG_JTAG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); - - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - first_unsent = cmd->next; - jtag_sleep(cmd->cmd.sleep->us); - DEBUG_JTAG_IO("sleep %" PRIi32 " usec while in %s", - cmd->cmd.sleep->us, - tap_state_name(tap_get_state())); - return retval; -} - -static int ft2232_execute_stableclocks(struct jtag_command *cmd) -{ - int retval; - retval = ERROR_OK; - - /* this is only allowed while in a stable state. A check for a stable - * state was done in jtag_add_clocks() - */ - if (ft2232_stableclocks(cmd->cmd.stableclocks->num_cycles, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - DEBUG_JTAG_IO("clocks %i while in %s", - cmd->cmd.stableclocks->num_cycles, - tap_state_name(tap_get_state())); - return retval; -} - -static int ft2232_execute_command(struct jtag_command *cmd) -{ - int retval; - retval = ERROR_OK; - - switch (cmd->type) - { - case JTAG_RESET: retval = ft2232_execute_reset(cmd); break; - case JTAG_RUNTEST: retval = ft2232_execute_runtest(cmd); break; - case JTAG_STATEMOVE: retval = ft2232_execute_statemove(cmd); break; - case JTAG_PATHMOVE: retval = ft2232_execute_pathmove(cmd); break; - case JTAG_SCAN: retval = ft2232_execute_scan(cmd); break; - case JTAG_SLEEP: retval = ft2232_execute_sleep(cmd); break; - case JTAG_STABLECLOCKS: retval = ft2232_execute_stableclocks(cmd); break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); - } - return retval; -} - -static int ft2232_execute_queue(void) -{ - struct jtag_command* cmd = jtag_command_queue; /* currently processed command */ - int retval; - - first_unsent = cmd; /* next command that has to be sent */ - require_send = 0; - - /* return ERROR_OK, unless ft2232_send_and_recv reports a failed check - * that wasn't handled by a caller-provided error handler - */ - retval = ERROR_OK; - - ft2232_buffer_size = 0; - ft2232_expect_read = 0; - - /* blink, if the current layout has that feature */ - if (layout->blink) - layout->blink(); - - while (cmd) - { - if (ft2232_execute_command(cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - /* Start reading input before FT2232 TX buffer fills up */ - cmd = cmd->next; - if (ft2232_expect_read > 256) - { - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - first_unsent = cmd; - } - } - - if (require_send > 0) - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - - return retval; -} - -#if BUILD_FT2232_FTD2XX == 1 -static int ft2232_init_ftd2xx(uint16_t vid, uint16_t pid, int more, int* try_more) -{ - FT_STATUS status; - DWORD deviceID; - char SerialNumber[16]; - char Description[64]; - DWORD openex_flags = 0; - char* openex_string = NULL; - uint8_t latency_timer; - - LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", ft2232_layout, vid, pid); - -#if IS_WIN32 == 0 - /* Add non-standard Vid/Pid to the linux driver */ - if ((status = FT_SetVIDPID(vid, pid)) != FT_OK) - { - LOG_WARNING("couldn't add %4.4x:%4.4x", vid, pid); - } -#endif - - if (ft2232_device_desc && ft2232_serial) - { - LOG_WARNING("can't open by device description and serial number, giving precedence to serial"); - ft2232_device_desc = NULL; - } - - if (ft2232_device_desc) - { - openex_string = ft2232_device_desc; - openex_flags = FT_OPEN_BY_DESCRIPTION; - } - else if (ft2232_serial) - { - openex_string = ft2232_serial; - openex_flags = FT_OPEN_BY_SERIAL_NUMBER; - } - else - { - LOG_ERROR("neither device description nor serial number specified"); - LOG_ERROR("please add \"ft2232_device_desc \" or \"ft2232_serial \" to your .cfg file"); - - return ERROR_JTAG_INIT_FAILED; - } - - status = FT_OpenEx(openex_string, openex_flags, &ftdih); - if (status != FT_OK) { - /* under Win32, the FTD2XX driver appends an "A" to the end - * of the description, if we tried by the desc, then - * try by the alternate "A" description. */ - if (openex_string == ft2232_device_desc) { - /* Try the alternate method. */ - openex_string = ft2232_device_desc_A; - status = FT_OpenEx(openex_string, openex_flags, &ftdih); - if (status == FT_OK) { - /* yea, the "alternate" method worked! */ - } else { - /* drat, give the user a meaningfull message. - * telling the use we tried *BOTH* methods. */ - LOG_WARNING("Unable to open FTDI Device tried: '%s' and '%s'\n", - ft2232_device_desc, - ft2232_device_desc_A); - } - } - } - - if (status != FT_OK) - { - DWORD num_devices; - - if (more) - { - LOG_WARNING("unable to open ftdi device (trying more): %lu", status); - *try_more = 1; - return ERROR_JTAG_INIT_FAILED; - } - LOG_ERROR("unable to open ftdi device: %lu", status); - status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY); - if (status == FT_OK) - { - char** desc_array = malloc(sizeof(char*) * (num_devices + 1)); - uint32_t i; - - for (i = 0; i < num_devices; i++) - desc_array[i] = malloc(64); - - desc_array[num_devices] = NULL; - - status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | openex_flags); - - if (status == FT_OK) - { - LOG_ERROR("ListDevices: %lu\n", num_devices); - for (i = 0; i < num_devices; i++) - LOG_ERROR("%" PRIu32 ": \"%s\"", i, desc_array[i]); - } - - for (i = 0; i < num_devices; i++) - free(desc_array[i]); - - free(desc_array); - } - else - { - LOG_ERROR("ListDevices: NONE\n"); - } - return ERROR_JTAG_INIT_FAILED; - } - - if ((status = FT_SetLatencyTimer(ftdih, ft2232_latency)) != FT_OK) - { - LOG_ERROR("unable to set latency timer: %lu", status); - return ERROR_JTAG_INIT_FAILED; - } - - if ((status = FT_GetLatencyTimer(ftdih, &latency_timer)) != FT_OK) - { - LOG_ERROR("unable to get latency timer: %lu", status); - return ERROR_JTAG_INIT_FAILED; - } - else - { - LOG_DEBUG("current latency timer: %i", latency_timer); - } - - if ((status = FT_SetTimeouts(ftdih, 5000, 5000)) != FT_OK) - { - LOG_ERROR("unable to set timeouts: %lu", status); - return ERROR_JTAG_INIT_FAILED; - } - - if ((status = FT_SetBitMode(ftdih, 0x0b, 2)) != FT_OK) - { - LOG_ERROR("unable to enable bit i/o mode: %lu", status); - return ERROR_JTAG_INIT_FAILED; - } - - if ((status = FT_GetDeviceInfo(ftdih, &ftdi_device, &deviceID, SerialNumber, Description, NULL)) != FT_OK) - { - LOG_ERROR("unable to get FT_GetDeviceInfo: %lu", status); - return ERROR_JTAG_INIT_FAILED; - } - else - { - static const char* type_str[] = - {"BM", "AM", "100AX", "UNKNOWN", "2232C", "232R", "2232H", "4232H"}; - unsigned no_of_known_types = ARRAY_SIZE(type_str) - 1; - unsigned type_index = ((unsigned)ftdi_device <= no_of_known_types) - ? ftdi_device : FT_DEVICE_UNKNOWN; - LOG_INFO("device: %lu \"%s\"", ftdi_device, type_str[type_index]); - LOG_INFO("deviceID: %lu", deviceID); - LOG_INFO("SerialNumber: %s", SerialNumber); - LOG_INFO("Description: %s", Description); - } - - return ERROR_OK; -} - -static int ft2232_purge_ftd2xx(void) -{ - FT_STATUS status; - - if ((status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK) - { - LOG_ERROR("error purging ftd2xx device: %lu", status); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -#endif /* BUILD_FT2232_FTD2XX == 1 */ - -#if BUILD_FT2232_LIBFTDI == 1 -static int ft2232_init_libftdi(uint16_t vid, uint16_t pid, int more, int* try_more) -{ - uint8_t latency_timer; - - LOG_DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)", - ft2232_layout, vid, pid); - - if (ftdi_init(&ftdic) < 0) - return ERROR_JTAG_INIT_FAILED; - - if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0) - { - LOG_ERROR("unable to select FT2232 channel A: %s", ftdic.error_str); - return ERROR_JTAG_INIT_FAILED; - } - - /* context, vendor id, product id */ - if (ftdi_usb_open_desc(&ftdic, vid, pid, ft2232_device_desc, - ft2232_serial) < 0) - { - if (more) - LOG_WARNING("unable to open ftdi device (trying more): %s", - ftdic.error_str); - else - LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); - *try_more = 1; - return ERROR_JTAG_INIT_FAILED; - } - - /* There is already a reset in ftdi_usb_open_desc, this should be redundant */ - if (ftdi_usb_reset(&ftdic) < 0) - { - LOG_ERROR("unable to reset ftdi device"); - return ERROR_JTAG_INIT_FAILED; - } - - if (ftdi_set_latency_timer(&ftdic, ft2232_latency) < 0) - { - LOG_ERROR("unable to set latency timer"); - return ERROR_JTAG_INIT_FAILED; - } - - if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) - { - LOG_ERROR("unable to get latency timer"); - return ERROR_JTAG_INIT_FAILED; - } - else - { - LOG_DEBUG("current latency timer: %i", latency_timer); - } - - ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */ - - ftdi_device = ftdic.type; - static const char* type_str[] = - {"AM", "BM", "2232C", "R", "2232H", "4232H", "Unknown"}; - unsigned no_of_known_types = ARRAY_SIZE(type_str) - 1; - unsigned type_index = ((unsigned)ftdi_device < no_of_known_types) - ? ftdi_device : no_of_known_types; - LOG_DEBUG("FTDI chip type: %i \"%s\"", (int)ftdi_device, type_str[type_index]); - return ERROR_OK; -} - -static int ft2232_purge_libftdi(void) -{ - if (ftdi_usb_purge_buffers(&ftdic) < 0) - { - LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -#endif /* BUILD_FT2232_LIBFTDI == 1 */ - -static int ft2232_init(void) -{ - uint8_t buf[1]; - int retval; - uint32_t bytes_written; - const struct ft2232_layout* cur_layout = ft2232_layouts; - int i; - - if (tap_get_tms_path_len(TAP_IRPAUSE,TAP_IRPAUSE) == 7) - { - LOG_DEBUG("ft2232 interface using 7 step jtag state transitions"); - } - else - { - LOG_DEBUG("ft2232 interface using shortest path jtag state transitions"); - - } - if ((ft2232_layout == NULL) || (ft2232_layout[0] == 0)) - { - ft2232_layout = "usbjtag"; - LOG_WARNING("No ft2232 layout specified, using default 'usbjtag'"); - } - - while (cur_layout->name) - { - if (strcmp(cur_layout->name, ft2232_layout) == 0) - { - layout = cur_layout; - break; - } - cur_layout++; - } - - if (!layout) - { - LOG_ERROR("No matching layout found for %s", ft2232_layout); - return ERROR_JTAG_INIT_FAILED; - } - - for (i = 0; 1; i++) - { - /* - * "more indicates that there are more IDs to try, so we should - * not print an error for an ID mismatch (but for anything - * else, we should). - * - * try_more indicates that the error code returned indicates an - * ID mismatch (and nothing else) and that we should proceeed - * with the next ID pair. - */ - int more = ft2232_vid[i + 1] || ft2232_pid[i + 1]; - int try_more = 0; - -#if BUILD_FT2232_FTD2XX == 1 - retval = ft2232_init_ftd2xx(ft2232_vid[i], ft2232_pid[i], - more, &try_more); -#elif BUILD_FT2232_LIBFTDI == 1 - retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i], - more, &try_more); -#endif - if (retval >= 0) - break; - if (!more || !try_more) - return retval; - } - - ft2232_buffer_size = 0; - ft2232_buffer = malloc(FT2232_BUFFER_SIZE); - - if (layout->init() != ERROR_OK) - return ERROR_JTAG_INIT_FAILED; - - if (ft2232_device_is_highspeed()) - { -#ifndef BUILD_FT2232_HIGHSPEED - #if BUILD_FT2232_FTD2XX == 1 - LOG_WARNING("High Speed device found - You need a newer FTD2XX driver (version 2.04.16 or later)"); - #elif BUILD_FT2232_LIBFTDI == 1 - LOG_WARNING("High Speed device found - You need a newer libftdi version (0.16 or later)"); - #endif -#endif - /* make sure the legacy mode is disabled */ - if (ft2232h_ft4232h_clk_divide_by_5(false) != ERROR_OK) - return ERROR_JTAG_INIT_FAILED; - } - - ft2232_speed(jtag_get_speed()); - - buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */ - if (((retval = ft2232_write(buf, 1, &bytes_written)) != ERROR_OK) || (bytes_written != 1)) - { - LOG_ERROR("couldn't write to FT2232 to disable loopback"); - return ERROR_JTAG_INIT_FAILED; - } - -#if BUILD_FT2232_FTD2XX == 1 - return ft2232_purge_ftd2xx(); -#elif BUILD_FT2232_LIBFTDI == 1 - return ft2232_purge_libftdi(); -#endif - - return ERROR_OK; -} - -static int usbjtag_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x0b; - - if (strcmp(ft2232_layout, "usbjtag") == 0) - { - nTRST = 0x10; - nTRSTnOE = 0x10; - nSRST = 0x40; - nSRSTnOE = 0x40; - } - else if (strcmp(ft2232_layout, "signalyzer") == 0) - { - nTRST = 0x10; - nTRSTnOE = 0x10; - nSRST = 0x20; - nSRSTnOE = 0x20; - } - else if (strcmp(ft2232_layout, "evb_lm3s811") == 0) - { - nTRST = 0x0; - nTRSTnOE = 0x00; - nSRST = 0x20; - nSRSTnOE = 0x20; - low_output = 0x88; - low_direction = 0x8b; - } - else if (strcmp(ft2232_layout, "luminary_icdi") == 0) - { - nTRST = 0x0; - nTRSTnOE = 0x00; - nSRST = 0x20; - nSRSTnOE = 0x20; - low_output = 0x88; - low_direction = 0xcb; - } - else - { - LOG_ERROR("BUG: usbjtag_init called for unknown layout '%s'", ft2232_layout); - return ERROR_JTAG_INIT_FAILED; - } - - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - { - low_direction &= ~nTRSTnOE; /* nTRST input */ - low_output &= ~nTRST; /* nTRST = 0 */ - } - else - { - low_direction |= nTRSTnOE; /* nTRST output */ - low_output |= nTRST; /* nTRST = 1 */ - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - { - low_direction |= nSRSTnOE; /* nSRST output */ - low_output |= nSRST; /* nSRST = 1 */ - } - else - { - low_direction &= ~nSRSTnOE; /* nSRST input */ - low_output &= ~nSRST; /* nSRST = 0 */ - } - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, xRST high) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'USBJTAG' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int axm0432_jtag_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x2b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - if (strcmp(layout->name, "axm0432_jtag") == 0) - { - nTRST = 0x08; - nTRSTnOE = 0x0; /* No output enable for TRST*/ - nSRST = 0x04; - nSRSTnOE = 0x0; /* No output enable for SRST*/ - } - else - { - LOG_ERROR("BUG: axm0432_jtag_init called for non axm0432 layout"); - exit(-1); - } - - high_output = 0x0; - high_direction = 0x0c; - - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - { - LOG_ERROR("can't set nTRSTOE to push-pull on the Dicarlo jtag"); - } - else - { - high_output |= nTRST; - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - { - LOG_ERROR("can't set nSRST to push-pull on the Dicarlo jtag"); - } - else - { - high_output |= nSRST; - } - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; /* value */ - buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'Dicarlo' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int jtagkey_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x1b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - if (strcmp(layout->name, "jtagkey") == 0) - { - nTRST = 0x01; - nTRSTnOE = 0x4; - nSRST = 0x02; - nSRSTnOE = 0x08; - } - else if ((strcmp(layout->name, "jtagkey_prototype_v1") == 0) - || (strcmp(layout->name, "oocdlink") == 0)) - { - nTRST = 0x02; - nTRSTnOE = 0x1; - nSRST = 0x08; - nSRSTnOE = 0x04; - } - else - { - LOG_ERROR("BUG: jtagkey_init called for non jtagkey layout"); - exit(-1); - } - - high_output = 0x0; - high_direction = 0x0f; - - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - { - high_output |= nTRSTnOE; - high_output &= ~nTRST; - } - else - { - high_output &= ~nTRSTnOE; - high_output |= nTRST; - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - { - high_output &= ~nSRSTnOE; - high_output |= nSRST; - } - else - { - high_output |= nSRSTnOE; - high_output &= ~nSRST; - } - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; /* value */ - buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int olimex_jtag_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x1b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nTRST = 0x01; - nTRSTnOE = 0x4; - nSRST = 0x02; - nSRSTnOE = 0x00; /* no output enable for nSRST */ - - high_output = 0x0; - high_direction = 0x0f; - - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - { - high_output |= nTRSTnOE; - high_output &= ~nTRST; - } - else - { - high_output &= ~nTRSTnOE; - high_output |= nTRST; - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - { - LOG_ERROR("can't set nSRST to push-pull on the Olimex ARM-USB-OCD"); - } - else - { - high_output &= ~nSRST; - } - - /* turn red LED on */ - high_output |= 0x08; - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; /* value */ - buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int flyswatter_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x18; - low_direction = 0xfb; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE[12]=out, n[ST]srst = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nTRST = 0x10; - nTRSTnOE = 0x0; /* not output enable for nTRST */ - nSRST = 0x20; - nSRSTnOE = 0x00; /* no output enable for nSRST */ - - high_output = 0x00; - high_direction = 0x0c; - - /* turn red LED3 on, LED2 off */ - high_output |= 0x08; - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; /* value */ - buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int turtle_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x5b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nSRST = 0x40; - - high_output = 0x00; - high_direction = 0x0C; - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; - buf[2] = high_direction; - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int comstick_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x0b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nTRST = 0x01; - nTRSTnOE = 0x00; /* no output enable for nTRST */ - nSRST = 0x02; - nSRSTnOE = 0x00; /* no output enable for nSRST */ - - high_output = 0x03; - high_direction = 0x03; - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; - buf[2] = high_direction; - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int stm32stick_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x88; - low_direction = 0x8b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nTRST = 0x01; - nTRSTnOE = 0x00; /* no output enable for nTRST */ - nSRST = 0x80; - nSRSTnOE = 0x00; /* no output enable for nSRST */ - - high_output = 0x01; - high_direction = 0x03; - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; - buf[2] = high_direction; - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int sheevaplug_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x1b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nTRSTnOE = 0x1; - nTRST = 0x02; - nSRSTnOE = 0x4; - nSRST = 0x08; - - high_output = 0x0; - high_direction = 0x0f; - - /* nTRST is always push-pull */ - high_output &= ~nTRSTnOE; - high_output |= nTRST; - - /* nSRST is always open-drain */ - high_output |= nSRSTnOE; - high_output &= ~nSRST; - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; /* value */ - buf[2] = high_direction; /* all outputs - xRST */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static int cortino_jtag_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - - low_output = 0x08; - low_direction = 0x1b; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; /* value (TMS = 1,TCK = 0, TDI = 0, nOE = 0) */ - buf[2] = low_direction; /* dir (output = 1), TCK/TDI/TMS = out, TDO = in, nOE = out */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'cortino' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nTRST = 0x01; - nTRSTnOE = 0x00; /* no output enable for nTRST */ - nSRST = 0x02; - nSRSTnOE = 0x00; /* no output enable for nSRST */ - - high_output = 0x03; - high_direction = 0x03; - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; - buf[2] = high_direction; - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static void olimex_jtag_blink(void) -{ - /* Olimex ARM-USB-OCD has a LED connected to ACBUS3 - * ACBUS3 is bit 3 of the GPIOH port - */ - if (high_output & 0x08) - { - /* set port pin high */ - high_output &= 0x07; - } - else - { - /* set port pin low */ - high_output |= 0x08; - } - - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); -} - -static void flyswatter_jtag_blink(void) -{ - /* - * Flyswatter has two LEDs connected to ACBUS2 and ACBUS3 - */ - high_output ^= 0x0c; - - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); -} - -static void turtle_jtag_blink(void) -{ - /* - * Turtelizer2 has two LEDs connected to ACBUS2 and ACBUS3 - */ - if (high_output & 0x08) - { - high_output = 0x04; - } - else - { - high_output = 0x08; - } - - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); -} - -static int ft2232_quit(void) -{ -#if BUILD_FT2232_FTD2XX == 1 - FT_STATUS status; - - status = FT_Close(ftdih); -#elif BUILD_FT2232_LIBFTDI == 1 - ftdi_usb_close(&ftdic); - - ftdi_deinit(&ftdic); -#endif - - free(ft2232_buffer); - ft2232_buffer = NULL; - - return ERROR_OK; -} - -COMMAND_HANDLER(ft2232_handle_device_desc_command) -{ - char *cp; - char buf[200]; - if (CMD_ARGC == 1) - { - ft2232_device_desc = strdup(CMD_ARGV[0]); - cp = strchr(ft2232_device_desc, 0); - /* under Win32, the FTD2XX driver appends an "A" to the end - * of the description, this examines the given desc - * and creates the 'missing' _A or non_A variable. */ - if ((cp[-1] == 'A') && (cp[-2]==' ')) { - /* it was, so make this the "A" version. */ - ft2232_device_desc_A = ft2232_device_desc; - /* and *CREATE* the non-A version. */ - strcpy(buf, ft2232_device_desc); - cp = strchr(buf, 0); - cp[-2] = 0; - ft2232_device_desc = strdup(buf); - } else { - /* A not defined - * so create it */ - sprintf(buf, "%s A", ft2232_device_desc); - ft2232_device_desc_A = strdup(buf); - } - } - else - { - LOG_ERROR("expected exactly one argument to ft2232_device_desc "); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(ft2232_handle_serial_command) -{ - if (CMD_ARGC == 1) - { - ft2232_serial = strdup(CMD_ARGV[0]); - } - else - { - LOG_ERROR("expected exactly one argument to ft2232_serial "); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(ft2232_handle_layout_command) -{ - if (CMD_ARGC == 0) - return ERROR_OK; - - ft2232_layout = malloc(strlen(CMD_ARGV[0]) + 1); - strcpy(ft2232_layout, CMD_ARGV[0]); - - return ERROR_OK; -} - -COMMAND_HANDLER(ft2232_handle_vid_pid_command) -{ - if (CMD_ARGC > MAX_USB_IDS * 2) - { - LOG_WARNING("ignoring extra IDs in ft2232_vid_pid " - "(maximum is %d pairs)", MAX_USB_IDS); - CMD_ARGC = MAX_USB_IDS * 2; - } - if (CMD_ARGC < 2 || (CMD_ARGC & 1)) - { - LOG_WARNING("incomplete ft2232_vid_pid configuration directive"); - if (CMD_ARGC < 2) - return ERROR_COMMAND_SYNTAX_ERROR; - /* remove the incomplete trailing id */ - CMD_ARGC -= 1; - } - - unsigned i; - for (i = 0; i < CMD_ARGC; i += 2) - { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], ft2232_vid[i >> 1]); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], ft2232_pid[i >> 1]); - } - - /* - * Explicitly terminate, in case there are multiples instances of - * ft2232_vid_pid. - */ - ft2232_vid[i >> 1] = ft2232_pid[i >> 1] = 0; - - return ERROR_OK; -} - -COMMAND_HANDLER(ft2232_handle_latency_command) -{ - if (CMD_ARGC == 1) - { - ft2232_latency = atoi(CMD_ARGV[0]); - } - else - { - LOG_ERROR("expected exactly one argument to ft2232_latency "); - } - - return ERROR_OK; -} - -static int ft2232_stableclocks(int num_cycles, struct jtag_command* cmd) -{ - int retval = 0; - - /* 7 bits of either ones or zeros. */ - uint8_t tms = (tap_get_state() == TAP_RESET ? 0x7F : 0x00); - - while (num_cycles > 0) - { - /* the command 0x4b, "Clock Data to TMS/CS Pin (no Read)" handles - * at most 7 bits per invocation. Here we invoke it potentially - * several times. - */ - int bitcount_per_command = (num_cycles > 7) ? 7 : num_cycles; - - if (ft2232_buffer_size + 3 >= FT2232_BUFFER_SIZE) - { - if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - - first_unsent = cmd; - } - - /* there are no state transitions in this code, so omit state tracking */ - - /* command "Clock Data to TMS/CS Pin (no Read)" */ - buffer_write(0x4b); - - /* scan 7 bit */ - buffer_write(bitcount_per_command - 1); - - /* TMS data bits are either all zeros or ones to stay in the current stable state */ - buffer_write(tms); - - require_send = 1; - - num_cycles -= bitcount_per_command; - } - - return retval; -} - -/* --------------------------------------------------------------------- - * Support for IceBear JTAG adapter from Section5: - * http://section5.ch/icebear - * - * Author: Sten, debian@sansys-electronic.com - */ - -/* Icebear pin layout - * - * ADBUS5 (nEMU) nSRST | 2 1| GND (10k->VCC) - * GND GND | 4 3| n.c. - * ADBUS3 TMS | 6 5| ADBUS6 VCC - * ADBUS0 TCK | 8 7| ADBUS7 (GND) - * ADBUS4 nTRST |10 9| ACBUS0 (GND) - * ADBUS1 TDI |12 11| ACBUS1 (GND) - * ADBUS2 TDO |14 13| GND GND - * - * ADBUS0 O L TCK ACBUS0 GND - * ADBUS1 O L TDI ACBUS1 GND - * ADBUS2 I TDO ACBUS2 n.c. - * ADBUS3 O H TMS ACBUS3 n.c. - * ADBUS4 O H nTRST - * ADBUS5 O H nSRST - * ADBUS6 - VCC - * ADBUS7 - GND - */ -static int icebear_jtag_init(void) { - uint8_t buf[3]; - uint32_t bytes_written; - - low_direction = 0x0b; /* output: TCK TDI TMS; input: TDO */ - low_output = 0x08; /* high: TMS; low: TCK TDI */ - nTRST = 0x10; - nSRST = 0x20; - - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if ((jtag_reset_config & RESET_TRST_OPEN_DRAIN) != 0) { - low_direction &= ~nTRST; /* nTRST high impedance */ - } - else { - low_direction |= nTRST; - low_output |= nTRST; - } - - low_direction |= nSRST; - low_output |= nSRST; - - /* initialize low byte for jtag */ - buf[0] = 0x80; /* command "set data bits low byte" */ - buf[1] = low_output; - buf[2] = low_direction; - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) { - LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (low)"); - return ERROR_JTAG_INIT_FAILED; - } - - high_output = 0x0; - high_direction = 0x00; - - - /* initialize high port */ - buf[0] = 0x82; /* command "set data bits high byte" */ - buf[1] = high_output; /* value */ - buf[2] = high_direction; /* all outputs (xRST and xRSTnOE) */ - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) { - LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (high)"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static void icebear_jtag_reset(int trst, int srst) { - - if (trst == 1) { - low_direction |= nTRST; - low_output &= ~nTRST; - } - else if (trst == 0) { - enum reset_types jtag_reset_config = jtag_get_reset_config(); - if ((jtag_reset_config & RESET_TRST_OPEN_DRAIN) != 0) - low_direction &= ~nTRST; - else - low_output |= nTRST; - } - - if (srst == 1) { - low_output &= ~nSRST; - } - else if (srst == 0) { - low_output |= nSRST; - } - - /* command "set data bits low byte" */ - buffer_write(0x80); - buffer_write(low_output); - buffer_write(low_direction); - - LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); -} - -/* --------------------------------------------------------------------- - * Support for Signalyzer H2 and Signalyzer H4 - * JTAG adapter from Xverve Technologies Inc. - * http://www.signalyzer.com or http://www.xverve.com - * - * Author: Oleg Seiljus, oleg@signalyzer.com - */ -static unsigned char signalyzer_h_side; -static unsigned int signalyzer_h_adapter_type; - -static int signalyzer_h_ctrl_write(int address, unsigned short value); - -#if BUILD_FT2232_FTD2XX == 1 -static int signalyzer_h_ctrl_read(int address, unsigned short *value); -#endif - -#define SIGNALYZER_COMMAND_ADDR 128 -#define SIGNALYZER_DATA_BUFFER_ADDR 129 - -#define SIGNALYZER_COMMAND_VERSION 0x41 -#define SIGNALYZER_COMMAND_RESET 0x42 -#define SIGNALYZER_COMMAND_POWERCONTROL_GET 0x50 -#define SIGNALYZER_COMMAND_POWERCONTROL_SET 0x51 -#define SIGNALYZER_COMMAND_PWM_SET 0x52 -#define SIGNALYZER_COMMAND_LED_SET 0x53 -#define SIGNALYZER_COMMAND_ADC 0x54 -#define SIGNALYZER_COMMAND_GPIO_STATE 0x55 -#define SIGNALYZER_COMMAND_GPIO_MODE 0x56 -#define SIGNALYZER_COMMAND_GPIO_PORT 0x57 -#define SIGNALYZER_COMMAND_I2C 0x58 - -#define SIGNALYZER_CHAN_A 1 -#define SIGNALYZER_CHAN_B 2 -/* LEDS use channel C */ -#define SIGNALYZER_CHAN_C 4 - -#define SIGNALYZER_LED_GREEN 1 -#define SIGNALYZER_LED_RED 2 - -#define SIGNALYZER_MODULE_TYPE_EM_LT16_A 0x0301 -#define SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG 0x0302 -#define SIGNALYZER_MODULE_TYPE_EM_JTAG 0x0303 -#define SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P 0x0304 -#define SIGNALYZER_MODULE_TYPE_EM_JTAG_P 0x0305 - - -static int signalyzer_h_ctrl_write(int address, unsigned short value) -{ -#if BUILD_FT2232_FTD2XX == 1 - return FT_WriteEE(ftdih, address, value); -#elif BUILD_FT2232_LIBFTDI == 1 - return 0; -#endif -} - -#if BUILD_FT2232_FTD2XX == 1 -static int signalyzer_h_ctrl_read(int address, unsigned short *value) -{ - return FT_ReadEE(ftdih, address, value); -} -#endif - -static int signalyzer_h_led_set(unsigned char channel, unsigned char led, - int on_time_ms, int off_time_ms, unsigned char cycles) -{ - unsigned char on_time; - unsigned char off_time; - - if (on_time_ms < 0xFFFF) - on_time = (unsigned char)(on_time_ms / 62); - else - on_time = 0xFF; - - off_time = (unsigned char)(off_time_ms / 62); - -#if BUILD_FT2232_FTD2XX == 1 - FT_STATUS status; - - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, - ((uint32_t)(channel << 8) | led))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - (SIGNALYZER_DATA_BUFFER_ADDR + 1), - ((uint32_t)(on_time << 8) | off_time))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - (SIGNALYZER_DATA_BUFFER_ADDR + 2), - ((uint32_t)cycles))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_LED_SET)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -#elif BUILD_FT2232_LIBFTDI == 1 - int retval; - - if ((retval = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, - ((uint32_t)(channel << 8) | led))) < 0) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %s", - ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((retval = signalyzer_h_ctrl_write( - (SIGNALYZER_DATA_BUFFER_ADDR + 1), - ((uint32_t)(on_time << 8) | off_time))) < 0) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %s", - ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((retval = signalyzer_h_ctrl_write( - (SIGNALYZER_DATA_BUFFER_ADDR + 2), - (uint32_t)cycles)) < 0) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %s", - ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((retval = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_LED_SET)) < 0) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %s", - ftdi_get_error_string(&ftdic)); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -#endif -} - -static int signalyzer_h_init(void) -{ -#if BUILD_FT2232_FTD2XX == 1 - FT_STATUS status; - int i; -#endif - - char *end_of_desc; - - uint16_t read_buf[12] = { 0 }; - uint8_t buf[3]; - uint32_t bytes_written; - - /* turn on center green led */ - signalyzer_h_led_set(SIGNALYZER_CHAN_C, SIGNALYZER_LED_GREEN, - 0xFFFF, 0x00, 0x00); - - /* determine what channel config wants to open - * TODO: change me... current implementation is made to work - * with openocd description parsing. - */ - end_of_desc = strrchr(ft2232_device_desc, 0x00); - - if (end_of_desc) - { - signalyzer_h_side = *(end_of_desc - 1); - if (signalyzer_h_side == 'B') - signalyzer_h_side = SIGNALYZER_CHAN_B; - else - signalyzer_h_side = SIGNALYZER_CHAN_A; - } - else - { - LOG_ERROR("No Channel was specified"); - return ERROR_FAIL; - } - - signalyzer_h_led_set(signalyzer_h_side, SIGNALYZER_LED_GREEN, - 1000, 1000, 0xFF); - -#if BUILD_FT2232_FTD2XX == 1 - /* read signalyzer versionining information */ - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_VERSION)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - for (i = 0; i < 10; i++) - { - if ((status = signalyzer_h_ctrl_read( - (SIGNALYZER_DATA_BUFFER_ADDR + i), - &read_buf[i])) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_read returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - LOG_INFO("Signalyzer: ID info: { %.4x %.4x %.4x %.4x %.4x %.4x %.4x }", - read_buf[0], read_buf[1], read_buf[2], read_buf[3], - read_buf[4], read_buf[5], read_buf[6]); - - /* set gpio register */ - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, - (uint32_t)(signalyzer_h_side << 8))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR + 1, - 0x0404)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_GPIO_STATE)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - /* read adapter type information */ - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, - ((uint32_t)(signalyzer_h_side << 8) | 0x01))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - (SIGNALYZER_DATA_BUFFER_ADDR + 1), 0xA000)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - (SIGNALYZER_DATA_BUFFER_ADDR + 2), 0x0008)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_I2C)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - usleep(100000); - - if ((status = signalyzer_h_ctrl_read(SIGNALYZER_COMMAND_ADDR, - &read_buf[0])) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_read returned: %lu", status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if (read_buf[0] != 0x0498) - signalyzer_h_adapter_type = 0x0000; - else - { - for (i = 0; i < 4; i++) - { - if ((status = signalyzer_h_ctrl_read( - (SIGNALYZER_DATA_BUFFER_ADDR + i), - &read_buf[i])) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_read returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - signalyzer_h_adapter_type = read_buf[0]; - } - -#elif BUILD_FT2232_LIBFTDI == 1 - /* currently libftdi does not allow reading individual eeprom - * locations, therefore adapter type cannot be detected. - * override with most common type - */ - signalyzer_h_adapter_type = SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG; -#endif - - enum reset_types jtag_reset_config = jtag_get_reset_config(); - - /* ADAPTOR: EM_LT16_A */ - if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_LT16_A) - { - LOG_INFO("Signalyzer: EM-LT (16-channel level translator) " - "detected. (HW: %2x).", (read_buf[1] >> 8)); - - nTRST = 0x10; - nTRSTnOE = 0x10; - nSRST = 0x20; - nSRSTnOE = 0x20; - - low_output = 0x08; - low_direction = 0x1b; - - high_output = 0x0; - high_direction = 0x0; - - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - { - low_direction &= ~nTRSTnOE; /* nTRST input */ - low_output &= ~nTRST; /* nTRST = 0 */ - } - else - { - low_direction |= nTRSTnOE; /* nTRST output */ - low_output |= nTRST; /* nTRST = 1 */ - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - { - low_direction |= nSRSTnOE; /* nSRST output */ - low_output |= nSRST; /* nSRST = 1 */ - } - else - { - low_direction &= ~nSRSTnOE; /* nSRST input */ - low_output &= ~nSRST; /* nSRST = 0 */ - } - -#if BUILD_FT2232_FTD2XX == 1 - /* enable power to the module */ - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR, - ((uint32_t)(signalyzer_h_side << 8) | 0x01))) - != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_POWERCONTROL_SET)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - /* set gpio mode register */ - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR, - (uint32_t)(signalyzer_h_side << 8))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0000)) - != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_GPIO_MODE)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - /* set gpio register */ - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR, - (uint32_t)(signalyzer_h_side << 8))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x4040)) - != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_GPIO_STATE)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } -#endif - } - - /* ADAPTOR: EM_ARM_JTAG, EM_ARM_JTAG_P, EM_JTAG, EM_JTAG_P */ - else if ((signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) || - (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) || - (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG) || - (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG_P)) - { - if (signalyzer_h_adapter_type - == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) - LOG_INFO("Signalyzer: EM-ARM-JTAG (ARM JTAG) " - "detected. (HW: %2x).", (read_buf[1] >> 8)); - else if (signalyzer_h_adapter_type - == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) - LOG_INFO("Signalyzer: EM-ARM-JTAG_P " - "(ARM JTAG with PSU) detected. (HW: %2x).", - (read_buf[1] >> 8)); - else if (signalyzer_h_adapter_type - == SIGNALYZER_MODULE_TYPE_EM_JTAG) - LOG_INFO("Signalyzer: EM-JTAG (Generic JTAG) " - "detected. (HW: %2x).", (read_buf[1] >> 8)); - else if (signalyzer_h_adapter_type - == SIGNALYZER_MODULE_TYPE_EM_JTAG_P) - LOG_INFO("Signalyzer: EM-JTAG-P " - "(Generic JTAG with PSU) detected. (HW: %2x).", - (read_buf[1] >> 8)); - - nTRST = 0x02; - nTRSTnOE = 0x04; - nSRST = 0x08; - nSRSTnOE = 0x10; - - low_output = 0x08; - low_direction = 0x1b; - - high_output = 0x0; - high_direction = 0x1f; - - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - { - high_output |= nTRSTnOE; - high_output &= ~nTRST; - } - else - { - high_output &= ~nTRSTnOE; - high_output |= nTRST; - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - { - high_output &= ~nSRSTnOE; - high_output |= nSRST; - } - else - { - high_output |= nSRSTnOE; - high_output &= ~nSRST; - } - -#if BUILD_FT2232_FTD2XX == 1 - /* enable power to the module */ - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR, - ((uint32_t)(signalyzer_h_side << 8) | 0x01))) - != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_POWERCONTROL_SET)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - /* set gpio mode register (IO_16 and IO_17 set as analog - * inputs, other is gpio) - */ - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR, - (uint32_t)(signalyzer_h_side << 8))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0060)) - != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_GPIO_MODE)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - /* set gpio register (all inputs, for -P modules, - * PSU will be turned off) - */ - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR, - (uint32_t)(signalyzer_h_side << 8))) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0000)) - != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } - - if ((status = signalyzer_h_ctrl_write( - SIGNALYZER_COMMAND_ADDR, - SIGNALYZER_COMMAND_GPIO_STATE)) != FT_OK) - { - LOG_ERROR("signalyzer_h_ctrl_write returned: %lu", - status); - return ERROR_JTAG_DEVICE_ERROR; - } -#endif - } - - else if (signalyzer_h_adapter_type == 0x0000) - { - LOG_INFO("Signalyzer: No external modules were detected."); - - nTRST = 0x10; - nTRSTnOE = 0x10; - nSRST = 0x20; - nSRSTnOE = 0x20; - - low_output = 0x08; - low_direction = 0x1b; - - high_output = 0x0; - high_direction = 0x0; - - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - { - low_direction &= ~nTRSTnOE; /* nTRST input */ - low_output &= ~nTRST; /* nTRST = 0 */ - } - else - { - low_direction |= nTRSTnOE; /* nTRST output */ - low_output |= nTRST; /* nTRST = 1 */ - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - { - low_direction |= nSRSTnOE; /* nSRST output */ - low_output |= nSRST; /* nSRST = 1 */ - } - else - { - low_direction &= ~nSRSTnOE; /* nSRST input */ - low_output &= ~nSRST; /* nSRST = 0 */ - } - } - else - { - LOG_ERROR("Unknown module type is detected: %.4x", - signalyzer_h_adapter_type); - return ERROR_JTAG_DEVICE_ERROR; - } - - /* initialize low byte of controller for jtag operation */ - buf[0] = 0x80; - buf[1] = low_output; - buf[2] = low_direction; - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) - || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize Signalyzer-H layout"); - return ERROR_JTAG_INIT_FAILED; - } - -#if BUILD_FT2232_FTD2XX == 1 - if (ftdi_device == FT_DEVICE_2232H) - { - /* initialize high byte of controller for jtag operation */ - buf[0] = 0x82; - buf[1] = high_output; - buf[2] = high_direction; - - if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK) - || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize Signalyzer-H layout"); - return ERROR_JTAG_INIT_FAILED; - } - } -#elif BUILD_FT2232_LIBFTDI == 1 - if (ftdi_device == TYPE_2232H) - { - /* initialize high byte of controller for jtag operation */ - buf[0] = 0x82; - buf[1] = high_output; - buf[2] = high_direction; - - if ((ft2232_write(buf, 3, &bytes_written) != ERROR_OK) - || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize Signalyzer-H layout"); - return ERROR_JTAG_INIT_FAILED; - } - } -#endif - return ERROR_OK; -} - -static void signalyzer_h_reset(int trst, int srst) -{ - enum reset_types jtag_reset_config = jtag_get_reset_config(); - - /* ADAPTOR: EM_LT16_A */ - if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_LT16_A) - { - if (trst == 1) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - /* switch to output pin (output is low) */ - low_direction |= nTRSTnOE; - else - /* switch output low */ - low_output &= ~nTRST; - } - else if (trst == 0) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - /* switch to input pin (high-Z + internal - * and external pullup) */ - low_direction &= ~nTRSTnOE; - else - /* switch output high */ - low_output |= nTRST; - } - - if (srst == 1) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - /* switch output low */ - low_output &= ~nSRST; - else - /* switch to output pin (output is low) */ - low_direction |= nSRSTnOE; - } - else if (srst == 0) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - /* switch output high */ - low_output |= nSRST; - else - /* switch to input pin (high-Z) */ - low_direction &= ~nSRSTnOE; - } - - /* command "set data bits low byte" */ - buffer_write(0x80); - buffer_write(low_output); - buffer_write(low_direction); - LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, " - "low_direction: 0x%2.2x", - trst, srst, low_output, low_direction); - } - /* ADAPTOR: EM_ARM_JTAG, EM_ARM_JTAG_P, EM_JTAG, EM_JTAG_P */ - else if ((signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) || - (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) || - (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG) || - (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG_P)) - { - if (trst == 1) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output &= ~nTRSTnOE; - else - high_output &= ~nTRST; - } - else if (trst == 0) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output |= nTRSTnOE; - else - high_output |= nTRST; - } - - if (srst == 1) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - high_output &= ~nSRST; - else - high_output &= ~nSRSTnOE; - } - else if (srst == 0) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - high_output |= nSRST; - else - high_output |= nSRSTnOE; - } - - /* command "set data bits high byte" */ - buffer_write(0x82); - buffer_write(high_output); - buffer_write(high_direction); - LOG_INFO("trst: %i, srst: %i, high_output: 0x%2.2x, " - "high_direction: 0x%2.2x", - trst, srst, high_output, high_direction); - } - else if (signalyzer_h_adapter_type == 0x0000) - { - if (trst == 1) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - /* switch to output pin (output is low) */ - low_direction |= nTRSTnOE; - else - /* switch output low */ - low_output &= ~nTRST; - } - else if (trst == 0) - { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - /* switch to input pin (high-Z + internal - * and external pullup) */ - low_direction &= ~nTRSTnOE; - else - /* switch output high */ - low_output |= nTRST; - } - - if (srst == 1) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - /* switch output low */ - low_output &= ~nSRST; - else - /* switch to output pin (output is low) */ - low_direction |= nSRSTnOE; - } - else if (srst == 0) - { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - /* switch output high */ - low_output |= nSRST; - else - /* switch to input pin (high-Z) */ - low_direction &= ~nSRSTnOE; - } - - /* command "set data bits low byte" */ - buffer_write(0x80); - buffer_write(low_output); - buffer_write(low_direction); - LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, " - "low_direction: 0x%2.2x", - trst, srst, low_output, low_direction); - } -} - -static void signalyzer_h_blink(void) -{ - signalyzer_h_led_set(signalyzer_h_side, SIGNALYZER_LED_RED, 100, 0, 1); -} - -/******************************************************************** - * Support for KT-LINK - * JTAG adapter from KRISTECH - * http://www.kristech.eu - *******************************************************************/ -static int ktlink_init(void) -{ - uint8_t buf[3]; - uint32_t bytes_written; - uint8_t swd_en = 0x20; //0x20 SWD disable, 0x00 SWD enable (ADBUS5) - - low_output = 0x08 | swd_en; // value; TMS=1,TCK=0,TDI=0,SWD=swd_en - low_direction = 0x3B; // out=1; TCK/TDI/TMS=out,TDO=in,SWD=out,RTCK=in,SRSTIN=in - - // initialize low port - buf[0] = 0x80; // command "set data bits low byte" - buf[1] = low_output; - buf[2] = low_direction; - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - nTRST = 0x01; - nSRST = 0x02; - nTRSTnOE = 0x04; - nSRSTnOE = 0x08; - - high_output = 0x80; // turn LED on - high_direction = 0xFF; // all outputs - - enum reset_types jtag_reset_config = jtag_get_reset_config(); - - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { - high_output |= nTRSTnOE; - high_output &= ~nTRST; - } else { - high_output &= ~nTRSTnOE; - high_output |= nTRST; - } - - if (jtag_reset_config & RESET_SRST_PUSH_PULL) { - high_output &= ~nSRSTnOE; - high_output |= nSRST; - } else { - high_output |= nSRSTnOE; - high_output &= ~nSRST; - } - - // initialize high port - buf[0] = 0x82; // command "set data bits high byte" - buf[1] = high_output; // value - buf[2] = high_direction; - LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); - - if (((ft2232_write(buf, 3, &bytes_written)) != ERROR_OK) || (bytes_written != 3)) - { - LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout"); - return ERROR_JTAG_INIT_FAILED; - } - - return ERROR_OK; -} - -static void ktlink_reset(int trst, int srst) -{ - enum reset_types jtag_reset_config = jtag_get_reset_config(); - - if (trst == 1) { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output &= ~nTRSTnOE; - else - high_output &= ~nTRST; - } else if (trst == 0) { - if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) - high_output |= nTRSTnOE; - else - high_output |= nTRST; - } - - if (srst == 1) { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - high_output &= ~nSRST; - else - high_output &= ~nSRSTnOE; - } else if (srst == 0) { - if (jtag_reset_config & RESET_SRST_PUSH_PULL) - high_output |= nSRST; - else - high_output |= nSRSTnOE; - } - - buffer_write(0x82); // command "set data bits high byte" - buffer_write(high_output); - buffer_write(high_direction); - LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output,high_direction); -} - -static void ktlink_blink(void) -{ - /* LED connected to ACBUS7 */ - if (high_output & 0x80) - high_output &= 0x7F; - else - high_output |= 0x80; - - buffer_write(0x82); // command "set data bits high byte" - buffer_write(high_output); - buffer_write(high_direction); -} - -static const struct command_registration ft2232_command_handlers[] = { - { - .name = "ft2232_device_desc", - .handler = &ft2232_handle_device_desc_command, - .mode = COMMAND_CONFIG, - .help = "set the USB device description of the FTDI FT2232 device", - .usage = "", - }, - { - .name = "ft2232_serial", - .handler = &ft2232_handle_serial_command, - .mode = COMMAND_CONFIG, - .help = "set the serial number of the FTDI FT2232 device", - .usage = "", - }, - { - .name = "ft2232_layout", - .handler = &ft2232_handle_layout_command, - .mode = COMMAND_CONFIG, - .help = "set the layout of the FT2232 GPIO signals used " - "to control output-enables and reset signals", - .usage = "", - }, - { - .name = "ft2232_vid_pid", - .handler = &ft2232_handle_vid_pid_command, - .mode = COMMAND_CONFIG, - .help = "the vendor ID and product ID of the FTDI FT2232 device", - .usage = " [...]", - }, - { - .name = "ft2232_latency", - .handler = &ft2232_handle_latency_command, - .mode = COMMAND_CONFIG, - .help = "set the FT2232 latency timer to a new value", - .usage = " [...]", - }, - COMMAND_REGISTRATION_DONE -}; - -struct jtag_interface ft2232_interface = { - .name = "ft2232", - .commands = ft2232_command_handlers, - .init = &ft2232_init, - .quit = &ft2232_quit, - .speed = &ft2232_speed, - .speed_div = &ft2232_speed_div, - .khz = &ft2232_khz, - .execute_queue = &ft2232_execute_queue, - }; diff --git a/src/jtag/gw16012.c b/src/jtag/gw16012.c deleted file mode 100644 index b827fd53..00000000 --- a/src/jtag/gw16012.c +++ /dev/null @@ -1,583 +0,0 @@ -/*************************************************************************** - * 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 -#include -#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 -#include -#define PPRSTATUS PPIGSTATUS -#define PPWDATA PPISDATA -#else -#include -#include -#endif -#include -#include -#else /* not PARPORT_USE_PPDEV */ -#ifndef _WIN32 -#include -#endif -#endif - -#if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 -#include -#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 = "", - }, - 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, - }; diff --git a/src/jtag/jlink.c b/src/jtag/jlink.c deleted file mode 100644 index 9b2326bd..00000000 --- a/src/jtag/jlink.c +++ /dev/null @@ -1,1085 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Juergen Stuber * - * based on Dominic Rath's and Benedikt Sauter's usbprog.c * - * * - * Copyright (C) 2008 by Spencer Oliver * - * spen@spen-soft.co.uk * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 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_common.h" - - -#define VID 0x1366 -#define PID 0x0101 - -#define JLINK_WRITE_ENDPOINT 0x02 -#define JLINK_READ_ENDPOINT 0x81 - -static unsigned int jlink_write_ep = JLINK_WRITE_ENDPOINT; -static unsigned int jlink_read_ep = JLINK_READ_ENDPOINT; -static unsigned int jlink_hw_jtag_version = 2; - -#define JLINK_USB_TIMEOUT 1000 - -// See Section 1.3.2 of the Segger JLink USB protocol manual -/* 2048 is the max value we can use here */ -//#define JLINK_TAP_BUFFER_SIZE 2048 -#define JLINK_TAP_BUFFER_SIZE 256 -//#define JLINK_TAP_BUFFER_SIZE 384 - -#define JLINK_IN_BUFFER_SIZE 2048 -#define JLINK_OUT_BUFFER_SIZE 2*2048 + 4 -#define JLINK_EMU_RESULT_BUFFER_SIZE 64 - -/* Global USB buffers */ -static uint8_t usb_in_buffer[JLINK_IN_BUFFER_SIZE]; -static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; -static uint8_t usb_emu_result_buffer[JLINK_EMU_RESULT_BUFFER_SIZE]; - -/* Constants for JLink command */ -#define EMU_CMD_VERSION 0x01 -#define EMU_CMD_SET_SPEED 0x05 -#define EMU_CMD_GET_STATE 0x07 -#define EMU_CMD_HW_CLOCK 0xc8 -#define EMU_CMD_HW_TMS0 0xc9 -#define EMU_CMD_HW_TMS1 0xca -#define EMU_CMD_HW_JTAG2 0xce -#define EMU_CMD_HW_JTAG3 0xcf -#define EMU_CMD_GET_MAX_MEM_BLOCK 0xd4 -#define EMU_CMD_HW_RESET0 0xdc -#define EMU_CMD_HW_RESET1 0xdd -#define EMU_CMD_HW_TRST0 0xde -#define EMU_CMD_HW_TRST1 0xdf -#define EMU_CMD_GET_CAPS 0xe8 -#define EMU_CMD_GET_HW_VERSION 0xf0 - -/* bits return from EMU_CMD_GET_CAPS */ -#define EMU_CAP_GET_HW_VERSION 1 -#define EMU_CAP_GET_MAX_BLOCK_SIZE 11 - -/* max speed 12MHz v5.0 jlink */ -#define JLINK_MAX_SPEED 12000 - -/* Queue command functions */ -static void jlink_end_state(tap_state_t state); -static void jlink_state_move(void); -static void jlink_path_move(int num_states, tap_state_t *path); -static void jlink_runtest(int num_cycles); -static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); -static void jlink_reset(int trst, int srst); -static void jlink_simple_command(uint8_t command); -static int jlink_get_status(void); - -/* J-Link tap buffer functions */ -static void jlink_tap_init(void); -static int jlink_tap_execute(void); -static void jlink_tap_ensure_space(int scans, int bits); -static void jlink_tap_append_step(int tms, int tdi); -static void jlink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); - -/* Jlink lowlevel functions */ -struct jlink { - struct usb_dev_handle* usb_handle; -}; - -static struct jlink *jlink_usb_open(void); -static void jlink_usb_close(struct jlink *jlink); -static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length); -static int jlink_usb_write(struct jlink *jlink, int out_length); -static int jlink_usb_read(struct jlink *jlink, int expected_size); -static int jlink_usb_read_emu_result(struct jlink *jlink); - -/* helper functions */ -static int jlink_get_version_info(void); - -#ifdef _DEBUG_USB_COMMS_ -static void jlink_debug_buffer(uint8_t *buffer, int length); -#endif - -static enum tap_state jlink_last_state = TAP_RESET; - -static struct jlink* jlink_handle; - -/***************************************************************************/ -/* External interface implementation */ - -static void jlink_execute_runtest(struct jtag_command *cmd) -{ - DEBUG_JTAG_IO("runtest %i cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - - jlink_end_state(cmd->cmd.runtest->end_state); - - jlink_runtest(cmd->cmd.runtest->num_cycles); -} - -static void jlink_execute_statemove(struct jtag_command *cmd) -{ - DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - - jlink_end_state(cmd->cmd.statemove->end_state); - jlink_state_move(); -} - -static void jlink_execute_pathmove(struct jtag_command *cmd) -{ - DEBUG_JTAG_IO("pathmove: %i states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - - jlink_path_move(cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path); -} - -static void jlink_execute_scan(struct jtag_command *cmd) -{ - int scan_size; - enum scan_type type; - uint8_t *buffer; - - DEBUG_JTAG_IO("scan end in %s", tap_state_name(cmd->cmd.scan->end_state)); - - jlink_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_ - jlink_debug_buffer(buffer, (scan_size + 7) / 8); -#endif - type = jtag_scan_type(cmd->cmd.scan); - jlink_scan(cmd->cmd.scan->ir_scan, - type, buffer, scan_size, cmd->cmd.scan); -} - -static void jlink_execute_reset(struct jtag_command *cmd) -{ - DEBUG_JTAG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); - - jlink_tap_execute(); - jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - jlink_tap_execute(); -} - -static void jlink_execute_sleep(struct jtag_command *cmd) -{ - DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); - jlink_tap_execute(); - jtag_sleep(cmd->cmd.sleep->us); -} - -static void jlink_execute_command(struct jtag_command *cmd) -{ - switch (cmd->type) - { - case JTAG_RUNTEST: jlink_execute_runtest(cmd); break; - case JTAG_STATEMOVE: jlink_execute_statemove(cmd); break; - case JTAG_PATHMOVE: jlink_execute_pathmove(cmd); break; - case JTAG_SCAN: jlink_execute_scan(cmd); break; - case JTAG_RESET: jlink_execute_reset(cmd); break; - case JTAG_SLEEP: jlink_execute_sleep(cmd); break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); - } -} - -static int jlink_execute_queue(void) -{ - struct jtag_command *cmd = jtag_command_queue; - - while (cmd != NULL) - { - jlink_execute_command(cmd); - cmd = cmd->next; - } - - return jlink_tap_execute(); -} - -/* Sets speed in kHz. */ -static int jlink_speed(int speed) -{ - int result; - - if (speed > JLINK_MAX_SPEED) - { - LOG_INFO("Ignoring speed request: %dkHz exceeds %dkHz maximum", - speed, JLINK_MAX_SPEED); - return ERROR_OK; - } - - /* check for RTCK setting */ - if (speed == 0) - speed = -1; - - usb_out_buffer[0] = EMU_CMD_SET_SPEED; - usb_out_buffer[1] = (speed >> 0) & 0xff; - usb_out_buffer[2] = (speed >> 8) & 0xff; - - result = jlink_usb_write(jlink_handle, 3); - if (result != 3) - { - LOG_ERROR("J-Link setting speed failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int jlink_speed_div(int speed, int* khz) -{ - *khz = speed; - - return ERROR_OK; -} - -static int jlink_khz(int khz, int *jtag_speed) -{ - *jtag_speed = khz; - - return ERROR_OK; -} - -static int jlink_init(void) -{ - int i; - - jlink_handle = jlink_usb_open(); - - if (jlink_handle == 0) - { - LOG_ERROR("Cannot find jlink Interface! Please check connection and permissions."); - return ERROR_JTAG_INIT_FAILED; - } - - /* - * The next three instructions were added after discovering a problem while using an oscilloscope. For the V8 - * SAM-ICE dongle (and likely other j-link device variants), the reset line to the target microprocessor was found to - * cycle only intermittently during emulator startup (even after encountering the downstream reset instruction later - * in the code). This was found to create two issues: 1) In general it is a bad practice to not reset a CPU to a known - * state when starting an emulator and 2) something critical happens inside the dongle when it does the first read - * following a new USB session. Keeping the processor in reset during the first read collecting version information - * seems to prevent errant "J-Link command EMU_CMD_VERSION failed" issues. - */ - - LOG_INFO("J-Link initialization started / target CPU reset initiated"); - jlink_simple_command(EMU_CMD_HW_TRST0); - jlink_simple_command(EMU_CMD_HW_RESET0); - usleep(1000); - - jlink_hw_jtag_version = 2; - - if (jlink_get_version_info() == ERROR_OK) - { - /* attempt to get status */ - jlink_get_status(); - } - - LOG_INFO("J-Link JTAG Interface ready"); - - jlink_reset(0, 0); - jtag_sleep(3000); - jlink_tap_init(); - jlink_speed(jtag_get_speed()); - - /* v5/6 jlink seems to have an issue if the first tap move - * is not divisible by 8, so we send a TLR on first power up */ - for (i = 0; i < 8; i++) { - jlink_tap_append_step(1, 0); - } - jlink_tap_execute(); - - return ERROR_OK; -} - -static int jlink_quit(void) -{ - jlink_usb_close(jlink_handle); - return ERROR_OK; -} - -/***************************************************************************/ -/* Queue command implementations */ - -static void jlink_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 jlink_state_move(void) -{ - int i; - int tms = 0; - uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - - for (i = 0; i < tms_scan_bits; i++) - { - tms = (tms_scan >> i) & 1; - jlink_tap_append_step(tms, 0); - } - - tap_set_state(tap_get_end_state()); -} - -static void jlink_path_move(int num_states, tap_state_t *path) -{ - int i; - - for (i = 0; i < num_states; i++) - { - if (path[i] == tap_state_transition(tap_get_state(), false)) - { - jlink_tap_append_step(0, 0); - } - else if (path[i] == tap_state_transition(tap_get_state(), true)) - { - jlink_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 jlink_runtest(int num_cycles) -{ - int i; - - tap_state_t saved_end_state = tap_get_end_state(); - - jlink_tap_ensure_space(1,num_cycles + 16); - - /* only do a state_move when we're not already in IDLE */ - if (tap_get_state() != TAP_IDLE) - { - jlink_end_state(TAP_IDLE); - jlink_state_move(); -// num_cycles--; - } - - /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) - { - jlink_tap_append_step(0, 0); - } - - /* finish in end_state */ - jlink_end_state(saved_end_state); - if (tap_get_state() != tap_get_end_state()) - { - jlink_state_move(); - } -} - -static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) -{ - tap_state_t saved_end_state; - - jlink_tap_ensure_space(1, scan_size + 16); - - saved_end_state = tap_get_end_state(); - - /* Move to appropriate scan state */ - jlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); - - /* Only move if we're not already there */ - if (tap_get_state() != tap_get_end_state()) - jlink_state_move(); - - jlink_end_state(saved_end_state); - - /* Scan */ - jlink_tap_append_scan(scan_size, buffer, command); - - /* We are in Exit1, go to Pause */ - jlink_tap_append_step(0, 0); - - tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); - - if (tap_get_state() != tap_get_end_state()) - { - jlink_state_move(); - } -} - -static void jlink_reset(int trst, int srst) -{ - LOG_DEBUG("trst: %i, srst: %i", trst, srst); - - /* Signals are active low */ - if (srst == 0) - { - jlink_simple_command(EMU_CMD_HW_RESET1); - } - if (srst == 1) - { - jlink_simple_command(EMU_CMD_HW_RESET0); - } - - if (trst == 1) - { - jlink_simple_command(EMU_CMD_HW_TRST0); - } - - if (trst == 0) - { - jlink_simple_command(EMU_CMD_HW_TRST1); - } -} - -static void jlink_simple_command(uint8_t command) -{ - int result; - - DEBUG_JTAG_IO("0x%02x", command); - - usb_out_buffer[0] = command; - result = jlink_usb_write(jlink_handle, 1); - - if (result != 1) - { - LOG_ERROR("J-Link command 0x%02x failed (%d)", command, result); - } -} - -static int jlink_get_status(void) -{ - int result; - - jlink_simple_command(EMU_CMD_GET_STATE); - - result = jlink_usb_read(jlink_handle, 8); - if (result != 8) - { - LOG_ERROR("J-Link command EMU_CMD_GET_STATE failed (%d)\n", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - int vref = usb_in_buffer[0] + (usb_in_buffer[1] << 8); - LOG_INFO("Vref = %d.%d TCK = %d TDI = %d TDO = %d TMS = %d SRST = %d TRST = %d\n", \ - vref / 1000, vref % 1000, \ - usb_in_buffer[2], usb_in_buffer[3], usb_in_buffer[4], \ - usb_in_buffer[5], usb_in_buffer[6], usb_in_buffer[7]); - - if (vref < 1500) - LOG_ERROR("Vref too low. Check Target Power\n"); - - return ERROR_OK; -} - -static int jlink_get_version_info(void) -{ - int result; - int len; - uint32_t jlink_caps, jlink_max_size; - - /* query hardware version */ - jlink_simple_command(EMU_CMD_VERSION); - - result = jlink_usb_read(jlink_handle, 2); - if (2 != result) - { - LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - len = buf_get_u32(usb_in_buffer, 0, 16); - if (len > JLINK_IN_BUFFER_SIZE) - { - LOG_ERROR("J-Link command EMU_CMD_VERSION impossible return length 0x%0x", len); - len = JLINK_IN_BUFFER_SIZE; - } - - result = jlink_usb_read(jlink_handle, len); - if (result != len) - { - LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)\n", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - usb_in_buffer[result] = 0; - LOG_INFO("%s", (char *)usb_in_buffer); - - /* query hardware capabilities */ - jlink_simple_command(EMU_CMD_GET_CAPS); - - result = jlink_usb_read(jlink_handle, 4); - if (4 != result) - { - LOG_ERROR("J-Link command EMU_CMD_GET_CAPS failed (%d)\n", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - jlink_caps = buf_get_u32(usb_in_buffer, 0, 32); - LOG_INFO("JLink caps 0x%x", (unsigned)jlink_caps); - - if (jlink_caps & (1 << EMU_CAP_GET_HW_VERSION)) - { - /* query hardware version */ - jlink_simple_command(EMU_CMD_GET_HW_VERSION); - - result = jlink_usb_read(jlink_handle, 4); - if (4 != result) - { - LOG_ERROR("J-Link command EMU_CMD_GET_HW_VERSION failed (%d)\n", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - uint32_t jlink_hw_version = buf_get_u32(usb_in_buffer, 0, 32); - uint32_t major_revision = (jlink_hw_version / 10000) % 100; - if (major_revision >= 5) - jlink_hw_jtag_version = 3; - - LOG_INFO("JLink hw version %i", (int)jlink_hw_version); - } - - if (jlink_caps & (1 << EMU_CAP_GET_MAX_BLOCK_SIZE)) - { - /* query hardware maximum memory block */ - jlink_simple_command(EMU_CMD_GET_MAX_MEM_BLOCK); - - result = jlink_usb_read(jlink_handle, 4); - if (4 != result) - { - LOG_ERROR("J-Link command EMU_CMD_GET_MAX_MEM_BLOCK failed (%d)\n", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - jlink_max_size = buf_get_u32(usb_in_buffer, 0, 32); - LOG_INFO("JLink max mem block %i", (int)jlink_max_size); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(jlink_handle_jlink_info_command) -{ - if (jlink_get_version_info() == ERROR_OK) - { - /* attempt to get status */ - jlink_get_status(); - } - - return ERROR_OK; -} - -COMMAND_HANDLER(jlink_handle_jlink_hw_jtag_command) -{ - switch (CMD_ARGC) { - case 0: - command_print(CMD_CTX, "jlink hw jtag %i", jlink_hw_jtag_version); - break; - case 1: { - int request_version = atoi(CMD_ARGV[0]); - switch (request_version) { - case 2: case 3: - jlink_hw_jtag_version = request_version; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - break; - } - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - -static const struct command_registration jlink_command_handlers[] = { - { - .name = "jlink_info", - .handler = &jlink_handle_jlink_info_command, - .mode = COMMAND_EXEC, - .help = "show jlink info", - }, - { - .name = "jlink_hw_jtag", - .handler = &jlink_handle_jlink_hw_jtag_command, - .mode = COMMAND_EXEC, - .help = "access J-Link HW JTAG command version", - .usage = "[2|3]", - }, - COMMAND_REGISTRATION_DONE -}; - -struct jtag_interface jlink_interface = { - .name = "jlink", - - .commands = jlink_command_handlers, - - .execute_queue = &jlink_execute_queue, - .speed = &jlink_speed, - .speed_div = &jlink_speed_div, - .khz = &jlink_khz, - - .init = &jlink_init, - .quit = &jlink_quit, - }; - -/***************************************************************************/ -/* J-Link tap functions */ - - -static unsigned tap_length = 0; -static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE]; -static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE]; -static uint8_t tdo_buffer[JLINK_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 void jlink_tap_init(void) -{ - tap_length = 0; - pending_scan_results_length = 0; -} - -static void jlink_tap_ensure_space(int scans, int bits) -{ - int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; - int available_bits = JLINK_TAP_BUFFER_SIZE * 8 - tap_length - 32; - - if (scans > available_scans || bits > available_bits) - { - jlink_tap_execute(); - } -} - -static void jlink_tap_append_step(int tms, int tdi) -{ - int index = tap_length / 8; - - if (index >= JLINK_TAP_BUFFER_SIZE) - { - LOG_ERROR("jlink_tap_append_step: overflow"); - *(uint32_t *)0xFFFFFFFF = 0; - exit(-1); - } - - int bit_index = tap_length % 8; - uint8_t bit = 1 << bit_index; - - // we do not pad TMS, so be sure to initialize all bits - if (0 == bit_index) - { - tms_buffer[index] = tdi_buffer[index] = 0; - } - - if (tms) - tms_buffer[index] |= bit; - else - tms_buffer[index] &= ~bit; - - if (tdi) - tdi_buffer[index] |= bit; - else - tdi_buffer[index] &= ~bit; - - tap_length++; -} - -static void jlink_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++) - { - int tms = (i < (length - 1)) ? 0 : 1; - int tdi = (buffer[i / 8] & (1 << (i % 8))) != 0; - jlink_tap_append_step(tms, tdi); - } - 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 jlink_tap_execute(void) -{ - int byte_length; - int i; - int result; - - if (!tap_length) - return ERROR_OK; - - /* JLink returns an extra NULL in packet when size of incoming - * message is a multiple of 64, creates problems with USB comms. - * WARNING: This will interfere with tap state counting. */ - while ((DIV_ROUND_UP(tap_length, 8) % 64) == 0) - { - jlink_tap_append_step((tap_get_state() == TAP_RESET)?1:0, 0); - } - - // number of full bytes (plus one if some would be left over) - byte_length = DIV_ROUND_UP(tap_length, 8); - - bool use_jtag3 = jlink_hw_jtag_version >= 3; - usb_out_buffer[0] = use_jtag3 ? EMU_CMD_HW_JTAG3 : EMU_CMD_HW_JTAG2; - usb_out_buffer[1] = 0; - usb_out_buffer[2] = (tap_length >> 0) & 0xff; - usb_out_buffer[3] = (tap_length >> 8) & 0xff; - memcpy(usb_out_buffer + 4, tms_buffer, byte_length); - memcpy(usb_out_buffer + 4 + byte_length, tdi_buffer, byte_length); - - jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer, - tap_length, jlink_last_state); - - result = jlink_usb_message(jlink_handle, 4 + 2 * byte_length, byte_length); - if (result != byte_length) - { - LOG_ERROR("jlink_tap_execute, wrong result %d (expected %d)", result, byte_length); - jlink_tap_init(); - return ERROR_JTAG_QUEUE_FAILED; - } - - memcpy(tdo_buffer, usb_in_buffer, byte_length); - - 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_ - jlink_debug_buffer(buffer, DIV_ROUND_UP(length, 8)); -#endif - - if (jtag_read_buffer(buffer, command) != ERROR_OK) - { - jlink_tap_init(); - return ERROR_JTAG_QUEUE_FAILED; - } - - if (pending_scan_result->buffer != NULL) - { - free(pending_scan_result->buffer); - } - } - - jlink_tap_init(); - return ERROR_OK; -} - -/*****************************************************************************/ -/* JLink USB low-level functions */ - -static struct jlink* jlink_usb_open() -{ - 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; - - /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS - * AREA!!!!!!!!!!! The behavior of libusb is not completely - * consistent across Windows, Linux, and Mac OS X platforms. - * The actions taken in the following compiler conditionals may - * not agree with published documentation for libusb, but were - * found to be necessary through trials and tribulations. Even - * little tweaks can break one or more platforms, so if you do - * make changes test them carefully on all platforms before - * committing them! - */ - -#if IS_WIN32 == 0 - - usb_reset(dev); - -#if IS_DARWIN == 0 - - int timeout = 5; - /* reopen jlink after usb_reset - * on win32 this may take a second or two to re-enumerate */ - int retval; - while ((retval = jtag_usb_open(vids, pids, &dev)) != ERROR_OK) - { - usleep(1000); - timeout--; - if (!timeout) { - break; - } - } - if (ERROR_OK != retval) - return NULL; -#endif - -#endif - - /* usb_set_configuration required under win32 */ - struct usb_device *udev = usb_device(dev); - usb_set_configuration(dev, udev->config[0].bConfigurationValue); - 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(result->usb_handle, 0); -#endif - struct usb_interface *iface = udev->config->interface; - struct usb_interface_descriptor *desc = iface->altsetting; - for (int i = 0; i < desc->bNumEndpoints; i++) - { - uint8_t epnum = desc->endpoint[i].bEndpointAddress; - bool is_input = epnum & 0x80; - LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum); - if (is_input) - jlink_read_ep = epnum; - else - jlink_write_ep = epnum; - } - - struct jlink *result = malloc(sizeof(struct jlink)); - result->usb_handle = dev; - return result; -} - -static void jlink_usb_close(struct jlink *jlink) -{ - usb_close(jlink->usb_handle); - free(jlink); -} - -/* Send a message and receive the reply. */ -static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length) -{ - int result; - - result = jlink_usb_write(jlink, out_length); - if (result != out_length) - { - LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", - out_length, result); - return ERROR_JTAG_DEVICE_ERROR; - } - - result = jlink_usb_read(jlink, in_length); - if ((result != in_length) && (result != (in_length + 1))) - { - LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", - in_length, result); - return ERROR_JTAG_DEVICE_ERROR; - } - - if (jlink_hw_jtag_version < 3) - return result; - - int result2 = ERROR_OK; - if (result == in_length) - { - /* Must read the result from the EMU too */ - result2 = jlink_usb_read_emu_result(jlink); - if (1 != result2) - { - LOG_ERROR("jlink_usb_read_emu_result retried requested = 1, result=%d, in_length=%i", result2,in_length); - /* Try again once, should only happen if (in_length%64 == 0) */ - result2 = jlink_usb_read_emu_result(jlink); - if (1 != result2) - { - LOG_ERROR("jlink_usb_read_emu_result failed " - "(requested = 1, result=%d)", result2); - return ERROR_JTAG_DEVICE_ERROR; - } - } - - /* Check the result itself */ - result2 = usb_emu_result_buffer[0]; - } - else - { - /* Save the result, then remove it from return value */ - result2 = usb_in_buffer[result--]; - } - - if (result2) - { - LOG_ERROR("jlink_usb_message failed with result=%d)", result2); - return ERROR_JTAG_DEVICE_ERROR; - } - - return result; -} - -/* calls the given usb_bulk_* function, allowing for the data to trickle in with some timeouts */ -static int usb_bulk_with_retries( - int (*f)(usb_dev_handle *, int, char *, int, int), - usb_dev_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - int tries = 3, count = 0; - - while (tries && (count < size)) - { - int result = f(dev, ep, bytes + count, size - count, timeout); - if (result > 0) - count += result; - else if ((-ETIMEDOUT != result) || !--tries) - return result; - } - return count; -} - -static int wrap_usb_bulk_write(usb_dev_handle *dev, int ep, - char *buff, int size, int timeout) -{ - /* usb_bulk_write() takes const char *buff */ - return usb_bulk_write(dev, ep, buff, size, timeout); -} - -static inline int usb_bulk_write_ex(usb_dev_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - return usb_bulk_with_retries(&wrap_usb_bulk_write, - dev, ep, bytes, size, timeout); -} - -static inline int usb_bulk_read_ex(usb_dev_handle *dev, int ep, - char *bytes, int size, int timeout) -{ - return usb_bulk_with_retries(&usb_bulk_read, - dev, ep, bytes, size, timeout); -} - -/* Write data from out_buffer to USB. */ -static int jlink_usb_write(struct jlink *jlink, int out_length) -{ - int result; - - if (out_length > JLINK_OUT_BUFFER_SIZE) - { - LOG_ERROR("jlink_write illegal out_length=%d (max=%d)", out_length, JLINK_OUT_BUFFER_SIZE); - return -1; - } - - result = usb_bulk_write_ex(jlink->usb_handle, jlink_write_ep, - (char *)usb_out_buffer, out_length, JLINK_USB_TIMEOUT); - - DEBUG_JTAG_IO("jlink_usb_write, out_length = %d, result = %d", out_length, result); - -#ifdef _DEBUG_USB_COMMS_ - jlink_debug_buffer(usb_out_buffer, out_length); -#endif - return result; -} - -/* Read data from USB into in_buffer. */ -static int jlink_usb_read(struct jlink *jlink, int expected_size) -{ - int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, - (char *)usb_in_buffer, expected_size, JLINK_USB_TIMEOUT); - - DEBUG_JTAG_IO("jlink_usb_read, result = %d", result); - -#ifdef _DEBUG_USB_COMMS_ - jlink_debug_buffer(usb_in_buffer, result); -#endif - return result; -} - -/* Read the result from the previous EMU cmd into result_buffer. */ -static int jlink_usb_read_emu_result(struct jlink *jlink) -{ - int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, - (char *)usb_emu_result_buffer, 1 /* JLINK_EMU_RESULT_BUFFER_SIZE */, - JLINK_USB_TIMEOUT); - - DEBUG_JTAG_IO("jlink_usb_read_result, result = %d", result); - -#ifdef _DEBUG_USB_COMMS_ - jlink_debug_buffer(usb_emu_result_buffer, result); -#endif - return result; -} - -#ifdef _DEBUG_USB_COMMS_ -#define BYTES_PER_LINE 16 - -static void jlink_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 - diff --git a/src/jtag/parport.c b/src/jtag/parport.c deleted file mode 100644 index e5f56113..00000000 --- a/src/jtag/parport.c +++ /dev/null @@ -1,533 +0,0 @@ -/*************************************************************************** - * 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 -#include -#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 -#include -#define PPRSTATUS PPIGSTATUS -#define PPWDATA PPISDATA -#else -#include -#include -#endif -#include -#else /* not PARPORT_USE_PPDEV */ -#ifndef _WIN32 -#include -#endif -#endif - -#if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 -#include -#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 "); - 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 = "[]", - }, - { - .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 = "[]", - }, - { - .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 = "[]", - }, - { - .name = "parport_toggling_time", - .handler = &parport_handle_parport_toggling_time_command, - .mode = COMMAND_CONFIG, - .help = "time it takes for the hardware to toggle TCK", - .usage = "[]", - }, - 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, - }; diff --git a/src/jtag/presto.c b/src/jtag/presto.c deleted file mode 100644 index f4e689c2..00000000 --- a/src/jtag/presto.c +++ /dev/null @@ -1,800 +0,0 @@ -/*************************************************************************** - * 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 -#elif BUILD_PRESTO_LIBFTDI == 1 -#include -#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 "); - } - - 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 = "", - }, - 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, - }; diff --git a/src/jtag/rlink/Makefile b/src/jtag/rlink/Makefile deleted file mode 100644 index 94c53f50..00000000 --- a/src/jtag/rlink/Makefile +++ /dev/null @@ -1,73 +0,0 @@ -#*************************************************************************** -#* 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' diff --git a/src/jtag/rlink/call.m4 b/src/jtag/rlink/call.m4 deleted file mode 100644 index 0139c7c2..00000000 --- a/src/jtag/rlink/call.m4 +++ /dev/null @@ -1,485 +0,0 @@ -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 = - 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 - = 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 = 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 - - diff --git a/src/jtag/rlink/dtc_cmd.h b/src/jtag/rlink/dtc_cmd.h deleted file mode 100644 index 98975098..00000000 --- a/src/jtag/rlink/dtc_cmd.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************** - * 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. */ diff --git a/src/jtag/rlink/ep1_cmd.h b/src/jtag/rlink/ep1_cmd.h deleted file mode 100644 index b30e1bb1..00000000 --- a/src/jtag/rlink/ep1_cmd.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * 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 . - * 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) diff --git a/src/jtag/rlink/init.m4 b/src/jtag/rlink/init.m4 deleted file mode 100644 index 3e64523c..00000000 --- a/src/jtag/rlink/init.m4 +++ /dev/null @@ -1,74 +0,0 @@ -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 diff --git a/src/jtag/rlink/rlink.c b/src/jtag/rlink/rlink.c deleted file mode 100644 index bb33ad8f..00000000 --- a/src/jtag/rlink/rlink.c +++ /dev/null @@ -1,1812 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005 by Dominic Rath * - * Dominic.Rath@gmx.de * - * * - * Copyright (C) 2007,2008 Øyvind Harboe * - * oyvind.harboe@zylin.com * - * * - * Copyright (C) 2008 Rob Brown, Lou Deluxe * - * rob@cobbleware.com, 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. * - ***************************************************************************/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* project specific includes */ -#include "interface.h" -#include "commands.h" -#include "rlink.h" -#include "st7.h" -#include "ep1_cmd.h" -#include "dtc_cmd.h" -#include "usb_common.h" - - -/* This feature is made useless by running the DTC all the time. When automatic, the LED is on whenever the DTC is running. Otherwise, USB messages are sent to turn it on and off. */ -#undef AUTOMATIC_BUSY_LED - -/* This feature may require derating the speed due to reduced hold time. */ -#undef USE_HARDWARE_SHIFTER_FOR_TMS - - -#define INTERFACE_NAME "RLink" - -#define USB_IDVENDOR (0x138e) -#define USB_IDPRODUCT (0x9000) - -#define USB_EP1OUT_ADDR (0x01) -#define USB_EP1OUT_SIZE (16) -#define USB_EP1IN_ADDR (USB_EP1OUT_ADDR | 0x80) -#define USB_EP1IN_SIZE (USB_EP1OUT_SIZE) - -#define USB_EP2OUT_ADDR (0x02) -#define USB_EP2OUT_SIZE (64) -#define USB_EP2IN_ADDR (USB_EP2OUT_ADDR | 0x80) -#define USB_EP2IN_SIZE (USB_EP2OUT_SIZE) -#define USB_EP2BANK_SIZE (512) - -#define USB_TIMEOUT_MS (3 * 1000) - -#define DTC_STATUS_POLL_BYTE (ST7_USB_BUF_EP0OUT + 0xff) - - -#define ST7_PD_NBUSY_LED ST7_PD0 -#define ST7_PD_NRUN_LED ST7_PD1 -/* low enables VPP at adapter header, high connects it to GND instead */ -#define ST7_PD_VPP_SEL ST7_PD6 -/* low: VPP = 12v, high: VPP <= 5v */ -#define ST7_PD_VPP_SHDN ST7_PD7 - -/* These pins are connected together */ -#define ST7_PE_ADAPTER_SENSE_IN ST7_PE3 -#define ST7_PE_ADAPTER_SENSE_OUT ST7_PE4 - -/* Symbolic mapping between port pins and numbered IO lines */ -#define ST7_PA_IO1 ST7_PA1 -#define ST7_PA_IO2 ST7_PA2 -#define ST7_PA_IO4 ST7_PA4 -#define ST7_PA_IO8 ST7_PA6 -#define ST7_PA_IO10 ST7_PA7 -#define ST7_PB_IO5 ST7_PB5 -#define ST7_PC_IO9 ST7_PC1 -#define ST7_PC_IO3 ST7_PC2 -#define ST7_PC_IO7 ST7_PC3 -#define ST7_PE_IO6 ST7_PE5 - -/* Symbolic mapping between numbered IO lines and adapter signals */ -#define ST7_PA_RTCK ST7_PA_IO0 -#define ST7_PA_NTRST ST7_PA_IO1 -#define ST7_PC_TDI ST7_PC_IO3 -#define ST7_PA_DBGRQ ST7_PA_IO4 -#define ST7_PB_NSRST ST7_PB_IO5 -#define ST7_PE_TMS ST7_PE_IO6 -#define ST7_PC_TCK ST7_PC_IO7 -#define ST7_PC_TDO ST7_PC_IO9 -#define ST7_PA_DBGACK ST7_PA_IO10 - -static usb_dev_handle *pHDev; - - -/* - * ep1 commands are up to USB_EP1OUT_SIZE bytes in length. - * This function takes care of zeroing the unused bytes before sending the packet. - * Any reply packet is not handled by this function. - */ -static -int -ep1_generic_commandl( - usb_dev_handle *pHDev, - size_t length, - ... -) { - uint8_t usb_buffer[USB_EP1OUT_SIZE]; - uint8_t *usb_buffer_p; - va_list ap; - int usb_ret; - - if (length > sizeof(usb_buffer)) { - length = sizeof(usb_buffer); - } - - usb_buffer_p = usb_buffer; - - va_start(ap, length); - while (length > 0) { - *usb_buffer_p++ = va_arg(ap, int); - length--; - } - - memset( - usb_buffer_p, - 0, - sizeof(usb_buffer) - (usb_buffer_p - usb_buffer) -); - - usb_ret = usb_bulk_write( - pHDev, - USB_EP1OUT_ADDR, - (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS -); - - return(usb_ret); -} - - - -#if 0 -static -ssize_t -ep1_memory_read( - usb_dev_handle *pHDev, - uint16_t addr, - size_t length, - uint8_t *buffer -) { - uint8_t usb_buffer[USB_EP1OUT_SIZE]; - int usb_ret; - size_t remain; - ssize_t count; - - usb_buffer[0] = EP1_CMD_MEMORY_READ; - memset( - usb_buffer + 4, - 0, - sizeof(usb_buffer) - 4 -); - - remain = length; - count = 0; - - while (remain) { - if (remain > sizeof(usb_buffer)) { - length = sizeof(usb_buffer); - } else { - length = remain; - } - - usb_buffer[1] = addr >> 8; - usb_buffer[2] = addr; - usb_buffer[3] = length; - - usb_ret = usb_bulk_write( - pHDev, USB_EP1OUT_ADDR, - usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS -); - - if (usb_ret < sizeof(usb_buffer)) { - break; - } - - usb_ret = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - buffer, length, - USB_TIMEOUT_MS -); - - if (usb_ret < length) { - break; - } - - addr += length; - buffer += length; - count += length; - remain -= length; - } - - return(count); -} -#endif - - - -static -ssize_t -ep1_memory_write( - usb_dev_handle *pHDev, - uint16_t addr, - size_t length, - uint8_t const *buffer -) { - uint8_t usb_buffer[USB_EP1OUT_SIZE]; - int usb_ret; - size_t remain; - ssize_t count; - - usb_buffer[0] = EP1_CMD_MEMORY_WRITE; - - remain = length; - count = 0; - - while (remain) { - if (remain > (sizeof(usb_buffer) - 4)) { - length = (sizeof(usb_buffer) - 4); - } else { - length = remain; - } - - usb_buffer[1] = addr >> 8; - usb_buffer[2] = addr; - usb_buffer[3] = length; - memcpy( - usb_buffer + 4, - buffer, - length -); - memset( - usb_buffer + 4 + length, - 0, - sizeof(usb_buffer) - 4 - length -); - - usb_ret = usb_bulk_write( - pHDev, USB_EP1OUT_ADDR, - (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS -); - - if ((size_t)usb_ret < sizeof(usb_buffer)) { - break; - } - - addr += length; - buffer += length; - count += length; - remain -= length; - } - - return(count); -} - - -#if 0 -static -ssize_t -ep1_memory_writel( - usb_dev_handle *pHDev, - uint16_t addr, - size_t length, - ... -) { - uint8_t buffer[USB_EP1OUT_SIZE - 4]; - uint8_t *buffer_p; - va_list ap; - size_t remain; - - if (length > sizeof(buffer)) { - length = sizeof(buffer); - } - - remain = length; - buffer_p = buffer; - - va_start(ap, length); - while (remain > 0) { - *buffer_p++ = va_arg(ap, int); - remain--; - } - - return(ep1_memory_write(pHDev, addr, length, buffer)); -} -#endif - - -#define DTCLOAD_COMMENT (0) -#define DTCLOAD_ENTRY (1) -#define DTCLOAD_LOAD (2) -#define DTCLOAD_RUN (3) -#define DTCLOAD_LUT_START (4) -#define DTCLOAD_LUT (5) - -#define DTC_LOAD_BUFFER ST7_USB_BUF_EP2UIDO - -/* This gets set by the DTC loader */ -static uint8_t dtc_entry_download; - - -/* The buffer is specially formatted to represent a valid image to load into the DTC. */ -static -int -dtc_load_from_buffer( - usb_dev_handle *pHDev, - const uint8_t *buffer, - size_t length -) { - struct header_s { - uint8_t type; - uint8_t length; - }; - - int usb_err; - struct header_s *header; - uint8_t lut_start = 0xc0; - - dtc_entry_download = 0; - - /* Stop the DTC before loading anything. */ - usb_err = ep1_generic_commandl( - pHDev, 1, - EP1_CMD_DTC_STOP -); - if (usb_err < 0) return(usb_err); - - while (length) { - if (length < sizeof(*header)) { - LOG_ERROR("Malformed DTC image\n"); - exit(1); - } - - header = (struct header_s *)buffer; - buffer += sizeof(*header); - length -= sizeof(*header); - - if (length < (size_t)header->length + 1) { - LOG_ERROR("Malformed DTC image\n"); - exit(1); - } - - switch (header->type) { - case DTCLOAD_COMMENT: - break; - - case DTCLOAD_ENTRY: - /* store entry addresses somewhere */ - if (!strncmp("download", (char *)buffer + 1, 8)) { - dtc_entry_download = buffer[0]; - } - break; - - case DTCLOAD_LOAD: - /* Send the DTC program to ST7 RAM. */ - usb_err = ep1_memory_write( - pHDev, - DTC_LOAD_BUFFER, - header->length + 1, buffer -); - if (usb_err < 0) return(usb_err); - - /* Load it into the DTC. */ - usb_err = ep1_generic_commandl( - pHDev, 3, - EP1_CMD_DTC_LOAD, - (DTC_LOAD_BUFFER >> 8), - DTC_LOAD_BUFFER -); - if (usb_err < 0) return(usb_err); - - break; - - case DTCLOAD_RUN: - usb_err = ep1_generic_commandl( - pHDev, 3, - EP1_CMD_DTC_CALL, - buffer[0], - EP1_CMD_DTC_WAIT -); - if (usb_err < 0) return(usb_err); - - break; - - case DTCLOAD_LUT_START: - lut_start = buffer[0]; - break; - - case DTCLOAD_LUT: - usb_err = ep1_memory_write( - pHDev, - ST7_USB_BUF_EP0OUT + lut_start, - header->length + 1, buffer -); - if (usb_err < 0) return(usb_err); - break; - - default: - LOG_ERROR("Invalid DTC image record type: 0x%02x\n", header->type); - exit(1); - break; - } - - buffer += (header->length + 1); - length -= (header->length + 1); - } - - return(0); -} - - -/* - * Start the DTC running in download mode (waiting for 512 byte command packets on ep2). - */ -static -int -dtc_start_download(void) { - int usb_err; - uint8_t ep2txr; - - /* set up for download mode and make sure EP2 is set up to transmit */ - usb_err = ep1_generic_commandl( - pHDev, 7, - - EP1_CMD_DTC_STOP, - EP1_CMD_SET_UPLOAD, - EP1_CMD_SET_DOWNLOAD, - EP1_CMD_MEMORY_READ, /* read EP2TXR for its data toggle */ - ST7_EP2TXR >> 8, - ST7_EP2TXR, - 1 -); - if (usb_err < 0) return(usb_err); - - /* read back ep2txr */ - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)&ep2txr, 1, - USB_TIMEOUT_MS -); - if (usb_err < 0) return(usb_err); - - usb_err = ep1_generic_commandl( - pHDev, 13, - - EP1_CMD_MEMORY_WRITE, /* preinitialize poll byte */ - DTC_STATUS_POLL_BYTE >> 8, - DTC_STATUS_POLL_BYTE, - 1, - 0x00, - EP1_CMD_MEMORY_WRITE, /* set EP2IN to return data */ - ST7_EP2TXR >> 8, - ST7_EP2TXR, - 1, - (ep2txr & ST7_EP2TXR_DTOG_TX) | ST7_EP2TXR_STAT_VALID, - EP1_CMD_DTC_CALL, /* start running the DTC */ - dtc_entry_download, - EP1_CMD_DTC_GET_CACHED_STATUS -); - if (usb_err < 0) return(usb_err); - - /* wait for completion */ - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)&ep2txr, 1, - USB_TIMEOUT_MS -); - - return(usb_err); -} - - -static -int -dtc_run_download( - usb_dev_handle *pHDev, - uint8_t *command_buffer, - int command_buffer_size, - uint8_t *reply_buffer, - int reply_buffer_size -) { - uint8_t ep2_buffer[USB_EP2IN_SIZE]; - int usb_err; - int i; - - LOG_DEBUG(": %d/%d\n", command_buffer_size, reply_buffer_size); - - usb_err = usb_bulk_write( - pHDev, - USB_EP2OUT_ADDR, - (char *)command_buffer, USB_EP2BANK_SIZE, - USB_TIMEOUT_MS -); - if (usb_err < 0) return(usb_err); - - - /* Wait for DTC to finish running command buffer */ - for (i = 10;;) { - usb_err = ep1_generic_commandl( - pHDev, 4, - - EP1_CMD_MEMORY_READ, - DTC_STATUS_POLL_BYTE >> 8, - DTC_STATUS_POLL_BYTE, - 1 -); - if (usb_err < 0) return(usb_err); - - usb_err = usb_bulk_read( - pHDev, - USB_EP1IN_ADDR, - (char *)ep2_buffer, 1, - USB_TIMEOUT_MS -); - if (usb_err < 0) return(usb_err); - - if (ep2_buffer[0] & 0x01) break; - - if (!--i) { - LOG_ERROR("%s, %d: too many retries waiting for DTC status\n", - __FILE__, __LINE__ -); - return(-ETIMEDOUT); - } - } - - - if (!reply_buffer) reply_buffer_size = 0; - if (reply_buffer_size) { - usb_err = usb_bulk_read( - pHDev, - USB_EP2IN_ADDR, - (char *)ep2_buffer, sizeof(ep2_buffer), - USB_TIMEOUT_MS -); - - if (usb_err < (int)sizeof(ep2_buffer)) { - LOG_ERROR("%s, %d: Read of endpoint 2 returned %d\n", - __FILE__, __LINE__, usb_err -); - return(usb_err); - } - - memcpy(reply_buffer, ep2_buffer, reply_buffer_size); - - } - - return(usb_err); -} - - -/* - * The dtc reply queue is a singly linked list that describes what to do with the reply packet that comes from the DTC. Only SCAN_IN and SCAN_IO generate these entries. - */ - -struct dtc_reply_queue_entry { - struct dtc_reply_queue_entry *next; - struct jtag_command *cmd; /* the command that resulted in this entry */ - - struct { - uint8_t *buffer; /* the scan buffer */ - int size; /* size of the scan buffer in bits */ - int offset; /* how many bits were already done before this? */ - int length; /* how many bits are processed in this operation? */ - enum scan_type type; /* SCAN_IN/SCAN_OUT/SCAN_IO */ - } scan; -}; - - -/* - * The dtc_queue consists of a buffer of pending commands and a reply queue. - * rlink_scan and tap_state_run add to the command buffer and maybe to the reply queue. - */ - -static -struct { - struct dtc_reply_queue_entry *rq_head; - struct dtc_reply_queue_entry *rq_tail; - uint32_t cmd_index; - uint32_t reply_index; - uint8_t cmd_buffer[USB_EP2BANK_SIZE]; -} dtc_queue; - - -/* - * The tap state queue is for accumulating TAP state changes wiithout needlessly flushing the dtc_queue. When it fills or is run, it adds the accumulated bytes to the dtc_queue. - */ - -static -struct { - uint32_t length; - uint32_t buffer; -} tap_state_queue; - - - -static -int -dtc_queue_init(void) { - dtc_queue.rq_head = NULL; - dtc_queue.rq_tail = NULL; - dtc_queue.cmd_index = 0; - dtc_queue.reply_index = 0; - return(0); -} - - -static -inline -struct dtc_reply_queue_entry * -dtc_queue_enqueue_reply( - enum scan_type type, - uint8_t *buffer, - int size, - int offset, - int length, - struct jtag_command *cmd -) { - struct dtc_reply_queue_entry *rq_entry; - - rq_entry = malloc(sizeof(struct dtc_reply_queue_entry)); - if (rq_entry != NULL) { - rq_entry->scan.type = type; - rq_entry->scan.buffer = buffer; - rq_entry->scan.size = size; - rq_entry->scan.offset = offset; - rq_entry->scan.length = length; - rq_entry->cmd = cmd; - rq_entry->next = NULL; - - if (dtc_queue.rq_head == NULL) - dtc_queue.rq_head = rq_entry; - else - dtc_queue.rq_tail->next = rq_entry; - - dtc_queue.rq_tail = rq_entry; - } - - return(rq_entry); -} - - -/* - * Running the queue means that any pending command buffer is run and any reply data dealt with. The command buffer is then cleared for subsequent processing. - * The queue is automatically run by append when it is necessary to get space for the append. -*/ - -static -int -dtc_queue_run(void) { - struct dtc_reply_queue_entry *rq_p, *rq_next; - int retval; - int usb_err; - int bit_cnt; - int x; - uint8_t *dtc_p, *tdo_p; - uint8_t dtc_mask, tdo_mask; - uint8_t reply_buffer[USB_EP2IN_SIZE]; - - retval = ERROR_OK; - - if (dtc_queue.cmd_index < 1) return(retval); - - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_STOP; - - /* run the cmd */ - if (dtc_queue.rq_head == NULL) { - usb_err = dtc_run_download(pHDev, - dtc_queue.cmd_buffer, dtc_queue.cmd_index, - NULL, 0 -); - if (usb_err < 0) { - LOG_ERROR("dtc_run_download: %s\n", usb_strerror()); - exit(1); - } - } else { - usb_err = dtc_run_download(pHDev, - dtc_queue.cmd_buffer, dtc_queue.cmd_index, - reply_buffer, dtc_queue.reply_index -); - if (usb_err < 0) { - LOG_ERROR("dtc_run_download: %s\n", usb_strerror()); - exit(1); - } else { - /* process the reply, which empties the reply queue and frees its entries */ - dtc_p = reply_buffer; - - /* The rigamarole with the masks and doing it bit-by-bit is due to the fact that the scan buffer is LSb-first and the DTC code is MSb-first for hardware reasons. It was that or craft a function to do the reversal, and that wouldn't work with bit-stuffing (supplying extra bits to use mostly byte operations), or any other scheme which would throw the byte alignment off. */ - - for ( - rq_p = dtc_queue.rq_head; - rq_p != NULL; - rq_p = rq_next -) { - tdo_p = rq_p->scan.buffer + (rq_p->scan.offset / 8); - tdo_mask = 1 << (rq_p->scan.offset % 8); - - - bit_cnt = rq_p->scan.length; - if (bit_cnt >= 8) { - /* bytes */ - - dtc_mask = 1 << (8 - 1); - - for ( - ; - bit_cnt; - bit_cnt-- -) { - if (*dtc_p & dtc_mask) { - *tdo_p |= tdo_mask; - } else { - *tdo_p &=~ tdo_mask; - } - - dtc_mask >>= 1; - if (dtc_mask == 0) { - dtc_p++; - dtc_mask = 1 << (8 - 1); - } - - tdo_mask <<= 1; - if (tdo_mask == 0) { - tdo_p++; - tdo_mask = 1; - } - } - } else { - /* extra bits or last bit */ - - x = *dtc_p++; - if (( - rq_p->scan.type == SCAN_IN -) && ( - rq_p->scan.offset != rq_p->scan.size - 1 -)) { - /* extra bits were sent as a full byte with padding on the end */ - dtc_mask = 1 << (8 - 1); - } else { - dtc_mask = 1 << (bit_cnt - 1); - } - - for ( - ; - bit_cnt; - bit_cnt-- -) { - if (x & dtc_mask) { - *tdo_p |= tdo_mask; - } else { - *tdo_p &=~ tdo_mask; - } - - dtc_mask >>= 1; - - tdo_mask <<= 1; - if (tdo_mask == 0) { - tdo_p++; - tdo_mask = 1; - } - - } - } - - if ((rq_p->scan.offset + rq_p->scan.length) >= rq_p->scan.size) { - /* feed scan buffer back into openocd and free it */ - if (jtag_read_buffer(rq_p->scan.buffer, rq_p->cmd->cmd.scan) != ERROR_OK) { - retval = ERROR_JTAG_QUEUE_FAILED; - } - free(rq_p->scan.buffer); - } - - rq_next = rq_p->next; - free(rq_p); - } - dtc_queue.rq_head = NULL; - dtc_queue.rq_tail = NULL; - } - - } - - - /* reset state for new appends */ - dtc_queue.cmd_index = 0; - dtc_queue.reply_index = 0; - - return(retval); -} - - - -static -int -tap_state_queue_init(void) { - tap_state_queue.length = 0; - tap_state_queue.buffer = 0; - return(0); -} - - -static -int -tap_state_queue_run(void) { - int i; - int bits; - uint8_t byte; - int retval; - - retval = 0; - if (!tap_state_queue.length) return(retval); - bits = 1; - byte = 0; - for (i = tap_state_queue.length; i--;) { - - byte <<= 1; - if (tap_state_queue.buffer & 1) { - byte |= 1; - } - if ((bits >= 8) || !i) { - byte <<= (8 - bits); - - /* make sure there's room for stop, byte op, and one byte */ - if (dtc_queue.cmd_index >= (sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1))) { - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_STOP; - dtc_queue_run(); - } - -#ifdef USE_HARDWARE_SHIFTER_FOR_TMS - if (bits == 8) { - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_SHIFT_TMS_BYTES(1); - } else { -#endif - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_SHIFT_TMS_BITS(bits); -#ifdef USE_HARDWARE_SHIFTER_FOR_TMS - } -#endif - - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - byte; - - byte = 0; - bits = 1; - } else { - bits++; - } - - tap_state_queue.buffer >>= 1; - } - retval = tap_state_queue_init(); - return(retval); -} - - -static -int -tap_state_queue_append( - uint8_t tms -) { - int retval; - - if (tap_state_queue.length >= sizeof(tap_state_queue.buffer) * 8) { - retval = tap_state_queue_run(); - if (retval != 0) return(retval); - } - - if (tms) { - tap_state_queue.buffer |= (1 << tap_state_queue.length); - } - tap_state_queue.length++; - - return(0); -} - - -static -void rlink_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 rlink_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()); - - for (i = 0; i < tms_count; i++) - { - tms = (tms_scan >> i) & 1; - tap_state_queue_append(tms); - } - - tap_set_state(tap_get_end_state()); -} - -static -void rlink_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); - } - - tap_state_queue_append(tms); - - tap_set_state(cmd->path[state_count]); - state_count++; - num_states--; - } - - tap_set_end_state(tap_get_state()); -} - - -static -void rlink_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 RTI */ - if (tap_get_state() != TAP_IDLE) - { - rlink_end_state(TAP_IDLE); - rlink_state_move(); - } - - /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) - { - tap_state_queue_append(0); - } - - /* finish in end_state */ - rlink_end_state(saved_end_state); - if (tap_get_state() != tap_get_end_state()) - rlink_state_move(); -} - - -/* (1) assert or (0) deassert reset lines */ -static -void rlink_reset(int trst, int srst) -{ - uint8_t bitmap; - int usb_err; - - /* Read port A for bit op */ - usb_err = ep1_generic_commandl( - pHDev, 4, - EP1_CMD_MEMORY_READ, - ST7_PADR >> 8, - ST7_PADR, - 1 -); - if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); - exit(1); - } - - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)&bitmap, 1, - USB_TIMEOUT_MS -); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); - exit(1); - } - - if (trst) { - bitmap &= ~ST7_PA_NTRST; - } else { - bitmap |= ST7_PA_NTRST; - } - - /* Write port A and read port B for bit op */ - /* port B has no OR, and we want to emulate open drain on NSRST, so we initialize DR to 0 and assert NSRST by setting DDR to 1. */ - usb_err = ep1_generic_commandl( - pHDev, 9, - EP1_CMD_MEMORY_WRITE, - ST7_PADR >> 8, - ST7_PADR, - 1, - bitmap, - EP1_CMD_MEMORY_READ, - ST7_PBDDR >> 8, - ST7_PBDDR, - 1 -); - if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); - exit(1); - } - - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)&bitmap, 1, - USB_TIMEOUT_MS -); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); - exit(1); - } - - if (srst) { - bitmap |= ST7_PB_NSRST; - } else { - bitmap &= ~ST7_PB_NSRST; - } - - /* write port B and read dummy to ensure completion before returning */ - usb_err = ep1_generic_commandl( - pHDev, 6, - EP1_CMD_MEMORY_WRITE, - ST7_PBDDR >> 8, - ST7_PBDDR, - 1, - bitmap, - EP1_CMD_DTC_GET_CACHED_STATUS -); - if (usb_err < 0) { - LOG_ERROR("%s", usb_strerror()); - exit(1); - } - - usb_err = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)&bitmap, 1, - USB_TIMEOUT_MS -); - if (usb_err < 1) { - LOG_ERROR("%s", usb_strerror()); - exit(1); - } -} - - -static -int -rlink_scan( - struct jtag_command *cmd, - enum scan_type type, - uint8_t *buffer, - int scan_size -) { - bool ir_scan; - tap_state_t saved_end_state; - int byte_bits; - int extra_bits; - int chunk_bits; - int chunk_bytes; - int x; - - int tdi_bit_offset; - uint8_t tdi_mask, *tdi_p; - uint8_t dtc_mask; - - if (scan_size < 1) { - LOG_ERROR("scan_size cannot be less than 1 bit\n"); - exit(1); - } - - ir_scan = cmd->cmd.scan->ir_scan; - - /* Move to the proper state before starting to shift TDI/TDO. */ - if (!( - (!ir_scan && (tap_get_state() == TAP_DRSHIFT)) - || - (ir_scan && (tap_get_state() == TAP_IRSHIFT)) -)) { - saved_end_state = tap_get_end_state(); - rlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); - rlink_state_move(); - rlink_end_state(saved_end_state); - } - - tap_state_queue_run(); - - -#if 0 - printf("scan_size = %d, type = 0x%x\n", scan_size, type); - { - int i; - - /* clear unused bits in scan buffer for ease of debugging */ - /* (it makes diffing output easier) */ - buffer[scan_size / 8] &= ((1 << ((scan_size - 1) % 8) + 1) - 1); - - printf("before scan:"); - for (i = 0; i < (scan_size + 7) / 8; i++) { - printf(" %02x", buffer[i]); - } - printf("\n"); - } -#endif - - /* The number of bits that can be shifted as complete bytes */ - byte_bits = (int)(scan_size - 1) / 8 * 8; - /* The number of bits left over, not counting the last bit */ - extra_bits = (scan_size - 1) - byte_bits; - - tdi_bit_offset = 0; - tdi_p = buffer; - tdi_mask = 1; - - if (extra_bits && (type == SCAN_OUT)) { - /* Schedule any extra bits into the DTC command buffer, padding as needed */ - /* For SCAN_OUT, this comes before the full bytes so the (leading) padding bits will fall off the end */ - /* make sure there's room for stop, byte op, and one byte */ - if ( - (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1)) -) { - dtc_queue_run(); - } - - x = 0; - dtc_mask = 1 << (extra_bits - 1); - - while (extra_bits--) { - if (*tdi_p & tdi_mask) { - x |= dtc_mask; - } - - dtc_mask >>= 1; - - tdi_mask <<= 1; - if (tdi_mask == 0) { - tdi_p++; - tdi_mask = 1; - } - } - - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_SHIFT_TDI_BYTES(1); - - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; - } - - /* Loop scheduling full bytes into the DTC command buffer */ - while (byte_bits) { - if (type == SCAN_IN) { - /* make sure there's room for stop and byte op */ - x = (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1)); - } else { - /* make sure there's room for stop, byte op, and at least one byte */ - x = (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1)); - } - - if (type != SCAN_OUT) { - /* make sure there's room for at least one reply byte */ - x |= (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1)); - } - - if (x) { - dtc_queue_run(); - } - - chunk_bits = byte_bits; - /* we can only use up to 16 bytes at a time */ - if (chunk_bits > (16 * 8)) chunk_bits = (16 * 8); - - if (type != SCAN_IN) { - /* how much is there room for, considering stop and byte op? */ - x = (sizeof(dtc_queue.cmd_buffer) - (dtc_queue.cmd_index + 1 + 1)) * 8; - if (chunk_bits > x) chunk_bits = x; - } - - if (type != SCAN_OUT) { - /* how much is there room for in the reply buffer? */ - x = (USB_EP2IN_SIZE - dtc_queue.reply_index) * 8; - if (chunk_bits > x) chunk_bits = x; - } - - /* so the loop will end */ - byte_bits -= chunk_bits; - - if (type != SCAN_OUT) { - if (dtc_queue_enqueue_reply( - type, buffer, scan_size, tdi_bit_offset, - chunk_bits, - cmd -) == NULL) { - LOG_ERROR("enqueuing DTC reply entry: %s\n", strerror(errno)); - exit(1); - } - - tdi_bit_offset += chunk_bits; - } - - /* chunk_bits is a multiple of 8, so there are no rounding issues. */ - chunk_bytes = chunk_bits / 8; - - switch (type) { - case SCAN_IN: - x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); - break; - case SCAN_OUT: - x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); - break; - default: - x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); - break; - } - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; - - if (type != SCAN_IN) { - x = 0; - dtc_mask = 1 << (8 - 1); - - while (chunk_bits--) { - if (*tdi_p & tdi_mask) { - x |= dtc_mask; - } - - dtc_mask >>= 1; - if (dtc_mask == 0) { - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; - dtc_queue.reply_index++; - x = 0; - dtc_mask = 1 << (8 - 1); - } - - tdi_mask <<= 1; - if (tdi_mask == 0) { - tdi_p++; - tdi_mask = 1; - } - } - } - } - - if (extra_bits && (type != SCAN_OUT)) { - /* Schedule any extra bits into the DTC command buffer */ - /* make sure there's room for stop, byte op, and one byte */ - if ( - (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1)) - || - (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1)) -) { - dtc_queue_run(); - } - - if (dtc_queue_enqueue_reply( - type, buffer, scan_size, tdi_bit_offset, - extra_bits, - cmd -) == NULL) { - LOG_ERROR("enqueuing DTC reply entry: %s\n", strerror(errno)); - exit(1); - } - - tdi_bit_offset += extra_bits; - - if (type == SCAN_IN) { - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_SHIFT_TDO_BYTES(1); - - } else { - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_SHIFT_TDIO_BITS(extra_bits); - - x = 0; - dtc_mask = 1 << (8 - 1); - - while (extra_bits--) { - if (*tdi_p & tdi_mask) { - x |= dtc_mask; - } - - dtc_mask >>= 1; - - tdi_mask <<= 1; - if (tdi_mask == 0) { - tdi_p++; - tdi_mask = 1; - } - } - - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; - } - - dtc_queue.reply_index++; - } - - /* Schedule the last bit into the DTC command buffer */ - { - /* make sure there's room for stop, and bit pair command */ - if ( - (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1)) - || - (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1)) -) { - dtc_queue_run(); - } - - if (type == SCAN_OUT) { - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 0); - - } else { - if (dtc_queue_enqueue_reply( - type, buffer, scan_size, tdi_bit_offset, - 1, - cmd -) == NULL) { - LOG_ERROR("enqueuing DTC reply entry: %s\n", strerror(errno)); - exit(1); - } - - dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = - DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 1); - - dtc_queue.reply_index++; - } - } - - /* Move to pause state */ - tap_state_queue_append(0); - tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); - if (tap_get_state() != tap_get_end_state()) rlink_state_move(); - - return(0); -} - - -static -int rlink_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, tmp_retval; - - /* return ERROR_OK, unless something goes wrong */ - retval = ERROR_OK; - -#ifndef AUTOMATIC_BUSY_LED - /* turn LED on */ - ep1_generic_commandl(pHDev, 2, - EP1_CMD_SET_PORTD_LEDS, - ~(ST7_PD_NBUSY_LED) -); -#endif - - while (cmd) - { - switch (cmd->type) - { - case JTAG_RUNTEST: - case JTAG_STATEMOVE: - case JTAG_PATHMOVE: - case JTAG_SCAN: - break; - - default: - /* some events, such as resets, need a queue flush to ensure consistency */ - tap_state_queue_run(); - dtc_queue_run(); - break; - } - - 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); - } - rlink_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 - if (cmd->cmd.runtest->end_state != -1) - rlink_end_state(cmd->cmd.runtest->end_state); - rlink_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 - if (cmd->cmd.statemove->end_state != -1) - rlink_end_state(cmd->cmd.statemove->end_state); - rlink_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 - rlink_path_move(cmd->cmd.pathmove); - break; - case JTAG_SCAN: -#ifdef _DEBUG_JTAG_IO_ - LOG_DEBUG("%s scan end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", cmd->cmd.scan->end_state); -#endif - if (cmd->cmd.scan->end_state != -1) - rlink_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) { - retval = ERROR_FAIL; - } - 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; - } - - /* Flush the DTC queue to make sure any pending reads have been done before exiting this function */ - tap_state_queue_run(); - tmp_retval = dtc_queue_run(); - if (tmp_retval != ERROR_OK) { - retval = tmp_retval; - } - -#ifndef AUTOMATIC_BUSY_LED - /* turn LED onff */ - ep1_generic_commandl(pHDev, 2, - EP1_CMD_SET_PORTD_LEDS, - ~0 -); -#endif - - return retval; -} - - -/* Using an unindexed table because it is infrequently accessed and it is short. The table must be in order of ascending speed (and descending prescaler), as it is scanned in reverse. */ - -static -int rlink_speed(int speed) -{ - int i; - - if (speed == 0) { - /* fastest speed */ - speed = rlink_speed_table[rlink_speed_table_size - 1].prescaler; - } - - for (i = rlink_speed_table_size; i--;) { - if (rlink_speed_table[i].prescaler == speed) { - if (dtc_load_from_buffer(pHDev, rlink_speed_table[i].dtc, rlink_speed_table[i].dtc_size) != 0) { - LOG_ERROR("An error occurred while trying to load DTC code for speed \"%d\".\n", speed); - exit(1); - } - - if (dtc_start_download() < 0) { - LOG_ERROR("%s, %d: starting DTC: %s", - __FILE__, __LINE__, - usb_strerror() -); - exit(1); - } - - return ERROR_OK; - } - } - - LOG_ERROR("%d is not a supported speed", speed); - return(ERROR_FAIL); -} - - -static -int rlink_speed_div( - int speed, - int *khz -) { - int i; - - for (i = rlink_speed_table_size; i--;) { - if (rlink_speed_table[i].prescaler == speed) { - *khz = rlink_speed_table[i].khz; - return(ERROR_OK); - } - } - - LOG_ERROR("%d is not a supported speed", speed); - return(ERROR_FAIL); -} - - -static -int rlink_khz( - int khz, - int *speed -) { - int i; - - if (khz == 0) { - LOG_ERROR("RCLK not supported"); - return ERROR_FAIL; - } - - for (i = rlink_speed_table_size; i--;) { - if (rlink_speed_table[i].khz <= khz) { - *speed = rlink_speed_table[i].prescaler; - return(ERROR_OK); - } - } - - LOG_WARNING("The lowest supported JTAG speed is %d KHz", rlink_speed_table[0].khz); - *speed = rlink_speed_table[0].prescaler; - return(ERROR_OK); -} - - -static -int rlink_init(void) -{ - int i, j, retries; - uint8_t reply_buffer[USB_EP1IN_SIZE]; - - usb_init(); - const uint16_t vids[] = { USB_IDVENDOR, 0 }; - const uint16_t pids[] = { USB_IDPRODUCT, 0 }; - if (jtag_usb_open(vids, pids, &pHDev) != ERROR_OK) - return ERROR_FAIL; - - struct usb_device *dev = usb_device(pHDev); - if (dev->descriptor.bNumConfigurations > 1) - { - LOG_ERROR("Whoops! NumConfigurations is not 1, don't know what to do...\n"); - return ERROR_FAIL; - } - if (dev->config->bNumInterfaces > 1) - { - LOG_ERROR("Whoops! NumInterfaces is not 1, don't know what to do...\n"); - return ERROR_FAIL; - } - - LOG_DEBUG("Opened device, pHDev = %p\n", pHDev); - - /* usb_set_configuration required under win32 */ - usb_set_configuration(pHDev, dev->config[0].bConfigurationValue); - - retries = 3; - do - { - i = usb_claim_interface(pHDev,0); - if (i) - { - LOG_ERROR("usb_claim_interface: %s", usb_strerror()); -#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP - j = usb_detach_kernel_driver_np(pHDev, 0); - if (j) - LOG_ERROR("detach kernel driver: %s", usb_strerror()); -#endif - } - else - { - LOG_DEBUG("interface claimed!\n"); - break; - } - } while (--retries); - - if (i) - { - LOG_ERROR("Initialisation failed."); - return ERROR_FAIL; - } - if (usb_set_altinterface(pHDev,0) != 0) - { - LOG_ERROR("Failed to set interface.\n"); - return ERROR_FAIL; - } - - /* The device starts out in an unknown state on open. As such, - * result reads time out, and it's not even known whether the - * command was accepted. So, for this first command, we issue - * it repeatedly until its response doesn't time out. Also, if - * sending a command is going to time out, we find that out here. - * - * It must be possible to open the device in such a way that - * this special magic isn't needed, but, so far, it escapes us. - */ - for (i = 0; i < 5; i++) { - j = ep1_generic_commandl( - pHDev, 1, - EP1_CMD_GET_FWREV -); - if (j < USB_EP1OUT_SIZE) { - LOG_ERROR("USB write error: %s", usb_strerror()); - return(ERROR_FAIL); - } - j = usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)reply_buffer, sizeof(reply_buffer), - 200 -); - if (j != -ETIMEDOUT) break; - } - - if (j < (int)sizeof(reply_buffer)) { - LOG_ERROR("USB read error: %s", usb_strerror()); - return(ERROR_FAIL); - } - LOG_DEBUG(INTERFACE_NAME" firmware version: %d.%d.%d\n", reply_buffer[0], reply_buffer[1], reply_buffer[2]); - - if ((reply_buffer[0] != 0) || (reply_buffer[1] != 0) || (reply_buffer[2] != 3)) { - LOG_WARNING("The rlink device is not of the version that the developers have played with. It may or may not work.\n"); - } - - /* Probe port E for adapter presence */ - ep1_generic_commandl( - pHDev, 16, - EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 0 */ - ST7_PEDR >> 8, - ST7_PEDR, - 3, - 0x00, /* DR */ - ST7_PE_ADAPTER_SENSE_OUT, /* DDR */ - ST7_PE_ADAPTER_SENSE_OUT, /* OR */ - EP1_CMD_MEMORY_READ, /* Read back */ - ST7_PEDR >> 8, - ST7_PEDR, - 1, - EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 1 */ - ST7_PEDR >> 8, - ST7_PEDR, - 1, - ST7_PE_ADAPTER_SENSE_OUT -); - - usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)reply_buffer, 1, - USB_TIMEOUT_MS -); - - if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) != 0) { - LOG_WARNING("target detection problem\n"); - } - - ep1_generic_commandl( - pHDev, 11, - EP1_CMD_MEMORY_READ, /* Read back */ - ST7_PEDR >> 8, - ST7_PEDR, - 1, - EP1_CMD_MEMORY_WRITE, /* float port E */ - ST7_PEDR >> 8, - ST7_PEDR, - 3, - 0x00, /* DR */ - 0x00, /* DDR */ - 0x00 /* OR */ -); - - usb_bulk_read( - pHDev, USB_EP1IN_ADDR, - (char *)reply_buffer, 1, - USB_TIMEOUT_MS -); - - - if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) == 0) { - LOG_WARNING("target not plugged in\n"); - } - - /* float ports A and B */ - ep1_generic_commandl( - pHDev, 11, - EP1_CMD_MEMORY_WRITE, - ST7_PADDR >> 8, - ST7_PADDR, - 2, - 0x00, - 0x00, - EP1_CMD_MEMORY_WRITE, - ST7_PBDDR >> 8, - ST7_PBDDR, - 1, - 0x00 -); - - /* make sure DTC is stopped, set VPP control, set up ports A and B */ - ep1_generic_commandl( - pHDev, 14, - EP1_CMD_DTC_STOP, - EP1_CMD_SET_PORTD_VPP, - ~(ST7_PD_VPP_SHDN), - EP1_CMD_MEMORY_WRITE, - ST7_PADR >> 8, - ST7_PADR, - 2, - ((~(0)) & (ST7_PA_NTRST)), - (ST7_PA_NTRST), - /* port B has no OR, and we want to emulate open drain on NSRST, so we set DR to 0 here and later assert NSRST by setting DDR bit to 1. */ - EP1_CMD_MEMORY_WRITE, - ST7_PBDR >> 8, - ST7_PBDR, - 1, - 0x00 -); - - /* set LED updating mode and make sure they're unlit */ - ep1_generic_commandl( - pHDev, 3, -#ifdef AUTOMATIC_BUSY_LED - EP1_CMD_LEDUE_BUSY, -#else - EP1_CMD_LEDUE_NONE, -#endif - EP1_CMD_SET_PORTD_LEDS, - ~0 -); - - tap_state_queue_init(); - dtc_queue_init(); - rlink_speed(jtag_get_speed()); - rlink_reset(0, 0); - - return ERROR_OK; -} - - -static -int rlink_quit(void) -{ - /* stop DTC and make sure LEDs are off */ - ep1_generic_commandl( - pHDev, 6, - EP1_CMD_DTC_STOP, - EP1_CMD_LEDUE_NONE, - EP1_CMD_SET_PORTD_LEDS, - ~0, - EP1_CMD_SET_PORTD_VPP, - ~0 -); - - usb_release_interface(pHDev,0); - usb_close(pHDev); - - - return ERROR_OK; -} - - -struct jtag_interface rlink_interface = -{ - .name = "rlink", - .init = rlink_init, - .quit = rlink_quit, - .speed = rlink_speed, - .speed_div = rlink_speed_div, - .khz = rlink_khz, - .execute_queue = rlink_execute_queue, -}; diff --git a/src/jtag/rlink/rlink.h b/src/jtag/rlink/rlink.h deleted file mode 100644 index b53be5ce..00000000 --- a/src/jtag/rlink/rlink.h +++ /dev/null @@ -1,31 +0,0 @@ -/*************************************************************************** - * 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; diff --git a/src/jtag/rlink/rlink_speed_table.c b/src/jtag/rlink/rlink_speed_table.c deleted file mode 100644 index 2ef62ee3..00000000 --- a/src/jtag/rlink/rlink_speed_table.c +++ /dev/null @@ -1,101 +0,0 @@ -/* 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 "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); - diff --git a/src/jtag/rlink/st7.h b/src/jtag/rlink/st7.h deleted file mode 100644 index 5f337ef1..00000000 --- a/src/jtag/rlink/st7.h +++ /dev/null @@ -1,114 +0,0 @@ -/*************************************************************************** - * 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) diff --git a/src/jtag/usb_common.c b/src/jtag/usb_common.c deleted file mode 100644 index 463f1af9..00000000 --- a/src/jtag/usb_common.c +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Zachary T Welch * - * * - * 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; -} diff --git a/src/jtag/usb_common.h b/src/jtag/usb_common.h deleted file mode 100644 index da395add..00000000 --- a/src/jtag/usb_common.h +++ /dev/null @@ -1,30 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Zachary T Welch * - * * - * 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 - -int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], - struct usb_dev_handle **out); - -#endif // JTAG_USB_COMMON_H diff --git a/src/jtag/usbprog.c b/src/jtag/usbprog.c deleted file mode 100644 index 204d0e2e..00000000 --- a/src/jtag/usbprog.c +++ /dev/null @@ -1,660 +0,0 @@ -/*************************************************************************** - * 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 - }; diff --git a/src/jtag/vsllink.c b/src/jtag/vsllink.c deleted file mode 100644 index cc3308f5..00000000 --- a/src/jtag/vsllink.c +++ /dev/null @@ -1,1903 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 by Simon Qian * - * * - * 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. * - ***************************************************************************/ - -/* Versaloon is a programming tool for multiple MCUs. - * OpenOCD and MSP430 supports are distributed under GPLv2. - * You can find it at http://www.SimonQian.com/en/Versaloon. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "interface.h" -#include "commands.h" -#include "usb_common.h" - -//#define _VSLLINK_IN_DEBUG_MODE_ - -#define VSLLINK_MODE_NORMAL 0 -#define VSLLINK_MODE_DMA 1 - -static uint16_t vsllink_usb_vid; -static uint16_t vsllink_usb_pid; -static uint8_t vsllink_usb_bulkout; -static uint8_t vsllink_usb_bulkin; -static uint8_t vsllink_usb_interface; -static uint8_t vsllink_mode = VSLLINK_MODE_NORMAL; -static int VSLLINK_USB_TIMEOUT = 10000; - -static int VSLLINK_BufferSize = 1024; - -/* Global USB buffers */ -static int vsllink_usb_out_buffer_idx; -static int vsllink_usb_in_want_length; -static uint8_t* vsllink_usb_in_buffer = NULL; -static uint8_t* vsllink_usb_out_buffer = NULL; - -/* Constants for VSLLink command */ -#define VSLLINK_CMD_CONN 0x80 -#define VSLLINK_CMD_DISCONN 0x81 -#define VSLLINK_CMD_SET_SPEED 0x82 -#define VSLLINK_CMD_SET_PORT 0x90 -#define VSLLINK_CMD_GET_PORT 0x91 -#define VSLLINK_CMD_SET_PORTDIR 0x92 -#define VSLLINK_CMD_HW_JTAGSEQCMD 0xA0 -#define VSLLINK_CMD_HW_JTAGHLCMD 0xA1 -#define VSLLINK_CMD_HW_SWDCMD 0xA2 -#define VSLLINK_CMD_HW_JTAGRAWCMD 0xA3 - -#define VSLLINK_CMDJTAGSEQ_TMSBYTE 0x00 -#define VSLLINK_CMDJTAGSEQ_TMSCLOCK 0x40 -#define VSLLINK_CMDJTAGSEQ_SCAN 0x80 - -#define VSLLINK_CMDJTAGSEQ_CMDMSK 0xC0 -#define VSLLINK_CMDJTAGSEQ_LENMSK 0x3F - -#define JTAG_PINMSK_SRST (1 << 0) -#define JTAG_PINMSK_TRST (1 << 1) -#define JTAG_PINMSK_USR1 (1 << 2) -#define JTAG_PINMSK_USR2 (1 << 3) -#define JTAG_PINMSK_TCK (1 << 4) -#define JTAG_PINMSK_TMS (1 << 5) -#define JTAG_PINMSK_TDI (1 << 6) -#define JTAG_PINMSK_TDO (1 << 7) - - -#define VSLLINK_TAP_MOVE(from, to) VSLLINK_tap_move[tap_move_ndx(from)][tap_move_ndx(to)] - -/* VSLLINK_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 - * - * SD->SD and SI->SI have to be caught in interface specific code - */ -static uint8_t VSLLINK_tap_move[6][6] = -{ -/* TLR RTI SD PD SI PI */ - {0xff, 0x7f, 0x2f, 0x0a, 0x37, 0x16}, /* TLR */ - {0xff, 0x00, 0x45, 0x05, 0x4b, 0x0b}, /* RTI */ - {0xff, 0x61, 0x00, 0x01, 0x0f, 0x2f}, /* SD */ - {0xfe, 0x60, 0x40, 0x5c, 0x3c, 0x5e}, /* PD */ - {0xff, 0x61, 0x07, 0x17, 0x00, 0x01}, /* SI */ - {0xfe, 0x60, 0x38, 0x5c, 0x40, 0x5e} /* PI */ -}; - -struct insert_insignificant_operation { - unsigned char insert_value; - unsigned char insert_position; -}; - -static struct insert_insignificant_operation VSLLINK_TAP_MOVE_INSERT_INSIGNIFICANT[6][6] = -{ -/* stuff offset */ - {/* TLR */ - {1, 0,}, /* TLR */ - {1, 0,}, /* RTI */ - {1, 0,}, /* SD */ - {1, 0,}, /* PD */ - {1, 0,}, /* SI */ - {1, 0,}}, /* PI */ - {/* RTI */ - {1, 0,}, /* TLR */ - {0, 0,}, /* RTI */ - {0, 4,}, /* SD */ - {0, 7,}, /* PD */ - {0, 5,}, /* SI */ - {0, 7,}}, /* PI */ - {/* SD */ - {0, 0,}, /* TLR */ - {0, 0,}, /* RTI */ - {0, 0,}, /* SD */ - {0, 0,}, /* PD */ - {0, 0,}, /* SI */ - {0, 0,}}, /* PI */ - {/* PD */ - {0, 0,}, /* TLR */ - {0, 0,}, /* RTI */ - {0, 0,}, /* SD */ - {0, 0,}, /* PD */ - {0, 0,}, /* SI */ - {0, 0,}}, /* PI */ - {/* SI */ - {0, 0,}, /* TLR */ - {0, 0,}, /* RTI */ - {0, 0,}, /* SD */ - {0, 0,}, /* PD */ - {0, 0,}, /* SI */ - {0, 0,}}, /* PI */ - {/* PI */ - {0, 0,}, /* TLR */ - {0, 0,}, /* RTI */ - {0, 0,}, /* SD */ - {0, 0,}, /* PD */ - {0, 0,}, /* SI */ - {0, 0,}}, /* PI */ -}; - -static uint8_t VSLLINK_BIT_MSK[8] = -{ - 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f -}; - -struct pending_scan_result { - int offset; - 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]; - -/* Queue command functions */ -static void vsllink_end_state(tap_state_t state); -static void vsllink_state_move_dma(void); -static void vsllink_state_move_normal(void); -static void (*vsllink_state_move)(void); -static void vsllink_path_move_dma(int num_states, tap_state_t *path); -static void vsllink_path_move_normal(int num_states, tap_state_t *path); -static void (*vsllink_path_move)(int num_states, tap_state_t *path); -static void vsllink_runtest(int num_cycles); -static void vsllink_stableclocks_dma(int num_cycles, int tms); -static void vsllink_stableclocks_normal(int num_cycles, int tms); -static void (*vsllink_stableclocks)(int num_cycles, int tms); -static void vsllink_scan_dma(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); -static void vsllink_scan_normal(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); -static void (*vsllink_scan)(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); -static void vsllink_reset(int trst, int srst); -static void vsllink_simple_command(uint8_t command); -static int vsllink_connect(void); -static int vsllink_disconnect(void); - -/* VSLLink tap buffer functions */ -static void vsllink_tap_append_step(int tms, int tdi); -static void vsllink_tap_init_dma(void); -static void vsllink_tap_init_normal(void); -static void (*vsllink_tap_init)(void); -static int vsllink_tap_execute_dma(void); -static int vsllink_tap_execute_normal(void); -static int (*vsllink_tap_execute)(void); -static void vsllink_tap_ensure_space_dma(int scans, int length); -static void vsllink_tap_ensure_space_normal(int scans, int length); -static void (*vsllink_tap_ensure_space)(int scans, int length); -static void vsllink_tap_append_scan_dma(int length, uint8_t *buffer, struct scan_command *command); -static void vsllink_tap_append_scan_normal(int length, uint8_t *buffer, struct scan_command *command, int offset); - -/* VSLLink lowlevel functions */ -struct vsllink { - struct usb_dev_handle* usb_handle; -}; - -static struct vsllink *vsllink_usb_open(void); -static void vsllink_usb_close(struct vsllink *vsllink); -static int vsllink_usb_message(struct vsllink *vsllink, int out_length, int in_length); -static int vsllink_usb_write(struct vsllink *vsllink, int out_length); -static int vsllink_usb_read(struct vsllink *vsllink); - -#if defined _DEBUG_USB_COMMS_ || defined _DEBUG_JTAG_IO_ -static void vsllink_debug_buffer(uint8_t *buffer, int length); -#endif - -static int vsllink_tms_data_len = 0; -static uint8_t* vsllink_tms_cmd_pos; - -static int tap_length = 0; -static int tap_buffer_size = 0; -static uint8_t *tms_buffer = NULL; -static uint8_t *tdi_buffer = NULL; -static uint8_t *tdo_buffer = NULL; -static int last_tms; - -static struct vsllink* vsllink_handle = NULL; - -static void reset_command_pointer(void) -{ - if (vsllink_mode == VSLLINK_MODE_NORMAL) - { - vsllink_usb_out_buffer[0] = VSLLINK_CMD_HW_JTAGSEQCMD; - vsllink_usb_out_buffer_idx = 3; - } - else - { - tap_length = 0; - } -} - -static int vsllink_execute_queue(void) -{ - struct jtag_command *cmd = jtag_command_queue; - int scan_size; - enum scan_type type; - uint8_t *buffer; - - DEBUG_JTAG_IO("--------------------------------- vsllink -------------------------------------"); - - reset_command_pointer(); - while (cmd != NULL) - { - switch (cmd->type) - { - case JTAG_RUNTEST: - DEBUG_JTAG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, \ - tap_state_name(cmd->cmd.runtest->end_state)); - - vsllink_end_state(cmd->cmd.runtest->end_state); - vsllink_runtest(cmd->cmd.runtest->num_cycles); - break; - - case JTAG_STATEMOVE: - DEBUG_JTAG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); - - vsllink_end_state(cmd->cmd.statemove->end_state); - vsllink_state_move(); - break; - - case JTAG_PATHMOVE: - DEBUG_JTAG_IO("pathmove: %i states, end in %s", \ - cmd->cmd.pathmove->num_states, \ - tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); - - vsllink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); - break; - - case JTAG_SCAN: - vsllink_end_state(cmd->cmd.scan->end_state); - - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - if (cmd->cmd.scan->ir_scan) - { - DEBUG_JTAG_IO("JTAG Scan write IR(%d bits), end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); - } - else - { - DEBUG_JTAG_IO("JTAG Scan write DR(%d bits), end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); - } - -#ifdef _DEBUG_JTAG_IO_ - vsllink_debug_buffer(buffer, (scan_size + 7) >> 3); -#endif - - type = jtag_scan_type(cmd->cmd.scan); - - vsllink_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); - - vsllink_tap_execute(); - - if (cmd->cmd.reset->trst == 1) - { - tap_set_state(TAP_RESET); - } - vsllink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - - case JTAG_SLEEP: - DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); - vsllink_tap_execute(); - jtag_sleep(cmd->cmd.sleep->us); - break; - - case JTAG_STABLECLOCKS: - DEBUG_JTAG_IO("add %d clocks", cmd->cmd.stableclocks->num_cycles); - switch (tap_get_state()) - { - case TAP_RESET: - // tms should be '1' to stay in TAP_RESET mode - scan_size = 1; - break; - case TAP_DRSHIFT: - case TAP_IDLE: - case TAP_DRPAUSE: - case TAP_IRSHIFT: - case TAP_IRPAUSE: - // in other mode, tms should be '0' - scan_size = 0; - break; /* above stable states are OK */ - default: - LOG_ERROR("jtag_add_clocks() was called with TAP in non-stable state \"%s\"", - tap_state_name(tap_get_state())); - exit(-1); - } - vsllink_stableclocks(cmd->cmd.stableclocks->num_cycles, scan_size); - break; - - default: - LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); - exit(-1); - } - cmd = cmd->next; - } - - return vsllink_tap_execute(); -} - -static int vsllink_speed(int speed) -{ - int result; - - vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_SPEED; - vsllink_usb_out_buffer[1] = (speed >> 0) & 0xff; - vsllink_usb_out_buffer[2] = (speed >> 8) & 0xFF; - - result = vsllink_usb_write(vsllink_handle, 3); - - if (result == 3) - { - return ERROR_OK; - } - else - { - LOG_ERROR("VSLLink setting speed failed (%d)", result); - return ERROR_JTAG_DEVICE_ERROR; - } - - return ERROR_OK; -} - -static int vsllink_khz(int khz, int *jtag_speed) -{ - *jtag_speed = khz; - - return ERROR_OK; -} - -static int vsllink_speed_div(int jtag_speed, int *khz) -{ - *khz = jtag_speed; - - return ERROR_OK; -} - -static int vsllink_init(void) -{ - int check_cnt, to_tmp; - int result; - char version_str[100]; - - vsllink_usb_in_buffer = malloc(VSLLINK_BufferSize); - vsllink_usb_out_buffer = malloc(VSLLINK_BufferSize); - if ((vsllink_usb_in_buffer == NULL) || (vsllink_usb_out_buffer == NULL)) - { - LOG_ERROR("Not enough memory"); - exit(-1); - } - - vsllink_handle = vsllink_usb_open(); - - if (vsllink_handle == 0) - { - LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); - return ERROR_JTAG_INIT_FAILED; - } - LOG_DEBUG("vsllink found on %04X:%04X", vsllink_usb_vid, vsllink_usb_pid); - - to_tmp = VSLLINK_USB_TIMEOUT; - VSLLINK_USB_TIMEOUT = 100; - check_cnt = 0; - while (check_cnt < 5) - { - vsllink_simple_command(0x00); - result = vsllink_usb_read(vsllink_handle); - - if (result > 2) - { - vsllink_usb_in_buffer[result] = 0; - VSLLINK_BufferSize = vsllink_usb_in_buffer[0] + (vsllink_usb_in_buffer[1] << 8); - strncpy(version_str, (char *)vsllink_usb_in_buffer + 2, sizeof(version_str)); - LOG_INFO("%s", version_str); - - // free the pre-alloc memroy - free(vsllink_usb_in_buffer); - free(vsllink_usb_out_buffer); - vsllink_usb_in_buffer = NULL; - vsllink_usb_out_buffer = NULL; - - // alloc new memory - vsllink_usb_in_buffer = malloc(VSLLINK_BufferSize); - vsllink_usb_out_buffer = malloc(VSLLINK_BufferSize); - if ((vsllink_usb_in_buffer == NULL) || (vsllink_usb_out_buffer == NULL)) - { - LOG_ERROR("Not enough memory"); - exit(-1); - } - else - { - LOG_INFO("buffer size for USB is %d bytes", VSLLINK_BufferSize); - } - // alloc memory for dma mode - if (vsllink_mode == VSLLINK_MODE_DMA) - { - tap_buffer_size = (VSLLINK_BufferSize - 3) / 2; - tms_buffer = (uint8_t*)malloc(tap_buffer_size); - tdi_buffer = (uint8_t*)malloc(tap_buffer_size); - tdo_buffer = (uint8_t*)malloc(tap_buffer_size); - if ((tms_buffer == NULL) || (tdi_buffer == NULL) || (tdo_buffer == NULL)) - { - LOG_ERROR("Not enough memory"); - exit(-1); - } - } - break; - } - vsllink_simple_command(VSLLINK_CMD_DISCONN); - check_cnt++; - } - if (check_cnt == 3) - { - // It's dangerout to proced - LOG_ERROR("VSLLink initial failed"); - exit(-1); - } - VSLLINK_USB_TIMEOUT = to_tmp; - - // connect to vsllink - vsllink_connect(); - // initialize function pointers - if (vsllink_mode == VSLLINK_MODE_NORMAL) - { - // normal mode - vsllink_state_move = vsllink_state_move_normal; - vsllink_path_move = vsllink_path_move_normal; - vsllink_stableclocks = vsllink_stableclocks_normal; - vsllink_scan = vsllink_scan_normal; - - vsllink_tap_init = vsllink_tap_init_normal; - vsllink_tap_execute = vsllink_tap_execute_normal; - vsllink_tap_ensure_space = vsllink_tap_ensure_space_normal; - - LOG_INFO("vsllink run in NORMAL mode"); - } - else - { - // dma mode - vsllink_state_move = vsllink_state_move_dma; - vsllink_path_move = vsllink_path_move_dma; - vsllink_stableclocks = vsllink_stableclocks_dma; - vsllink_scan = vsllink_scan_dma; - - vsllink_tap_init = vsllink_tap_init_dma; - vsllink_tap_execute = vsllink_tap_execute_dma; - vsllink_tap_ensure_space = vsllink_tap_ensure_space_dma; - - LOG_INFO("vsllink run in DMA mode"); - } - - // Set SRST and TRST to output, Set USR1 and USR2 to input - vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_PORTDIR; - vsllink_usb_out_buffer[1] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST | JTAG_PINMSK_USR1 | JTAG_PINMSK_USR2; - vsllink_usb_out_buffer[2] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST; - if (vsllink_usb_write(vsllink_handle, 3) != 3) - { - LOG_ERROR("VSLLink USB send data error"); - exit(-1); - } - - vsllink_reset(0, 0); - - LOG_INFO("VSLLink JTAG Interface ready"); - - vsllink_tap_init(); - - return ERROR_OK; -} - -static int vsllink_quit(void) -{ - if ((vsllink_usb_in_buffer != NULL) && (vsllink_usb_out_buffer != NULL)) - { - // Set all pins to input - vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_PORTDIR; - vsllink_usb_out_buffer[1] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST | JTAG_PINMSK_USR1 | JTAG_PINMSK_USR2; - vsllink_usb_out_buffer[2] = 0; - if (vsllink_usb_write(vsllink_handle, 3) != 3) - { - LOG_ERROR("VSLLink USB send data error"); - exit(-1); - } - - // disconnect - vsllink_disconnect(); - vsllink_usb_close(vsllink_handle); - vsllink_handle = NULL; - } - - if (vsllink_usb_in_buffer != NULL) - { - free(vsllink_usb_in_buffer); - vsllink_usb_in_buffer = NULL; - } - if (vsllink_usb_out_buffer != NULL) - { - free(vsllink_usb_out_buffer); - vsllink_usb_out_buffer = NULL; - } - - return ERROR_OK; -} - -/***************************************************************************/ -/* Queue command implementations */ -static int vsllink_disconnect(void) -{ - vsllink_simple_command(VSLLINK_CMD_DISCONN); - return ERROR_OK; -} - -static int vsllink_connect(void) -{ - char vsllink_str[100]; - - vsllink_usb_out_buffer[0] = VSLLINK_CMD_CONN; - vsllink_usb_out_buffer[1] = vsllink_mode; - vsllink_usb_message(vsllink_handle, 2, 0); - if (vsllink_usb_read(vsllink_handle) > 2) - { - strncpy(vsllink_str, (char *)vsllink_usb_in_buffer + 2, sizeof(vsllink_str)); - LOG_INFO("%s", vsllink_str); - } - - return ERROR_OK; -} - -// when vsllink_tms_data_len > 0, vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] is the byte that need to be appended. -// length of VSLLINK_CMDJTAGSEQ_TMSBYTE has been set, no need to set it here. -static void vsllink_append_tms(void) -{ - uint8_t tms_scan = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); - uint16_t tms2; - struct insert_insignificant_operation *insert = \ - &VSLLINK_TAP_MOVE_INSERT_INSIGNIFICANT[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())]; - - if (((tap_get_state() != TAP_RESET) && (tap_get_state() != TAP_IDLE) && (tap_get_state() != TAP_DRPAUSE) && (tap_get_state() != TAP_IRPAUSE)) || \ - (vsllink_tms_data_len <= 0) || (vsllink_tms_data_len >= 8) || \ - (vsllink_tms_cmd_pos == NULL)) - { - LOG_ERROR("There MUST be some bugs in the driver"); - exit(-1); - } - - tms2 = (tms_scan & VSLLINK_BIT_MSK[insert->insert_position]) << \ - vsllink_tms_data_len; - if (insert->insert_value == 1) - { - tms2 |= VSLLINK_BIT_MSK[8 - vsllink_tms_data_len] << \ - (vsllink_tms_data_len + insert->insert_position); - } - tms2 |= (tms_scan >> insert->insert_position) << \ - (8 + insert->insert_position); - - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (tms2 >> 0) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms2 >> 8) & 0xff; - - vsllink_tms_data_len = 0; - vsllink_tms_cmd_pos = NULL; -} - -static void vsllink_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 vsllink_state_move_normal(void) -{ - if (vsllink_tms_data_len > 0) - { - vsllink_append_tms(); - } - else - { - vsllink_tap_ensure_space(0, 2); - - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); - } - - tap_set_state(tap_get_end_state()); -} -static void vsllink_state_move_dma(void) -{ - int i, insert_length = (tap_length % 8) ? (8 - (tap_length % 8)) : 0; - struct insert_insignificant_operation *insert = \ - &VSLLINK_TAP_MOVE_INSERT_INSIGNIFICANT[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())]; - uint8_t tms_scan = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); - - if (tap_get_state() == TAP_RESET) - { - vsllink_tap_ensure_space(0, 8); - - for (i = 0; i < 8; i++) - { - vsllink_tap_append_step(1, 0); - } - } - - if (insert_length > 0) - { - vsllink_tap_ensure_space(0, 16); - - for (i = 0; i < insert->insert_position; i++) - { - vsllink_tap_append_step((tms_scan >> i) & 1, 0); - } - for (i = 0; i < insert_length; i++) - { - vsllink_tap_append_step(insert->insert_value, 0); - } - for (i = insert->insert_position; i < 8; i++) - { - vsllink_tap_append_step((tms_scan >> i) & 1, 0); - } - } - else - { - vsllink_tap_ensure_space(0, 8); - - for (i = 0; i < 8; i++) - { - vsllink_tap_append_step((tms_scan >> i) & 1, 0); - } - } - - tap_set_state(tap_get_end_state()); -} - -// write tms from current vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] -static void vsllink_add_path(int start, int num, tap_state_t *path) -{ - int i; - - for (i = start; i < (start + num); i++) - { - if ((i & 7) == 0) - { - if (i > 0) - { - vsllink_usb_out_buffer_idx++; - } - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = 0; - } - - if (path[i - start] == tap_state_transition(tap_get_state(), true)) - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] |= 1 << (i & 7); - } - else if (path[i - start] == tap_state_transition(tap_get_state(), false)) - { - // nothing to do - } - 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 - start]); - } - if ((i > 0) && ((i & 7) == 0)) - { - vsllink_usb_out_buffer_idx++; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = 0; - } - - tap_set_end_state(tap_get_state()); -} - -static void vsllink_path_move_normal(int num_states, tap_state_t *path) -{ - int i, tms_len, tms_cmd_pos, path_idx = 0; - - if (vsllink_tms_data_len > 0) - { - // there are vsllink_tms_data_len more tms bits to be shifted - // so there are vsllink_tms_data_len + num_states tms bits in all - tms_len = vsllink_tms_data_len + num_states; - if (tms_len <= 16) - { - // merge into last tms shift - if (tms_len < 8) - { - // just append tms data to the last tms byte - vsllink_add_path(vsllink_tms_data_len, num_states, path); - } - else if (tms_len == 8) - { - // end last tms shift command - (*vsllink_tms_cmd_pos)--; - vsllink_add_path(vsllink_tms_data_len, num_states, path); - } - else if (tms_len < 16) - { - if ((*vsllink_tms_cmd_pos & VSLLINK_CMDJTAGSEQ_LENMSK) < VSLLINK_CMDJTAGSEQ_LENMSK) - { - // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most - // there is enought tms length in the current tms shift command - (*vsllink_tms_cmd_pos)++; - vsllink_add_path(vsllink_tms_data_len, num_states, path); - } - else - { - // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most - // not enough tms length in the current tms shift command - // so a new command should be added - // first decrease byte length of last tms shift command - (*vsllink_tms_cmd_pos)--; - // append tms data to the last tms byte - vsllink_add_path(vsllink_tms_data_len, 8 - vsllink_tms_data_len, path); - path += 8 - vsllink_tms_data_len; - // add new command(3 bytes) - vsllink_tap_ensure_space(0, 3); - vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; - vsllink_add_path(0, num_states - (8 - vsllink_tms_data_len), path); - } - } - else if (tms_len == 16) - { - // end last tms shift command - vsllink_add_path(vsllink_tms_data_len, num_states, path); - } - - vsllink_tms_data_len = (vsllink_tms_data_len + num_states) & 7; - if (vsllink_tms_data_len == 0) - { - vsllink_tms_cmd_pos = NULL; - } - num_states = 0; - } - else - { - vsllink_add_path(vsllink_tms_data_len, 16 - vsllink_tms_data_len, path); - - path += 16 - vsllink_tms_data_len; - num_states -= 16 - vsllink_tms_data_len; - vsllink_tms_data_len = 0; - vsllink_tms_cmd_pos = NULL; - } - } - - if (num_states > 0) - { - // Normal operation, don't need to append tms data - vsllink_tms_data_len = num_states & 7; - - while (num_states > 0) - { - if (num_states > ((VSLLINK_CMDJTAGSEQ_LENMSK + 1) * 8)) - { - i = (VSLLINK_CMDJTAGSEQ_LENMSK + 1) * 8; - } - else - { - i = num_states; - } - tms_len = (i + 7) >> 3; - vsllink_tap_ensure_space(0, tms_len + 2); - tms_cmd_pos = vsllink_usb_out_buffer_idx; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | (tms_len - 1); - - vsllink_add_path(0, i, path + path_idx); - - path_idx += i; - num_states -= i; - } - - if (vsllink_tms_data_len > 0) - { - if (tms_len < (VSLLINK_CMDJTAGSEQ_LENMSK + 1)) - { - vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[tms_cmd_pos]; - (*vsllink_tms_cmd_pos)++; - } - else - { - vsllink_usb_out_buffer[tms_cmd_pos]--; - - tms_len = vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; - vsllink_tap_ensure_space(0, 3); - vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = tms_len; - } - } - } -} -static void vsllink_path_move_dma(int num_states, tap_state_t *path) -{ - int i, j = 0; - - if (tap_length & 7) - { - if ((8 - (tap_length & 7)) < num_states) - { - j = 8 - (tap_length & 7); - } - else - { - j = num_states; - } - for (i = 0; i < j; i++) - { - if (path[i] == tap_state_transition(tap_get_state(), false)) - { - vsllink_tap_append_step(0, 0); - } - else if (path[i] == tap_state_transition(tap_get_state(), true)) - { - vsllink_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]); - } - num_states -= j; - } - - if (num_states > 0) - { - vsllink_tap_ensure_space(0, num_states); - - for (i = 0; i < num_states; i++) - { - if (path[j + i] == tap_state_transition(tap_get_state(), false)) - { - vsllink_tap_append_step(0, 0); - } - else if (path[j + i] == tap_state_transition(tap_get_state(), true)) - { - vsllink_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[j + i]); - } - } - - tap_set_end_state(tap_get_state()); -} - -static void vsllink_stableclocks_normal(int num_cycles, int tms) -{ - int tms_len; - uint16_t tms_append_byte; - - if (vsllink_tms_data_len > 0) - { - // there are vsllink_tms_data_len more tms bits to be shifted - // so there are vsllink_tms_data_len + num_cycles tms bits in all - tms_len = vsllink_tms_data_len + num_cycles; - if (tms > 0) - { - // append '1' for tms - tms_append_byte = (uint16_t)((((1 << num_cycles) - 1) << vsllink_tms_data_len) & 0xFFFF); - } - else - { - // append '0' for tms - tms_append_byte = 0; - } - if (tms_len <= 16) - { - // merge into last tms shift - if (tms_len < 8) - { - // just add to vsllink_tms_data_len - // same result if tun through - //vsllink_tms_data_len += num_cycles; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] |= (uint8_t)(tms_append_byte & 0xFF); - } - else if (tms_len == 8) - { - // end last tms shift command - // just reduce it, and append last tms byte - (*vsllink_tms_cmd_pos)--; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); - } - else if (tms_len < 16) - { - if ((*vsllink_tms_cmd_pos & VSLLINK_CMDJTAGSEQ_LENMSK) < VSLLINK_CMDJTAGSEQ_LENMSK) - { - // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most - // there is enought tms length in the current tms shift command - // increase the tms byte length by 1 and set the last byte to 0 - (*vsllink_tms_cmd_pos)++; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = (uint8_t)(tms_append_byte >> 8); - } - else - { - // every tms shift command can contain VSLLINK_CMDJTAGSEQ_LENMSK + 1 bytes in most - // not enough tms length in the current tms shift command - // so a new command should be added - // first decrease byte length of last tms shift command - (*vsllink_tms_cmd_pos)--; - // append last tms byte and move the command pointer to the next empty position - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); - // add new command(3 bytes) - vsllink_tap_ensure_space(0, 3); - vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = (uint8_t)(tms_append_byte >> 8); - } - } - else if (tms_len == 16) - { - // end last tms shift command - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (uint8_t)(tms_append_byte >> 8); - } - - vsllink_tms_data_len = tms_len & 7; - if (vsllink_tms_data_len == 0) - { - vsllink_tms_cmd_pos = NULL; - } - num_cycles = 0; - } - else - { - // more shifts will be needed - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= (uint8_t)(tms_append_byte & 0xFF); - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (uint8_t)(tms_append_byte >> 8); - - num_cycles -= 16 - vsllink_tms_data_len; - vsllink_tms_data_len = 0; - vsllink_tms_cmd_pos = NULL; - } - } - // from here vsllink_tms_data_len == 0 or num_cycles == 0 - - if (vsllink_tms_data_len > 0) - { - // num_cycles == 0 - // no need to shift - if (num_cycles > 0) - { - LOG_ERROR("There MUST be some bugs in the driver"); - exit(-1); - } - } - else - { - // get number of bytes left to be sent - tms_len = num_cycles >> 3; - if (tms_len > 0) - { - vsllink_tap_ensure_space(1, 5); - // if tms_len > 0, vsllink_tms_data_len == 0 - // so just add new command - // LSB of the command byte is the tms value when do the shifting - if (tms > 0) - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSCLOCK | 1; - } - else - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSCLOCK; - } - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 0) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 8) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 16) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tms_len >> 24) & 0xff; - - vsllink_usb_in_want_length += 1; - pending_scan_results_buffer[pending_scan_results_length].buffer = NULL; - pending_scan_results_length++; - - if (tms_len > 0xFFFF) - { - vsllink_tap_execute(); - } - } - - // post-process - vsllink_tms_data_len = num_cycles & 7; - if (vsllink_tms_data_len > 0) - { - vsllink_tap_ensure_space(0, 3); - vsllink_tms_cmd_pos = &vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_TMSBYTE | 1; - if (tms > 0) - { - // append '1' for tms - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = (1 << vsllink_tms_data_len) - 1; - } - else - { - // append '0' for tms - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] = 0x00; - } - } - } -} -static void vsllink_stableclocks_dma(int num_cycles, int tms) -{ - int i, cur_cycles; - - if (tap_length & 7) - { - if ((8 - (tap_length & 7)) < num_cycles) - { - cur_cycles = 8 - (tap_length & 7); - } - else - { - cur_cycles = num_cycles; - } - for (i = 0; i < cur_cycles; i++) - { - vsllink_tap_append_step(tms, 0); - } - num_cycles -= cur_cycles; - } - - while (num_cycles > 0) - { - if (num_cycles > 8 * tap_buffer_size) - { - cur_cycles = 8 * tap_buffer_size; - } - else - { - cur_cycles = num_cycles; - } - - vsllink_tap_ensure_space(0, cur_cycles); - - for (i = 0; i < cur_cycles; i++) - { - vsllink_tap_append_step(tms, 0); - } - - num_cycles -= cur_cycles; - } -} - -static void vsllink_runtest(int num_cycles) -{ - tap_state_t saved_end_state = tap_get_end_state(); - - if (tap_get_state() != TAP_IDLE) - { - // enter into IDLE state - vsllink_end_state(TAP_IDLE); - vsllink_state_move(); - } - - vsllink_stableclocks(num_cycles, 0); - - // post-process - // set end_state - vsllink_end_state(saved_end_state); - tap_set_state(TAP_IDLE); - if (tap_get_end_state() != TAP_IDLE) - { - vsllink_state_move(); - } -} - -static void vsllink_scan_normal(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) -{ - tap_state_t saved_end_state; - uint8_t bits_left, tms_tmp, tdi_len; - int i; - - if (0 == scan_size) - { - return; - } - - tdi_len = ((scan_size + 7) >> 3); - if ((tdi_len + 7) > VSLLINK_BufferSize) - { - LOG_ERROR("Your implementation of VSLLink has not enough buffer"); - exit(-1); - } - - saved_end_state = tap_get_end_state(); - - /* Move to appropriate scan state */ - vsllink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); - - if (vsllink_tms_data_len > 0) - { - if (tap_get_state() == tap_get_end_state()) - { - // already in IRSHIFT or DRSHIFT state - // merge tms data in the last tms shift command into next scan command - if (*vsllink_tms_cmd_pos < 1) - { - LOG_ERROR("There MUST be some bugs in the driver"); - exit(-1); - } - else if (*vsllink_tms_cmd_pos < 2) - { - tms_tmp = vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; - vsllink_usb_out_buffer_idx--; - } - else - { - tms_tmp = vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx]; - *vsllink_tms_cmd_pos -= 2; - } - - vsllink_tap_ensure_space(1, tdi_len + 7); - // VSLLINK_CMDJTAGSEQ_SCAN ored by 1 means that tms_before is valid - // which is merged from the last tms shift command - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_SCAN | 1; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1) >> 0) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1) >> 8) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = tms_tmp; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = buffer[0] << (8 - vsllink_tms_data_len); - - for (i = 0; i < tdi_len; i++) - { - buffer[i] >>= 8 - vsllink_tms_data_len; - if (i != tdi_len) - { - buffer[i] += buffer[i + 1] << vsllink_tms_data_len; - } - } - - vsllink_tap_append_scan_normal(scan_size - vsllink_tms_data_len, buffer, command, vsllink_tms_data_len); - scan_size -= 8 - vsllink_tms_data_len; - vsllink_tms_data_len = 0; - } - else - { - vsllink_state_move(); - vsllink_tap_ensure_space(1, tdi_len + 5); - - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_SCAN; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tdi_len >> 0) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = (tdi_len >> 8) & 0xff; - - vsllink_tap_append_scan_normal(scan_size, buffer, command, 0); - } - } - else - { - vsllink_tap_ensure_space(1, tdi_len + 7); - - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_CMDJTAGSEQ_SCAN | 1; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1) >> 0) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = ((tdi_len + 1)>> 8) & 0xff; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0; - - vsllink_tap_append_scan_normal(scan_size, buffer, command, 8); - } - vsllink_end_state(saved_end_state); - - bits_left = scan_size & 0x07; - tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); - - if (bits_left > 0) - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 1 << (bits_left - 1); - } - else - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 1 << 7; - } - - if (tap_get_state() != tap_get_end_state()) - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = VSLLINK_TAP_MOVE(tap_get_state(), tap_get_end_state()); - } - else - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0; - } - - tap_set_state(tap_get_end_state()); -} -static void vsllink_scan_dma(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) -{ - tap_state_t saved_end_state; - - saved_end_state = tap_get_end_state(); - - /* Move to appropriate scan state */ - vsllink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); - - vsllink_state_move(); - vsllink_end_state(saved_end_state); - - /* Scan */ - vsllink_tap_append_scan_dma(scan_size, buffer, command); - - tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); - while (tap_length % 8 != 0) - { - // more 0s in Pause - vsllink_tap_append_step(0, 0); - } - - if (tap_get_state() != tap_get_end_state()) - { - vsllink_state_move(); - } -} - -static void vsllink_reset(int trst, int srst) -{ - int result; - - LOG_DEBUG("trst: %i, srst: %i", trst, srst); - - /* Signals are active low */ - vsllink_usb_out_buffer[0] = VSLLINK_CMD_SET_PORT; - vsllink_usb_out_buffer[1] = JTAG_PINMSK_SRST | JTAG_PINMSK_TRST; - vsllink_usb_out_buffer[2] = 0; - if (srst == 0) - { - vsllink_usb_out_buffer[2] |= JTAG_PINMSK_SRST; - } - if (trst == 0) - { - vsllink_usb_out_buffer[2] |= JTAG_PINMSK_TRST; - } - - result = vsllink_usb_write(vsllink_handle, 3); - if (result != 3) - { - LOG_ERROR("VSLLink command VSLLINK_CMD_SET_PORT failed (%d)", result); - } -} - -static void vsllink_simple_command(uint8_t command) -{ - int result; - - DEBUG_JTAG_IO("0x%02x", command); - - vsllink_usb_out_buffer[0] = command; - result = vsllink_usb_write(vsllink_handle, 1); - - if (result != 1) - { - LOG_ERROR("VSLLink command 0x%02x failed (%d)", command, result); - } -} - -COMMAND_HANDLER(vsllink_handle_mode_command) -{ - if (CMD_ARGC != 1) { - LOG_ERROR("parameter error, should be one parameter for VID"); - return ERROR_FAIL; - } - - if (!strcmp(CMD_ARGV[0], "normal")) - { - vsllink_mode = VSLLINK_MODE_NORMAL; - } - else if (!strcmp(CMD_ARGV[0], "dma")) - { - vsllink_mode = VSLLINK_MODE_DMA; - } - else - { - LOG_ERROR("invalid vsllink_mode: %s", CMD_ARGV[0]); - return ERROR_FAIL; - } - - return ERROR_OK; -} - -COMMAND_HANDLER(vsllink_handle_usb_vid_command) -{ - if (CMD_ARGC != 1) - { - LOG_ERROR("parameter error, should be one parameter for VID"); - return ERROR_OK; - } - - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], vsllink_usb_vid); - return ERROR_OK; -} - -COMMAND_HANDLER(vsllink_handle_usb_pid_command) -{ - if (CMD_ARGC != 1) - { - LOG_ERROR("parameter error, should be one parameter for PID"); - return ERROR_OK; - } - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], vsllink_usb_pid); - return ERROR_OK; -} - -COMMAND_HANDLER(vsllink_handle_usb_bulkin_command) -{ - if (CMD_ARGC != 1) - { - LOG_ERROR("parameter error, should be one parameter for BULKIN endpoint"); - return ERROR_OK; - } - - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], vsllink_usb_bulkin); - - vsllink_usb_bulkin |= 0x80; - - return ERROR_OK; -} - -COMMAND_HANDLER(vsllink_handle_usb_bulkout_command) -{ - if (CMD_ARGC != 1) - { - LOG_ERROR("parameter error, should be one parameter for BULKOUT endpoint"); - return ERROR_OK; - } - - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], vsllink_usb_bulkout); - - vsllink_usb_bulkout &= ~0x80; - - return ERROR_OK; -} - -COMMAND_HANDLER(vsllink_handle_usb_interface_command) -{ - if (CMD_ARGC != 1) - { - LOG_ERROR("parameter error, should be one parameter for interface number"); - return ERROR_OK; - } - - COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], vsllink_usb_interface); - return ERROR_OK; -} - -/***************************************************************************/ -/* VSLLink tap functions */ - -static void vsllink_tap_init_normal(void) -{ - vsllink_usb_out_buffer_idx = 0; - vsllink_usb_in_want_length = 0; - pending_scan_results_length = 0; -} -static void vsllink_tap_init_dma(void) -{ - tap_length = 0; - pending_scan_results_length = 0; -} - -static void vsllink_tap_ensure_space_normal(int scans, int length) -{ - int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; - int available_bytes = VSLLINK_BufferSize - vsllink_usb_out_buffer_idx; - - if (scans > available_scans || length > available_bytes) - { - vsllink_tap_execute(); - } -} -static void vsllink_tap_ensure_space_dma(int scans, int length) -{ - int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; - int available_bytes = tap_buffer_size * 8 - tap_length; - - if (scans > available_scans || length > available_bytes) - { - vsllink_tap_execute(); - } -} - -static void vsllink_tap_append_step(int tms, int tdi) -{ - last_tms = tms; - int index = tap_length / 8; - - if (index < 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("buffer overflow, tap_length=%d", tap_length); - } -} - -static void vsllink_tap_append_scan_normal(int length, uint8_t *buffer, struct scan_command *command, int offset) -{ - struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; - int i; - - if (offset > 0) - { - vsllink_usb_in_want_length += ((length + 7) >> 3) + 1; - } - else - { - vsllink_usb_in_want_length += (length + 7) >> 3; - } - pending_scan_result->length = length; - pending_scan_result->offset = offset; - pending_scan_result->command = command; - pending_scan_result->buffer = buffer; - - for (i = 0; i < ((length + 7) >> 3); i++) - { - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = buffer[i]; - } - - pending_scan_results_length++; -} -static void vsllink_tap_append_scan_dma(int length, uint8_t *buffer, struct scan_command *command) -{ - struct pending_scan_result *pending_scan_result; - int len_tmp, len_all, i; - - len_all = 0; - while (len_all < length) - { - if ((length - len_all) > tap_buffer_size * 8) - { - len_tmp = tap_buffer_size * 8; - } - else - { - len_tmp = length - len_all; - } - - vsllink_tap_ensure_space(1, (len_tmp + 7) & ~7); - - pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; - pending_scan_result->offset = tap_length; - pending_scan_result->length = len_tmp; - pending_scan_result->command = command; - pending_scan_result->buffer = buffer + len_all / 8; - - for (i = 0; i < len_tmp; i++) - { - vsllink_tap_append_step(((len_all + i) < length-1 ? 0 : 1), (buffer[(len_all + i)/8] >> ((len_all + i)%8)) & 1); - } - - pending_scan_results_length++; - len_all += len_tmp; - } -} - -/* Pad and send a tap sequence to the device, and receive the answer. - * For the purpose of padding we assume that we are in reset or idle or pause state. */ -static int vsllink_tap_execute_normal(void) -{ - int i; - int result; - int first = 0; - - if (vsllink_tms_data_len > 0) - { - if ((tap_get_state() != TAP_RESET) && (tap_get_state() != TAP_IDLE) && (tap_get_state() != TAP_IRPAUSE) && (tap_get_state() != TAP_DRPAUSE)) - { - LOG_WARNING("%s is not in RESET or IDLE or PAUSR state", tap_state_name(tap_get_state())); - } - - if (vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx] & (1 << (vsllink_tms_data_len - 1))) - { - // last tms bit is '1' - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] |= 0xFF << vsllink_tms_data_len; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0xFF; - vsllink_tms_data_len = 0; - } - else - { - // last tms bit is '0' - vsllink_usb_out_buffer_idx++; - vsllink_usb_out_buffer[vsllink_usb_out_buffer_idx++] = 0; - vsllink_tms_data_len = 0; - } - } - - if (vsllink_usb_out_buffer_idx > 3) - { - if (vsllink_usb_out_buffer[0] == VSLLINK_CMD_HW_JTAGSEQCMD) - { - vsllink_usb_out_buffer[1] = (vsllink_usb_out_buffer_idx >> 0) & 0xff; - vsllink_usb_out_buffer[2] = (vsllink_usb_out_buffer_idx >> 8) & 0xff; - } - - result = vsllink_usb_message(vsllink_handle, vsllink_usb_out_buffer_idx, vsllink_usb_in_want_length); - - if (result == vsllink_usb_in_want_length) - { - 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 offset = pending_scan_result->offset; - struct scan_command *command = pending_scan_result->command; - - if (buffer != NULL) - { - // IRSHIFT or DRSHIFT - buf_set_buf(vsllink_usb_in_buffer, first * 8 + offset, buffer, 0, length); - first += (length + offset + 7) >> 3; - - DEBUG_JTAG_IO("JTAG scan read(%d bits):", length); -#ifdef _DEBUG_JTAG_IO_ - vsllink_debug_buffer(buffer, (length + 7) >> 3); -#endif - - if (jtag_read_buffer(buffer, command) != ERROR_OK) - { - vsllink_tap_init(); - return ERROR_JTAG_QUEUE_FAILED; - } - - free(pending_scan_result->buffer); - pending_scan_result->buffer = NULL; - } - else - { - first++; - } - } - } - else - { - LOG_ERROR("vsllink_tap_execute, wrong result %d, expected %d", result, vsllink_usb_in_want_length); - return ERROR_JTAG_QUEUE_FAILED; - } - - vsllink_tap_init(); - } - reset_command_pointer(); - - return ERROR_OK; -} -static int vsllink_tap_execute_dma(void) -{ - int byte_length; - 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. */ - vsllink_tap_append_step(last_tms, 0); - } - byte_length = tap_length / 8; - - vsllink_usb_out_buffer[0] = VSLLINK_CMD_HW_JTAGRAWCMD; - vsllink_usb_out_buffer[1] = ((byte_length * 2 + 3) >> 0) & 0xff; // package size - vsllink_usb_out_buffer[2] = ((byte_length * 2 + 3) >> 8) & 0xff; - - memcpy(&vsllink_usb_out_buffer[3], tdi_buffer, byte_length); - memcpy(&vsllink_usb_out_buffer[3 + byte_length], tms_buffer, byte_length); - - result = vsllink_usb_message(vsllink_handle, 3 + 2 * byte_length, byte_length); - if (result == byte_length) - { - 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->offset; - - struct scan_command *command = pending_scan_result->command; - buf_set_buf(vsllink_usb_in_buffer, first, buffer, 0, length); - - DEBUG_JTAG_IO("JTAG scan read(%d bits, from %d bits):", length, first); -#ifdef _DEBUG_JTAG_IO_ - vsllink_debug_buffer(buffer, (length + 7) >> 3); -#endif - - if (jtag_read_buffer(buffer, command) != ERROR_OK) - { - vsllink_tap_init(); - return ERROR_JTAG_QUEUE_FAILED; - } - - if (pending_scan_result->buffer != NULL) - { - free(pending_scan_result->buffer); - } - } - } - else - { - LOG_ERROR("vsllink_tap_execute, wrong result %d, expected %d", result, byte_length); - return ERROR_JTAG_QUEUE_FAILED; - } - - vsllink_tap_init(); - } - - return ERROR_OK; -} - -/*****************************************************************************/ -/* VSLLink USB low-level functions */ - -static struct vsllink* vsllink_usb_open(void) -{ - usb_init(); - - const uint16_t vids[] = { vsllink_usb_vid, 0 }; - const uint16_t pids[] = { vsllink_usb_pid, 0 }; - struct usb_dev_handle *dev; - if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) - return NULL; - - /* usb_set_configuration required under win32 */ - struct usb_device *udev = usb_device(dev); - int ret = usb_set_configuration(dev, udev->config[0].bConfigurationValue); - if (ret != 0) - { - LOG_ERROR("fail to set configuration to %d (error %d)." - "Not enough permissions for the device?", - udev->config[0].bConfigurationValue, ret); - return NULL; - } - ret = usb_claim_interface(dev, vsllink_usb_interface); - if (ret != 0) - { - LOG_ERROR("fail to claim interface %d, %d returned", - vsllink_usb_interface, ret); - return NULL; - } -#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 - - struct vsllink *result = malloc(sizeof(struct vsllink)); - result->usb_handle = dev; - return result; -} - -static void vsllink_usb_close(struct vsllink *vsllink) -{ - int ret; - - ret = usb_release_interface(vsllink->usb_handle, vsllink_usb_interface); - if (ret != 0) - { - LOG_ERROR("fail to release interface %d, %d returned", vsllink_usb_interface, ret); - exit(-1); - } - - ret = usb_close(vsllink->usb_handle); - if (ret != 0) - { - LOG_ERROR("fail to close usb, %d returned", ret); - exit(-1); - } - - free(vsllink); -} - -/* Send a message and receive the reply. */ -static int vsllink_usb_message(struct vsllink *vsllink, int out_length, int in_length) -{ - int result; - - result = vsllink_usb_write(vsllink, out_length); - if (result == out_length) - { - if (in_length > 0) - { - result = vsllink_usb_read(vsllink); - if (result == in_length) - { - return result; - } - else - { - LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); - return -1; - } - } - return 0; - } - else - { - LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); - return -1; - } -} - -/* Write data from out_buffer to USB. */ -static int vsllink_usb_write(struct vsllink *vsllink, int out_length) -{ - int result; - - if (out_length > VSLLINK_BufferSize) - { - LOG_ERROR("vsllink_write illegal out_length=%d (max=%d)", out_length, VSLLINK_BufferSize); - return -1; - } - - result = usb_bulk_write(vsllink->usb_handle, vsllink_usb_bulkout, \ - (char *)vsllink_usb_out_buffer, out_length, VSLLINK_USB_TIMEOUT); - - DEBUG_JTAG_IO("vsllink_usb_write, out_length = %d, result = %d", out_length, result); - -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("USB out:"); - vsllink_debug_buffer(vsllink_usb_out_buffer, out_length); -#endif - -#ifdef _VSLLINK_IN_DEBUG_MODE_ - usleep(100000); -#endif - - return result; -} - -/* Read data from USB into in_buffer. */ -static int vsllink_usb_read(struct vsllink *vsllink) -{ - int result = usb_bulk_read(vsllink->usb_handle, vsllink_usb_bulkin, \ - (char *)vsllink_usb_in_buffer, VSLLINK_BufferSize, VSLLINK_USB_TIMEOUT); - - DEBUG_JTAG_IO("vsllink_usb_read, result = %d", result); - -#ifdef _DEBUG_USB_COMMS_ - LOG_DEBUG("USB in:"); - vsllink_debug_buffer(vsllink_usb_in_buffer, result); -#endif - return result; -} - -#define BYTES_PER_LINE 16 - -#if defined _DEBUG_USB_COMMS_ || defined _DEBUG_JTAG_IO_ -static void vsllink_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 // _DEBUG_USB_COMMS_ || _DEBUG_JTAG_IO_ - -static const struct command_registration vsllink_command_handlers[] = { - { - .name = "vsllink_usb_vid", - .handler = &vsllink_handle_usb_vid_command, - .mode = COMMAND_CONFIG, - }, - { - .name = "vsllink_usb_pid", - .handler = &vsllink_handle_usb_pid_command, - .mode = COMMAND_CONFIG, - }, - { - .name = "vsllink_usb_bulkin", - .handler = &vsllink_handle_usb_bulkin_command, - .mode = COMMAND_CONFIG, - }, - { - .name = "vsllink_usb_bulkout", - .handler = &vsllink_handle_usb_bulkout_command, - .mode = COMMAND_CONFIG, - }, - { - .name = "vsllink_usb_interface", - .handler = &vsllink_handle_usb_interface_command, - .mode = COMMAND_CONFIG, - }, - { - .name = "vsllink_mode", - .handler = &vsllink_handle_mode_command, - .mode = COMMAND_CONFIG, - }, - COMMAND_REGISTRATION_DONE -}; - -struct jtag_interface vsllink_interface = { - .name = "vsllink", - .commands = vsllink_command_handlers, - - .init = &vsllink_init, - .quit = &vsllink_quit, - .khz = &vsllink_khz, - .speed = &vsllink_speed, - .speed_div = &vsllink_speed_div, - .execute_queue = &vsllink_execute_queue, - }; -- cgit v1.2.3