plan9fox/sys/src/9/zynq/devarch.c

390 lines
5.9 KiB
C
Raw Normal View History

2014-12-24 09:21:51 +00:00
#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,
Qfbctl,
2014-12-24 09:21:51 +00:00
Qbase,
Qmax = 16,
};
static Dirtab archdir[Qmax] = {
".", { Qdir, 0, QTDIR }, 0, 0555,
"temp", { Qtemp, 0}, 0, 0440,
"pl", { Qpl, 0 }, 0, 0660,
"fbctl", { Qfbctl, 0 }, 0, 0660,
2014-12-24 09:21:51 +00:00
};
static int narchdir = Qbase;
static int temp = -128;
static ulong *devc;
static int dmadone;
2014-12-24 09:21:51 +00:00
enum { PLBUFSIZ = 8192 };
static uchar *plbuf;
static Rendez plinitr, pldoner, pldmar;
static QLock plrlock, plwlock;
static Ref plwopen;
static Physseg *axi;
2014-12-24 09:21:51 +00:00
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;
devc[DEVMASK] |= DONE;
axi->attr &= ~SG_FAULT;
2014-12-24 09:21:51 +00:00
wakeup(&pldoner);
}
if((fl & DMADONE) != 0){
dmadone++;
wakeup(&pldmar);
}
devc[DEVISTS] = fl;
}
static void
plinit(void)
{
Physseg seg;
memset(&seg, 0, sizeof seg);
seg.attr = SG_PHYSICAL | SG_FAULT;
seg.name = "axi";
seg.pa = 0x40000000;
seg.size = 0x8000000;
axi = addphysseg(&seg);
2014-12-24 09:21:51 +00:00
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;
}
static void
plconf(void)
{
axi->attr |= SG_FAULT;
procflushpseg(axi);
flushmmu();
2014-12-24 09:21:51 +00:00
slcr[0x240/4] = 0xf;
slcr[0x900/4] = 0xa;
devc[DEVISTS] = DONE|INITPE|DMADONE;
devc[DEVCTRL] |= PROG;
devc[DEVCTRL] &= ~PROG;
devc[DEVMASK] &= ~DONE;
devc[DEVCTRL] |= PROG;
while(waserror())
;
2014-12-24 09:21:51 +00:00
sleep(&plinitr, isplinit, nil);
poperror();
2014-12-24 09:21:51 +00:00
}
static long
plwrite(uintptr pa, long n)
{
dmadone = 0;
coherence();
devc[DMASRC] = pa;
devc[DMADST] = -1;
devc[DMASRCL] = n>>2;
2014-12-24 09:21:51 +00:00
devc[DMADSTL] = 0;
while(waserror())
;
sleep(&pldmar, isdmadone, nil);
poperror();
2014-12-24 09:21:51 +00:00
return n;
}
static long
plcopy(uchar *d, long n)
{
long ret;
ulong nn;
uintptr pa;
if((n & 3) != 0 || n <= 0)
error(Eshort);
eqlock(&plwlock);
if(waserror()){
qunlock(&plwlock);
nexterror();
}
2014-12-24 09:21:51 +00:00
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);
}
qunlock(&plwlock);
poperror();
2014-12-24 09:21:51 +00:00
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:
eqlock(&plrlock);
if(waserror()){
qunlock(&plrlock);
nexterror();
}
2014-12-24 09:21:51 +00:00
sleep(&pldoner, ispldone, nil);
qunlock(&plrlock);
poperror();
2014-12-24 09:21:51 +00:00
return 0;
case Qfbctl:
return fbctlread(c, a, n, offset);
2014-12-24 09:21:51 +00:00
default:
error(Egreg);
return -1;
}
}
static long
archwrite(Chan *c, void *a, long n, vlong offset)
2014-12-24 09:21:51 +00:00
{
switch((ulong)c->qid.path){
case Qpl:
return plcopy(a, n);
case Qfbctl:
return fbctlwrite(c, a, n, offset);
2014-12-24 09:21:51 +00:00
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 || c->mode == ORDWR)){
if(incref(&plwopen) != 1){
c->flag &= ~COPEN;
decref(&plwopen);
error(Einuse);
}
plbuf = smalloc(PLBUFSIZ);
2014-12-24 09:21:51 +00:00
plconf();
}
2014-12-24 09:21:51 +00:00
return c;
}
static void
archclose(Chan* c)
{
if((c->flag & COPEN) != 0)
if((ulong)c->qid.path == Qpl && (c->mode == OWRITE || c->mode == ORDWR)){
2014-12-24 09:21:51 +00:00
free(plbuf);
plbuf = nil;
decref(&plwopen);
2014-12-24 09:21:51 +00:00
}
}
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,
};