summaryrefslogtreecommitdiff
path: root/sys/src/9/cycv/devarch.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2020-01-08 02:35:01 +0000
committeraiju <devnull@localhost>2020-01-08 02:35:01 +0000
commit17ebe55031ae6945ad1f671b69267a672328e4b1 (patch)
treef3879436d00a88389d57d549a9b07171206c17c1 /sys/src/9/cycv/devarch.c
parent826c76f90df66a9b20a3cf279bfb47d4d27322af (diff)
add cycv kernel
Diffstat (limited to 'sys/src/9/cycv/devarch.c')
-rw-r--r--sys/src/9/cycv/devarch.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/sys/src/9/cycv/devarch.c b/sys/src/9/cycv/devarch.c
new file mode 100644
index 000000000..00a368fd6
--- /dev/null
+++ b/sys/src/9/cycv/devarch.c
@@ -0,0 +1,389 @@
+#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_DEVICE | SG_NOEXEC | 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,
+};
+