jtagonizer

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
MMakefile | 13++++++++-----
Adap.c | 257+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adap.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) +