pcrtc.c revision 162954
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz and Don Ahn.
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 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	from: @(#)clock.c	7.2 (Berkeley) 5/12/91
33 * $FreeBSD: head/sys/pc98/cbus/pcrtc.c 162954 2006-10-02 12:59:59Z phk $
34 */
35
36/*
37 * Routines to handle clock hardware.
38 */
39
40/*
41 * inittodr, settodr and support routines written
42 * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
43 *
44 * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
45 */
46
47/*
48 * modified for PC98 by Kakefuda
49 */
50
51#include "opt_apic.h"
52#include "opt_clock.h"
53#include "opt_isa.h"
54#include "opt_mca.h"
55
56#include <sys/param.h>
57#include <sys/systm.h>
58#include <sys/bus.h>
59#include <sys/clock.h>
60#include <sys/lock.h>
61#include <sys/kdb.h>
62#include <sys/mutex.h>
63#include <sys/proc.h>
64#include <sys/time.h>
65#include <sys/timetc.h>
66#include <sys/kernel.h>
67#include <sys/limits.h>
68#include <sys/module.h>
69#include <sys/sysctl.h>
70#include <sys/cons.h>
71#include <sys/power.h>
72
73#include <machine/clock.h>
74#include <machine/cpu.h>
75#include <machine/cputypes.h>
76#include <machine/frame.h>
77#include <machine/intr_machdep.h>
78#include <machine/md_var.h>
79#include <machine/psl.h>
80#ifdef DEV_APIC
81#include <machine/apicvar.h>
82#endif
83#include <machine/specialreg.h>
84#include <machine/ppireg.h>
85#include <machine/timerreg.h>
86
87#include <i386/isa/icu.h>
88#include <pc98/cbus/cbus.h>
89#include <pc98/pc98/pc98_machdep.h>
90#ifdef DEV_ISA
91#include <isa/isavar.h>
92#endif
93
94/*
95 * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
96 * can use a simple formula for leap years.
97 */
98#define	LEAPYEAR(y) (((u_int)(y) % 4 == 0) ? 1 : 0)
99#define DAYSPERYEAR   (31+28+31+30+31+30+31+31+30+31+30+31)
100
101#define	TIMER_DIV(x) ((timer_freq + (x) / 2) / (x))
102
103int	adjkerntz;		/* local offset from GMT in seconds */
104int	clkintr_pending;
105int	disable_rtc_set;	/* disable resettodr() if != 0 */
106int	pscnt = 1;
107int	psdiv = 1;
108int	statclock_disable;
109#ifndef TIMER_FREQ
110#define TIMER_FREQ   2457600
111#endif
112u_int	timer_freq = TIMER_FREQ;
113int	timer0_max_count;
114int	timer0_real_max_count;
115int	wall_cmos_clock;	/* wall CMOS clock assumed if != 0 */
116struct mtx clock_lock;
117
118static	int	beeping = 0;
119static	const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
120static	struct intsrc *i8254_intsrc;
121static	u_int32_t i8254_lastcount;
122static	u_int32_t i8254_offset;
123static	int	(*i8254_pending)(struct intsrc *);
124static	int	i8254_ticked;
125static	int	using_lapic_timer;
126
127/* Values for timerX_state: */
128#define	RELEASED	0
129#define	RELEASE_PENDING	1
130#define	ACQUIRED	2
131#define	ACQUIRE_PENDING	3
132
133static 	u_char	timer1_state;
134static	u_char	timer2_state;
135static void rtc_serialcombit(int);
136static void rtc_serialcom(int);
137static int rtc_inb(void);
138static void rtc_outb(int);
139
140static	unsigned i8254_get_timecount(struct timecounter *tc);
141static	unsigned i8254_simple_get_timecount(struct timecounter *tc);
142static	void	set_timer_freq(u_int freq, int intr_freq);
143
144static struct timecounter i8254_timecounter = {
145	i8254_get_timecount,	/* get_timecount */
146	0,			/* no poll_pps */
147	~0u,			/* counter_mask */
148	0,			/* frequency */
149	"i8254",		/* name */
150	0			/* quality */
151};
152
153static void
154clkintr(struct trapframe *frame)
155{
156
157	if (timecounter->tc_get_timecount == i8254_get_timecount) {
158		mtx_lock_spin(&clock_lock);
159		if (i8254_ticked)
160			i8254_ticked = 0;
161		else {
162			i8254_offset += timer0_max_count;
163			i8254_lastcount = 0;
164		}
165		clkintr_pending = 0;
166		mtx_unlock_spin(&clock_lock);
167	}
168	KASSERT(!using_lapic_timer, ("clk interrupt enabled with lapic timer"));
169	hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
170}
171
172int
173acquire_timer1(int mode)
174{
175
176	if (timer1_state != RELEASED)
177		return (-1);
178	timer1_state = ACQUIRED;
179
180	/*
181	 * This access to the timer registers is as atomic as possible
182	 * because it is a single instruction.  We could do better if we
183	 * knew the rate.  Use of splclock() limits glitches to 10-100us,
184	 * and this is probably good enough for timer2, so we aren't as
185	 * careful with it as with timer0.
186	 */
187	outb(TIMER_MODE, TIMER_SEL1 | (mode & 0x3f));
188
189	return (0);
190}
191
192int
193acquire_timer2(int mode)
194{
195
196	if (timer2_state != RELEASED)
197		return (-1);
198	timer2_state = ACQUIRED;
199
200	/*
201	 * This access to the timer registers is as atomic as possible
202	 * because it is a single instruction.  We could do better if we
203	 * knew the rate.  Use of splclock() limits glitches to 10-100us,
204	 * and this is probably good enough for timer2, so we aren't as
205	 * careful with it as with timer0.
206	 */
207	outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f));
208
209	return (0);
210}
211
212int
213release_timer1()
214{
215
216	if (timer1_state != ACQUIRED)
217		return (-1);
218	timer1_state = RELEASED;
219	outb(TIMER_MODE, TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT);
220	return (0);
221}
222
223int
224release_timer2()
225{
226
227	if (timer2_state != ACQUIRED)
228		return (-1);
229	timer2_state = RELEASED;
230	outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT);
231	return (0);
232}
233
234
235static int
236getit(void)
237{
238	int high, low;
239
240	mtx_lock_spin(&clock_lock);
241
242	/* Select timer0 and latch counter value. */
243	outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
244
245	low = inb(TIMER_CNTR0);
246	high = inb(TIMER_CNTR0);
247
248	mtx_unlock_spin(&clock_lock);
249	return ((high << 8) | low);
250}
251
252/*
253 * Wait "n" microseconds.
254 * Relies on timer 1 counting down from (timer_freq / hz)
255 * Note: timer had better have been programmed before this is first used!
256 */
257void
258DELAY(int n)
259{
260	int delta, prev_tick, tick, ticks_left;
261
262#ifdef DELAYDEBUG
263	int getit_calls = 1;
264	int n1;
265	static int state = 0;
266
267	if (state == 0) {
268		state = 1;
269		for (n1 = 1; n1 <= 10000000; n1 *= 10)
270			DELAY(n1);
271		state = 2;
272	}
273	if (state == 1)
274		printf("DELAY(%d)...", n);
275#endif
276	/*
277	 * Guard against the timer being uninitialized if we are called
278	 * early for console i/o.
279	 */
280	if (timer0_max_count == 0)
281		set_timer_freq(timer_freq, hz);
282
283	/*
284	 * Read the counter first, so that the rest of the setup overhead is
285	 * counted.  Guess the initial overhead is 20 usec (on most systems it
286	 * takes about 1.5 usec for each of the i/o's in getit().  The loop
287	 * takes about 6 usec on a 486/33 and 13 usec on a 386/20.  The
288	 * multiplications and divisions to scale the count take a while).
289	 *
290	 * However, if ddb is active then use a fake counter since reading
291	 * the i8254 counter involves acquiring a lock.  ddb must not do
292	 * locking for many reasons, but it calls here for at least atkbd
293	 * input.
294	 */
295#ifdef KDB
296	if (kdb_active)
297		prev_tick = 1;
298	else
299#endif
300		prev_tick = getit();
301	n -= 0;			/* XXX actually guess no initial overhead */
302	/*
303	 * Calculate (n * (timer_freq / 1e6)) without using floating point
304	 * and without any avoidable overflows.
305	 */
306	if (n <= 0)
307		ticks_left = 0;
308	else if (n < 256)
309		/*
310		 * Use fixed point to avoid a slow division by 1000000.
311		 * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
312		 * 2^15 is the first power of 2 that gives exact results
313		 * for n between 0 and 256.
314		 */
315		ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
316	else
317		/*
318		 * Don't bother using fixed point, although gcc-2.7.2
319		 * generates particularly poor code for the long long
320		 * division, since even the slow way will complete long
321		 * before the delay is up (unless we're interrupted).
322		 */
323		ticks_left = ((u_int)n * (long long)timer_freq + 999999)
324			     / 1000000;
325
326	while (ticks_left > 0) {
327#ifdef KDB
328		if (kdb_active) {
329			outb(0x5f, 0);
330			tick = prev_tick - 1;
331			if (tick <= 0)
332				tick = timer0_max_count;
333		} else
334#endif
335			tick = getit();
336#ifdef DELAYDEBUG
337		++getit_calls;
338#endif
339		delta = prev_tick - tick;
340		prev_tick = tick;
341		if (delta < 0) {
342			delta += timer0_max_count;
343			/*
344			 * Guard against timer0_max_count being wrong.
345			 * This shouldn't happen in normal operation,
346			 * but it may happen if set_timer_freq() is
347			 * traced.
348			 */
349			if (delta < 0)
350				delta = 0;
351		}
352		ticks_left -= delta;
353	}
354#ifdef DELAYDEBUG
355	if (state == 1)
356		printf(" %d calls to getit() at %d usec each\n",
357		       getit_calls, (n + 5) / getit_calls);
358#endif
359}
360
361static void
362sysbeepstop(void *chan)
363{
364	ppi_spkr_off();		/* disable counter1 output to speaker */
365	timer_spkr_release();
366	beeping = 0;
367}
368
369int
370sysbeep(int pitch, int period)
371{
372	int x = splclock();
373
374	if (timer_spkr_acquire())
375		if (!beeping) {
376			/* Something else owns it. */
377			splx(x);
378			return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */
379		}
380	disable_intr();
381	spkr_set_pitch(pitch);
382	enable_intr();
383	if (!beeping) {
384		/* enable counter1 output to speaker */
385		ppi_spkr_on();
386		beeping = period;
387		timeout(sysbeepstop, (void *)NULL, period);
388	}
389	splx(x);
390	return (0);
391}
392
393
394unsigned int delaycount;
395#define FIRST_GUESS	0x2000
396static void findcpuspeed(void)
397{
398	int i;
399	int remainder;
400
401	/* Put counter in count down mode */
402	outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
403	outb(TIMER_CNTR0, 0xff);
404	outb(TIMER_CNTR0, 0xff);
405	for (i = FIRST_GUESS; i; i--)
406		;
407	remainder = getit();
408	delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff - remainder);
409}
410
411static u_int
412calibrate_clocks(void)
413{
414	int	timeout;
415	u_int	count, prev_count, tot_count;
416	u_short	sec, start_sec;
417
418	if (bootverbose)
419	        printf("Calibrating clock(s) ... ");
420	/* Check ARTIC. */
421	if (!(PC98_SYSTEM_PARAMETER(0x458) & 0x80) &&
422	    !(PC98_SYSTEM_PARAMETER(0x45b) & 0x04))
423		goto fail;
424	timeout = 100000000;
425
426	/* Read the ARTIC. */
427	sec = inw(0x5e);
428
429	/* Wait for the ARTIC to changes. */
430	start_sec = sec;
431	for (;;) {
432		sec = inw(0x5e);
433		if (sec != start_sec)
434			break;
435		if (--timeout == 0)
436			goto fail;
437	}
438	prev_count = getit();
439	if (prev_count == 0 || prev_count > timer0_max_count)
440		goto fail;
441	tot_count = 0;
442
443	start_sec = sec;
444	for (;;) {
445		sec = inw(0x5e);
446		count = getit();
447		if (count == 0 || count > timer0_max_count)
448			goto fail;
449		if (count > prev_count)
450			tot_count += prev_count - (count - timer0_max_count);
451		else
452			tot_count += prev_count - count;
453		prev_count = count;
454		if ((sec == start_sec + 1200) || /* 1200 = 307.2KHz >> 8 */
455		    (sec < start_sec &&
456		        (u_int)sec + 0x10000 == (u_int)start_sec + 1200))
457			break;
458		if (--timeout == 0)
459			goto fail;
460	}
461
462	if (bootverbose) {
463	        printf("i8254 clock: %u Hz\n", tot_count);
464	}
465	return (tot_count);
466
467fail:
468	if (bootverbose)
469	        printf("failed, using default i8254 clock of %u Hz\n",
470		       timer_freq);
471	return (timer_freq);
472}
473
474static void
475set_timer_freq(u_int freq, int intr_freq)
476{
477	int new_timer0_real_max_count;
478
479	i8254_timecounter.tc_frequency = freq;
480	mtx_lock_spin(&clock_lock);
481	timer_freq = freq;
482	if (using_lapic_timer)
483		new_timer0_real_max_count = 0x10000;
484	else
485		new_timer0_real_max_count = TIMER_DIV(intr_freq);
486	if (new_timer0_real_max_count != timer0_real_max_count) {
487		timer0_real_max_count = new_timer0_real_max_count;
488		if (timer0_real_max_count == 0x10000)
489			timer0_max_count = 0xffff;
490		else
491			timer0_max_count = timer0_real_max_count;
492		outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
493		outb(TIMER_CNTR0, timer0_real_max_count & 0xff);
494		outb(TIMER_CNTR0, timer0_real_max_count >> 8);
495	}
496	mtx_unlock_spin(&clock_lock);
497}
498
499static void
500i8254_restore(void)
501{
502
503	mtx_lock_spin(&clock_lock);
504	outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
505	outb(TIMER_CNTR0, timer0_real_max_count & 0xff);
506	outb(TIMER_CNTR0, timer0_real_max_count >> 8);
507	mtx_unlock_spin(&clock_lock);
508}
509
510
511/*
512 * Restore all the timers non-atomically (XXX: should be atomically).
513 *
514 * This function is called from pmtimer_resume() to restore all the timers.
515 * This should not be necessary, but there are broken laptops that do not
516 * restore all the timers on resume.
517 */
518void
519timer_restore(void)
520{
521
522	i8254_restore();		/* restore timer_freq and hz */
523}
524
525/*
526 * Initialize 8254 timer 0 early so that it can be used in DELAY().
527 * XXX initialization of other timers is unintentionally left blank.
528 */
529void
530startrtclock()
531{
532	u_int delta, freq;
533
534	findcpuspeed();
535	if (pc98_machine_type & M_8M)
536		timer_freq = 1996800L; /* 1.9968 MHz */
537	else
538		timer_freq = 2457600L; /* 2.4576 MHz */
539
540	set_timer_freq(timer_freq, hz);
541	freq = calibrate_clocks();
542#ifdef CLK_CALIBRATION_LOOP
543	if (bootverbose) {
544		printf(
545		"Press a key on the console to abort clock calibration\n");
546		while (cncheckc() == -1)
547			calibrate_clocks();
548	}
549#endif
550
551	/*
552	 * Use the calibrated i8254 frequency if it seems reasonable.
553	 * Otherwise use the default, and don't use the calibrated i586
554	 * frequency.
555	 */
556	delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq;
557	if (delta < timer_freq / 100) {
558#ifndef CLK_USE_I8254_CALIBRATION
559		if (bootverbose)
560			printf(
561"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n");
562		freq = timer_freq;
563#endif
564		timer_freq = freq;
565	} else {
566		if (bootverbose)
567			printf(
568		    "%d Hz differs from default of %d Hz by more than 1%%\n",
569			       freq, timer_freq);
570	}
571
572	set_timer_freq(timer_freq, hz);
573	tc_init(&i8254_timecounter);
574
575	init_TSC();
576}
577
578static void
579rtc_serialcombit(int i)
580{
581	outb(IO_RTC, ((i&0x01)<<5)|0x07);
582	DELAY(1);
583	outb(IO_RTC, ((i&0x01)<<5)|0x17);
584	DELAY(1);
585	outb(IO_RTC, ((i&0x01)<<5)|0x07);
586	DELAY(1);
587}
588
589static void
590rtc_serialcom(int i)
591{
592	rtc_serialcombit(i&0x01);
593	rtc_serialcombit((i&0x02)>>1);
594	rtc_serialcombit((i&0x04)>>2);
595	rtc_serialcombit((i&0x08)>>3);
596	outb(IO_RTC, 0x07);
597	DELAY(1);
598	outb(IO_RTC, 0x0f);
599	DELAY(1);
600	outb(IO_RTC, 0x07);
601 	DELAY(1);
602}
603
604static void
605rtc_outb(int val)
606{
607	int s;
608	int sa = 0;
609
610	for (s=0;s<8;s++) {
611	    sa = ((val >> s) & 0x01) ? 0x27 : 0x07;
612	    outb(IO_RTC, sa);		/* set DI & CLK 0 */
613	    DELAY(1);
614	    outb(IO_RTC, sa | 0x10);	/* CLK 1 */
615	    DELAY(1);
616	}
617	outb(IO_RTC, sa & 0xef);	/* CLK 0 */
618}
619
620static int
621rtc_inb(void)
622{
623	int s;
624	int sa = 0;
625
626	for (s=0;s<8;s++) {
627	    sa |= ((inb(0x33) & 0x01) << s);
628	    outb(IO_RTC, 0x17);	/* CLK 1 */
629	    DELAY(1);
630	    outb(IO_RTC, 0x07);	/* CLK 0 */
631	    DELAY(2);
632	}
633	return sa;
634}
635
636/*
637 * Initialize the time of day register, based on the time base which is, e.g.
638 * from a filesystem.
639 */
640void
641inittodr(time_t base)
642{
643	unsigned long	sec, days;
644	int		year, month;
645	int		y, m, s;
646	struct timespec ts;
647	int		second, min, hour;
648
649	if (base) {
650		s = splclock();
651		ts.tv_sec = base;
652		ts.tv_nsec = 0;
653		tc_setclock(&ts);
654		splx(s);
655	}
656
657	rtc_serialcom(0x03);	/* Time Read */
658	rtc_serialcom(0x01);	/* Register shift command. */
659	DELAY(20);
660
661	second = bcd2bin(rtc_inb() & 0xff);	/* sec */
662	min = bcd2bin(rtc_inb() & 0xff);	/* min */
663	hour = bcd2bin(rtc_inb() & 0xff);	/* hour */
664	days = bcd2bin(rtc_inb() & 0xff) - 1;	/* date */
665
666	month = (rtc_inb() >> 4) & 0x0f;	/* month */
667	for (m = 1; m <	month; m++)
668		days +=	daysinmonth[m-1];
669	year = bcd2bin(rtc_inb() & 0xff) + 1900;	/* year */
670	/* 2000 year problem */
671	if (year < 1995)
672		year += 100;
673	if (year < 1970)
674		goto wrong_time;
675	for (y = 1970; y < year; y++)
676		days +=	DAYSPERYEAR + LEAPYEAR(y);
677	if ((month > 2)	&& LEAPYEAR(year))
678		days ++;
679	sec = ((( days * 24 +
680		  hour) * 60 +
681		  min) * 60 +
682		  second);
683	/* sec now contains the	number of seconds, since Jan 1 1970,
684	   in the local	time zone */
685
686	s = splhigh();
687
688	sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
689
690	y = time_second - sec;
691	if (y <= -2 || y >= 2) {
692		/* badly off, adjust it */
693		ts.tv_sec = sec;
694		ts.tv_nsec = 0;
695		tc_setclock(&ts);
696	}
697	splx(s);
698	return;
699
700wrong_time:
701	printf("Invalid time in real time clock.\n");
702	printf("Check and reset the date immediately!\n");
703}
704
705/*
706 * Write system time back to RTC
707 */
708void
709resettodr()
710{
711	unsigned long	tm;
712	int		y, m, s;
713	int		wd;
714
715	if (disable_rtc_set)
716		return;
717
718	s = splclock();
719	tm = time_second;
720	splx(s);
721
722	rtc_serialcom(0x01);	/* Register shift command. */
723
724	/* Calculate local time	to put in RTC */
725
726	tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
727
728	rtc_outb(bin2bcd(tm%60)); tm /= 60;	/* Write back Seconds */
729	rtc_outb(bin2bcd(tm%60)); tm /= 60;	/* Write back Minutes */
730	rtc_outb(bin2bcd(tm%24)); tm /= 24;	/* Write back Hours   */
731
732	/* We have now the days	since 01-01-1970 in tm */
733	wd = (tm + 4) % 7 + 1;			/* Write back Weekday */
734	for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y);
735	     tm >= m;
736	     y++,      m = DAYSPERYEAR + LEAPYEAR(y))
737	     tm -= m;
738
739	/* Now we have the years in y and the day-of-the-year in tm */
740	for (m = 0; ; m++) {
741		int ml;
742
743		ml = daysinmonth[m];
744		if (m == 1 && LEAPYEAR(y))
745			ml++;
746		if (tm < ml)
747			break;
748		tm -= ml;
749	}
750
751	m++;
752	rtc_outb(bin2bcd(tm+1));		/* Write back Day     */
753	rtc_outb((m << 4) | wd);		/* Write back Month & Weekday  */
754	rtc_outb(bin2bcd(y%100));		/* Write back Year    */
755
756	rtc_serialcom(0x02);	/* Time set & Counter hold command. */
757	rtc_serialcom(0x00);	/* Register hold command. */
758}
759
760
761/*
762 * Start both clocks running.
763 */
764void
765cpu_initclocks()
766{
767
768#ifdef DEV_APIC
769	using_lapic_timer = lapic_setup_clock();
770#endif
771	/*
772	 * If we aren't using the local APIC timer to drive the kernel
773	 * clocks, setup the interrupt handler for the 8254 timer 0 so
774	 * that it can drive hardclock().  Otherwise, change the 8254
775	 * timecounter to user a simpler algorithm.
776	 */
777	if (!using_lapic_timer) {
778		intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL,
779		    INTR_TYPE_CLK | INTR_FAST, NULL);
780		i8254_intsrc = intr_lookup_source(0);
781		if (i8254_intsrc != NULL)
782			i8254_pending =
783			    i8254_intsrc->is_pic->pic_source_pending;
784	} else {
785		i8254_timecounter.tc_get_timecount =
786		    i8254_simple_get_timecount;
787		i8254_timecounter.tc_counter_mask = 0xffff;
788		set_timer_freq(timer_freq, hz);
789	}
790
791	init_TSC_tc();
792}
793
794void
795cpu_startprofclock(void)
796{
797}
798
799void
800cpu_stopprofclock(void)
801{
802}
803
804static int
805sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)
806{
807	int error;
808	u_int freq;
809
810	/*
811	 * Use `i8254' instead of `timer' in external names because `timer'
812	 * is is too generic.  Should use it everywhere.
813	 */
814	freq = timer_freq;
815	error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
816	if (error == 0 && req->newptr != NULL)
817		set_timer_freq(freq, hz);
818	return (error);
819}
820
821SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
822    0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU", "");
823
824static unsigned
825i8254_simple_get_timecount(struct timecounter *tc)
826{
827
828	return (timer0_max_count - getit());
829}
830
831static unsigned
832i8254_get_timecount(struct timecounter *tc)
833{
834	u_int count;
835	u_int high, low;
836	u_int eflags;
837
838	eflags = read_eflags();
839	mtx_lock_spin(&clock_lock);
840
841	/* Select timer0 and latch counter value. */
842	outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
843
844	low = inb(TIMER_CNTR0);
845	high = inb(TIMER_CNTR0);
846	count = timer0_max_count - ((high << 8) | low);
847	if (count < i8254_lastcount ||
848	    (!i8254_ticked && (clkintr_pending ||
849	    ((count < 20 || (!(eflags & PSL_I) && count < timer0_max_count / 2u)) &&
850	    i8254_pending != NULL && i8254_pending(i8254_intsrc))))) {
851		i8254_ticked = 1;
852		i8254_offset += timer0_max_count;
853	}
854	i8254_lastcount = count;
855	count += i8254_offset;
856	mtx_unlock_spin(&clock_lock);
857	return (count);
858}
859
860#ifdef DEV_ISA
861/*
862 * Attach to the ISA PnP descriptors for the timer and realtime clock.
863 */
864static struct isa_pnp_id attimer_ids[] = {
865	{ 0x0001d041 /* PNP0100 */, "AT timer" },
866	{ 0x000bd041 /* PNP0B00 */, "AT realtime clock" },
867	{ 0 }
868};
869
870static int
871attimer_probe(device_t dev)
872{
873	int result;
874
875	if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids)) <= 0)
876		device_quiet(dev);
877	return(result);
878}
879
880static int
881attimer_attach(device_t dev)
882{
883	return(0);
884}
885
886static device_method_t attimer_methods[] = {
887	/* Device interface */
888	DEVMETHOD(device_probe,		attimer_probe),
889	DEVMETHOD(device_attach,	attimer_attach),
890	DEVMETHOD(device_detach,	bus_generic_detach),
891	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
892	DEVMETHOD(device_suspend,	bus_generic_suspend),	/* XXX stop statclock? */
893	DEVMETHOD(device_resume,	bus_generic_resume),	/* XXX restart statclock? */
894	{ 0, 0 }
895};
896
897static driver_t attimer_driver = {
898	"attimer",
899	attimer_methods,
900	1,		/* no softc */
901};
902
903static devclass_t attimer_devclass;
904
905DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0);
906#endif /* DEV_ISA */
907