Annotation of sys/arch/luna88k/dev/timekeeper.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: timekeeper.c,v 1.3 2004/08/18 13:29:46 aoyama Exp $ */
! 2: /* $NetBSD: timekeeper.c,v 1.1 2000/01/05 08:48:56 nisimura Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Tohru Nishimura.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/device.h>
! 43: #include <sys/kernel.h>
! 44: #include <sys/evcount.h>
! 45:
! 46: #include <machine/autoconf.h>
! 47: #include <machine/board.h> /* machtype value */
! 48: #include <machine/cpu.h>
! 49:
! 50: #include <dev/clock_subr.h>
! 51:
! 52: #include <luna88k/luna88k/clockvar.h>
! 53: #include <luna88k/dev/timekeeper.h>
! 54:
! 55: #define MK_YEAR0 1970 /* year offset of MK */
! 56: #define DS_YEAR0 1990 /* year offset of DS */
! 57:
! 58: struct timekeeper_softc {
! 59: struct device sc_dev;
! 60: void *sc_clock, *sc_nvram;
! 61: int sc_nvramsize;
! 62: struct evcount sc_count;
! 63: };
! 64:
! 65: /*
! 66: * BCD to decimal and decimal to BCD.
! 67: */
! 68: #define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))
! 69: #define TOBCD(x) (((x) / 10 * 16) + ((x) % 10))
! 70:
! 71: int clock_match(struct device *, void *, void *);
! 72: void clock_attach(struct device *, struct device *, void *);
! 73:
! 74: struct cfattach clock_ca = {
! 75: sizeof (struct timekeeper_softc), clock_match, clock_attach
! 76: };
! 77:
! 78: struct cfdriver clock_cd = {
! 79: NULL, "clock", DV_DULL
! 80: };
! 81:
! 82: void mkclock_get(struct device *, time_t, struct clock_ymdhms *);
! 83: void mkclock_set(struct device *, struct clock_ymdhms *);
! 84: void dsclock_get(struct device *, time_t, struct clock_ymdhms *);
! 85: void dsclock_set(struct device *, struct clock_ymdhms *);
! 86:
! 87: const struct clockfns mkclock_clockfns = {
! 88: NULL /* never used */, mkclock_get, mkclock_set,
! 89: };
! 90:
! 91: const struct clockfns dsclock_clockfns = {
! 92: NULL /* never used */, dsclock_get, dsclock_set,
! 93: };
! 94:
! 95: int
! 96: clock_match(parent, match, aux)
! 97: struct device *parent;
! 98: void *match, *aux;
! 99: {
! 100: struct mainbus_attach_args *ma = aux;
! 101:
! 102: if (strcmp(ma->ma_name, clock_cd.cd_name))
! 103: return 0;
! 104: return 1;
! 105: }
! 106:
! 107: extern int machtype; /* in machdep.c */
! 108:
! 109: void
! 110: clock_attach(parent, self, aux)
! 111: struct device *parent, *self;
! 112: void *aux;
! 113: {
! 114: struct timekeeper_softc *sc = (void *)self;
! 115: struct mainbus_attach_args *ma = aux;
! 116: const struct clockfns *clockwork;
! 117:
! 118: switch (machtype) {
! 119: default:
! 120: case LUNA_88K: /* Mostek MK48T02 */
! 121: sc->sc_clock = (void *)(ma->ma_addr + 2040);
! 122: sc->sc_nvram = (void *)ma->ma_addr;
! 123: sc->sc_nvramsize = 2040;
! 124: clockwork = &mkclock_clockfns;
! 125: printf(": MK48T02\n");
! 126: break;
! 127: case LUNA_88K2: /* Dallas DS1397 */
! 128: sc->sc_clock = (void *)ma->ma_addr;
! 129: sc->sc_nvram = (void *)(ma->ma_addr + 50);
! 130: sc->sc_nvramsize = 50;
! 131: clockwork = &dsclock_clockfns;
! 132: printf(": DS1397\n");
! 133: break;
! 134: }
! 135:
! 136: evcount_attach(&sc->sc_count, self->dv_xname, (void *)&ma->ma_ilvl, &evcount_intr);
! 137:
! 138: clockattach(&sc->sc_dev, clockwork, &sc->sc_count);
! 139: }
! 140:
! 141: /*
! 142: * Get the time of day, based on the clock's value and/or the base value.
! 143: */
! 144: void
! 145: mkclock_get(dev, base, dt)
! 146: struct device *dev;
! 147: time_t base;
! 148: struct clock_ymdhms *dt;
! 149: {
! 150: struct timekeeper_softc *sc = (void *)dev;
! 151: volatile u_int8_t *chiptime = (void *)sc->sc_clock;
! 152: int s;
! 153:
! 154: s = splclock();
! 155: chiptime[MK_CSR] |= MK_CSR_READ; /* enable read (stop time) */
! 156: dt->dt_sec = FROMBCD(chiptime[MK_SEC]);
! 157: dt->dt_min = FROMBCD(chiptime[MK_MIN]);
! 158: dt->dt_hour = FROMBCD(chiptime[MK_HOUR]);
! 159: dt->dt_wday = FROMBCD(chiptime[MK_DOW]);
! 160: dt->dt_day = FROMBCD(chiptime[MK_DOM]);
! 161: dt->dt_mon = FROMBCD(chiptime[MK_MONTH]);
! 162: dt->dt_year = FROMBCD(chiptime[MK_YEAR]) + MK_YEAR0;
! 163: chiptime[MK_CSR] &= ~MK_CSR_READ; /* time wears on */
! 164: splx(s);
! 165: #ifdef TIMEKEEPER_DEBUG
! 166: printf("get %d/%d/%d %d:%d:%d\n",
! 167: dt->dt_year, dt->dt_mon, dt->dt_day,
! 168: dt->dt_hour, dt->dt_min, dt->dt_sec);
! 169: #endif
! 170: }
! 171:
! 172: /*
! 173: * Reset the TODR based on the time value.
! 174: */
! 175: void
! 176: mkclock_set(dev, dt)
! 177: struct device *dev;
! 178: struct clock_ymdhms *dt;
! 179: {
! 180: struct timekeeper_softc *sc = (void *)dev;
! 181: volatile u_int8_t *chiptime = (void *)sc->sc_clock;
! 182: volatile u_int8_t *stamp = (u_int8_t *)sc->sc_nvram + 0x10;
! 183: int s;
! 184:
! 185: s = splclock();
! 186: chiptime[MK_CSR] |= MK_CSR_WRITE; /* enable write */
! 187: chiptime[MK_SEC] = TOBCD(dt->dt_sec);
! 188: chiptime[MK_MIN] = TOBCD(dt->dt_min);
! 189: chiptime[MK_HOUR] = TOBCD(dt->dt_hour);
! 190: chiptime[MK_DOW] = TOBCD(dt->dt_wday);
! 191: chiptime[MK_DOM] = TOBCD(dt->dt_day);
! 192: chiptime[MK_MONTH] = TOBCD(dt->dt_mon);
! 193: chiptime[MK_YEAR] = TOBCD(dt->dt_year - MK_YEAR0);
! 194: chiptime[MK_CSR] &= ~MK_CSR_WRITE; /* load them up */
! 195: splx(s);
! 196: #ifdef TIMEKEEPER_DEBUG
! 197: printf("set %d/%d/%d %d:%d:%d\n",
! 198: dt->dt_year, dt->dt_mon, dt->dt_day,
! 199: dt->dt_hour, dt->dt_min, dt->dt_sec);
! 200: #endif
! 201:
! 202: stamp[0] = 'R'; stamp[1] = 'T'; stamp[2] = 'C'; stamp[3] = '\0';
! 203: }
! 204:
! 205: #define _DS_GET(off, data) \
! 206: do { *chiptime = (off); (u_int8_t)(data) = (*chipdata); } while (0)
! 207: #define _DS_SET(off, data) \
! 208: do { *chiptime = (off); *chipdata = (u_int8_t)(data); } while (0)
! 209: #define _DS_GET_BCD(off, data) \
! 210: do { \
! 211: u_int8_t c; \
! 212: *chiptime = (off); \
! 213: c = *chipdata; (u_int8_t)(data) = FROMBCD(c); \
! 214: } while (0)
! 215: #define _DS_SET_BCD(off, data) \
! 216: do { \
! 217: *chiptime = (off); \
! 218: *chipdata = TOBCD((u_int8_t)(data)); \
! 219: } while (0)
! 220:
! 221: /*
! 222: * Get the time of day, based on the clock's value and/or the base value.
! 223: */
! 224: void
! 225: dsclock_get(dev, base, dt)
! 226: struct device *dev;
! 227: time_t base;
! 228: struct clock_ymdhms *dt;
! 229: {
! 230: struct timekeeper_softc *sc = (void *)dev;
! 231: volatile u_int8_t *chiptime = (void *)sc->sc_clock;
! 232: volatile u_int8_t *chipdata = (void *)(sc->sc_clock + 1);
! 233: int s;
! 234: u_int8_t c;
! 235:
! 236: s = splclock();
! 237:
! 238: /* specify 24hr and BCD mode */
! 239: _DS_GET(DS_REGB, c);
! 240: c |= DS_REGB_24HR;
! 241: c &= ~DS_REGB_BINARY;
! 242: _DS_SET(DS_REGB, c);
! 243:
! 244: /* update in progress; spin loop */
! 245: *chiptime = DS_REGA;
! 246: while (*chipdata & DS_REGA_UIP)
! 247: ;
! 248:
! 249: _DS_GET_BCD(DS_SEC, dt->dt_sec);
! 250: _DS_GET_BCD(DS_MIN, dt->dt_min);
! 251: _DS_GET_BCD(DS_HOUR, dt->dt_hour);
! 252: _DS_GET_BCD(DS_DOW, dt->dt_wday);
! 253: _DS_GET_BCD(DS_DOM, dt->dt_day);
! 254: _DS_GET_BCD(DS_MONTH, dt->dt_mon);
! 255: _DS_GET_BCD(DS_YEAR, dt->dt_year);
! 256: dt->dt_year += DS_YEAR0;
! 257:
! 258: splx(s);
! 259:
! 260: #ifdef TIMEKEEPER_DEBUG
! 261: printf("get %d/%d/%d %d:%d:%d\n",
! 262: dt->dt_year, dt->dt_mon, dt->dt_day,
! 263: dt->dt_hour, dt->dt_min, dt->dt_sec);
! 264: #endif
! 265: }
! 266:
! 267: /*
! 268: * Reset the TODR based on the time value.
! 269: */
! 270: void
! 271: dsclock_set(dev, dt)
! 272: struct device *dev;
! 273: struct clock_ymdhms *dt;
! 274: {
! 275: struct timekeeper_softc *sc = (void *)dev;
! 276: volatile u_int8_t *chiptime = (void *)sc->sc_clock;
! 277: volatile u_int8_t *chipdata = (void *)(sc->sc_clock + 1);
! 278: int s;
! 279: u_int8_t c;
! 280:
! 281: s = splclock();
! 282:
! 283: /* enable write */
! 284: _DS_GET(DS_REGB, c);
! 285: c |= DS_REGB_SET;
! 286: _DS_SET(DS_REGB, c);
! 287:
! 288: _DS_SET_BCD(DS_SEC, dt->dt_sec);
! 289: _DS_SET_BCD(DS_MIN, dt->dt_min);
! 290: _DS_SET_BCD(DS_HOUR, dt->dt_hour);
! 291: _DS_SET_BCD(DS_DOW, dt->dt_wday);
! 292: _DS_SET_BCD(DS_DOM, dt->dt_day);
! 293: _DS_SET_BCD(DS_MONTH, dt->dt_mon);
! 294: _DS_SET_BCD(DS_YEAR, dt->dt_year - DS_YEAR0);
! 295:
! 296: _DS_GET(DS_REGB, c);
! 297: c &= ~DS_REGB_SET;
! 298: _DS_SET(DS_REGB, c);
! 299:
! 300: splx(s);
! 301:
! 302: #ifdef TIMEKEEPER_DEBUG
! 303: printf("set %d/%d/%d %d:%d:%d\n",
! 304: dt->dt_year, dt->dt_mon, dt->dt_day,
! 305: dt->dt_hour, dt->dt_min, dt->dt_sec);
! 306: #endif
! 307: }
CVSweb