1 1.32 thorpej /* $NetBSD: mcclock.c,v 1.32 2025/09/07 21:45:15 thorpej Exp $ */ 2 1.2 cgd 3 1.2 cgd /* 4 1.2 cgd * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 5 1.2 cgd * All rights reserved. 6 1.2 cgd * 7 1.2 cgd * Author: Chris G. Demetriou 8 1.2 cgd * 9 1.2 cgd * Permission to use, copy, modify and distribute this software and 10 1.2 cgd * its documentation is hereby granted, provided that both the copyright 11 1.2 cgd * notice and this permission notice appear in all copies of the 12 1.2 cgd * software, derivative works or modified versions, and any portions 13 1.2 cgd * thereof, and that both notices appear in supporting documentation. 14 1.2 cgd * 15 1.2 cgd * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 1.2 cgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 1.2 cgd * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 1.2 cgd * 19 1.2 cgd * Carnegie Mellon requests users of this software to return to 20 1.2 cgd * 21 1.2 cgd * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 22 1.2 cgd * School of Computer Science 23 1.2 cgd * Carnegie Mellon University 24 1.2 cgd * Pittsburgh PA 15213-3890 25 1.2 cgd * 26 1.2 cgd * any improvements or extensions that they make and grant Carnegie the 27 1.2 cgd * rights to redistribute these changes. 28 1.2 cgd */ 29 1.6 cgd 30 1.13 lukem #include <sys/cdefs.h> 31 1.32 thorpej __KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.32 2025/09/07 21:45:15 thorpej Exp $"); 32 1.1 cgd 33 1.1 cgd #include <sys/param.h> 34 1.1 cgd #include <sys/kernel.h> 35 1.1 cgd #include <sys/systm.h> 36 1.1 cgd #include <sys/device.h> 37 1.18 joerg #include <dev/clock_subr.h> 38 1.1 cgd 39 1.8 jonathan #include <dev/dec/clockvar.h> 40 1.8 jonathan #include <dev/dec/mcclockvar.h> 41 1.1 cgd #include <dev/ic/mc146818reg.h> 42 1.1 cgd 43 1.11 jonathan /* 44 1.14 simonb * XXX default rate is machine-dependent. 45 1.12 thorpej */ 46 1.12 thorpej #ifdef __alpha__ 47 1.29 andvar #define MC_DEFAULTHZ 1024 48 1.11 jonathan #endif 49 1.12 thorpej #ifdef pmax 50 1.14 simonb #define MC_DEFAULTHZ 256 51 1.11 jonathan #endif 52 1.11 jonathan 53 1.11 jonathan 54 1.23 cegger void mcclock_init(device_t); 55 1.24 tsutsui int mcclock_get(todr_chip_handle_t, struct timeval *); 56 1.24 tsutsui int mcclock_set(todr_chip_handle_t, struct timeval *); 57 1.1 cgd 58 1.1 cgd const struct clockfns mcclock_clockfns = { 59 1.18 joerg mcclock_init, 60 1.1 cgd }; 61 1.1 cgd 62 1.27 tsutsui #define mc146818_write(sc, reg, datum) \ 63 1.27 tsutsui (*(sc)->sc_busfns->mc_bf_write)(sc, reg, datum) 64 1.27 tsutsui #define mc146818_read(sc, reg) \ 65 1.27 tsutsui (*(sc)->sc_busfns->mc_bf_read)(sc, reg) 66 1.1 cgd 67 1.1 cgd void 68 1.22 dsl mcclock_attach(struct mcclock_softc *sc, const struct mcclock_busfns *busfns) 69 1.1 cgd { 70 1.1 cgd 71 1.30 tsutsui aprint_normal(": mc146818 or compatible"); 72 1.1 cgd 73 1.1 cgd sc->sc_busfns = busfns; 74 1.1 cgd 75 1.1 cgd /* Turn interrupts off, just in case. */ 76 1.1 cgd mc146818_write(sc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR); 77 1.1 cgd 78 1.27 tsutsui clockattach(sc->sc_dev, &mcclock_clockfns); 79 1.18 joerg 80 1.18 joerg sc->sc_todr.todr_gettime = mcclock_get; 81 1.18 joerg sc->sc_todr.todr_settime = mcclock_set; 82 1.32 thorpej KASSERT(sc->sc_dev != NULL); 83 1.32 thorpej sc->sc_todr.todr_dev = sc->sc_dev; 84 1.18 joerg todr_attach(&sc->sc_todr); 85 1.1 cgd } 86 1.1 cgd 87 1.1 cgd void 88 1.23 cegger mcclock_init(device_t dev) 89 1.1 cgd { 90 1.27 tsutsui struct mcclock_softc *sc = device_private(dev); 91 1.14 simonb int rate; 92 1.1 cgd 93 1.14 simonb again: 94 1.14 simonb switch (hz) { 95 1.14 simonb case 32: 96 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_32_Hz; 97 1.14 simonb break; 98 1.14 simonb case 64: 99 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_64_Hz; 100 1.14 simonb break; 101 1.14 simonb case 128: 102 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_128_Hz; 103 1.14 simonb break; 104 1.14 simonb case 256: 105 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_256_Hz; 106 1.14 simonb break; 107 1.14 simonb case 512: 108 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_512_Hz; 109 1.14 simonb break; 110 1.14 simonb case 1024: 111 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_1024_Hz; 112 1.14 simonb break; 113 1.14 simonb case 2048: 114 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_2048_Hz; 115 1.14 simonb break; 116 1.14 simonb case 4096: 117 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_4096_Hz; 118 1.14 simonb break; 119 1.14 simonb case 8192: 120 1.14 simonb rate = MC_BASE_32_KHz | MC_RATE_8192_Hz; 121 1.14 simonb break; 122 1.14 simonb case 16384: 123 1.14 simonb rate = MC_BASE_4_MHz | MC_RATE_1; 124 1.14 simonb break; 125 1.14 simonb case 32768: 126 1.14 simonb rate = MC_BASE_4_MHz | MC_RATE_2; 127 1.14 simonb break; 128 1.14 simonb default: 129 1.14 simonb printf("%s: Cannot get %d Hz clock; using %d Hz\n", 130 1.27 tsutsui device_xname(dev), hz, MC_DEFAULTHZ); 131 1.14 simonb hz = MC_DEFAULTHZ; 132 1.14 simonb goto again; 133 1.14 simonb } 134 1.14 simonb mc146818_write(sc, MC_REGA, rate); 135 1.1 cgd mc146818_write(sc, MC_REGB, 136 1.5 cgd MC_REGB_PIE | MC_REGB_SQWE | MC_REGB_BINARY | MC_REGB_24HR); 137 1.1 cgd } 138 1.1 cgd 139 1.1 cgd /* 140 1.18 joerg * Experiments (and passing years) show that Decstation PROMS 141 1.18 joerg * assume the kernel uses the clock chip as a time-of-year clock. 142 1.18 joerg * The PROM assumes the clock is always set to 1972 or 1973, and contains 143 1.18 joerg * time-of-year in seconds. The PROM checks the clock at boot time, 144 1.18 joerg * and if it's outside that range, sets it to 1972-01-01. 145 1.18 joerg * 146 1.18 joerg * XXX should be at the mc146818 layer? 147 1.18 joerg */ 148 1.18 joerg 149 1.18 joerg /* 150 1.1 cgd * Get the time of day, based on the clock's value and/or the base value. 151 1.1 cgd */ 152 1.18 joerg int 153 1.24 tsutsui mcclock_get(todr_chip_handle_t tch, struct timeval *tvp) 154 1.1 cgd { 155 1.32 thorpej struct mcclock_softc *sc = device_private(tch->todr_dev); 156 1.18 joerg uint32_t yearsecs; 157 1.1 cgd mc_todregs regs; 158 1.1 cgd int s; 159 1.18 joerg struct clock_ymdhms dt; 160 1.1 cgd 161 1.1 cgd s = splclock(); 162 1.1 cgd MC146818_GETTOD(sc, ®s) 163 1.1 cgd splx(s); 164 1.1 cgd 165 1.18 joerg dt.dt_sec = regs[MC_SEC]; 166 1.18 joerg dt.dt_min = regs[MC_MIN]; 167 1.18 joerg dt.dt_hour = regs[MC_HOUR]; 168 1.18 joerg dt.dt_day = regs[MC_DOM]; 169 1.18 joerg dt.dt_mon = regs[MC_MONTH]; 170 1.18 joerg dt.dt_year = 1972; 171 1.18 joerg 172 1.28 christos yearsecs = clock_ymdhms_to_secs(&dt) - (72 - 70) * SECS_PER_COMMON_YEAR; 173 1.18 joerg 174 1.18 joerg /* 175 1.18 joerg * Take the actual year from the filesystem if possible; 176 1.18 joerg * allow for 2 days of clock loss and 363 days of clock gain. 177 1.18 joerg */ 178 1.28 christos dt.dt_year = 1972; /* or MINYEAR or base/SECS_PER_COMMON_YEAR+1970... */ 179 1.18 joerg dt.dt_mon = 1; 180 1.18 joerg dt.dt_day = 1; 181 1.18 joerg dt.dt_hour = 0; 182 1.18 joerg dt.dt_min = 0; 183 1.18 joerg dt.dt_sec = 0; 184 1.18 joerg for(;;) { 185 1.18 joerg tvp->tv_sec = yearsecs + clock_ymdhms_to_secs(&dt); 186 1.31 thorpej if (tvp->tv_sec > tch->todr_base_time - 2 * SECS_PER_DAY) 187 1.18 joerg break; 188 1.18 joerg dt.dt_year++; 189 1.18 joerg } 190 1.18 joerg 191 1.18 joerg tvp->tv_usec = 0; 192 1.18 joerg return 0; 193 1.1 cgd } 194 1.1 cgd 195 1.1 cgd /* 196 1.1 cgd * Reset the TODR based on the time value. 197 1.1 cgd */ 198 1.18 joerg int 199 1.24 tsutsui mcclock_set(todr_chip_handle_t tch, struct timeval *tvp) 200 1.1 cgd { 201 1.32 thorpej struct mcclock_softc *sc = device_private(tch->todr_dev); 202 1.18 joerg struct clock_ymdhms dt; 203 1.18 joerg uint32_t yearsecs; 204 1.1 cgd mc_todregs regs; 205 1.1 cgd int s; 206 1.1 cgd 207 1.18 joerg /* 208 1.18 joerg * calculate seconds relative to this year 209 1.18 joerg */ 210 1.18 joerg clock_secs_to_ymdhms(tvp->tv_sec, &dt); /* get the year */ 211 1.18 joerg dt.dt_mon = 1; 212 1.18 joerg dt.dt_day = 1; 213 1.18 joerg dt.dt_hour = 0; 214 1.18 joerg dt.dt_min = 0; 215 1.18 joerg dt.dt_sec = 0; 216 1.18 joerg yearsecs = tvp->tv_sec - clock_ymdhms_to_secs(&dt); 217 1.18 joerg 218 1.28 christos #define first72 ((72 - 70) * SECS_PER_COMMON_YEAR) 219 1.18 joerg clock_secs_to_ymdhms(first72 + yearsecs, &dt); 220 1.18 joerg 221 1.18 joerg #ifdef DEBUG 222 1.18 joerg if (dt.dt_year != 1972) 223 1.26 tsutsui printf("resettodr: botch (%d, %" PRId64 ")\n", 224 1.26 tsutsui yearsecs, time_second); 225 1.18 joerg #endif 226 1.18 joerg 227 1.1 cgd s = splclock(); 228 1.1 cgd MC146818_GETTOD(sc, ®s); 229 1.1 cgd splx(s); 230 1.1 cgd 231 1.18 joerg regs[MC_SEC] = dt.dt_sec; 232 1.18 joerg regs[MC_MIN] = dt.dt_min; 233 1.18 joerg regs[MC_HOUR] = dt.dt_hour; 234 1.18 joerg regs[MC_DOW] = dt.dt_wday; 235 1.18 joerg regs[MC_DOM] = dt.dt_day; 236 1.18 joerg regs[MC_MONTH] = dt.dt_mon; 237 1.25 mhitch regs[MC_YEAR] = dt.dt_year - 1900; /* rt clock wants 2 digits */ 238 1.1 cgd 239 1.1 cgd s = splclock(); 240 1.1 cgd MC146818_PUTTOD(sc, ®s); 241 1.1 cgd splx(s); 242 1.18 joerg 243 1.18 joerg return 0; 244 1.1 cgd } 245