389 lines
5.9 KiB
C
389 lines
5.9 KiB
C
#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,
|
|
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,
|
|
};
|
|
static int narchdir = Qbase;
|
|
|
|
static int temp = -128;
|
|
static ulong *devc;
|
|
static int dmadone;
|
|
enum { PLBUFSIZ = 8192 };
|
|
static uchar *plbuf;
|
|
static Rendez plinitr, pldoner, pldmar;
|
|
static QLock plrlock, plwlock;
|
|
static Ref plwopen;
|
|
static Physseg *axi;
|
|
|
|
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;
|
|
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);
|
|
|
|
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();
|
|
|
|
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())
|
|
;
|
|
sleep(&plinitr, isplinit, nil);
|
|
poperror();
|
|
}
|
|
|
|
static long
|
|
plwrite(uintptr pa, long n)
|
|
{
|
|
dmadone = 0;
|
|
coherence();
|
|
devc[DMASRC] = pa;
|
|
devc[DMADST] = -1;
|
|
devc[DMASRCL] = n>>2;
|
|
devc[DMADSTL] = 0;
|
|
|
|
while(waserror())
|
|
;
|
|
sleep(&pldmar, isdmadone, nil);
|
|
poperror();
|
|
|
|
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();
|
|
}
|
|
|
|
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();
|
|
|
|
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();
|
|
}
|
|
sleep(&pldoner, ispldone, nil);
|
|
qunlock(&plrlock);
|
|
poperror();
|
|
return 0;
|
|
case Qfbctl:
|
|
return fbctlread(c, a, n, offset);
|
|
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);
|
|
case Qfbctl:
|
|
return fbctlwrite(c, a, n, offset);
|
|
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);
|
|
plconf();
|
|
}
|
|
return c;
|
|
}
|
|
|
|
static void
|
|
archclose(Chan* c)
|
|
{
|
|
if((c->flag & COPEN) != 0)
|
|
if((ulong)c->qid.path == Qpl && (c->mode == OWRITE || c->mode == ORDWR)){
|
|
free(plbuf);
|
|
plbuf = nil;
|
|
decref(&plwopen);
|
|
}
|
|
}
|
|
|
|
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,
|
|
};
|
|
|