commit 55d9eb1f1dc97b76141456d66f088438b08a9c48
parent b5011c8fe6a782310f1345f31807a1afde5520f2
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 22 Sep 2014 22:21:01 -0700
dap: some glue for arm debug access ports
Originally written for the old non-transactional jtag midlayer.
Will need some reshuffling.
Diffstat:
M | Makefile | | | 13 | ++++++++----- |
A | dap.c | | | 257 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | dap.h | | | 71 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 336 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
@@ -4,14 +4,17 @@ CFLAGS := -Wall -O2 -g
LIBS := -lusb-1.0
-all: jtag
+all: jtag dap
JTAG_OBJS := jtag-mpsse-driver.o jtag-core.o jtag.o
-
-$(JTAG_OBJS): jtag.h
-
+$(JTAG_OBJS): jtag.h jtag-driver.h
jtag: $(JTAG_OBJS)
$(CC) -o jtag $(JTAG_OBJS) $(LIBS)
+DAP_OBJS := dap.o jtag-core.o jtag-mpsse-driver.o
+$(DAP_OBJS): jtag.h jtag-driver.h dap.h
+dap: $(DAP_OBJS)
+ $(CC) -o dap $(DAP_OBJS) $(LIBS)
+
clean:
- rm -f *.o jtag
+ rm -f *.o jtag dap
diff --git a/dap.c b/dap.c
@@ -0,0 +1,257 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdio.h>
+#include <string.h>
+
+#include "jtag.h"
+#include "dap.h"
+
+typedef struct {
+ JTAG *jtag;
+ u32 cache_ir;
+ u32 cache_apnum;
+ u32 cache_apaddr;
+} DAP;
+
+int dap_ir_wr(DAP *dap, u32 ir) {
+ if (dap->cache_ir != ir) {
+ jtag_ir_wr(dap->jtag, 4, &ir);
+ if (jtag_commit(dap->jtag)) {
+ dap->cache_ir = 0xFFFFFFFF;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int dap_dr_io(DAP *dap, u32 bitcount, u64 wdata, u64 *rdata) {
+ if (rdata) {
+ *rdata = 0;
+ jtag_dr_io(dap->jtag, bitcount, &wdata, rdata);
+ } else {
+ jtag_dr_wr(dap->jtag, bitcount, &wdata);
+ }
+ return jtag_commit(dap->jtag);
+}
+
+int dap_dp_rd(DAP *dap, u32 addr, u32 *val) {
+ int retry = 30;
+ u64 u;
+ dap_ir_wr(dap, DAP_IR_DPACC);
+ dap_dr_io(dap, 35, XPACC_RD(addr), NULL);
+ while (retry-- > 0) {
+ dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
+ switch (XPACC_STATUS(u)) {
+ case XPACC_OK:
+ *val = u >> 3;
+ return 0;
+ case XPACC_WAIT:
+ fprintf(stderr,"!");
+ continue;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+int dap_dp_wr(DAP *dap, u32 addr, u32 val) {
+ int retry = 100;
+ u64 u;
+ u = XPACC_WR(addr);
+ u |= (((u64) val) << 3);
+ dap_ir_wr(dap, DAP_IR_DPACC);
+ dap_dr_io(dap, 35, u, NULL);
+ while (retry-- > 0) {
+ dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
+ switch (XPACC_STATUS(u)) {
+ case XPACC_OK:
+ return 0;
+ case XPACC_WAIT:
+ fprintf(stderr,"!");
+ continue;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+/* TODO: cache state, check errors */
+int dap_ap_rd(DAP *dap, u32 apnum, u32 addr, u32 *val) {
+ u64 u;
+ if ((dap->cache_apnum != apnum) || (dap->cache_apaddr != (addr & 0xFFFFFFF0))) {
+ if (dap_dp_wr(dap, DPACC_SELECT,
+ DPSEL_APSEL(apnum) | DPSEL_APBANKSEL(addr))) {
+ dap->cache_apnum = 0xFFFFFFFF;
+ dap->cache_apaddr = 0xFFFFFFFF;
+ return -1;
+ }
+ dap->cache_apnum = apnum;
+ dap->cache_apaddr = addr;
+ }
+ dap_ir_wr(dap, DAP_IR_APACC);
+ dap_dr_io(dap, 35, XPACC_RD(addr), NULL);
+ dap_ir_wr(dap, DAP_IR_DPACC);
+ dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
+ *val = (u >> 3);
+ return 0;
+}
+
+int dap_ap_wr(DAP *dap, u32 apnum, u32 addr, u32 val) {
+ u64 u;
+ if ((dap->cache_apnum != apnum) || (dap->cache_apaddr != (addr & 0xFFFFFFF0))) {
+ if (dap_dp_wr(dap, DPACC_SELECT,
+ DPSEL_APSEL(apnum) | DPSEL_APBANKSEL(addr))) {
+ dap->cache_apnum = 0xFFFFFFFF;
+ dap->cache_apaddr = 0xFFFFFFFF;
+ return -1;
+ }
+ dap->cache_apnum = apnum;
+ dap->cache_apaddr = addr;
+ }
+ dap_ir_wr(dap, DAP_IR_APACC);
+ u = XPACC_WR(addr);
+ u |= (((u64) val) << 3);
+ dap_dr_io(dap, 35, u, NULL);
+ dap_ir_wr(dap, DAP_IR_DPACC);
+ dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
+ return 0;
+}
+
+int dap_ap_wr_x(DAP *dap, u32 apnum, u32 addr, u32 val) {
+ u64 u;
+ if ((dap->cache_apnum != apnum) || (dap->cache_apaddr != (addr & 0xFFFFFFF0))) {
+ if (dap_dp_wr(dap, DPACC_SELECT,
+ DPSEL_APSEL(apnum) | DPSEL_APBANKSEL(addr))) {
+ dap->cache_apnum = 0xFFFFFFFF;
+ dap->cache_apaddr = 0xFFFFFFFF;
+ return -1;
+ }
+ dap->cache_apnum = apnum;
+ dap->cache_apaddr = addr;
+ }
+ dap_ir_wr(dap, DAP_IR_APACC);
+ u = XPACC_WR(addr);
+ u |= (((u64) val) << 3);
+ dap_dr_io(dap, 35, u, NULL);
+ return 0;
+}
+void dap_flush_cache(DAP *dap) {
+ dap->cache_ir = 0xFFFFFFFF;
+ dap->cache_apnum = 0xFFFFFFFF;
+ dap->cache_apaddr = 0xFFFFFFFF;
+}
+
+DAP *dap_init(JTAG *jtag) {
+ DAP *dap = malloc(sizeof(DAP));
+ memset(dap, 0, sizeof(DAP));
+ dap->jtag = jtag;
+ dap_flush_cache(dap);
+ return dap;
+}
+
+int dap_attach(DAP *dap) {
+ unsigned n;
+ u32 x;
+ // attempt to power up and clear errors
+ for (n = 0; n < 100; n++) {
+ if (dap_dp_wr(dap, DPACC_CSW,
+ DPCSW_CSYSPWRUPREQ | DPCSW_CDBGPWRUPREQ |
+ DPCSW_STICKYERR | DPCSW_STICKYCMP | DPCSW_STICKYORUN))
+ continue;
+ if (dap_dp_rd(dap, DPACC_CSW, &x))
+ continue;
+ if (x & (DPCSW_STICKYERR | DPCSW_STICKYCMP | DPCSW_STICKYORUN))
+ continue;
+ if (!(x & DPCSW_CSYSPWRUPACK))
+ continue;
+ if (!(x & DPCSW_CDBGPWRUPACK))
+ continue;
+ return 0;
+ }
+ fprintf(stderr,"dap: attach failed\n");
+ return -1;
+}
+
+int dap_mem_wr32(DAP *dap, u32 addr, u32 val) {
+ if (addr & 3)
+ return -1;
+ if (dap_ap_wr(dap, 0, APACC_TAR, addr))
+ return -1;
+ if (dap_ap_wr(dap, 0, APACC_DRW, val))
+ return -1;
+ return 0;
+}
+
+int dap_mem_rd32(DAP *dap, u32 addr, u32 *val) {
+ if (addr & 3)
+ return -1;
+ if (dap_ap_wr(dap, 0, APACC_TAR, addr))
+ return -1;
+ if (dap_ap_rd(dap, 0, APACC_DRW, val))
+ return -1;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ JTAG *jtag;
+ DAP *dap;
+ unsigned n;
+ u64 u;
+ u32 x;
+
+ if (jtag_mpsse_open(&jtag)) return -1;
+ if (jtag_enumerate(jtag) < 0) return -1;
+ if (jtag_select_device(jtag, 0x4ba00477)) return -1;
+
+ dap = dap_init(jtag);
+ if (dap_attach(dap))
+ return -1;
+
+ for (n = 0; n < 256; n++) {
+ if (dap_ap_rd(dap, n, APACC_IDR, &x))
+ break;
+ if (x == 0)
+ break;
+ printf("AP%d ID=%08x\n", n, x);
+ if (dap_ap_rd(dap, n, APACC_CSW, &x) == 0)
+ printf("AP%d CSW=%08x\n", n, x);
+ }
+
+#if 1
+ for (n = 0; n < 8; n++) {
+ dap_mem_rd32(dap, n*4, &x);
+ printf("%08x: %08x\n", n*4, x);
+ }
+#endif
+
+#if 0
+ for (n = 0; n < 4096; n++) {
+ dap_mem_wr32(dap, n*4, 0xeeeeeeee);
+ }
+ return 0;
+#endif
+
+#if 0
+ dap_ap_wr(dap, 0, APACC_CSW, APCSW_DBGSWEN | APCSW_INCR_SINGLE | APCSW_SIZE32);
+ dap_ap_wr(dap, 0, APACC_TAR, n);
+ for (n = 0; n < 4096; n++) {
+ dap_ap_wr_x(dap, 0, APACC_DRW, 0xaaaaaaaa);
+ }
+ return 0;
+#endif
+ return 0;
+}
diff --git a/dap.h b/dap.h
@@ -0,0 +1,71 @@
+
+/* ARM DAP Controller (4bit IR) */
+#define DAP_IR_SIZE 4
+
+#define DAP_IR_ABORT 0x08
+#define DAP_IR_DPACC 0x0A
+#define DAP_IR_APACC 0x0B
+#define DAP_IR_IDCODE 0x0E
+#define DAP_IR_BYPASS 0x0F
+
+/* DPACC/APACC DR bits */
+#define XPACC_STATUS(n) ((n) & 0x3)
+#define XPACC_WAIT 0x1
+#define XPACC_OK 0x2
+#define XPACC_RD(n) (0x1 | (((n) >> 1) & 6))
+#define XPACC_WR(n) (0x0 | (((n) >> 1) & 6))
+
+/* DP addresses */
+#define DPACC_RESERVED 0x0
+#define DPACC_CSW 0x4
+#define DPACC_SELECT 0x8
+#define DPACC_RDBUFF 0xC
+
+#define DPCSW_CSYSPWRUPACK (1 << 31)
+#define DPCSW_CSYSPWRUPREQ (1 << 30)
+#define DPCSW_CDBGPWRUPACK (1 << 29)
+#define DPCSW_CDBGPWRUPREQ (1 << 28)
+#define DPCSW_CDBGRSTACK (1 << 27)
+#define DPCSW_CDBGRSTREQ (1 << 26)
+#define DPCSW_TRNCNT(n) (((n) & 0x3FF) << 12)
+#define DPCSW_MASKLANE(n) (((n) & 0xF) << 8) // pushed verify or compare
+#define DPCSW_WDATAERR (1 << 7) // reserved on jtag
+#define DPCSW_READOK (1 << 6) // reserved on jtag
+#define DPCSW_STICKYERR (1 << 5)
+#define DPCSW_STICKYCMP (1 << 4)
+#define DPCSW_TRNMODE_NORMAL (0 << 2)
+#define DPCSW_TRNMODE_PUSH_VRFY (1 << 2)
+#define DPCSW_TRNMODE_PUSH_CMP (2 << 2)
+#define DPCSW_STICKYORUN (1 << 1)
+#define DPCSW_ORUNDETECT (1 << 0)
+
+#define DPSEL_APSEL(n) (((n) & 0xFF) << 24)
+#define DPSEL_APBANKSEL(a) ((a) & 0xF0)
+#define DPSEL_CTRLSEL (1 << 0) // reserved on jtag
+
+/* Reading RDBUFF returns 0, has no side effects */
+/* Can be used to obtain final read result and ack values at end of seq */
+
+/* AP addresses */
+#define APACC_CSW 0x00
+#define APACC_TAR 0x04
+#define APACC_DRW 0x0C
+#define APACC_BD0 0x10
+#define APACC_BD1 0x14
+#define APACC_BD2 0x18
+#define APACC_BD3 0x1C
+#define APACC_CFG 0xF4
+#define APACC_BASE 0xF8
+#define APACC_IDR 0xFC
+
+#define APCSW_DBGSWEN (1 << 31)
+#define APCSW_SPIDEN (1 << 23) // ro
+#define APCSW_TRBUSY (1 << 7) // ro
+#define APCSW_DEVICEEN (1 << 6) // ro
+#define APCSW_INCR_NONE (0 << 4)
+#define APCSW_INCR_SINGLE (1 << 4)
+#define APCSW_INCR_PACKED (2 << 4) // may not be supported
+#define APCSW_SIZE8 (0 << 0) // may not be supported
+#define APCSW_SIZE16 (1 << 0) // may not be supported
+#define APCSW_SIZE32 (2 << 0)
+