diff options
author | aiju <aiju@phicode.de> | 2014-12-24 10:21:51 +0100 |
---|---|---|
committer | aiju <aiju@phicode.de> | 2014-12-24 10:21:51 +0100 |
commit | 7a3f0998a0ce7470d70c1a13bc4646abafdcc236 (patch) | |
tree | 9cea39d933719c0b82eb242ec286c25eed0d728c /sys/src | |
parent | 6dafa424805d128fcd08c71dca3e3abdc40aa6c6 (diff) |
added zynq kernel
Diffstat (limited to 'sys/src')
37 files changed, 6601 insertions, 0 deletions
diff --git a/sys/src/9/zynq/dat.h b/sys/src/9/zynq/dat.h new file mode 100644 index 000000000..9937b365b --- /dev/null +++ b/sys/src/9/zynq/dat.h @@ -0,0 +1,196 @@ +typedef struct Conf Conf; +typedef struct Confmem Confmem; +typedef struct FPsave FPsave; +typedef struct L1 L1; +typedef struct Label Label; +typedef struct Lock Lock; +typedef struct KMap KMap; +typedef struct MMMU MMMU; +typedef struct Mach Mach; +typedef struct Notsave Notsave; +typedef struct Page Page; +typedef struct Proc Proc; +typedef struct PMMU PMMU; +typedef u32int PTE; +typedef struct Ureg Ureg; +typedef struct ISAConf ISAConf; +typedef uvlong Tval; + +#pragma incomplete Ureg + +#define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */ + +#define AOUT_MAGIC (E_MAGIC) + +struct Lock +{ + ulong key; + u32int sr; + uintptr pc; + Proc* p; + Mach* m; + int isilock; +}; + +struct Label +{ + uintptr sp; + uintptr pc; +}; + +struct FPsave +{ + ulong exc, scr; + uchar regs[256]; +}; + +/* + * FPsave.status + */ +enum +{ + FPinit, + FPactive, + FPinactive, + FPillegal = 0x100 +}; + +struct Confmem +{ + uintptr base; + uintptr limit; + usize npage; + uintptr kbase; + uintptr klimit; +}; + +struct Conf +{ + ulong nmach; /* processors */ + ulong nproc; /* processes */ + Confmem mem[1]; /* physical memory */ + ulong npage; /* total physical pages of memory */ + usize upages; /* user page pool */ + ulong copymode; /* 0 is copy on write, 1 is copy on reference */ + ulong ialloc; /* max interrupt time allocation in bytes */ + ulong pipeqsize; /* size in bytes of pipe queues */ + ulong nimage; /* number of page cache image headers */ + ulong nswap; /* number of swap pages */ + int nswppo; /* max # of pageouts per segment pass */ + int monitor; +}; + +/* + * things saved in the Proc structure during a notify + */ +struct Notsave { + int emptiness; +}; + +/* + * MMU stuff in proc + */ +#define NCOLOR 1 + +struct PMMU +{ + L1 *l1; + Page *mmuused, *mmufree; + + int nkmap; + Page *kmaptable; +}; + +#include "../port/portdat.h" + +struct L1 +{ + Ref; + uintptr pa; + ulong *va; + L1 *next; +}; + +struct MMMU +{ + L1 l1; + L1 *l1free; + int nfree; + uchar asid; +}; + +struct Mach +{ + /* known to assembly */ + int machno; /* physical id of processor */ + uintptr splpc; /* pc of last caller to splhi */ + Proc* proc; /* current process */ + ulong excregs[3]; + ulong cycleshi; + /* end of known to assembly */ + + int flushmmu; /* flush current proc mmu state */ + + ulong ticks; /* of the clock since boot time */ + Label sched; /* scheduler wakeup */ + Lock alarmlock; /* access to alarm list */ + void* alarm; /* alarms bound to this clock */ + int inclockintr; + + Proc* readied; /* for runproc */ + ulong schedticks; /* next forced context switch */ + + int cputype; + ulong delayloop; + + /* stats */ + int tlbfault; + int tlbpurge; + int pfault; + int cs; + int syscall; + int load; + int intr; + uvlong fastclock; /* last sampled value */ + uvlong inidle; /* time spent in idlehands() */ +// ulong spuriousintr; + int lastintr; + int ilockdepth; + Perf perf; /* performance counters */ + + + int cpumhz; + uvlong cpuhz; /* speed of cpu */ + uvlong cyclefreq; /* Frequency of user readable cycle counter */ + + MMMU; + + int stack[1]; +}; + +struct ISAConf +{ + int dummy; + char *type; + ulong port; + int irq; +}; +#define BUSUNKNOWN -1 + +struct +{ + Lock; + int machs; /* bitmap of active CPUs */ + int exiting; /* shutdown */ + int ispanic; /* shutdown in response to a panic */ +}active; + +extern register Mach* m; /* R10 */ +extern register Proc* up; /* R9 */ + +extern int normalprint; + +extern ulong *mpcore, *slcr; + +void nope(void); +#define NOPE nope(); diff --git a/sys/src/9/zynq/devarch.c b/sys/src/9/zynq/devarch.c new file mode 100644 index 000000000..31b2aab34 --- /dev/null +++ b/sys/src/9/zynq/devarch.c @@ -0,0 +1,391 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" + +enum { + Qdir = 0, + Qtemp, + Qpl, + Qbase, + + Qmax = 16, +}; + +static Dirtab archdir[Qmax] = { + ".", { Qdir, 0, QTDIR }, 0, 0555, + "temp", { Qtemp, 0}, 0, 0440, + "pl", { Qpl, 0 }, 0, 0660, +}; +static int narchdir = Qbase; + +int temp = -128; +ulong *devc; +int dmadone; +QLock pllock; +enum { PLBUFSIZ = 8192 }; +uchar *plbuf; +Rendez plinitr, pldoner, pldmar; + +enum { + DEVCTRL = 0, + DEVISTS = 0xc/4, + DEVMASK, + DEVSTS, + DMASRC = 0x18/4, + DMADST, + DMASRCL, + DMADSTL, + XADCCFG = 0x100/4, + XADCSTS, + XADCMASK, + XADCMSTS, + XADCCMD, + XADCREAD, + XADCMCTL, + + FPGA0_CLK_CTRL = 0x170/4, +}; + +enum { + PROG = 1<<30, + DONE = 1<<2, + INITPE = 1<<1, + INIT = 1<<4, + DMADONE = 1<<13, +}; + +static void +scram(void) +{ + splhi(); + slcr[0x100/4] |= 1<<4; + slcr[0x104/4] |= 1<<4; + slcr[0x108/4] |= 1<<4; + slcr[DEVCTRL] &= ~PROG; + slcr[0x244/4] = 1<<4|1<<5; +} + +static void +xadcirq(Ureg *, void *) +{ + int v; + static int al, notfirst; + + while((devc[XADCMSTS] & 1<<8) == 0){ + v = ((u16int)devc[XADCREAD]) >> 4; + if(v == 0){ + if(notfirst) + print("temperature sensor reads 0, shouldn't happen\n"); + break; + } + notfirst = 1; + temp = v * 5040 / 4096 - 2732; + if(temp >= 800){ + if(al == 0) + print("temperature exceeds 80 deg C\n"); + al = 1; + } + if(temp <= 750) + al = 0; + if(temp >= 900){ + print("chip temperature exceeds 90 deg C, shutting down"); + scram(); + } + } + devc[XADCSTS] = -1; +} + +static void +xadctimer(void) +{ + devc[XADCCMD] = 1<<26 | 0<<16; +} + +static void +xadcinit(void) +{ + int i; + int x; + + devc = vmap(DEVC_BASE, 0x11C); + devc[XADCMCTL] |= 1<<4; + devc[XADCMCTL] &= ~(1<<4); + devc[XADCCMD] = 0x08030000; + for(i = 0; i < 15; i++) + devc[XADCCMD] = 0; + while((devc[XADCMSTS] & 1<<10) == 0) + ; + while((devc[XADCMSTS] & 1<<8) == 0){ + x = devc[XADCREAD]; + USED(x); + } + devc[XADCCFG] = 0x80001114; + devc[XADCMASK] = ~(1<<8); + devc[XADCSTS] = -1; + intrenable(XADCIRQ, xadcirq, nil, LEVEL, "xadc"); + addclock0link(xadctimer, XADCINTERVAL); +} + +static int +isplinit(void *) +{ + return devc[DEVSTS] & INIT; +} + +static int +ispldone(void *) +{ + return devc[DEVISTS] & DONE; +} + +static int +isdmadone(void *) +{ + return dmadone; +} + +static void +plirq(Ureg *, void *) +{ + ulong fl; + + fl = devc[DEVISTS]; + if((fl & INITPE) != 0) + wakeup(&plinitr); + if((fl & DONE) != 0){ + slcr[0x900/4] = 0xf; + slcr[0x240/4] = 0; + print("DONE!\n"); + devc[DEVMASK] |= DONE; + wakeup(&pldoner); + } + if((fl & DMADONE) != 0){ + dmadone++; + wakeup(&pldmar); + } + devc[DEVISTS] = fl; +} + +static void +plinit(void) +{ + Physseg seg; + + devc[DEVCTRL] &= ~(PROG|1<<25); + devc[DEVCTRL] |= 3<<26|PROG; + devc[DEVISTS] = -1; + devc[DEVMASK] = ~(DONE|INITPE|DMADONE); + intrenable(DEVCIRQ, plirq, nil, LEVEL, "pl"); + + slcr[FPGA0_CLK_CTRL] = 1<<20 | 10<<8; + + memset(&seg, 0, sizeof seg); + seg.attr = SG_PHYSICAL; + seg.name = "axi"; + seg.pa = 0x40000000; + seg.size = 0x8000000; + addphysseg(&seg); +} + +static void +plconf(void) +{ + if(!canqlock(&pllock)) + error(Einuse); + slcr[0x240/4] = 0xf; + slcr[0x900/4] = 0xa; + dmadone = 1; + devc[DEVISTS] = DONE|INITPE|DMADONE; + devc[DEVCTRL] |= PROG; + devc[DEVCTRL] &= ~PROG; + devc[DEVMASK] &= ~DONE; + devc[DEVCTRL] |= PROG; + sleep(&plinitr, isplinit, nil); + plbuf = smalloc(PLBUFSIZ); +} + +static long +plwrite(uintptr pa, long n) +{ + long w; + + w = n >> 2; + sleep(&pldmar, isdmadone, nil); + dmadone = 0; + coherence(); + devc[DMASRC] = pa; + devc[DMADST] = -1; + devc[DMASRCL] = w; + devc[DMADSTL] = 0; + return n; +} + +static long +plcopy(uchar *d, long n) +{ + long ret; + ulong nn; + uintptr pa; + + if((n & 3) != 0 || n <= 0) + error(Eshort); + ret = n; + pa = PADDR(plbuf); + while(n > 0){ + if(n > PLBUFSIZ) + nn = PLBUFSIZ; + else + nn = n; + memmove(plbuf, d, nn); + cleandse(plbuf, plbuf + nn); + clean2pa(pa, pa + nn); + n -= plwrite(pa, nn); + } + return ret; +} + +static long +userdma(void *a, long n, long (*f)(uintptr, long)) +{ + ulong s; + void *va; + uintptr pa; + long off, nn, ret; + + evenaddr((uintptr) a); + if((n & 3) != 0) + error(Eshort); + + ret = n; + while(n > 0){ + off = (uintptr)a & BY2PG - 1; + va = (void *) ((uintptr)a & ~(BY2PG - 1)); + s = splhi(); + while(pa = palookur(va), (pa & 1) != 0){ + splx(s); + if(fault(pa, 1) < 0) + error(Egreg); + s = splhi(); + } + if(off + n >= BY2PG) + nn = BY2PG - off; + else + nn = n; + pa = (pa & ~(BY2PG - 1)) + off; + cleandse((char *) a + off, (char*) a + off + nn); + clean2pa(pa, pa + nn); + n -= f(pa, nn); + splx(s); + a = (char *) va + BY2PG; + } + return ret; +} + +void +archinit(void) +{ + slcr[2] = 0xDF0D; + xadcinit(); + plinit(); +} + +static long +archread(Chan *c, void *a, long n, vlong offset) +{ + char buf[64]; + + switch((ulong)c->qid.path){ + case Qdir: + return devdirread(c, a, n, archdir, narchdir, devgen); + case Qtemp: + snprint(buf, sizeof(buf), "%d.%d\n", temp/10, temp%10); + return readstr(offset, a, n, buf); + case Qpl: + sleep(&pldoner, ispldone, nil); + return 0; + default: + error(Egreg); + return -1; + } +} + +static long +archwrite(Chan *c, void *a, long n, vlong offset) +{ + switch((ulong)c->qid.path){ + case Qpl: + return plcopy(a, n); + default: + error(Egreg); + return -1; + } +} + +Walkqid* +archwalk(Chan* c, Chan *nc, char** name, int nname) +{ + return devwalk(c, nc, name, nname, archdir, narchdir, devgen); +} + +static int +archstat(Chan* c, uchar* dp, int n) +{ + return devstat(c, dp, n, archdir, narchdir, devgen); +} + +static Chan* +archopen(Chan* c, int omode) +{ + devopen(c, omode, archdir, narchdir, devgen); + if((ulong)c->qid.path == Qpl && c->mode == OWRITE) + plconf(); + return c; +} + +static void +archclose(Chan* c) +{ + if((ulong)c->qid.path == Qpl && c->mode == OWRITE){ + /* cleandse(plbuf, plbuf + plbufn); + clean2pa(PADDR(plbuf), PADDR(plbuf) + plbufn); + plwrite(PADDR(plbuf), 4096); + plwrite(PADDR(plbuf) + 4096, plbufn - 4096); + plbufn = 0;*/ + free(plbuf); + plbuf = nil; + qunlock(&pllock); + } +} + +static Chan* +archattach(char* spec) +{ + return devattach('P', spec); +} + +Dev archdevtab = { + 'P', + "arch", + + devreset, + devinit, + devshutdown, + archattach, + archwalk, + archstat, + archopen, + devcreate, + archclose, + archread, + devbread, + archwrite, + devbwrite, + devremove, + devwstat, +}; + diff --git a/sys/src/9/zynq/devether.c b/sys/src/9/zynq/devether.c new file mode 100644 index 000000000..c6ed2eac3 --- /dev/null +++ b/sys/src/9/zynq/devether.c @@ -0,0 +1,517 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "pool.h" +#include "ureg.h" +#include "../port/error.h" +#include "../port/netif.h" + +#include "etherif.h" + +static Ether *etherxx[MaxEther]; + +Chan* +etherattach(char* spec) +{ + ulong ctlrno; + char *p; + Chan *chan; + + ctlrno = 0; + if(spec && *spec){ + ctlrno = strtoul(spec, &p, 0); + if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) + error(Ebadarg); + } + if(etherxx[ctlrno] == 0) + error(Enodev); + + chan = devattach('l', spec); + if(waserror()){ + chanfree(chan); + nexterror(); + } + chan->dev = ctlrno; + if(etherxx[ctlrno]->attach) + etherxx[ctlrno]->attach(etherxx[ctlrno]); + poperror(); + return chan; +} + +static Walkqid* +etherwalk(Chan* chan, Chan* nchan, char** name, int nname) +{ + return netifwalk(etherxx[chan->dev], chan, nchan, name, nname); +} + +static int +etherstat(Chan* chan, uchar* dp, int n) +{ + return netifstat(etherxx[chan->dev], chan, dp, n); +} + +static Chan* +etheropen(Chan* chan, int omode) +{ + return netifopen(etherxx[chan->dev], chan, omode); +} + +static Chan* +ethercreate(Chan*, char*, int, ulong) +{ + error(Eperm); + return 0; +} + +static void +etherclose(Chan* chan) +{ + netifclose(etherxx[chan->dev], chan); +} + +static long +etherread(Chan* chan, void* buf, long n, vlong off) +{ + Ether *ether; + ulong offset = off; + + ether = etherxx[chan->dev]; + if((chan->qid.type & QTDIR) == 0 && ether->ifstat){ + /* + * With some controllers it is necessary to reach + * into the chip to extract statistics. + */ + if(NETTYPE(chan->qid.path) == Nifstatqid) + return ether->ifstat(ether, buf, n, offset); + else if(NETTYPE(chan->qid.path) == Nstatqid) + ether->ifstat(ether, buf, 0, offset); + } + + return netifread(ether, chan, buf, n, offset); +} + +static Block* +etherbread(Chan* chan, long n, ulong offset) +{ + return netifbread(etherxx[chan->dev], chan, n, offset); +} + +static int +etherwstat(Chan* chan, uchar* dp, int n) +{ + return netifwstat(etherxx[chan->dev], chan, dp, n); +} + +static void +etherrtrace(Netfile* f, Etherpkt* pkt, int len) +{ + int i, n; + Block *bp; + + if(qwindow(f->in) <= 0) + return; + if(len > 58) + n = 58; + else + n = len; + bp = iallocb(64); + if(bp == nil) + return; + memmove(bp->wp, pkt->d, n); + i = TK2MS(MACHP(0)->ticks); + bp->wp[58] = len>>8; + bp->wp[59] = len; + bp->wp[60] = i>>24; + bp->wp[61] = i>>16; + bp->wp[62] = i>>8; + bp->wp[63] = i; + bp->wp += 64; + qpass(f->in, bp); +} + +Block* +etheriq(Ether* ether, Block* bp, int fromwire) +{ + Etherpkt *pkt; + ushort type; + int len, multi, tome, fromme; + Netfile **ep, *f, **fp, *fx; + Block *xbp; + + ether->inpackets++; + + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); + type = (pkt->type[0]<<8)|pkt->type[1]; + fx = 0; + ep = ðer->f[Ntypes]; + + multi = pkt->d[0] & 1; + /* check for valid multicast addresses */ + if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){ + if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ + if(fromwire){ + freeb(bp); + bp = 0; + } + return bp; + } + } + + /* is it for me? */ + tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; + fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0; + + /* + * Multiplex the packet to all the connections which want it. + * If the packet is not to be used subsequently (fromwire != 0), + * attempt to simply pass it into one of the connections, thereby + * saving a copy of the data (usual case hopefully). + */ + for(fp = ether->f; fp < ep; fp++){ + if(f = *fp) + if(f->type == type || f->type < 0) + if(tome || multi || f->prom){ + /* Don't want to hear bridged packets */ + if(f->bridge && !fromwire && !fromme) + continue; + if(!f->headersonly){ + if(fromwire && fx == 0) + fx = f; + else if(xbp = iallocb(len)){ + memmove(xbp->wp, pkt, len); + xbp->wp += len; + if(qpass(f->in, xbp) < 0) { + // print("soverflow for f->in\n"); + ether->soverflows++; + } + } + else { + // print("soverflow iallocb\n"); + ether->soverflows++; + } + } + else + etherrtrace(f, pkt, len); + } + } + + if(fx){ + if(qpass(fx->in, bp) < 0) { + // print("soverflow for fx->in\n"); + ether->soverflows++; + } + return 0; + } + if(fromwire){ + freeb(bp); + return 0; + } + + return bp; +} + +static int +etheroq(Ether* ether, Block* bp) +{ + int len, loopback; + Etherpkt *pkt; + + ether->outpackets++; + + /* + * Check if the packet has to be placed back onto the input queue, + * i.e. if it's a loopback or broadcast packet or the interface is + * in promiscuous mode. + * If it's a loopback packet indicate to etheriq that the data isn't + * needed and return, etheriq will pass-on or free the block. + * To enable bridging to work, only packets that were originated + * by this interface are fed back. + */ + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); + loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; + if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom) + if(etheriq(ether, bp, loopback) == 0) + return len; + + qbwrite(ether->oq, bp); + if(ether->transmit != nil) + ether->transmit(ether); + return len; +} + +static long +etherwrite(Chan* chan, void* buf, long n, vlong) +{ + Ether *ether; + Block *bp; + int nn, onoff; + Cmdbuf *cb; + + ether = etherxx[chan->dev]; + if(NETTYPE(chan->qid.path) != Ndataqid) { + nn = netifwrite(ether, chan, buf, n); + if(nn >= 0) + return nn; + cb = parsecmd(buf, n); + if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){ + if(cb->nf <= 1) + onoff = 1; + else + onoff = atoi(cb->f[1]); + qnoblock(ether->oq, onoff); + free(cb); + return n; + } + free(cb); + if(ether->ctl!=nil) + return ether->ctl(ether,buf,n); + + error(Ebadctl); + } + + if(n > ether->maxmtu) + error(Etoobig); + if(n < ether->minmtu) + error(Etoosmall); + + bp = allocb(n); + if(waserror()){ + freeb(bp); + nexterror(); + } + memmove(bp->rp, buf, n); + memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen); + poperror(); + bp->wp += n; + + return etheroq(ether, bp); +} + +static long +etherbwrite(Chan* chan, Block* bp, ulong) +{ + Ether *ether; + long n; + + n = BLEN(bp); + if(NETTYPE(chan->qid.path) != Ndataqid){ + if(waserror()) { + freeb(bp); + nexterror(); + } + n = etherwrite(chan, bp->rp, n, 0); + poperror(); + freeb(bp); + return n; + } + ether = etherxx[chan->dev]; + + if(n > ether->maxmtu){ + freeb(bp); + error(Etoobig); + } + if(n < ether->minmtu){ + freeb(bp); + error(Etoosmall); + } + + return etheroq(ether, bp); +} + +static struct { + char* type; + int (*reset)(Ether*); +} cards[MaxEther+1]; + +void +addethercard(char* t, int (*r)(Ether*)) +{ + static int ncard; + + if(ncard == MaxEther) + panic("too many ether cards"); + cards[ncard].type = t; + cards[ncard].reset = r; + ncard++; +} + +int +parseether(uchar *to, char *from) +{ + char nip[4]; + char *p; + int i; + + p = from; + for(i = 0; i < Eaddrlen; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + +static Ether* +etherprobe(int cardno, int ctlrno) +{ + int i, lg; + ulong mb, bsz; + Ether *ether; + char buf[128], name[32]; + + ether = malloc(sizeof(Ether)); + if(ether == nil){ + print("etherprobe: no memory for Ether\n"); + return nil; + } + memset(ether, 0, sizeof(Ether)); + ether->ctlrno = ctlrno; + ether->mbps = 10; + ether->minmtu = ETHERMINTU; + ether->maxmtu = ETHERMAXTU; + + if(cardno >= MaxEther || cards[cardno].type == nil){ + free(ether); + return nil; + } + if(cards[cardno].reset(ether) < 0){ + free(ether); + return nil; + } + + snprint(name, sizeof(name), "ether%d", ctlrno); + + intrenable(ether->irq, ether->interrupt, ether, ether->irqlevel, name); + + i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d", + ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq); + i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux", + ether->ea[0], ether->ea[1], ether->ea[2], + ether->ea[3], ether->ea[4], ether->ea[5]); + sprint(buf+i, "\n"); + print(buf); + + /* compute log10(ether->mbps) into lg */ + for(lg = 0, mb = ether->mbps; mb >= 10; lg++) + mb /= 10; + if (lg > 0) + lg--; + if (lg > 14) /* 2^(14+17) = 2³¹ */ + lg = 14; + /* allocate larger output queues for higher-speed interfaces */ + bsz = 1UL << (lg + 17); /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */ + while (bsz > mainmem->maxsize / 8 && bsz > 128*1024) + bsz /= 2; + + netifinit(ether, name, Ntypes, bsz); + if(ether->oq == nil) { + ether->oq = qopen(bsz, Qmsg, 0, 0); + ether->limit = bsz; + } + if(ether->oq == nil) + panic("etherreset %s: can't allocate output queue of %ld bytes", name, bsz); + ether->alen = Eaddrlen; + memmove(ether->addr, ether->ea, Eaddrlen); + memset(ether->bcast, 0xFF, Eaddrlen); + + return ether; +} + +static void +etherreset(void) +{ + Ether *ether; + int cardno, ctlrno; + + for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + if((ether = etherprobe(-1, ctlrno)) == nil) + continue; + etherxx[ctlrno] = ether; + } + + cardno = ctlrno = 0; + while(cards[cardno].type != nil && ctlrno < MaxEther){ + if(etherxx[ctlrno] != nil){ + ctlrno++; + continue; + } + if((ether = etherprobe(cardno, ctlrno)) == nil){ + cardno++; + continue; + } + etherxx[ctlrno] = ether; + ctlrno++; + } +} + +static void +ethershutdown(void) +{ + Ether *ether; + int i; + + for(i = 0; i < MaxEther; i++){ + ether = etherxx[i]; + if(ether == nil) + continue; + if(ether->shutdown == nil) { + print("#l%d: no shutdown function\n", i); + continue; + } + (*ether->shutdown)(ether); + } +} + + +#define POLY 0xedb88320 + +/* really slow 32 bit crc for ethers */ +ulong +ethercrc(uchar *p, int len) +{ + int i, j; + ulong crc, b; + + crc = 0xffffffff; + for(i = 0; i < len; i++){ + b = *p++; + for(j = 0; j < 8; j++){ + crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0); + b >>= 1; + } + } + return crc; +} + +Dev etherdevtab = { + 'l', + "ether", + + etherreset, + devinit, + ethershutdown, + etherattach, + etherwalk, + etherstat, + etheropen, + ethercreate, + etherclose, + etherread, + etherbread, + etherwrite, + etherbwrite, + devremove, + etherwstat, +}; diff --git a/sys/src/9/zynq/devqspi.c b/sys/src/9/zynq/devqspi.c new file mode 100644 index 000000000..8c920d0f7 --- /dev/null +++ b/sys/src/9/zynq/devqspi.c @@ -0,0 +1,275 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" + +enum { + QSPIDIV = 1, + QSPISIZ = 1<<24, +}; + +enum { + CONF, + INTSTAT, + INTEN, + INTDIS, + INTMASK, + SPIEN, + DELAY, + TXD0, + RXD, + IDLE, + TXTHRES, + RXTHRES, + TXD1 = 0x80/4, + TXD2, + TXD3, + LQSPICFG = 0xA0/4, +}; + +enum { + TXFULL = 1<<3, + TXNFULL = 1<<2, + RXNEMPTY = 1<<4, + STARTCOM = 1<<16, +}; + +enum { + Qdir = 0, + Qboot, + Qbase, + + Qmax = 16, +}; + +static ulong *qspi; +static QLock qspil; + +static Dirtab qspidir[Qmax] = { + ".", { Qdir, 0, QTDIR }, 0, 0555, + "boot", { Qboot, 0}, 65536, 0640, +}; +static int nqspidir = Qbase; + +static ulong +qspicmd(int n, ulong d) +{ + while((qspi[INTSTAT] & TXNFULL) == 0) + ; + if(n == 4) + qspi[TXD0] = d; + else + qspi[TXD1 - 1 + n] = d; + qspi[CONF] |= STARTCOM; + while((qspi[INTSTAT] & (TXNFULL|RXNEMPTY)) != (TXNFULL|RXNEMPTY)) + ; + return qspi[RXD]; +} + +static void +qspiinit(void) +{ + static int done; + + if(done) + return; + qspi = vmap(QSPI_BASE, 0x100); + qspi[LQSPICFG] &= ~(1<<31); + qspi[CONF] = 1<<31 | 1<<19 | 1<<15 | 1<<14 | 1<<10 | 3<<6 | QSPIDIV<<3 | 1; + qspi[SPIEN] = 1; +} + +static void +qspisel(int sel) +{ + if(sel) + qspi[CONF] &= ~(1<<10); + else + qspi[CONF] |= 1<<10; +} + +static void +waitbusy(void) +{ + ulong d; + + for(;;){ + qspisel(1); + d = qspicmd(2, 0x05); + qspisel(0); + if((d & 1<<24) == 0) + break; + tsleep(&up->sleep, return0, nil, 1); + } +} + +static ulong +doread(uvlong addr, void *a, ulong n) +{ + ulong d, *aa, nn, ret; + + if(addr >= QSPISIZ) + return 0; + if(addr + n > QSPISIZ) + n = QSPISIZ - addr; + evenaddr((uintptr) a); + qspisel(1); + qspicmd(4, 0x6B | addr << 8); + qspicmd(1, 0); + ret = n; + aa = a; + while(n > 0){ + d = qspicmd(4, 0); + if(n >= 4){ + *aa++ = d; + n -= 4; + }else{ + memmove(aa, (char*) &d + 4 - n, n); + break; + } + } + qspisel(0); + return ret; +} + +static ulong +dowrite(uvlong addr, void *a, ulong n) +{ + ulong *aa, ret, nn; + + if(addr >= QSPISIZ) + return 0; + if(addr + n > QSPISIZ) + n = QSPISIZ - addr; + evenaddr((uintptr) a); + ret = n; + aa = a; + while(n > 0){ + qspisel(1); + qspicmd(1, 6); + qspisel(0); + qspisel(1); + qspicmd(4, 0x32 | addr << 8); + if(n > 256) + nn = 256; + else + nn = n; + n -= nn; + addr += nn; + while(nn > 0) + if(nn >= 4){ + qspicmd(4, *aa++); + nn -= 4; + }else{ + qspicmd(n, *aa); + break; + } + qspisel(0); + waitbusy(); + } + return ret; +} + +static void +doerase(ulong addr) +{ + qspisel(1); + qspicmd(1, 6); + qspisel(0); + qspisel(1); + qspicmd(4, 0xD8 | addr << 8); + qspisel(0); + waitbusy(); +} + +static Walkqid* +qspiwalk(Chan* c, Chan *nc, char** name, int nname) +{ + return devwalk(c, nc, name, nname, qspidir, nqspidir, devgen); +} + +static int +qspistat(Chan* c, uchar* dp, int n) +{ + return devstat(c, dp, n, qspidir, nqspidir, devgen); +} + +static Chan* +qspiopen(Chan* c, int omode) +{ + devopen(c, omode, qspidir, nqspidir, devgen); + if(c->qid.path == Qboot){ + qlock(&qspil); + if((omode & OTRUNC) != 0) + doerase(0); + } + return c; +} + +static void +qspiclose(Chan* c) +{ + if(c->qid.path == Qboot) + qunlock(&qspil); +} + +static long +qspiread(Chan *c, void *a, long n, vlong offset) +{ + char buf[64]; + + switch((ulong)c->qid.path){ + case Qdir: + return devdirread(c, a, n, qspidir, nqspidir, devgen); + case Qboot: + return doread(offset, a, n); + default: + error(Egreg); + return -1; + } +} + +static long +qspiwrite(Chan *c, void *a, long n, vlong offset) +{ + switch((ulong)c->qid.path){ + case Qboot: + return dowrite(offset, a, n); + default: + error(Egreg); + return -1; + } +} + +static Chan* +qspiattach(char* spec) +{ + qspiinit(); + return devattach('Q', spec); +} + +Dev qspidevtab = { + 'Q', + "qspi", + + devreset, + devinit, + devshutdown, + qspiattach, + qspiwalk, + qspistat, + qspiopen, + devcreate, + qspiclose, + qspiread, + devbread, + qspiwrite, + devbwrite, + devremove, + devwstat, +}; + diff --git a/sys/src/9/zynq/etherif.h b/sys/src/9/zynq/etherif.h new file mode 100644 index 000000000..d7ea87523 --- /dev/null +++ b/sys/src/9/zynq/etherif.h @@ -0,0 +1,40 @@ +enum { + MaxEther = 64, + Ntypes = 8, +}; + +typedef struct Ether Ether; +struct Ether { + + int ctlrno; + int minmtu; + int maxmtu; + uchar ea[Eaddrlen]; + + int irq, irqlevel; + uintptr port; + + void (*attach)(Ether*); /* filled in by reset routine */ + void (*detach)(Ether*); + void (*transmit)(Ether*); + void (*interrupt)(Ureg*, void*); + long (*ifstat)(Ether*, void*, long, ulong); + long (*ctl)(Ether*, void*, long); /* custom ctl messages */ + void (*power)(Ether*, int); /* power on/off */ + void (*shutdown)(Ether*); /* shutdown hardware before reboot */ + void *ctlr; + + Queue* oq; + + Netif; +}; + +extern Block* etheriq(Ether*, Block*, int); +extern void addethercard(char*, int(*)(Ether*)); +extern ulong ethercrc(uchar*, int); +extern int parseether(uchar*, char*); + +#define NEXT(x, l) (((x)+1)%(l)) +#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) diff --git a/sys/src/9/zynq/etherzynq.c b/sys/src/9/zynq/etherzynq.c new file mode 100644 index 000000000..775d219f4 --- /dev/null +++ b/sys/src/9/zynq/etherzynq.c @@ -0,0 +1,380 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/netif.h" +#include "etherif.h" + +#define Rbsz ROUNDUP(sizeof(Etherpkt)+16, 64) + +enum { + RXRING = 0x200, + TXRING = 0x200, + Linkdelay = 500, + MDC_DIV = 6, +}; + +enum { + NET_CTRL, + NET_CFG, + NET_STATUS, + DMA_CFG = 4, + TX_STATUS, + RX_QBAR, + TX_QBAR, + RX_STATUS, + INTR_STATUS, + INTR_EN, + INTR_DIS, + INTR_MASK, + PHY_MAINT, + RX_PAUSEQ, + TX_PAUSEQ, + HASH_BOT = 32, + HASH_TOP, + SPEC_ADDR1_BOT, + SPEC_ADDR1_TOP, +}; + +enum { + MDCTRL, + MDSTATUS, + MDID1, + MDID2, + MDAUTOADV, + MDAUTOPART, + MDAUTOEX, + MDAUTONEXT, + MDAUTOLINK, + MDGCTRL, + MDGSTATUS, + MDPHYCTRL = 0x1f, +}; + +enum { + /* NET_CTRL */ + RXEN = 1<<2, + TXEN = 1<<3, + MDEN = 1<<4, + STARTTX = 1<<9, + /* NET_CFG */ + SPEED = 1<<0, + FDEN = 1<<1, + RX1536EN = 1<<8, + GIGE_EN = 1<<10, + RXCHKSUMEN = 1<<24, + /* NET_STATUS */ + PHY_IDLE = 1<<2, + /* DMA_CFG */ + TXCHKSUMEN = 1<<11, + /* TX_STATUS */ + TXCOMPL = 1<<5, + /* INTR_{EN,DIS} */ + MGMTDONE = 1<<0, + RXCOMPL = 1<<1, + RXUSED = 1<<2, + TXUNDER = 1<<4, + RXOVER = 1<<10, + /* MDCTRL */ + MDRESET = 1<<15, + AUTONEG = 1<<12, + FULLDUP = 1<<8, + /* MDSTATUS */ + LINK = 1<<2, + /* MDGSTATUS */ + RECVOK = 3<<12, +}; + +enum { + RxUsed = 1, + TxUsed = 1<<31, + FrameEnd = 1<<15, +}; + +typedef struct Ctlr Ctlr; + +struct Ctlr { + ulong *r; + Rendez phy; + int phyaddr; + int rxconsi, rxprodi, txi; + ulong *rxr, *txr; + Block **rxs, **txs; + Lock txlock; + int attach; +}; + +static int +phyidle(void *v) +{ + return ((Ctlr*)v)->r[NET_STATUS] & PHY_IDLE; +} + +static void +mdwrite(Ctlr *c, int r, u16int v) +{ + sleep(&c->phy, phyidle, c); + c->r[PHY_MAINT] = 1<<30 | 1<<28 | 1<<17 | c->phyaddr << 23 | r << 18 | v; + sleep(&c->phy, phyidle, c); +} + +static u16int +mdread(Ctlr *c, int r) +{ + sleep(&c->phy, phyidle, c); + c->r[PHY_MAINT] = 1<<30 | 1<< 29 | 1<<17 | c->phyaddr << 23 | r << 18; + sleep(&c->phy, phyidle, c); + return c->r[PHY_MAINT]; +} + +static void +ethproc(void *ved) +{ + Ether *edev; + Ctlr *c; + char *sp, *dpl; + u16int v; + + edev = ved; + c = edev->ctlr; + mdwrite(c, MDCTRL, AUTONEG); + for(;;){ + if((mdread(c, MDSTATUS) & LINK) == 0){ + edev->link = 0; + print("eth: no link\n"); + while((mdread(c, MDSTATUS) & LINK) == 0) + tsleep(&up->sleep, return0, nil, Linkdelay); + } + v = mdread(c, MDPHYCTRL); + if((v & 0x40) != 0){ + sp = "1000BASE-T"; + while((mdread(c, MDGSTATUS) & RECVOK) != RECVOK) + ; + edev->mbps = 1000; + c->r[NET_CFG] |= GIGE_EN; + }else if((v & 0x20) != 0){ + sp = "100BASE-TX"; + edev->mbps = 100; + c->r[NET_CFG] = NET_CFG & ~GIGE_EN | SPEED; + }else if((v & 0x10) != 0){ + sp = "10BASE-T"; + edev->mbps = 10; + c->r[NET_CFG] = NET_CFG & ~(GIGE_EN | SPEED); + }else + sp = "???"; + if((v & 0x08) != 0){ + dpl = "full"; + c->r[NET_CFG] |= FDEN; + }else{ + dpl = "half"; + c->r[NET_CFG] &= ~FDEN; + } + edev->link = 1; + print("eth: %s %s duplex link\n", sp, dpl); + while((mdread(c, MDSTATUS) & LINK) != 0) + tsleep(&up->sleep, return0, nil, Linkdelay); + } +} + +static int +replenish(Ctlr *c) +{ + Block *bp; + int i; + ulong *r; + + while(c->rxprodi != c->rxconsi){ + i = c->rxprodi; + bp = iallocb(Rbsz); + if(bp == nil){ + print("eth: out of memory for receive buffers\n"); + return -1; + } + c->rxs[i] = bp; + r = &c->rxr[2 * i]; + r[0] = RxUsed | PADDR(bp->rp); + if(i == RXRING - 1) + r[0] |= 2; + r[1] = 0; + cleandse(bp->base, bp->lim); + clean2pa(PADDR(bp->base), PADDR(bp->lim)); + r[0] &= ~RxUsed; + c->rxprodi = (c->rxprodi + 1) & (RXRING - 1); + } + return 0; +} + +static void +ethrx(Ether *edev) +{ + Ctlr *c; + ulong *r; + Block *bp; + + c = edev->ctlr; +// print("rx! %p %p\n", PADDR(&c->rxr[2 * c->rxconsi]), c->r[RX_QBAR]); + for(;;){ + r = &c->rxr[2 * c->rxconsi]; + if((r[0] & RxUsed) == 0) + break; + if((r[1] & FrameEnd) == 0) + print("eth: partial frame received -- shouldn't happen\n"); + bp = c->rxs[c->rxconsi]; + bp->wp = bp->rp + (r[1] & 0x1fff); + invaldse(bp->rp, bp->wp); + inval2pa(PADDR(bp->rp), PADDR(bp->wp)); + etheriq(edev, bp, 1); + c->rxconsi = (c->rxconsi + 1) & (RXRING - 1); + replenish(c); + } +} + +static void +ethtx(Ether *edev) +{ + Ctlr *c; + ulong *r; + Block *bp; + + c = edev->ctlr; + ilock(&c->txlock); + for(;;){ + r = &c->txr[2 * c->txi]; + if((r[1] & TxUsed) == 0){ + print("eth: transmit buffer full\n"); + break; + } + bp = qget(edev->oq); + if(bp == nil) + break; + if(c->txs[c->txi] != nil) + freeb(c->txs[c->txi]); + c->txs[c->txi] = bp; + cleandse(bp->rp, bp->wp); + clean2pa(PADDR(bp->rp), PADDR(bp->wp)); + r[0] = PADDR(bp->rp); + r[1] = BLEN(bp) | FrameEnd | TxUsed; + if(r == c->txr + 2 * (TXRING - 1)) + r[1] |= 1<<30; + coherence(); + r[1] &= ~TxUsed; + coherence(); + c->r[NET_CTRL] |= STARTTX; + c->txi = (c->txi + 1) & (TXRING - 1); + } + iunlock(&c->txlock); +} + +static void +ethirq(Ureg *, void *arg) +{ + Ether *edev; + Ctlr *c; + ulong fl; + + edev = arg; + c = edev->ctlr; + fl = c->r[INTR_STATUS]; + c->r[INTR_STATUS] = fl; + if((fl & MGMTDONE) != 0) + wakeup(&c->phy); + if((fl & TXUNDER) != 0) + ethtx(edev); + if((fl & RXCOMPL) != 0) + ethrx(edev); + if((fl & RXUSED) != 0) + print("eth: DMA read RX descriptor with used bit set, shouldn't happen\n"); + if((fl & RXOVER) != 0) + print("eth: RX overrun, shouldn't happen\n"); +} + +static int +ethinit(Ether *edev) +{ + Ctlr *c; + int i; + uintptr rxrpa, txrpa; + + c = edev->ctlr; + c->r[NET_CTRL] = 0; + c->r[RX_STATUS] = 0xf; + c->r[TX_STATUS] = 0xff; + c->r[INTR_DIS] = 0x7FFFEFF; + c->r[NET_CFG] = MDC_DIV << 18 | FDEN | SPEED | RX1536EN | GIGE_EN | RXCHKSUMEN; + c->r[SPEC_ADDR1_BOT] = edev->ea[0] | edev->ea[1] << 8 | edev->ea[2] << 16 | edev->ea[3] << 24; + c->r[SPEC_ADDR1_TOP] = edev->ea[4] | edev->ea[5] << 8; + c->r[DMA_CFG] = TXCHKSUMEN | (Rbsz/64) << 16 | 1 << 10 | 3 << 8 | 0x10; + + rxrpa = ualloc(8 * RXRING, &c->rxr); + txrpa = ualloc(8 * TXRING, &c->txr); + c->rxs = xspanalloc(4 * RXRING, 4, 0); + c->txs = xspanalloc(4 * TXRING, 4, 0); + for(i = 0; i < 2 * RXRING; ){ + c->rxr[i++] = 1; + c->rxr[i++] = 0; + } + c->rxconsi = 1; + replenish(c); + c->rxconsi = 0; + replenish(c); + for(i = 0; i < 2 * TXRING; ){ + c->txr[i++] = 0; + c->txr[i++] = 1<<31; + } + c->txr[2 * (TXRING - 1)] |= 1<<30; + c->r[RX_QBAR] = rxrpa; + c->r[TX_QBAR] = txrpa; + + c->r[NET_CTRL] = MDEN | TXEN | RXEN; + c->r[INTR_EN] = MGMTDONE | TXUNDER | RXCOMPL | RXUSED | RXOVER; + return 0; +} + +static void +ethattach(Ether *edev) +{ + Ctlr *c; + + c = edev->ctlr; + if(c->attach) + return; + c->attach = 1; + kproc("ethproc", ethproc, edev); +} + +static int +etherpnp(Ether *edev) +{ + static Ctlr ct; + static uchar mac[] = {0x0e, 0xa7, 0xde, 0xad, 0xbe, 0xef}; + + if(ct.r != nil) + return -1; + + memmove(edev->ea, mac, 6); + edev->ctlr = &ct; + edev->port = ETH0_BASE; + ct.r = vmap(edev->port, BY2PG); + edev->irq = ETH0IRQ; + edev->irqlevel = LEVEL; + edev->ctlr = &ct; + edev->interrupt = ethirq; + edev->transmit = ethtx; + edev->attach = ethattach; + edev->arg = edev; + edev->mbps = 1000; + + if(ethinit(edev) < 0){ + edev->ctlr = nil; + return -1; + } + return 0; +} + +void +etherzynqlink(void) +{ + addethercard("eth", etherpnp); +} diff --git a/sys/src/9/zynq/fns.h b/sys/src/9/zynq/fns.h new file mode 100644 index 000000000..8c2950a1e --- /dev/null +++ b/sys/src/9/zynq/fns.h @@ -0,0 +1,75 @@ +#include "../port/portfns.h" + +int tas(void *); +int cmpswap(long *, long, long); +void evenaddr(uintptr); +void* kaddr(uintptr); +uintptr paddr(void *); +uintptr cankaddr(uintptr); +void procsave(Proc *); +void procrestore(Proc *); +void idlehands(void); +void coherence(void); +void procfork(Proc *); +void procsetup(Proc *); +KMap* kmap(Page *); +void kunmap(KMap *); + +#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) +#define getpgcolor(a) 0 +#define kmapinval() +#define KADDR(a) kaddr(a) +#define PADDR(a) paddr((void*)(a)) +#define userureg(ur) (((ur)->psr & PsrMask) == PsrMusr) +#define VA(k) ((void*)(k)) +#define PTR2UINT(p) ((uintptr)(p)) + +void uartinit(void); +void mmuinit(void); +uintptr ttbget(void); +void ttbput(uintptr); +void cycles(uvlong *); +void kexit(Ureg *); +ulong getifsr(void); +ulong getdfsr(void); +uintptr getifar(void); +uintptr getdfar(void); +void links(void); +void* vmap(uintptr, ulong); +void timerinit(void); +void setpmcr(ulong); +void* tmpmap(uintptr); +void tmpunmap(void*); +void flushpg(void *); +void setasid(ulong); +void flushtlb(void); +void touser(void *); +void noted(Ureg *, ulong); +void l1switch(L1 *, int); +void intrenable(int, void (*)(Ureg *, void *), void *, int, char *); +void intrinit(void); +void intr(Ureg *); +int uartconsole(void); +void fpoff(void); +void fpsave(FPsave *); +void fprestore(FPsave *); +void fpinit(void); +void fpclear(void); +char* getconf(char *); +void invalise(void *, void *); +void cleandse(void *, void *); +void invaldse(void *, void *); +void clinvdse(void *, void *); +void invaldln(void *); +void cleandln(void *); +void clinvdln(void *); +uintptr ualloc(ulong, void **); +void clean2pa(uintptr, uintptr); +void inval2pa(uintptr, uintptr); +void archinit(void); +uintptr palookur(void *); +void screeninit(void); +int isaconfig(char*, int, ISAConf*); +void *ucalloc(usize); +void *ucallocalign(usize, int, int); +void ucfree(void *); diff --git a/sys/src/9/zynq/init9.s b/sys/src/9/zynq/init9.s new file mode 100644 index 000000000..8d6f11df4 --- /dev/null +++ b/sys/src/9/zynq/init9.s @@ -0,0 +1,7 @@ +TEXT _main(SB), $-4 + MOVW $setR12(SB), R12 + MOVW 4(R13), R0 + ADD $4, R13, R1 + SUB $4, R13 + MOVW R1, 8(R13) + MOVW $startboot(SB), R15 diff --git a/sys/src/9/zynq/intr.c b/sys/src/9/zynq/intr.c new file mode 100644 index 000000000..b8bf858f4 --- /dev/null +++ b/sys/src/9/zynq/intr.c @@ -0,0 +1,118 @@ +#include "u.h" +#include <ureg.h> +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +enum { + NINTR = 96, + NPRIVATE = 32 +}; + +static struct irq { + void (*f)(Ureg *, void *); + void *arg; + char *name; +} irqs[NINTR]; + +enum { + ICCICR = 0x100/4, + ICCPMR, + ICCBPR, + ICCIAR, + ICCEOIR, + ICDDCR = 0x1000/4, + ICDISR = 0x1080/4, + ICDISER = 0x1100/4, + ICDICER = 0x1180/4, + ICDICPR = 0x1280/4, + ICDABR = 0x1300/4, + ICDIPRI = 0x1400/4, + ICDIPTR = 0x1800/4, + ICDICFR = 0x1C00/4, +}; + +void +intrinit(void) +{ + int i; + + mpcore[ICDDCR] = 3; + mpcore[ICCICR] = 7; + mpcore[ICCBPR] = 3; + mpcore[ICCPMR] = 255; + + /* disable all irqs and clear any pending interrupts */ + for(i = 0; i < NINTR/32; i++){ + mpcore[ICDISR + i] = -1; + mpcore[ICDICER + i] = -1; + mpcore[ICDICPR + i] = -1; + mpcore[ICDABR + i] = 0; + } +} + +void +intrenable(int irq, void (*f)(Ureg *, void *), void *arg, int type, char *name) +{ + ulong *e, s; + struct irq *i; + + if(f == nil) + panic("intrenable: f == nil"); + if(irq < 0 || irq >= NINTR) + panic("intrenable: invalid irq %d", irq); + if(type != LEVEL && type != EDGE) + panic("intrenable: invalid type %d", type); + if(irqs[irq].f != nil) + panic("intrenable: handler already assigned"); + if(irq >= NPRIVATE){ + e = &mpcore[ICDIPTR + (irq >> 2)]; + s = irq << 3 & 24; + *e = *e & ~(3 << s) | 1 << s; + e = &mpcore[ICDICFR + (irq >> 4)]; + s = irq << 1 & 30 | 1; + *e = *e & ~(1 << s) | type << s; + } + ((uchar*)&mpcore[ICDIPRI])[irq] = 0; + i = &irqs[irq]; + i->f = f; + i->arg = arg; + i->name = name; + mpcore[ICDISER + (irq >> 5)] = 1 << (irq & 31); + mpcore[ICDABR + (irq >> 5)] |= 1 << (irq & 31); +} + +void +intr(Ureg *ureg) +{ + ulong v; + int irq; + struct irq *i; + + v = mpcore[ICCIAR]; + irq = v & 0x3ff; + if(irq == 0x3ff) + return; + + m->intr++; + m->lastintr = irq; + i = &irqs[irq]; + if(i->f == nil) + print("irq without handler %d\n", irq); + else + i->f(ureg, i->arg); + mpcore[ICCEOIR] = v; + + if(up != nil){ + if(irq == TIMERIRQ){ + if(up->delaysched){ + splhi(); + sched(); + } + }else + preempted(); + } +} diff --git a/sys/src/9/zynq/io.h b/sys/src/9/zynq/io.h new file mode 100644 index 000000000..7baf42e9c --- /dev/null +++ b/sys/src/9/zynq/io.h @@ -0,0 +1,25 @@ +#define PS_CLK 33 + +#define UART_BASE 0xE0001000 +#define USB0_BASE 0xE0002000 +#define USB1_BASE 0xE0003000 +#define ETH0_BASE 0xE000B000 +#define QSPI_BASE 0xE000D000 +#define SLCR_BASE 0xF8000000 +#define DEVC_BASE 0xF8007000 +#define MPCORE_BASE 0xF8F00000 +#define L2_BASE 0xF8F02000 +#define OCM_BASE 0xFFFC0000 + +#define TIMERIRQ 29 +#define XADCIRQ 39 +#define DEVCIRQ 40 +#define USB0IRQ 53 +#define ETH0IRQ 54 +#define USB1IRQ 76 +#define UART1IRQ 82 + +#define LEVEL 0 +#define EDGE 1 + +#define XADCINTERVAL 500 diff --git a/sys/src/9/zynq/l.s b/sys/src/9/zynq/l.s new file mode 100644 index 000000000..a02ac6c7c --- /dev/null +++ b/sys/src/9/zynq/l.s @@ -0,0 +1,460 @@ +#include "mem.h" +#include "io.h" + +#define PUTC(c) MOVW $(c), R0; MOVW R0, (R8) + +TEXT _start(SB), $-4 + MOVW $(KTZERO-KZERO), R13 + MOVW $0xE0001030, R8 + + PUTC('P') + MOVW $0, R0 + MOVW R0, R1 + MOVW $(CONFADDR-KZERO), R2 +_start0: + MOVW.P R0, 4(R1) + CMP.S R1, R2 + BNE _start0 + + PUTC('l') + MOVW $SECSZ, R0 + MOVW $(CPU0L1-KZERO), R4 + MOVW $KZERO, R1 + ADD R1>>(SECSH-2), R4, R1 + MOVW $(L1SEC|L1CACHED|L1KERRW), R2 + MOVW $(-KZERO), R3 +_start1: + MOVW.P R2, 4(R1) + ADD R0, R2 + CMP.S R2, R3 + BGE _start1 + + PUTC('a') + MOVW $L2SZ, R0 + MOVW $VMAP, R1 + ADD R1>>(SECSH-2), R4, R1 + MOVW $((VMAPL2-KZERO)|L1PT), R2 + MOVW $(VMAPL2-KZERO+VMAPL2SZ), R3 +_start2: + MOVW.P R2, 4(R1) + ADD R0, R2 + CMP.S R2, R3 + BGE _start2 + + MOVW $(UART_BASE|L2VALID|L2DEVICE|L2KERRW), R0 + MOVW $(VMAPL2 - KZERO), R1 + MOVW R0, (R1) + + PUTC('n') + MOVW $0, R0 + MCR 15, 0, R0, C(8), C(7), 0 + MOVW $(CPU0L1 - KZERO | TTBATTR), R1 + MCR 15, 0, R1, C(2), C(0), 0 + MOVW $0x20c5047b, R1 + MOVW $_virt(SB), R2 + PUTC(' ') + MCR 15, 0, R1, C(1), C(0), 0 + MOVW R2, R15 + +TEXT _virt(SB), $-4 + DSB + ISB + + MOVW $(MACH(0) + MACHSIZE), R13 + MOVW $(MACH(0) + 12), R0 + BL loadsp(SB) + MOVW $vectors(SB), R1 + MCR 15, 0, R1, C(12), C(0) + + /* enable MMU permission checking */ + MOVW $0x55555555, R0 + MCR 15, 0, R0, C(3), C(0), 0 + + /* enable maths coprocessors in CPACR but disable them in FPEXC */ + MRC 15, 0, R0, C(1), C(0), 2 + ORR $(15<<20), R0 + MCR 15, 0, R0, C(1), C(0), 2 + + VMRS(0xe, FPEXC, 0) + BIC $(3<<30), R0 + VMSR(0xe, 0, FPEXC) + + /* enable L1 cache */ + MOVW $0, R0 + MCR 15, 0, R0, C(7), C(5), 0 + MCR 15, 0, R0, C(7), C(5), 6 + BL l1dclear(SB) + MRC 15, 0, R0, C(1), C(0), 1 + ORR $(1|1<<6), R0 + MCR 15, 0, R0, C(1), C(0), 1 + MRC 15, 0, R0, C(1), C(0), 0 + ORR $(1<<12|1<<2), R0 + MCR 15, 0, R0, C(1), C(0), 0 + DSB + ISB + + MOVW $(VMAP+0x30), R8 + PUTC('9') + + MOVW $setR12(SB), R12 + MOVW $MACH(0), R(Rmach) + MOVW $0, R(Rup) + BL main(SB) + B idlehands(SB) + + BL _div(SB) /* hack to load _div */ + +TEXT touser(SB), $-4 + CPS(CPSID) + + SUB $12, R13 + MOVW R0, (R13) + MOVW $0, R1 + MOVW R1, 4(R13) + MOVW $(UTZERO+0x20), R1 + MOVW R1, 8(R13) + + MOVW CPSR, R1 + BIC $(PsrMask|PsrDirq|PsrDfiq), R1 + ORR $PsrMusr, R1 + MOVW R1, SPSR + + MOVW $(KTZERO-(15*4)), R0 + MOVM.IA (R0), [R0-R12] + + MOVM.IA.S (R13), [R13-R14] + ADD $8, R13 + MOVM.IA.W.S (R13), [R15] + +TEXT forkret(SB), $-4 + MOVW (16*4)(R13), R0 + MOVW R0, SPSR + MOVM.IA.W (R13), [R0-R12] + MOVM.IA.S (R13), [R13-R14] + ADD $16, R13 + DSB + ISB + MOVM.IA.W.S (R13), [R15] + +TEXT nope(SB), $-4 // NOPE + MOVW $(VMAP+0x30), R8 + PUTC(13) + PUTC(10) + MOVW R14, R7 + BL puthex(SB) + PUTC(' ') + PUTC('N') + PUTC('O') + PUTC('P') + PUTC('E') +_nope: B _nope + +TEXT loadsp(SB), $0 + CPS(CPSMODE | PsrMabt) + MOVW R0, R13 + CPS(CPSMODE | PsrMund) + MOVW R0, R13 + CPS(CPSMODE | PsrMirq) + MOVW R0, R13 + CPS(CPSMODE | PsrMfiq) + MOVW R0, R13 + CPS(CPSMODE | PsrMsvc) + RET + +TEXT cputhex(SB), $0 + MOVW R0, R7 + MOVW $(VMAP+0x30), R8 +TEXT puthex(SB), $0 +_p0: + MOVW -4(R8), R6 + AND.S $(1<<3), R6 + BEQ _p0 +#define DIG MOVW R7>>28, R6; AND $15, R6; ADD $'0', R6; CMP $'9', R6; ADD.GT $7, R6; MOVW R6, (R8); MOVW R7<<4, R7 + DIG; DIG; DIG; DIG + DIG; DIG; DIG; DIG + MOVW $13, R6 + MOVW R6, (R8) + MOVW $10, R6 + MOVW R6, (R8) + RET + +TEXT spllo(SB), $-4 + MOVW CPSR, R0 + CPS(CPSIE) + RET + +TEXT splhi(SB), $-4 + MOVW R14, 4(R(Rmach)) + MOVW CPSR, R0 + CPS(CPSID) + RET + +TEXT splx(SB), $-4 + MOVW R14, 4(R(Rmach)) + MOVW R0, R1 + MOVW CPSR, R0 + MOVW R1, CPSR + RET + +TEXT spldone(SB), $-4 + RET + +TEXT islo(SB), $0 + MOVW CPSR, R0 + AND $(PsrDirq), R0 + EOR $(PsrDirq), R0 + RET + +TEXT setlabel(SB), $-4 + MOVW R13, 0(R0) + MOVW R14, 4(R0) + MOVW $0, R0 + RET + +TEXT gotolabel(SB), $-4 + MOVW 0(R0), R13 + MOVW 4(R0), R14 + MOVW $1, R0 + RET + +TEXT tas(SB), $0 + DMB + MOVW $0xDEADDEAD, R2 +_tas1: + LDREX (R0), R1 + STREX R2, (R0), R3 + CMP.S $0, R3 + BNE _tas1 + MOVW R1, R0 + DMB + RET + +TEXT coherence(SB), $0 + DSB + RET + +TEXT idlehands(SB), $0 + DSB + WFE + RET + +TEXT ttbget(SB), $0 + MRC 15, 0, R0, C(2), C(0), 0 + BIC $0x7f, R0 + RET + +TEXT ttbput(SB), $0 + ORR $(TTBATTR), R0 + MCR 15, 0, R0, C(2), C(0), 0 + RET + +TEXT flushpg(SB), $0 + MCR 15, 0, R0, C(8), C(7), 3 + DSB + RET + +TEXT flushtlb(SB), $0 + MCR 15, 0, R0, C(8), C(3), 0 + DSB + RET + +TEXT setasid(SB), $0 + MCR 15, 0, R0, C(13), C(0), 1 + RET + +TEXT getifar(SB), $0 + MRC 15, 0, R0, C(6), C(0), 2 + RET + +TEXT getdfar(SB), $0 + MRC 15, 0, R0, C(6), C(0), 0 + RET + +TEXT getifsr(SB), $0 + MRC 15, 0, R0, C(5), C(0), 1 + RET + +TEXT getdfsr(SB), $0 + MRC 15, 0, R0, C(5), C(0), 0 + RET + +TEXT setpmcr(SB), $0 + MCR 15, 0, R0, C(9), C(12), 0 + RET + +TEXT perfticks(SB), $0 + MRC 15, 0, R0, C(9), C(13), 0 + RET + +TEXT cycles(SB), $0 + MRC 15, 0, R1, C(9), C(13), 0 + MOVW R1, (R0) + MOVW 24(R(Rmach)), R1 + MRC 15, 0, R2, C(9), C(12), 3 + AND.S $(1<<31), R2 + BEQ _cycles0 + MCR 15, 0, R2, C(9), C(12), 3 + ADD $1, R1 + MOVW R1, 24(R(Rmach)) +_cycles0: + MOVW R1, 4(R0) + RET + +TEXT fpinit(SB), $0 + MOVW $(1<<30), R0 + VMSR(0xe, 0, FPEXC) + MOVW $0, R0 + VMSR(0xe, 0, FPSCR) + RET + +TEXT fpsave(SB), $0 + VMRS(0xe, FPEXC, 1) + VMRS(0xe, FPSCR, 2) + MOVM.IA.W [R1-R2], (R0) + WORD $0xeca00b20 + WORD $0xece00b20 + RET + +TEXT fprestore(SB), $0 + MOVM.IA.W (R0), [R1-R2] + VMSR(0xe, 1, FPEXC) + VMSR(0xe, 2, FPSCR) + WORD $0xecb00b20 + WORD $0xecf00b20 + RET + +TEXT fpoff(SB), $0 + MOVW $0, R1 + VMSR(0xe, 1, FPEXC) + RET + +TEXT fpclear(SB), $0 + VMRS(0xe, FPEXC, 1) + AND $(3<<30), R1 + VMSR(0xe, 1, FPEXC) + RET + +#define Rnoway R1 +#define Rwayinc R2 +#define Rmaxway R3 +#define Rsetinc R4 +#define Rmaxset R5 + +TEXT l1dclear(SB), $0 + MOVW $0, R0 + MCR 15, 2, R0, C(0), C(0), 0 + MRC 15, 1, R9, C(0), C(0), 0 + AND $7, R9, R8 + ADD $4, R8 + MOVW $1, Rsetinc + MOVW Rsetinc<<R8, Rsetinc + + MOVW R9>>13, Rmaxset + AND $0x7fff, Rmaxset + MOVW Rmaxset<<R8, Rmaxset + + MOVW R9>>3, R0 + AND $0x3ff, R0 + MOVW $(1<<31), Rwayinc + MOVW $(1<<31), Rnoway + MOVW R0, Rmaxway + ADD $1, R0 +_l1dclear0: + MOVW.S R0>>1, R0 + BEQ _l1dclear1 + MOVW Rwayinc>>1, Rwayinc + MOVW Rnoway->1, Rnoway + MOVW Rmaxway@>1, Rmaxway + B _l1dclear0 +_l1dclear1: + MOVW Rwayinc<<1, Rwayinc + MVN Rnoway<<1, Rnoway + BIC Rnoway, Rmaxway + + MOVW $0, R0 +_l1dclear2: + MCR 15, 0, R0, C(7), C(14), 2 + ADD Rwayinc, R0 + CMP.S Rmaxway, R0 + BLT _l1dclear2 + AND Rnoway, R0 + ADD Rsetinc, R0 + CMP.S Rmaxset, R0 + BLT _l1dclear2 + RET + +TEXT invalise(SB), $0 + MOVW 4(FP), R1 + ADD $(LINSIZ - 1), R1 + BIC $(LINSIZ - 1), R0 + BIC $(LINSIZ - 1), R1 +_invalise0: + MCR 15, 0, R0, C(7), C(5), 1 + ADD $LINSIZ, R0 + CMP.S R1, R0 + BLT _invalise0 + RET + +TEXT cleandse(SB), $0 + DSB + MOVW 4(FP), R1 + ADD $(LINSIZ - 1), R1 + BIC $(LINSIZ - 1), R0 + BIC $(LINSIZ - 1), R1 +_cleandse0: + MCR 15, 0, R0, C(7), C(10), 1 + ADD $LINSIZ, R0 + CMP.S R1, R0 + BLT _cleandse0 + DSB + RET + +TEXT invaldse(SB), $0 + MOVW 4(FP), R1 + ADD $(LINSIZ - 1), R1 + BIC $(LINSIZ - 1), R0 + BIC $(LINSIZ - 1), R1 +_invaldse0: + MCR 15, 0, R0, C(7), C(6), 1 + ADD $LINSIZ, R0 + CMP.S R1, R0 + BLT _invaldse0 + DSB + RET + +TEXT clinvdse(SB), $0 + DSB + MOVW 4(FP), R1 + ADD $(LINSIZ - 1), R1 + BIC $(LINSIZ - 1), R0 + BIC $(LINSIZ - 1), R1 +_clinvdse0: + MCR 15, 0, R0, C(7), C(14), 1 + ADD $LINSIZ, R0 + CMP.S R1, R0 + BLT _clinvdse0 + DSB + RET + +TEXT cleandln(SB), $0 + DSB + MCR 15, 0, R0, C(7), C(10), 1 + DSB + RET + +TEXT invaldln(SB), $0 + MCR 15, 0, R0, C(7), C(6), 1 + DSB + RET + +TEXT clinvdln(SB), $0 + DSB + MCR 15, 0, R0, C(7), C(14), 1 + DSB + RET + +TEXT palookur(SB), $0 + MCR 15, 0, R0, C(7), C(8), 2 + DSB + MRC 15, 0, R0, C(7), C(4), 0 + RET diff --git a/sys/src/9/zynq/ltrap.s b/sys/src/9/zynq/ltrap.s new file mode 100644 index 000000000..09d15a49e --- /dev/null +++ b/sys/src/9/zynq/ltrap.s @@ -0,0 +1,98 @@ +#include "mem.h" +#include "io.h" + +TEXT vectors(SB), $-4 + MOVW $_start-KZERO(SB), R15 + MOVW $_vexc(SB), R15 + MOVW $_vsvc(SB), R15 + MOVW $_viabt(SB), R15 + MOVW $_vexc(SB), R15 + MOVW $vectors(SB), R15 + MOVW $_vexc(SB), R15 + MOVW $_vexc(SB), R15 + +TEXT _viabt(SB), $-4 + CPS(CPSID) + CLREX + DSB + MOVW R14, 8(R13) + MOVW SPSR, R14 + MOVW R14, 4(R13) + MOVW CPSR, R14 + AND $0x1e, R14 + B _exc + + +TEXT _vexc(SB), $-4 + CPS(CPSID) + CLREX + DSB + MOVW R14, 8(R13) + MOVW SPSR, R14 + MOVW R14, 4(R13) + MOVW CPSR, R14 + AND $0x1f, R14 +_exc: + MOVW R14, 0(R13) + CPS(CPSMODE | PsrMsvc) + + SUB $(18*4), R13 + MOVM.IA [R0-R14], (R13) + + MOVW $MACH(0), R(Rmach) /* FIXME */ + MOVW 8(R(Rmach)), R(Rup) + MOVW $setR12(SB), R12 + + ADD $12, R(Rmach), R0 + MOVM.IA (R0), [R1-R3] + ADD $(15*4), R13, R0 + MOVM.IA [R1-R3], (R0) + + AND.S $0xf, R2 + ADD.NE $(18*4), R13, R0 + MOVW.NE R0, (13*4)(R13) + ADD.EQ $(13*4), R13, R0 + MOVM.IA.S.EQ [R13-R14], (R0) + + MOVW R13, R0 + SUB $8, R13 + BL trap(SB) + ADD $8, R13 + + MOVW (16*4)(R13), R0 + MOVW R0, SPSR + AND.S $0xf, R0 + BEQ _uret + MOVW R(Rmach), (Rmach*4)(R13) + MOVM.IA (R13), [R0-R14] + DSB + MOVM.DB.S (R13), [R15] + +TEXT _vsvc(SB), $-4 + CLREX + DSB + MOVW.W R14, -4(R13) + MOVW SPSR, R14 + MOVW.W R14, -4(R13) + MOVW $PsrMsvc, R14 + MOVW.W R14, -4(R13) + MOVM.DB.S [R0-R14], (R13) + SUB $(15*4), R13 + + MOVW $MACH(0), R(Rmach) /* FIXME */ + MOVW 8(R(Rmach)), R(Rup) + MOVW $setR12(SB), R12 + + MOVW R13, R0 + SUB $8, R13 + BL syscall(SB) + ADD $8, R13 + + MOVW (16*4)(R13), R0 + MOVW R0, SPSR +_uret: + MOVM.IA.S (R13), [R0-R14] + ADD $(17*4), R13 + DSB + ISB + MOVM.IA.S.W (R13), [R15] diff --git a/sys/src/9/zynq/main.bin b/sys/src/9/zynq/main.bin new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/sys/src/9/zynq/main.bin diff --git a/sys/src/9/zynq/main.c b/sys/src/9/zynq/main.c new file mode 100644 index 000000000..dc0bdcce7 --- /dev/null +++ b/sys/src/9/zynq/main.c @@ -0,0 +1,372 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "init.h" +#include "pool.h" +#include "io.h" +#include "../port/error.h" +#include "tos.h" + +Conf conf; +int normalprint, delaylink; +uchar *sp; + +enum { MAXCONF = 64 }; + +char *confname[MAXCONF], *confval[MAXCONF]; +int nconf; + +void +exit(int) +{ + NOPE +} + +void +reboot(void *, void *, ulong) +{ + NOPE +} + +void +evenaddr(uintptr va) +{ + if((va & 3) != 0){ + dumpstack(); + postnote(up, 1, "sys: odd address", NDebug); + error(Ebadarg); + } +} + +void +procfork(Proc *p) +{ + ulong s; + + p->kentry = up->kentry; + p->pcycles = -p->kentry; + + s = splhi(); + switch(up->fpstate & ~FPillegal){ + case FPactive: + fpsave(&up->fpsave); + up->fpstate = FPinactive; + case FPinactive: + p->fpsave = up->fpsave; + p->fpstate = FPinactive; + } + splx(s); +} + +void +procsetup(Proc *p) +{ + p->fpstate = FPinit; + fpoff(); + + cycles(&p->kentry); + p->pcycles = -p->kentry; +} + +int +cmpswap(long *a, long b, long c) +{ + extern int cas(int *, int, int); + + return cas((int *) a, b, c); +} + +void +kexit(Ureg *) +{ + Tos *tos; + uvlong t; + + tos = (Tos*)(USTKTOP-sizeof(Tos)); + cycles(&t); + tos->kcycles += t - up->kentry; + tos->pcycles = t + up->pcycles; + tos->pid = up->pid; +} + +ulong *l2; + +void +l2init(void) +{ + enum { + CTRL = 0x100/4, + AUX, + TAGRAM, + DATARAM, + INVPA = 0x770/4, + INVWAY = 0x77C/4, + PREFETCH = 0xF60/4, + }; + + mpcore[0] |= 1; + slcr[0xa1c/4] = 0x020202; + l2 = vmap(L2_BASE, BY2PG); + l2[CTRL] &= ~1; + l2[TAGRAM] = l2[TAGRAM] & ~0x777 | 0x111; + l2[DATARAM] = l2[DATARAM] & ~0x777 | 0x121; + l2[PREFETCH] |= 3<<28; + l2[AUX] |= 3<<28 | 1<<20; + l2[INVWAY] = 0xff; + while((l2[INVPA] & 1) != 0) + ; + l2[CTRL] = 1; +} + +void +clean2pa(uintptr start, uintptr end) +{ + uintptr pa; + + start &= ~31; + end = (end + 31) & ~31; + for(pa = start; pa < end; pa += 32) + l2[0x7b0/4] = pa; +} + +void +inval2pa(uintptr start, uintptr end) +{ + uintptr pa; + + start &= ~31; + end = (end + 31) & ~31; + for(pa = start; pa < end; pa += 32) + l2[0x770/4] = pa; +} + +static void +options(void) +{ + long i, n; + char *cp, *line[MAXCONF], *p, *q; + + cp = (char *) CONFADDR; + + p = cp; + for(q = cp; *q; q++){ + if(*q == '\r') + continue; + if(*q == '\t') + *q = ' '; + *p++ = *q; + } + *p = 0; + + n = getfields(cp, line, MAXCONF, 1, "\n"); + for(i = 0; i < n; i++){ + if(*line[i] == '#') + continue; + cp = strchr(line[i], '='); + if(cp == nil) + continue; + *cp++ = '\0'; + confname[nconf] = line[i]; + confval[nconf] = cp; + nconf++; + } + +} + +void +confinit(void) +{ + int i; + + conf.nmach = 1; + conf.nproc = 100; + conf.ialloc = 16*1024*1024; + conf.nimage = conf.nproc; + conf.mem[0].base = PGROUND((ulong)end - KZERO); + conf.mem[0].limit = 1024*1024*1024; + conf.npage = 0; + for(i = 0; i < nelem(conf.mem); i++) + conf.npage += conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base) >> PGSHIFT; + conf.upages = conf.npage - 100*1024*1024 / BY2PG; +} + +static uchar * +pusharg(char *p) +{ + int n; + + n = strlen(p) + 1; + sp -= n; + memmove(sp, p, n); + return sp; +} + +static void +bootargs(void *base) +{ + int i, ac; + uchar *av[32]; + uchar **lsp; + + sp = (uchar *) base + BY2PG - sizeof(Tos); + + ac = 0; + av[ac++] = pusharg("boot"); + sp = (uchar *) ((ulong) sp & ~3); + sp -= (ac + 1) * sizeof(sp); + lsp = (uchar **) sp; + for(i = 0; i < ac; i++) + lsp[i] = av[i] + ((USTKTOP - BY2PG) - (ulong) base); + lsp[i] = 0; + sp += (USTKTOP - BY2PG) - (ulong) base; + sp -= BY2WD; +} + +static void +init0(void) +{ + char buf[ERRMAX]; + int i; + + up->nerrlab = 0; + spllo(); + + up->slash = namec("#/", Atodir, 0, 0); + pathclose(up->slash->path); + up->slash->path = newpath("/"); + up->dot = cclone(up->slash); + + chandevinit(); + uartconsole(); + + if(!waserror()){ + ksetenv("cputype", "arm", 0); + if(cpuserver) + ksetenv("service", "cpu", 0); + else + ksetenv("service", "terminal", 0); + ksetenv("console", "0", 0); + snprint(buf, sizeof(buf), "zynq %s", conffile); + ksetenv("terminal", buf, 0); + for(i = 0; i < nconf; i++){ + if(*confname[i] != '*') + ksetenv(confname[i], confval[i], 0); + ksetenv(confname[i], confval[i], 1); + } + poperror(); + } + kproc("alarm", alarmkproc, 0); + touser(sp); +} + +void +userinit(void) +{ + Proc *p; + Segment *s; + void *v; + Page *pg; + + p = newproc(); + p->pgrp = newpgrp(); + p->egrp = smalloc(sizeof(Egrp)); + p->egrp->ref = 1; + p->fgrp = dupfgrp(nil); + p->rgrp = newrgrp(); + p->procmode = 0640; + + kstrdup(&eve, ""); + kstrdup(&p->text, "*init*"); + kstrdup(&p->user, eve); + + procsetup(p); + + p->sched.pc = (ulong)init0; + p->sched.sp = (ulong)p->kstack + KSTACK - (sizeof(Sargs) + BY2WD); + + s = newseg(SG_STACK, USTKTOP - USTKSIZE, USTKSIZE / BY2PG); + p->seg[SSEG] = s; + pg = newpage(0, 0, USTKTOP - BY2PG); + v = tmpmap(pg->pa); + memset(v, 0, BY2PG); + segpage(s, pg); + bootargs(v); + tmpunmap(v); + + s = newseg(SG_TEXT, UTZERO, 1); + s->flushme++; + p->seg[TSEG] = s; + pg = newpage(0, 0, UTZERO); + memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); + + segpage(s, pg); + v = tmpmap(pg->pa); + memset(v, 0, BY2PG); + memmove(v, initcode, sizeof(initcode)); + tmpunmap(v); + + ready(p); +} + +void +sanity(void) +{ + static int dat = 0xdeadbeef; + extern ulong vectors[]; + + assert(dat == 0xdeadbeef); + assert(((uintptr)vectors & 31) == 0); + assert(sizeof(Mach) + KSTACK <= MACHSIZE); + assert((KZERO & SECSZ - 1) == 0); +} + +char * +getconf(char *n) +{ + int i; + + for(i = 0; i < nconf; i++) + if(cistrcmp(confname[i], n) == 0) + return confval[i]; + return nil; +} + +int +isaconfig(char *, int, ISAConf*) +{ + return 1; +} + +void +main(void) +{ + uartinit(); + mmuinit(); + l2init(); + intrinit(); + options(); + confinit(); + timerinit(); + uartputs(" from Bell Labs\n", 16); + xinit(); + printinit(); + quotefmtinstall(); + sanity(); + todinit(); + timersinit(); + procinit0(); + initseg(); + if(delaylink) + bootlinks(); + else + links(); + archinit(); + chandevreset(); + pageinit(); + swapinit(); + screeninit(); + userinit(); + schedinit(); +} diff --git a/sys/src/9/zynq/mem.h b/sys/src/9/zynq/mem.h new file mode 100644 index 000000000..24c39b6a0 --- /dev/null +++ b/sys/src/9/zynq/mem.h @@ -0,0 +1,124 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +#define MIN(a, b) ((a) < (b)? (a): (b)) +#define MAX(a, b) ((a) > (b)? (a): (b)) + +/* + * Sizes + */ +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2V 8 /* bytes per double word */ +#define BY2PG 4096 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1)) +#define PGROUND(s) ROUND(s, BY2PG) +#define LINSIZ 32 +#define BLOCKALIGN LINSIZ +#define FPalign 16 + +#define MAXMACH 2 +#define KSTACK 4096 + +#define HZ (1000) +#define MS2HZ (1000/HZ) +#define TK2SEC(t) ((t)/HZ) + +#define KZERO 0xF0000000 +#define KTZERO (KZERO+0x80000) +#define VMAPSZ (SECSZ * 4) +#define VMAP (KZERO - VMAPSZ) +#define TMAPSZ SECSZ +#define TMAP (VMAP - TMAPSZ) +#define KMAPSZ SECSZ +#define KMAP (TMAP - KMAPSZ) +#define NKMAP (KMAPSZ / BY2PG - 1) +#define MACHSIZE 8192 +#define MACH(n) (KZERO+(n)*MACHSIZE) +#define MACHP(n) ((Mach *)MACH(n)) +#define CPU0L1 ROUND(MACH(MAXMACH), L1SZ) +#define VMAPL2 (CPU0L1 + L1SZ) +#define VMAPL2SZ (L2SZ * (VMAPSZ / SECSZ)) +#define TMAPL2(n) (VMAPL2 + VMAPL2SZ + (n) * L2SZ) +#define TMAPL2SZ (MAXMACH * L2SZ) +#define CONFSIZE 65536 +#define CONFADDR (KTZERO-CONFSIZE) + +#define UZERO 0 +#define UTZERO BY2PG +#define UTROUND(t) ROUNDUP(t, BY2PG) +#define USTKTOP 0xE0000000 +#define USTKSIZE (16*1024*1024) + +#define PTEMAPMEM (1024*1024) +#define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 1984 +#define SSEGMAPSIZE 16 + +#define PTEVALID L2VALID +#define PTERONLY L2RONLY +#define PTEWRITE L2WRITE +#define PTEUNCACHED L2DEVICE +#define PPN(x) ((x)&~(BY2PG-1)) + +#define PsrDirq (1<<7) +#define PsrDfiq (1<<6) +#define PsrMask 0x1f +#define PsrMusr 0x10 +#define PsrMfiq 0x11 +#define PsrMirq 0x12 +#define PsrMsvc 0x13 +#define PsrMabt 0x17 +#define PsrMiabt 0x16 /* not an actual mode; for ureg->type */ +#define PsrMund 0x1b + +#define DMB WORD $0xf57ff05f +#define DSB WORD $0xf57ff04f +#define ISB WORD $0xf57ff06f +#define WFE WORD $0xe320f002 +#define CPS(m) WORD $(0xf1000000|(m)) +#define CPSMODE (1<<17) +#define CPSIE (3<<6|2<<18) +#define CPSID (3<<6|3<<18) +#define Rmach 10 +#define Rup 9 + +#define VMSR(c, r1, r2) WORD $(0x0ee00a10|(c)<<28|(r2)<<16|(r1)<<12) +#define VMRS(c, r1, r2) WORD $(0x0ef00a10|(c)<<28|(r2)<<12|(r1)<<16) +#define FPSID 0x0 +#define FPSCR 0x1 +#define MVFR1 0x6 +#define MVFR0 0x7 +#define FPEXC 0x8 + +#define L1PT 1 +#define L1SEC (2|1<<10) +#define L1DEVICE (1<<4) +#define L1CACHED (1<<16|1<<14|1<<12|1<<2) +#define L1KERRW 0 +#define L1SZ (4096*4) +#define L2SZ (256*4) +#define SECSZ 1048576 +#define SECSH 20 +#define NL2 256 + +#define L1X(va) (((ulong)(va)) >> 20) +#define L1RX(va) (((ulong)(va)) >> 20 & ~3) +#define L2X(va) (((ulong)(va)) >> 12 & 0xff) +#define L2RX(va) (((ulong)(va)) >> 12 & 0x3ff) + +#define L2VALID (2|1<<4) +#define L2CACHED (1<<10|1<<8|1<<6|1<<2) +#define L2DEVICE (1<<0) +#define L2KERRW L2KERNEL +#define L2KERNEL 0 +#define L2USER (1<<5) +#define L2RONLY (1<<9) +#define L2WRITE 0 +#define L2LOCAL (1<<11) + +#define TTBATTR (1<<6|1<<3) diff --git a/sys/src/9/zynq/mkfile b/sys/src/9/zynq/mkfile new file mode 100644 index 000000000..690540bfd --- /dev/null +++ b/sys/src/9/zynq/mkfile @@ -0,0 +1,92 @@ +CONF=zynq +CONFLIST=zynq + +#must match mem.h +KTZERO=0xf0080020 + +objtype=arm +</$objtype/mkfile +p=9 + +DEVS=`{rc ../port/mkdevlist $CONF} + +PORT=\ + alarm.$O\ + alloc.$O\ + allocb.$O\ + auth.$O\ + cache.$O\ + chan.$O\ + dev.$O\ + edf.$O\ + fault.$O\ + mul64fract.$O\ + rebootcmd.$O\ + page.$O\ + parse.$O\ + pgrp.$O\ + portclock.$O\ + print.$O\ + proc.$O\ + qio.$O\ + qlock.$O\ + segment.$O\ + swap.$O\ + sysfile.$O\ + sysproc.$O\ + taslock.$O\ + tod.$O\ + xalloc.$O\ + random.$O\ + rdb.$O\ + syscallfmt.$O\ + +OBJ=\ + ltrap.$O\ + l.$O\ + main.$O\ + mmu.$O\ + trap.$O\ + intr.$O\ + timer.$O\ + $CONF.root.$O\ + $CONF.rootc.$O\ + $DEVS\ + $PORT\ + + +LIB=\ + /$objtype/lib/libmemlayer.a\ + /$objtype/lib/libmemdraw.a\ + /$objtype/lib/libdraw.a\ + /$objtype/lib/libip.a\ + /$objtype/lib/libsec.a\ + /$objtype/lib/libmp.a\ + /$objtype/lib/libc.a\ + +9:V: install # $p$CONF + +$p$CONF:D: $CONF.c $OBJ $LIB mkfile + $CC $CFLAGS '-DKERNDATE='`{date -n} $CONF.c + $LD -o $target -T$KTZERO -l $OBJ $CONF.$O $LIB + +<../boot/bootmkfile +<../port/portmkfile +<|../port/mkbootrules $CONF + +init.h:D: ../port/initcode.c init9.s + $CC ../port/initcode.c + $AS init9.s + $LD -l -R1 -s -o init.out init9.$O initcode.$O /arm/lib/libc.a + {echo 'uchar initcode[]={' + xd -1x <init.out | + sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g' + echo '};'} > init.h + +install:V: $p$CONF + cp $p$CONF /$objtype/ + for(i in $EXTRACOPIES) + import $i / /n/$i && cp $p$CONF $p$CONF.gz /n/$i/$objtype/ + +devusb.$O usbehci.$O usbehcizynq.$O: ../port/usb.h uncached.h +usbehci.$O usbehcizynq.$O: usbehci.h diff --git a/sys/src/9/zynq/mmu.c b/sys/src/9/zynq/mmu.c new file mode 100644 index 000000000..f2fa6e0f9 --- /dev/null +++ b/sys/src/9/zynq/mmu.c @@ -0,0 +1,422 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +ulong *mpcore, *slcr; + +void +mmuinit(void) +{ + m->l1.pa = ttbget(); + m->l1.va = KADDR(m->l1.pa); + mpcore = vmap(MPCORE_BASE, 0x2000); + slcr = vmap(SLCR_BASE, 0x1000); + m->l1.va[L1X(TMAP)] = PADDR(TMAPL2(m->machno)) | L1PT; + incref(&m->l1); +} + +void +l1switch(L1 *p, int flush) +{ + assert(!islo()); + + ttbput(p->pa); + if(flush){ + if(++m->asid == 0) + flushtlb(); + setasid(m->asid); + } +} + +static L1 * +l1alloc(void) +{ + L1 *p; + int s; + + s = splhi(); + if(m->l1free != nil){ + p = m->l1free; + p->next = nil; + m->l1free = m->l1free->next; + m->nfree--; + splx(s); + return p; + }else{ + p = smalloc(sizeof(L1)); + for(;;){ + p->va = mallocalign(L1SZ, L1SZ, 0, 0); + if(p->va != nil) + break; + if(!waserror()){ + resrcwait("no memory for L1 table"); + poperror(); + } + } + memmove(p->va, m->l1.va, L1SZ); + p->pa = PADDR(p->va); + splx(s); + return p; + } +} + +static void +l1free(L1 *l1) +{ + if(islo()) + panic("l1free: islo"); + if(m->nfree >= 40){ + free(l1->va); + free(l1); + }else{ + l1->next = m->l1free; + m->l1free = l1; + m->nfree++; + } +} + +static void +upallocl1(void) +{ + L1 *p; + int s; + + if(up->l1 != nil) + return; + p = l1alloc(); + s = splhi(); + if(up->l1 != nil) + l1free(p); + else{ + up->l1 = p; + l1switch(p, 1); + } + splx(s); +} + +static void +l2free(Proc *proc) +{ + int s; + ulong *t; + Page *p, **l; + + if(proc->l1 == nil || proc->mmuused == nil) + return; + s = splhi(); + l = &proc->mmuused; + for(p = *l; p != nil; p = p->next){ + t = proc->l1->va + p->daddr; + *t++ = 0; + *t++ = 0; + *t++ = 0; + *t = 0; + l = &p->next; + } + splx(s); + *l = proc->mmufree; + proc->mmufree = proc->mmuused; + proc->mmuused = 0; +} + +void +mmuswitch(Proc *p) +{ + if(p->newtlb){ + p->newtlb = 0; + l2free(p); + } + if(p->l1 != nil) + l1switch(p->l1, 1); + else + l1switch(&m->l1, 1); +} + +void +putmmu(uintptr va, uintptr pa, Page *pg) +{ + Page *p; + ulong *e; + ulong *l2; + PTE old; + uintptr l2p; + + if(up->l1 == nil) + upallocl1(); + if((pa & PTEUNCACHED) == 0) + pa |= L2CACHED; + e = &up->l1->va[L1RX(va)]; + if((*e & 3) == 0){ + if(up->mmufree != nil){ + p = up->mmufree; + up->mmufree = p->next; + }else + p = newpage(0, 0, 0); + l2p = p->pa; + l2 = tmpmap(l2p); + memset(l2, 0, BY2PG); + coherence(); + e[0] = p->pa | L1PT; + e[1] = e[0] + L2SZ; + e[2] = e[1] + L2SZ; + e[3] = e[2] + L2SZ; + coherence(); + p->daddr = L1RX(va); + p->next = up->mmuused; + up->mmuused = p; + }else{ + l2p = *e & ~(BY2PG - 1); + l2 = tmpmap(l2p); + } + e = &l2[L2RX(va)]; + old = *e; + *e = pa | L2VALID | L2USER | L2LOCAL; + tmpunmap(l2); + coherence(); + if((old & L2VALID) != 0) + flushpg((void *) va); + if(pg->cachectl[0] == PG_TXTFLUSH){ + cleandse((void *) va, (void *) (va + BY2PG)); + invalise((void *) va, (void *) (va + BY2PG)); + pg->cachectl[0] = PG_NOFLUSH; + } +} + +void +checkmmu(uintptr, uintptr) +{ + print("checkmmu\n"); +} + +void +flushmmu(void) +{ + int s; + + s = splhi(); + up->newtlb = 1; + mmuswitch(up); + splx(s); +} + +void +mmurelease(Proc *proc) +{ + Page *p, *n; + + if(islo()) + panic("mmurelease: islo"); + + l1switch(&m->l1, 0); + if(proc->kmaptable != nil){ + if(proc->l1 == nil) + panic("mmurelease: no l1"); + if(decref(proc->kmaptable) != 0) + panic("mmurelease: kmap ref %ld", proc->kmaptable->ref); + if(proc->nkmap) + panic("mmurelease: nkmap %d", proc->nkmap); + if(PPN(proc->l1->va[L1X(KMAP)]) != proc->kmaptable->pa) + panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], proc->kmaptable->pa); + proc->l1->va[L1X(KMAP)] = 0; + pagechainhead(proc->kmaptable); + proc->kmaptable = nil; + } + if(proc->l1 != nil){ + l2free(proc); + l1free(proc->l1); + proc->l1 = nil; + } + for(p = proc->mmufree; p != nil; p = n){ + n = p->next; + if(decref(p) != 0) + panic("mmurelease: p->ref %ld", p->ref); + pagechainhead(p); + } + if(proc->mmufree != nil && palloc.r.p != nil) + wakeup(&palloc.r); + proc->mmufree = nil; +} + +void +countpagerefs(ulong *, int) +{ + print("countpagerefs\n"); +} + +void * +kaddr(uintptr u) +{ + if(u >= (uintptr)-KZERO) + panic("kaddr: pa=%#.8lux", u); + return (void *)(u + KZERO); +} + +uintptr +paddr(void *v) +{ + if((uintptr)v < KZERO) + panic("paddr: va=%#.8lux", (uintptr) v); + return (uintptr)v - KZERO; +} + +uintptr +cankaddr(uintptr u) +{ + if(u >= (uintptr)-KZERO) + return 0; + return -KZERO - u; +} + +KMap * +kmap(Page *page) +{ + ulong *e, *v; + int i; + ulong s; + + if(up == nil) + panic("kmap: up=0 pc=%#.8lux", getcallerpc(&page)); + if(up->l1 == nil) + upallocl1(); + if(up->nkmap < 0) + panic("kmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap); + s = splhi(); + up->nkmap++; + e = &up->l1->va[L1X(KMAP)]; + if((*e & 3) == 0){ + if(up->kmaptable != nil) + panic("kmaptable"); + spllo(); + up->kmaptable = newpage(0, 0, 0); + splhi(); + v = tmpmap(up->kmaptable->pa); + memset(v, 0, BY2PG); + v[0] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL; + v[NKMAP] = up->kmaptable->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL; + tmpunmap(v); + coherence(); + *e = up->kmaptable->pa | L1PT; + splx(s); + coherence(); + return (KMap *) KMAP; + } + if(up->kmaptable == nil) + panic("kmaptable"); + e = (ulong *) (KMAP + NKMAP * BY2PG); + for(i = 0; i < NKMAP; i++) + if((e[i] & 3) == 0){ + e[i] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL; + splx(s); + coherence(); + return (KMap *) (KMAP + i * BY2PG); + } + panic("out of kmap"); + return nil; +} + +void +kunmap(KMap *arg) +{ + uintptr va; + ulong *e; + + va = (uintptr) arg; + if(up->l1 == nil || (up->l1->va[L1X(KMAP)] & 3) == 0) + panic("kunmap: no kmaps"); + if(va < KMAP || va >= KMAP + NKMAP * BY2PG) + panic("kunmap: bad address %#.8lux pc=%#p", va, getcallerpc(&arg)); + e = (ulong *) (KMAP + NKMAP * BY2PG) + L2X(va); + if((*e & 3) == 0) + panic("kunmap: not mapped %#.8lux pc=%#p", va, getcallerpc(&arg)); + up->nkmap--; + if(up->nkmap < 0) + panic("kunmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap); + *e = 0; + coherence(); + flushpg((void *) va); +} + +void * +tmpmap(ulong pa) +{ + ulong *u, *ub, *ue; + void *v; + + if(cankaddr(pa)) + return KADDR(pa); + ub = (ulong *) TMAPL2(m->machno); + ue = ub + NL2; + for(u = ub; u < ue; u++) + if((*u & 3) == 0){ + *u = pa | L2VALID | L2CACHED | L2KERRW; + coherence(); + v = (void *) ((u - ub) * BY2PG + TMAP); + return v; + } + panic("tmpmap: full (pa=%#.8lux)", pa); + return nil; +} + +void +tmpunmap(void *v) +{ + ulong *u; + + if(v >= (void*) KZERO) + return; + if(v < (void*)TMAP || v >= (void*)(TMAP + TMAPSZ)) + panic("tmpunmap: invalid address (va=%#.8lux)", (uintptr) v); + u = (ulong *) TMAPL2(m->machno) + L2X(v); + if((*u & 3) == 0) + panic("tmpunmap: double unmap (va=%#.8lux)", (uintptr) v); + *u = 0; + coherence(); + flushpg(v); +} + +void * +vmap(uintptr pa, ulong sz) +{ + ulong np; + void *vr, *ve; + static ulong *vp = (ulong *) VMAPL2 + 1; /* first page is uart */ + + if((pa & BY2PG - 1) != 0) + panic("vmap: misaligned pa=%#.8lux", pa); + np = (sz + BY2PG - 1) >> PGSHIFT; + vr = (char*) VMAP + (vp - (ulong *)VMAPL2 << PGSHIFT); + ve = (ulong *) (VMAPL2 + VMAPL2SZ); + while(np-- != 0){ + if(vp == ve) + panic("vmap: out of vmap space (pa=%#.8lux)", pa); + *vp++ = pa | L2VALID | L2DEVICE | L2KERRW; + pa += BY2PG; + } + coherence(); + return vr; +} + +/* nasty things happen when there are cache entries for uncached memory + so must make sure memory is not mapped ANYWHERE cached */ +uintptr +ualloc(ulong len, void **va) +{ + static uintptr free = OCM_BASE; + uintptr pa; + + if(len == 0) + panic("ualloc: len == 0"); + len = PGROUND(len); + if(free + len < OCM_BASE) + panic("ualloc: out of uncached memory"); + pa = free; + free += len; + if(va != nil){ + *va = vmap(pa, len); + invaldse(*va, (char *) *va + len); + } + return pa; +} diff --git a/sys/src/9/zynq/screen.c b/sys/src/9/zynq/screen.c new file mode 100644 index 000000000..a3211ffa9 --- /dev/null +++ b/sys/src/9/zynq/screen.c @@ -0,0 +1,126 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define Image IMAGE +#include <draw.h> +#include <memdraw.h> +#include <cursor.h> +#include "screen.h" + +Cursor arrow = { + { -1, -1 }, + { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, + 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, + 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, + 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, + }, + { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, + 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, + 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, + 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, + }, +}; + +Memimage *gscreen; +static Memdata xgdata; + +static Memimage xgscreen = +{ + { 0, 0, 800, 600 }, /* r */ + { 0, 0, 800, 600 }, /* clipr */ + 24, /* depth */ + 3, /* nchan */ + BGR24, /* chan */ + nil, /* cmap */ + &xgdata, /* data */ + 0, /* zero */ + 0, /* width in words of a single scan line */ + 0, /* layer */ + 0, /* flags */ +}; + +void +cursoron(void) +{ +} + +void +cursoroff(void) +{ +} + +void +setcursor(Cursor*) +{ +} + +void +flushmemscreen(Rectangle) +{ +} + +void +drawflushreal(void) +{ + uchar *fb, *fbe; + + fb = xgdata.bdata; + fbe = fb + Dx(xgscreen.r) * Dy(xgscreen.r) * 3; + cleandse(fb, fbe); + clean2pa(PADDR(fb), PADDR(fbe)); +} + +void +screeninit(void) +{ + uchar *fb; + + fb = xspanalloc(Dx(xgscreen.r) * Dy(xgscreen.r) * 3, 64, 0); + print("%x\n", PADDR(fb)); + memsetchan(&xgscreen, BGR24); + conf.monitor = 1; + xgdata.bdata = fb; + xgdata.ref = 1; + gscreen = &xgscreen; + gscreen->width = wordsperline(gscreen->r, gscreen->depth); + + memimageinit(); +} + +uchar* +attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen) +{ + *r = gscreen->r; + *d = gscreen->depth; + *chan = gscreen->chan; + *width = gscreen->width; + *softscreen = 0; + + return gscreen->data->bdata; +} + +void +getcolor(ulong, ulong *, ulong *, ulong *) +{ +} + +int +setcolor(ulong, ulong, ulong, ulong) +{ + return 0; +} + +void +blankscreen(int) +{ +} + +void +mousectl(Cmdbuf *) +{ +} diff --git a/sys/src/9/zynq/screen.h b/sys/src/9/zynq/screen.h new file mode 100644 index 000000000..9c45e3a2f --- /dev/null +++ b/sys/src/9/zynq/screen.h @@ -0,0 +1,44 @@ +typedef struct Cursor Cursor; +typedef struct Cursorinfo Cursorinfo; +struct Cursorinfo { + Cursor; + Lock; +}; + +/* devmouse.c */ +extern void mousetrack(int, int, int, int); +extern void absmousetrack(int, int, int, int); +extern Point mousexy(void); + +extern void mouseaccelerate(int); +extern int m3mouseputc(Queue*, int); +extern int m5mouseputc(Queue*, int); +extern int mouseputc(Queue*, int); + +extern Cursorinfo cursor; +extern Cursor arrow; + +/* mouse.c */ +extern void mousectl(Cmdbuf*); +extern void mouseresize(void); +extern void mouseredraw(void); + +/* screen.c */ +extern void blankscreen(int); +extern void flushmemscreen(Rectangle); +extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*); +extern void cursoron(void); +extern void cursoroff(void); +extern void setcursor(Cursor*); + +/* devdraw.c */ +extern QLock drawlock; + +#define ishwimage(i) 1 /* for ../port/devdraw.c */ + +/* swcursor.c */ +void swcursorhide(void); +void swcursoravoid(Rectangle); +void swcursordraw(Point); +void swcursorload(Cursor *); +void swcursorinit(void); diff --git a/sys/src/9/zynq/timer.c b/sys/src/9/zynq/timer.c new file mode 100644 index 000000000..42211446c --- /dev/null +++ b/sys/src/9/zynq/timer.c @@ -0,0 +1,91 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +enum { + TIMERDIV = 1, + LTIMERDIV = 1, + + ARM_PLL_CTRL = 0x100/4, + ARM_CLK_CTRL = 0x120/4, + + GTIMERVALL = 0x200/4, + GTIMERVALH, + GTIMERCTL, + LTIMERVAL = 0x604/4, + LTIMERCTL, + LTIMERISR, +}; + +uvlong timerhz; + +void +delay(int) +{ +} + +void +microdelay(int) +{ +} + +uvlong +fastticks(uvlong *hz) +{ + ulong lo, hi; + + if(hz != nil) + *hz = timerhz; + do{ + hi = mpcore[GTIMERVALH]; + lo = mpcore[GTIMERVALL]; + }while(hi != mpcore[GTIMERVALH]); + return lo | (uvlong)hi << 32; +} + +ulong +µs(void) +{ + NOPE + return 0; +} + +void +timerset(Tval v) +{ + vlong w; + + w = v - fastticks(nil); + if(w < 1) + w = 1; + if(w > 0xffffffffLL) + w = 0xffffffff; + mpcore[LTIMERCTL] &= ~1; + mpcore[LTIMERVAL] = w; + mpcore[LTIMERCTL] |= 1; +} + +void +timerirq(Ureg *u, void *) +{ + if((mpcore[LTIMERISR] & 1) != 0){ + mpcore[LTIMERISR] |= 1; + timerintr(u, 0); + } +} + +void +timerinit(void) +{ + int mhz; + + mhz = PS_CLK * (slcr[ARM_PLL_CTRL] >> 12 & 0x7f) / (slcr[ARM_CLK_CTRL] >> 8 & 0x3f); + timerhz = mhz * 500000; + mpcore[GTIMERCTL] = TIMERDIV - 1 << 8 | 3; + mpcore[LTIMERCTL] = LTIMERDIV - 1 << 8 | 4; + intrenable(TIMERIRQ, timerirq, nil, EDGE, "clock"); + setpmcr(7); +} diff --git a/sys/src/9/zynq/trap.c b/sys/src/9/zynq/trap.c new file mode 100644 index 000000000..2173bbd8b --- /dev/null +++ b/sys/src/9/zynq/trap.c @@ -0,0 +1,544 @@ +#include "u.h" +#include <ureg.h> +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "tos.h" + +static void +_dumpstack(Ureg *ureg) +{ + uintptr l, v, i, estack; + extern ulong etext; + int x; + char *s; + + if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){ + iprint("dumpstack disabled\n"); + return; + } + iprint("dumpstack\n"); + + x = 0; + x += iprint("ktrace /arm/9zynq %.8lux %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp, ureg->r14); + i = 0; + if(up + && (uintptr)&l >= (uintptr)up->kstack + && (uintptr)&l <= (uintptr)up->kstack+KSTACK) + estack = (uintptr)up->kstack+KSTACK; + else if((uintptr)&l >= (uintptr)m->stack + && (uintptr)&l <= (uintptr)m+MACHSIZE) + estack = (uintptr)m+MACHSIZE; + else + return; + x += iprint("estackx %p\n", estack); + + for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){ + v = *(uintptr*)l; + if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){ + x += iprint("%.8p=%.8p ", l, v); + i++; + } + if(i == 4){ + i = 0; + x += iprint("\n"); + } + } + if(i) + iprint("\n"); + iprint("EOF\n"); +} + +static void +faultarm(Ureg *ureg, ulong fsr, uintptr addr) +{ + int user, insyscall, read, n; + static char buf[ERRMAX]; + + read = (fsr & (1<<11)) == 0; + user = userureg(ureg); + if(!user){ + if(addr >= USTKTOP || up == nil) + _dumpstack(ureg); + if(addr >= USTKTOP) + panic("kernel fault: bad address pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr); + if(up == nil) + panic("kernel fault: no user process pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr); + } + if(up == nil) + panic("user fault: up=nil pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr); + insyscall = up->insyscall; + up->insyscall = 1; + n = fault(addr, read); + if(n < 0){ + if(!user){ + dumpregs(ureg); + _dumpstack(ureg); + panic("kernel fault: pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr); + } + sprint(buf, "sys: trap: fault %s addr=%#.8lux", read ? "read" : "write", addr); + postnote(up, 1, buf, NDebug); + } + up->insyscall = insyscall; +} + +static void +mathtrap(Ureg *, ulong) +{ + if((up->fpstate & FPillegal) != 0){ + postnote(up, 1, "sys: floating point in note handler", NDebug); + return; + } + switch(up->fpstate){ + case FPinit: + fpinit(); + up->fpstate = FPactive; + break; + case FPinactive: + fprestore(&up->fpsave); + up->fpstate = FPactive; + break; + case FPactive: + postnote(up, 1, "sys: floating point error", NDebug); + break; + } +} + +void +trap(Ureg *ureg) +{ + int user; + ulong opc, cp; + + user = userureg(ureg); + if(user){ + if(up == nil) + panic("user trap: up=nil"); + up->dbgreg = ureg; + cycles(&up->kentry); + } + switch(ureg->type){ + case PsrMund: + ureg->pc -= 4; + if(user){ + spllo(); + if(okaddr(ureg->pc, 4, 0)){ + opc = *(ulong*)ureg->pc; + if((opc & 0x0f000000) == 0x0e000000 || (opc & 0x0e000000) == 0x0c000000){ + cp = opc >> 8 & 15; + if(cp == 10 || cp == 11){ + mathtrap(ureg, opc); + break; + } + } + } + postnote(up, 1, "sys: trap: invalid opcode", NDebug); + break; + } + panic("invalid opcode at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14); + break; + case PsrMiabt: + ureg->pc -= 4; + faultarm(ureg, getifsr(), getifar()); + break; + case PsrMabt: + ureg->pc -= 8; + faultarm(ureg, getdfsr(), getdfar()); + break; + case PsrMirq: + ureg->pc -= 4; + intr(ureg); + break; + default: + print("unknown trap type %ulx\n", ureg->type); + } + splhi(); + if(user){ + if(up->procctl || up->nnote) + notify(ureg); + kexit(ureg); + } +} + +#include "../port/systab.h" + +void +syscall(Ureg *ureg) +{ + char *e; + uintptr sp; + long ret; + int i, s; + ulong scallnr; + vlong startns, stopns; + + if(!userureg(ureg)) + panic("syscall: pc=%#.8lux", ureg->pc); + + cycles(&up->kentry); + + m->syscall++; + up->insyscall = 1; + up->pc = ureg->pc; + up->dbgreg = ureg; + + sp = ureg->sp; + up->scallnr = scallnr = ureg->r0; + + spllo(); + + up->nerrlab = 0; + ret = -1; + if(!waserror()){ + if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){ + validaddr(sp, sizeof(Sargs)+BY2WD, 0); + evenaddr(sp); + } + up->s = *((Sargs*) (sp + BY2WD)); + + if(up->procctl == Proc_tracesyscall){ + syscallfmt(scallnr, ureg->pc, (va_list) up->s.args); + s = splhi(); + up->procctl = Proc_stopme; + procctl(up); + splx(s); + startns = todget(nil); + } + + if(scallnr >= nsyscall || systab[scallnr] == 0){ + pprint("bad sys call number %lud pc %lux", scallnr, ureg->pc); + postnote(up, 1, "sys: bad sys call", NDebug); + error(Ebadarg); + } + up->psstate = sysctab[scallnr]; + ret = systab[scallnr]((va_list)up->s.args); + poperror(); + }else{ + e = up->syserrstr; + up->syserrstr = up->errstr; + up->errstr = e; + } + if(up->nerrlab){ + print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab); + for(i = 0; i < NERR; i++) + print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc); + panic("error stack"); + } + + ureg->r0 = ret; + if(up->procctl == Proc_tracesyscall){ + stopns = todget(nil); + sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns); + s = splhi(); + up->procctl = Proc_stopme; + procctl(up); + splx(s); + } + + up->insyscall = 0; + up->psstate = 0; + if(scallnr == NOTED) + noted(ureg, *((ulong *) up->s.args)); + + if(scallnr != RFORK && (up->procctl || up->nnote)){ + splhi(); + notify(ureg); + } + if(up->delaysched) + sched(); + kexit(ureg); + splhi(); +} + +int +notify(Ureg *ureg) +{ + int l; + ulong s, sp; + Note *n; + + if(up->procctl) + procctl(up); + if(up->nnote == 0) + return 0; + + if(up->fpstate == FPactive){ + fpsave(&up->fpsave); + up->fpstate = FPinactive; + } + up->fpstate |= FPillegal; + + s = spllo(); + qlock(&up->debug); + up->notepending = 0; + n = &up->note[0]; + if(strncmp(n->msg, "sys:", 4) == 0){ + l = strlen(n->msg); + if(l > ERRMAX-15) /* " pc=0x12345678\0" */ + l = ERRMAX-15; + sprint(n->msg+l, " pc=0x%.8lux", ureg->pc); + } + + if(n->flag!=NUser && (up->notified || up->notify==0)){ + qunlock(&up->debug); + if(n->flag == NDebug) + pprint("suicide: %s\n", n->msg); + pexit(n->msg, n->flag!=NDebug); + } + + if(up->notified){ + qunlock(&up->debug); + splhi(); + return 0; + } + + if(!up->notify){ + qunlock(&up->debug); + pexit(n->msg, n->flag!=NDebug); + } + sp = ureg->sp; + sp -= 256; /* debugging: preserve context causing problem */ + sp -= sizeof(Ureg); + + if(!okaddr((uintptr)up->notify, 1, 0) + || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1) + || ((uintptr) up->notify & 3) != 0 + || (sp & 3) != 0){ + qunlock(&up->debug); + pprint("suicide: bad address in notify\n"); + pexit("Suicide", 0); + } + + memmove((Ureg*)sp, ureg, sizeof(Ureg)); + *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */ + up->ureg = (void*)sp; + sp -= BY2WD+ERRMAX; + memmove((char*)sp, up->note[0].msg, ERRMAX); + sp -= 3*BY2WD; + *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; + *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg; + ureg->r0 = (uintptr) up->ureg; + ureg->sp = sp; + ureg->pc = (uintptr) up->notify; + ureg->r14 = 0; + up->notified = 1; + up->nnote--; + memmove(&up->lastnote, &up->note[0], sizeof(Note)); + memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); + + qunlock(&up->debug); + splx(s); + return 1; +} + +void +noted(Ureg *ureg, ulong arg0) +{ + Ureg *nureg; + ulong oureg, sp; + + qlock(&up->debug); + if(arg0 != NRSTR && !up->notified){ + qunlock(&up->debug); + pprint("call to noted() when not notified\n"); + pexit("Suicide", 0); + } + up->notified = 0; + + nureg = up->ureg; + up->fpstate &= ~FPillegal; + + oureg = (ulong) nureg; + if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){ + qunlock(&up->debug); + pprint("bad ureg in noted or call to noted when not notified\n"); + pexit("Suicide", 0); + } + + nureg->psr = nureg->psr & 0xf80f0000 | ureg->psr & 0x07f0ffff; + + memmove(ureg, nureg, sizeof(Ureg)); + + switch(arg0){ + case NCONT: case NRSTR: + if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) || + (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){ + qunlock(&up->debug); + pprint("suicide: trap in noted\n"); + pexit("Suicide", 0); + } + up->ureg = (Ureg *) (*(ulong *) (oureg - BY2WD)); + qunlock(&up->debug); + break; + + case NSAVE: + if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) || + (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){ + qunlock(&up->debug); + pprint("suicide: trap in noted\n"); + pexit("Suicide", 0); + } + qunlock(&up->debug); + sp = oureg - 4 * BY2WD - ERRMAX; + splhi(); + ureg->sp = sp; + ((ulong *) sp)[1] = oureg; + ((ulong *) sp)[0] = 0; + break; + + default: + up->lastnote.flag = NDebug; + + case NDFLT: + qunlock(&up->debug); + if(up->lastnote.flag == NDebug) + pprint("suicide: %s\n", up->lastnote.msg); + pexit(up->lastnote.msg, up->lastnote.flag != NDebug); + } +} + + +void +dumpstack(void) +{ + callwithureg(_dumpstack); +} + +void +dumpregs(Ureg *) +{ + print("dumpregs\n"); +} + +void +setkernur(Ureg *ureg, Proc *p) +{ + ureg->pc = p->sched.pc; + ureg->sp = p->sched.sp + 4; + ureg->r14 = (uintptr) sched; +} + +void +setregisters(Ureg* ureg, char* pureg, char* uva, int n) +{ + ulong v; + + v = ureg->psr; + memmove(pureg, uva, n); + ureg->psr = ureg->psr & 0xf80f0000 | v & 0x07f0ffff; +} + +void +callwithureg(void (*f) (Ureg *)) +{ + Ureg u; + + u.pc = getcallerpc(&f); + u.sp = (uintptr) &f - 4; + f(&u); +} + +uintptr +userpc(void) +{ + Ureg *ur; + + ur = up->dbgreg; + return ur->pc; +} + +uintptr +dbgpc(Proc *) +{ + Ureg *ur; + + ur = up->dbgreg; + if(ur == nil) + return 0; + return ur->pc; +} + +void +procsave(Proc *p) +{ + uvlong t; + + if(p->fpstate == FPactive){ + if(p->state == Moribund) + fpclear(); + else + fpsave(&p->fpsave); + p->fpstate = FPinactive; + } + cycles(&t); + p->kentry -= t; + p->pcycles += t; + + l1switch(&m->l1, 0); +} + +void +procrestore(Proc *p) +{ + uvlong t; + + if(p->kp) + return; + + cycles(&t); + p->kentry += t; + p->pcycles -= t; +} + +static void +linkproc(void) +{ + spllo(); + up->kpfun(up->kparg); + pexit("kproc dying", 0); +} + +void +kprocchild(Proc* p, void (*func)(void*), void* arg) +{ + p->sched.pc = (uintptr) linkproc; + p->sched.sp = (uintptr) p->kstack + KSTACK; + + p->kpfun = func; + p->kparg = arg; +} + +void +forkchild(Proc *p, Ureg *ureg) +{ + Ureg *cureg; + + p->sched.pc = (uintptr) forkret; + p->sched.sp = (uintptr) p->kstack + KSTACK - sizeof(Ureg); + + cureg = (Ureg*) p->sched.sp; + memmove(cureg, ureg, sizeof(Ureg)); + cureg->r0 = 0; + + p->psstate = 0; + p->insyscall = 0; +} + +uintptr +execregs(uintptr entry, ulong ssize, ulong nargs) +{ + ulong *sp; + Ureg *ureg; + + sp = (ulong*)(USTKTOP - ssize); + *--sp = nargs; + + ureg = up->dbgreg; + ureg->sp = (uintptr) sp; + ureg->pc = entry; + ureg->r14 = 0; + return USTKTOP-sizeof(Tos); +} diff --git a/sys/src/9/zynq/uartzynq.c b/sys/src/9/zynq/uartzynq.c new file mode 100644 index 000000000..81bc31569 --- /dev/null +++ b/sys/src/9/zynq/uartzynq.c @@ -0,0 +1,244 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +enum { + CTRL = 0, + MODE, + IRQEN, + IRQDIS, + MASK, + INTSTAT, + RXFIFOLVL = 0x20/4, + CHANSTAT = 0x2C/4, + FIFO = 0x30/4, +}; + +enum { + TXFULL = 1<<4, + TXEMPTY = 1<<3, + RXEMPTY = 1<<1, + RXTRIG = 1<<0, +}; + +typedef struct Ctlr { + Lock; + ulong *r; + int irq, iena; +} Ctlr; + +Uart* uartenable(Uart *); + +extern PhysUart zynqphysuart; + +static Ctlr zctlr[1] = { + { + .r = (void *) VMAP, + .irq = UART1IRQ, + } +}; + +static Uart zuart[1] = { + { + .regs = &zctlr[0], + .name = "UART1", + .freq = 25000000, + .phys = &zynqphysuart, + .console = 1, + .baud = 115200, + } +}; + +void +uartinit(void) +{ + consuart = zuart; +} + +static Uart * +zuartpnp(void) +{ + return zuart; +} + +static void +zuartkick(Uart *uart) +{ + Ctlr *ct; + int i; + + if(uart->blocked) + return; + ct = uart->regs; + for(i = 0; i < 128; i++){ + if((ct->r[CHANSTAT] & TXFULL) != 0) + break; + if(uart->op >= uart->oe && uartstageoutput(uart) == 0) + break; + ct->r[FIFO] = *uart->op++; + } +} + +static void +zuartintr(Ureg *, void *arg) +{ + Uart *uart; + Ctlr *ct; + int c; + ulong fl; + + uart = arg; + ct = uart->regs; + fl = ct->r[INTSTAT] & ct->r[MASK]; + ct->r[INTSTAT] = fl; + if((fl & RXTRIG) != 0) + while((ct->r[CHANSTAT] & RXEMPTY) == 0){ + c = ct->r[FIFO]; + uartrecv(uart, c); + } + if((fl & TXEMPTY) != 0) + zuartkick(uart); +} + +static void +zuartenable(Uart *uart, int ie) +{ + Ctlr *ctlr; + + ctlr = uart->regs; + ilock(ctlr); + while((ctlr->r[CHANSTAT] & TXEMPTY) == 0) + ; + ctlr->r[IRQDIS] = -1; + ctlr->r[RXFIFOLVL] = 1; + if(ie){ + if(!ctlr->iena){ + intrenable(ctlr->irq, zuartintr, uart, LEVEL, uart->name); + ctlr->iena = 1; + } + ctlr->r[IRQEN] = RXTRIG | TXEMPTY; + } + iunlock(ctlr); +} + +static int +zuartgetc(Uart *uart) +{ + Ctlr *c; + + c = uart->regs; + while((c->r[CHANSTAT] & RXEMPTY) != 0) + ; + return c->r[FIFO]; +} + +static void +zuartputc(Uart *uart, int c) +{ + Ctlr *ct; + + ct = uart->regs; + while((ct->r[CHANSTAT] & TXFULL) != 0) + ; + ct->r[FIFO] = c; + return; +} + +int +uartconsole(void) +{ + Uart *uart = zuart; + + if(up == nil) + return -1; + + if(uartenable(uart) != nil){ + serialoq = uart->oq; + uart->opens++; + consuart = uart; + } + return 0; +} + +int +zuartbits(Uart *uart, int n) +{ + Ctlr *ct; + + ct = uart->regs; + ct->r[MODE] &= ~6; + switch(n){ + case 8: + return 0; + case 7: + ct->r[MODE] |= 4; + return 0; + case 6: + ct->r[MODE] |= 6; + return 0; + default: + return -1; + } +} + +int +zuartbaud(Uart *, int n) +{ + print("uart baud %d\n", n); + return 0; +} + +int +zuartparity(Uart *uart, int p) +{ + Ctlr *ct; + + ct = uart->regs; + switch(p){ + case 'o': + ct->r[MODE] = ct->r[MODE] & ~0x38 | 0x08; + return 0; + case 'e': + ct->r[MODE] = ct->r[MODE] & ~0x38; + return 0; + case 'n': + ct->r[MODE] = ct->r[MODE] & 0x38 | 0x20; + return 0; + default: + return -1; + } +} + +void +zuartnop(Uart *, int) +{ +} + +int +zuartnope(Uart *, int) +{ + return -1; +} + + +PhysUart zynqphysuart = { + .pnp = zuartpnp, + .enable = zuartenable, + .kick = zuartkick, + .getc = zuartgetc, + .putc = zuartputc, + .bits = zuartbits, + .baud = zuartbaud, + .parity = zuartparity, + + .stop = zuartnope, + .rts = zuartnop, + .dtr = zuartnop, + .dobreak = zuartnop, + .fifo = zuartnop, + .power = zuartnop, + .modemctl = zuartnop, +}; diff --git a/sys/src/9/zynq/uncached.h b/sys/src/9/zynq/uncached.h new file mode 100644 index 000000000..0a7b50883 --- /dev/null +++ b/sys/src/9/zynq/uncached.h @@ -0,0 +1,27 @@ +#define free ucfree +#define malloc myucalloc +#define mallocz ucallocz +#define smalloc myucalloc +#define xspanalloc ucallocalign + +#define allocb ucallocb +#define iallocb uciallocb +#define freeb ucfreeb + +static void * +ucallocz(uint n, int) +{ + char *p = ucalloc(n); + + if (p) + memset(p, 0, n); + else + panic("ucalloc: out of memory"); + return p; +} + +static void * +myucalloc(uint n) +{ + return ucallocz(n, 1); +} diff --git a/sys/src/9/zynq/usbehci.h b/sys/src/9/zynq/usbehci.h new file mode 100644 index 000000000..2c71d12bc --- /dev/null +++ b/sys/src/9/zynq/usbehci.h @@ -0,0 +1,141 @@ +/* override default macros from ../port/usb.h */ +#undef dprint +#undef ddprint +#undef deprint +#undef ddeprint +#define dprint if(ehcidebug)print +#define ddprint if(ehcidebug>1)print +#define deprint if(ehcidebug || ep->debug)print +#define ddeprint if(ehcidebug>1 || ep->debug>1)print + +enum { + /* typed links */ + Lterm = 1, + Litd = 0<<1, + Lqh = 1<<1, + Lsitd = 2<<1, + Lfstn = 3<<1, /* we don't use these */ + + /* Cmd reg. */ + Cstop = 0x00000, /* stop running */ + Crun = 0x00001, /* start operation */ + Chcreset = 0x00002, /* host controller reset */ + Cflsmask = 0x0000C, /* frame list size bits */ + Cfls1024 = 0x00000, /* frame list size 1024 */ + Cfls512 = 0x00004, /* frame list size 512 frames */ + Cfls256 = 0x00008, /* frame list size 256 frames */ + Cpse = 0x00010, /* periodic sched. enable */ + Case = 0x00020, /* async sched. enable */ + Ciasync = 0x00040, /* interrupt on async advance doorbell */ + Citc1 = 0x10000, /* interrupt threshold ctl. 1 µframe */ + Citc4 = 0x40000, /* same. 2 µframes */ + /* ... */ + Citc8 = 0x80000, /* same. 8 µframes (can go up to 64) */ + + /* Sts reg. */ + Sasyncss = 0x08000, /* aync schedule status */ + Speriodss = 0x04000, /* periodic schedule status */ + Srecl = 0x02000, /* reclamnation (empty async sched.) */ + Shalted = 0x01000, /* h.c. is halted */ + Sasync = 0x00020, /* interrupt on async advance */ + Sherr = 0x00010, /* host system error */ + Sfrroll = 0x00008, /* frame list roll over */ + Sportchg = 0x00004, /* port change detect */ + Serrintr = 0x00002, /* error interrupt */ + Sintr = 0x00001, /* interrupt */ + Sintrs = 0x0003F, /* interrupts status */ + + /* Portsc reg. */ + Pspresent = 0x00000001, /* device present */ + Psstatuschg = 0x00000002, /* Pspresent changed */ + Psenable = 0x00000004, /* device enabled */ + Pschange = 0x00000008, /* Psenable changed */ + Psresume = 0x00000040, /* resume detected */ + Pssuspend = 0x00000080, /* port suspended */ + Psreset = 0x00000100, /* port reset */ + Pspower = 0x00001000, /* port power on */ + + /* Intr reg. */ + Iusb = 0x01, /* intr. on usb */ + Ierr = 0x02, /* intr. on usb error */ + Iportchg = 0x04, /* intr. on port change */ + Ifrroll = 0x08, /* intr. on frlist roll over */ + Ihcerr = 0x10, /* intr. on host error */ + Iasync = 0x20, /* intr. on async advance enable */ + Iall = 0x3F, /* all interrupts */ + + Callmine = 1, + + /* hack to disable port handoff */ + Psowner = 0, + Pslinemask = 0, + Pslow = -1 +}; + +typedef struct Ctlr Ctlr; +typedef void Ecapio; +typedef struct Eopio Eopio; +typedef struct Isoio Isoio; +typedef struct Poll Poll; +typedef struct Qh Qh; +typedef struct Qtree Qtree; + +#pragma incomplete Ctlr + +struct Eopio +{ + ulong cmd; + ulong sts; + ulong intr; + ulong frno; + ulong dummy1[2]; + ulong frbase; + ulong link; + ulong dummy2[9]; + ulong config; + ulong portsc[1]; +}; + +struct Poll +{ + Lock; + Rendez; + int must; + int does; +}; + +struct Ctlr +{ + Rendez; /* for waiting to async advance doorbell */ + Lock; /* for ilock. qh lists and basic ctlr I/O */ + QLock portlck; /* for port resets/enable... (and doorbell) */ + int active; /* in use or not */ + void* capio; /* base address for debug info */ + Eopio* opio; /* Operational i/o regs */ + + int nframes; /* 1024, 512, or 256 frames in the list */ + ulong* frames; /* periodic frame list (hw) */ + Qh* qhs; /* async Qh circular list for bulk/ctl */ + Qtree* tree; /* tree of Qhs for the periodic list */ + int ntree; /* number of dummy qhs in tree */ + Qh* intrqhs; /* list of (not dummy) qhs in tree */ + Isoio* iso; /* list of active Iso I/O */ + ulong load; + ulong isoload; + int nintr; /* number of interrupts attended */ + int ntdintr; /* number of intrs. with something to do */ + int nqhintr; /* number of async td intrs. */ + int nisointr; /* number of periodic td intrs. */ + int nreqs; + Poll poll; + + ulong base; + int irq; + ulong* r; +}; + +extern int ehcidebug; + +void ehcilinkage(Hci *hp); +void ehcimeminit(Ctlr *ctlr); +void ehcirun(Ctlr *ctlr, int on); diff --git a/sys/src/9/zynq/usbehcizynq.c b/sys/src/9/zynq/usbehcizynq.c new file mode 100644 index 000000000..e233fb429 --- /dev/null +++ b/sys/src/9/zynq/usbehcizynq.c @@ -0,0 +1,103 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +#include "../port/usb.h" +#include "usbehci.h" + +enum { + USBMODE = 0x1A8/4, + USBHOST = 3, + OTGSC = 0x1A4/4, + ULPI = 0x170/4, +}; + +static Ctlr ctlrs[3] = { + { + .base = USB0_BASE, + .irq = USB0IRQ, + }, + { + .base = USB1_BASE, + .irq = USB1IRQ, + }, +}; + +static void +ehcireset(Ctlr *ctlr) +{ + int i; + Eopio *opio; + + ilock(ctlr); + opio = ctlr->opio; + ehcirun(ctlr, 0); + opio->cmd |= Chcreset; + for(i = 0; i < 100; i++){ + if((opio->cmd & Chcreset) == 0) + break; + delay(1); + } + if(i == 100) + print("ehci %#p controller reset timed out\n", ctlr->base); + opio->cmd |= Citc1; + switch(opio->cmd & Cflsmask){ + case Cfls1024: + ctlr->nframes = 1024; + break; + case Cfls512: + ctlr->nframes = 512; + break; + case Cfls256: + ctlr->nframes = 256; + break; + default: + panic("ehci: unknown fls %ld", opio->cmd & Cflsmask); + } + dprint("ehci: %d frames\n", ctlr->nframes); + iunlock(ctlr); +} + +static int +reset(Hci *hp) +{ + static Lock resetlck; + Ctlr *ctlr; + + ilock(&resetlck); + for(ctlr = ctlrs; ctlr->base != 0; ctlr++) + if(!ctlr->active && (hp->port == 0 || hp->port == ctlr->base)){ + ctlr->active = 1; + break; + } + iunlock(&resetlck); + if(ctlr->base == 0) + return -1; + hp->port = ctlr->base; + hp->irq = ctlr->irq; + hp->aux = ctlr; + + ctlr->r = vmap(ctlr->base, 0x1F0); + ctlr->opio = (Eopio *) ((uchar *) ctlr->r + 0x140); + ctlr->capio = (void *) ctlr->base; + hp->nports = 1; + ctlr->r[USBMODE] |= USBHOST; + + ehcireset(ctlr); + ehcimeminit(ctlr); + ehcilinkage(hp); + ctlr->r[ULPI] = 1<<30 | 1<<29 | 0x0B << 16 | 3<<5; + if(hp->interrupt != nil) + intrenable(hp->irq, hp->interrupt, hp, LEVEL, hp->type); + return 0; +} + +void +usbehcilink(void) +{ + ehcidebug = 2; + addhcitype("ehci", reset); +} diff --git a/sys/src/9/zynq/zynq b/sys/src/9/zynq/zynq new file mode 100644 index 000000000..c769920f3 --- /dev/null +++ b/sys/src/9/zynq/zynq @@ -0,0 +1,56 @@ +dev + root + cons + arch + uart + mnt + srv + shr + proc + env + pipe + dup + ether netif + ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno + ssl + tls + cap + kprof + fs + qspi + draw screen + mouse + usb + +link + etherzynq + ethermedium + loopbackmedium + usbehci usbehcizynq + +misc + uartzynq + +ip + tcp + udp + rudp + ipifc + icmp + icmp6 + gre + ipmux + esp + +port + int cpuserver = 0; + +boot boot + tcp + local + +bootdir + boot$CONF.out boot + /$objtype/bin/paqfs + /$objtype/bin/auth/factotum + bootfs.paq diff --git a/sys/src/boot/zynq/boothead.c b/sys/src/boot/zynq/boothead.c new file mode 100644 index 000000000..98aed00c7 --- /dev/null +++ b/sys/src/boot/zynq/boothead.c @@ -0,0 +1,71 @@ +#include <u.h> +#include <libc.h> + +char *data; +uchar head[0x8c0]; + +void +usage(void) +{ + fprint(2, "usage: %s file\n", argv0); + exits("usage"); +} + +void +u32(int n, u32int p) +{ + head[n] = p; + head[n+1] = p >> 8; + head[n+2] = p >> 16; + head[n+3] = p >> 24; +} + +u32int +gu32(int n) +{ + return head[n] | head[n+1] << 8 | head[n+2] << 16 | head[n+3] << 24; +} + +void +main(int argc, char **argv) +{ + int fd, sz, i; + u32int ck; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if(argc != 1) + usage(); + fd = open(argv[0], OREAD); + if(fd < 0) + sysfatal("open: %r"); + sz = seek(fd, 0, 2); + if(sz < 0) + sysfatal("seek: %r"); + data = malloc(sz); + if(data == nil) + sysfatal("malloc: %r"); + seek(fd, 0, 0); + if(readn(fd, data, sz) < sz) + sysfatal("read: %r"); + close(fd); + memset(head, 0, sizeof(head)); + + u32(0x20, 0xaa995566); + u32(0x24, 0x584C4E58); + u32(0x30, sizeof(head)); + u32(0x34, sz); + u32(0x40, sz); + ck = 0; + for(i = 0x20; i < 0x48; i += 4) + ck += gu32(i); + u32(0x48, ~ck); + u32(0xa0, -1); + + write(1, head, sizeof(head)); + write(1, data, sz); + exits(nil); +} diff --git a/sys/src/boot/zynq/dat.h b/sys/src/boot/zynq/dat.h new file mode 100644 index 000000000..81cb90749 --- /dev/null +++ b/sys/src/boot/zynq/dat.h @@ -0,0 +1,11 @@ +enum { + DHCPTIMEOUT = 2000, + ARPTIMEOUT = 1000, + TFTPTIMEOUT = 10000, + + TZERO = 0x80000, + CONFSIZE = 65536, + CONF = TZERO - CONFSIZE, +}; + +#define nelem(x) (sizeof(x)/sizeof(*(x))) diff --git a/sys/src/boot/zynq/ddr.s b/sys/src/boot/zynq/ddr.s new file mode 100644 index 000000000..28686f702 --- /dev/null +++ b/sys/src/boot/zynq/ddr.s @@ -0,0 +1,258 @@ +#define OUTPUT_EN (3<<9) +#define DCI_EN (7<<4) +#define INP_VREF (1<<1) +#define INP_DIFF (2<<1) + +TEXT ddriob(SB), $-4 + WORD $(OUTPUT_EN) // DDRIOB_ADDR0 + WORD $(OUTPUT_EN) // DDRIOB_ADDR1 + WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA0 + WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA1 + WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF0 + WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF1 + WORD $(OUTPUT_EN) // DDRIOB_CLOCK + WORD $0x0018C61C // DDRIOB_DRIVE_SLEW_ADDR + WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DATA + WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DIFF + WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_CLOCK + WORD $0xE60 // DDRIOB_DDR_CTRL + +TEXT ddrdata(SB), $-4 + WORD $0XF8006000 + WORD $0x0001FFFF + WORD $0x00000080 + WORD $0XF8006004 + WORD $0x1FFFFFFF + WORD $0x00081081 + WORD $0XF8006008 + WORD $0x03FFFFFF + WORD $0x03C0780F + WORD $0XF800600C + WORD $0x03FFFFFF + WORD $0x02001001 + WORD $0XF8006010 + WORD $0x03FFFFFF + WORD $0x00014001 + WORD $0XF8006014 + WORD $0x001FFFFF + WORD $0x0004281A + WORD $0XF8006018 + WORD $0xF7FFFFFF + WORD $0x44E458D2 + WORD $0XF800601C + WORD $0xFFFFFFFF + WORD $0x82023965 + WORD $0XF8006020 + WORD $0xFFFFFFFC + WORD $0x2B288290 + WORD $0XF8006024 + WORD $0x0FFFFFFF + WORD $0x0000003C + WORD $0XF8006028 + WORD $0x00003FFF + WORD $0x00002007 + WORD $0XF800602C + WORD $0xFFFFFFFF + WORD $0x00000008 + WORD $0XF8006030 + WORD $0xFFFFFFFF + WORD $0x00040970 + WORD $0XF8006034 + WORD $0x13FF3FFF + WORD $0x00011054 + WORD $0XF8006038 + WORD $0x00001FC3 + WORD $0x00000000 + WORD $0XF800603C + WORD $0x000FFFFF + WORD $0x00000777 + WORD $0XF8006040 + WORD $0xFFFFFFFF + WORD $0xFFF00000 + WORD $0XF8006044 + WORD $0x0FFFFFFF + WORD $0x0F666666 + WORD $0XF8006048 + WORD $0x3FFFFFFF + WORD $0x0003C248 + WORD $0XF8006050 + WORD $0xFF0F8FFF + WORD $0x77010800 + WORD $0XF8006058 + WORD $0x0001FFFF + WORD $0x00000101 + WORD $0XF800605C + WORD $0x0000FFFF + WORD $0x00005003 + WORD $0XF8006060 + WORD $0x000017FF + WORD $0x0000003E + WORD $0XF8006064 + WORD $0x00021FE0 + WORD $0x00020000 + WORD $0XF8006068 + WORD $0x03FFFFFF + WORD $0x00284545 + WORD $0XF800606C + WORD $0x0000FFFF + WORD $0x00001610 + WORD $0XF80060A0 + WORD $0x00FFFFFF + WORD $0x00008000 + WORD $0XF80060A4 + WORD $0xFFFFFFFF + WORD $0x10200802 + WORD $0XF80060A8 + WORD $0x0FFFFFFF + WORD $0x0690CB73 + WORD $0XF80060AC + WORD $0x000001FF + WORD $0x000001FE + WORD $0XF80060B0 + WORD $0x1FFFFFFF + WORD $0x04FFFFFF + WORD $0XF80060B4 + WORD $0x000007FF + WORD $0x00000200 + WORD $0XF80060B8 + WORD $0x01FFFFFF + WORD $0x0020006A + WORD $0XF80060C4 + WORD $0x00000003 + WORD $0x00000003 + WORD $0XF80060C4 + WORD $0x00000003 + WORD $0x00000000 + WORD $0XF80060C8 + WORD $0x000000FF + WORD $0x00000000 + WORD $0XF80060DC + WORD $0x00000001 + WORD $0x00000000 + WORD $0XF80060F0 + WORD $0x0000FFFF + WORD $0x00000000 + WORD $0XF80060F4 + WORD $0x0000000F + WORD $0x00000008 + WORD $0XF8006114 + WORD $0x000000FF + WORD $0x00000000 + WORD $0XF8006118 + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF800611C + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF8006120 + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF8006124 + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF800612C + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006130 + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006134 + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006138 + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006140 + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF8006144 + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF8006148 + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF800614C + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF8006154 + WORD $0x000FFFFF + WORD $0x00000080 + WORD $0XF8006158 + WORD $0x000FFFFF + WORD $0x00000080 + WORD $0XF800615C + WORD $0x000FFFFF + WORD $0x00000080 + WORD $0XF8006160 + WORD $0x000FFFFF + WORD $0x00000075 + WORD $0XF8006168 + WORD $0x001FFFFF + WORD $0x000000EE + WORD $0XF800616C + WORD $0x001FFFFF + WORD $0x000000E4 + WORD $0XF8006170 + WORD $0x001FFFFF + WORD $0x000000FC + WORD $0XF8006174 + WORD $0x001FFFFF + WORD $0x000000F4 + WORD $0XF800617C + WORD $0x000FFFFF + WORD $0x000000C0 + WORD $0XF8006180 + WORD $0x000FFFFF + WORD $0x000000C0 + WORD $0XF8006184 + WORD $0x000FFFFF + WORD $0x000000C0 + WORD $0XF8006188 + WORD $0x000FFFFF + WORD $0x000000B5 + WORD $0XF8006190 + WORD $0xFFFFFFFF + WORD $0x10040080 + WORD $0XF8006194 + WORD $0x000FFFFF + WORD $0x00007D02 + WORD $0XF8006204 + WORD $0xFFFFFFFF + WORD $0x00000000 + WORD $0XF8006208 + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF800620C + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF8006210 + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF8006214 + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF8006218 + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF800621C + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF8006220 + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF8006224 + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF80062A8 + WORD $0x00000FF7 + WORD $0x00000000 + WORD $0XF80062AC + WORD $0xFFFFFFFF + WORD $0x00000000 + WORD $0XF80062B0 + WORD $0x003FFFFF + WORD $0x00005125 + WORD $0xF80062B4 + WORD $0x003FFFFF + WORD $0x000012A8 + WORD $0 diff --git a/sys/src/boot/zynq/fns.h b/sys/src/boot/zynq/fns.h new file mode 100644 index 000000000..48f0a3ff9 --- /dev/null +++ b/sys/src/boot/zynq/fns.h @@ -0,0 +1,13 @@ +void putc(int); +void puts(char *); +int netboot(void); +void puthex(u32int); +void memset(void *, char, int); +void memcpy(void *, void *, int); +void print(char *, ...); +u32int u32get(void *); +void jump(void *); +void sleep(int); +void timeren(int); +int timertrig(void); +void flash(void); diff --git a/sys/src/boot/zynq/fsbl.s b/sys/src/boot/zynq/fsbl.s new file mode 100644 index 000000000..4923cdf52 --- /dev/null +++ b/sys/src/boot/zynq/fsbl.s @@ -0,0 +1,310 @@ +#include "mem.h" + +#define Rb R10 +#define SET(R, V) MOVW $(V), R0 ; MOVW R0, (R)(Rb) +#define RMW(r, m, v) MOVW (r)(Rb), R0; BIC $(m), R0; ORR $(v), R0; MOVW R0, (r)(Rb) + +TEXT _start(SB), $-4 + WORD $0xea000006 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + +TEXT reloc(SB), $-4 + MOVW $(1<<7|1<<6|0x13), R0 + MOVW R0, CPSR + MOVW $STACKTOP, R13 + MOVW $_start(SB), R0 + MCR CpMMU, 0, R0, C(12), C(0) + MOVW $SLCR_BASE, Rb + SET(SLCR_UNLOCK, UNLOCK_KEY) + MOVW $0, R0 + MCR 15, 0, R0, C(8), C(7), 0 + MCR 15, 0, R0, C(7), C(5), 0 + MCR 15, 0, R0, C(7), C(5), 6 + MOVW $0xc5047a, R1 + MCR 15, 0, R1, C(1), C(0), 0 + DSB + ISB + CMP.S $0, R15 + BL.LT reset(SB) + + MOVW $0xf, R1 + MOVW $0xffff0000, R3 + MOVW $0xe58a1910, R0 + MOVW R0, (R3) + MOVW $0xf57ff04f, R0 + MOVW R0, 4(R3) + MOVW $0xf57ff06f, R0 + MOVW R0, 8(R3) + MOVW $0xe28ef000, R0 + MOVW R0, 12(R3) + MOVW $reset(SB), R14 + DSB + ISB + MOVW R3, R15 + +TEXT reset(SB), $-4 + BL pllsetup(SB) + BL miosetup(SB) + BL ddrsetup(SB) + BL uartsetup(SB) + MOVW $SLCR_BASE, Rb + SET(SLCR_LOCK, LOCK_KEY) +// BL memtest(SB) + MOVW $setR12(SB), R12 + BL main(SB) + B abort(SB) + +TEXT pllsetup(SB), $0 + MOVW $SLCR_BASE, Rb + + SET(ARM_PLL_CFG, ARM_PLL_CFG_VAL) + SET(DDR_PLL_CFG, DDR_PLL_CFG_VAL) + SET(IO_PLL_CFG, IO_PLL_CFG_VAL) + + MOVW $(ARM_FDIV | PLL_BYPASS_FORCE), R0 + MOVW R0, ARM_PLL_CTRL(Rb) + ORR $(PLL_RESET), R4 + MOVW R4, ARM_PLL_CTRL(Rb) + MOVW R0, ARM_PLL_CTRL(Rb) + + MOVW $(DDR_FDIV | PLL_BYPASS_FORCE), R0 + MOVW R0, DDR_PLL_CTRL(Rb) + ORR $(PLL_RESET), R4 + MOVW R4, DDR_PLL_CTRL(Rb) + MOVW R0, DDR_PLL_CTRL(Rb) + + MOVW $(IO_FDIV | PLL_BYPASS_FORCE), R0 + MOVW R0, IO_PLL_CTRL(Rb) + ORR $(PLL_RESET), R4 + MOVW R4, IO_PLL_CTRL(Rb) + MOVW R0, IO_PLL_CTRL(Rb) + +_pllsetupl: + MOVW PLL_STATUS(Rb), R0 + AND $7, R0 + CMP.S $7, R0 + BNE _pllsetupl + + SET(ARM_PLL_CTRL, ARM_FDIV) + SET(DDR_PLL_CTRL, DDR_FDIV) + SET(IO_PLL_CTRL, IO_FDIV) + + SET(ARM_CLK_CTRL, 0x1f << 24 | CPU_DIV << 8) + SET(UART_CLK_CTRL, UART_DIV << 8 | 3) + SET(DDR_CLK_CTRL, DDR_DIV3 << 20 | DDR_DIV2 << 26 | 3) + SET(DCI_CLK_CTRL, DCI_DIV0 << 8 | DCI_DIV1 << 20 | 1) + SET(GEM0_RCLK_CTRL, 1) + SET(GEM1_RCLK_CTRL, 0) + SET(GEM0_CLK_CTRL, ETH_DIV0 << 8 | ETH_DIV1 << 20 | 1) + SET(GEM1_CLK_CTRL, 0) + SET(GPIOB_CTRL, VREF_SW_EN) + SET(APER_CLK_CTRL, LQSPI_CLK_EN | GPIO_CLK_EN | UART0_CLK_EN | UART1_CLK_EN | I2C0_CLK_EN | SDIO1_CLK_EN | GEM0_CLK_EN | USB0_CLK_EN | USB1_CLK_EN | DMA_CLK_EN) + SET(SMC_CLK_CTRL, 0x3C20) + SET(LQSPI_CLK_CTRL, QSPI_DIV << 8 | 1) + SET(SDIO_CLK_CTRL, SDIO_DIV << 8 | 2) + SET(SPI_CLK_CTRL, 0x3F00) + SET(CAN_CLK_CTRL, 0x501900) + SET(PCAP_CLK_CTRL, PCAP_DIV << 8 | 1) + RET + +TEXT miosetup(SB), $0 + MOVW $SLCR_BASE, Rb + SET(UART_RST_CTRL, 0xf) + SET(UART_RST_CTRL, 0) + + MOVW $miodata(SB), R1 + ADD $MIO_PIN_0, Rb, R2 + MOVW $54, R3 + BL copy(SB) + + MOVW $0, R0 + MOVW R0, MIO_MST_TRI0(Rb) + MOVW R0, MIO_MST_TRI1(Rb) + RET + +TEXT copy(SB), $0 +_copyl: + MOVW.P 4(R1), R0 + MOVW.P R0, 4(R2) + SUB.S $1, R3 + BNE _copyl + RET + +TEXT ddrsetup(SB), $0 + MOVW $SLCR_BASE, Rb + RMW(DDRIOB_DCI_CTRL, DCI_RESET, DCI_RESET) + RMW(DDRIOB_DCI_CTRL, DCI_RESET, 0) + RMW(DDRIOB_DCI_CTRL, DDRIOB_DCI_CTRL_MASK, DCI_NREF | DCI_ENABLE | DCI_RESET) + + MOVW $ddriob(SB), R1 + ADD $DDRIOB_ADDR0, Rb, R2 + MOVW $12, R3 + BL copy(SB) + + MOVW $ddrdata(SB), R1 +_ddrl1: + MOVW.P 4(R1), R2 + ORR.S $0, R2 + BEQ _ddrl2 + MOVW.P 4(R1), R3 + MOVW.P 4(R1), R4 + AND R3, R4 + MOVW (R2), R0 + BIC R3, R0 + ORR R4, R0 + MOVW R0, (R2) + B _ddrl1 +_ddrl2: + MOVW DDRIOB_DCI_STATUS(Rb), R0 + AND.S $(1<<13), R0 + BEQ _ddrl2 + MOVW $DDR_BASE, Rb + RMW(DDRC_CTRL, 0x1ffff, 0x81) +_ddrl4: + MOVW DDR_MODE_STS(Rb), R0 + AND.S $7, R0 + BEQ _ddrl4 + + MOVW $MP_BASE, Rb + SET(FILTER_START, 0) + RET + +TEXT memtest(SB), $0 + MOVW $0, R0 + ADD $(1024 * 1024 * 10), R0, R1 +_testl: + MOVW R0, (R0) + ADD $4, R0 + CMP.S R0, R1 + BNE _testl + MOVW $0, R0 +_testl2: + MOVW (R0), R2 + CMP.S R0, R2 + BNE _no + ADD $4, R0 + CMP.S R0, R1 + BNE _testl2 + MOVW $'.', R0 + BL putc(SB) + RET +_no: + MOVW $'!', R0 + BL putc(SB) + RET + +TEXT uartsetup(SB), $0 + MOVW $UART1_BASE, Rb + SET(UART_CTRL, 0x17) + SET(UART_MODE, 0x20) + SET(UART_SAMP, 15) + SET(UART_BAUD, 14) + RET + +TEXT putc(SB), $0 + MOVW $UART1_BASE, Rb + CMP.S $10, R0 + BNE _putcl + MOVW R0, R2 + MOVW $13, R0 + BL putc(SB) + MOVW R2, R0 +_putcl: + MOVW UART_STAT(Rb), R1 + AND.S $0x10, R1 + BNE _putcl + AND $0xFF, R0 + MOVW R0, UART_DATA(Rb) + RET + +TEXT jump(SB), $-4 + MOVW R0, R15 + +TEXT abort(SB), $0 + MOVW $'?', R0 + BL putc(SB) +_loop: + WFE + B _loop + +#define TRI 1 +#define LVCMOS18 (1<<9) +#define LVCMOS25 (2<<9) +#define LVCMOS33 (3<<9) +#define HSTL (4<<9) +#define PULLUP (1<<12) +#define NORECV (1<<13) +#define FAST (1<<8) +#define MUX(a, b, c, d) ((a)<<1 | (b)<<2 | (c)<<3 | (d)<<5) + +#define NO (TRI | LVCMOS33) +#define SPI (MUX(1, 0, 0, 0) | LVCMOS33) +#define UART (MUX(0, 0, 0, 7) | LVCMOS33) +#define SD (MUX(0, 0, 0, 4) | LVCMOS33) +#define ETX (MUX(1, 0, 0, 0) | HSTL | NORECV | PULLUP) +#define ERX (MUX(1, 0, 0, 0) | HSTL | TRI | PULLUP) +#define USB (MUX(0, 1, 0, 0) | LVCMOS18) +#define MDCLK (MUX(0, 0, 0, 4) | HSTL) +#define MDDATA (MUX(0, 0, 0, 4) | HSTL) + +TEXT miodata(SB), $-4 + WORD $NO // 0 + WORD $SPI // 1 + WORD $SPI // 2 + WORD $SPI // 3 + WORD $SPI // 4 + WORD $SPI // 5 + WORD $SPI // 6 + WORD $NO // 7 + WORD $UART // 8 + WORD $(UART|TRI) // 9 + WORD $SD // 10 + WORD $SD // 11 + WORD $SD // 12 + WORD $SD // 13 + WORD $SD // 14 + WORD $SD // 15 + WORD $ETX // 16 + WORD $ETX // 17 + WORD $ETX // 18 + WORD $ETX // 19 + WORD $ETX // 20 + WORD $ETX // 21 + WORD $ERX // 22 + WORD $ERX // 23 + WORD $ERX // 24 + WORD $ERX // 25 + WORD $ERX // 26 + WORD $ERX // 27 + WORD $USB // 28 + WORD $USB // 29 + WORD $USB // 30 + WORD $USB // 31 + WORD $USB // 32 + WORD $USB // 33 + WORD $USB // 34 + WORD $USB // 35 + WORD $USB // 36 + WORD $USB // 37 + WORD $USB // 38 + WORD $USB // 39 + WORD $USB // 40 + WORD $USB // 41 + WORD $USB // 42 + WORD $USB // 43 + WORD $USB // 44 + WORD $USB // 45 + WORD $USB // 46 + WORD $USB // 47 + WORD $USB // 48 + WORD $USB // 49 + WORD $USB // 50 + WORD $USB // 51 + WORD $MDCLK // 52 + WORD $MDDATA // 53 diff --git a/sys/src/boot/zynq/main.c b/sys/src/boot/zynq/main.c new file mode 100644 index 000000000..ffe2daddd --- /dev/null +++ b/sys/src/boot/zynq/main.c @@ -0,0 +1,184 @@ +#include <u.h> +#include <a.out.h> +#include "dat.h" +#include "fns.h" + +void +puts(char *s) +{ + while(*s) + putc(*s++); +} + +void +puthex(u32int u) +{ + static char *dig = "0123456789abcdef"; + int i; + + for(i = 0; i < 8; i++){ + putc(dig[u >> 28]); + u <<= 4; + } +} + +void +putdec(int n) +{ + if(n / 10 != 0) + putdec(n / 10); + putc(n % 10 + '0'); +} + +void +print(char *s, ...) +{ + va_list va; + int n; + u32int u; + + va_start(va, s); + while(*s) + if(*s == '%'){ + switch(*++s){ + case 's': + puts(va_arg(va, char *)); + break; + case 'x': + puthex(va_arg(va, u32int)); + break; + case 'd': + n = va_arg(va, int); + if(n < 0){ + putc('-'); + putdec(-n); + }else + putdec(n); + break; + case 'I': + u = va_arg(va, u32int); + putdec(u >> 24); + putc('.'); + putdec((uchar)(u >> 16)); + putc('.'); + putdec((uchar)(u >> 8)); + putc('.'); + putdec((uchar)u); + break; + case 0: + va_end(va); + return; + } + s++; + }else + putc(*s++); + va_end(va); +} + +void +memset(void *v, char c, int n) +{ + char *vc; + + vc = v; + while(n--) + *vc++ = c; +} + +void +memcpy(void *d, void *s, int n) +{ + char *cd, *cs; + + cd = d; + cs = s; + while(n--) + *cd++ = *cs++; +} + +void +run(void) +{ + ulong t, tr; + char *p, *d; + int n; + ulong *h; + + h = (ulong *) TZERO; + if(u32get(&h[0]) != E_MAGIC){ + print("invalid magic: %x != %x\n", u32get(&h[0]), E_MAGIC); + return; + } + t = u32get(&h[1]) + 0x20; + tr = t + 0xfff & ~0xfff; + if(t != tr){ + n = u32get(&h[2]); + p = (char *) (TZERO + t + n); + d = (char *) (TZERO + tr + n); + while(n--) + *--d = *--p; + } + p = (char *) (TZERO + tr + u32get(&h[2])); + memset(p, 0, u32get(&h[3])); + jump((void *) (u32get(&h[5]) & 0xfffffff)); +} + +enum { + TIMERVALL, + TIMERVALH, + TIMERCTL, + TIMERSTAT, + TIMERCOMPL, + TIMERCOMPH, +}; + +void +timeren(int n) +{ + ulong *r; + + r = (ulong *) 0xf8f00200; + if(n < 0){ + r[TIMERSTAT] |= 1; + r[TIMERCTL] = 0; + return; + } + r[TIMERCTL] = 0; + r[TIMERVALL] = 0; + r[TIMERVALH] = 0; + r[TIMERCOMPL] = 1000 * n; + r[TIMERCOMPH] = 0; + r[TIMERSTAT] |= 1; + r[TIMERCTL] = 100 << 8 | 3; +} + +int +timertrig(void) +{ + ulong *r; + + r = (ulong *) 0xf8f00200; + if((r[TIMERSTAT] & 1) != 0){ + r[TIMERCTL] = 0; + r[TIMERSTAT] |= 1; + return 1; + } + return 0; +} + +void +sleep(int n) +{ + timeren(n); + while(!timertrig()) + ; +} + +void +main(void) +{ + puts("Booting ...\n"); + if(netboot() > 0) + run(); + print("hjboot: ending\n"); +} diff --git a/sys/src/boot/zynq/mem.h b/sys/src/boot/zynq/mem.h new file mode 100644 index 000000000..9753fc346 --- /dev/null +++ b/sys/src/boot/zynq/mem.h @@ -0,0 +1,107 @@ +#define STACKTOP 0xFFFFFE00 + +#define ARM_FDIV (40 << PLL_FDIV_SH) +#define DDR_FDIV (32 << PLL_FDIV_SH) +#define IO_FDIV (30 << PLL_FDIV_SH) +#define PLL_CFG_VAL(CP, RES, CNT) ((CP)<<8 | (RES)<<4 | (CNT)<<12) +#define ARM_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 250) +#define DDR_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 300) +#define IO_PLL_CFG_VAL PLL_CFG_VAL(2, 12, 325) +#define PLL_FDIV_SH 12 +#define PLL_BYPASS_FORCE 0x10 +#define PLL_RESET 0x01 + +#define CPU_DIV 2 +#define DDR_DIV3 2 +#define DDR_DIV2 3 +#define UART_DIV 40 +#define DCI_DIV0 20 +#define DCI_DIV1 5 +#define ETH_DIV0 8 +#define ETH_DIV1 1 +#define QSPI_DIV 5 +#define SDIO_DIV 10 +#define PCAP_DIV 5 +#define MDC_DIV 6 /* this value depends on CPU_1xCLK, see TRM GEM.net_cfg description */ + +#define SLCR_BASE 0xF8000000 +#define SLCR_LOCK 0x004 +#define LOCK_KEY 0x767B +#define SLCR_UNLOCK 0x008 +#define UNLOCK_KEY 0xDF0D + +#define ARM_PLL_CTRL 0x100 +#define DDR_PLL_CTRL 0x104 +#define IO_PLL_CTRL 0x108 +#define PLL_STATUS 0x10C +#define ARM_PLL_CFG 0x110 +#define DDR_PLL_CFG 0x114 +#define IO_PLL_CFG 0x118 +#define ARM_CLK_CTRL 0x120 +#define DDR_CLK_CTRL 0x124 +#define DCI_CLK_CTRL 0x128 +#define APER_CLK_CTRL 0x12C +#define GEM0_RCLK_CTRL 0x138 +#define GEM1_RCLK_CTRL 0x13C +#define GEM0_CLK_CTRL 0x140 +#define GEM1_CLK_CTRL 0x144 +#define SMC_CLK_CTRL 0x148 +#define LQSPI_CLK_CTRL 0x14C +#define SDIO_CLK_CTRL 0x150 +#define UART_CLK_CTRL 0x154 +#define SPI_CLK_CTRL 0x158 +#define CAN_CLK_CTRL 0x15C +#define PCAP_CLK_CTRL 0x168 +#define UART_RST_CTRL 0x228 +#define A9_CPU_RST_CTRL 0x244 + +#define LQSPI_CLK_EN (1<<23) +#define GPIO_CLK_EN (1<<22) +#define UART0_CLK_EN (1<<20) +#define UART1_CLK_EN (1<<21) +#define I2C0_CLK_EN (1<<18) +#define SDIO1_CLK_EN (1<<11) +#define GEM0_CLK_EN (1<<6) +#define USB1_CLK_EN (1<<3) +#define USB0_CLK_EN (1<<2) +#define DMA_CLK_EN (1<<0) + +#define MIO_PIN_0 0x00000700 +#define MIO_MST_TRI0 0x80C +#define MIO_MST_TRI1 0x810 +#define OCM_CFG 0x910 +#define GPIOB_CTRL 0xB00 +#define VREF_SW_EN (1<<11) +#define DDRIOB_ADDR0 0xB40 +#define DDRIOB_DCI_CTRL 0xB70 +#define DDRIOB_DCI_CTRL_MASK 0x1ffc3 +#define DDRIOB_DCI_STATUS 0xB74 +#define DCI_RESET 1 +#define DCI_NREF (1<<11) +#define DCI_ENABLE 2 + +#define DDR_BASE 0xF8006000 +#define DDRC_CTRL 0x0 +#define DDR_MODE_STS 0x54 + +#define UART1_BASE 0xE0001000 +#define UART_CTRL 0x0 +#define UART_MODE 0x4 +#define UART_BAUD 0x18 +#define UART_STAT 0x2C +#define UART_DATA 0x30 +#define UART_SAMP 0x34 + +#define QSPI_BASE 0xE000D000 +#define QSPI_CFG 0x0 +#define SPI_EN 0x4 +#define QSPI_TX 0x1c + +#define MP_BASE 0xF8F00000 +#define FILTER_START 0x40 + +#define CpMMU 15 + +#define DSB WORD $0xf57ff04f +#define ISB WORD $0xf57ff06f +#define WFE WORD $0xe320f002 diff --git a/sys/src/boot/zynq/mkfile b/sys/src/boot/zynq/mkfile new file mode 100644 index 000000000..fc8e84a63 --- /dev/null +++ b/sys/src/boot/zynq/mkfile @@ -0,0 +1,34 @@ +objtype=arm +</$objtype/mkfile +BIN=/arm +TARG=fsbl fsbl.img +CLEANFILES=boothead.$cputype +FSBLFILES=fsbl.$O ddr.$O main.$O net.$O div.$O qspi.$O + +all:V: $TARG + +clean:V: + rm -rf $TARG *.$O + +fsbl: $FSBLFILES + $LD -o $target -T0xfffc0000 -H6 -R4096 -l -s $prereq + +9fsbl: $FSBLFILES + $LD -o $target -T0xfffc0000 -l $prereq + +fsbl.img:D: fsbl boothead.$cputype + boothead.$cputype fsbl >fsbl.img + +boothead.$cputype:V: mkfile.boothead + @{objtype=$cputype mk -f $prereq all} + +div.$O: /sys/src/libc/arm/div.s + $AS /sys/src/libc/arm/div.s + +%.$O: dat.h fns.h mem.h + +%.$O: %.s + $AS $stem.s + +%.$O: %.c + $CC $CFLAGS $stem.c diff --git a/sys/src/boot/zynq/mkfile.boothead b/sys/src/boot/zynq/mkfile.boothead new file mode 100644 index 000000000..cadebcb78 --- /dev/null +++ b/sys/src/boot/zynq/mkfile.boothead @@ -0,0 +1,9 @@ +</$objtype/mkfile + +all:V: boothead.$objtype + +boothead.$objtype: boothead.$O + $LD $LDFLAGS -o $target $prereq + +%.$O: %.c + $CC $CFLAGS $stem.c diff --git a/sys/src/boot/zynq/net.c b/sys/src/boot/zynq/net.c new file mode 100644 index 000000000..f783958a0 --- /dev/null +++ b/sys/src/boot/zynq/net.c @@ -0,0 +1,591 @@ +#include <u.h> +#include "dat.h" +#include "fns.h" +#include "mem.h" + +enum { + ETHLEN = 1600, + UDPLEN = 576, + NRX = 64, + RXBASE = 128 * 1024 * 1024, + + ETHHEAD = 14, + IPHEAD = 20, + UDPHEAD = 8, + + BOOTREQ = 1, + DHCPDISCOVER = 1, + DHCPOFFER, + DHCPREQUEST, + DHCPDECLINE, +}; + +enum { + NET_CTRL, + NET_CFG, + NET_STATUS, + DMA_CFG = 4, + TX_STATUS, + RX_QBAR, + TX_QBAR, + RX_STATUS, + INTR_STATUS, + INTR_EN, + INTR_DIS, + INTR_MASK, + PHY_MAINT, + RX_PAUSEQ, + TX_PAUSEQ, + HASH_BOT = 32, + HASH_TOP, + SPEC_ADDR1_BOT, + SPEC_ADDR1_TOP, +}; + +enum { + MDCTRL, + MDSTATUS, + MDID1, + MDID2, + MDAUTOADV, + MDAUTOPART, + MDAUTOEX, + MDAUTONEXT, + MDAUTOLINK, + MDGCTRL, + MDGSTATUS, + MDPHYCTRL = 0x1f, +}; + +enum { + /* NET_CTRL */ + RXEN = 1<<2, + TXEN = 1<<3, + MDEN = 1<<4, + STARTTX = 1<<9, + /* NET_CFG */ + SPEED = 1<<0, + FDEN = 1<<1, + RX1536EN = 1<<8, + GIGE_EN = 1<<10, + RXCHKSUMEN = 1<<24, + /* NET_STATUS */ + PHY_IDLE = 1<<2, + /* DMA_CFG */ + TXCHKSUMEN = 1<<11, + /* TX_STATUS */ + TXCOMPL = 1<<5, + /* MDCTRL */ + MDRESET = 1<<15, + AUTONEG = 1<<12, + FULLDUP = 1<<8, + /* MDSTATUS */ + LINK = 1<<2, + /* MDGSTATUS */ + RECVOK = 3<<12, +}; + +typedef struct { + uchar edest[6]; + uchar esrc[6]; + ulong idest; + ulong isrc; + ushort dport, sport; + ushort len; + uchar data[UDPLEN]; +} udp; + +static ulong *eth0 = (ulong *) 0xe000b000; +static int phyaddr = 7; + +static u32int myip, dhcpip, tftpip, xid; +static uchar mac[6] = {0x0E, 0xA7, 0xDE, 0xAD, 0xBE, 0xEF}; +static uchar tmac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static char file[128]; + +static udp ubuf, urbuf; +static uchar txbuf[ETHLEN]; +static ulong txdesc[4], *txact, *rxact; +static ulong rxdesc[NRX*2]; + +void +mdwrite(ulong *r, int reg, u16int val) +{ + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; + r[PHY_MAINT] = 1<<30 | 1<<28 | 1<<17 | phyaddr << 23 | reg << 18 | val; + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; +} + +u16int +mdread(ulong *r, int reg) +{ + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; + r[PHY_MAINT] = 1<<30 | 1<<29 | 1<<17 | phyaddr << 23 | reg << 18; + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; + return r[PHY_MAINT]; +} + +void +ethinit(ulong *r) +{ + int v; + ulong *p; + ulong d; + + r[NET_CTRL] = 0; + r[RX_STATUS] = 0xf; + r[TX_STATUS] = 0xff; + r[INTR_DIS] = 0x7FFFEFF; + r[RX_QBAR] = r[TX_QBAR] = 0; + r[NET_CFG] = MDC_DIV << 18 | FDEN | SPEED | RX1536EN | GIGE_EN | RXCHKSUMEN; + r[SPEC_ADDR1_BOT] = mac[0] | mac[1] << 8 | mac[2] << 16 | mac[3] << 24; + r[SPEC_ADDR1_TOP] = mac[4] | mac[5] << 8; + r[DMA_CFG] = TXCHKSUMEN | 0x18 << 16 | 1 << 10 | 3 << 8 | 0x10; + + txdesc[0] = 0; + txdesc[1] = 1<<31; + txdesc[2] = 0; + txdesc[3] = 1<<31 | 1<<30; + txact = txdesc; + r[TX_QBAR] = (ulong) txdesc; + for(p = rxdesc, d = RXBASE; p < rxdesc + nelem(rxdesc); d += ETHLEN){ + *p++ = d; + *p++ = 0; + } + p[-2] |= 2; + rxact = rxdesc; + r[RX_QBAR] = (ulong) rxdesc; + + r[NET_CTRL] = MDEN; +// mdwrite(r, MDCTRL, MDRESET); + mdwrite(r, MDCTRL, AUTONEG); + if((mdread(r, MDSTATUS) & LINK) == 0){ + puts("Waiting for Link ...\n"); + while((mdread(r, MDSTATUS) & LINK) == 0) + ; + } + v = mdread(r, MDPHYCTRL); + if((v & 0x40) != 0){ + puts("1000BASE-T"); + while((mdread(r, MDGSTATUS) & RECVOK) != RECVOK) + ; + r[NET_CFG] |= GIGE_EN; + }else if((v & 0x20) != 0){ + puts("100BASE-TX"); + r[NET_CFG] = NET_CFG & ~GIGE_EN | SPEED; + }else if((v & 0x10) != 0){ + puts("10BASE-T"); + r[NET_CFG] = NET_CFG & ~(GIGE_EN | SPEED); + }else + puts("???"); + if((v & 0x08) != 0) + puts(" Full Duplex\n"); + else{ + puts(" Half Duplex\n"); + r[NET_CFG] &= ~FDEN; + } + r[NET_CTRL] |= TXEN | RXEN; +} + +u32int +u32get(void *pp) +{ + uchar *p; + + p = pp; + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +uchar * +u32put(uchar *p, u32int v) +{ + p[0] = v >> 24; + p[1] = v >> 16; + p[2] = v >> 8; + p[3] = v; + return p + 4; +} + +void +ethtx(ulong *r, uchar *buf, int len) +{ + txact[0] = (ulong) buf; + txact[1] = 1<<15 | len; + if(txact == txdesc + nelem(txdesc) - 2){ + txact[1] |= 1<<30; + txact = txdesc; + }else + txact += 2; + r[TX_STATUS] = -1; + r[NET_CTRL] |= STARTTX; + while((r[TX_STATUS] & TXCOMPL) == 0) + ; +} + +void +udptx(ulong *r, udp *u) +{ + uchar *p, *q; + int n; + + p = q = txbuf; + memcpy(p, u->edest, 6); + memcpy(p + 6, u->esrc, 6); + q += 12; + *q++ = 8; + *q++ = 0; + + *q++ = 5 | 4 << 4; + *q++ = 0; + n = IPHEAD + UDPHEAD + u->len; + *q++ = n >> 8; + *q++ = n; + + *q++ = 0x13; + *q++ = 0x37; + *q++ = 1<<6; + *q++ = 0; + + *q++ = 1; + *q++ = 0x11; + *q++ = 0; + *q++ = 0; + q = u32put(q, u->isrc); + q = u32put(q, u->idest); + + *q++ = u->sport >> 8; + *q++ = u->sport; + *q++ = u->dport >> 8; + *q++ = u->dport; + n = UDPHEAD + u->len; + *q++ = n >> 8; + *q++ = n; + *q++ = 0; + *q++ = 0; + + memcpy(q, u->data, u->len); + ethtx(r, p, ETHHEAD + IPHEAD + UDPHEAD + u->len); +} + +void +dhcppkg(ulong *r, int t) +{ + uchar *p; + udp *u; + + u = &ubuf; + p = u->data; + *p++ = BOOTREQ; + *p++ = 1; + *p++ = 6; + *p++ = 0; + p = u32put(p, xid); + p = u32put(p, 0x8000); + memset(p, 0, 16); + u32put(p + 8, dhcpip); + p += 16; + memcpy(p, mac, 6); + p += 6; + memset(p, 0, 202); + p += 202; + *p++ = 99; + *p++ = 130; + *p++ = 83; + *p++ = 99; + + *p++ = 53; + *p++ = 1; + *p++ = t; + if(t == DHCPREQUEST){ + *p++ = 50; + *p++ = 4; + p = u32put(p, myip); + *p++ = 54; + *p++ = 4; + p = u32put(p, dhcpip); + } + + *p++ = 0xff; + + memset(u->edest, 0xff, 6); + memcpy(u->esrc, mac, 6); + u->sport = 68; + u->dport = 67; + u->idest = -1; + u->isrc = 0; + u->len = p - u->data; + udptx(r, u); +} + +uchar * +ethrx(void) +{ + while((*rxact & 1) == 0) + if(timertrig()) + return nil; + return (uchar *) (*rxact & ~3); +} + +void +ethnext(void) +{ + *rxact &= ~1; + if((*rxact & 2) != 0) + rxact = rxdesc; + else + rxact += 2; +} + +void +arp(int op, uchar *edest, ulong idest) +{ + uchar *p; + static uchar broad[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + p = txbuf; + if(edest == nil) + edest = broad; + memcpy(p, edest, 6); + memcpy(p + 6, mac, 6); + p[12] = 8; + p[13] = 6; + p += 14; + p = u32put(p, 0x00010800); + p = u32put(p, 0x06040000 | op); + memcpy(p, mac, 6); + p = u32put(p + 6, myip); + memcpy(p, edest, 6); + p = u32put(p + 6, idest); + ethtx(eth0, txbuf, p - txbuf); +} + +void +arpc(uchar *p) +{ + p += 14; + if(u32get(p) != 0x00010800 || p[4] != 6 || p[5] != 4 || p[6] != 0) + return; + switch(p[7]){ + case 1: + if(myip != 0 && u32get(p + 24) == myip) + arp(2, p + 8, u32get(p + 14)); + break; + case 2: + if(tftpip != 0 && u32get(p + 14) == tftpip) + memcpy(tmac, p + 8, 6); + break; + } +} + +udp * +udprx(void) +{ + uchar *p; + ulong v; + udp *u; + + u = &urbuf; + for(;; ethnext()){ + p = ethrx(); + if(p == nil) + return nil; + if(p[12] != 8) + continue; + if(p[13] == 6){ + arpc(p); + continue; + } + if(p[13] != 0) + continue; + p += ETHHEAD; + if((p[0] >> 4) != 4 || p[9] != 0x11) + continue; + v = u32get(p + 16); + if(v != (ulong) -1 && v != myip) + continue; + u->idest = v; + u->isrc = u32get(p + 12); + p += (p[0] & 0xf) << 2; + u->sport = p[0] << 8 | p[1]; + u->dport = p[2] << 8 | p[3]; + u->len = p[4] << 8 | p[5]; + if(u->len < 8) + continue; + u->len -= 8; + if(u->len >= sizeof(u->data)) + u->len = sizeof(u->data); + memcpy(u->data, p + 8, u->len); + ethnext(); + return u; + } +} + +void +arpreq(void) +{ + uchar *p; + + arp(1, nil, tftpip); + timeren(ARPTIMEOUT); + for(;; ethnext()){ + p = ethrx(); + if(p == nil){ + print("ARP timeout\n"); + timeren(ARPTIMEOUT); + arp(1, nil, tftpip); + } + if(p[12] != 8 || p[13] != 6) + continue; + arpc(p); + if(tmac[0] != 0xff) + break; + } + timeren(-1); +} + +void +dhcp(ulong *r) +{ + udp *u; + uchar *p; + uchar type; + + xid = 0xdeadbeef; + tftpip = 0; + dhcppkg(r, DHCPDISCOVER); + timeren(DHCPTIMEOUT); + for(;;){ + u = udprx(); + if(u == nil){ + timeren(DHCPTIMEOUT); + dhcppkg(r, DHCPDISCOVER); + print("DHCP timeout\n"); + } + p = u->data; + if(u->dport != 68 || p[0] != 2 || u32get(p + 4) != xid || u32get(p + 236) != 0x63825363) + continue; + p += 240; + type = 0; + dhcpip = 0; + for(; p < u->data + u->len && *p != 0xff; p += 2 + p[1]) + switch(*p){ + case 53: + type = p[2]; + break; + case 54: + dhcpip = u32get(p + 2); + break; + } + if(type != DHCPOFFER) + continue; + p = u->data; + if(p[108] == 0){ + print("Offer from %I for %I with no boot file\n", dhcpip, u32get(p + 16)); + continue; + } + myip = u32get(p + 16); + tftpip = u32get(p + 20); + memcpy(file, p + 108, 128); + print("Offer from %I for %I with boot file '%s' at %I\n", dhcpip, myip, file, tftpip); + break; + } + timeren(-1); + dhcppkg(r, DHCPREQUEST); +} + +udp * +tftppkg(void) +{ + udp *u; + + u = &ubuf; + memcpy(u->edest, tmac, 6); + memcpy(u->esrc, mac, 6); + u->idest = tftpip; + u->isrc = myip; + u->sport = 69; + u->dport = 69; + return u; +} + +void +tftp(ulong *r, char *q, uintptr base) +{ + udp *u, *v; + uchar *p; + int bn, len; + +restart: + u = tftppkg(); + p = u->data; + *p++ = 0; + *p++ = 1; + do + *p++ = *q; + while(*q++ != 0); + memcpy(p, "octet", 6); + p += 6; + u->len = p - u->data; + udptx(r, u); + timeren(TFTPTIMEOUT); + + for(;;){ + v = udprx(); + if(v == nil){ + print("TFTP timeout"); + goto restart; + } + if(v->dport != 69 || v->isrc != tftpip || v->idest != myip) + continue; + if(v->data[0] != 0) + continue; + switch(v->data[1]){ + case 3: + bn = v->data[2] << 8 | v->data[3]; + len = v->len - 4; + if(len < 0) + continue; + if(len > 512) + len = 512; + memcpy((char*)base + ((bn - 1) << 9), v->data + 4, len); + if((bn & 127) == 0) + putc('.'); + p = u->data; + *p++ = 0; + *p++ = 4; + *p++ = bn >> 8; + *p = bn; + u->len = 4; + udptx(r, u); + if(len < 512){ + putc(10); + timeren(-1); + return; + } + timeren(TFTPTIMEOUT); + break; + case 5: + v->data[v->len - 1] = 0; + print("TFTP error: %s\n", v->data + 4); + timeren(-1); + return; + } + } +} + +int +netboot(void) +{ + ethinit(eth0); + myip = 0; + dhcp(eth0); + arpreq(); + tftp(eth0, file, TZERO); + memset((void *) CONF, 0, CONFSIZE); + tftp(eth0, "/cfg/pxe/0ea7deadbeef", CONF); + return 1; +} diff --git a/sys/src/boot/zynq/qspi.c b/sys/src/boot/zynq/qspi.c new file mode 100644 index 000000000..6134592ce --- /dev/null +++ b/sys/src/boot/zynq/qspi.c @@ -0,0 +1,45 @@ +#include <u.h> +#include "dat.h" +#include "fns.h" + +enum { + QSPI_CFG, + QSPI_STATUS, + QSPI_EN = 5, + QSPI_TXD4 = 7, + QSPI_RXD, + QSPI_TXD1 = 32, + QSPI_TXD2, + QSPI_TXD3 +}; + +#define QSPI0 ((void *) 0xE000D000) + +static u32int +cmd(ulong *r, int sz, u32int c) +{ + if(sz == 4) + r[QSPI_TXD4] = c; + else + r[QSPI_TXD1 + sz - 1] = c; + r[QSPI_CFG] |= 1<<16; + while((r[QSPI_STATUS] & (1<<2|1<<4)) != (1<<2|1<<4)) + ; + return r[QSPI_RXD]; +} + +void +flash(void) +{ + ulong *r; + + r = QSPI0; + r[QSPI_CFG] = 1<<31 | 1<<19 | 3<<6 | 1<<15 | 1<<14 | 1<<10 | 1<<3 | 1; + r[QSPI_CFG] &= ~(1<<10); + r[QSPI_EN] = 1; + cmd(r, 1, 0x06); +// cmd(r, 3, 0xD8); + for(;;) + print("%x\n", cmd(r, 2, 0x05)); + +} |