jtagonizer

yet another JTAG tool
git clone http://frotz.net/git/jtagonizer.git
Log | Files | Refs | README

dap.c (9437B)


      1 // Copyright 2014 Brian Swetland <swetland@frotz.net>
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 
     19 #include "dap.h"
     20 #include "dap-registers.h"
     21 
     22 #define CSW_ERRORS (DPCSW_STICKYERR | DPCSW_STICKYCMP | DPCSW_STICKYORUN)
     23 #define CSW_ENABLES (DPCSW_CSYSPWRUPREQ | DPCSW_CDBGPWRUPREQ | DPCSW_ORUNDETECT)
     24 
     25 #include <time.h>
     26 static u64 NOW(void) {
     27 	struct timespec ts;
     28 	if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) return 0;
     29 	return (((u64) ts.tv_sec) * ((u64)1000000000)) + ((u64) ts.tv_nsec);
     30 }
     31 
     32 struct DAP {
     33 	JTAG *jtag;
     34 	u32 device_id;
     35 	u32 cached_ir;
     36 };
     37 
     38 static void q_dap_ir_wr(DAP *dap, u32 ir) {
     39 	if (dap->cached_ir != ir) {
     40 		dap->cached_ir = ir;
     41 		jtag_ir_wr(dap->jtag, 4, &ir);
     42 	}
     43 }
     44 
     45 // force ir write even if redundant
     46 // used for a timing hack
     47 static void _q_dap_ir_wr(DAP *dap, u32 ir) {
     48 	dap->cached_ir = ir;
     49 	jtag_ir_wr(dap->jtag, 4, &ir);
     50 }
     51 
     52 static void q_dap_dr_io(DAP *dap, u32 bitcount, u64 wdata, u64 *rdata) {
     53 	if (rdata) {
     54 		*rdata = 0;
     55 		jtag_dr_io(dap->jtag, bitcount, &wdata, rdata);
     56 	} else {
     57 		jtag_dr_wr(dap->jtag, bitcount, &wdata);
     58 	}
     59 }
     60 
     61 static void q_dap_abort(DAP *dap) {
     62 	u32 x;
     63 	u64 u;
     64 	x = DAP_IR_ABORT;
     65 	u = 8;
     66 	jtag_ir_wr(dap->jtag, 4, &x);
     67 	jtag_dr_wr(dap->jtag, 35, &u);
     68 	dap->cached_ir = 0xFFFFFFFF;
     69 }
     70 
     71 // queue a DPCSW status query, commit jtag txn
     72 static int dap_commit(DAP *dap) {
     73 	u64 a, b;
     74 	q_dap_ir_wr(dap, DAP_IR_DPACC);
     75 	q_dap_dr_io(dap, 35, XPACC_RD(DPACC_CSW), &a);
     76 	q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &b);
     77 	dap->cached_ir = 0xFFFFFFFF;
     78 	if (jtag_commit(dap->jtag)) {
     79 		return -1;
     80 	}
     81 	if (XPACC_STATUS(a) != XPACC_OK) {
     82 		fprintf(stderr, "dap: invalid txn status\n");
     83 		return -1;
     84 	}
     85 	if (XPACC_STATUS(b) != XPACC_OK) {
     86 		fprintf(stderr, "dap: cannot read status\n");
     87 		return -1;
     88 	}
     89 	b >>= 3;
     90 	if (b & DPCSW_STICKYORUN) {
     91 		fprintf(stderr, "dap: overrun\n");
     92 		return -1;
     93 	}
     94 	if (b & DPCSW_STICKYERR) {
     95 		fprintf(stderr, "dap: error\n");
     96 		return -1;
     97 	}
     98 	return 0;
     99 }
    100 
    101 int dap_dp_rd(DAP *dap, u32 addr, u32 *val) {
    102 	u64 u;
    103 	q_dap_ir_wr(dap, DAP_IR_DPACC);
    104 	q_dap_dr_io(dap, 35, XPACC_RD(addr), NULL);
    105 	q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
    106 	if (jtag_commit(dap->jtag)) {
    107 		return -1;
    108 	}
    109 	if (XPACC_STATUS(u) != XPACC_OK) {
    110 		return -1;
    111 	}
    112 	*val = u >> 3;
    113 	return 0;
    114 }
    115 
    116 static void q_dap_dp_wr(DAP *dap, u32 addr, u32 val) {
    117 	q_dap_ir_wr(dap, DAP_IR_DPACC);
    118 	q_dap_dr_io(dap, 35, XPACC_WR(addr, val), NULL);
    119 	//q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &s->u);
    120 }
    121 
    122 int dap_dp_wr(DAP *dap, u32 addr, u32 val) {
    123 	q_dap_dp_wr(dap, addr, val);
    124 	return jtag_commit(dap->jtag);
    125 }
    126 
    127 int dap_ap_rd(DAP *dap, u32 apnum, u32 addr, u32 *val) {
    128 	u64 u;
    129 	q_dap_ir_wr(dap, DAP_IR_DPACC);
    130 	q_dap_dp_wr(dap, DPACC_SELECT, DPSEL_APSEL(apnum) | DPSEL_APBANKSEL(addr));
    131 	q_dap_ir_wr(dap, DAP_IR_APACC);
    132 	q_dap_dr_io(dap, 35, XPACC_RD(addr), NULL);
    133 	q_dap_ir_wr(dap, DAP_IR_DPACC);
    134 	q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
    135 	// TODO: redundant ir wr
    136 	if (dap_commit(dap)) {
    137 		return -1;
    138 	}
    139 	*val = (u >> 3);
    140 	return 0;
    141 }
    142 
    143 void q_dap_ap_wr(DAP *dap, u32 apnum, u32 addr, u32 val) {
    144 	q_dap_ir_wr(dap, DAP_IR_DPACC);
    145 	q_dap_dp_wr(dap, DPACC_SELECT, DPSEL_APSEL(apnum) | DPSEL_APBANKSEL(addr));
    146 	q_dap_ir_wr(dap, DAP_IR_APACC);
    147 	q_dap_dr_io(dap, 35, XPACC_WR(addr, val), NULL);
    148 }
    149 
    150 int dap_mem_wr32(DAP *dap, u32 n, u32 addr, u32 val) {
    151 	if (addr & 3)
    152 		return -1;
    153 	q_dap_ap_wr(dap, n, APACC_CSW,
    154 		APCSW_DBGSWEN | APCSW_INCR_NONE | APCSW_SIZE32);
    155 	q_dap_ap_wr(dap, n, APACC_TAR, addr);
    156 	q_dap_ap_wr(dap, n, APACC_DRW, val);
    157 	return dap_commit(dap);
    158 }
    159 
    160 int dap_mem_rd32(DAP *dap, u32 n, u32 addr, u32 *val) {
    161 	if (addr & 3)
    162 		return -1;
    163 	q_dap_ap_wr(dap, n, APACC_TAR, addr);
    164 	if (dap_ap_rd(dap, n, APACC_DRW, val))
    165 		return -1;
    166 	return 0;
    167 }
    168 
    169 int dap_mem_read(DAP *dap, u32 apnum, u32 addr, void *data, u32 len) {
    170 	u64 scratch[1024];
    171 	u32 *x = data;
    172 	u32 n;
    173 
    174 	if ((addr & 3) || (((u64) data) & 3)) {
    175 		// base and length must be aligned
    176 		return -1;
    177 	}
    178 
    179 	while (len > 0) {
    180 		// max transfer is 1K
    181 		// transfer may not cross 1K boundary
    182 		u32 xfer = 1024 - (addr & 0x3FF);
    183 		if (xfer > len) {
    184 			xfer = len;
    185 		}
    186 		q_dap_ap_wr(dap, apnum, APACC_CSW,
    187 			APCSW_DBGSWEN | APCSW_INCR_SINGLE | APCSW_SIZE32);
    188 		q_dap_dr_io(dap, 35, XPACC_WR(APACC_TAR, addr), NULL);
    189 		// read txn will be returned on the next txn
    190 		q_dap_dr_io(dap, 35, XPACC_RD(APACC_DRW), NULL);
    191 		_q_dap_ir_wr(dap, DAP_IR_APACC); // HACK, timing
    192 		for (n = 0; n < (xfer-4); n += 4) {
    193 			q_dap_dr_io(dap, 35, XPACC_RD(APACC_DRW), &scratch[n/4]);
    194 			_q_dap_ir_wr(dap, DAP_IR_APACC); // HACK, timing
    195 		}
    196 		// dummy read of TAR to pick up last read value
    197 		q_dap_dr_io(dap, 35, XPACC_RD(APACC_TAR), &scratch[n/4]);
    198 		if (dap_commit(dap)) {
    199 			return -1;
    200 		}
    201 		for (n = 0; n < xfer; n += 4) {
    202 			switch(XPACC_STATUS(scratch[n/4])) {
    203 			case XPACC_WAIT: fprintf(stderr,"w"); break;
    204 			case XPACC_OK: fprintf(stderr,"o"); break;
    205 			default: fprintf(stderr,"?"); break;
    206 			}
    207 			*x++ = scratch[n/4] >> 3;
    208 		}
    209 		fprintf(stderr,"\n");
    210 		len -= xfer;
    211 		addr += xfer;
    212 	}
    213 	return 0;
    214 }
    215 
    216 int dap_mem_write(DAP *dap, u32 apnum, u32 addr, void *data, u32 len) {
    217 	u32 *x = data;
    218 	u32 n;
    219 
    220 	if ((addr & 3) || (((u64) data) & 3)) {
    221 		// base and length must be aligned
    222 		return -1;
    223 	}
    224 
    225 	while (len > 0) {
    226 		// max transfer is 1K
    227 		// transfer may not cross 1K boundary
    228 		u32 xfer = 1024 - (addr & 0x3FF);
    229 		if (xfer > len) {
    230 			xfer = len;
    231 		}
    232 		q_dap_ap_wr(dap, apnum, APACC_CSW, APCSW_DBGSWEN | APCSW_INCR_SINGLE | APCSW_SIZE32);
    233 		q_dap_dr_io(dap, 35, XPACC_WR(APACC_TAR, addr), NULL);
    234 		for (n = 0; n < xfer; n += 4) {
    235 			_q_dap_ir_wr(dap, DAP_IR_APACC); // HACK, timing
    236 			q_dap_dr_io(dap, 35, XPACC_WR(APACC_DRW, *x++), NULL);
    237 		}
    238 		if (dap_commit(dap)) {
    239 			return -1;
    240 		} 
    241 		len -= xfer;
    242 		addr += xfer;
    243 	}
    244 	return 0;
    245 }
    246 
    247 DAP *dap_init(JTAG *jtag, u32 id) {
    248 	DAP *dap = malloc(sizeof(DAP));
    249 	memset(dap, 0, sizeof(DAP));
    250 	dap->jtag = jtag;
    251 	dap->cached_ir = 0xFFFFFFFF;
    252 	dap->device_id = id;
    253 	return dap;
    254 }
    255 
    256 int dap_attach(DAP *dap) {
    257 	unsigned n;
    258 	u32 x;
    259 
    260 	if (jtag_enumerate(dap->jtag) < 0) {
    261 		fprintf(stderr, "dap: jtag enumeration failed\n");
    262 		return -1;
    263 	}
    264 	if (jtag_select_device(dap->jtag, dap->device_id)) {
    265 		fprintf(stderr, "dap: cannot find device on chain\n");
    266 		return -1;
    267 	}
    268 
    269 	// make sure we abort any ongoing transactions first
    270 	q_dap_abort(dap);
    271 
    272 	// attempt to power up and clear errors
    273 	for (n = 0; n < 10; n++) {
    274 		if (dap_dp_wr(dap, DPACC_CSW, CSW_ERRORS | CSW_ENABLES))
    275 			continue;
    276 		if (dap_dp_rd(dap, DPACC_CSW, &x))
    277 			continue;
    278 		if (x & CSW_ERRORS)
    279 			continue;
    280 		if (!(x & DPCSW_CSYSPWRUPACK))
    281 			continue;
    282 		if (!(x & DPCSW_CDBGPWRUPACK))
    283 			continue;
    284 		return 0;
    285 	}
    286 	fprintf(stderr,"dap: attach failed\n");
    287 	return -1;
    288 }
    289 
    290 static int read4xid(DAP *dap, u32 n, u32 addr, u32 *val) {
    291 	u32 a,b,c,d;
    292 	if (dap_mem_rd32(dap, n, addr + 0x00, &a)) return -1;
    293 	if (dap_mem_rd32(dap, n, addr + 0x04, &b)) return -1;
    294 	if (dap_mem_rd32(dap, n, addr + 0x08, &c)) return -1;
    295 	if (dap_mem_rd32(dap, n, addr + 0x0C, &d)) return -1;
    296 	*val = (a & 0xFF) | ((b & 0xFF) << 8) | ((c & 0xFF) << 16) | ((d & 0xFF) << 24);
    297 	return 0;
    298 }
    299 
    300 static int readinfo(DAP *dap, u32 n, u32 base, u32 *cid, u32 *pid0, u32 *pid1) {
    301 	if (read4xid(dap, n, base + 0xFF0, cid)) return -1;
    302 	if (read4xid(dap, n, base + 0xFE0, pid0)) return -1;
    303 	if (read4xid(dap, n, base + 0xFD0, pid1)) return -1;
    304 	return 0;
    305 }
    306 
    307 static void dumptable(DAP *dap, u32 n, u32 base) {
    308 	u32 cid, pid0, pid1, memtype;
    309 	u32 x, addr;
    310 	int i;
    311 
    312 	printf("TABLE   @%08x ", base);
    313 	if (readinfo(dap, n, base, &cid, &pid0, &pid1)) {
    314 		printf("<error reading cid & pid>\n");
    315 		return;
    316 	}
    317 	if (dap_mem_rd32(dap, n, base + 0xFCC, &memtype)) {
    318 		printf("<error reading memtype>\n");
    319 		return;
    320 	}
    321 	printf("CID %08x  PID %08x %08x  %dKB%s\n", cid, pid1, pid0,
    322 		4 * (1 + ((pid1 & 0xF0) >> 4)),
    323 		(memtype & 1) ? "  SYSMEM": "");
    324 	for (i = 0; i < 128; i++) {
    325 		if (dap_mem_rd32(dap, n, base + i * 4, &x)) break;
    326 		if (x == 0) break;
    327 		if ((x & 3) != 3) continue;
    328 		addr = base + (x & 0xFFFFF000);
    329 		if (readinfo(dap, n, addr, &cid, &pid0, &pid1)) {
    330 			printf("    <error reading cid & pid>\n");
    331 			continue;
    332 		}
    333 		printf("    %02d: @%08x CID %08x  PID %08x %08x  %dKB\n",
    334 			i, addr, cid, pid1, pid0,
    335 			4 * (1 + ((pid1 & 0xF0) >> 4)));
    336 		if (((cid >> 12) & 0xF) == 1) {
    337 			dumptable(dap, n, addr);
    338 		}
    339 	}
    340 }
    341 
    342 int dap_probe(DAP *dap) {
    343 	unsigned n;
    344 	u32 x, y;
    345 
    346 	for (n = 0; n < 256; n++) {
    347 		if (dap_ap_rd(dap, n, APACC_IDR, &x))
    348 			break;
    349 		if (x == 0)
    350 			break;
    351 		y = 0;
    352 		dap_ap_rd(dap, n, APACC_BASE, &y);
    353 		printf("AP%d ID=%08x BASE=%08x\n", n, x, y);
    354 		if (y && (y != 0xFFFFFFFF)) {
    355 			dumptable(dap, n, y);
    356 		}
    357 		if (dap_ap_rd(dap, n, APACC_CSW, &x) == 0)
    358 			printf("AP%d CSW=%08x\n", n, x);
    359 	}
    360 	return 0;
    361 }
    362 
    363 int dap_reset(DAP *dap) {
    364 	u32 x;
    365 	if (dap_dp_wr(dap, DPACC_CSW, CSW_ENABLES | DPCSW_CDBGRSTREQ)) {
    366 		return -1;
    367 	}
    368 	if (dap_dp_rd(dap, DPACC_CSW, &x)) {
    369 		return -1;
    370 	}
    371 	printf("%08x\n", x);
    372 	return 0;
    373 }