]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/i386/kernel/timers/timer_pit.c
e42e46d351591d583782921f6b30e5b302b2285a
[karo-tx-linux.git] / arch / i386 / kernel / timers / timer_pit.c
1 /*
2  * This code largely moved from arch/i386/kernel/time.c.
3  * See comments there for proper credits.
4  */
5
6 #include <linux/spinlock.h>
7 #include <linux/module.h>
8 #include <linux/device.h>
9 #include <linux/sysdev.h>
10 #include <linux/timex.h>
11 #include <asm/delay.h>
12 #include <asm/mpspec.h>
13 #include <asm/timer.h>
14 #include <asm/smp.h>
15 #include <asm/io.h>
16 #include <asm/arch_hooks.h>
17 #include <asm/i8253.h>
18
19 #include "do_timer.h"
20 #include "io_ports.h"
21
22 static int count_p; /* counter in get_offset_pit() */
23
24 static int __init init_pit(char* override)
25 {
26         /* check clock override */
27         if (override[0] && strncmp(override,"pit",3))
28                 printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
29  
30         count_p = LATCH;
31         return 0;
32 }
33
34 static void mark_offset_pit(void)
35 {
36         /* nothing needed */
37 }
38
39 static unsigned long long monotonic_clock_pit(void)
40 {
41         return 0;
42 }
43
44 static void delay_pit(unsigned long loops)
45 {
46         int d0;
47         __asm__ __volatile__(
48                 "\tjmp 1f\n"
49                 ".align 16\n"
50                 "1:\tjmp 2f\n"
51                 ".align 16\n"
52                 "2:\tdecl %0\n\tjns 2b"
53                 :"=&a" (d0)
54                 :"0" (loops));
55 }
56
57
58 /* This function must be called with xtime_lock held.
59  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
60  * 
61  * However, the pc-audio speaker driver changes the divisor so that
62  * it gets interrupted rather more often - it loads 64 into the
63  * counter rather than 11932! This has an adverse impact on
64  * do_gettimeoffset() -- it stops working! What is also not
65  * good is that the interval that our timer function gets called
66  * is no longer 10.0002 ms, but 9.9767 ms. To get around this
67  * would require using a different timing source. Maybe someone
68  * could use the RTC - I know that this can interrupt at frequencies
69  * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
70  * it so that at startup, the timer code in sched.c would select
71  * using either the RTC or the 8253 timer. The decision would be
72  * based on whether there was any other device around that needed
73  * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
74  * and then do some jiggery to have a version of do_timer that 
75  * advanced the clock by 1/1024 s. Every time that reached over 1/100
76  * of a second, then do all the old code. If the time was kept correct
77  * then do_gettimeoffset could just return 0 - there is no low order
78  * divider that can be accessed.
79  *
80  * Ideally, you would be able to use the RTC for the speaker driver,
81  * but it appears that the speaker driver really needs interrupt more
82  * often than every 120 us or so.
83  *
84  * Anyway, this needs more thought....          pjsg (1993-08-28)
85  * 
86  * If you are really that interested, you should be reading
87  * comp.protocols.time.ntp!
88  */
89
90 static unsigned long get_offset_pit(void)
91 {
92         int count;
93         unsigned long flags;
94         static unsigned long jiffies_p = 0;
95
96         /*
97          * cache volatile jiffies temporarily; we have xtime_lock. 
98          */
99         unsigned long jiffies_t;
100
101         spin_lock_irqsave(&i8253_lock, flags);
102         /* timer count may underflow right here */
103         outb_p(0x00, PIT_MODE); /* latch the count ASAP */
104
105         count = inb_p(PIT_CH0); /* read the latched count */
106
107         /*
108          * We do this guaranteed double memory access instead of a _p 
109          * postfix in the previous port access. Wheee, hackady hack
110          */
111         jiffies_t = jiffies;
112
113         count |= inb_p(PIT_CH0) << 8;
114         
115         /* VIA686a test code... reset the latch if count > max + 1 */
116         if (count > LATCH) {
117                 outb_p(0x34, PIT_MODE);
118                 outb_p(LATCH & 0xff, PIT_CH0);
119                 outb(LATCH >> 8, PIT_CH0);
120                 count = LATCH - 1;
121         }
122         
123         /*
124          * avoiding timer inconsistencies (they are rare, but they happen)...
125          * there are two kinds of problems that must be avoided here:
126          *  1. the timer counter underflows
127          *  2. hardware problem with the timer, not giving us continuous time,
128          *     the counter does small "jumps" upwards on some Pentium systems,
129          *     (see c't 95/10 page 335 for Neptun bug.)
130          */
131
132         if( jiffies_t == jiffies_p ) {
133                 if( count > count_p ) {
134                         /* the nutcase */
135                         count = do_timer_overflow(count);
136                 }
137         } else
138                 jiffies_p = jiffies_t;
139
140         count_p = count;
141
142         spin_unlock_irqrestore(&i8253_lock, flags);
143
144         count = ((LATCH-1) - count) * TICK_SIZE;
145         count = (count + LATCH/2) / LATCH;
146
147         return count;
148 }
149
150
151 /* tsc timer_opts struct */
152 struct timer_opts timer_pit = {
153         .name = "pit",
154         .mark_offset = mark_offset_pit, 
155         .get_offset = get_offset_pit,
156         .monotonic_clock = monotonic_clock_pit,
157         .delay = delay_pit,
158 };
159
160 struct init_timer_opts __initdata timer_pit_init = {
161         .init = init_pit, 
162         .opts = &timer_pit,
163 };
164
165 void setup_pit_timer(void)
166 {
167         unsigned long flags;
168
169         spin_lock_irqsave(&i8253_lock, flags);
170         outb_p(0x34,PIT_MODE);          /* binary, mode 2, LSB/MSB, ch 0 */
171         udelay(10);
172         outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
173         udelay(10);
174         outb(LATCH >> 8 , PIT_CH0);     /* MSB */
175         spin_unlock_irqrestore(&i8253_lock, flags);
176 }