1 | /* $NetBSD: rtc.c,v 1.1 2009/06/16 21:05:34 bouyer 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.1 2009/06/16 21:05:34 bouyer 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 | static void rtcinit(void); |
149 | static int rtcget(mc_todregs *); |
150 | static void rtcput(mc_todregs *); |
151 | static int cmoscheck(void); |
152 | static int clock_expandyear(int); |
153 | |
154 | /* XXX use sc? */ |
155 | u_int |
156 | mc146818_read(void *sc, u_int reg) |
157 | { |
158 | |
159 | outb(IO_RTC, reg); |
160 | return (inb(IO_RTC+1)); |
161 | } |
162 | |
163 | void |
164 | mc146818_write(void *sc, u_int reg, u_int datum) |
165 | { |
166 | |
167 | outb(IO_RTC, reg); |
168 | outb(IO_RTC+1, datum); |
169 | } |
170 | |
171 | static void |
172 | rtcinit(void) |
173 | { |
174 | static int first_rtcopen_ever = 1; |
175 | |
176 | if (!first_rtcopen_ever) |
177 | return; |
178 | first_rtcopen_ever = 0; |
179 | |
180 | mc146818_write(NULL, MC_REGA, /* XXX softc */ |
181 | MC_BASE_32_KHz | MC_RATE_1024_Hz); |
182 | mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */ |
183 | } |
184 | |
185 | static int |
186 | rtcget(mc_todregs *regs) |
187 | { |
188 | |
189 | rtcinit(); |
190 | if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */ |
191 | return (-1); |
192 | MC146818_GETTOD(NULL, regs); /* XXX softc */ |
193 | return (0); |
194 | } |
195 | |
196 | static void |
197 | rtcput(mc_todregs *regs) |
198 | { |
199 | |
200 | rtcinit(); |
201 | MC146818_PUTTOD(NULL, regs); /* XXX softc */ |
202 | } |
203 | |
204 | /* |
205 | * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), |
206 | * to be called at splclock() |
207 | */ |
208 | static int |
209 | cmoscheck(void) |
210 | { |
211 | int i; |
212 | unsigned short cksum = 0; |
213 | |
214 | for (i = 0x10; i <= 0x2d; i++) |
215 | cksum += mc146818_read(NULL, i); /* XXX softc */ |
216 | |
217 | return (cksum == (mc146818_read(NULL, 0x2e) << 8) |
218 | + mc146818_read(NULL, 0x2f)); |
219 | } |
220 | |
221 | #if NMCA > 0 |
222 | /* |
223 | * Check whether the CMOS layout is PS/2 like, to be called at splclock(). |
224 | */ |
225 | static int cmoscheckps2(void); |
226 | static int |
227 | cmoscheckps2(void) |
228 | { |
229 | #if 0 |
230 | /* Disabled until I find out the CRC checksum algorithm IBM uses */ |
231 | int i; |
232 | unsigned short cksum = 0; |
233 | |
234 | for (i = 0x10; i <= 0x31; i++) |
235 | cksum += mc146818_read(NULL, i); /* XXX softc */ |
236 | |
237 | return (cksum == (mc146818_read(NULL, 0x32) << 8) |
238 | + mc146818_read(NULL, 0x33)); |
239 | #else |
240 | /* Check 'incorrect checksum' bit of IBM PS/2 Diagnostic Status Byte */ |
241 | return ((mc146818_read(NULL, NVRAM_DIAG) & (1<<6)) == 0); |
242 | #endif |
243 | } |
244 | #endif /* NMCA > 0 */ |
245 | |
246 | /* |
247 | * patchable to control century byte handling: |
248 | * 1: always update |
249 | * -1: never touch |
250 | * 0: try to figure out itself |
251 | */ |
252 | int rtc_update_century = 0; |
253 | |
254 | /* |
255 | * Expand a two-digit year as read from the clock chip |
256 | * into full width. |
257 | * Being here, deal with the CMOS century byte. |
258 | */ |
259 | static int centb = NVRAM_CENTURY; |
260 | static int |
261 | clock_expandyear(int clockyear) |
262 | { |
263 | int s, clockcentury, cmoscentury; |
264 | |
265 | clockcentury = (clockyear < 70) ? 20 : 19; |
266 | clockyear += 100 * clockcentury; |
267 | |
268 | if (rtc_update_century < 0) |
269 | return (clockyear); |
270 | |
271 | s = splclock(); |
272 | if (cmoscheck()) |
273 | cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); |
274 | #if NMCA > 0 |
275 | else if (MCA_system && cmoscheckps2()) |
276 | cmoscentury = mc146818_read(NULL, (centb = 0x37)); |
277 | #endif |
278 | else |
279 | cmoscentury = 0; |
280 | splx(s); |
281 | if (!cmoscentury) { |
282 | #ifdef DIAGNOSTIC |
283 | printf("clock: unknown CMOS layout\n" ); |
284 | #endif |
285 | return (clockyear); |
286 | } |
287 | cmoscentury = bcdtobin(cmoscentury); |
288 | |
289 | if (cmoscentury != clockcentury) { |
290 | /* XXX note: saying "century is 20" might confuse the naive. */ |
291 | printf("WARNING: NVRAM century is %d but RTC year is %d\n" , |
292 | cmoscentury, clockyear); |
293 | |
294 | /* Kludge to roll over century. */ |
295 | if ((rtc_update_century > 0) || |
296 | ((cmoscentury == 19) && (clockcentury == 20) && |
297 | (clockyear == 2000))) { |
298 | printf("WARNING: Setting NVRAM century to %d\n" , |
299 | clockcentury); |
300 | s = splclock(); |
301 | mc146818_write(NULL, centb, bintobcd(clockcentury)); |
302 | splx(s); |
303 | } |
304 | } else if (cmoscentury == 19 && rtc_update_century == 0) |
305 | rtc_update_century = 1; /* will update later in resettodr() */ |
306 | |
307 | return (clockyear); |
308 | } |
309 | |
310 | int |
311 | rtc_get_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt) |
312 | { |
313 | int s; |
314 | mc_todregs rtclk; |
315 | |
316 | s = splclock(); |
317 | if (rtcget(&rtclk)) { |
318 | splx(s); |
319 | return -1; |
320 | } |
321 | splx(s); |
322 | |
323 | dt->dt_sec = bcdtobin(rtclk[MC_SEC]); |
324 | dt->dt_min = bcdtobin(rtclk[MC_MIN]); |
325 | dt->dt_hour = bcdtobin(rtclk[MC_HOUR]); |
326 | dt->dt_day = bcdtobin(rtclk[MC_DOM]); |
327 | dt->dt_mon = bcdtobin(rtclk[MC_MONTH]); |
328 | dt->dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR])); |
329 | |
330 | return 0; |
331 | } |
332 | |
333 | int |
334 | rtc_set_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt) |
335 | { |
336 | mc_todregs rtclk; |
337 | int century; |
338 | int s; |
339 | |
340 | s = splclock(); |
341 | if (rtcget(&rtclk)) |
342 | memset(&rtclk, 0, sizeof(rtclk)); |
343 | splx(s); |
344 | |
345 | rtclk[MC_SEC] = bintobcd(dt->dt_sec); |
346 | rtclk[MC_MIN] = bintobcd(dt->dt_min); |
347 | rtclk[MC_HOUR] = bintobcd(dt->dt_hour); |
348 | rtclk[MC_DOW] = dt->dt_wday + 1; |
349 | rtclk[MC_YEAR] = bintobcd(dt->dt_year % 100); |
350 | rtclk[MC_MONTH] = bintobcd(dt->dt_mon); |
351 | rtclk[MC_DOM] = bintobcd(dt->dt_day); |
352 | |
353 | #ifdef DEBUG_CLOCK |
354 | printf("setclock: %x/%x/%x %x:%x:%x\n" , rtclk[MC_YEAR], rtclk[MC_MONTH], |
355 | rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]); |
356 | #endif |
357 | s = splclock(); |
358 | rtcput(&rtclk); |
359 | if (rtc_update_century > 0) { |
360 | century = bintobcd(dt->dt_year / 100); |
361 | mc146818_write(NULL, centb, century); /* XXX softc */ |
362 | } |
363 | splx(s); |
364 | return 0; |
365 | |
366 | } |
367 | |
368 | void |
369 | rtc_register(void) |
370 | { |
371 | static struct todr_chip_handle tch; |
372 | tch.todr_gettime_ymdhms = rtc_get_ymdhms; |
373 | tch.todr_settime_ymdhms = rtc_set_ymdhms; |
374 | tch.todr_setwen = NULL; |
375 | |
376 | todr_attach(&tch); |
377 | } |
378 | |
379 | |