1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008 Poul-Henning Kamp 5 * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include "opt_isa.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/bus.h> 40 #include <sys/clock.h> 41 #include <sys/lock.h> 42 #include <sys/mutex.h> 43 #include <sys/kdb.h> 44 #include <sys/kernel.h> 45 #include <sys/module.h> 46 #include <sys/proc.h> 47 #include <sys/rman.h> 48 #include <sys/timeet.h> 49 50 #include <isa/rtc.h> 51 #ifdef DEV_ISA 52 #include <isa/isareg.h> 53 #include <isa/isavar.h> 54 #endif 55 #include <machine/intr_machdep.h> 56 #include "clock_if.h" 57 58 /* 59 * clock_lock protects low-level access to individual hardware registers. 60 * atrtc_time_lock protects the entire sequence of accessing multiple registers 61 * to read or write the date and time. 62 */ 63 #define RTC_LOCK do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0) 64 #define RTC_UNLOCK do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0) 65 66 struct mtx atrtc_time_lock; 67 MTX_SYSINIT(atrtc_lock_init, &atrtc_time_lock, "atrtc", MTX_DEF); 68 69 int atrtcclock_disable = 0; 70 71 static int rtc_reg = -1; 72 static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; 73 static u_char rtc_statusb = RTCSB_24HR; 74 75 /* 76 * RTC support routines 77 */ 78 79 int 80 rtcin(int reg) 81 { 82 u_char val; 83 84 RTC_LOCK; 85 if (rtc_reg != reg) { 86 inb(0x84); 87 outb(IO_RTC, reg); 88 rtc_reg = reg; 89 inb(0x84); 90 } 91 val = inb(IO_RTC + 1); 92 RTC_UNLOCK; 93 return (val); 94 } 95 96 void 97 writertc(int reg, u_char val) 98 { 99 100 RTC_LOCK; 101 if (rtc_reg != reg) { 102 inb(0x84); 103 outb(IO_RTC, reg); 104 rtc_reg = reg; 105 inb(0x84); 106 } 107 outb(IO_RTC + 1, val); 108 inb(0x84); 109 RTC_UNLOCK; 110 } 111 112 static __inline int 113 readrtc(int port) 114 { 115 int readval; 116 117 readval = rtcin(port); 118 if (readval >= 0 && (readval & 0xf) < 0xa && (readval & 0xf0) < 0xa0) 119 return (bcd2bin(readval)); 120 return (0); 121 } 122 123 static void 124 atrtc_start(void) 125 { 126 127 writertc(RTC_STATUSA, rtc_statusa); 128 writertc(RTC_STATUSB, RTCSB_24HR); 129 } 130 131 static void 132 atrtc_rate(unsigned rate) 133 { 134 135 rtc_statusa = RTCSA_DIVIDER | rate; 136 writertc(RTC_STATUSA, rtc_statusa); 137 } 138 139 static void 140 atrtc_enable_intr(void) 141 { 142 143 rtc_statusb |= RTCSB_PINTR; 144 writertc(RTC_STATUSB, rtc_statusb); 145 rtcin(RTC_INTR); 146 } 147 148 static void 149 atrtc_disable_intr(void) 150 { 151 152 rtc_statusb &= ~RTCSB_PINTR; 153 writertc(RTC_STATUSB, rtc_statusb); 154 rtcin(RTC_INTR); 155 } 156 157 void 158 atrtc_restore(void) 159 { 160 161 /* Restore all of the RTC's "status" (actually, control) registers. */ 162 rtcin(RTC_STATUSA); /* dummy to get rtc_reg set */ 163 writertc(RTC_STATUSB, RTCSB_24HR); 164 writertc(RTC_STATUSA, rtc_statusa); 165 writertc(RTC_STATUSB, rtc_statusb); 166 rtcin(RTC_INTR); 167 } 168 169 static void 170 atrtc_set(struct timespec *ts) 171 { 172 struct clocktime ct; 173 174 clock_ts_to_ct(ts, &ct); 175 176 mtx_lock(&atrtc_time_lock); 177 178 /* Disable RTC updates and interrupts. */ 179 writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); 180 181 writertc(RTC_SEC, bin2bcd(ct.sec)); /* Write back Seconds */ 182 writertc(RTC_MIN, bin2bcd(ct.min)); /* Write back Minutes */ 183 writertc(RTC_HRS, bin2bcd(ct.hour)); /* Write back Hours */ 184 185 writertc(RTC_WDAY, ct.dow + 1); /* Write back Weekday */ 186 writertc(RTC_DAY, bin2bcd(ct.day)); /* Write back Day */ 187 writertc(RTC_MONTH, bin2bcd(ct.mon)); /* Write back Month */ 188 writertc(RTC_YEAR, bin2bcd(ct.year % 100)); /* Write back Year */ 189 #ifdef USE_RTC_CENTURY 190 writertc(RTC_CENTURY, bin2bcd(ct.year / 100)); /* ... and Century */ 191 #endif 192 193 /* Re-enable RTC updates and interrupts. */ 194 writertc(RTC_STATUSB, rtc_statusb); 195 rtcin(RTC_INTR); 196 197 mtx_unlock(&atrtc_time_lock); 198 } 199 200 /********************************************************************** 201 * RTC driver for subr_rtc 202 */ 203 204 struct atrtc_softc { 205 int port_rid, intr_rid; 206 struct resource *port_res; 207 struct resource *intr_res; 208 void *intr_handler; 209 struct eventtimer et; 210 }; 211 212 static int 213 rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 214 { 215 216 atrtc_rate(max(fls(period + (period >> 1)) - 17, 1)); 217 atrtc_enable_intr(); 218 return (0); 219 } 220 221 static int 222 rtc_stop(struct eventtimer *et) 223 { 224 225 atrtc_disable_intr(); 226 return (0); 227 } 228 229 /* 230 * This routine receives statistical clock interrupts from the RTC. 231 * As explained above, these occur at 128 interrupts per second. 232 * When profiling, we receive interrupts at a rate of 1024 Hz. 233 * 234 * This does not actually add as much overhead as it sounds, because 235 * when the statistical clock is active, the hardclock driver no longer 236 * needs to keep (inaccurate) statistics on its own. This decouples 237 * statistics gathering from scheduling interrupts. 238 * 239 * The RTC chip requires that we read status register C (RTC_INTR) 240 * to acknowledge an interrupt, before it will generate the next one. 241 * Under high interrupt load, rtcintr() can be indefinitely delayed and 242 * the clock can tick immediately after the read from RTC_INTR. In this 243 * case, the mc146818A interrupt signal will not drop for long enough 244 * to register with the 8259 PIC. If an interrupt is missed, the stat 245 * clock will halt, considerably degrading system performance. This is 246 * why we use 'while' rather than a more straightforward 'if' below. 247 * Stat clock ticks can still be lost, causing minor loss of accuracy 248 * in the statistics, but the stat clock will no longer stop. 249 */ 250 static int 251 rtc_intr(void *arg) 252 { 253 struct atrtc_softc *sc = (struct atrtc_softc *)arg; 254 int flag = 0; 255 256 while (rtcin(RTC_INTR) & RTCIR_PERIOD) { 257 flag = 1; 258 if (sc->et.et_active) 259 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 260 } 261 return(flag ? FILTER_HANDLED : FILTER_STRAY); 262 } 263 264 /* 265 * Attach to the ISA PnP descriptors for the timer and realtime clock. 266 */ 267 static struct isa_pnp_id atrtc_ids[] = { 268 { 0x000bd041 /* PNP0B00 */, "AT realtime clock" }, 269 { 0 } 270 }; 271 272 static int 273 atrtc_probe(device_t dev) 274 { 275 int result; 276 277 result = ISA_PNP_PROBE(device_get_parent(dev), dev, atrtc_ids); 278 /* ENOENT means no PnP-ID, device is hinted. */ 279 if (result == ENOENT) { 280 device_set_desc(dev, "AT realtime clock"); 281 return (BUS_PROBE_LOW_PRIORITY); 282 } 283 return (result); 284 } 285 286 static int 287 atrtc_attach(device_t dev) 288 { 289 struct atrtc_softc *sc; 290 rman_res_t s; 291 int i; 292 293 sc = device_get_softc(dev); 294 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 295 IO_RTC, IO_RTC + 1, 2, RF_ACTIVE); 296 if (sc->port_res == NULL) 297 device_printf(dev, "Warning: Couldn't map I/O.\n"); 298 atrtc_start(); 299 clock_register(dev, 1000000); 300 bzero(&sc->et, sizeof(struct eventtimer)); 301 if (!atrtcclock_disable && 302 (resource_int_value(device_get_name(dev), device_get_unit(dev), 303 "clock", &i) != 0 || i != 0)) { 304 sc->intr_rid = 0; 305 while (bus_get_resource(dev, SYS_RES_IRQ, sc->intr_rid, 306 &s, NULL) == 0 && s != 8) 307 sc->intr_rid++; 308 sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ, 309 &sc->intr_rid, 8, 8, 1, RF_ACTIVE); 310 if (sc->intr_res == NULL) { 311 device_printf(dev, "Can't map interrupt.\n"); 312 return (0); 313 } else if ((bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK, 314 rtc_intr, NULL, sc, &sc->intr_handler))) { 315 device_printf(dev, "Can't setup interrupt.\n"); 316 return (0); 317 } else { 318 /* Bind IRQ to BSP to avoid live migration. */ 319 bus_bind_intr(dev, sc->intr_res, 0); 320 } 321 sc->et.et_name = "RTC"; 322 sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_POW2DIV; 323 sc->et.et_quality = 0; 324 sc->et.et_frequency = 32768; 325 sc->et.et_min_period = 0x00080000; 326 sc->et.et_max_period = 0x80000000; 327 sc->et.et_start = rtc_start; 328 sc->et.et_stop = rtc_stop; 329 sc->et.et_priv = dev; 330 et_register(&sc->et); 331 } 332 return(0); 333 } 334 335 static int 336 atrtc_resume(device_t dev) 337 { 338 339 atrtc_restore(); 340 return(0); 341 } 342 343 static int 344 atrtc_settime(device_t dev __unused, struct timespec *ts) 345 { 346 347 atrtc_set(ts); 348 return (0); 349 } 350 351 static int 352 atrtc_gettime(device_t dev, struct timespec *ts) 353 { 354 struct clocktime ct; 355 356 /* Look if we have a RTC present and the time is valid */ 357 if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) { 358 device_printf(dev, "WARNING: Battery failure indication\n"); 359 return (EINVAL); 360 } 361 362 /* 363 * wait for time update to complete 364 * If RTCSA_TUP is zero, we have at least 244us before next update. 365 * This is fast enough on most hardware, but a refinement would be 366 * to make sure that no more than 240us pass after we start reading, 367 * and try again if so. 368 */ 369 mtx_lock(&atrtc_time_lock); 370 while (rtcin(RTC_STATUSA) & RTCSA_TUP) 371 continue; 372 critical_enter(); 373 ct.nsec = 0; 374 ct.sec = readrtc(RTC_SEC); 375 ct.min = readrtc(RTC_MIN); 376 ct.hour = readrtc(RTC_HRS); 377 ct.day = readrtc(RTC_DAY); 378 ct.dow = readrtc(RTC_WDAY) - 1; 379 ct.mon = readrtc(RTC_MONTH); 380 ct.year = readrtc(RTC_YEAR); 381 #ifdef USE_RTC_CENTURY 382 ct.year += readrtc(RTC_CENTURY) * 100; 383 #else 384 ct.year += (ct.year < 80 ? 2000 : 1900); 385 #endif 386 critical_exit(); 387 mtx_unlock(&atrtc_time_lock); 388 /* Set dow = -1 because some clocks don't set it correctly. */ 389 ct.dow = -1; 390 return (clock_ct_to_ts(&ct, ts)); 391 } 392 393 static device_method_t atrtc_methods[] = { 394 /* Device interface */ 395 DEVMETHOD(device_probe, atrtc_probe), 396 DEVMETHOD(device_attach, atrtc_attach), 397 DEVMETHOD(device_detach, bus_generic_detach), 398 DEVMETHOD(device_shutdown, bus_generic_shutdown), 399 DEVMETHOD(device_suspend, bus_generic_suspend), 400 /* XXX stop statclock? */ 401 DEVMETHOD(device_resume, atrtc_resume), 402 403 /* clock interface */ 404 DEVMETHOD(clock_gettime, atrtc_gettime), 405 DEVMETHOD(clock_settime, atrtc_settime), 406 407 { 0, 0 } 408 }; 409 410 static driver_t atrtc_driver = { 411 "atrtc", 412 atrtc_methods, 413 sizeof(struct atrtc_softc), 414 }; 415 416 static devclass_t atrtc_devclass; 417 418 DRIVER_MODULE(atrtc, isa, atrtc_driver, atrtc_devclass, 0, 0); 419 DRIVER_MODULE(atrtc, acpi, atrtc_driver, atrtc_devclass, 0, 0); 420 421 #include "opt_ddb.h" 422 #ifdef DDB 423 #include <ddb/ddb.h> 424 425 DB_SHOW_COMMAND(rtc, rtc) 426 { 427 printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n", 428 rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY), 429 rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC), 430 rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR)); 431 } 432 #endif /* DDB */ 433