* better
[mascara-docs.git] / i386 / linux-2.3.21 / arch / mips / sgi / kernel / indy_timer.c
blob9a12cca87b5d1f01fdb8da67386085ab27e15e05
1 /* $Id: indy_timer.c,v 1.12 1999/06/13 16:30:36 ralf Exp $
3 * indy_timer.c: Setting up the clock on the INDY 8254 controller.
5 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
6 * Copytight (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
7 */
8 #include <linux/errno.h>
9 #include <linux/init.h>
10 #include <linux/sched.h>
11 #include <linux/kernel.h>
12 #include <linux/param.h>
13 #include <linux/string.h>
14 #include <linux/mm.h>
15 #include <linux/interrupt.h>
16 #include <linux/timex.h>
17 #include <linux/kernel_stat.h>
19 #include <asm/bootinfo.h>
20 #include <asm/io.h>
21 #include <asm/irq.h>
22 #include <asm/ptrace.h>
23 #include <asm/system.h>
24 #include <asm/sgi.h>
25 #include <asm/sgialib.h>
26 #include <asm/sgihpc.h>
27 #include <asm/sgint23.h>
30 /* Because of a bug in the i8254 timer we need to use the onchip r4k
31 * counter as our system wide timer interrupt running at 100HZ.
33 static unsigned long r4k_offset; /* Amount to increment compare reg each time */
34 static unsigned long r4k_cur; /* What counter should be at next timer irq */
36 static inline void ack_r4ktimer(unsigned long newval)
38 write_32bit_cp0_register(CP0_COMPARE, newval);
41 static int set_rtc_mmss(unsigned long nowtime)
43 struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS;
44 int retval = 0;
45 int real_seconds, real_minutes, clock_minutes;
47 #define FROB_FROM_CLOCK(x) (((x) & 0xf) | ((((x) & 0xf0) >> 4) * 10));
48 #define FROB_TO_CLOCK(x) ((((((x) & 0xff) / 10)<<4) | (((x) & 0xff) % 10)) & 0xff)
50 clock->cmd &= ~(0x80);
51 clock_minutes = clock->min;
52 clock->cmd |= (0x80);
54 clock_minutes = FROB_FROM_CLOCK(clock_minutes);
55 real_seconds = nowtime % 60;
56 real_minutes = nowtime / 60;
58 if(((abs(real_minutes - clock_minutes) + 15)/30) & 1)
59 real_minutes += 30; /* correct for half hour time zone */
61 real_minutes %= 60;
62 if(abs(real_minutes - clock_minutes) < 30) {
63 /* Force clock oscillator to be on. */
64 clock->month &= ~(0x80);
66 /* Write real_seconds and real_minutes into the Dallas. */
67 clock->cmd &= ~(0x80);
68 clock->sec = real_seconds;
69 clock->min = real_minutes;
70 clock->cmd |= (0x80);
71 } else
72 return -1;
74 #undef FROB_FROM_CLOCK
75 #undef FROB_TO_CLOCK
77 return retval;
80 static long last_rtc_update = 0;
81 unsigned long missed_heart_beats = 0;
83 void indy_timer_interrupt(struct pt_regs *regs)
85 unsigned long count;
86 int irq = 7;
88 /* Ack timer and compute new compare. */
89 count = read_32bit_cp0_register(CP0_COUNT);
90 /* This has races. */
91 if ((count - r4k_cur) >= r4k_offset) {
92 /* If this happens to often we'll need to compensate. */
93 missed_heart_beats++;
94 r4k_cur = count + r4k_offset;
96 else
97 r4k_cur += r4k_offset;
98 ack_r4ktimer(r4k_cur);
99 kstat.irqs[0][irq]++;
100 do_timer(regs);
102 /* We update the Dallas time of day approx. every 11 minutes,
103 * because of how the numbers work out we need to make
104 * absolutely sure we do this update within 500ms before the
105 * next second starts, thus the following code.
107 if ((time_status & STA_UNSYNC) == 0 &&
108 xtime.tv_sec > last_rtc_update + 660 &&
109 xtime.tv_usec >= 500000 - (tick >> 1) &&
110 xtime.tv_usec <= 500000 + (tick >> 1))
111 if (set_rtc_mmss(xtime.tv_sec) == 0)
112 last_rtc_update = xtime.tv_sec;
113 else
114 last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
117 static unsigned long dosample(volatile unsigned char *tcwp,
118 volatile unsigned char *tc2p)
120 unsigned long ct0, ct1;
121 unsigned char msb, lsb;
123 /* Start the counter. */
124 *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MRGEN);
125 *tc2p = (SGINT_TCSAMP_COUNTER & 0xff);
126 *tc2p = (SGINT_TCSAMP_COUNTER >> 8);
128 /* Get initial counter invariant */
129 ct0 = read_32bit_cp0_register(CP0_COUNT);
131 /* Latch and spin until top byte of counter2 is zero */
132 do {
133 *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT);
134 lsb = *tc2p;
135 msb = *tc2p;
136 ct1 = read_32bit_cp0_register(CP0_COUNT);
137 } while(msb);
139 /* Stop the counter. */
140 *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST);
142 /* Return the difference, this is how far the r4k counter increments
143 * for every one HZ.
145 return ct1 - ct0;
148 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
149 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
150 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
152 * [For the Julian calendar (which was used in Russia before 1917,
153 * Britain & colonies before 1752, anywhere else before 1582,
154 * and is still in use by some communities) leave out the
155 * -year/100+year/400 terms, and add 10.]
157 * This algorithm was first published by Gauss (I think).
159 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
160 * machines were long is 32-bit! (However, as time_t is signed, we
161 * will already get problems at other places on 2038-01-19 03:14:08)
163 static inline unsigned long mktime(unsigned int year, unsigned int mon,
164 unsigned int day, unsigned int hour,
165 unsigned int min, unsigned int sec)
167 if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
168 mon += 12; /* Puts Feb last since it has leap day */
169 year -= 1;
171 return (((
172 (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
173 year*365 - 719499
174 )*24 + hour /* now have hours */
175 )*60 + min /* now have minutes */
176 )*60 + sec; /* finally seconds */
179 static unsigned long __init get_indy_time(void)
181 struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS;
182 unsigned int year, mon, day, hour, min, sec;
184 /* Freeze it. */
185 clock->cmd &= ~(0x80);
187 /* Read regs. */
188 sec = clock->sec;
189 min = clock->min;
190 hour = (clock->hr & 0x3f);
191 day = (clock->date & 0x3f);
192 mon = (clock->month & 0x1f);
193 year = clock->year;
195 /* Unfreeze clock. */
196 clock->cmd |= 0x80;
198 /* Frob the bits. */
199 #define FROB1(x) (((x) & 0xf) + ((((x) & 0xf0) >> 4) * 10));
200 #define FROB2(x) (((x) & 0xf) + (((((x) & 0xf0) >> 4) & 0x3) * 10));
202 /* XXX Should really check that secs register is the same
203 * XXX as when we first read it and if not go back and
204 * XXX read the regs above again.
206 sec = FROB1(sec); min = FROB1(min); day = FROB1(day);
207 mon = FROB1(mon); year = FROB1(year);
208 hour = FROB2(hour);
210 #undef FROB1
211 #undef FROB2
213 /* Wheee... */
214 if(year < 45)
215 year += 30;
216 if ((year += 1940) < 1970)
217 year += 100;
219 return mktime(year, mon, day, hour, min, sec);
222 #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
224 void __init indy_timer_init(void)
226 struct sgi_ioc_timers *p;
227 volatile unsigned char *tcwp, *tc2p;
229 /* Figure out the r4k offset, the algorithm is very simple
230 * and works in _all_ cases as long as the 8254 counter
231 * register itself works ok (as an interrupt driving timer
232 * it does not because of bug, this is why we are using
233 * the onchip r4k counter/compare register to serve this
234 * purpose, but for r4k_offset calculation it will work
235 * ok for us). There are other very complicated ways
236 * of performing this calculation but this one works just
237 * fine so I am not going to futz around. ;-)
239 p = ioc_timers;
240 tcwp = &p->tcword;
241 tc2p = &p->tcnt2;
243 printk("calculating r4koff... ");
244 dosample(tcwp, tc2p); /* First sample. */
245 dosample(tcwp, tc2p); /* Eat one. */
246 r4k_offset = dosample(tcwp, tc2p); /* Second sample. */
248 printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
250 r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
251 write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
252 set_cp0_status(ST0_IM, ALLINTS);
253 sti();
255 /* Read time from the dallas chipset. */
256 xtime.tv_sec = get_indy_time();
257 xtime.tv_usec = 0;
260 void indy_8254timer_irq(void)
262 int cpu = smp_processor_id();
263 int irq = 4;
265 hardirq_enter(cpu);
266 kstat.irqs[0][irq]++;
267 printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n");
268 prom_getchar();
269 prom_imode();
270 hardirq_exit(cpu);
273 void do_gettimeofday(struct timeval *tv)
275 unsigned long flags;
277 save_and_cli(flags);
278 *tv = xtime;
279 restore_flags(flags);
282 void do_settimeofday(struct timeval *tv)
284 cli();
285 xtime = *tv;
286 time_state = TIME_BAD;
287 time_maxerror = MAXPHASE;
288 time_esterror = MAXPHASE;
289 sti();