clock.c revision 1.4.4.2 1 1.4.4.2 rpaulo /* $NetBSD: clock.c,v 1.4.4.2 2006/09/09 02:44:49 rpaulo Exp $ */
2 1.4.4.2 rpaulo
3 1.4.4.2 rpaulo /*-
4 1.4.4.2 rpaulo * Copyright (c) 1990 The Regents of the University of California.
5 1.4.4.2 rpaulo * All rights reserved.
6 1.4.4.2 rpaulo *
7 1.4.4.2 rpaulo * This code is derived from software contributed to Berkeley by
8 1.4.4.2 rpaulo * William Jolitz and Don Ahn.
9 1.4.4.2 rpaulo *
10 1.4.4.2 rpaulo * Redistribution and use in source and binary forms, with or without
11 1.4.4.2 rpaulo * modification, are permitted provided that the following conditions
12 1.4.4.2 rpaulo * are met:
13 1.4.4.2 rpaulo * 1. Redistributions of source code must retain the above copyright
14 1.4.4.2 rpaulo * notice, this list of conditions and the following disclaimer.
15 1.4.4.2 rpaulo * 2. Redistributions in binary form must reproduce the above copyright
16 1.4.4.2 rpaulo * notice, this list of conditions and the following disclaimer in the
17 1.4.4.2 rpaulo * documentation and/or other materials provided with the distribution.
18 1.4.4.2 rpaulo * 3. Neither the name of the University nor the names of its contributors
19 1.4.4.2 rpaulo * may be used to endorse or promote products derived from this software
20 1.4.4.2 rpaulo * without specific prior written permission.
21 1.4.4.2 rpaulo *
22 1.4.4.2 rpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.4.4.2 rpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.4.4.2 rpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.4.4.2 rpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.4.4.2 rpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.4.4.2 rpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.4.4.2 rpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.4.4.2 rpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.4.4.2 rpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.4.4.2 rpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.4.4.2 rpaulo * SUCH DAMAGE.
33 1.4.4.2 rpaulo *
34 1.4.4.2 rpaulo * @(#)clock.c 7.2 (Berkeley) 5/12/91
35 1.4.4.2 rpaulo */
36 1.4.4.2 rpaulo /*-
37 1.4.4.2 rpaulo * Copyright (c) 1993, 1994 Charles M. Hannum.
38 1.4.4.2 rpaulo *
39 1.4.4.2 rpaulo * This code is derived from software contributed to Berkeley by
40 1.4.4.2 rpaulo * William Jolitz and Don Ahn.
41 1.4.4.2 rpaulo *
42 1.4.4.2 rpaulo * Redistribution and use in source and binary forms, with or without
43 1.4.4.2 rpaulo * modification, are permitted provided that the following conditions
44 1.4.4.2 rpaulo * are met:
45 1.4.4.2 rpaulo * 1. Redistributions of source code must retain the above copyright
46 1.4.4.2 rpaulo * notice, this list of conditions and the following disclaimer.
47 1.4.4.2 rpaulo * 2. Redistributions in binary form must reproduce the above copyright
48 1.4.4.2 rpaulo * notice, this list of conditions and the following disclaimer in the
49 1.4.4.2 rpaulo * documentation and/or other materials provided with the distribution.
50 1.4.4.2 rpaulo * 3. All advertising materials mentioning features or use of this software
51 1.4.4.2 rpaulo * must display the following acknowledgement:
52 1.4.4.2 rpaulo * This product includes software developed by the University of
53 1.4.4.2 rpaulo * California, Berkeley and its contributors.
54 1.4.4.2 rpaulo * 4. Neither the name of the University nor the names of its contributors
55 1.4.4.2 rpaulo * may be used to endorse or promote products derived from this software
56 1.4.4.2 rpaulo * without specific prior written permission.
57 1.4.4.2 rpaulo *
58 1.4.4.2 rpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 1.4.4.2 rpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 1.4.4.2 rpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 1.4.4.2 rpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 1.4.4.2 rpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 1.4.4.2 rpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 1.4.4.2 rpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 1.4.4.2 rpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 1.4.4.2 rpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 1.4.4.2 rpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 1.4.4.2 rpaulo * SUCH DAMAGE.
69 1.4.4.2 rpaulo *
70 1.4.4.2 rpaulo * @(#)clock.c 7.2 (Berkeley) 5/12/91
71 1.4.4.2 rpaulo */
72 1.4.4.2 rpaulo /*
73 1.4.4.2 rpaulo * Mach Operating System
74 1.4.4.2 rpaulo * Copyright (c) 1991,1990,1989 Carnegie Mellon University
75 1.4.4.2 rpaulo * All Rights Reserved.
76 1.4.4.2 rpaulo *
77 1.4.4.2 rpaulo * Permission to use, copy, modify and distribute this software and its
78 1.4.4.2 rpaulo * documentation is hereby granted, provided that both the copyright
79 1.4.4.2 rpaulo * notice and this permission notice appear in all copies of the
80 1.4.4.2 rpaulo * software, derivative works or modified versions, and any portions
81 1.4.4.2 rpaulo * thereof, and that both notices appear in supporting documentation.
82 1.4.4.2 rpaulo *
83 1.4.4.2 rpaulo * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
84 1.4.4.2 rpaulo * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
85 1.4.4.2 rpaulo * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
86 1.4.4.2 rpaulo *
87 1.4.4.2 rpaulo * Carnegie Mellon requests users of this software to return to
88 1.4.4.2 rpaulo *
89 1.4.4.2 rpaulo * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
90 1.4.4.2 rpaulo * School of Computer Science
91 1.4.4.2 rpaulo * Carnegie Mellon University
92 1.4.4.2 rpaulo * Pittsburgh PA 15213-3890
93 1.4.4.2 rpaulo *
94 1.4.4.2 rpaulo * any improvements or extensions that they make and grant Carnegie Mellon
95 1.4.4.2 rpaulo * the rights to redistribute these changes.
96 1.4.4.2 rpaulo */
97 1.4.4.2 rpaulo /*
98 1.4.4.2 rpaulo Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
99 1.4.4.2 rpaulo
100 1.4.4.2 rpaulo All Rights Reserved
101 1.4.4.2 rpaulo
102 1.4.4.2 rpaulo Permission to use, copy, modify, and distribute this software and
103 1.4.4.2 rpaulo its documentation for any purpose and without fee is hereby
104 1.4.4.2 rpaulo granted, provided that the above copyright notice appears in all
105 1.4.4.2 rpaulo copies and that both the copyright notice and this permission notice
106 1.4.4.2 rpaulo appear in supporting documentation, and that the name of Intel
107 1.4.4.2 rpaulo not be used in advertising or publicity pertaining to distribution
108 1.4.4.2 rpaulo of the software without specific, written prior permission.
109 1.4.4.2 rpaulo
110 1.4.4.2 rpaulo INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
111 1.4.4.2 rpaulo INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
112 1.4.4.2 rpaulo IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
113 1.4.4.2 rpaulo CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
114 1.4.4.2 rpaulo LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
115 1.4.4.2 rpaulo NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
116 1.4.4.2 rpaulo WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
117 1.4.4.2 rpaulo */
118 1.4.4.2 rpaulo
119 1.4.4.2 rpaulo /*
120 1.4.4.2 rpaulo * Primitive clock interrupt routines.
121 1.4.4.2 rpaulo */
122 1.4.4.2 rpaulo
123 1.4.4.2 rpaulo #include <sys/cdefs.h>
124 1.4.4.2 rpaulo __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.4.4.2 2006/09/09 02:44:49 rpaulo Exp $");
125 1.4.4.2 rpaulo
126 1.4.4.2 rpaulo /* #define CLOCKDEBUG */
127 1.4.4.2 rpaulo /* #define CLOCK_PARANOIA */
128 1.4.4.2 rpaulo
129 1.4.4.2 rpaulo #include "opt_multiprocessor.h"
130 1.4.4.2 rpaulo #include "opt_ntp.h"
131 1.4.4.2 rpaulo
132 1.4.4.2 rpaulo #include <sys/param.h>
133 1.4.4.2 rpaulo #include <sys/systm.h>
134 1.4.4.2 rpaulo #include <sys/time.h>
135 1.4.4.2 rpaulo #include <sys/timetc.h>
136 1.4.4.2 rpaulo #include <sys/kernel.h>
137 1.4.4.2 rpaulo #include <sys/device.h>
138 1.4.4.2 rpaulo
139 1.4.4.2 rpaulo #include <machine/cpu.h>
140 1.4.4.2 rpaulo #include <machine/intr.h>
141 1.4.4.2 rpaulo #include <machine/pio.h>
142 1.4.4.2 rpaulo #include <machine/cpufunc.h>
143 1.4.4.2 rpaulo
144 1.4.4.2 rpaulo #include <dev/isa/isareg.h>
145 1.4.4.2 rpaulo #include <dev/isa/isavar.h>
146 1.4.4.2 rpaulo #include <dev/ic/mc146818reg.h>
147 1.4.4.2 rpaulo #include <dev/ic/i8253reg.h>
148 1.4.4.2 rpaulo #include <i386/isa/nvram.h>
149 1.4.4.2 rpaulo #include <x86/x86/tsc.h>
150 1.4.4.2 rpaulo #include <dev/clock_subr.h>
151 1.4.4.2 rpaulo #include <machine/specialreg.h>
152 1.4.4.2 rpaulo
153 1.4.4.2 rpaulo #include "config_time.h" /* for CONFIG_TIME */
154 1.4.4.2 rpaulo
155 1.4.4.2 rpaulo #ifndef __x86_64__
156 1.4.4.2 rpaulo #include "mca.h"
157 1.4.4.2 rpaulo #endif
158 1.4.4.2 rpaulo #if NMCA > 0
159 1.4.4.2 rpaulo #include <machine/mca_machdep.h> /* for MCA_system */
160 1.4.4.2 rpaulo #endif
161 1.4.4.2 rpaulo
162 1.4.4.2 rpaulo #include "pcppi.h"
163 1.4.4.2 rpaulo #if (NPCPPI > 0)
164 1.4.4.2 rpaulo #include <dev/isa/pcppivar.h>
165 1.4.4.2 rpaulo
166 1.4.4.2 rpaulo int sysbeepmatch(struct device *, struct cfdata *, void *);
167 1.4.4.2 rpaulo void sysbeepattach(struct device *, struct device *, void *);
168 1.4.4.2 rpaulo
169 1.4.4.2 rpaulo CFATTACH_DECL(sysbeep, sizeof(struct device),
170 1.4.4.2 rpaulo sysbeepmatch, sysbeepattach, NULL, NULL);
171 1.4.4.2 rpaulo
172 1.4.4.2 rpaulo static int ppi_attached;
173 1.4.4.2 rpaulo static pcppi_tag_t ppicookie;
174 1.4.4.2 rpaulo #endif /* PCPPI */
175 1.4.4.2 rpaulo
176 1.4.4.2 rpaulo #ifdef __x86_64__
177 1.4.4.2 rpaulo #define READ_FLAGS() read_rflags()
178 1.4.4.2 rpaulo #define WRITE_FLAGS(x) write_rflags(x)
179 1.4.4.2 rpaulo #else /* i386 architecture processor */
180 1.4.4.2 rpaulo #define READ_FLAGS() read_eflags()
181 1.4.4.2 rpaulo #define WRITE_FLAGS(x) write_eflags(x)
182 1.4.4.2 rpaulo #endif
183 1.4.4.2 rpaulo
184 1.4.4.2 rpaulo #ifdef CLOCKDEBUG
185 1.4.4.2 rpaulo int clock_debug = 0;
186 1.4.4.2 rpaulo #define DPRINTF(arg) if (clock_debug) printf arg
187 1.4.4.2 rpaulo #else
188 1.4.4.2 rpaulo #define DPRINTF(arg)
189 1.4.4.2 rpaulo #endif
190 1.4.4.2 rpaulo
191 1.4.4.2 rpaulo int gettick(void);
192 1.4.4.2 rpaulo void sysbeep(int, int);
193 1.4.4.2 rpaulo static void tickle_tc(void);
194 1.4.4.2 rpaulo
195 1.4.4.2 rpaulo static int clockintr(void *, struct intrframe);
196 1.4.4.2 rpaulo static void rtcinit(void);
197 1.4.4.2 rpaulo static int rtcget(mc_todregs *);
198 1.4.4.2 rpaulo static void rtcput(mc_todregs *);
199 1.4.4.2 rpaulo
200 1.4.4.2 rpaulo static int cmoscheck(void);
201 1.4.4.2 rpaulo
202 1.4.4.2 rpaulo static int clock_expandyear(int);
203 1.4.4.2 rpaulo
204 1.4.4.2 rpaulo static inline int gettick_broken_latch(void);
205 1.4.4.2 rpaulo
206 1.4.4.2 rpaulo static volatile uint32_t i8254_lastcount;
207 1.4.4.2 rpaulo static volatile uint32_t i8254_offset;
208 1.4.4.2 rpaulo static volatile int i8254_ticked;
209 1.4.4.2 rpaulo
210 1.4.4.2 rpaulo static struct simplelock tmr_lock = SIMPLELOCK_INITIALIZER; /* protect TC timer variables */
211 1.4.4.2 rpaulo
212 1.4.4.2 rpaulo inline u_int mc146818_read(void *, u_int);
213 1.4.4.2 rpaulo inline void mc146818_write(void *, u_int, u_int);
214 1.4.4.2 rpaulo
215 1.4.4.2 rpaulo u_int i8254_get_timecount(struct timecounter *);
216 1.4.4.2 rpaulo static void rtc_register(void);
217 1.4.4.2 rpaulo
218 1.4.4.2 rpaulo static struct timecounter i8254_timecounter = {
219 1.4.4.2 rpaulo i8254_get_timecount, /* get_timecount */
220 1.4.4.2 rpaulo 0, /* no poll_pps */
221 1.4.4.2 rpaulo ~0u, /* counter_mask */
222 1.4.4.2 rpaulo TIMER_FREQ, /* frequency */
223 1.4.4.2 rpaulo "i8254", /* name */
224 1.4.4.2 rpaulo 100, /* quality */
225 1.4.4.2 rpaulo NULL, /* prev */
226 1.4.4.2 rpaulo NULL, /* next */
227 1.4.4.2 rpaulo };
228 1.4.4.2 rpaulo
229 1.4.4.2 rpaulo /* XXX use sc? */
230 1.4.4.2 rpaulo inline u_int
231 1.4.4.2 rpaulo mc146818_read(void *sc, u_int reg)
232 1.4.4.2 rpaulo {
233 1.4.4.2 rpaulo
234 1.4.4.2 rpaulo outb(IO_RTC, reg);
235 1.4.4.2 rpaulo return (inb(IO_RTC+1));
236 1.4.4.2 rpaulo }
237 1.4.4.2 rpaulo
238 1.4.4.2 rpaulo /* XXX use sc? */
239 1.4.4.2 rpaulo inline void
240 1.4.4.2 rpaulo mc146818_write(void *sc, u_int reg, u_int datum)
241 1.4.4.2 rpaulo {
242 1.4.4.2 rpaulo
243 1.4.4.2 rpaulo outb(IO_RTC, reg);
244 1.4.4.2 rpaulo outb(IO_RTC+1, datum);
245 1.4.4.2 rpaulo }
246 1.4.4.2 rpaulo
247 1.4.4.2 rpaulo u_long rtclock_tval; /* i8254 reload value for countdown */
248 1.4.4.2 rpaulo int rtclock_init = 0;
249 1.4.4.2 rpaulo
250 1.4.4.2 rpaulo int clock_broken_latch = 0;
251 1.4.4.2 rpaulo
252 1.4.4.2 rpaulo #ifdef CLOCK_PARANOIA
253 1.4.4.2 rpaulo static int ticks[6];
254 1.4.4.2 rpaulo #endif
255 1.4.4.2 rpaulo /*
256 1.4.4.2 rpaulo * i8254 latch check routine:
257 1.4.4.2 rpaulo * National Geode (formerly Cyrix MediaGX) has a serious bug in
258 1.4.4.2 rpaulo * its built-in i8254-compatible clock module.
259 1.4.4.2 rpaulo * machdep sets the variable 'clock_broken_latch' to indicate it.
260 1.4.4.2 rpaulo */
261 1.4.4.2 rpaulo
262 1.4.4.2 rpaulo int
263 1.4.4.2 rpaulo gettick_broken_latch(void)
264 1.4.4.2 rpaulo {
265 1.4.4.2 rpaulo u_long flags;
266 1.4.4.2 rpaulo int v1, v2, v3;
267 1.4.4.2 rpaulo int w1, w2, w3;
268 1.4.4.2 rpaulo
269 1.4.4.2 rpaulo /* Don't want someone screwing with the counter while we're here. */
270 1.4.4.2 rpaulo flags = READ_FLAGS();
271 1.4.4.2 rpaulo disable_intr();
272 1.4.4.2 rpaulo
273 1.4.4.2 rpaulo v1 = inb(IO_TIMER1+TIMER_CNTR0);
274 1.4.4.2 rpaulo v1 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
275 1.4.4.2 rpaulo v2 = inb(IO_TIMER1+TIMER_CNTR0);
276 1.4.4.2 rpaulo v2 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
277 1.4.4.2 rpaulo v3 = inb(IO_TIMER1+TIMER_CNTR0);
278 1.4.4.2 rpaulo v3 |= inb(IO_TIMER1+TIMER_CNTR0) << 8;
279 1.4.4.2 rpaulo
280 1.4.4.2 rpaulo WRITE_FLAGS(flags);
281 1.4.4.2 rpaulo
282 1.4.4.2 rpaulo #ifdef CLOCK_PARANOIA
283 1.4.4.2 rpaulo if (clock_debug) {
284 1.4.4.2 rpaulo ticks[0] = ticks[3];
285 1.4.4.2 rpaulo ticks[1] = ticks[4];
286 1.4.4.2 rpaulo ticks[2] = ticks[5];
287 1.4.4.2 rpaulo ticks[3] = v1;
288 1.4.4.2 rpaulo ticks[4] = v2;
289 1.4.4.2 rpaulo ticks[5] = v3;
290 1.4.4.2 rpaulo }
291 1.4.4.2 rpaulo #endif
292 1.4.4.2 rpaulo
293 1.4.4.2 rpaulo if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200)
294 1.4.4.2 rpaulo return (v2);
295 1.4.4.2 rpaulo
296 1.4.4.2 rpaulo #define _swap_val(a, b) do { \
297 1.4.4.2 rpaulo int c = a; \
298 1.4.4.2 rpaulo a = b; \
299 1.4.4.2 rpaulo b = c; \
300 1.4.4.2 rpaulo } while (0)
301 1.4.4.2 rpaulo
302 1.4.4.2 rpaulo /*
303 1.4.4.2 rpaulo * sort v1 v2 v3
304 1.4.4.2 rpaulo */
305 1.4.4.2 rpaulo if (v1 < v2)
306 1.4.4.2 rpaulo _swap_val(v1, v2);
307 1.4.4.2 rpaulo if (v2 < v3)
308 1.4.4.2 rpaulo _swap_val(v2, v3);
309 1.4.4.2 rpaulo if (v1 < v2)
310 1.4.4.2 rpaulo _swap_val(v1, v2);
311 1.4.4.2 rpaulo
312 1.4.4.2 rpaulo /*
313 1.4.4.2 rpaulo * compute the middle value
314 1.4.4.2 rpaulo */
315 1.4.4.2 rpaulo
316 1.4.4.2 rpaulo if (v1 - v3 < 0x200)
317 1.4.4.2 rpaulo return (v2);
318 1.4.4.2 rpaulo
319 1.4.4.2 rpaulo w1 = v2 - v3;
320 1.4.4.2 rpaulo w2 = v3 - v1 + rtclock_tval;
321 1.4.4.2 rpaulo w3 = v1 - v2;
322 1.4.4.2 rpaulo if (w1 >= w2) {
323 1.4.4.2 rpaulo if (w1 >= w3)
324 1.4.4.2 rpaulo return (v1);
325 1.4.4.2 rpaulo } else {
326 1.4.4.2 rpaulo if (w2 >= w3)
327 1.4.4.2 rpaulo return (v2);
328 1.4.4.2 rpaulo }
329 1.4.4.2 rpaulo return (v3);
330 1.4.4.2 rpaulo }
331 1.4.4.2 rpaulo
332 1.4.4.2 rpaulo /* minimal initialization, enough for delay() */
333 1.4.4.2 rpaulo void
334 1.4.4.2 rpaulo initrtclock(u_long freq)
335 1.4.4.2 rpaulo {
336 1.4.4.2 rpaulo u_long tval;
337 1.4.4.2 rpaulo /*
338 1.4.4.2 rpaulo * Compute timer_count, the count-down count the timer will be
339 1.4.4.2 rpaulo * set to. Also, correctly round
340 1.4.4.2 rpaulo * this by carrying an extra bit through the division.
341 1.4.4.2 rpaulo */
342 1.4.4.2 rpaulo tval = (freq * 2) / (u_long) hz;
343 1.4.4.2 rpaulo tval = (tval / 2) + (tval & 0x1);
344 1.4.4.2 rpaulo
345 1.4.4.2 rpaulo /* initialize 8254 clock */
346 1.4.4.2 rpaulo outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
347 1.4.4.2 rpaulo
348 1.4.4.2 rpaulo /* Correct rounding will buy us a better precision in timekeeping */
349 1.4.4.2 rpaulo outb(IO_TIMER1+TIMER_CNTR0, tval % 256);
350 1.4.4.2 rpaulo outb(IO_TIMER1+TIMER_CNTR0, tval / 256);
351 1.4.4.2 rpaulo
352 1.4.4.2 rpaulo rtclock_tval = tval ? tval : 0xFFFF;
353 1.4.4.2 rpaulo rtclock_init = 1;
354 1.4.4.2 rpaulo }
355 1.4.4.2 rpaulo
356 1.4.4.2 rpaulo void
357 1.4.4.2 rpaulo startrtclock(void)
358 1.4.4.2 rpaulo {
359 1.4.4.2 rpaulo int s;
360 1.4.4.2 rpaulo
361 1.4.4.2 rpaulo if (!rtclock_init)
362 1.4.4.2 rpaulo initrtclock(TIMER_FREQ);
363 1.4.4.2 rpaulo
364 1.4.4.2 rpaulo /* Check diagnostic status */
365 1.4.4.2 rpaulo if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) { /* XXX softc */
366 1.4.4.2 rpaulo char bits[128];
367 1.4.4.2 rpaulo printf("RTC BIOS diagnostic error %s\n",
368 1.4.4.2 rpaulo bitmask_snprintf(s, NVRAM_DIAG_BITS, bits, sizeof(bits)));
369 1.4.4.2 rpaulo }
370 1.4.4.2 rpaulo
371 1.4.4.2 rpaulo tc_init(&i8254_timecounter);
372 1.4.4.2 rpaulo
373 1.4.4.2 rpaulo #if defined(I586_CPU) || defined(I686_CPU) || defined(__x86_64__)
374 1.4.4.2 rpaulo init_TSC();
375 1.4.4.2 rpaulo #endif
376 1.4.4.2 rpaulo
377 1.4.4.2 rpaulo rtc_register();
378 1.4.4.2 rpaulo }
379 1.4.4.2 rpaulo
380 1.4.4.2 rpaulo
381 1.4.4.2 rpaulo static void
382 1.4.4.2 rpaulo tickle_tc(void)
383 1.4.4.2 rpaulo {
384 1.4.4.2 rpaulo #if defined(MULTIPROCESSOR)
385 1.4.4.2 rpaulo struct cpu_info *ci = curcpu();
386 1.4.4.2 rpaulo /*
387 1.4.4.2 rpaulo * If we are not the primary CPU, we're not allowed to do
388 1.4.4.2 rpaulo * any more work.
389 1.4.4.2 rpaulo */
390 1.4.4.2 rpaulo if (CPU_IS_PRIMARY(ci) == 0)
391 1.4.4.2 rpaulo return;
392 1.4.4.2 rpaulo #endif
393 1.4.4.2 rpaulo if (rtclock_tval && timecounter->tc_get_timecount == i8254_get_timecount) {
394 1.4.4.2 rpaulo simple_lock(&tmr_lock);
395 1.4.4.2 rpaulo if (i8254_ticked)
396 1.4.4.2 rpaulo i8254_ticked = 0;
397 1.4.4.2 rpaulo else {
398 1.4.4.2 rpaulo i8254_offset += rtclock_tval;
399 1.4.4.2 rpaulo i8254_lastcount = 0;
400 1.4.4.2 rpaulo }
401 1.4.4.2 rpaulo simple_unlock(&tmr_lock);
402 1.4.4.2 rpaulo }
403 1.4.4.2 rpaulo
404 1.4.4.2 rpaulo }
405 1.4.4.2 rpaulo
406 1.4.4.2 rpaulo static int
407 1.4.4.2 rpaulo clockintr(void *arg, struct intrframe frame)
408 1.4.4.2 rpaulo {
409 1.4.4.2 rpaulo tickle_tc();
410 1.4.4.2 rpaulo
411 1.4.4.2 rpaulo hardclock((struct clockframe *)&frame);
412 1.4.4.2 rpaulo
413 1.4.4.2 rpaulo #if NMCA > 0
414 1.4.4.2 rpaulo if (MCA_system) {
415 1.4.4.2 rpaulo /* Reset PS/2 clock interrupt by asserting bit 7 of port 0x61 */
416 1.4.4.2 rpaulo outb(0x61, inb(0x61) | 0x80);
417 1.4.4.2 rpaulo }
418 1.4.4.2 rpaulo #endif
419 1.4.4.2 rpaulo return -1;
420 1.4.4.2 rpaulo }
421 1.4.4.2 rpaulo
422 1.4.4.2 rpaulo u_int
423 1.4.4.2 rpaulo i8254_get_timecount(struct timecounter *tc)
424 1.4.4.2 rpaulo {
425 1.4.4.2 rpaulo u_int count;
426 1.4.4.2 rpaulo u_char high, low;
427 1.4.4.2 rpaulo u_long flags;
428 1.4.4.2 rpaulo
429 1.4.4.2 rpaulo /* Don't want someone screwing with the counter while we're here. */
430 1.4.4.2 rpaulo flags = READ_FLAGS();
431 1.4.4.2 rpaulo disable_intr();
432 1.4.4.2 rpaulo
433 1.4.4.2 rpaulo simple_lock(&tmr_lock);
434 1.4.4.2 rpaulo
435 1.4.4.2 rpaulo /* Select timer0 and latch counter value. */
436 1.4.4.2 rpaulo outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
437 1.4.4.2 rpaulo
438 1.4.4.2 rpaulo low = inb(IO_TIMER1 + TIMER_CNTR0);
439 1.4.4.2 rpaulo high = inb(IO_TIMER1 + TIMER_CNTR0);
440 1.4.4.2 rpaulo count = rtclock_tval - ((high << 8) | low);
441 1.4.4.2 rpaulo
442 1.4.4.2 rpaulo if (rtclock_tval && (count < i8254_lastcount || !i8254_ticked)) {
443 1.4.4.2 rpaulo i8254_ticked = 1;
444 1.4.4.2 rpaulo i8254_offset += rtclock_tval;
445 1.4.4.2 rpaulo }
446 1.4.4.2 rpaulo
447 1.4.4.2 rpaulo i8254_lastcount = count;
448 1.4.4.2 rpaulo count += i8254_offset;
449 1.4.4.2 rpaulo
450 1.4.4.2 rpaulo simple_unlock(&tmr_lock);
451 1.4.4.2 rpaulo
452 1.4.4.2 rpaulo WRITE_FLAGS(flags);
453 1.4.4.2 rpaulo return (count);
454 1.4.4.2 rpaulo }
455 1.4.4.2 rpaulo
456 1.4.4.2 rpaulo int
457 1.4.4.2 rpaulo gettick(void)
458 1.4.4.2 rpaulo {
459 1.4.4.2 rpaulo u_long flags;
460 1.4.4.2 rpaulo u_char lo, hi;
461 1.4.4.2 rpaulo
462 1.4.4.2 rpaulo if (clock_broken_latch)
463 1.4.4.2 rpaulo return (gettick_broken_latch());
464 1.4.4.2 rpaulo
465 1.4.4.2 rpaulo /* Don't want someone screwing with the counter while we're here. */
466 1.4.4.2 rpaulo flags = READ_FLAGS();
467 1.4.4.2 rpaulo disable_intr();
468 1.4.4.2 rpaulo /* Select counter 0 and latch it. */
469 1.4.4.2 rpaulo outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
470 1.4.4.2 rpaulo lo = inb(IO_TIMER1+TIMER_CNTR0);
471 1.4.4.2 rpaulo hi = inb(IO_TIMER1+TIMER_CNTR0);
472 1.4.4.2 rpaulo WRITE_FLAGS(flags);
473 1.4.4.2 rpaulo return ((hi << 8) | lo);
474 1.4.4.2 rpaulo }
475 1.4.4.2 rpaulo
476 1.4.4.2 rpaulo /*
477 1.4.4.2 rpaulo * Wait approximately `n' microseconds.
478 1.4.4.2 rpaulo * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
479 1.4.4.2 rpaulo * Note: timer had better have been programmed before this is first used!
480 1.4.4.2 rpaulo * (Note that we use `rate generator' mode, which counts at 1:1; `square
481 1.4.4.2 rpaulo * wave' mode counts at 2:1).
482 1.4.4.2 rpaulo * Don't rely on this being particularly accurate.
483 1.4.4.2 rpaulo */
484 1.4.4.2 rpaulo void
485 1.4.4.2 rpaulo i8254_delay(int n)
486 1.4.4.2 rpaulo {
487 1.4.4.2 rpaulo int delay_tick, odelay_tick;
488 1.4.4.2 rpaulo static const int delaytab[26] = {
489 1.4.4.2 rpaulo 0, 2, 3, 4, 5, 6, 7, 9, 10, 11,
490 1.4.4.2 rpaulo 12, 13, 15, 16, 17, 18, 19, 21, 22, 23,
491 1.4.4.2 rpaulo 24, 25, 27, 28, 29, 30,
492 1.4.4.2 rpaulo };
493 1.4.4.2 rpaulo
494 1.4.4.2 rpaulo /* allow DELAY() to be used before startrtclock() */
495 1.4.4.2 rpaulo if (!rtclock_init)
496 1.4.4.2 rpaulo initrtclock(TIMER_FREQ);
497 1.4.4.2 rpaulo
498 1.4.4.2 rpaulo /*
499 1.4.4.2 rpaulo * Read the counter first, so that the rest of the setup overhead is
500 1.4.4.2 rpaulo * counted.
501 1.4.4.2 rpaulo */
502 1.4.4.2 rpaulo odelay_tick = gettick();
503 1.4.4.2 rpaulo
504 1.4.4.2 rpaulo if (n <= 25)
505 1.4.4.2 rpaulo n = delaytab[n];
506 1.4.4.2 rpaulo else {
507 1.4.4.2 rpaulo #ifdef __GNUC__
508 1.4.4.2 rpaulo /*
509 1.4.4.2 rpaulo * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler
510 1.4.4.2 rpaulo * code so we can take advantage of the intermediate 64-bit
511 1.4.4.2 rpaulo * quantity to prevent loss of significance.
512 1.4.4.2 rpaulo */
513 1.4.4.2 rpaulo int m;
514 1.4.4.2 rpaulo __asm volatile("mul %3"
515 1.4.4.2 rpaulo : "=a" (n), "=d" (m)
516 1.4.4.2 rpaulo : "0" (n), "r" (TIMER_FREQ));
517 1.4.4.2 rpaulo __asm volatile("div %4"
518 1.4.4.2 rpaulo : "=a" (n), "=d" (m)
519 1.4.4.2 rpaulo : "0" (n), "1" (m), "r" (1000000));
520 1.4.4.2 rpaulo #else
521 1.4.4.2 rpaulo /*
522 1.4.4.2 rpaulo * Calculate ((n * TIMER_FREQ) / 1e6) without using floating
523 1.4.4.2 rpaulo * point and without any avoidable overflows.
524 1.4.4.2 rpaulo */
525 1.4.4.2 rpaulo int sec = n / 1000000,
526 1.4.4.2 rpaulo usec = n % 1000000;
527 1.4.4.2 rpaulo n = sec * TIMER_FREQ +
528 1.4.4.2 rpaulo usec * (TIMER_FREQ / 1000000) +
529 1.4.4.2 rpaulo usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 +
530 1.4.4.2 rpaulo usec * (TIMER_FREQ % 1000) / 1000000;
531 1.4.4.2 rpaulo #endif
532 1.4.4.2 rpaulo }
533 1.4.4.2 rpaulo
534 1.4.4.2 rpaulo while (n > 0) {
535 1.4.4.2 rpaulo #ifdef CLOCK_PARANOIA
536 1.4.4.2 rpaulo int delta;
537 1.4.4.2 rpaulo delay_tick = gettick();
538 1.4.4.2 rpaulo if (delay_tick > odelay_tick)
539 1.4.4.2 rpaulo delta = rtclock_tval - (delay_tick - odelay_tick);
540 1.4.4.2 rpaulo else
541 1.4.4.2 rpaulo delta = odelay_tick - delay_tick;
542 1.4.4.2 rpaulo if (delta < 0 || delta >= rtclock_tval / 2) {
543 1.4.4.2 rpaulo DPRINTF(("delay: ignore ticks %.4x-%.4x",
544 1.4.4.2 rpaulo odelay_tick, delay_tick));
545 1.4.4.2 rpaulo if (clock_broken_latch) {
546 1.4.4.2 rpaulo DPRINTF((" (%.4x %.4x %.4x %.4x %.4x %.4x)\n",
547 1.4.4.2 rpaulo ticks[0], ticks[1], ticks[2],
548 1.4.4.2 rpaulo ticks[3], ticks[4], ticks[5]));
549 1.4.4.2 rpaulo } else {
550 1.4.4.2 rpaulo DPRINTF(("\n"));
551 1.4.4.2 rpaulo }
552 1.4.4.2 rpaulo } else
553 1.4.4.2 rpaulo n -= delta;
554 1.4.4.2 rpaulo #else
555 1.4.4.2 rpaulo delay_tick = gettick();
556 1.4.4.2 rpaulo if (delay_tick > odelay_tick)
557 1.4.4.2 rpaulo n -= rtclock_tval - (delay_tick - odelay_tick);
558 1.4.4.2 rpaulo else
559 1.4.4.2 rpaulo n -= odelay_tick - delay_tick;
560 1.4.4.2 rpaulo #endif
561 1.4.4.2 rpaulo odelay_tick = delay_tick;
562 1.4.4.2 rpaulo }
563 1.4.4.2 rpaulo }
564 1.4.4.2 rpaulo
565 1.4.4.2 rpaulo #if (NPCPPI > 0)
566 1.4.4.2 rpaulo int
567 1.4.4.2 rpaulo sysbeepmatch(struct device *parent, struct cfdata *match, void *aux)
568 1.4.4.2 rpaulo {
569 1.4.4.2 rpaulo return (!ppi_attached);
570 1.4.4.2 rpaulo }
571 1.4.4.2 rpaulo
572 1.4.4.2 rpaulo void
573 1.4.4.2 rpaulo sysbeepattach(struct device *parent, struct device *self, void *aux)
574 1.4.4.2 rpaulo {
575 1.4.4.2 rpaulo aprint_naive("\n");
576 1.4.4.2 rpaulo aprint_normal("\n");
577 1.4.4.2 rpaulo
578 1.4.4.2 rpaulo ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie;
579 1.4.4.2 rpaulo ppi_attached = 1;
580 1.4.4.2 rpaulo }
581 1.4.4.2 rpaulo #endif
582 1.4.4.2 rpaulo
583 1.4.4.2 rpaulo void
584 1.4.4.2 rpaulo sysbeep(int pitch, int period)
585 1.4.4.2 rpaulo {
586 1.4.4.2 rpaulo #if (NPCPPI > 0)
587 1.4.4.2 rpaulo if (ppi_attached)
588 1.4.4.2 rpaulo pcppi_bell(ppicookie, pitch, period, 0);
589 1.4.4.2 rpaulo #endif
590 1.4.4.2 rpaulo }
591 1.4.4.2 rpaulo
592 1.4.4.2 rpaulo void
593 1.4.4.2 rpaulo i8254_initclocks(void)
594 1.4.4.2 rpaulo {
595 1.4.4.2 rpaulo
596 1.4.4.2 rpaulo /*
597 1.4.4.2 rpaulo * XXX If you're doing strange things with multiple clocks, you might
598 1.4.4.2 rpaulo * want to keep track of clock handlers.
599 1.4.4.2 rpaulo */
600 1.4.4.2 rpaulo (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK,
601 1.4.4.2 rpaulo (int (*)(void *))clockintr, 0);
602 1.4.4.2 rpaulo }
603 1.4.4.2 rpaulo
604 1.4.4.2 rpaulo static void
605 1.4.4.2 rpaulo rtcinit(void)
606 1.4.4.2 rpaulo {
607 1.4.4.2 rpaulo static int first_rtcopen_ever = 1;
608 1.4.4.2 rpaulo
609 1.4.4.2 rpaulo if (!first_rtcopen_ever)
610 1.4.4.2 rpaulo return;
611 1.4.4.2 rpaulo first_rtcopen_ever = 0;
612 1.4.4.2 rpaulo
613 1.4.4.2 rpaulo mc146818_write(NULL, MC_REGA, /* XXX softc */
614 1.4.4.2 rpaulo MC_BASE_32_KHz | MC_RATE_1024_Hz);
615 1.4.4.2 rpaulo mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */
616 1.4.4.2 rpaulo }
617 1.4.4.2 rpaulo
618 1.4.4.2 rpaulo static int
619 1.4.4.2 rpaulo rtcget(mc_todregs *regs)
620 1.4.4.2 rpaulo {
621 1.4.4.2 rpaulo
622 1.4.4.2 rpaulo rtcinit();
623 1.4.4.2 rpaulo if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
624 1.4.4.2 rpaulo return (-1);
625 1.4.4.2 rpaulo MC146818_GETTOD(NULL, regs); /* XXX softc */
626 1.4.4.2 rpaulo return (0);
627 1.4.4.2 rpaulo }
628 1.4.4.2 rpaulo
629 1.4.4.2 rpaulo static void
630 1.4.4.2 rpaulo rtcput(mc_todregs *regs)
631 1.4.4.2 rpaulo {
632 1.4.4.2 rpaulo
633 1.4.4.2 rpaulo rtcinit();
634 1.4.4.2 rpaulo MC146818_PUTTOD(NULL, regs); /* XXX softc */
635 1.4.4.2 rpaulo }
636 1.4.4.2 rpaulo
637 1.4.4.2 rpaulo /*
638 1.4.4.2 rpaulo * check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
639 1.4.4.2 rpaulo * to be called at splclock()
640 1.4.4.2 rpaulo */
641 1.4.4.2 rpaulo static int
642 1.4.4.2 rpaulo cmoscheck(void)
643 1.4.4.2 rpaulo {
644 1.4.4.2 rpaulo int i;
645 1.4.4.2 rpaulo unsigned short cksum = 0;
646 1.4.4.2 rpaulo
647 1.4.4.2 rpaulo for (i = 0x10; i <= 0x2d; i++)
648 1.4.4.2 rpaulo cksum += mc146818_read(NULL, i); /* XXX softc */
649 1.4.4.2 rpaulo
650 1.4.4.2 rpaulo return (cksum == (mc146818_read(NULL, 0x2e) << 8)
651 1.4.4.2 rpaulo + mc146818_read(NULL, 0x2f));
652 1.4.4.2 rpaulo }
653 1.4.4.2 rpaulo
654 1.4.4.2 rpaulo #if NMCA > 0
655 1.4.4.2 rpaulo /*
656 1.4.4.2 rpaulo * Check whether the CMOS layout is PS/2 like, to be called at splclock().
657 1.4.4.2 rpaulo */
658 1.4.4.2 rpaulo static int cmoscheckps2(void);
659 1.4.4.2 rpaulo static int
660 1.4.4.2 rpaulo cmoscheckps2(void)
661 1.4.4.2 rpaulo {
662 1.4.4.2 rpaulo #if 0
663 1.4.4.2 rpaulo /* Disabled until I find out the CRC checksum algorithm IBM uses */
664 1.4.4.2 rpaulo int i;
665 1.4.4.2 rpaulo unsigned short cksum = 0;
666 1.4.4.2 rpaulo
667 1.4.4.2 rpaulo for (i = 0x10; i <= 0x31; i++)
668 1.4.4.2 rpaulo cksum += mc146818_read(NULL, i); /* XXX softc */
669 1.4.4.2 rpaulo
670 1.4.4.2 rpaulo return (cksum == (mc146818_read(NULL, 0x32) << 8)
671 1.4.4.2 rpaulo + mc146818_read(NULL, 0x33));
672 1.4.4.2 rpaulo #else
673 1.4.4.2 rpaulo /* Check 'incorrect checksum' bit of IBM PS/2 Diagnostic Status Byte */
674 1.4.4.2 rpaulo return ((mc146818_read(NULL, NVRAM_DIAG) & (1<<6)) == 0);
675 1.4.4.2 rpaulo #endif
676 1.4.4.2 rpaulo }
677 1.4.4.2 rpaulo #endif /* NMCA > 0 */
678 1.4.4.2 rpaulo
679 1.4.4.2 rpaulo /*
680 1.4.4.2 rpaulo * patchable to control century byte handling:
681 1.4.4.2 rpaulo * 1: always update
682 1.4.4.2 rpaulo * -1: never touch
683 1.4.4.2 rpaulo * 0: try to figure out itself
684 1.4.4.2 rpaulo */
685 1.4.4.2 rpaulo int rtc_update_century = 0;
686 1.4.4.2 rpaulo
687 1.4.4.2 rpaulo /*
688 1.4.4.2 rpaulo * Expand a two-digit year as read from the clock chip
689 1.4.4.2 rpaulo * into full width.
690 1.4.4.2 rpaulo * Being here, deal with the CMOS century byte.
691 1.4.4.2 rpaulo */
692 1.4.4.2 rpaulo static int centb = NVRAM_CENTURY;
693 1.4.4.2 rpaulo static int
694 1.4.4.2 rpaulo clock_expandyear(int clockyear)
695 1.4.4.2 rpaulo {
696 1.4.4.2 rpaulo int s, clockcentury, cmoscentury;
697 1.4.4.2 rpaulo
698 1.4.4.2 rpaulo clockcentury = (clockyear < 70) ? 20 : 19;
699 1.4.4.2 rpaulo clockyear += 100 * clockcentury;
700 1.4.4.2 rpaulo
701 1.4.4.2 rpaulo if (rtc_update_century < 0)
702 1.4.4.2 rpaulo return (clockyear);
703 1.4.4.2 rpaulo
704 1.4.4.2 rpaulo s = splclock();
705 1.4.4.2 rpaulo if (cmoscheck())
706 1.4.4.2 rpaulo cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
707 1.4.4.2 rpaulo #if NMCA > 0
708 1.4.4.2 rpaulo else if (MCA_system && cmoscheckps2())
709 1.4.4.2 rpaulo cmoscentury = mc146818_read(NULL, (centb = 0x37));
710 1.4.4.2 rpaulo #endif
711 1.4.4.2 rpaulo else
712 1.4.4.2 rpaulo cmoscentury = 0;
713 1.4.4.2 rpaulo splx(s);
714 1.4.4.2 rpaulo if (!cmoscentury) {
715 1.4.4.2 rpaulo #ifdef DIAGNOSTIC
716 1.4.4.2 rpaulo printf("clock: unknown CMOS layout\n");
717 1.4.4.2 rpaulo #endif
718 1.4.4.2 rpaulo return (clockyear);
719 1.4.4.2 rpaulo }
720 1.4.4.2 rpaulo cmoscentury = bcdtobin(cmoscentury);
721 1.4.4.2 rpaulo
722 1.4.4.2 rpaulo if (cmoscentury != clockcentury) {
723 1.4.4.2 rpaulo /* XXX note: saying "century is 20" might confuse the naive. */
724 1.4.4.2 rpaulo printf("WARNING: NVRAM century is %d but RTC year is %d\n",
725 1.4.4.2 rpaulo cmoscentury, clockyear);
726 1.4.4.2 rpaulo
727 1.4.4.2 rpaulo /* Kludge to roll over century. */
728 1.4.4.2 rpaulo if ((rtc_update_century > 0) ||
729 1.4.4.2 rpaulo ((cmoscentury == 19) && (clockcentury == 20) &&
730 1.4.4.2 rpaulo (clockyear == 2000))) {
731 1.4.4.2 rpaulo printf("WARNING: Setting NVRAM century to %d\n",
732 1.4.4.2 rpaulo clockcentury);
733 1.4.4.2 rpaulo s = splclock();
734 1.4.4.2 rpaulo mc146818_write(NULL, centb, bintobcd(clockcentury));
735 1.4.4.2 rpaulo splx(s);
736 1.4.4.2 rpaulo }
737 1.4.4.2 rpaulo } else if (cmoscentury == 19 && rtc_update_century == 0)
738 1.4.4.2 rpaulo rtc_update_century = 1; /* will update later in resettodr() */
739 1.4.4.2 rpaulo
740 1.4.4.2 rpaulo return (clockyear);
741 1.4.4.2 rpaulo }
742 1.4.4.2 rpaulo
743 1.4.4.2 rpaulo static int
744 1.4.4.2 rpaulo rtc_get_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
745 1.4.4.2 rpaulo {
746 1.4.4.2 rpaulo int s;
747 1.4.4.2 rpaulo mc_todregs rtclk;
748 1.4.4.2 rpaulo
749 1.4.4.2 rpaulo s = splclock();
750 1.4.4.2 rpaulo if (rtcget(&rtclk)) {
751 1.4.4.2 rpaulo splx(s);
752 1.4.4.2 rpaulo return -1;
753 1.4.4.2 rpaulo }
754 1.4.4.2 rpaulo splx(s);
755 1.4.4.2 rpaulo
756 1.4.4.2 rpaulo dt->dt_sec = bcdtobin(rtclk[MC_SEC]);
757 1.4.4.2 rpaulo dt->dt_min = bcdtobin(rtclk[MC_MIN]);
758 1.4.4.2 rpaulo dt->dt_hour = bcdtobin(rtclk[MC_HOUR]);
759 1.4.4.2 rpaulo dt->dt_day = bcdtobin(rtclk[MC_DOM]);
760 1.4.4.2 rpaulo dt->dt_mon = bcdtobin(rtclk[MC_MONTH]);
761 1.4.4.2 rpaulo dt->dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR]));
762 1.4.4.2 rpaulo
763 1.4.4.2 rpaulo return 0;
764 1.4.4.2 rpaulo }
765 1.4.4.2 rpaulo
766 1.4.4.2 rpaulo static int
767 1.4.4.2 rpaulo rtc_set_ymdhms(todr_chip_handle_t tch, struct clock_ymdhms *dt)
768 1.4.4.2 rpaulo {
769 1.4.4.2 rpaulo mc_todregs rtclk;
770 1.4.4.2 rpaulo int century;
771 1.4.4.2 rpaulo int s;
772 1.4.4.2 rpaulo
773 1.4.4.2 rpaulo s = splclock();
774 1.4.4.2 rpaulo if (rtcget(&rtclk))
775 1.4.4.2 rpaulo memset(&rtclk, 0, sizeof(rtclk));
776 1.4.4.2 rpaulo splx(s);
777 1.4.4.2 rpaulo
778 1.4.4.2 rpaulo rtclk[MC_SEC] = bintobcd(dt->dt_sec);
779 1.4.4.2 rpaulo rtclk[MC_MIN] = bintobcd(dt->dt_min);
780 1.4.4.2 rpaulo rtclk[MC_HOUR] = bintobcd(dt->dt_hour);
781 1.4.4.2 rpaulo rtclk[MC_DOW] = dt->dt_wday + 1;
782 1.4.4.2 rpaulo rtclk[MC_YEAR] = bintobcd(dt->dt_year % 100);
783 1.4.4.2 rpaulo rtclk[MC_MONTH] = bintobcd(dt->dt_mon);
784 1.4.4.2 rpaulo rtclk[MC_DOM] = bintobcd(dt->dt_day);
785 1.4.4.2 rpaulo
786 1.4.4.2 rpaulo #ifdef DEBUG_CLOCK
787 1.4.4.2 rpaulo printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH],
788 1.4.4.2 rpaulo rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]);
789 1.4.4.2 rpaulo #endif
790 1.4.4.2 rpaulo s = splclock();
791 1.4.4.2 rpaulo rtcput(&rtclk);
792 1.4.4.2 rpaulo if (rtc_update_century > 0) {
793 1.4.4.2 rpaulo century = bintobcd(dt->dt_year / 100);
794 1.4.4.2 rpaulo mc146818_write(NULL, centb, century); /* XXX softc */
795 1.4.4.2 rpaulo }
796 1.4.4.2 rpaulo splx(s);
797 1.4.4.2 rpaulo return 0;
798 1.4.4.2 rpaulo
799 1.4.4.2 rpaulo }
800 1.4.4.2 rpaulo
801 1.4.4.2 rpaulo static void
802 1.4.4.2 rpaulo rtc_register(void)
803 1.4.4.2 rpaulo {
804 1.4.4.2 rpaulo static struct todr_chip_handle tch;
805 1.4.4.2 rpaulo tch.todr_gettime_ymdhms = rtc_get_ymdhms;
806 1.4.4.2 rpaulo tch.todr_settime_ymdhms = rtc_set_ymdhms;
807 1.4.4.2 rpaulo tch.todr_setwen = NULL;
808 1.4.4.2 rpaulo
809 1.4.4.2 rpaulo todr_attach(&tch);
810 1.4.4.2 rpaulo }
811 1.4.4.2 rpaulo
812 1.4.4.2 rpaulo void
813 1.4.4.2 rpaulo setstatclockrate(int arg)
814 1.4.4.2 rpaulo {
815 1.4.4.2 rpaulo }
816