xref: /inferno-os/os/mpc/devrtc.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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