ref: 2d564a5004850469b4aa5adb85bb07bdc3da03d8
parent: d57f23fb877eecd1f692d73411114110cdd6423b
author: cinap_lenrek <[email protected]>
date: Wed May 13 00:12:49 EDT 2015
boot/zynq: add jtagload utility
--- /dev/null
+++ b/sys/src/boot/zynq/jtagload.c
@@ -1,0 +1,647 @@
+#include <u.h>
+#include <libc.h>
+
+typedef struct Tap Tap;
+typedef struct Dap Dap;
+
+struct Tap
+{
+ int off;
+ int len;
+ int delay;
+
+ u32int id;
+ u32int dapsel;
+};
+
+struct Dap
+{
+ Tap *tap;
+
+ uint port;
+ u32int id;
+};
+
+int dfd = -1;
+int lastbit = -1;
+
+int irlen;
+
+int ntaps;
+Tap* taps;
+
+int ndaps;
+Dap* daps;
+
+Dap* ahbap;
+Dap* apbap;
+
+/* MPSSE command bits */
+enum {
+ FEW = 1<<0, /* -ve CLK on write */
+ BITS = 1<<1, /* bits or bytes */
+ FER = 1<<2, /* -ve CLK on read */
+ LSB = 1<<3, /* LSB first = 1 else MSB first */
+ TDI = 1<<4, /* do write TDI */
+ TDO = 1<<5, /* do read TDO */
+ TMS = 1<<6, /* do write TMS */
+};
+
+void
+ioinit(char *dev)
+{
+ uchar b[3];
+
+ dfd = open(dev, ORDWR);
+ if(dfd < 0)
+ sysfatal("open: %r");
+
+ b[0] = 0x80;
+ b[1] = 0x08;
+ b[2] = 0x0B;
+ write(dfd, b, 3);
+}
+
+void
+io(int cmd, int len, uchar *dat)
+{
+ uchar buf[64];
+ uchar *p = buf;
+
+ *p++ = cmd;
+ *p++ = len-1;
+ if((cmd & BITS) != 0)
+ len = 1;
+ else
+ *p++ = (len-1)>>8;
+ if((cmd & (TDI|TMS)) != 0){
+ memmove(p, dat, len);
+ p += len;
+ }
+ if(write(dfd, buf, p - buf) != (p - buf))
+ sysfatal("io write: %r");
+ if((cmd & TDO) != 0)
+ if(readn(dfd, dat, len) != len)
+ sysfatal("io read: %r");
+}
+
+void
+dstate(u32int s, int len)
+{
+ uchar b[1];
+
+ assert(len < 8);
+ b[0] = s;
+ if(lastbit != -1){
+ b[0] |= lastbit << 7;
+ lastbit = -1;
+ }
+ io(TMS|LSB|BITS|FEW, len, b);
+}
+uvlong
+dshift(uvlong w, int len)
+{
+ uchar b[8];
+ int c, s, n;
+
+ c = TDI|LSB|FEW;
+ if(len < 0){
+ len = -len;
+ c |= TDO;
+ }
+ s = 0;
+ n = len/8;
+ if(n > 0) {
+ switch(n){
+ case 8: b[7] = w >> 56;
+ case 7: b[6] = w >> 48;
+ case 6: b[5] = w >> 40;
+ case 5: b[4] = w >> 32;
+ case 4: b[3] = w >> 24;
+ case 3: b[2] = w >> 16;
+ case 2: b[1] = w >> 8;
+ case 1: b[0] = w >> 0;
+ }
+ io(c, n, b);
+ s = n*8;
+ if((c & TDO) != 0){
+ w &= ~((1ULL<<s)-1);
+ switch(n){
+ case 8: w |= (uvlong)b[7] << 56;
+ case 7: w |= (uvlong)b[6] << 48;
+ case 6: w |= (uvlong)b[5] << 40;
+ case 5: w |= (uvlong)b[4] << 32;
+ case 4: w |= (uvlong)b[3] << 24;
+ case 3: w |= (uvlong)b[2] << 16;
+ case 2: w |= (uvlong)b[1] << 8;
+ case 1: w |= (uvlong)b[0] << 0;
+ }
+ }
+ len -= s;
+ }
+ if(len > 0){
+ b[0] = w >> s;
+ c |= BITS;
+ io(c, len, b);
+ if((c & TDO) != 0){
+ w &= ~((uvlong)((1<<len)-1) << s);
+ w |= (uvlong)(b[0] >> 8-len) << s;
+ }
+ s += len;
+ }
+ return w & (1ULL<<s)-1;
+}
+void
+dshiftones(int len)
+{
+ while(len >= 64){
+ dshift(~0ULL, 64);
+ len -= 64;
+ }
+ dshift(~0ULL, len);
+}
+int
+dshiftdelay(void)
+{
+ int i;
+
+ /* send ones */
+ dshiftones(512);
+ for(i=0; i<512; i++){
+ if(dshift(i != 0, -1) == 0)
+ return i;
+ }
+ return 0;
+}
+
+void
+irw(Tap *tap, uvlong w)
+{
+ /* 0011 -> Shift-IR */
+ dstate(0x3, 4);
+
+ dshiftones(tap->off);
+ if((tap->off + tap->len) == irlen){
+ dshift(w, tap->len-1);
+ lastbit = w >> (tap->len-1);
+ } else {
+ dshift(w, tap->len);
+ dshiftones(irlen - (tap->off + tap->len-1));
+ lastbit = 1;
+ }
+
+ /* 011 -> Idle */
+ dstate(0x3, 3);
+}
+uvlong
+drr(Tap *tap, int len)
+{
+ uvlong w, d;
+
+ /* 001 -> Shift-DR */
+ dstate(0x1, 3);
+
+ d = dshift(0, -tap->delay);
+ w = dshift(0, -len);
+ dshift(d, tap->delay);
+ dshift(w, len-1);
+ lastbit = (w >> len-1) & 1;
+
+ /* 011 -> Idle */
+ dstate(0x3, 3);
+
+ return w;
+}
+void
+drw(Tap *tap, uvlong w, int len)
+{
+ /* 001 -> Shift-DR */
+ dstate(0x1, 3);
+
+ dshift(0, tap->delay);
+ dshift(w, len-1);
+ lastbit = (w >> len-1) & 1;
+
+ /* 011 -> Idle */
+ dstate(0x3, 3);
+}
+
+enum {
+ ABORT = 0x8,
+ DPACC = 0xA,
+ APACC = 0xB,
+ CTRLSTAT = 0x4,
+ SELECT = 0x8,
+ RDBUF = 0xC,
+};
+
+u32int
+dapr(Dap *dap, uchar r, uchar a)
+{
+ uvlong w;
+
+ irw(dap->tap, r);
+ w = 1 | (a >> 1) & 0x6;
+ drw(dap->tap, w, 35);
+ do {
+ w = drr(dap->tap, 35);
+ } while((w & 7) == 1);
+ return w >> 3;
+}
+void
+dapw(Dap *dap, uchar r, uchar a, u32int v)
+{
+ uvlong w;
+
+ irw(dap->tap, r);
+ w = (a >> 1) & 0x6;
+ w |= (uvlong)v << 3;
+ drw(dap->tap, w, 35);
+}
+
+void
+app(Dap *dap)
+{
+ enum {
+ CSYSPWRUPACK = 1<<31,
+ CSYSPWRUPREQ = 1<<30,
+ CDBGPWRUPACK = 1<<29,
+ CDBGPWRUPREQ = 1<<28,
+ CDBGRSTACK = 1<<27,
+ CDBGRSTREQ = 1<<26,
+ };
+ u32int s;
+
+ for(;;){
+ s = dapr(dap, DPACC, CTRLSTAT);
+ if((s & (CDBGPWRUPACK|CSYSPWRUPACK)) == (CDBGPWRUPACK|CSYSPWRUPACK))
+ break;
+ s |= CSYSPWRUPREQ|CDBGPWRUPREQ;
+ dapw(dap, DPACC, CTRLSTAT, s);
+ }
+}
+void
+apa(Dap *dap, uchar a)
+{
+ u32int s;
+
+ s = dap->port<<24 | a&0xf0;
+ if(s != dap->tap->dapsel){
+ dap->tap->dapsel = s;
+ dapw(dap, DPACC, SELECT, s);
+ app(dap);
+ }
+}
+u32int
+apr(Dap *dap, uchar a)
+{
+ apa(dap, a);
+ return dapr(dap, APACC, a&0xC);
+}
+void
+apw(Dap *dap, uchar a, u32int v)
+{
+ apa(dap, a);
+ dapw(dap, APACC, a&0xC, v);
+}
+u32int
+mmr(Dap *ap, u32int addr)
+{
+ apw(ap, 0x4, addr);
+ return apr(ap, 0xC);
+}
+void
+mmw(Dap *ap, u32int addr, u32int val)
+{
+ apw(ap, 0x4, addr);
+ apw(ap, 0xC, val);
+}
+
+void
+tapreset(void)
+{
+ int i, j, o;
+
+ dstate(0x1F, 6); /* 011111 -> Reset->Idle */
+ dstate(0x3, 4); /* 0011 -> Shift-IR */
+
+ irlen = dshiftdelay();
+ lastbit = 1;
+
+ dstate(0x7, 5); /* 00111 -> Shift-IR->Shift-DR */
+
+ ntaps = dshiftdelay();
+
+ dstate(0x1F, 6); /* 011111 -> Reset->Idle */
+ dstate(0x1, 3); /* 001 -> Shift-DR */
+
+ taps = realloc(taps, sizeof(taps[0]) * ntaps);
+
+ o = 0;
+ for(i=ntaps-1; i>=0; i--){
+ taps[i].delay = ntaps - i - 1;
+ taps[i].off = o;
+ taps[i].id = dshift(0, -32);
+ switch(taps[i].id){
+ default:
+ sysfatal("unknown tapid %.8ux\n", taps[i].id);
+ case 0x03727093:
+ case 0x0373b093:
+ case 0x23727093:
+ taps[i].len = 6;
+ break;
+ case 0x4ba00477:
+ taps[i].len = 4;
+ break;
+ }
+ o += taps[i].len;
+ }
+
+ dstate(0x1F, 6); /* 011111 -> Reset->Idle */
+
+ if(o != irlen)
+ sysfatal("wrong tapchain irlen %d %d\n", o, irlen);
+
+ ndaps = 0;
+ for(i=0; i<ntaps; i++){
+ fprint(2, "tap%d: id=%.8ux off=%d len=%d delay=%d\n",
+ i, taps[i].id, taps[i].off, taps[i].len, taps[i].delay);
+
+ switch(taps[i].id){
+ case 0x4ba00477:
+ o = 3;
+ daps = realloc(daps, sizeof(daps[0]) * (ndaps+o));
+ for(j=0; j<o; j++){
+ daps[ndaps].tap = taps+i;
+ daps[ndaps].port = j;
+ daps[ndaps].id = apr(daps+ndaps, 0xFC);
+ fprint(2, "\tdap%d: id=%.8ux\n", j, daps[ndaps].id);
+
+ ndaps++;
+ }
+ break;
+ }
+ }
+
+ for(i=0; i<ndaps; i++){
+ switch(daps[i].id){
+ case 0x44770001:
+ ahbap = daps+i;
+ break;
+ case 0x24770002:
+ apbap = daps+i;
+ break;
+ }
+ }
+}
+
+enum {
+ DBGDIDR = 0x000,
+ DBGDEVID = 0xFC8,
+ DBGDSCR = 0x088,
+ RXfull = 1<<30,
+ TXfull = 1<<29,
+ RXfull_1 = 1<<27,
+ TXfull_1 = 1<<26,
+ PipeAdv = 1<<25,
+ InstrCompl_1 = 1<<24,
+ ExtDCCmodeShift = 20,
+ ExtDCCmodeMask = 3<<ExtDCCmodeShift,
+ ADAdiscard = 1<<19,
+ NS = 1<<18,
+ SPNIDdis = 1<<17,
+ SPIDdis = 1<<16,
+ MDBGen = 1<<15,
+ HDBGen = 1<<14,
+ ITRen = 1<<13,
+ UDCCdis = 1<<12,
+ INTdis = 1<<11,
+ DBGack = 1<<10,
+ UND_1 = 1<<8,
+ ADABORT_1 = 1<<7,
+ SDABORT_1 = 1<<6,
+ MOEShift = 2,
+ MOEMask = 15<<MOEShift,
+ RESTARTED = 1<<1,
+ HALTED = 1<<0,
+
+ DBGDRCR = 0x90,
+ RestartReq = 1<<1,
+ HaltReq = 1<<0,
+
+ DBGPRCR = 0x310,
+
+ DBGITR = 0x084, /* Instruction Transfer Register */
+ DBGDTRRX = 0x080, /* Host to Target Data Transfer Register */
+ DBGDTRTX = 0x08C, /* Target to Host Data Transfer Register */
+};
+
+typedef struct Arm Arm;
+struct Arm
+{
+ u32int dbgbase;
+
+ Dap *dbgap;
+ Dap *memap;
+
+ char *id;
+};
+Arm arm[2];
+u32int
+dbgr(Arm *arm, u32int reg)
+{
+ return mmr(arm->dbgap, arm->dbgbase+reg);
+}
+void
+dbgw(Arm *arm, u32int reg, u32int val)
+{
+ mmw(arm->dbgap, arm->dbgbase+reg, val);
+}
+u32int
+dbgrpoll(Arm *arm, u32int reg, u32int mask, u32int val)
+{
+ u32int w;
+
+ for(;;){
+ w = dbgr(arm, reg);
+ if((w & mask) == val)
+ break;
+ }
+ return w;
+}
+
+void
+startstop(Arm *arm, int stop)
+{
+ u32int s;
+
+ s = dbgr(arm, DBGDSCR);
+ if((s & HALTED) != stop){
+ if(!stop){
+ s &= ~ITRen;
+ dbgw(arm, DBGDSCR, s);
+ }
+ dbgw(arm, DBGDRCR, stop ? HaltReq : RestartReq);
+ s = dbgrpoll(arm, DBGDSCR, HALTED, stop);
+ if(stop){
+ s |= ITRen;
+ dbgw(arm, DBGDSCR, s);
+ }
+ fprint(2, "%s: startstop: %.8ux\n", arm->id, s);
+ }
+}
+
+void
+armxec(Arm *arm, u32int instr)
+{
+ dbgw(arm, DBGITR, instr);
+ dbgrpoll(arm, DBGDSCR, InstrCompl_1, InstrCompl_1);
+}
+
+#define ARMV4_5_MRC(CP, op1, Rd, CRn, CRm, op2) \
+ (0xee100010 | (CRm) | ((op2) << 5) | ((CP) << 8) \
+ | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21))
+#define ARMV4_5_MCR(CP, op1, Rd, CRn, CRm, op2) \
+ (0xee000010 | (CRm) | ((op2) << 5) | ((CP) << 8) \
+ | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21))
+
+void
+trrxw(Arm *arm, u32int val)
+{
+ dbgrpoll(arm, DBGDSCR, RXfull_1, 0);
+ dbgw(arm, DBGDTRRX, val);
+}
+u32int
+trtxr(Arm *arm)
+{
+ dbgrpoll(arm, DBGDSCR, TXfull_1, TXfull_1);
+ return dbgr(arm, DBGDTRTX);
+}
+
+void
+armrw(Arm *arm, int reg, u32int val);
+
+u32int
+armrr(Arm *arm, int rn)
+{
+ if(rn == 15){
+ u32int r0;
+
+ r0 = armrr(arm, 0);
+ armxec(arm, 0xE1A0000F);
+ armxec(arm, ARMV4_5_MCR(14, 0, 0, 0, 5, 0));
+ armrw(arm, 0, r0);
+ } else {
+ armxec(arm, ARMV4_5_MCR(14, 0, rn, 0, 5, 0));
+ }
+ return trtxr(arm);
+}
+void
+armrw(Arm *arm, int rn, u32int val)
+{
+ if(rn == 15){
+ u32int r0;
+
+ r0 = armrr(arm, 0);
+ armrw(arm, 0, val);
+ armxec(arm, 0xE1A0F000);
+ armrw(arm, 0, r0);
+ } else {
+ trrxw(arm, val);
+ armxec(arm, ARMV4_5_MRC(14, 0, rn, 0, 5, 0));
+ }
+}
+
+/*
+ * mww phys 0xf8000008 0xdf0d
+ * mww phys 0xf8000910 0xf
+ * load_image "/sys/src/boot/zynq/fsbl" 0xfffc0000 bin
+ * reg pc 0xfffc0000
+ */
+void
+boot(char *file, u32int entry)
+{
+ u32int *buf, *src;
+ int fd, size;
+ u32int dst;
+
+ fprint(2, "load %s", file);
+ if((fd = open(file, OREAD)) < 0)
+ sysfatal("open: %r");
+
+ size = seek(fd, 0, 2);
+ fprint(2, " [%ud]", size);
+ seek(fd, 0, 0);
+ buf = malloc((size+3) & ~3);
+ if(readn(fd, buf, size) != size)
+ sysfatal("read: %r");
+ close(fd);
+
+ /* map ocm */
+ mmw(arm->memap, 0xf8000008, 0xdf0d);
+ mmw(arm->memap, 0xf8000910, 0xf);
+
+ src = buf;
+ for(dst = entry; size > 0; dst += 4, size -= 4){
+ if((dst & 0xF) == 0)
+ fprint(2, ".");
+ mmw(arm->memap, dst, *src++);
+ }
+ free(buf);
+ fprint(2, ".\nentry %.8ux\n", entry);
+
+ armrw(arm, 15, entry);
+}
+
+void
+usage(void)
+{
+ fprint(2, "%s [ -j jtagdev ] entry image\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ char *jtag = "/dev/jtagddd94.0";
+ char *image;
+ u32int entry;
+
+ fmtinstall('H', encodefmt);
+
+ ARGBEGIN {
+ case 'j':
+ jtag = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc != 2)
+ usage();
+ entry = strtoul(argv[0], nil, 0);
+ image = argv[1];
+
+ ioinit(jtag);
+ tapreset();
+
+ arm[0].dbgbase = 0x80090000;
+ arm[0].dbgap = apbap;
+ arm[0].memap = ahbap;
+ arm[0].id = "arm0";
+
+ arm[1].dbgbase = 0x80092000;
+ arm[1].dbgap = apbap;
+ arm[1].memap = ahbap;
+ arm[1].id = "arm1";
+
+ startstop(arm+0, 1);
+ startstop(arm+1, 1);
+
+ boot(image, entry);
+
+ startstop(arm+0, 0);
+ startstop(arm+1, 0);
+
+ exits(nil);
+}
--- a/sys/src/boot/zynq/mkfile
+++ b/sys/src/boot/zynq/mkfile
@@ -2,25 +2,29 @@
</$objtype/mkfile
BIN=/arm
TARG=fsbl fsbl.img
-CLEANFILES=boothead.$cputype
FSBLFILES=fsbl.$O ddr.$O main.$O mmc.$O net.$O div.$O qspi.$O
+TEXTBASE=0xfffc0000
all:V: $TARG
clean:V:
rm -rf $TARG *.$O
+ @{objtype=$cputype mk -f mkfile.port clean}
fsbl: $FSBLFILES
- $LD -o $target -T0xfffc0000 -H6 -R4096 -l -s $prereq
+ $LD -o $target -T$TEXTBASE -H6 -R4096 -l -s $prereq
9fsbl: $FSBLFILES
- $LD -o $target -T0xfffc0000 -l $prereq
+ $LD -o $target -T$TEXTBASE -l $prereq
fsbl.img:D: fsbl boothead.$cputype
boothead.$cputype fsbl >fsbl.img
-boothead.$cputype:V: mkfile.boothead
- @{objtype=$cputype mk -f $prereq all}
+%.$cputype:V: mkfile.port
+ @{objtype=$cputype mk -f $prereq $target}
+
+jtagload:V: fsbl jtagload.$cputype
+ ./jtagload.$cputype -j /dev/jtag*.0 $TEXTBASE fsbl
div.$O: /sys/src/libc/arm/div.s
$AS /sys/src/libc/arm/div.s
--- a/sys/src/boot/zynq/mkfile.boothead
+++ /dev/null
@@ -1,9 +1,0 @@
-</$objtype/mkfile
-
-all:V: boothead.$objtype
-
-boothead.$objtype: boothead.$O
- $LD $LDFLAGS -o $target $prereq
-
-%.$O: %.c
- $CC $CFLAGS $stem.c
--- /dev/null
+++ b/sys/src/boot/zynq/mkfile.port
@@ -1,0 +1,14 @@
+</$objtype/mkfile
+
+TARG=boothead.$objtype jtagload.$objtype
+
+all:V: $TARG
+
+clean:V:
+ rm -f $TARG *.$O
+
+%.$objtype: %.$O
+ $LD $LDFLAGS -o $target $prereq
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c