added zynq kernel
This commit is contained in:
parent
6dafa42480
commit
7a3f0998a0
37 changed files with 6601 additions and 0 deletions
196
sys/src/9/zynq/dat.h
Normal file
196
sys/src/9/zynq/dat.h
Normal 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
391
sys/src/9/zynq/devarch.c
Normal 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
517
sys/src/9/zynq/devether.c
Normal 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 = ðer->f[Ntypes];
|
||||
|
||||
multi = pkt->d[0] & 1;
|
||||
/* check for valid multicast addresses */
|
||||
if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
|
||||
if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
|
||||
if(fromwire){
|
||||
freeb(bp);
|
||||
bp = 0;
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
}
|
||||
|
||||
/* is it for me? */
|
||||
tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
|
||||
fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
|
||||
|
||||
/*
|
||||
* Multiplex the packet to all the connections which want it.
|
||||
* If the packet is not to be used subsequently (fromwire != 0),
|
||||
* attempt to simply pass it into one of the connections, thereby
|
||||
* saving a copy of the data (usual case hopefully).
|
||||
*/
|
||||
for(fp = ether->f; fp < ep; fp++){
|
||||
if(f = *fp)
|
||||
if(f->type == type || f->type < 0)
|
||||
if(tome || multi || f->prom){
|
||||
/* Don't want to hear bridged packets */
|
||||
if(f->bridge && !fromwire && !fromme)
|
||||
continue;
|
||||
if(!f->headersonly){
|
||||
if(fromwire && fx == 0)
|
||||
fx = f;
|
||||
else if(xbp = iallocb(len)){
|
||||
memmove(xbp->wp, pkt, len);
|
||||
xbp->wp += len;
|
||||
if(qpass(f->in, xbp) < 0) {
|
||||
// print("soverflow for f->in\n");
|
||||
ether->soverflows++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// print("soverflow iallocb\n");
|
||||
ether->soverflows++;
|
||||
}
|
||||
}
|
||||
else
|
||||
etherrtrace(f, pkt, len);
|
||||
}
|
||||
}
|
||||
|
||||
if(fx){
|
||||
if(qpass(fx->in, bp) < 0) {
|
||||
// print("soverflow for fx->in\n");
|
||||
ether->soverflows++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(fromwire){
|
||||
freeb(bp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bp;
|
||||
}
|
||||
|
||||
static int
|
||||
etheroq(Ether* ether, Block* bp)
|
||||
{
|
||||
int len, loopback;
|
||||
Etherpkt *pkt;
|
||||
|
||||
ether->outpackets++;
|
||||
|
||||
/*
|
||||
* Check if the packet has to be placed back onto the input queue,
|
||||
* i.e. if it's a loopback or broadcast packet or the interface is
|
||||
* in promiscuous mode.
|
||||
* If it's a loopback packet indicate to etheriq that the data isn't
|
||||
* needed and return, etheriq will pass-on or free the block.
|
||||
* To enable bridging to work, only packets that were originated
|
||||
* by this interface are fed back.
|
||||
*/
|
||||
pkt = (Etherpkt*)bp->rp;
|
||||
len = BLEN(bp);
|
||||
loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
|
||||
if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
|
||||
if(etheriq(ether, bp, loopback) == 0)
|
||||
return len;
|
||||
|
||||
qbwrite(ether->oq, bp);
|
||||
if(ether->transmit != nil)
|
||||
ether->transmit(ether);
|
||||
return len;
|
||||
}
|
||||
|
||||
static long
|
||||
etherwrite(Chan* chan, void* buf, long n, vlong)
|
||||
{
|
||||
Ether *ether;
|
||||
Block *bp;
|
||||
int nn, onoff;
|
||||
Cmdbuf *cb;
|
||||
|
||||
ether = etherxx[chan->dev];
|
||||
if(NETTYPE(chan->qid.path) != Ndataqid) {
|
||||
nn = netifwrite(ether, chan, buf, n);
|
||||
if(nn >= 0)
|
||||
return nn;
|
||||
cb = parsecmd(buf, n);
|
||||
if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
|
||||
if(cb->nf <= 1)
|
||||
onoff = 1;
|
||||
else
|
||||
onoff = atoi(cb->f[1]);
|
||||
qnoblock(ether->oq, onoff);
|
||||
free(cb);
|
||||
return n;
|
||||
}
|
||||
free(cb);
|
||||
if(ether->ctl!=nil)
|
||||
return ether->ctl(ether,buf,n);
|
||||
|
||||
error(Ebadctl);
|
||||
}
|
||||
|
||||
if(n > ether->maxmtu)
|
||||
error(Etoobig);
|
||||
if(n < ether->minmtu)
|
||||
error(Etoosmall);
|
||||
|
||||
bp = allocb(n);
|
||||
if(waserror()){
|
||||
freeb(bp);
|
||||
nexterror();
|
||||
}
|
||||
memmove(bp->rp, buf, n);
|
||||
memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
|
||||
poperror();
|
||||
bp->wp += n;
|
||||
|
||||
return etheroq(ether, bp);
|
||||
}
|
||||
|
||||
static long
|
||||
etherbwrite(Chan* chan, Block* bp, ulong)
|
||||
{
|
||||
Ether *ether;
|
||||
long n;
|
||||
|
||||
n = BLEN(bp);
|
||||
if(NETTYPE(chan->qid.path) != Ndataqid){
|
||||
if(waserror()) {
|
||||
freeb(bp);
|
||||
nexterror();
|
||||
}
|
||||
n = etherwrite(chan, bp->rp, n, 0);
|
||||
poperror();
|
||||
freeb(bp);
|
||||
return n;
|
||||
}
|
||||
ether = etherxx[chan->dev];
|
||||
|
||||
if(n > ether->maxmtu){
|
||||
freeb(bp);
|
||||
error(Etoobig);
|
||||
}
|
||||
if(n < ether->minmtu){
|
||||
freeb(bp);
|
||||
error(Etoosmall);
|
||||
}
|
||||
|
||||
return etheroq(ether, bp);
|
||||
}
|
||||
|
||||
static struct {
|
||||
char* type;
|
||||
int (*reset)(Ether*);
|
||||
} cards[MaxEther+1];
|
||||
|
||||
void
|
||||
addethercard(char* t, int (*r)(Ether*))
|
||||
{
|
||||
static int ncard;
|
||||
|
||||
if(ncard == MaxEther)
|
||||
panic("too many ether cards");
|
||||
cards[ncard].type = t;
|
||||
cards[ncard].reset = r;
|
||||
ncard++;
|
||||
}
|
||||
|
||||
int
|
||||
parseether(uchar *to, char *from)
|
||||
{
|
||||
char nip[4];
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
p = from;
|
||||
for(i = 0; i < Eaddrlen; i++){
|
||||
if(*p == 0)
|
||||
return -1;
|
||||
nip[0] = *p++;
|
||||
if(*p == 0)
|
||||
return -1;
|
||||
nip[1] = *p++;
|
||||
nip[2] = 0;
|
||||
to[i] = strtoul(nip, 0, 16);
|
||||
if(*p == ':')
|
||||
p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Ether*
|
||||
etherprobe(int cardno, int ctlrno)
|
||||
{
|
||||
int i, lg;
|
||||
ulong mb, bsz;
|
||||
Ether *ether;
|
||||
char buf[128], name[32];
|
||||
|
||||
ether = malloc(sizeof(Ether));
|
||||
if(ether == nil){
|
||||
print("etherprobe: no memory for Ether\n");
|
||||
return nil;
|
||||
}
|
||||
memset(ether, 0, sizeof(Ether));
|
||||
ether->ctlrno = ctlrno;
|
||||
ether->mbps = 10;
|
||||
ether->minmtu = ETHERMINTU;
|
||||
ether->maxmtu = ETHERMAXTU;
|
||||
|
||||
if(cardno >= MaxEther || cards[cardno].type == nil){
|
||||
free(ether);
|
||||
return nil;
|
||||
}
|
||||
if(cards[cardno].reset(ether) < 0){
|
||||
free(ether);
|
||||
return nil;
|
||||
}
|
||||
|
||||
snprint(name, sizeof(name), "ether%d", ctlrno);
|
||||
|
||||
intrenable(ether->irq, ether->interrupt, ether, ether->irqlevel, name);
|
||||
|
||||
i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
|
||||
ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
|
||||
i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
|
||||
ether->ea[0], ether->ea[1], ether->ea[2],
|
||||
ether->ea[3], ether->ea[4], ether->ea[5]);
|
||||
sprint(buf+i, "\n");
|
||||
print(buf);
|
||||
|
||||
/* compute log10(ether->mbps) into lg */
|
||||
for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
|
||||
mb /= 10;
|
||||
if (lg > 0)
|
||||
lg--;
|
||||
if (lg > 14) /* 2^(14+17) = 2³¹ */
|
||||
lg = 14;
|
||||
/* allocate larger output queues for higher-speed interfaces */
|
||||
bsz = 1UL << (lg + 17); /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
|
||||
while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
|
||||
bsz /= 2;
|
||||
|
||||
netifinit(ether, name, Ntypes, bsz);
|
||||
if(ether->oq == nil) {
|
||||
ether->oq = qopen(bsz, Qmsg, 0, 0);
|
||||
ether->limit = bsz;
|
||||
}
|
||||
if(ether->oq == nil)
|
||||
panic("etherreset %s: can't allocate output queue of %ld bytes", name, bsz);
|
||||
ether->alen = Eaddrlen;
|
||||
memmove(ether->addr, ether->ea, Eaddrlen);
|
||||
memset(ether->bcast, 0xFF, Eaddrlen);
|
||||
|
||||
return ether;
|
||||
}
|
||||
|
||||
static void
|
||||
etherreset(void)
|
||||
{
|
||||
Ether *ether;
|
||||
int cardno, ctlrno;
|
||||
|
||||
for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
|
||||
if((ether = etherprobe(-1, ctlrno)) == nil)
|
||||
continue;
|
||||
etherxx[ctlrno] = ether;
|
||||
}
|
||||
|
||||
cardno = ctlrno = 0;
|
||||
while(cards[cardno].type != nil && ctlrno < MaxEther){
|
||||
if(etherxx[ctlrno] != nil){
|
||||
ctlrno++;
|
||||
continue;
|
||||
}
|
||||
if((ether = etherprobe(cardno, ctlrno)) == nil){
|
||||
cardno++;
|
||||
continue;
|
||||
}
|
||||
etherxx[ctlrno] = ether;
|
||||
ctlrno++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ethershutdown(void)
|
||||
{
|
||||
Ether *ether;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MaxEther; i++){
|
||||
ether = etherxx[i];
|
||||
if(ether == nil)
|
||||
continue;
|
||||
if(ether->shutdown == nil) {
|
||||
print("#l%d: no shutdown function\n", i);
|
||||
continue;
|
||||
}
|
||||
(*ether->shutdown)(ether);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define POLY 0xedb88320
|
||||
|
||||
/* really slow 32 bit crc for ethers */
|
||||
ulong
|
||||
ethercrc(uchar *p, int len)
|
||||
{
|
||||
int i, j;
|
||||
ulong crc, b;
|
||||
|
||||
crc = 0xffffffff;
|
||||
for(i = 0; i < len; i++){
|
||||
b = *p++;
|
||||
for(j = 0; j < 8; j++){
|
||||
crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
|
||||
b >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
Dev etherdevtab = {
|
||||
'l',
|
||||
"ether",
|
||||
|
||||
etherreset,
|
||||
devinit,
|
||||
ethershutdown,
|
||||
etherattach,
|
||||
etherwalk,
|
||||
etherstat,
|
||||
etheropen,
|
||||
ethercreate,
|
||||
etherclose,
|
||||
etherread,
|
||||
etherbread,
|
||||
etherwrite,
|
||||
etherbwrite,
|
||||
devremove,
|
||||
etherwstat,
|
||||
};
|
275
sys/src/9/zynq/devqspi.c
Normal file
275
sys/src/9/zynq/devqspi.c
Normal 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
40
sys/src/9/zynq/etherif.h
Normal 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
380
sys/src/9/zynq/etherzynq.c
Normal 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
75
sys/src/9/zynq/fns.h
Normal 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
7
sys/src/9/zynq/init9.s
Normal 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
118
sys/src/9/zynq/intr.c
Normal 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
25
sys/src/9/zynq/io.h
Normal 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
460
sys/src/9/zynq/l.s
Normal 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
98
sys/src/9/zynq/ltrap.s
Normal 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
0
sys/src/9/zynq/main.bin
Normal file
372
sys/src/9/zynq/main.c
Normal file
372
sys/src/9/zynq/main.c
Normal 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
124
sys/src/9/zynq/mem.h
Normal 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
92
sys/src/9/zynq/mkfile
Normal 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
422
sys/src/9/zynq/mmu.c
Normal 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
126
sys/src/9/zynq/screen.c
Normal 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
44
sys/src/9/zynq/screen.h
Normal 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
91
sys/src/9/zynq/timer.c
Normal 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
544
sys/src/9/zynq/trap.c
Normal 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
244
sys/src/9/zynq/uartzynq.c
Normal 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
27
sys/src/9/zynq/uncached.h
Normal 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
141
sys/src/9/zynq/usbehci.h
Normal 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);
|
103
sys/src/9/zynq/usbehcizynq.c
Normal file
103
sys/src/9/zynq/usbehcizynq.c
Normal 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
56
sys/src/9/zynq/zynq
Normal 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
|
71
sys/src/boot/zynq/boothead.c
Normal file
71
sys/src/boot/zynq/boothead.c
Normal 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
11
sys/src/boot/zynq/dat.h
Normal 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
258
sys/src/boot/zynq/ddr.s
Normal 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
13
sys/src/boot/zynq/fns.h
Normal 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
310
sys/src/boot/zynq/fsbl.s
Normal 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
184
sys/src/boot/zynq/main.c
Normal 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
107
sys/src/boot/zynq/mem.h
Normal 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
34
sys/src/boot/zynq/mkfile
Normal 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
|
9
sys/src/boot/zynq/mkfile.boothead
Normal file
9
sys/src/boot/zynq/mkfile.boothead
Normal 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
591
sys/src/boot/zynq/net.c
Normal 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
45
sys/src/boot/zynq/qspi.c
Normal 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));
|
||||
|
||||
}
|
Loading…
Reference in a new issue