commit d8209428eb028a358f41c50ee3200ea5202550ca
parent 5bdbf977007e9c52b171e979f0cbfeae1ec3090d
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 22 Sep 2014 19:27:30 -0700
add enumeration and selection support
Diffstat:
M | jtag-core.c | | | 148 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | jtag.h | | | 25 | +++++++++++++++++++++++++ |
2 files changed, 161 insertions(+), 12 deletions(-)
diff --git a/jtag-core.c b/jtag-core.c
@@ -18,6 +18,30 @@
#include "jtag-driver.h"
+
+#define ZYNQID(code) ((0x1B<<21)|(0x9<<17)|((code)<<12)|(0x49<<1)|1)
+#define ZYNQMASK 0x0FFFFFFF
+
+static JTAG_INFO LIBRARY[] = {
+ { 0x4ba00477, 0xFFFFFFFF, 4, "Cortex A9" },
+ { ZYNQID(0x02), ZYNQMASK, 6, "xc7x010" },
+ { ZYNQID(0x1b), ZYNQMASK, 6, "xc7x015" },
+ { ZYNQID(0x07), ZYNQMASK, 6, "xc7x020" },
+ { ZYNQID(0x0c), ZYNQMASK, 6, "xc7x030" },
+ { ZYNQID(0x11), ZYNQMASK, 6, "xc7x045" },
+ { 0x13631093, 0xFFFFFFFF, 6, "xc7a100t" },
+};
+
+JTAG_INFO *jtag_lookup_device(unsigned idcode) {
+ int n;
+ for (n = 0; n < (sizeof(LIBRARY)/sizeof(LIBRARY[0])); n++) {
+ if ((idcode & LIBRARY[n].idmask) == LIBRARY[n].idcode) {
+ return LIBRARY + n;
+ }
+ }
+ return NULL;
+}
+
#define TRACE_STATEMACHINE 0
// configuration and state or IR or DR
@@ -30,6 +54,8 @@ typedef struct JREG {
u32 idlestate;
} JREG;
+#define DEVMAX 32
+
// configuration and state of JTAG
struct JTAG {
JDRV *drv;
@@ -39,6 +65,9 @@ struct JTAG {
JREG dr;
u32 state;
+
+ int devcount;
+ JTAG_INFO devinfo[DEVMAX];
};
#define _setspeed(khz) \
@@ -52,8 +81,22 @@ struct JTAG {
#define _close() \
jtag->vt->close(jtag->drv)
-static u8 ZEROS[32];
-static u8 ONES[32];
+static u8 ONES[1024];
+
+void jtag_clear_state(JTAG *jtag) {
+ jtag->ir.idlestate = JTAG_IDLE;
+ jtag->ir.scanstate = JTAG_IRSHIFT;
+ jtag->dr.idlestate = JTAG_IDLE;
+ jtag->dr.scanstate = JTAG_DRSHIFT;
+ jtag->ir.prebits = 0;
+ jtag->ir.precount = 0;
+ jtag->ir.postbits = 0;
+ jtag->ir.postcount = 0;
+ jtag->dr.prebits = 0;
+ jtag->dr.precount = 0;
+ jtag->dr.postbits = 0;
+ jtag->dr.postcount = 0;
+}
int jtag_init(JTAG **_jtag, JDRV *drv, JDVT *vt) {
JTAG *jtag;
@@ -63,13 +106,9 @@ int jtag_init(JTAG **_jtag, JDRV *drv, JDVT *vt) {
memset(jtag, 0, sizeof(JTAG));
jtag->drv = drv;
jtag->vt = vt;
- jtag->ir.idlestate = JTAG_IDLE;
- jtag->ir.scanstate = JTAG_IRSHIFT;
- jtag->dr.idlestate = JTAG_IDLE;
- jtag->dr.scanstate = JTAG_DRSHIFT;
+ jtag_clear_state(jtag);
*_jtag = jtag;
- memset(ZEROS, 0x00, 32);
- memset(ONES, 0xFF, 32);
+ memset(ONES, 0xFF, sizeof(ONES));
return 0;
}
@@ -91,19 +130,19 @@ void jtag_set_dr_idle(JTAG *jtag, unsigned state) {
}
void jtag_set_ir_prefix(JTAG *jtag, unsigned count, const void *bits) {
- jtag->ir.prebits = (u8*) bits;
+ jtag->ir.prebits = count ? (u8*) bits : 0;
jtag->ir.precount = count;
}
void jtag_set_ir_postfix(JTAG *jtag, unsigned count, const void *bits) {
- jtag->ir.postbits = (u8*) bits;
+ jtag->ir.postbits = count ? (u8*) bits : 0;
jtag->ir.postcount = count;
}
void jtag_set_dr_prefix(JTAG *jtag, unsigned count, const void *bits) {
- jtag->dr.prebits = (u8*) bits;
+ jtag->dr.prebits = count ? (u8*) bits : 0;
jtag->dr.precount = count;
}
void jtag_set_dr_postfix(JTAG *jtag, unsigned count, const void *bits) {
- jtag->dr.postbits = (u8*) bits;
+ jtag->dr.postbits = count ? (u8*) bits : 0;
jtag->dr.postcount = count;
}
@@ -252,3 +291,88 @@ void jtag_dr_io(JTAG *jtag, unsigned count, const void *wbits, void *rbits) {
int jtag_commit(JTAG *jtag) {
return _commit();
}
+
+int jtag_enumerate(JTAG *jtag) {
+ JTAG_INFO *info;
+ u32 data[DEVMAX];
+ int n;
+
+ jtag_clear_state(jtag);
+ jtag->devcount = 0;
+
+ jtag_goto(jtag, JTAG_RESET);
+ jtag_goto(jtag, JTAG_RESET);
+ jtag_goto(jtag, JTAG_RESET);
+ jtag_dr_io(jtag, DEVMAX * 4 * 8, ONES, data);
+ if (jtag_commit(jtag)) {
+ return -1;
+ }
+ for (n = 0; n < DEVMAX; n++) {
+
+ if (data[n] == 0xffffffff) {
+ if (n == 0) {
+ fprintf(stderr, "no devices found\n");
+ return -1;
+ }
+ jtag->devcount = n;
+ return n;
+ }
+ if (!(data[n] & 1)) {
+ fprintf(stderr, "device %d has no idcode\n", n);
+ return -1;
+ }
+ if ((info = jtag_lookup_device(data[n])) == NULL) {
+ fprintf(stderr, "device %d (id %08x) unknown\n",
+ n, (unsigned) data[n]);
+ return -1;
+ }
+ memcpy(jtag->devinfo + n, info, sizeof(JTAG_INFO));
+ fprintf(stderr, "device %02d idcode %08x '%s'\n",
+ n, info->idcode, info->name);
+ }
+ fprintf(stderr, "too many devices\n");
+ return -1;
+}
+
+JTAG_INFO *jtag_get_nth_device(JTAG *jtag, int n) {
+ if ((n >= jtag->devcount) || (n < 0)) {
+ return NULL;
+ }
+ return jtag->devinfo + n;
+}
+
+int jtag_select_device_nth(JTAG *jtag, int num) {
+ u32 irpre = 0;
+ u32 irpost = 0;
+ u32 drpre = 0;
+ u32 drpost = 0;
+ int n;
+ if ((num >= jtag->devcount) || (num < 0)) {
+ return -1;
+ }
+ for (n = 0; n < jtag->devcount; n++) {
+ if (n < num) {
+ irpre += jtag->devinfo[n].irsize;
+ drpre += 1;
+ } else if (n > num) {
+ irpost += jtag->devinfo[n].irsize;
+ drpost += 1;
+ }
+ }
+ jtag_set_ir_prefix(jtag, irpre, ONES);
+ jtag_set_ir_postfix(jtag, irpost, ONES);
+ jtag_set_dr_prefix(jtag, drpre, ONES);
+ jtag_set_dr_postfix(jtag, drpost, ONES);
+ return 0;
+}
+
+int jtag_select_device(JTAG *jtag, unsigned idcode) {
+ int n;
+ for (n = 0; n < jtag->devcount; n++) {
+ if (jtag->devinfo[n].idcode == idcode) {
+ return jtag_select_device_nth(jtag, n);
+ }
+ }
+ return -1;
+}
+
diff --git a/jtag.h b/jtag.h
@@ -52,6 +52,10 @@ void jtag_set_ir_postfix(JTAG *jtag, unsigned count, const void *bits);
void jtag_set_dr_prefix(JTAG *jtag, unsigned count, const void *bits);
void jtag_set_dr_postfix(JTAG *jtag, unsigned count, const void *bits);
+// clear all prefix/postfix patterns and return to default
+// idle states
+void jtag_clear_state(JTAG *jtag);
+
// Move jtag state machine from current state to new state.
// Moving to JTAG_RESET will work even if current state
// is out of sync.
@@ -69,4 +73,25 @@ void jtag_dr_io(JTAG *jtag, unsigned count, const void *wbits, void *rbits);
int jtag_commit(JTAG *jtag);
+typedef struct {
+ unsigned idcode;
+ unsigned idmask;
+ unsigned irsize;
+ const char *name;
+} JTAG_INFO;
+
+// reset the bus and probe it
+// returns number of devices detected, negative on error
+int jtag_enumerate(JTAG *jtag);
+
+// get information about the nth device on the chain
+JTAG_INFO *jtag_get_nth_device(JTAG *jtag, int n);
+
+// configure for communication with a single device
+// will setup ir/dr prefix and postfix
+int jtag_select_device(JTAG *jtag, unsigned idcode);
+
+// select by position in scan chain
+int jtag_select_device_nth(JTAG *jtag, int n);
+
#endif