diff --git a/sys/src/boot/zynq/jtagload.c b/sys/src/boot/zynq/jtagload.c new file mode 100644 index 000000000..00792b9c3 --- /dev/null +++ b/sys/src/boot/zynq/jtagload.c @@ -0,0 +1,647 @@ +#include +#include + +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< 0){ + b[0] = w >> s; + c |= BITS; + io(c, len, b); + if((c & TDO) != 0){ + w &= ~((uvlong)((1<> 8-len) << s; + } + s += len; + } + return w & (1ULL<= 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; idbgap, 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); +} diff --git a/sys/src/boot/zynq/mkfile b/sys/src/boot/zynq/mkfile index 9b0e29b81..a3cac74fc 100644 --- a/sys/src/boot/zynq/mkfile +++ b/sys/src/boot/zynq/mkfile @@ -2,25 +2,29 @@ objtype=arm 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 diff --git a/sys/src/boot/zynq/mkfile.boothead b/sys/src/boot/zynq/mkfile.boothead deleted file mode 100644 index cadebcb78..000000000 --- a/sys/src/boot/zynq/mkfile.boothead +++ /dev/null @@ -1,9 +0,0 @@ -