1/* $NetBSD: rtc.c,v 1.2 2022/12/30 21:40:20 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 102Permission to use, copy, modify, and distribute this software and 103its documentation for any purpose and without fee is hereby 104granted, provided that the above copyright notice appears in all 105copies and that both the copyright notice and this permission notice 106appear in supporting documentation, and that the name of Intel 107not be used in advertising or publicity pertaining to distribution 108of the software without specific, written prior permission. 109 110INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 111INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 112IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 113CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 114LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 115NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 116WITH 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.2 2022/12/30 21:40:20 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 153static void rtcinit(void); 154static int rtcget(mc_todregs *); 155static void rtcput(mc_todregs *); 156static int cmoscheck(void); 157static int clock_expandyear(int); 158 159/* XXX use sc? */ 160u_int 161mc146818_read(void *sc, u_int reg) 162{ 163 164 outb(IO_RTC, reg); 165 return (inb(IO_RTC+1)); 166} 167 168void 169mc146818_write(void *sc, u_int reg, u_int datum) 170{ 171 172 outb(IO_RTC, reg); 173 outb(IO_RTC+1, datum); 174} 175 176static void 177rtcinit(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 190static int 191rtcget(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 201static void 202rtcput(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 */ 213static int 214cmoscheck(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 */ 230static int cmoscheckps2(void); 231static int 232cmoscheckps2(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 */ 257int 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 */ 264static int centb = NVRAM_CENTURY; 265static int 266clock_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) 279 cmoscentury = mc146818_read(NULL, 280 (centb = AcpiGbl_FADT.Century)); 281 else 282#endif 283 if (cmoscheck()) 284 cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); 285#if NMCA > 0 286 else if (MCA_system && cmoscheckps2()) 287 cmoscentury = mc146818_read(NULL, (centb = 0x37)); 288#endif 289 else 290 cmoscentury = 0; 291 splx(s); 292 if (!cmoscentury) { 293#ifdef DIAGNOSTIC 294 printf("clock: unknown CMOS layout\n"); 295#endif 296 return (clockyear); 297 } 298 cmoscentury = bcdtobin(cmoscentury); 299 300 if (cmoscentury != clockcentury) { 301 /* XXX note: saying "century is 20" might confuse the naive. */ 302 printf("WARNING: NVRAM century is %d but RTC year is %d\n", 303 cmoscentury, clockyear); 304 305 /* Kludge to roll over century. */ 306 if ((rtc_update_century > 0) || 307 ((cmoscentury == 19) && (clockcentury == 20) && 308 (clockyear == 2000))) { 309 printf("WARNING: Setting NVRAM century to %d\n", 310 clockcentury); 311 s = splclock(); 312 mc146818_write(NULL, centb, bintobcd(clockcentury)); 313 splx(s); 314 } 315 } else if (cmoscentury == 19 && rtc_update_century == 0) 316 rtc_update_century = 1; /* will update later in resettodr() */ 317 318 return (clockyear); 319} 320 321int 322rtc_get_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt) 323{ 324 int s; 325 mc_todregs rtclk; 326 327 s = splclock(); 328 if (rtcget(&rtclk)) { 329 splx(s); 330 return -1; 331 } 332 splx(s); 333 334 dt->dt_sec = bcdtobin(rtclk[MC_SEC]); 335 dt->dt_min = bcdtobin(rtclk[MC_MIN]); 336 dt->dt_hour = bcdtobin(rtclk[MC_HOUR]); 337 dt->dt_day = bcdtobin(rtclk[MC_DOM]); 338 dt->dt_mon = bcdtobin(rtclk[MC_MONTH]); 339 dt->dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR])); 340 341 return 0; 342} 343 344int 345rtc_set_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt) 346{ 347 mc_todregs rtclk; 348 int century; 349 int s; 350 351 s = splclock(); 352 if (rtcget(&rtclk)) 353 memset(&rtclk, 0, sizeof(rtclk)); 354 splx(s); 355 356 rtclk[MC_SEC] = bintobcd(dt->dt_sec); 357 rtclk[MC_MIN] = bintobcd(dt->dt_min); 358 rtclk[MC_HOUR] = bintobcd(dt->dt_hour); 359 rtclk[MC_DOW] = dt->dt_wday + 1; 360 rtclk[MC_YEAR] = bintobcd(dt->dt_year % 100); 361 rtclk[MC_MONTH] = bintobcd(dt->dt_mon); 362 rtclk[MC_DOM] = bintobcd(dt->dt_day); 363 364#ifdef DEBUG_CLOCK 365 printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH], 366 rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]); 367#endif 368 s = splclock(); 369 rtcput(&rtclk); 370 if (rtc_update_century > 0) { 371 century = bintobcd(dt->dt_year / 100); 372 mc146818_write(NULL, centb, century); /* XXX softc */ 373 } 374 splx(s); 375 return 0; 376 377} 378 379void 380rtc_register(void) 381{ 382 static struct todr_chip_handle tch; 383 tch.todr_gettime_ymdhms = rtc_get_ymdhms; 384 tch.todr_settime_ymdhms = rtc_set_ymdhms; 385 tch.todr_setwen = NULL; 386 387 todr_attach(&tch); 388} 389 390