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