timekeeper.c revision 1.8
1/* $OpenBSD: timekeeper.c,v 1.8 2013/11/12 13:56:23 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/device.h> 36#include <sys/kernel.h> 37#include <sys/evcount.h> 38 39#include <machine/autoconf.h> 40#include <machine/board.h> /* machtype value */ 41#include <machine/cpu.h> 42 43#include <dev/clock_subr.h> 44 45#include <luna88k/luna88k/clockvar.h> 46#include <luna88k/dev/timekeeper.h> 47 48#define MK_YEAR0 1970 /* year offset of MK */ 49#define DS_YEAR0 1990 /* year offset of DS */ 50 51struct timekeeper_softc { 52 struct device sc_dev; 53 void *sc_clock, *sc_nvram; 54 int sc_nvramsize; 55 struct evcount sc_count; 56}; 57 58/* 59 * BCD to decimal and decimal to BCD. 60 */ 61#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf)) 62#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10)) 63 64int clock_match(struct device *, void *, void *); 65void clock_attach(struct device *, struct device *, void *); 66 67struct cfattach clock_ca = { 68 sizeof (struct timekeeper_softc), clock_match, clock_attach 69}; 70 71struct cfdriver clock_cd = { 72 NULL, "clock", DV_DULL 73}; 74 75void mkclock_get(struct device *, time_t, struct clock_ymdhms *); 76void mkclock_set(struct device *, struct clock_ymdhms *); 77void dsclock_get(struct device *, time_t, struct clock_ymdhms *); 78void dsclock_set(struct device *, struct clock_ymdhms *); 79 80const struct clockfns mkclock_clockfns = { 81 NULL /* never used */, mkclock_get, mkclock_set, 82}; 83 84const struct clockfns dsclock_clockfns = { 85 NULL /* never used */, dsclock_get, dsclock_set, 86}; 87 88int 89clock_match(parent, match, aux) 90 struct device *parent; 91 void *match, *aux; 92{ 93 struct mainbus_attach_args *ma = aux; 94 95 if (strcmp(ma->ma_name, clock_cd.cd_name)) 96 return 0; 97 return 1; 98} 99 100extern int machtype; /* in machdep.c */ 101 102void 103clock_attach(parent, self, aux) 104 struct device *parent, *self; 105 void *aux; 106{ 107 struct timekeeper_softc *sc = (void *)self; 108 struct mainbus_attach_args *ma = aux; 109 const struct clockfns *clockwork; 110 111 switch (machtype) { 112 default: 113 case LUNA_88K: /* Mostek MK48T02 */ 114 sc->sc_clock = (void *)(ma->ma_addr + MK_NVRAM_SPACE); 115 sc->sc_nvram = (void *)ma->ma_addr; 116 sc->sc_nvramsize = MK_NVRAM_SPACE; 117 clockwork = &mkclock_clockfns; 118 printf(": MK48T02\n"); 119 break; 120 case LUNA_88K2: /* Dallas DS1397 */ 121 sc->sc_clock = (void *)ma->ma_addr; 122 sc->sc_nvram = (void *)(ma->ma_addr + 50); 123 sc->sc_nvramsize = 50; 124 clockwork = &dsclock_clockfns; 125 printf(": DS1397\n"); 126 break; 127 } 128 129 evcount_attach(&sc->sc_count, self->dv_xname, &ma->ma_ilvl); 130 131 clockattach(&sc->sc_dev, clockwork, &sc->sc_count); 132} 133 134/* 135 * On LUNA-88K, NVRAM contents and Timekeeper registers are mapped on the 136 * most significant byte of each 32bit word. (i.e. 4-bytes stride) 137 * 138 * Get the time of day, based on the clock's value and/or the base value. 139 */ 140void 141mkclock_get(dev, base, dt) 142 struct device *dev; 143 time_t base; 144 struct clock_ymdhms *dt; 145{ 146 struct timekeeper_softc *sc = (void *)dev; 147 volatile u_int32_t *chiptime = (void *)sc->sc_clock; 148 int s; 149 150 s = splclock(); 151 152 /* enable read (stop time) */ 153 chiptime[MK_CSR] |= (MK_CSR_READ << 24); 154 155 dt->dt_sec = FROMBCD(chiptime[MK_SEC] >> 24); 156 dt->dt_min = FROMBCD(chiptime[MK_MIN] >> 24); 157 dt->dt_hour = FROMBCD(chiptime[MK_HOUR] >> 24); 158 dt->dt_wday = FROMBCD(chiptime[MK_DOW] >> 24); 159 dt->dt_day = FROMBCD(chiptime[MK_DOM] >> 24); 160 dt->dt_mon = FROMBCD(chiptime[MK_MONTH] >> 24); 161 dt->dt_year = FROMBCD(chiptime[MK_YEAR] >> 24); 162 163 chiptime[MK_CSR] &= (~MK_CSR_READ << 24); /* time wears on */ 164 165 /* UniOS-Mach doesn't set the correct BCD year after Y2K */ 166 if (dt->dt_year > 100) dt->dt_year -= (MK_YEAR0 % 100); 167 168 dt->dt_year += MK_YEAR0; 169 splx(s); 170#ifdef TIMEKEEPER_DEBUG 171 printf("get %02d/%02d/%02d %02d:%02d:%02d\n", 172 dt->dt_year, dt->dt_mon, dt->dt_day, 173 dt->dt_hour, dt->dt_min, dt->dt_sec); 174#endif 175} 176 177/* 178 * Reset the TODR based on the time value. 179 */ 180void 181mkclock_set(dev, dt) 182 struct device *dev; 183 struct clock_ymdhms *dt; 184{ 185 struct timekeeper_softc *sc = (void *)dev; 186 volatile u_int32_t *chiptime = (void *)sc->sc_clock; 187 volatile u_int32_t *stamp = (void *)(sc->sc_nvram + (4 * 0x10)); 188 int s; 189 190 s = splclock(); 191 chiptime[MK_CSR] |= (MK_CSR_WRITE << 24); /* enable write */ 192 193 chiptime[MK_SEC] = TOBCD(dt->dt_sec) << 24; 194 chiptime[MK_MIN] = TOBCD(dt->dt_min) << 24; 195 chiptime[MK_HOUR] = TOBCD(dt->dt_hour) << 24; 196 chiptime[MK_DOW] = TOBCD(dt->dt_wday) << 24; 197 chiptime[MK_DOM] = TOBCD(dt->dt_day) << 24; 198 chiptime[MK_MONTH] = TOBCD(dt->dt_mon) << 24; 199 /* XXX: We don't consider UniOS-Mach Y2K problem */ 200 chiptime[MK_YEAR] = TOBCD(dt->dt_year - MK_YEAR0) << 24; 201 202 chiptime[MK_CSR] &= (~MK_CSR_WRITE << 24); /* load them up */ 203 splx(s); 204#ifdef TIMEKEEPER_DEBUG 205 printf("set %02d/%02d/%02d %02d:%02d:%02d\n", 206 dt->dt_year, dt->dt_mon, dt->dt_day, 207 dt->dt_hour, dt->dt_min, dt->dt_sec); 208#endif 209 210 /* Write a stamp at NVRAM address 0x10-0x13 */ 211 stamp[0] = 'R' << 24; stamp[1] = 'T' << 24; 212 stamp[2] = 'C' << 24; stamp[3] = '\0' << 24; 213} 214 215#define _DS_GET(off, data) \ 216 do { *chiptime = (off); (data) = (*chipdata); } while (0) 217#define _DS_SET(off, data) \ 218 do { *chiptime = (off); *chipdata = (u_int8_t)(data); } while (0) 219#define _DS_GET_BCD(off, data) \ 220 do { \ 221 u_int8_t c; \ 222 *chiptime = (off); \ 223 c = *chipdata; (data) = FROMBCD(c); \ 224 } while (0) 225#define _DS_SET_BCD(off, data) \ 226 do { \ 227 *chiptime = (off); \ 228 *chipdata = TOBCD((u_int8_t)(data)); \ 229 } while (0) 230 231/* 232 * Get the time of day, based on the clock's value and/or the base value. 233 */ 234void 235dsclock_get(dev, base, dt) 236 struct device *dev; 237 time_t base; 238 struct clock_ymdhms *dt; 239{ 240 struct timekeeper_softc *sc = (void *)dev; 241 volatile u_int8_t *chiptime = (void *)sc->sc_clock; 242 volatile u_int8_t *chipdata = (void *)(sc->sc_clock + 1); 243 int s; 244 u_int8_t c; 245 246 s = splclock(); 247 248 /* specify 24hr and BCD mode */ 249 _DS_GET(DS_REGB, c); 250 c |= DS_REGB_24HR; 251 c &= ~DS_REGB_BINARY; 252 _DS_SET(DS_REGB, c); 253 254 /* update in progress; spin loop */ 255 for (;;) { 256 *chiptime = DS_REGA; 257 if ((*chipdata & DS_REGA_UIP) == 0) 258 break; 259 } 260 261 _DS_GET_BCD(DS_SEC, dt->dt_sec); 262 _DS_GET_BCD(DS_MIN, dt->dt_min); 263 _DS_GET_BCD(DS_HOUR, dt->dt_hour); 264 _DS_GET_BCD(DS_DOW, dt->dt_wday); 265 _DS_GET_BCD(DS_DOM, dt->dt_day); 266 _DS_GET_BCD(DS_MONTH, dt->dt_mon); 267 _DS_GET_BCD(DS_YEAR, dt->dt_year); 268 269 /* UniOS-Mach doesn't set the correct BCD year after Y2K */ 270 if (dt->dt_year > 100) dt->dt_year -= (DS_YEAR0 % 100); 271 272 dt->dt_year += DS_YEAR0; 273 splx(s); 274 275#ifdef TIMEKEEPER_DEBUG 276 printf("get %02d/%02d/%02d %02d:%02d:%02d\n", 277 dt->dt_year, dt->dt_mon, dt->dt_day, 278 dt->dt_hour, dt->dt_min, dt->dt_sec); 279#endif 280} 281 282/* 283 * Reset the TODR based on the time value. 284 */ 285void 286dsclock_set(dev, dt) 287 struct device *dev; 288 struct clock_ymdhms *dt; 289{ 290 struct timekeeper_softc *sc = (void *)dev; 291 volatile u_int8_t *chiptime = (void *)sc->sc_clock; 292 volatile u_int8_t *chipdata = (void *)(sc->sc_clock + 1); 293 int s; 294 u_int8_t c; 295 296 s = splclock(); 297 298 /* enable write */ 299 _DS_GET(DS_REGB, c); 300 c |= DS_REGB_SET; 301 _DS_SET(DS_REGB, c); 302 303 _DS_SET_BCD(DS_SEC, dt->dt_sec); 304 _DS_SET_BCD(DS_MIN, dt->dt_min); 305 _DS_SET_BCD(DS_HOUR, dt->dt_hour); 306 _DS_SET_BCD(DS_DOW, dt->dt_wday); 307 _DS_SET_BCD(DS_DOM, dt->dt_day); 308 _DS_SET_BCD(DS_MONTH, dt->dt_mon); 309 /* XXX: We don't consider UniOS-Mach Y2K problem */ 310 _DS_SET_BCD(DS_YEAR, dt->dt_year - DS_YEAR0); 311 312 _DS_GET(DS_REGB, c); 313 c &= ~DS_REGB_SET; 314 _DS_SET(DS_REGB, c); 315 316 splx(s); 317 318#ifdef TIMEKEEPER_DEBUG 319 printf("set %02d/%02d/%02d %02d:%02d:%02d\n", 320 dt->dt_year, dt->dt_mon, dt->dt_day, 321 dt->dt_hour, dt->dt_min, dt->dt_sec); 322#endif 323} 324