Annotation of sys/arch/luna88k/dev/timekeeper.c, Revision 1.1.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