This is an automated email from Gerrit.

Peter Lawrence (majbt...@gmail.com) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/4875

-- gerrit

commit 338fb714af71f3c9174f2b00adee2965ad77c24c
Author: Peter Lawrence <majbt...@gmail.com>
Date:   Sun Jan 27 12:01:55 2019 -0600

    drivers/jtag-ap: add JTAG-AP interface
    
    This happened because of SEGGER.  Their tech support demanded $70k to
    consider adding JTAG-AP support (as it turns out J-Link has no such
    functionality whatsoever).
    
    JTAG-AP is part of ARM's ADIv5 specification (IHI 0031).
    
    JTAG-AP allows up to eight distinct legacy JTAG chains to be individually
    accessed over a CoreSight bus.  Nominally, this would be one ARM TAP
    on each port, but this is not a hard requirement.
    
    From OpenOCD's perspective, the target has a "Cortex" (CoreSight) TAP.
    However, each CPU on a JTAG-AP port would be its own "scan_chain" with an
    ARM7/ARM9/ARM11/other TAP on it.
    
    To map this into OpenOCD's architecture, I resorted to running two
    instances of OpenOCD.  The first connects to the target hardware (and uses
    a mem_ap target, if needed, to pacify OpenOCD's need for a target); the
    second uses this source code's interface implementation and connects to
    the first via its TCL port and issues many "apreg" commands.
    
    This is SLOW and only allows debugging of just one JTAG-AP port, but I
    could not find a better way to work within OpenOCD.  The concept of only
    one single JTAG chain (directly associated with a target interface) seems
    deeply woven into the source code fabric of OpenOCD.
    
    On the plus side, this approach has minimal impact on the OpenOCD source
    code for what is considered an "uncommon" feature.
    
    Change-Id: I62652d66a76f618b255100ec8c977ec6f1f0fb7f
    Signed-off-by: Peter Lawrence <majbt...@gmail.com>

diff --git a/configure.ac b/configure.ac
index d4338df..cf5f064 100644
--- a/configure.ac
+++ b/configure.ac
@@ -336,6 +336,10 @@ AS_CASE([$host_os],
     ])
 ])
 
+AC_ARG_ENABLE([jtag-ap],
+  AS_HELP_STRING([--enable-jtag-ap], [Enable building support for JTAG-AP]),
+  [build_jtag_ap=$enableval], [build_jtag_ap=no])
+
 AC_ARG_ENABLE([minidriver_dummy],
   AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]),
   [build_minidriver_dummy=$enableval], [build_minidriver_dummy=no])
