1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "../port/lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "../port/error.h"
7*74a4d8c2SCharles.Forsyth
8*74a4d8c2SCharles.Forsyth #include "io.h"
9*74a4d8c2SCharles.Forsyth
10*74a4d8c2SCharles.Forsyth /*
11*74a4d8c2SCharles.Forsyth * MPC8xx real time clock
12*74a4d8c2SCharles.Forsyth * optional board option switch
13*74a4d8c2SCharles.Forsyth * optional nvram
14*74a4d8c2SCharles.Forsyth * interrupt statistics
15*74a4d8c2SCharles.Forsyth */
16*74a4d8c2SCharles.Forsyth
17*74a4d8c2SCharles.Forsyth enum{
18*74a4d8c2SCharles.Forsyth Qdir,
19*74a4d8c2SCharles.Forsyth Qrtc,
20*74a4d8c2SCharles.Forsyth Qswitch,
21*74a4d8c2SCharles.Forsyth Qnvram,
22*74a4d8c2SCharles.Forsyth Qintstat,
23*74a4d8c2SCharles.Forsyth
24*74a4d8c2SCharles.Forsyth Qporta,
25*74a4d8c2SCharles.Forsyth Qportb,
26*74a4d8c2SCharles.Forsyth Qportc,
27*74a4d8c2SCharles.Forsyth
28*74a4d8c2SCharles.Forsyth /* sccr */
29*74a4d8c2SCharles.Forsyth RTDIV= 1<<24,
30*74a4d8c2SCharles.Forsyth RTSEL= 1<<23,
31*74a4d8c2SCharles.Forsyth
32*74a4d8c2SCharles.Forsyth /* rtcsc */
33*74a4d8c2SCharles.Forsyth RTE= 1<<0,
34*74a4d8c2SCharles.Forsyth R38K= 1<<4,
35*74a4d8c2SCharles.Forsyth };
36*74a4d8c2SCharles.Forsyth
37*74a4d8c2SCharles.Forsyth static QLock rtclock; /* mutex on clock operations */
38*74a4d8c2SCharles.Forsyth
39*74a4d8c2SCharles.Forsyth static Dirtab rtcdir[]={
40*74a4d8c2SCharles.Forsyth ".", {Qdir,0,QTDIR}, 0, 0555,
41*74a4d8c2SCharles.Forsyth "rtc", {Qrtc, 0}, 12, 0664,
42*74a4d8c2SCharles.Forsyth "switch", {Qswitch, 0}, 0, 0444,
43*74a4d8c2SCharles.Forsyth "intstat", {Qintstat, 0}, 0, 0444,
44*74a4d8c2SCharles.Forsyth "porta", {Qporta, 0}, 0, 0444,
45*74a4d8c2SCharles.Forsyth "portb", {Qportb, 0}, 0, 0444,
46*74a4d8c2SCharles.Forsyth "portc", {Qportc, 0}, 0, 0444,
47*74a4d8c2SCharles.Forsyth "nvram", {Qnvram, 0}, 0, 0660,
48*74a4d8c2SCharles.Forsyth };
49*74a4d8c2SCharles.Forsyth static long nrtc = nelem(rtcdir)-1; /* excludes nvram */
50*74a4d8c2SCharles.Forsyth
51*74a4d8c2SCharles.Forsyth static long readport(int, ulong, char*, long);
52*74a4d8c2SCharles.Forsyth
53*74a4d8c2SCharles.Forsyth static void
rtcreset(void)54*74a4d8c2SCharles.Forsyth rtcreset(void)
55*74a4d8c2SCharles.Forsyth {
56*74a4d8c2SCharles.Forsyth IMM *io;
57*74a4d8c2SCharles.Forsyth int n;
58*74a4d8c2SCharles.Forsyth
59*74a4d8c2SCharles.Forsyth io = m->iomem;
60*74a4d8c2SCharles.Forsyth io->rtcsck = KEEP_ALIVE_KEY;
61*74a4d8c2SCharles.Forsyth n = (RTClevel<<8)|RTE;
62*74a4d8c2SCharles.Forsyth if(m->clockgen == 5*MHz)
63*74a4d8c2SCharles.Forsyth n |= R38K;
64*74a4d8c2SCharles.Forsyth io->rtcsc = n;
65*74a4d8c2SCharles.Forsyth io->rtcsck = ~KEEP_ALIVE_KEY;
66*74a4d8c2SCharles.Forsyth if(conf.nvramsize != 0){
67*74a4d8c2SCharles.Forsyth rtcdir[nrtc].length = conf.nvramsize;
68*74a4d8c2SCharles.Forsyth nrtc++;
69*74a4d8c2SCharles.Forsyth }
70*74a4d8c2SCharles.Forsyth }
71*74a4d8c2SCharles.Forsyth
72*74a4d8c2SCharles.Forsyth static Chan*
rtcattach(char * spec)73*74a4d8c2SCharles.Forsyth rtcattach(char *spec)
74*74a4d8c2SCharles.Forsyth {
75*74a4d8c2SCharles.Forsyth return devattach('r', spec);
76*74a4d8c2SCharles.Forsyth }
77*74a4d8c2SCharles.Forsyth
78*74a4d8c2SCharles.Forsyth static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)79*74a4d8c2SCharles.Forsyth rtcwalk(Chan *c, Chan *nc, char **name, int nname)
80*74a4d8c2SCharles.Forsyth {
81*74a4d8c2SCharles.Forsyth return devwalk(c, nc, name, nname, rtcdir, nrtc, devgen);
82*74a4d8c2SCharles.Forsyth }
83*74a4d8c2SCharles.Forsyth
84*74a4d8c2SCharles.Forsyth static int
rtcstat(Chan * c,uchar * dp,int n)85*74a4d8c2SCharles.Forsyth rtcstat(Chan *c, uchar *dp, int n)
86*74a4d8c2SCharles.Forsyth {
87*74a4d8c2SCharles.Forsyth return devstat(c, dp, n, rtcdir, nrtc, devgen);
88*74a4d8c2SCharles.Forsyth }
89*74a4d8c2SCharles.Forsyth
90*74a4d8c2SCharles.Forsyth static Chan*
rtcopen(Chan * c,int omode)91*74a4d8c2SCharles.Forsyth rtcopen(Chan *c, int omode)
92*74a4d8c2SCharles.Forsyth {
93*74a4d8c2SCharles.Forsyth return devopen(c, omode, rtcdir, nrtc, devgen);
94*74a4d8c2SCharles.Forsyth }
95*74a4d8c2SCharles.Forsyth
96*74a4d8c2SCharles.Forsyth static void
rtcclose(Chan *)97*74a4d8c2SCharles.Forsyth rtcclose(Chan*)
98*74a4d8c2SCharles.Forsyth {
99*74a4d8c2SCharles.Forsyth }
100*74a4d8c2SCharles.Forsyth
101*74a4d8c2SCharles.Forsyth static long
rtcread(Chan * c,void * buf,long n,vlong off)102*74a4d8c2SCharles.Forsyth rtcread(Chan *c, void *buf, long n, vlong off)
103*74a4d8c2SCharles.Forsyth {
104*74a4d8c2SCharles.Forsyth ulong offset = off;
105*74a4d8c2SCharles.Forsyth ulong t;
106*74a4d8c2SCharles.Forsyth char *b;
107*74a4d8c2SCharles.Forsyth
108*74a4d8c2SCharles.Forsyth if(c->qid.type & QTDIR)
109*74a4d8c2SCharles.Forsyth return devdirread(c, buf, n, rtcdir, nrtc, devgen);
110*74a4d8c2SCharles.Forsyth
111*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
112*74a4d8c2SCharles.Forsyth case Qrtc:
113*74a4d8c2SCharles.Forsyth t = m->iomem->rtc;
114*74a4d8c2SCharles.Forsyth n = readnum(offset, buf, n, t, 12);
115*74a4d8c2SCharles.Forsyth return n;
116*74a4d8c2SCharles.Forsyth case Qswitch:
117*74a4d8c2SCharles.Forsyth return readnum(offset, buf, n, archoptionsw(), 12);
118*74a4d8c2SCharles.Forsyth case Qintstat:
119*74a4d8c2SCharles.Forsyth b = malloc(2048);
120*74a4d8c2SCharles.Forsyth if(waserror()){
121*74a4d8c2SCharles.Forsyth free(b);
122*74a4d8c2SCharles.Forsyth nexterror();
123*74a4d8c2SCharles.Forsyth }
124*74a4d8c2SCharles.Forsyth intrstats(b, 2048);
125*74a4d8c2SCharles.Forsyth t = readstr(offset, buf, n, b);
126*74a4d8c2SCharles.Forsyth poperror();
127*74a4d8c2SCharles.Forsyth free(b);
128*74a4d8c2SCharles.Forsyth return t;
129*74a4d8c2SCharles.Forsyth case Qporta:
130*74a4d8c2SCharles.Forsyth case Qportb:
131*74a4d8c2SCharles.Forsyth case Qportc:
132*74a4d8c2SCharles.Forsyth return readport(c->qid.path, offset, buf, n);
133*74a4d8c2SCharles.Forsyth case Qnvram:
134*74a4d8c2SCharles.Forsyth if(offset < 0 || offset >= conf.nvramsize)
135*74a4d8c2SCharles.Forsyth return 0;
136*74a4d8c2SCharles.Forsyth if(offset + n > conf.nvramsize)
137*74a4d8c2SCharles.Forsyth n = conf.nvramsize - offset;
138*74a4d8c2SCharles.Forsyth memmove(buf, (char*)conf.nvrambase+offset, n);
139*74a4d8c2SCharles.Forsyth return n;
140*74a4d8c2SCharles.Forsyth }
141*74a4d8c2SCharles.Forsyth error(Egreg);
142*74a4d8c2SCharles.Forsyth return 0; /* not reached */
143*74a4d8c2SCharles.Forsyth }
144*74a4d8c2SCharles.Forsyth
145*74a4d8c2SCharles.Forsyth static long
rtcwrite(Chan * c,void * buf,long n,vlong off)146*74a4d8c2SCharles.Forsyth rtcwrite(Chan *c, void *buf, long n, vlong off)
147*74a4d8c2SCharles.Forsyth {
148*74a4d8c2SCharles.Forsyth ulong offset = off;
149*74a4d8c2SCharles.Forsyth ulong secs;
150*74a4d8c2SCharles.Forsyth char *cp, sbuf[32];
151*74a4d8c2SCharles.Forsyth IMM *io;
152*74a4d8c2SCharles.Forsyth
153*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
154*74a4d8c2SCharles.Forsyth case Qrtc:
155*74a4d8c2SCharles.Forsyth /*
156*74a4d8c2SCharles.Forsyth * read the time
157*74a4d8c2SCharles.Forsyth */
158*74a4d8c2SCharles.Forsyth if(offset != 0 || n >= sizeof(sbuf)-1)
159*74a4d8c2SCharles.Forsyth error(Ebadarg);
160*74a4d8c2SCharles.Forsyth memmove(sbuf, buf, n);
161*74a4d8c2SCharles.Forsyth sbuf[n] = '\0';
162*74a4d8c2SCharles.Forsyth cp = sbuf;
163*74a4d8c2SCharles.Forsyth while(*cp){
164*74a4d8c2SCharles.Forsyth if(*cp>='0' && *cp<='9')
165*74a4d8c2SCharles.Forsyth break;
166*74a4d8c2SCharles.Forsyth cp++;
167*74a4d8c2SCharles.Forsyth }
168*74a4d8c2SCharles.Forsyth secs = strtoul(cp, 0, 0);
169*74a4d8c2SCharles.Forsyth /*
170*74a4d8c2SCharles.Forsyth * set it
171*74a4d8c2SCharles.Forsyth */
172*74a4d8c2SCharles.Forsyth io = ioplock();
173*74a4d8c2SCharles.Forsyth io->rtck = KEEP_ALIVE_KEY;
174*74a4d8c2SCharles.Forsyth io->rtc = secs;
175*74a4d8c2SCharles.Forsyth io->rtck = ~KEEP_ALIVE_KEY;
176*74a4d8c2SCharles.Forsyth iopunlock();
177*74a4d8c2SCharles.Forsyth return n;
178*74a4d8c2SCharles.Forsyth case Qnvram:
179*74a4d8c2SCharles.Forsyth if(offset < 0 || offset >= conf.nvramsize)
180*74a4d8c2SCharles.Forsyth return 0;
181*74a4d8c2SCharles.Forsyth if(offset + n > conf.nvramsize)
182*74a4d8c2SCharles.Forsyth n = conf.nvramsize - offset;
183*74a4d8c2SCharles.Forsyth memmove((char*)conf.nvrambase+offset, buf, n);
184*74a4d8c2SCharles.Forsyth return n;
185*74a4d8c2SCharles.Forsyth }
186*74a4d8c2SCharles.Forsyth error(Egreg);
187*74a4d8c2SCharles.Forsyth return 0; /* not reached */
188*74a4d8c2SCharles.Forsyth }
189*74a4d8c2SCharles.Forsyth
190*74a4d8c2SCharles.Forsyth static long
readport(int p,ulong offset,char * buf,long n)191*74a4d8c2SCharles.Forsyth readport(int p, ulong offset, char *buf, long n)
192*74a4d8c2SCharles.Forsyth {
193*74a4d8c2SCharles.Forsyth long t;
194*74a4d8c2SCharles.Forsyth char *b;
195*74a4d8c2SCharles.Forsyth int v[4], i;
196*74a4d8c2SCharles.Forsyth IMM *io;
197*74a4d8c2SCharles.Forsyth
198*74a4d8c2SCharles.Forsyth io = m->iomem;
199*74a4d8c2SCharles.Forsyth for(i=0;i<nelem(v); i++)
200*74a4d8c2SCharles.Forsyth v[i] = 0;
201*74a4d8c2SCharles.Forsyth switch(p){
202*74a4d8c2SCharles.Forsyth case Qporta:
203*74a4d8c2SCharles.Forsyth v[0] = io->padat;
204*74a4d8c2SCharles.Forsyth v[1] = io->padir;
205*74a4d8c2SCharles.Forsyth v[2] = io->papar;
206*74a4d8c2SCharles.Forsyth break;
207*74a4d8c2SCharles.Forsyth case Qportb:
208*74a4d8c2SCharles.Forsyth v[0] = io->pbdat;
209*74a4d8c2SCharles.Forsyth v[1] = io->pbdir;
210*74a4d8c2SCharles.Forsyth v[2] = io->pbpar;
211*74a4d8c2SCharles.Forsyth break;
212*74a4d8c2SCharles.Forsyth case Qportc:
213*74a4d8c2SCharles.Forsyth v[0] = io->pcdat;
214*74a4d8c2SCharles.Forsyth v[1] = io->pcdir;
215*74a4d8c2SCharles.Forsyth v[2] = io->pcpar;
216*74a4d8c2SCharles.Forsyth v[3] = io->pcso;
217*74a4d8c2SCharles.Forsyth break;
218*74a4d8c2SCharles.Forsyth }
219*74a4d8c2SCharles.Forsyth b = malloc(READSTR);
220*74a4d8c2SCharles.Forsyth if(waserror()){
221*74a4d8c2SCharles.Forsyth free(b);
222*74a4d8c2SCharles.Forsyth nexterror();
223*74a4d8c2SCharles.Forsyth }
224*74a4d8c2SCharles.Forsyth t = 0;
225*74a4d8c2SCharles.Forsyth for(i=0; i<nelem(v); i++)
226*74a4d8c2SCharles.Forsyth t += snprint(b+t, READSTR-t, " %8.8ux", v[i]);
227*74a4d8c2SCharles.Forsyth t = readstr(offset, buf, n, b);
228*74a4d8c2SCharles.Forsyth poperror();
229*74a4d8c2SCharles.Forsyth free(b);
230*74a4d8c2SCharles.Forsyth return t;
231*74a4d8c2SCharles.Forsyth }
232*74a4d8c2SCharles.Forsyth
233*74a4d8c2SCharles.Forsyth long
rtctime(void)234*74a4d8c2SCharles.Forsyth rtctime(void)
235*74a4d8c2SCharles.Forsyth {
236*74a4d8c2SCharles.Forsyth return m->iomem->rtc;
237*74a4d8c2SCharles.Forsyth }
238*74a4d8c2SCharles.Forsyth
239*74a4d8c2SCharles.Forsyth Dev rtcdevtab = {
240*74a4d8c2SCharles.Forsyth 'r',
241*74a4d8c2SCharles.Forsyth "rtc",
242*74a4d8c2SCharles.Forsyth
243*74a4d8c2SCharles.Forsyth rtcreset,
244*74a4d8c2SCharles.Forsyth devinit,
245*74a4d8c2SCharles.Forsyth devshutdown,
246*74a4d8c2SCharles.Forsyth rtcattach,
247*74a4d8c2SCharles.Forsyth rtcwalk,
248*74a4d8c2SCharles.Forsyth rtcstat,
249*74a4d8c2SCharles.Forsyth rtcopen,
250*74a4d8c2SCharles.Forsyth devcreate,
251*74a4d8c2SCharles.Forsyth rtcclose,
252*74a4d8c2SCharles.Forsyth rtcread,
253*74a4d8c2SCharles.Forsyth devbread,
254*74a4d8c2SCharles.Forsyth rtcwrite,
255*74a4d8c2SCharles.Forsyth devbwrite,
256*74a4d8c2SCharles.Forsyth devremove,
257*74a4d8c2SCharles.Forsyth devwstat,
258*74a4d8c2SCharles.Forsyth };
259