summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2010-03-16 14:12:00 -0700
committerDavid Brownell <dbrownell@users.sourceforge.net>2010-03-16 14:12:00 -0700
commit6f8b8593d63bc9781435270a54b6f7d245eecd8e (patch)
tree5b5928e9b4b2cfbafe287dd5d69c85254c099e2d
parent030ee192dd9647b10ff0841a671facec9d6b833f (diff)
downloadopenocd+libswd-6f8b8593d63bc9781435270a54b6f7d245eecd8e.tar.gz
openocd+libswd-6f8b8593d63bc9781435270a54b6f7d245eecd8e.tar.bz2
openocd+libswd-6f8b8593d63bc9781435270a54b6f7d245eecd8e.tar.xz
openocd+libswd-6f8b8593d63bc9781435270a54b6f7d245eecd8e.zip
ADIv5 transport support moves to separate files
Unclutter arm_adi_v5.c by moving most transport-specific code to a transport-specific files adi_v5_{jtag,swd}.c ... it's not a full cleanup, because of some issues which need to be addressed as part of SWD support (along with implementing the DAP operations on top of SWD transport): - The mess where mem_ap_read_buf_u32() is currently coded to know about JTAG scan chains, and thus needs rewriting before it will work with SWD; - Initialization is still JTAG-specific Also move JTAG_{DP,ACK}_* constants from adi_v5.h to the JTAG file; no other code should care about those values. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
-rw-r--r--src/target/Makefile.am2
-rw-r--r--src/target/adi_v5_jtag.c481
-rw-r--r--src/target/adi_v5_swd.c92
-rw-r--r--src/target/arm_adi_v5.c434
-rw-r--r--src/target/arm_adi_v5.h10
5 files changed, 589 insertions, 430 deletions
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index ad0ff7c0..ea6d88fc 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -83,6 +83,8 @@ ARM_DEBUG_SRC = \
arm_simulator.c \
arm_semihosting.c \
arm_adi_v5.c \
+ adi_v5_jtag.c \
+ adi_v5_swd.c \
embeddedice.c \
trace.c \
etb.c \
diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c
new file mode 100644
index 00000000..eac83b7b
--- /dev/null
+++ b/src/target/adi_v5_jtag.c
@@ -0,0 +1,481 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Magnus Lundin
+ * lundin@mlu.mine.nu
+ *
+ * Copyright (C) 2008 by Spencer Oliver
+ * spen@spen-soft.co.uk
+ *
+ * Copyright (C) 2009 by Oyvind Harboe
+ * oyvind.harboe@zylin.com
+ *
+ * Copyright (C) 2009-2010 by David Brownell
+ *
+ * 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.
+ ***************************************************************************/
+
+/**
+ * @file
+ * This file implements JTAG transport support for cores implementing
+ the ARM Debug Interface version 5 (ADIv5).
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arm.h"
+#include "arm_adi_v5.h"
+#include <helper/time_support.h>
+
+
+/* JTAG instructions/registers for JTAG-DP and SWJ-DP */
+#define JTAG_DP_ABORT 0x8
+#define JTAG_DP_DPACC 0xA
+#define JTAG_DP_APACC 0xB
+#define JTAG_DP_IDCODE 0xE
+
+/* three-bit ACK values for DPACC and APACC reads */
+#define JTAG_ACK_OK_FAULT 0x2
+#define JTAG_ACK_WAIT 0x1
+
+/***************************************************************************
+ *
+ * DPACC and APACC scanchain access through JTAG-DP (or SWJ-DP)
+ *
+***************************************************************************/
+
+/**
+ * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness
+ * conversions are performed. See section 4.4.3 of the ADIv5 spec, which
+ * discusses operations which access these registers.
+ *
+ * Note that only one scan is performed. If RnW is set, a separate scan
+ * will be needed to collect the data which was read; the "invalue" collects
+ * the posted result of a preceding operation, not the current one.
+ *
+ * @param swjdp the DAP
+ * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access)
+ * @param reg_addr two significant bits; A[3:2]; for APACC access, the
+ * SELECT register has more addressing bits.
+ * @param RnW false iff outvalue will be written to the DP or AP
+ * @param outvalue points to a 32-bit (little-endian) integer
+ * @param invalue NULL, or points to a 32-bit (little-endian) integer
+ * @param ack points to where the three bit JTAG_ACK_* code will be stored
+ */
+
+/* FIXME don't export ... this is a temporary workaround for the
+ * mem_ap_read_buf_u32() mess, until it's no longer JTAG-specific.
+ */
+int adi_jtag_dp_scan(struct adiv5_dap *swjdp,
+ uint8_t instr, uint8_t reg_addr, uint8_t RnW,
+ uint8_t *outvalue, uint8_t *invalue, uint8_t *ack)
+{
+ struct arm_jtag *jtag_info = swjdp->jtag_info;
+ struct scan_field fields[2];
+ uint8_t out_addr_buf;
+
+ jtag_set_end_state(TAP_IDLE);
+ arm_jtag_set_instr(jtag_info, instr, NULL);
+
+ /* Scan out a read or write operation using some DP or AP register.
+ * For APACC access with any sticky error flag set, this is discarded.
+ */
+ fields[0].num_bits = 3;
+ buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1));
+ fields[0].out_value = &out_addr_buf;
+ fields[0].in_value = ack;
+
+ /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not
+ * complete; data we write is discarded, data we read is unpredictable.
+ * When overrun detect is active, STICKYORUN is set.
+ */
+
+ fields[1].num_bits = 32;
+ fields[1].out_value = outvalue;
+ fields[1].in_value = invalue;
+
+ jtag_add_dr_scan(jtag_info->tap, 2, fields, jtag_get_end_state());
+
+ /* Add specified number of tck clocks after starting memory bus
+ * access, giving the hardware time to complete the access.
+ * They provide more time for the (MEM) AP to complete the read ...
+ * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec.
+ */
+ if ((instr == JTAG_DP_APACC)
+ && ((reg_addr == AP_REG_DRW)
+ || ((reg_addr & 0xF0) == AP_REG_BD0))
+ && (swjdp->memaccess_tck != 0))
+ jtag_add_runtest(swjdp->memaccess_tck,
+ jtag_set_end_state(TAP_IDLE));
+
+ return jtag_get_error();
+}
+
+/**
+ * Scan DPACC or APACC out and in from host ordered uint32_t buffers.
+ * This is exactly like adi_jtag_dp_scan(), except that endianness
+ * conversions are performed (so the types of invalue and outvalue
+ * must be different).
+ */
+static int adi_jtag_dp_scan_u32(struct adiv5_dap *swjdp,
+ uint8_t instr, uint8_t reg_addr, uint8_t RnW,
+ uint32_t outvalue, uint32_t *invalue, uint8_t *ack)
+{
+ uint8_t out_value_buf[4];
+ int retval;
+
+ buf_set_u32(out_value_buf, 0, 32, outvalue);
+
+ retval = adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW,
+ out_value_buf, (uint8_t *)invalue, ack);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (invalue)
+ jtag_add_callback(arm_le_to_h_u32,
+ (jtag_callback_data_t) invalue);
+
+ return retval;
+}
+
+/**
+ * Utility to write AP registers.
+ */
+static inline int adi_jtag_ap_write_check(struct adiv5_dap *dap,
+ uint8_t reg_addr, uint8_t *outvalue)
+{
+ return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE,
+ outvalue, NULL, NULL);
+}
+
+static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *swjdp,
+ uint8_t instr, uint8_t reg_addr, uint8_t RnW,
+ uint32_t outvalue, uint32_t *invalue)
+{
+ int retval;
+
+ /* Issue the read or write */
+ retval = adi_jtag_dp_scan_u32(swjdp, instr, reg_addr,
+ RnW, outvalue, NULL, NULL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* For reads, collect posted value; RDBUFF has no other effect.
+ * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK".
+ */
+ if ((RnW == DPAP_READ) && (invalue != NULL))
+ retval = adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC,
+ DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack);
+ return retval;
+}
+
+static int jtagdp_transaction_endcheck(struct adiv5_dap *swjdp)
+{
+ int retval;
+ uint32_t ctrlstat;
+
+ /* too expensive to call keep_alive() here */
+
+#if 0
+ /* Danger!!!! BROKEN!!!! */
+ adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+ DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
+ /* Danger!!!! BROKEN!!!! Why will jtag_execute_queue() fail here????
+ R956 introduced the check on return value here and now Michael Schwingen reports
+ that this code no longer works....
+
+ https://lists.berlios.de/pipermail/openocd-development/2008-September/003107.html
+ */
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ {
+ LOG_ERROR("BUG: Why does this fail the first time????");
+ }
+ /* Why??? second time it works??? */
+#endif
+
+ /* Post CTRL/STAT read; discard any previous posted read value
+ * but collect its ACK status.
+ */
+ adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+ DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
+ if ((retval = jtag_execute_queue()) != ERROR_OK)
+ return retval;
+
+ swjdp->ack = swjdp->ack & 0x7;
+
+ /* common code path avoids calling timeval_ms() */
+ if (swjdp->ack != JTAG_ACK_OK_FAULT)
+ {
+ long long then = timeval_ms();
+
+ while (swjdp->ack != JTAG_ACK_OK_FAULT)
+ {
+ if (swjdp->ack == JTAG_ACK_WAIT)
+ {
+ if ((timeval_ms()-then) > 1000)
+ {
+ /* NOTE: this would be a good spot
+ * to use JTAG_DP_ABORT.
+ */
+ LOG_WARNING("Timeout (1000ms) waiting "
+ "for ACK=OK/FAULT "
+ "in JTAG-DP transaction");
+ return ERROR_JTAG_DEVICE_ERROR;
+ }
+ }
+ else
+ {
+ LOG_WARNING("Invalid ACK %#x "
+ "in JTAG-DP transaction",
+ swjdp->ack);
+ return ERROR_JTAG_DEVICE_ERROR;
+ }
+
+ adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+ DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
+ if ((retval = dap_run(swjdp)) != ERROR_OK)
+ return retval;
+ swjdp->ack = swjdp->ack & 0x7;
+ }
+ }
+
+ /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */
+
+ /* Check for STICKYERR and STICKYORUN */
+ if (ctrlstat & (SSTICKYORUN | SSTICKYERR))
+ {
+ LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat);
+ /* Check power to debug regions */
+ if ((ctrlstat & 0xf0000000) != 0xf0000000)
+ ahbap_debugport_init(swjdp);
+ else
+ {
+ uint32_t mem_ap_csw, mem_ap_tar;
+
+ /* Maybe print information about last intended
+ * MEM-AP access; but not if autoincrementing.
+ * *Real* CSW and TAR values are always shown.
+ */
+ if (swjdp->ap_tar_value != (uint32_t) -1)
+ LOG_DEBUG("MEM-AP Cached values: "
+ "ap_bank 0x%" PRIx32
+ ", ap_csw 0x%" PRIx32
+ ", ap_tar 0x%" PRIx32,
+ swjdp->ap_bank_value,
+ swjdp->ap_csw_value,
+ swjdp->ap_tar_value);
+
+ if (ctrlstat & SSTICKYORUN)
+ LOG_ERROR("JTAG-DP OVERRUN - check clock, "
+ "memaccess, or reduce jtag speed");
+
+ if (ctrlstat & SSTICKYERR)
+ LOG_ERROR("JTAG-DP STICKY ERROR");
+
+ /* Clear Sticky Error Bits */
+ adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+ DP_CTRL_STAT, DPAP_WRITE,
+ swjdp->dp_ctrl_stat | SSTICKYORUN
+ | SSTICKYERR, NULL);
+ adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
+ DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
+ if ((retval = dap_run(swjdp)) != ERROR_OK)
+ return retval;
+
+ LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
+
+ retval = dap_queue_ap_read(swjdp,
+ AP_REG_CSW, &mem_ap_csw);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = dap_queue_ap_read(swjdp,
+ AP_REG_TAR, &mem_ap_tar);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if ((retval = dap_run(swjdp)) != ERROR_OK)
+ return retval;
+ LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%"
+ PRIx32, mem_ap_csw, mem_ap_tar);
+
+ }
+ if ((retval = dap_run(swjdp)) != ERROR_OK)
+ return retval;
+ return ERROR_JTAG_DEVICE_ERROR;
+ }
+
+ return ERROR_OK;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int jtag_idcode_q_read(struct adiv5_dap *dap,
+ uint8_t *ack, uint32_t *data)
+{
+ struct arm_jtag *jtag_info = dap->jtag_info;
+ int retval;
+ struct scan_field fields[1];
+
+ jtag_set_end_state(TAP_IDLE);
+
+ /* This is a standard JTAG operation -- no DAP tweakage */
+ retval = arm_jtag_set_instr(jtag_info, JTAG_DP_IDCODE, NULL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ fields[0].num_bits = 32;
+ fields[0].out_value = NULL;
+ fields[0].in_value = (void *) data;
+
+ jtag_add_dr_scan(jtag_info->tap, 1, fields, jtag_get_end_state());
+ retval = jtag_get_error();
+ if (retval != ERROR_OK)
+ return retval;
+
+ jtag_add_callback(arm_le_to_h_u32,
+ (jtag_callback_data_t) data);
+
+ return retval;
+}
+
+static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
+ uint32_t *data)
+{
+ return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+ reg, DPAP_READ, 0, data);
+}
+
+static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg,
+ uint32_t data)
+{
+ return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
+ reg, DPAP_WRITE, data, NULL);
+}
+
+/** Select the AP register bank matching bits 7:4 of reg. */
+static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
+{
+ uint32_t select = reg & 0x000000F0;
+
+ if (select == dap->ap_bank_value)
+ return ERROR_OK;
+ dap->ap_bank_value = select;
+
+ select |= dap->apsel;
+
+ return jtag_dp_q_write(dap, DP_SELECT, select);
+}
+
+static int jtag_ap_q_read(struct adiv5_dap *dap, unsigned reg,
+ uint32_t *data)
+{
+ int retval = jtag_ap_q_bankselect(dap, reg);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_APACC, reg,
+ DPAP_READ, 0, data);
+}
+
+static int jtag_ap_q_write(struct adiv5_dap *dap, unsigned reg,
+ uint32_t data)
+{
+ uint8_t out_value_buf[4];
+
+ int retval = jtag_ap_q_bankselect(dap, reg);
+ if (retval != ERROR_OK)
+ return retval;
+
+ buf_set_u32(out_value_buf, 0, 32, data);
+
+ return adi_jtag_ap_write_check(dap, reg, out_value_buf);
+}
+
+static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
+{
+ /* for JTAG, this is the only valid ABORT register operation */
+ return adi_jtag_dp_scan_u32(dap, JTAG_DP_ABORT,
+ 0, DPAP_WRITE, 1, NULL, ack);
+}
+
+static int jtag_dp_run(struct adiv5_dap *dap)
+{
+ return jtagdp_transaction_endcheck(dap);
+}
+
+/* FIXME don't export ... just initialize as
+ * part of DAP setup
+*/
+const struct dap_ops jtag_dp_ops = {
+ .queue_idcode_read = jtag_idcode_q_read,
+ .queue_dp_read = jtag_dp_q_read,
+ .queue_dp_write = jtag_dp_q_write,
+ .queue_ap_read = jtag_ap_q_read,
+ .queue_ap_write = jtag_ap_q_write,
+ .queue_ap_abort = jtag_ap_q_abort,
+ .run = jtag_dp_run,
+};
+
+
+const uint8_t swd2jtag_bitseq[] = {
+ /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
+ * putting both JTAG and SWD logic into reset state.
+ */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* Switching equence disables SWD and enables JTAG
+ * NOTE: bits in the DP's IDCODE can expose the need for
+ * the old/deprecated sequence (0xae 0xde).
+ */
+ 0x3c, 0xe7,
+ /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high,
+ * putting both JTAG and SWD logic into reset state.
+ * NOTE: some docs say "at least 5".
+ */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+/** Put the debug link into JTAG mode, if the target supports it.
+ * The link's initial mode may be either SWD or JTAG.
+ *
+ * @param target Enters JTAG mode (if possible).
+ *
+ * Note that targets implemented with SW-DP do not support JTAG, and
+ * that some targets which could otherwise support it may have been
+ * configured to disable JTAG signaling
+ *
+ * @return ERROR_OK or else a fault code.
+ */
+int dap_to_jtag(struct target *target)
+{
+ int retval;
+
+ LOG_DEBUG("Enter JTAG mode");
+
+ /* REVISIT it's nasty to need to make calls to a "jtag"
+ * subsystem if the link isn't in JTAG mode...
+ */
+
+ retval = jtag_add_tms_seq(8 * sizeof(swd2jtag_bitseq),
+ swd2jtag_bitseq, TAP_RESET);
+ if (retval == ERROR_OK)
+ retval = jtag_execute_queue();
+
+ /* REVISIT set up the DAP's ops vector for JTAG mode. */
+
+ return retval;
+}
diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c
new file mode 100644
index 00000000..f103e4b0
--- /dev/null
+++ b/src/target/adi_v5_swd.c
@@ -0,0 +1,92 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2010 by David Brownell
+ *
+ * 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.
+ ***************************************************************************/
+
+/**
+ * @file
+ * This file implements SWD transport support for cores implementing
+ the ARM Debug Interface version 5 (ADIv5).
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arm.h"
+#include "arm_adi_v5.h"
+#include <helper/time_support.h>
+
+/*
+ * This represents the bits which must be sent out on TMS/SWDIO to
+ * switch a DAP implemented using an SWJ-DP module into SWD mode.
+ * These bits are stored (and transmitted) LSB-first.
+ *
+ * See the DAP-Lite specification, section 2.2.5 for information
+ * about making the debug link select SWD or JTAG. (Similar info
+ * is in a few other ARM documents.)
+ */
+static const uint8_t jtag2swd_bitseq[] = {
+ /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
+ * putting both JTAG and SWD logic into reset state.
+ */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* Switching sequence enables SWD and disables JTAG
+ * NOTE: bits in the DP's IDCODE may expose the need for
+ * an old/deprecated sequence (0xb6 0xed).
+ */
+ 0x9e, 0xe7,
+ /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
+ * putting both JTAG and SWD logic into reset state.
+ */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+/**
+ * Put the debug link into SWD mode, if the target supports it.
+ * The link's initial mode may be either JTAG (for example,
+ * with SWJ-DP after reset) or SWD.
+ *
+ * @param target Enters SWD mode (if possible).
+ *
+ * Note that targets using the JTAG-DP do not support SWD, and that
+ * some targets which could otherwise support it may have have been
+ * configured to disable SWD signaling
+ *
+ * @return ERROR_OK or else a fault code.
+ */
+int dap_to_swd(struct target *target)
+{
+ int retval;
+
+ LOG_DEBUG("Enter SWD mode");
+
+ /* REVISIT it's nasty to need to make calls to a "jtag"
+ * subsystem if the link isn't in JTAG mode...
+ */
+
+ retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq),
+ jtag2swd_bitseq, TAP_INVALID);
+ if (retval == ERROR_OK)
+ retval = jtag_execute_queue();
+
+ /* REVISIT set up the DAP's ops vector for SWD mode. */
+
+ return retval;
+}
+
diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index 61cf9892..dcad0fbc 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -87,272 +87,6 @@ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address
/***************************************************************************
* *
- * DPACC and APACC scanchain access through JTAG-DP *
- * *
-***************************************************************************/
-
-/**
- * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness
- * conversions are performed. See section 4.4.3 of the ADIv5 spec, which
- * discusses operations which access these registers.
- *
- * Note that only one scan is performed. If RnW is set, a separate scan
- * will be needed to collect the data which was read; the "invalue" collects
- * the posted result of a preceding operation, not the current one.
- *
- * @param swjdp the DAP
- * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access)
- * @param reg_addr two significant bits; A[3:2]; for APACC access, the
- * SELECT register has more addressing bits.
- * @param RnW false iff outvalue will be written to the DP or AP
- * @param outvalue points to a 32-bit (little-endian) integer
- * @param invalue NULL, or points to a 32-bit (little-endian) integer
- * @param ack points to where the three bit JTAG_ACK_* code will be stored
- */
-static int adi_jtag_dp_scan(struct adiv5_dap *swjdp,
- uint8_t instr, uint8_t reg_addr, uint8_t RnW,
- uint8_t *outvalue, uint8_t *invalue, uint8_t *ack)
-{
- struct arm_jtag *jtag_info = swjdp->jtag_info;
- struct scan_field fields[2];
- uint8_t out_addr_buf;
-
- jtag_set_end_state(TAP_IDLE);
- arm_jtag_set_instr(jtag_info, instr, NULL);
-
- /* Scan out a read or write operation using some DP or AP register.
- * For APACC access with any sticky error flag set, this is discarded.
- */
- fields[0].num_bits = 3;
- buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1));
- fields[0].out_value = &out_addr_buf;
- fields[0].in_value = ack;
-
- /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not
- * complete; data we write is discarded, data we read is unpredictable.
- * When overrun detect is active, STICKYORUN is set.
- */
-
- fields[1].num_bits = 32;
- fields[1].out_value = outvalue;
- fields[1].in_value = invalue;
-
- jtag_add_dr_scan(jtag_info->tap, 2, fields, jtag_get_end_state());
-
- /* Add specified number of tck clocks after starting memory bus
- * access, giving the hardware time to complete the access.
- * They provide more time for the (MEM) AP to complete the read ...
- * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec.
- */
- if ((instr == JTAG_DP_APACC)
- && ((reg_addr == AP_REG_DRW)
- || ((reg_addr & 0xF0) == AP_REG_BD0))
- && (swjdp->memaccess_tck != 0))
- jtag_add_runtest(swjdp->memaccess_tck,
- jtag_set_end_state(TAP_IDLE));
-
- return jtag_get_error();
-}
-
-/**
- * Scan DPACC or APACC out and in from host ordered uint32_t buffers.
- * This is exactly like adi_jtag_dp_scan(), except that endianness
- * conversions are performed (so the types of invalue and outvalue
- * must be different).
- */
-static int adi_jtag_dp_scan_u32(struct adiv5_dap *swjdp,
- uint8_t instr, uint8_t reg_addr, uint8_t RnW,
- uint32_t outvalue, uint32_t *invalue, uint8_t *ack)
-{
- uint8_t out_value_buf[4];
- int retval;
-
- buf_set_u32(out_value_buf, 0, 32, outvalue);
-
- retval = adi_jtag_dp_scan(swjdp, instr, reg_addr, RnW,
- out_value_buf, (uint8_t *)invalue, ack);
- if (retval != ERROR_OK)
- return retval;
-
- if (invalue)
- jtag_add_callback(arm_le_to_h_u32,
- (jtag_callback_data_t) invalue);
-
- return retval;
-}
-
-/**
- * Utility to write AP registers.
- */
-static inline int adi_jtag_ap_write_check(struct adiv5_dap *dap,
- uint8_t reg_addr, uint8_t *outvalue)
-{
- return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE,
- outvalue, NULL, NULL);
-}
-
-static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *swjdp,
- uint8_t instr, uint8_t reg_addr, uint8_t RnW,
- uint32_t outvalue, uint32_t *invalue)
-{
- int retval;
-
- /* Issue the read or write */
- retval = adi_jtag_dp_scan_u32(swjdp, instr, reg_addr,
- RnW, outvalue, NULL, NULL);
- if (retval != ERROR_OK)
- return retval;
-
- /* For reads, collect posted value; RDBUFF has no other effect.
- * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK".
- */
- if ((RnW == DPAP_READ) && (invalue != NULL))
- retval = adi_jtag_dp_scan_u32(swjdp, JTAG_DP_DPACC,
- DP_RDBUFF, DPAP_READ, 0, invalue, &swjdp->ack);
- return retval;
-}
-
-static int jtagdp_transaction_endcheck(struct adiv5_dap *swjdp)
-{
- int retval;
- uint32_t ctrlstat;
-
- /* too expensive to call keep_alive() here */
-
-#if 0
- /* Danger!!!! BROKEN!!!! */
- adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
- DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- /* Danger!!!! BROKEN!!!! Why will jtag_execute_queue() fail here????
- R956 introduced the check on return value here and now Michael Schwingen reports
- that this code no longer works....
-
- https://lists.berlios.de/pipermail/openocd-development/2008-September/003107.html
- */
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- {
- LOG_ERROR("BUG: Why does this fail the first time????");
- }
- /* Why??? second time it works??? */
-#endif
-
- /* Post CTRL/STAT read; discard any previous posted read value
- * but collect its ACK status.
- */
- adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
- DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- if ((retval = jtag_execute_queue()) != ERROR_OK)
- return retval;
-
- swjdp->ack = swjdp->ack & 0x7;
-
- /* common code path avoids calling timeval_ms() */
- if (swjdp->ack != JTAG_ACK_OK_FAULT)
- {
- long long then = timeval_ms();
-
- while (swjdp->ack != JTAG_ACK_OK_FAULT)
- {
- if (swjdp->ack == JTAG_ACK_WAIT)
- {
- if ((timeval_ms()-then) > 1000)
- {
- /* NOTE: this would be a good spot
- * to use JTAG_DP_ABORT.
- */
- LOG_WARNING("Timeout (1000ms) waiting "
- "for ACK=OK/FAULT "
- "in JTAG-DP transaction");
- return ERROR_JTAG_DEVICE_ERROR;
- }
- }
- else
- {
- LOG_WARNING("Invalid ACK %#x "
- "in JTAG-DP transaction",
- swjdp->ack);
- return ERROR_JTAG_DEVICE_ERROR;
- }
-
- adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
- DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- if ((retval = dap_run(swjdp)) != ERROR_OK)
- return retval;
- swjdp->ack = swjdp->ack & 0x7;
- }
- }
-
- /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */
-
- /* Check for STICKYERR and STICKYORUN */
- if (ctrlstat & (SSTICKYORUN | SSTICKYERR))
- {
- LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat);
- /* Check power to debug regions */
- if ((ctrlstat & 0xf0000000) != 0xf0000000)
- ahbap_debugport_init(swjdp);
- else
- {
- uint32_t mem_ap_csw, mem_ap_tar;
-
- /* Maybe print information about last intended
- * MEM-AP access; but not if autoincrementing.
- * *Real* CSW and TAR values are always shown.
- */
- if (swjdp->ap_tar_value != (uint32_t) -1)
- LOG_DEBUG("MEM-AP Cached values: "
- "ap_bank 0x%" PRIx32
- ", ap_csw 0x%" PRIx32
- ", ap_tar 0x%" PRIx32,
- swjdp->ap_bank_value,
- swjdp->ap_csw_value,
- swjdp->ap_tar_value);
-
- if (ctrlstat & SSTICKYORUN)
- LOG_ERROR("JTAG-DP OVERRUN - check clock, "
- "memaccess, or reduce jtag speed");
-
- if (ctrlstat & SSTICKYERR)
- LOG_ERROR("JTAG-DP STICKY ERROR");
-
- /* Clear Sticky Error Bits */
- adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
- DP_CTRL_STAT, DPAP_WRITE,
- swjdp->dp_ctrl_stat | SSTICKYORUN
- | SSTICKYERR, NULL);
- adi_jtag_scan_inout_check_u32(swjdp, JTAG_DP_DPACC,
- DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat);
- if ((retval = dap_run(swjdp)) != ERROR_OK)
- return retval;
-
- LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat);
-
- retval = dap_queue_ap_read(swjdp,
- AP_REG_CSW, &mem_ap_csw);
- if (retval != ERROR_OK)
- return retval;
-
- retval = dap_queue_ap_read(swjdp,
- AP_REG_TAR, &mem_ap_tar);
- if (retval != ERROR_OK)
- return retval;
-
- if ((retval = dap_run(swjdp)) != ERROR_OK)
- return retval;
- LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%"
- PRIx32, mem_ap_csw, mem_ap_tar);
-
- }
- if ((retval = dap_run(swjdp)) != ERROR_OK)
- return retval;
- return ERROR_JTAG_DEVICE_ERROR;
- }
-
- return ERROR_OK;
-}
-
-/***************************************************************************
- * *
* DP and MEM-AP register access through APACC and DPACC *
* *
***************************************************************************/
@@ -818,6 +552,13 @@ int mem_ap_write_buf_u8(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uin
return retval;
}
+/* FIXME don't import ... this is a temporary workaround for the
+ * mem_ap_read_buf_u32() mess, until it's no longer JTAG-specific.
+ */
+extern int adi_jtag_dp_scan(struct adiv5_dap *swjdp,
+ uint8_t instr, uint8_t reg_addr, uint8_t RnW,
+ uint8_t *outvalue, uint8_t *invalue, uint8_t *ack);
+
/**
* Synchronously read a block of 32-bit words into a buffer
* @param swjdp The DAP connected to the MEM-AP.
@@ -1116,110 +857,11 @@ int mem_ap_read_buf_u8(struct adiv5_dap *swjdp, uint8_t *buffer,
/*--------------------------------------------------------------------------*/
-static int jtag_idcode_q_read(struct adiv5_dap *dap,
- uint8_t *ack, uint32_t *data)
-{
- struct arm_jtag *jtag_info = dap->jtag_info;
- int retval;
- struct scan_field fields[1];
-
- jtag_set_end_state(TAP_IDLE);
-
- /* This is a standard JTAG operation -- no DAP tweakage */
- retval = arm_jtag_set_instr(jtag_info, JTAG_DP_IDCODE, NULL);
- if (retval != ERROR_OK)
- return retval;
-
- fields[0].num_bits = 32;
- fields[0].out_value = NULL;
- fields[0].in_value = (void *) data;
-
- jtag_add_dr_scan(jtag_info->tap, 1, fields, jtag_get_end_state());
- retval = jtag_get_error();
- if (retval != ERROR_OK)
- return retval;
-
- jtag_add_callback(arm_le_to_h_u32,
- (jtag_callback_data_t) data);
-
- return retval;
-}
-
-static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg,
- uint32_t *data)
-{
- return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
- reg, DPAP_READ, 0, data);
-}
-
-static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg,
- uint32_t data)
-{
- return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
- reg, DPAP_WRITE, data, NULL);
-}
-
-/** Select the AP register bank matching bits 7:4 of reg. */
-static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg)
-{
- uint32_t select = reg & 0x000000F0;
-
- if (select == dap->ap_bank_value)
- return ERROR_OK;
- dap->ap_bank_value = select;
-
- select |= dap->apsel;
-
- return jtag_dp_q_write(dap, DP_SELECT, select);
-}
-
-static int jtag_ap_q_read(struct adiv5_dap *dap, unsigned reg,
- uint32_t *data)
-{
- int retval = jtag_ap_q_bankselect(dap, reg);
-
- if (retval != ERROR_OK)
- return retval;
-
- return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_APACC, reg,
- DPAP_READ, 0, data);
-}
-
-static int jtag_ap_q_write(struct adiv5_dap *dap, unsigned reg,
- uint32_t data)
-{
- uint8_t out_value_buf[4];
-
- int retval = jtag_ap_q_bankselect(dap, reg);
- if (retval != ERROR_OK)
- return retval;
- buf_set_u32(out_value_buf, 0, 32, data);
-
- return adi_jtag_ap_write_check(dap, reg, out_value_buf);
-}
-
-static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack)
-{
- /* for JTAG, this is the only valid ABORT register operation */
- return adi_jtag_dp_scan_u32(dap, JTAG_DP_ABORT,
- 0, DPAP_WRITE, 1, NULL, ack);
-}
-
-static int jtag_dp_run(struct adiv5_dap *dap)
-{
- return jtagdp_transaction_endcheck(dap);
-}
-
-static const struct dap_ops jtag_dp_ops = {
- .queue_idcode_read = jtag_idcode_q_read,
- .queue_dp_read = jtag_dp_q_read,
- .queue_dp_write = jtag_dp_q_write,
- .queue_ap_read = jtag_ap_q_read,
- .queue_ap_write = jtag_ap_q_write,
- .queue_ap_abort = jtag_ap_q_abort,
- .run = jtag_dp_run,
-};
+/* FIXME don't import ... just initialize as
+ * part of DAP transport setup
+*/
+extern const struct dap_ops jtag_dp_ops;
/*--------------------------------------------------------------------------*/
@@ -1988,57 +1630,3 @@ int dap_to_swd(struct target *target)
return retval;
}
-/**
- * This represents the bits which must be sent out on TMS/SWDIO to
- * switch a DAP implemented using an SWJ-DP module into JTAG mode.
- * These bits are stored (and transmitted) LSB-first.
- *
- * These bits are stored (and transmitted) LSB-first.
- */
-static const uint8_t swd2jtag_bitseq[] = {
- /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
- * putting both JTAG and SWD logic into reset state.
- */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- /* Switching equence disables SWD and enables JTAG
- * NOTE: bits in the DP's IDCODE can expose the need for
- * the old/deprecated sequence (0xae 0xde).
- */
- 0x3c, 0xe7,
- /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high,
- * putting both JTAG and SWD logic into reset state.
- * NOTE: some docs say "at least 5".
- */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
-/** Put the debug link into JTAG mode, if the target supports it.
- * The link's initial mode may be either SWD or JTAG.
- *
- * @param target Enters JTAG mode (if possible).
- *
- * Note that targets implemented with SW-DP do not support JTAG, and
- * that some targets which could otherwise support it may have been
- * configured to disable JTAG signaling
- *
- * @return ERROR_OK or else a fault code.
- */
-int dap_to_jtag(struct target *target)
-{
- int retval;
-
- LOG_DEBUG("Enter JTAG mode");
-
- /* REVISIT it's nasty to need to make calls to a "jtag"
- * subsystem if the link isn't in JTAG mode...
- */
-
- retval = jtag_add_tms_seq(8 * sizeof(swd2jtag_bitseq),
- swd2jtag_bitseq, TAP_RESET);
- if (retval == ERROR_OK)
- retval = jtag_execute_queue();
-
- /* REVISIT set up the DAP's ops vector for JTAG mode. */
-
- return retval;
-}
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index d207fd9c..4ee36ff1 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -32,15 +32,11 @@
#include "arm_jtag.h"
-/* JTAG instructions/registers for JTAG-DP and SWJ-DP */
-#define JTAG_DP_ABORT 0x8
+/* FIXME remove these JTAG-specific decls when mem_ap_read_buf_u32()
+ * is no longer JTAG-specific
+ */
#define JTAG_DP_DPACC 0xA
#define JTAG_DP_APACC 0xB
-#define JTAG_DP_IDCODE 0xE
-
-/* three-bit ACK values for DPACC and APACC reads */
-#define JTAG_ACK_OK_FAULT 0x2
-#define JTAG_ACK_WAIT 0x1
/* three-bit ACK values for SWD access (sent LSB first) */
#define SWD_ACK_OK 0x4