added zynq kernel

This commit is contained in:
aiju 2014-12-24 10:21:51 +01:00
parent 6dafa42480
commit 7a3f0998a0
37 changed files with 6601 additions and 0 deletions

196
sys/src/9/zynq/dat.h Normal file
View file

@ -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();

391
sys/src/9/zynq/devarch.c Normal file
View file

@ -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,
};

517
sys/src/9/zynq/devether.c Normal file
View file

@ -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 = &ether->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,
};

275
sys/src/9/zynq/devqspi.c Normal file
View file

@ -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,
};

40
sys/src/9/zynq/etherif.h Normal file
View file

@ -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))

380
sys/src/9/zynq/etherzynq.c Normal file
View file

@ -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);
}

75
sys/src/9/zynq/fns.h Normal file
View file

@ -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 *);

7
sys/src/9/zynq/init9.s Normal file
View file

@ -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

118
sys/src/9/zynq/intr.c Normal file
View file

@ -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();
}
}

25
sys/src/9/zynq/io.h Normal file
View file

@ -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

460
sys/src/9/zynq/l.s Normal file
View file

@ -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

98
sys/src/9/zynq/ltrap.s Normal file
View file

@ -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]

0
sys/src/9/zynq/main.bin Normal file
View file

372
sys/src/9/zynq/main.c Normal file
View file

@ -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();
}

124
sys/src/9/zynq/mem.h Normal file
View file

@ -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)

92
sys/src/9/zynq/mkfile Normal file
View file

@ -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

422
sys/src/9/zynq/mmu.c Normal file
View file

@ -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;
}

126
sys/src/9/zynq/screen.c Normal file
View file

@ -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 *)
{
}

44
sys/src/9/zynq/screen.h Normal file
View file

@ -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);

91
sys/src/9/zynq/timer.c Normal file
View file

@ -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);
}

544
sys/src/9/zynq/trap.c Normal file
View file

@ -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);
}

244
sys/src/9/zynq/uartzynq.c Normal file
View file

@ -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,
};

27
sys/src/9/zynq/uncached.h Normal file
View file

@ -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);
}

141
sys/src/9/zynq/usbehci.h Normal file
View file

@ -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);

View file

@ -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);
}

56
sys/src/9/zynq/zynq Normal file
View file

@ -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

View file

@ -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);
}

11
sys/src/boot/zynq/dat.h Normal file
View file

@ -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)))

258
sys/src/boot/zynq/ddr.s Normal file
View file

@ -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

13
sys/src/boot/zynq/fns.h Normal file
View file

@ -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);

310
sys/src/boot/zynq/fsbl.s Normal file
View file

@ -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

184
sys/src/boot/zynq/main.c Normal file
View file

@ -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");
}

107
sys/src/boot/zynq/mem.h Normal file
View file

@ -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

34
sys/src/boot/zynq/mkfile Normal file
View file

@ -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

View file

@ -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

591
sys/src/boot/zynq/net.c Normal file
View file

@ -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;
}

45
sys/src/boot/zynq/qspi.c Normal file
View file

@ -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));
}