summaryrefslogtreecommitdiff
path: root/os/mpc/devrtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/mpc/devrtc.c')
-rw-r--r--os/mpc/devrtc.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/os/mpc/devrtc.c b/os/mpc/devrtc.c
new file mode 100644
index 00000000..90193764
--- /dev/null
+++ b/os/mpc/devrtc.c
@@ -0,0 +1,258 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "io.h"
+
+/*
+ * MPC8xx real time clock
+ * optional board option switch
+ * optional nvram
+ * interrupt statistics
+ */
+
+enum{
+ Qdir,
+ Qrtc,
+ Qswitch,
+ Qnvram,
+ Qintstat,
+
+ Qporta,
+ Qportb,
+ Qportc,
+
+ /* sccr */
+ RTDIV= 1<<24,
+ RTSEL= 1<<23,
+
+ /* rtcsc */
+ RTE= 1<<0,
+ R38K= 1<<4,
+};
+
+static QLock rtclock; /* mutex on clock operations */
+
+static Dirtab rtcdir[]={
+ ".", {Qdir,0,QTDIR}, 0, 0555,
+ "rtc", {Qrtc, 0}, 12, 0664,
+ "switch", {Qswitch, 0}, 0, 0444,
+ "intstat", {Qintstat, 0}, 0, 0444,
+ "porta", {Qporta, 0}, 0, 0444,
+ "portb", {Qportb, 0}, 0, 0444,
+ "portc", {Qportc, 0}, 0, 0444,
+ "nvram", {Qnvram, 0}, 0, 0660,
+};
+static long nrtc = nelem(rtcdir)-1; /* excludes nvram */
+
+static long readport(int, ulong, char*, long);
+
+static void
+rtcreset(void)
+{
+ IMM *io;
+ int n;
+
+ io = m->iomem;
+ io->rtcsck = KEEP_ALIVE_KEY;
+ n = (RTClevel<<8)|RTE;
+ if(m->clockgen == 5*MHz)
+ n |= R38K;
+ io->rtcsc = n;
+ io->rtcsck = ~KEEP_ALIVE_KEY;
+ if(conf.nvramsize != 0){
+ rtcdir[nrtc].length = conf.nvramsize;
+ nrtc++;
+ }
+}
+
+static Chan*
+rtcattach(char *spec)
+{
+ return devattach('r', spec);
+}
+
+static Walkqid*
+rtcwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ return devwalk(c, nc, name, nname, rtcdir, nrtc, devgen);
+}
+
+static int
+rtcstat(Chan *c, uchar *dp, int n)
+{
+ return devstat(c, dp, n, rtcdir, nrtc, devgen);
+}
+
+static Chan*
+rtcopen(Chan *c, int omode)
+{
+ return devopen(c, omode, rtcdir, nrtc, devgen);
+}
+
+static void
+rtcclose(Chan*)
+{
+}
+
+static long
+rtcread(Chan *c, void *buf, long n, vlong off)
+{
+ ulong offset = off;
+ ulong t;
+ char *b;
+
+ if(c->qid.type & QTDIR)
+ return devdirread(c, buf, n, rtcdir, nrtc, devgen);
+
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ t = m->iomem->rtc;
+ n = readnum(offset, buf, n, t, 12);
+ return n;
+ case Qswitch:
+ return readnum(offset, buf, n, archoptionsw(), 12);
+ case Qintstat:
+ b = malloc(2048);
+ if(waserror()){
+ free(b);
+ nexterror();
+ }
+ intrstats(b, 2048);
+ t = readstr(offset, buf, n, b);
+ poperror();
+ free(b);
+ return t;
+ case Qporta:
+ case Qportb:
+ case Qportc:
+ return readport(c->qid.path, offset, buf, n);
+ case Qnvram:
+ if(offset < 0 || offset >= conf.nvramsize)
+ return 0;
+ if(offset + n > conf.nvramsize)
+ n = conf.nvramsize - offset;
+ memmove(buf, (char*)conf.nvrambase+offset, n);
+ return n;
+ }
+ error(Egreg);
+ return 0; /* not reached */
+}
+
+static long
+rtcwrite(Chan *c, void *buf, long n, vlong off)
+{
+ ulong offset = off;
+ ulong secs;
+ char *cp, sbuf[32];
+ IMM *io;
+
+ switch((ulong)c->qid.path){
+ case Qrtc:
+ /*
+ * read the time
+ */
+ if(offset != 0 || n >= sizeof(sbuf)-1)
+ error(Ebadarg);
+ memmove(sbuf, buf, n);
+ sbuf[n] = '\0';
+ cp = sbuf;
+ while(*cp){
+ if(*cp>='0' && *cp<='9')
+ break;
+ cp++;
+ }
+ secs = strtoul(cp, 0, 0);
+ /*
+ * set it
+ */
+ io = ioplock();
+ io->rtck = KEEP_ALIVE_KEY;
+ io->rtc = secs;
+ io->rtck = ~KEEP_ALIVE_KEY;
+ iopunlock();
+ return n;
+ case Qnvram:
+ if(offset < 0 || offset >= conf.nvramsize)
+ return 0;
+ if(offset + n > conf.nvramsize)
+ n = conf.nvramsize - offset;
+ memmove((char*)conf.nvrambase+offset, buf, n);
+ return n;
+ }
+ error(Egreg);
+ return 0; /* not reached */
+}
+
+static long
+readport(int p, ulong offset, char *buf, long n)
+{
+ long t;
+ char *b;
+ int v[4], i;
+ IMM *io;
+
+ io = m->iomem;
+ for(i=0;i<nelem(v); i++)
+ v[i] = 0;
+ switch(p){
+ case Qporta:
+ v[0] = io->padat;
+ v[1] = io->padir;
+ v[2] = io->papar;
+ break;
+ case Qportb:
+ v[0] = io->pbdat;
+ v[1] = io->pbdir;
+ v[2] = io->pbpar;
+ break;
+ case Qportc:
+ v[0] = io->pcdat;
+ v[1] = io->pcdir;
+ v[2] = io->pcpar;
+ v[3] = io->pcso;
+ break;
+ }
+ b = malloc(READSTR);
+ if(waserror()){
+ free(b);
+ nexterror();
+ }
+ t = 0;
+ for(i=0; i<nelem(v); i++)
+ t += snprint(b+t, READSTR-t, " %8.8ux", v[i]);
+ t = readstr(offset, buf, n, b);
+ poperror();
+ free(b);
+ return t;
+}
+
+long
+rtctime(void)
+{
+ return m->iomem->rtc;
+}
+
+Dev rtcdevtab = {
+ 'r',
+ "rtc",
+
+ rtcreset,
+ devinit,
+ devshutdown,
+ rtcattach,
+ rtcwalk,
+ rtcstat,
+ rtcopen,
+ devcreate,
+ rtcclose,
+ rtcread,
+ devbread,
+ rtcwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};