@@ -593,6 +597,13 @@ AS_IF([test "x$build_sysfsgpio" = "xyes"], [
   AC_DEFINE([BUILD_SYSFSGPIO], [0], [0 if you don't want SysfsGPIO driver.])
 ])
 
+AS_IF([test "x$build_jtag_ap" = "xyes"], [
+  build_jtag_ap=yes
+  AC_DEFINE([BUILD_JTAG_AP], [1], [1 if you want the JTAG-AP driver.])
+], [
+  AC_DEFINE([BUILD_JTAG_AP], [0], [0 if you don't want JTAG-AP driver.])
+])
+
 AS_IF([test "x$build_target64" = "xyes"], [
   AC_DEFINE([BUILD_TARGET64], [1], [1 if you want 64-bit addresses.])
 ], [
@@ -712,6 +723,7 @@ AM_CONDITIONAL([OOCD_TRACE], [test "x$build_oocd_trace" = 
"xyes"])
 AM_CONDITIONAL([REMOTE_BITBANG], [test "x$build_remote_bitbang" = "xyes"])
 AM_CONDITIONAL([BUSPIRATE], [test "x$build_buspirate" = "xyes"])
 AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"])
+AM_CONDITIONAL([JTAG_AP], [test "x$build_jtag_ap" = "xyes"])
 AM_CONDITIONAL([USE_LIBUSB0], [test "x$use_libusb0" = "xyes"])
 AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"])
 AM_CONDITIONAL([IS_CYGWIN], [test "x$is_cygwin" = "xyes"])
diff --git a/doc/openocd.texi b/doc/openocd.texi
index bede1c8..9a7c175 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -617,6 +617,9 @@ produced, PDF schematics are easily found and it is easy to 
make.
 @* A JTAG driver acting as a client for the JTAG VPI server interface.
 @* Link: @url{http://github.com/fjullien/jtag_vpi}
 
+@item @b{jtag_ap}
+@* A JTAG driver that maps into a single JTAG-AP port
+
 @end itemize
 
 @node About Jim-Tcl
@@ -3130,6 +3133,10 @@ pinout.
 
 @end deffn
 
+@deffn {Interface Driver} {jtag_ap}
+JTAG-AP is a mechanism to allow legacy JTAG devices to be implemented
+within a CoreSight(tm) systen.
+@end deffn
 
 @deffn {Interface Driver} {openjtag}
 OpenJTAG compatible USB adapter.
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index ccef018..cc3940a 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -162,6 +162,9 @@ endif
 if XDS110
 DRIVERFILES += %D%/xds110.c
 endif
+if JTAG_AP
+DRIVERFILES += %D%/jtag-ap.c
+endif
 
 DRIVERHEADERS = \
        %D%/bitbang.h \
diff --git a/src/jtag/drivers/jtag-ap.c b/src/jtag/drivers/jtag-ap.c
new file mode 100644
index 0000000..4cded32
--- /dev/null
+++ b/src/jtag/drivers/jtag-ap.c
@@ -0,0 +1,607 @@
+/***************************************************************************
+ *   Copyright (C) 2019 by Peter Lawrence                                  *
+ *   majbt...@gmail.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, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+/* the thunking TCL socket code at the end borrows heavily from 
remote_bitbang.c
+ * which is Copyright (C) 2011 by Richard Uhler
+ */
+
+/* this code has three sections in this order:
+ * 1) the JTAG-AP interface implementation
+ * 2) struct jtag_interface and command handler definitions
+ * 3) thunking code that maps DAP operations to TCL "apreg" operations
+ */
+
+/*
+ * JTAG-AP is part of ARM's ADIv5 specification (IHI 0031).
+ *
+ * JTAG-AP allows up to eight distinct legacy JTAG chains to be individually
+ * accessed over a CoreSight bus.  Nominally, this would be one ARM TAP
+ * on each port, but this is not a hard requirement.
+ *
+ * To map this into OpenOCD's architecture, I resorted to running two
+ * instances of OpenOCD.  The first connects to the target hardware (and uses
+ * a mem_ap target, if needed, to pacify OpenOCD's need for a target); the
+ * second uses this source code's interface implementation and connects to
+ * the first via its TCL port and issues many "apreg" commands.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/interface.h>
+#include "../target/arm_adi_v5.h"
+
+/* prototypes for code in Section 3 */
+static int jtag_ap_thunk_init(void);
+static int jtag_ap_thunk_quit(void);
+static int jtag_ap_thunk_dap_read(uint32_t reg, uint32_t *value);
+static int jtag_ap_thunk_dap_write(uint32_t reg, uint32_t value);
+
+/*
+ * Section 1: the JTAG-AP interface implementation
+ */
+
+static int jtag_ap_init(void)
+{
+       LOG_INFO("Initializing jtag_ap driver");
+
+       if (ERROR_OK != jtag_ap_thunk_init())
+               return ERROR_FAIL;
+
+       /* there must be one and only one JTAG-AP port selected */
+       uint32_t psel = 0;
+       jtag_ap_thunk_dap_read(JTAG_AP_REG_PSEL, &psel);
+       for (int port = 0; port < 8; port++)
+               if ((1UL << port) == psel)
+                       goto success;
+
+       if (psel)
+               LOG_ERROR("jtag_ap PSEL register must select only one port");
+       else
+               LOG_ERROR("jtag_ap PSEL register is zero; select one port");
+
+       return ERROR_FAIL;
+
+success:
+       LOG_INFO("jtag_ap driver initialized");
+
+       return ERROR_OK;
+}
+
+static int jtag_ap_quit(void)
+{
+       if (ERROR_OK != jtag_ap_thunk_quit())
+               return ERROR_FAIL;
+
+       LOG_INFO("jtag_ap interface quit");
+       return ERROR_OK;
+}
+
+static void jtag_ap_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 jtag_ap_wait_until_ready(int clear_data)
+{
+       uint32_t status = 0;
+       uint32_t data;
+
+       for (;;) {
+               /* read current CSW */
+               if (ERROR_OK != jtag_ap_thunk_dap_read(JTAG_AP_REG_CSW, 
&status))
+                       break;
+
+               /* loop until SERACTV bit of CSR is no longer set */
+               if (status & CSW_SERACTV_MASK)
+                       continue;
+
+               /* if clear_data is set, flush any existing data */
+               if (clear_data && (status & CSW_RFIFOCNT_MASK)) {
+                       /* read an outstanding byte from Response FIFO */
+                       jtag_ap_thunk_dap_read(JTAG_AP_REG_BRFIFO1, &data);
+                       continue;
+               }
+
+               break;
+       }
+}
+
+static void jtag_ap_state_execute(uint32_t tms_scan, uint32_t tms_scan_bits)
+{
+       while (tms_scan_bits) {
+               /* each JTAG-AP TMS command byte can encode up to 5 TMS bits */
+               /* see ARM IHI 0031 Section 9.2.1 for further details */
+               uint32_t chunk_size = (tms_scan_bits > 5) ? 5 : tms_scan_bits;
+               uint32_t encode_len = 1UL << chunk_size;
+               uint32_t command = (tms_scan & (encode_len - 1)) | encode_len;
+
+               jtag_ap_wait_until_ready(1);
+               jtag_ap_thunk_dap_write(JTAG_AP_REG_BWFIFO1, command);
+
+               tms_scan >>= chunk_size;
+               tms_scan_bits -= chunk_size;
+       }
+}
+
+static void jtag_ap_state_move(int skip)
+{
+       uint32_t tms_scan = tap_get_tms_path(tap_get_state(), 
tap_get_end_state());
+       uint32_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), 
tap_get_end_state());
+
+       /* chop off the prescribed number of bits at the beginning */
+       tms_scan >>= skip;
+       tms_scan_bits -= skip;
+
+       jtag_ap_state_execute(tms_scan, tms_scan_bits);
+
+       tap_set_state(tap_get_end_state());
+}
+
+static void jtag_ap_stableclocks(int num_cycles)
+{
+       uint32_t tms_scan = (tap_get_state() == TAP_RESET) ? 0xFFFFFFFF : 0;
+
+       while (num_cycles) {
+               /* 30 rather than 32 bits to be an even multiple of five */
+               uint32_t chunk_size = (num_cycles > 30) ? 30 : num_cycles;
+               jtag_ap_state_execute(tms_scan, chunk_size);
+               num_cycles -= chunk_size;
+       }
+}
+
+static void jtag_ap_cmd_stableclocks(struct jtag_command *cmd)
+{
+       jtag_ap_stableclocks(cmd->cmd.runtest->num_cycles);
+}
+
+static void jtag_ap_cmd_runtest(struct jtag_command *cmd)
+{
+       tap_state_t saved_end_state = tap_get_end_state();
+
+       /* Only do a state_move when we're not already in IDLE. */
+       if (TAP_IDLE != tap_get_state()) {
+               jtag_ap_end_state(TAP_IDLE);
+               jtag_ap_state_move(0);
+       }
+
+       jtag_ap_stableclocks(cmd->cmd.runtest->num_cycles);
+
+       /* Finish in end_state. */
+       jtag_ap_end_state(saved_end_state);
+
+       if (tap_get_state() != tap_get_end_state())
+               jtag_ap_state_move(0);
+}
+
+static void jtag_ap_cmd_statemove(struct jtag_command *cmd)
+{
+       jtag_ap_end_state(cmd->cmd.statemove->end_state);
+       jtag_ap_state_move(0);
+}
+
+static void jtag_ap_cmd_pathmove(struct jtag_command *cmd)
+{
+       int num_states = cmd->cmd.pathmove->num_states;
+       tap_state_t *path = cmd->cmd.pathmove->path;
+       uint32_t tms_scan_bits = 0;
+       uint32_t tms_scan = 0;
+
+       while (num_states--) {
+               if (tap_state_transition(tap_get_state(), true) == *path)
+                       tms_scan |= 1UL << tms_scan_bits;
+               else if (tap_state_transition(tap_get_state(), false) != *path) 
{
+                       LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.",
+                               tap_state_name(tap_get_state()), 
tap_state_name(*path));
+                       exit(-1);
+               }
+
+               tms_scan_bits++;
+               tap_set_state(*path);
+       }
+
+       jtag_ap_state_execute(tms_scan, tms_scan_bits);
+
+       tap_set_end_state(tap_get_state());
+}
+
+static int jtag_ap_cmd_scan(struct jtag_command *cmd)
+{
+       int scan_size, chunk_size;
+       uint8_t *buffer, *buffer_ptr;
+       int retval = ERROR_OK;
+       enum scan_type scan_type = jtag_scan_type(cmd->cmd.scan);
+
+       scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
+
+       if (cmd->cmd.scan->ir_scan) {
+               if (tap_get_state() != TAP_IRSHIFT) {
+                       jtag_ap_end_state(TAP_IRSHIFT);
+                       jtag_ap_state_move(0);
+               }
+       } else {
+               if (tap_get_state() != TAP_DRSHIFT) {
+                       jtag_ap_end_state(TAP_DRSHIFT);
+                       jtag_ap_state_move(0);
+               }
+       }
+
+       for (buffer_ptr = buffer; scan_size; scan_size -= chunk_size, 
buffer_ptr++) {
+
+               /* JTAG-AP TDI_TDO packets are 2 or more bytes in length */
+               /* see ARM IHI 0031 Section 9.2.2 for further details */
+
+               /* the following is a 3-byte packet consisting of:
+                * opcode byte
+                * 'normal format' length byte
+                * data byte with up to 8 bits of TDI
+                */
+
+               uint32_t command = 0x84; /* TDI_TDO opcode - RTDO set */
+
+               chunk_size = scan_size;
+               if (chunk_size > 8)
+                       chunk_size = 8;
+               else
+                       command |= 1UL << 3; /* TMS HIGH on last cycle */
+
+               /* TDI_TDO 'normal format' length byte */
+               command |= (chunk_size - 1) << 8;
+
+               /* data byte */
+               if (SCAN_IN != scan_type)
+                       command |= (uint32_t)*buffer_ptr << 16;
+
+               jtag_ap_wait_until_ready(1);
+               jtag_ap_thunk_dap_write(JTAG_AP_REG_BWFIFO3, command);
+               jtag_ap_wait_until_ready(0);
+               jtag_ap_thunk_dap_read(JTAG_AP_REG_BRFIFO1, &command);
+
+               /* chunk_size bits of TDO have been returned */
+               *buffer_ptr = (uint8_t)command;
+       }
+
+       if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) {
+               retval = ERROR_JTAG_QUEUE_FAILED;
+               goto bail;
+       }
+
+bail:
+       if (buffer)
+               free(buffer);
+
+       if (tap_get_state() != cmd->cmd.scan->end_state) {
+               jtag_ap_end_state(cmd->cmd.scan->end_state);
+               /* in this special case, we've already done the first TMS=1 */
+               jtag_ap_state_move(1);
+       }
+
+       return retval;
+}
+
+static void jtag_ap_cmd_reset(struct jtag_command *cmd)
+{
+       /* this reset operation procedure is documented under the heading:
+        * 'Resetting JTAG devices' in ARM IHI 0031 Section 12.2.1
+        */
+
+       /* assert TRST_OUT */
+       jtag_ap_thunk_dap_write(JTAG_AP_REG_CSW, CSW_TRST_OUT_MASK);
+       /* drive sequence of at least five TMS=1 clocks */
+       jtag_ap_thunk_dap_write(JTAG_AP_REG_BWFIFO1, 0x3F);
+       /* de-assert TRST_OUT */
+       jtag_ap_thunk_dap_write(JTAG_AP_REG_CSW, 0);
+}
+
+static void jtag_ap_cmd_sleep(struct jtag_command *cmd)
+{
+       jtag_sleep(cmd->cmd.sleep->us);
+}
+
+static int jtag_ap_command(struct jtag_command *cmd)
+{
+       switch (cmd->type) {
+               case JTAG_STABLECLOCKS:
+                       jtag_ap_cmd_stableclocks(cmd);
+                       break;
+               case JTAG_RUNTEST:
+                       jtag_ap_cmd_runtest(cmd);
+                       break;
+               case JTAG_TLR_RESET:
+                       jtag_ap_cmd_statemove(cmd);
+                       break;
+               case JTAG_PATHMOVE:
+                       jtag_ap_cmd_pathmove(cmd);
+                       break;
+               case JTAG_SCAN:
+                       jtag_ap_cmd_scan(cmd);
+                       break;
+               case JTAG_RESET:
+                       jtag_ap_cmd_reset(cmd);
+                       break;
+               case JTAG_SLEEP:
+                       jtag_ap_cmd_sleep(cmd);
+                       break;
+               default:
+                       LOG_ERROR("BUG: Unknown JTAG command type 
encountered.");
+                       return ERROR_JTAG_QUEUE_FAILED;
+       }
+
+       return ERROR_OK;
+}
+
+static int jtag_ap_queue(void)
+{
+       int ret;
+       struct jtag_command *cmd = jtag_command_queue;
+
+       while (NULL != cmd) {
+               ret = jtag_ap_command(cmd);
+
+               if (ERROR_OK != ret)
+                       return ret;
+
+               cmd = cmd->next;
+       }
+
+       return ERROR_OK;
+}
+
+/*
+ * Section 2: struct jtag_interface and command handler definitions
+ */
+
+/* prototype functions in thunking code further below */
+COMMAND_HANDLER(jtag_ap_handle_thunk_port_command);
+COMMAND_HANDLER(jtag_ap_handle_thunk_dap_instance);
+COMMAND_HANDLER(jtag_ap_handle_thunk_apsel);
+
+static const struct command_registration jtag_ap_command_handlers[] = {
+       {
+               .name = "jtag_ap_port",
+               .handler = jtag_ap_handle_thunk_port_command,
+               .mode = COMMAND_CONFIG,
+               .help = "Set the port to use to connect to the remote TCL 
server.",
+               .usage = "port_number",
+       },
+       {
+               .name = "jtag_ap_dap_instance",
+               .handler = jtag_ap_handle_thunk_dap_instance,
+               .mode = COMMAND_CONFIG,
+               .help = "name of dap instance (i.e. \"foo.dap\") on the remote 
server",
+               .usage = "dap_instance",
+       },
+       {
+               .name = "jtag_ap_apsel",
+               .handler = jtag_ap_handle_thunk_apsel,
+               .mode = COMMAND_CONFIG,
+               .help = "number of dap AP on the remote server providing 
JTAG-AP",
+               .usage = "ap_num",
+       },
+       COMMAND_REGISTRATION_DONE,
+};
+
+static const char * const jtag_ap_transports[] = { "jtag", NULL };
+
+struct jtag_interface jtag_ap_interface = {
+       .name = "jtag-ap",
+       .execute_queue = jtag_ap_queue,
+       .transports = jtag_ap_transports,
+       .commands = jtag_ap_command_handlers,
+       .init = jtag_ap_init,
+       .quit = jtag_ap_quit,
+};
+
+/*
+ * Section 3: thunking code that maps DAP operations to TCL "apreg" operations
+ */
+
+#ifndef _WIN32
+#include <sys/un.h>
+#include <netdb.h>
+#endif
+
+static char *jtag_thunk_ap_port;
+static char *jtag_ap_thunk_dap_instance;
+static const char *jtag_ap_default_dap_instance = "portal.dap";
+static uint32_t jtag_ap_thunk_apsel;
+
+static FILE *jtag_ap_thunk_file;
+static int jtag_ap_thunk_fd;
+
+COMMAND_HANDLER(jtag_ap_handle_thunk_port_command)
+{
+       if (CMD_ARGC == 1) {
+               uint16_t port;
+               COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
+               free(jtag_thunk_ap_port);
+               jtag_thunk_ap_port = port == 0 ? NULL : strdup(CMD_ARGV[0]);
+               return ERROR_OK;
+       }
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(jtag_ap_handle_thunk_dap_instance)
+{
+       if (CMD_ARGC == 1) {
+               free(jtag_ap_thunk_dap_instance);
+               jtag_ap_thunk_dap_instance = strdup(CMD_ARGV[0]);
+               return ERROR_OK;
+       }
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+COMMAND_HANDLER(jtag_ap_handle_thunk_apsel)
+{
+       if (CMD_ARGC == 1) {
+               uint32_t apsel;
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
+               if (apsel > DP_APSEL_MAX)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               jtag_ap_thunk_apsel = apsel;
+               return ERROR_OK;
+       }
+       return ERROR_COMMAND_SYNTAX_ERROR;
+}
+
+static int jtag_ap_thunk_init(void)
+{
+       struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = 
SOCK_STREAM };
+       struct addrinfo *result, *rp;
+
+       LOG_INFO("Connecting to localhost:%s", jtag_thunk_ap_port);
+
+       /* Obtain address(es) matching host/port */
+       int s = getaddrinfo(NULL, jtag_thunk_ap_port, &hints, &result);
+       if (s != 0) {
+               LOG_ERROR("getaddrinfo: %s\n", gai_strerror(s));
+               return ERROR_FAIL;
+       }
+
+       /* getaddrinfo() returns a list of address structures.
+        Try each address until we successfully connect(2).
+        If socket(2) (or connect(2)) fails, we (close the socket
+        and) try the next address. */
+
+       for (rp = result; rp != NULL ; rp = rp->ai_next) {
+               jtag_ap_thunk_fd = socket(rp->ai_family, rp->ai_socktype, 
rp->ai_protocol);
+               if (jtag_ap_thunk_fd == -1)
+                       continue;
+
+               if (connect(jtag_ap_thunk_fd, rp->ai_addr, rp->ai_addrlen) != 
-1)
+                       break; /* Success */
+
+               close(jtag_ap_thunk_fd);
+       }
+
+       freeaddrinfo(result); /* No longer needed */
+
+       if (rp == NULL) { /* No address succeeded */
+               LOG_ERROR("Failed to connect: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       if (jtag_ap_thunk_fd < 0)
+               return ERROR_FAIL;
+
+       jtag_ap_thunk_file = fdopen(jtag_ap_thunk_fd, "w+");
+       if (jtag_ap_thunk_file == NULL) {
+               LOG_ERROR("fdopen: failed to open write stream");
+               close(jtag_ap_thunk_fd);
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int jtag_ap_thunk_quit(void)
+{
+       if (EOF == fflush(jtag_ap_thunk_file)) {
+               LOG_ERROR("fflush: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       /* We only need to close one of the FILE*s, because they both use the 
same */
+       /* underlying file descriptor. */
+       if (EOF == fclose(jtag_ap_thunk_file)) {
+               LOG_ERROR("fclose: %s", strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       free(jtag_thunk_ap_port);
+
+       return ERROR_OK;
+}
+
+static int jtag_ap_thunk_dap_write(uint32_t reg, uint32_t value)
+{
+       char byte;
+       ssize_t count;
+       const char *dap_instance = (jtag_ap_thunk_dap_instance) ?
+               jtag_ap_thunk_dap_instance : jtag_ap_default_dap_instance;
+
+       /* generate Ctrl-Z terminated apreg write operation */
+       if (EOF == fprintf(jtag_ap_thunk_file, "ocd_%s apreg %u %d 0x%x\x1A",
+               dap_instance, jtag_ap_thunk_apsel, reg, value)) {
+               LOG_ERROR("jtag_ap_thunk_dap_write fprintf: %s", 
strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       fflush(jtag_ap_thunk_file);
+
+       /* look for a Ctrl-Z, ignoring any intermediate data */
+       for (;;) {
+               count = read(jtag_ap_thunk_fd, &byte, 1);
+
+               if (count <= 0) {
+                       LOG_ERROR("jtag_ap_thunk_dap_write read: %s (%d)",
+                                       strerror(errno), errno);
+                       return ERROR_FAIL;
+               }
+
+               if ('\x1A' == byte)
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+static int jtag_ap_thunk_dap_read(uint32_t reg, uint32_t *value)
+{
+       char buffer[64];
+       ssize_t count, index;
+       const char *dap_instance = (jtag_ap_thunk_dap_instance) ?
+               jtag_ap_thunk_dap_instance : jtag_ap_default_dap_instance;
+
+       /* generate Ctrl-Z terminated apreg read operation */
+       if (EOF == fprintf(jtag_ap_thunk_file, "ocd_%s apreg %u %d\x1A",
+               dap_instance, jtag_ap_thunk_apsel, reg)) {
+               LOG_ERROR("jtag_ap_thunk_dap_read fprintf: %s", 
strerror(errno));
+               return ERROR_FAIL;
+       }
+
+       fflush(jtag_ap_thunk_file);
+
+       /* look for a Ctrl-Z, collecting intermediate data in 'buffer' */
+       for (index = 0; index < (ssize_t)sizeof(buffer); index++) {
+               count = read(jtag_ap_thunk_fd, buffer + index, 1);
+
+               if (count <= 0) {
+                       LOG_ERROR("jtag_ap_thunk_dap_read read: %s (%d)",
+                                       strerror(errno), errno);
+                       return ERROR_FAIL;
+               }
+
+               if ('\x1A' == buffer[index]) {
+                       buffer[index] = '\0';
+                       break;
+               }
+       }
+
+       if (value)
+               *value = strtoul(buffer, NULL, 0);
+
+       return ERROR_OK;
+}
+
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 286a73a..74c5106 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -135,6 +135,9 @@ extern struct jtag_interface imx_gpio_interface;
 #if BUILD_XDS110 == 1
 extern struct jtag_interface xds110_interface;
 #endif
+#if BUILD_JTAG_AP == 1
+extern struct jtag_interface jtag_ap_interface;
+#endif
 #endif /* standard drivers */
 
 /**
@@ -240,6 +243,9 @@ struct jtag_interface *jtag_interfaces[] = {
 #if BUILD_XDS110 == 1
                &xds110_interface,
 #endif
+#if BUILD_JTAG_AP == 1
+               &jtag_ap_interface,
+#endif
 #endif /* standard drivers */
                NULL,
        };
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index a340b76..54c0acf 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -139,6 +139,30 @@
 #define DP_APSEL_MAX        (255)
 #define DP_APSEL_INVALID    (-1)
 
+/* JTAG-AP register addresses */
+#define JTAG_AP_REG_CSW                0x00
+#define JTAG_AP_REG_PSEL       0x04
+#define JTAG_AP_REG_PSTA       0x08
+#define JTAG_AP_REG_BRFIFO1    0x10
+#define JTAG_AP_REG_BWFIFO1    0x10
+#define JTAG_AP_REG_BRFIFO2    0x14
+#define JTAG_AP_REG_BWFIFO2    0x14
+#define JTAG_AP_REG_BRFIFO3    0x18
+#define JTAG_AP_REG_BWFIFO3    0x18
+#define JTAG_AP_REG_BRFIFO4    0x1C
+#define JTAG_AP_REG_BWFIFO4    0x1C
+
+/* Fields of the JTAG-AP's CSW register */
+#define CSW_SERACTV_MASK       (1UL << 31)
+#define CSW_WFIFOCNT_POS       28
+#define CSW_WFIFOCNT_MASK      (7UL << CSW_WFIFOCNT_POS)
+#define CSW_RFIFOCNT_POS       24
+#define CSW_RFIFOCNT_MASK      (7UL << CSW_RFIFOCNT_POS)
+#define CSW_PORTCONNECTED_MASK (1UL << 3)
+#define CSW_SRSTCONNECTED_MASK (1UL << 2)
+#define CSW_TRST_OUT_MASK      (1UL << 1)
+#define CSW_SRST_OUT_MASK      (1UL << 0)
+
 /**
  * This represents an ARM Debug Interface (v5) Access Port (AP).
  * Most common is a MEM-AP, for memory access.

-- 


_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to