1 /* $NetBSD: rtc.c,v 1.3 2025/01/07 22:37:13 jakllsch Exp $ */ 2 3 /*- 4 * Copyright (c) 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * William Jolitz and Don Ahn. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)clock.c 7.2 (Berkeley) 5/12/91 35 */ 36 /*- 37 * Copyright (c) 1993, 1994 Charles M. Hannum. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * William Jolitz and Don Ahn. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 * 70 * @(#)clock.c 7.2 (Berkeley) 5/12/91 71 */ 72 /* 73 * Mach Operating System 74 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 75 * All Rights Reserved. 76 * 77 * Permission to use, copy, modify and distribute this software and its 78 * documentation is hereby granted, provided that both the copyright 79 * notice and this permission notice appear in all copies of the 80 * software, derivative works or modified versions, and any portions 81 * thereof, and that both notices appear in supporting documentation. 82 * 83 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 84 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 85 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 86 * 87 * Carnegie Mellon requests users of this software to return to 88 * 89 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 90 * School of Computer Science 91 * Carnegie Mellon University 92 * Pittsburgh PA 15213-3890 93 * 94 * any improvements or extensions that they make and grant Carnegie Mellon 95 * the rights to redistribute these changes. 96 */ 97 /* 98 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. 99 100 All Rights Reserved 101 102 Permission to use, copy, modify, and distribute this software and 103 its documentation for any purpose and without fee is hereby 104 granted, provided that the above copyright notice appears in all 105 copies and that both the copyright notice and this permission notice 106 appear in supporting documentation, and that the name of Intel 107 not be used in advertising or publicity pertaining to distribution 108 of the software without specific, written prior permission. 109 110 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 111 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 112 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 113 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 114 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 115 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 116 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 117 */ 118 119 /* 120 * Primitive RTC chip routines. 121 */ 122 123 #include <sys/cdefs.h> 124 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.3 2025/01/07 22:37:13 jakllsch Exp $"); 125 126 #include <sys/param.h> 127 #include <sys/systm.h> 128 #include <sys/time.h> 129 #include <sys/timetc.h> 130 #include <sys/kernel.h> 131 132 #include <dev/isa/isareg.h> 133 #include <dev/isa/isavar.h> 134 #include <i386/isa/nvram.h> 135 136 #include <machine/pio.h> 137 138 #include <dev/ic/mc146818reg.h> 139 #include <x86/rtc.h> 140 141 #ifndef __x86_64__ 142 #include "mca.h" 143 #endif 144 #if NMCA > 0 145 #include <machine/mca_machdep.h> /* for MCA_system */ 146 #endif 147 148 #include "acpica.h" 149 #if NACPICA > 0 150 #include <dev/acpi/acpivar.h> 151 #endif 152 153 static void rtcinit(void); 154 static int rtcget(mc_todregs *); 155 static void rtcput(mc_todregs *); 156 static int cmoscheck(void); 157 static int clock_expandyear(int); 158 159 /* XXX use sc? */ 160 u_int 161 mc146818_read(void *sc, u_int reg) 162 { 163 164 outb(IO_RTC, reg); 165 return (inb(IO_RTC+1)); 166 } 167 168 void 169 mc146818_write(void *sc, u_int reg, u_int datum) 170 { 171 172 outb(IO_RTC, reg); 173 outb(IO_RTC+1, datum); 174 } 175 176 static void 177 rtcinit(void) 178 { 179 static int first_rtcopen_ever = 1; 180 181 if (!first_rtcopen_ever) 182 return; 183 first_rtcopen_ever = 0; 184 185 mc146818_write(NULL, MC_REGA, /* XXX softc */ 186 MC_BASE_32_KHz | MC_RATE_1024_Hz); 187 mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */ 188 } 189 190 static int 191 rtcget(mc_todregs *regs) 192 { 193 194 rtcinit(); 195 if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */ 196 return (-1); 197 MC146818_GETTOD(NULL, regs); /* XXX softc */ 198 return (0); 199 } 200 201 static void 202 rtcput(mc_todregs *regs) 203 { 204 205 rtcinit(); 206 MC146818_PUTTOD(NULL, regs); /* XXX softc */ 207 } 208 209 /* 210 * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), 211 * to be called at splclock() 212 */ 213 static int 214 cmoscheck(void) 215 { 216 int i; 217 unsigned short cksum = 0; 218 219 for (i = 0x10; i <= 0x2d; i++) 220 cksum += mc146818_read(NULL, i); /* XXX softc */ 221 222 return (cksum == (mc146818_read(NULL, 0x2e) << 8) 223 + mc146818_read(NULL, 0x2f)); 224 } 225 226 #if NMCA > 0 227 /* 228 * Check whether the CMOS layout is PS/2 like, to be called at splclock(). 229 */ 230 static int cmoscheckps2(void); 231 static int 232 cmoscheckps2(void) 233 { 234 #if 0 235 /* Disabled until I find out the CRC checksum algorithm IBM uses */ 236 int i; 237 unsigned short cksum = 0; 238 239 for (i = 0x10; i <= 0x31; i++) 240 cksum += mc146818_read(NULL, i); /* XXX softc */ 241 242 return (cksum == (mc146818_read(NULL, 0x32) << 8) 243 + mc146818_read(NULL, 0x33)); 244 #else 245 /* Check 'incorrect checksum' bit of IBM PS/2 Diagnostic Status Byte */ 246 return ((mc146818_read(NULL, NVRAM_DIAG) & (1<<6)) == 0); 247 #endif 248 } 249 #endif /* NMCA > 0 */ 250 251 /* 252 * patchable to control century byte handling: 253 * 1: always update 254 * -1: never touch 255 * 0: try to figure out itself 256 */ 257 int rtc_update_century = 0; 258 259 /* 260 * Expand a two-digit year as read from the clock chip 261 * into full width. 262 * Being here, deal with the CMOS century byte. 263 */ 264 static int centb = NVRAM_CENTURY; 265 static int 266 clock_expandyear(int clockyear) 267 { 268 int s, clockcentury, cmoscentury; 269 270 clockcentury = (clockyear < 70) ? 20 : 19; 271 clockyear += 100 * clockcentury; 272 273 if (rtc_update_century < 0) 274 return (clockyear); 275 276 s = splclock(); 277 #if NACPICA > 0 278 if (acpi_active && AcpiGbl_FADT.Century >= MC_NVRAM_START && 279 AcpiGbl_FADT.Century < (MC_NVRAM_START + MC_NVRAM_SIZE)) 280 cmoscentury = mc146818_read(NULL, 281 (centb = AcpiGbl_FADT.Century)); 282 else 283 #endif 284 if (cmoscheck()) 285 cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); 286 #if NMCA > 0 287 else if (MCA_system && cmoscheckps2()) 288 cmoscentury = mc146818_read(NULL, (centb = 0x37)); 289 #endif 290 else 291 cmoscentury = 0; 292 splx(s); 293 if (!cmoscentury) { 294 #ifdef DIAGNOSTIC 295 printf("clock: unknown CMOS layout\n"); 296 #endif 297 return (clockyear); 298 } 299 cmoscentury = bcdtobin(cmoscentury); 300 301 if (cmoscentury != clockcentury) { 302 /* XXX note: saying "century is 20" might confuse the naive. */ 303 printf("WARNING: NVRAM century is %d but RTC year is %d\n", 304 cmoscentury, clockyear); 305 306 /* Kludge to roll over century. */ 307 if ((rtc_update_century > 0) || 308 ((cmoscentury == 19) && (clockcentury == 20) && 309 (clockyear == 2000))) { 310 printf("WARNING: Setting NVRAM century to %d\n", 311 clockcentury); 312 s = splclock(); 313 mc146818_write(NULL, centb, bintobcd(clockcentury)); 314 splx(s); 315 } 316 } else if (cmoscentury == 19 && rtc_update_century == 0) 317 rtc_update_century = 1; /* will update later in resettodr() */ 318 319 return (clockyear); 320 } 321 322 int 323 rtc_get_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt) 324 { 325 int s; 326 mc_todregs rtclk; 327 328 s = splclock(); 329 if (rtcget(&rtclk)) { 330 splx(s); 331 return -1; 332 } 333 splx(s); 334 335 dt->dt_sec = bcdtobin(rtclk[MC_SEC]); 336 dt->dt_min = bcdtobin(rtclk[MC_MIN]); 337 dt->dt_hour = bcdtobin(rtclk[MC_HOUR]); 338 dt->dt_day = bcdtobin(rtclk[MC_DOM]); 339 dt->dt_mon = bcdtobin(rtclk[MC_MONTH]); 340 dt->dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR])); 341 342 return 0; 343 } 344 345 int 346 rtc_set_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt) 347 { 348 mc_todregs rtclk; 349 int century; 350 int s; 351 352 s = splclock(); 353 if (rtcget(&rtclk)) 354 memset(&rtclk, 0, sizeof(rtclk)); 355 splx(s); 356 357 rtclk[MC_SEC] = bintobcd(dt->dt_sec); 358 rtclk[MC_MIN] = bintobcd(dt->dt_min); 359 rtclk[MC_HOUR] = bintobcd(dt->dt_hour); 360 rtclk[MC_DOW] = dt->dt_wday + 1; 361 rtclk[MC_YEAR] = bintobcd(dt->dt_year % 100); 362 rtclk[MC_MONTH] = bintobcd(dt->dt_mon); 363 rtclk[MC_DOM] = bintobcd(dt->dt_day); 364 365 #ifdef DEBUG_CLOCK 366 printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH], 367 rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]); 368 #endif 369 s = splclock(); 370 rtcput(&rtclk); 371 if (rtc_update_century > 0) { 372 century = bintobcd(dt->dt_year / 100); 373 mc146818_write(NULL, centb, century); /* XXX softc */ 374 } 375 splx(s); 376 return 0; 377 378 } 379 380 void 381 rtc_register(void) 382 { 383 static struct todr_chip_handle tch; 384 tch.todr_gettime_ymdhms = rtc_get_ymdhms; 385 tch.todr_settime_ymdhms = rtc_set_ymdhms; 386 tch.todr_setwen = NULL; 387 388 todr_attach(&tch); 389 } 390 391