Annotation of sys/arch/mvme88k/dev/nvram.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: nvram.c,v 1.29 2006/06/19 15:13:35 deraadt Exp $ */
2:
3: /*
4: * Copyright (c) 1995 Theo de Raadt
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27:
28: #include <sys/param.h>
29: #include <sys/kernel.h>
30: #include <sys/device.h>
31: #include <sys/malloc.h>
32: #include <sys/systm.h>
33: #include <sys/proc.h>
34: #include <sys/ioctl.h>
35: #include <sys/uio.h>
36:
37: #include <machine/autoconf.h>
38: #include <machine/bugio.h>
39: #include <machine/conf.h>
40: #include <machine/cpu.h>
41: #include <machine/mioctl.h>
42: #include <machine/psl.h>
43: #include <machine/vmparam.h>
44:
45: #include <uvm/uvm_param.h>
46:
47: #include <mvme88k/dev/memdevs.h>
48: #include <mvme88k/dev/nvramreg.h>
49: #include <mvme88k/dev/pcctworeg.h>
50:
51: struct nvramsoftc {
52: struct device sc_dev;
53: paddr_t sc_base;
54: bus_space_tag_t sc_iot;
55: bus_space_handle_t sc_ioh;
56: bus_addr_t sc_regs;
57: size_t sc_len;
58:
59: #ifdef MVME188
60: u_int8_t *sc_nvram;
61: #endif
62: };
63:
64: void nvramattach(struct device *, struct device *, void *);
65: int nvrammatch(struct device *, void *, void *);
66:
67: struct cfattach nvram_ca = {
68: sizeof(struct nvramsoftc), nvrammatch, nvramattach
69: };
70:
71: struct cfdriver nvram_cd = {
72: NULL, "nvram", DV_DULL
73: };
74:
75: u_long chiptotime(int, int, int, int, int, int);
76: int nvram188read(struct nvramsoftc *, struct uio *, int);
77: int nvram188write(struct nvramsoftc *, struct uio *, int);
78:
79: int
80: nvrammatch(parent, vcf, args)
81: struct device *parent;
82: void *vcf, *args;
83: {
84: struct confargs *ca = args;
85: bus_space_handle_t ioh;
86: int rc;
87:
88: if (bus_space_map(ca->ca_iot, ca->ca_paddr, PAGE_SIZE, 0, &ioh) != 0)
89: return (0);
90: rc = badaddr((vaddr_t)bus_space_vaddr(ca->ca_iot, ioh), 1) == 0;
91: bus_space_unmap(ca->ca_iot, ioh, PAGE_SIZE);
92: return (rc);
93: }
94:
95: void
96: nvramattach(parent, self, args)
97: struct device *parent, *self;
98: void *args;
99: {
100: struct confargs *ca = args;
101: struct nvramsoftc *sc = (struct nvramsoftc *)self;
102: bus_space_handle_t ioh;
103: vsize_t maplen;
104:
105: switch (brdtyp) {
106: #ifdef MVME188
107: case BRD_188:
108: sc->sc_len = MK48T02_SIZE;
109: maplen = sc->sc_len * 4;
110: sc->sc_regs = M188_NVRAM_TOD_OFF;
111: break;
112: #endif
113: default:
114: sc->sc_len = MK48T08_SIZE;
115: maplen = sc->sc_len;
116: sc->sc_regs = SBC_NVRAM_TOD_OFF;
117: break;
118: }
119:
120: sc->sc_iot = ca->ca_iot;
121: sc->sc_base = ca->ca_paddr;
122:
123: if (bus_space_map(sc->sc_iot, sc->sc_base, round_page(maplen),
124: BUS_SPACE_MAP_LINEAR, &ioh) != 0) {
125: printf(": can't map memory!\n");
126: return;
127: }
128:
129: sc->sc_ioh = ioh;
130:
131: printf(": MK48T0%d\n", sc->sc_len / 1024);
132: }
133:
134: /*
135: * Return the best possible estimate of the time in the timeval
136: * to which tvp points. We do this by returning the current time
137: * plus the amount of time since the last clock interrupt (clock.c:clkread).
138: *
139: * Check that this time is no less than any previously-reported time,
140: * which could happen around the time of a clock adjustment. Just for fun,
141: * we guarantee that the time will be greater than the value obtained by a
142: * previous call.
143: */
144: void
145: microtime(tvp)
146: struct timeval *tvp;
147: {
148: int s = splhigh();
149: static struct timeval lasttime;
150:
151: *tvp = time;
152: while (tvp->tv_usec >= 1000000) {
153: tvp->tv_sec++;
154: tvp->tv_usec -= 1000000;
155: }
156: if (tvp->tv_sec == lasttime.tv_sec &&
157: tvp->tv_usec <= lasttime.tv_usec &&
158: (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
159: tvp->tv_sec++;
160: tvp->tv_usec -= 1000000;
161: }
162: lasttime = *tvp;
163: splx(s);
164: }
165:
166: /*
167: * BCD to decimal and decimal to BCD.
168: */
169: #define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))
170: #define TOBCD(x) (((x) / 10 * 16) + ((x) % 10))
171:
172: #define SECYR (SECDAY * 365)
173: #define LEAPYEAR(y) (((y) & 3) == 0)
174:
175: /*
176: * This code is defunct after 2068.
177: * Will Unix still be here then??
178: */
179: const int dayyr[12] =
180: { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
181:
182: u_long
183: chiptotime(sec, min, hour, day, mon, year)
184: int sec, min, hour, day, mon, year;
185: {
186: int days, yr;
187:
188: sec = FROMBCD(sec);
189: min = FROMBCD(min);
190: hour = FROMBCD(hour);
191: day = FROMBCD(day);
192: mon = FROMBCD(mon);
193: year = FROMBCD(year) + YEAR0;
194:
195: /* simple sanity checks */
196: if (year>164 || mon<1 || mon>12 || day<1 || day>31)
197: return (0);
198: yr = 70;
199: days = 0;
200:
201: if (year < 70) { /* 2000 <= year */
202: for (; yr < 100; yr++) /* deal with first 30 years */
203: days += LEAPYEAR(yr) ? 366 : 365;
204: yr = 0;
205: }
206:
207: for (; yr < year; yr++) /* deal with years left */
208: days += LEAPYEAR(yr) ? 366 : 365;
209:
210: days += dayyr[mon - 1] + day - 1;
211:
212: if (LEAPYEAR(yr) && mon > 2)
213: days++;
214:
215: /* now have days since Jan 1, 1970; the rest is easy... */
216: return (days * SECDAY + hour * 3600 + min * 60 + sec);
217: }
218:
219: struct chiptime {
220: int sec;
221: int min;
222: int hour;
223: int wday;
224: int day;
225: int mon;
226: int year;
227: };
228:
229: void timetochip(struct chiptime *c);
230:
231: void
232: timetochip(c)
233: struct chiptime *c;
234: {
235: int t, t2, t3, now = time.tv_sec;
236:
237: /* January 1 1970 was a Thursday (4 in unix wdays) */
238: /* compute the days since the epoch */
239: t2 = now / SECDAY;
240:
241: t3 = (t2 + 4) % 7; /* day of week */
242: c->wday = TOBCD(t3 + 1);
243:
244: /* compute the year */
245: t = 69;
246: while (t2 >= 0) { /* whittle off years */
247: t3 = t2;
248: t++;
249: t2 -= LEAPYEAR(t) ? 366 : 365;
250: }
251: c->year = t;
252:
253: /* t3 = month + day; separate */
254: t = LEAPYEAR(t);
255: for (t2 = 1; t2 < 12; t2++)
256: if (t3 < (dayyr[t2] + ((t && (t2 > 1)) ? 1:0)))
257: break;
258:
259: /* t2 is month */
260: c->mon = t2;
261: c->day = t3 - dayyr[t2 - 1] + 1;
262: if (t && t2 > 2)
263: c->day--;
264:
265: /* the rest is easy */
266: t = now % SECDAY;
267: c->hour = t / 3600;
268: t %= 3600;
269: c->min = t / 60;
270: c->sec = t % 60;
271:
272: c->sec = TOBCD(c->sec);
273: c->min = TOBCD(c->min);
274: c->hour = TOBCD(c->hour);
275: c->day = TOBCD(c->day);
276: c->mon = TOBCD(c->mon);
277: c->year = TOBCD((c->year - YEAR0) % 100);
278: }
279:
280: /*
281: * Set up the system's time, given a `reasonable' time value.
282: */
283:
284: void
285: inittodr(base)
286: time_t base;
287: {
288: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0];
289: int sec, min, hour, day, mon, year;
290: int badbase = 0, waszero = base == 0;
291:
292: if (base < 35 * SECYR) {
293: /*
294: * If base is 0, assume filesystem time is just unknown
295: * in stead of preposterous. Don't bark.
296: */
297: if (base != 0)
298: printf("WARNING: preposterous time in file system\n");
299: /* not going to use it anyway, if the chip is readable */
300: base = 36 * SECYR + 109 * SECDAY + 22 * 3600;
301: badbase = 1;
302: }
303:
304: if (brdtyp == BRD_188) {
305: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
306: sc->sc_regs + (CLK_CSR << 2), CLK_READ |
307: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
308: sc->sc_regs + (CLK_CSR << 2)));
309: sec = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
310: sc->sc_regs + (CLK_SEC << 2)) & 0xff;
311: min = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
312: sc->sc_regs + (CLK_MIN << 2)) & 0xff;
313: hour = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
314: sc->sc_regs + (CLK_HOUR << 2)) & 0xff;
315: day = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
316: sc->sc_regs + (CLK_DAY << 2)) & 0xff;
317: mon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
318: sc->sc_regs + (CLK_MONTH << 2)) & 0xff;
319: year = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
320: sc->sc_regs + (CLK_YEAR << 2)) & 0xff;
321: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
322: sc->sc_regs + (CLK_CSR << 2),
323: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
324: sc->sc_regs + (CLK_CSR << 2)) & ~CLK_READ);
325: } else {
326: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
327: sc->sc_regs + CLK_CSR, CLK_READ |
328: bus_space_read_1(sc->sc_iot, sc->sc_ioh,
329: sc->sc_regs + CLK_CSR));
330: sec = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
331: sc->sc_regs + CLK_SEC);
332: min = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
333: sc->sc_regs + CLK_MIN);
334: hour = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
335: sc->sc_regs + CLK_HOUR);
336: day = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
337: sc->sc_regs + CLK_DAY);
338: mon = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
339: sc->sc_regs + CLK_MONTH);
340: year = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
341: sc->sc_regs + CLK_YEAR);
342: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
343: sc->sc_regs + CLK_CSR,
344: bus_space_read_1(sc->sc_iot, sc->sc_ioh,
345: sc->sc_regs + CLK_CSR) & ~CLK_READ);
346: }
347:
348: if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) {
349: printf("WARNING: bad date in nvram");
350: #ifdef DEBUG
351: printf("\nday = %d, mon = %d, year = %d, hour = %d, min = %d, sec = %d",
352: FROMBCD(day), FROMBCD(mon), FROMBCD(year) + YEAR0,
353: FROMBCD(hour), FROMBCD(min), FROMBCD(sec));
354: #endif
355: /*
356: * Believe the time in the file system for lack of
357: * anything better, resetting the clock.
358: */
359: time.tv_sec = base;
360: if (!badbase)
361: resettodr();
362: } else {
363: int deltat = time.tv_sec - base;
364:
365: if (deltat < 0)
366: deltat = -deltat;
367: if (waszero || deltat < 2 * SECDAY)
368: return;
369: printf("WARNING: clock %s %d days",
370: time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
371: }
372: printf(" -- CHECK AND RESET THE DATE!\n");
373: }
374:
375: /*
376: * Reset the clock based on the current time.
377: * Used when the current clock is preposterous, when the time is changed,
378: * and when rebooting. Do nothing if the time is not yet known, e.g.,
379: * when crashing during autoconfig.
380: */
381: void
382: resettodr()
383: {
384: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0];
385: struct chiptime c;
386:
387: if (!time.tv_sec || sc == NULL)
388: return;
389: timetochip(&c);
390:
391: if (brdtyp == BRD_188) {
392: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
393: sc->sc_regs + (CLK_CSR << 2), CLK_WRITE |
394: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
395: sc->sc_regs + (CLK_CSR << 2)));
396: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
397: sc->sc_regs + (CLK_SEC << 2), c.sec);
398: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
399: sc->sc_regs + (CLK_MIN << 2), c.min);
400: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
401: sc->sc_regs + (CLK_HOUR << 2), c.hour);
402: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
403: sc->sc_regs + (CLK_WDAY << 2), c.wday);
404: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
405: sc->sc_regs + (CLK_DAY << 2), c.day);
406: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
407: sc->sc_regs + (CLK_MONTH << 2), c.mon);
408: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
409: sc->sc_regs + (CLK_YEAR << 2), c.year);
410: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
411: sc->sc_regs + (CLK_CSR << 2),
412: bus_space_read_4(sc->sc_iot, sc->sc_ioh,
413: sc->sc_regs + (CLK_CSR << 2)) & ~CLK_WRITE);
414: } else {
415: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
416: sc->sc_regs + CLK_CSR, CLK_WRITE |
417: bus_space_read_1(sc->sc_iot, sc->sc_ioh,
418: sc->sc_regs + CLK_CSR));
419: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
420: sc->sc_regs + CLK_SEC, c.sec);
421: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
422: sc->sc_regs + CLK_MIN, c.min);
423: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
424: sc->sc_regs + CLK_HOUR, c.hour);
425: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
426: sc->sc_regs + CLK_WDAY, c.wday);
427: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
428: sc->sc_regs + CLK_DAY, c.day);
429: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
430: sc->sc_regs + CLK_MONTH, c.mon);
431: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
432: sc->sc_regs + CLK_YEAR, c.year);
433: bus_space_write_1(sc->sc_iot, sc->sc_ioh,
434: sc->sc_regs + CLK_CSR,
435: bus_space_read_1(sc->sc_iot, sc->sc_ioh,
436: sc->sc_regs + CLK_CSR) & ~CLK_WRITE);
437: }
438: }
439:
440: /*ARGSUSED*/
441: int
442: nvramopen(dev, flag, mode, p)
443: dev_t dev;
444: int flag, mode;
445: struct proc *p;
446: {
447: if (minor(dev) >= nvram_cd.cd_ndevs ||
448: nvram_cd.cd_devs[minor(dev)] == NULL)
449: return (ENODEV);
450:
451: return (0);
452: }
453:
454: /*ARGSUSED*/
455: int
456: nvramclose(dev, flag, mode, p)
457: dev_t dev;
458: int flag, mode;
459: struct proc *p;
460: {
461: /*
462: * On MVME188, it might be worth free()ing the NVRAM copy here.
463: */
464: return (0);
465: }
466:
467: /*ARGSUSED*/
468: int
469: nvramioctl(dev, cmd, data, flag, p)
470: dev_t dev;
471: u_long cmd;
472: caddr_t data;
473: int flag;
474: struct proc *p;
475: {
476: int unit = minor(dev);
477: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
478: int error = 0;
479:
480: switch (cmd) {
481: case MIOCGSIZ:
482: *(int *)data = sc->sc_len;
483: break;
484: default:
485: error = ENOTTY;
486: break;
487: }
488: return (error);
489: }
490:
491: /*ARGSUSED*/
492: int
493: nvramread(dev_t dev, struct uio *uio, int flags)
494: {
495: int unit = minor(dev);
496: struct nvramsoftc *sc = (struct nvramsoftc *)nvram_cd.cd_devs[unit];
497:
498: #ifdef MVME188
499: if (brdtyp == BRD_188)
500: return (nvram188read(sc, uio, flags));
501: #endif
502:
503: return (memdevrw(bus_space_vaddr(sc->sc_iot, sc->sc_ioh),
504: sc->sc_len, uio, flags));
505: }
506:
507: /*ARGSUSED*/
508: int
509: nvramwrite(dev_t dev, struct uio *uio, int flags)
510: {
511: int unit = minor(dev);
512: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
513:
514: #ifdef MVME188
515: if (brdtyp == BRD_188)
516: return (nvram188write(sc, uio, flags));
517: #endif
518:
519: return (memdevrw(bus_space_vaddr(sc->sc_iot, sc->sc_ioh),
520: sc->sc_len, uio, flags));
521: }
522:
523: paddr_t
524: nvrammmap(dev, off, prot)
525: dev_t dev;
526: off_t off;
527: int prot;
528: {
529: int unit = minor(dev);
530: struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
531:
532: if (minor(dev) != 0)
533: return (-1);
534:
535: #ifdef MVME188
536: /* disallow mmap on MVME188 due to non-linear layout */
537: if (brdtyp == BRD_188)
538: return (-1);
539: #endif
540:
541: /* allow access only in RAM */
542: if (off < 0 || off > sc->sc_len)
543: return (-1);
544: return (atop(sc->sc_base + off));
545: }
546:
547: #ifdef MVME188
548:
549: int read_nvram(struct nvramsoftc *);
550:
551: /*
552: * Build a local copy of the NVRAM contents.
553: */
554: int
555: read_nvram(struct nvramsoftc *sc)
556: {
557: u_int cnt;
558: u_int8_t *dest;
559: u_int32_t *src;
560:
561: if (sc->sc_nvram == NULL) {
562: sc->sc_nvram = (u_int8_t *)malloc(sc->sc_len, M_DEVBUF,
563: M_WAITOK | M_CANFAIL);
564: if (sc->sc_nvram == NULL)
565: return (EAGAIN);
566: }
567:
568: dest = sc->sc_nvram;
569: src = (u_int32_t *)bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
570: cnt = sc->sc_len;
571: while (cnt-- != 0)
572: *dest++ = (u_int8_t)*src++;
573:
574: return (0);
575: }
576:
577: /*
578: * Specific memdevrw wrappers to cope with the 188 design.
579: */
580:
581: int
582: nvram188read(struct nvramsoftc *sc, struct uio *uio, int flags)
583: {
584: int rc;
585:
586: /*
587: * Get a copy of the NVRAM contents.
588: */
589: rc = read_nvram(sc);
590: if (rc != 0)
591: return (rc);
592:
593: /*
594: * Move data from our NVRAM copy to the user.
595: */
596: return (memdevrw(sc->sc_nvram, sc->sc_len, uio, flags));
597: }
598:
599: int
600: nvram188write(struct nvramsoftc *sc, struct uio *uio, int flags)
601: {
602: u_int cnt;
603: u_int8_t *src;
604: u_int32_t *dest;
605: int rc;
606:
607: /*
608: * Get a copy of the NVRAM contents.
609: */
610: rc = read_nvram(sc);
611: if (rc != 0)
612: return (rc);
613:
614: /*
615: * Move data from the user to our NVRAM copy.
616: */
617: rc = memdevrw(sc->sc_nvram, sc->sc_len, uio, flags);
618: if (rc != 0) {
619: /* reset NVRAM copy contents */
620: read_nvram(sc);
621: return (rc);
622: }
623:
624: /*
625: * Update the NVRAM. This could be optimized by only working on
626: * the areas which have been modified by the user.
627: */
628: src = sc->sc_nvram;
629: dest = (u_int32_t *)bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
630: cnt = sc->sc_len;
631: while (cnt-- != 0) {
632: if ((*dest & 0xff) != *src)
633: *dest = (u_int32_t)*src;
634: dest++;
635: src++;
636: }
637:
638: return (0);
639: }
640: #endif
CVSweb