1 #include <console/console.h>
3 #include <cpu/x86/msr.h>
4 #include <cpu/x86/tsc.h>
5 #include <smp/spinlock.h>
8 static unsigned long clocks_per_usec;
10 #if (CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2 == 1)
11 #define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
13 /* ------ Calibrate the TSC -------
14 * Too much 64-bit arithmetic here to do this cleanly in C, and for
15 * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
16 * output busy loop as low as possible. We avoid reading the CTC registers
17 * directly because of the awkward 8-bit access mechanism of the 82C54
21 #define CALIBRATE_INTERVAL ((20*CLOCK_TICK_RATE)/1000) /* 20ms */
22 #define CALIBRATE_DIVISOR (20*1000) /* 20ms / 20000 == 1usec */
24 static unsigned long long calibrate_tsc(void)
26 /* Set the Gate high, disable speaker */
27 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
30 * Now let's take care of CTC channel 2
32 * Set the Gate high, program CTC channel 2 for mode 0,
33 * (interrupt on terminal count mode), binary count,
34 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
36 outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
37 outb(CALIBRATE_INTERVAL & 0xff, 0x42); /* LSB of count */
38 outb(CALIBRATE_INTERVAL >> 8, 0x42); /* MSB of count */
49 } while ((inb(0x61) & 0x20) == 0);
52 /* Error: ECTCNEVERSET */
56 /* 64-bit subtract - gcc just messes up with long longs */
57 __asm__("subl %2,%0\n\t"
59 :"=a" (end.lo), "=d" (end.hi)
60 :"g" (start.lo), "g" (start.hi),
61 "0" (end.lo), "1" (end.hi));
63 /* Error: ECPUTOOFAST */
68 /* Error: ECPUTOOSLOW */
69 if (end.lo <= CALIBRATE_DIVISOR)
72 return (end.lo + CALIBRATE_DIVISOR -1)/CALIBRATE_DIVISOR;
76 * The CTC wasn't reliable: we got a hit on the very first read,
77 * or the CPU was so fast/slow that the quotient wouldn't fit in
81 printk(BIOS_ERR, "bad_ctc\n");
85 #else /* CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2 */
88 * this is the "no timer2" version.
89 * to calibrate tsc, we get a TSC reading, then do 1,000,000 outbs to port 0x80
90 * then we read TSC again, and divide the difference by 1,000,000
91 * we have found on a wide range of machines that this gives us a a
92 * good microsecond value
93 * to +- 10%. On a dual AMD 1.6 Ghz box, it gives us .97 microseconds, and on a
94 * 267 Mhz. p5, it gives us 1.1 microseconds.
95 * also, since gcc now supports long long, we use that.
96 * also no unsigned long long / operator, so we play games.
97 * about the only thing you can do with long longs, it seems,
98 *is return them and assign them.
99 * (and do asm on them, yuck)
100 * so avoid all ops on long longs.
102 static unsigned long long calibrate_tsc(void)
104 unsigned long long start, end, delta;
105 unsigned long result, count;
107 printk(BIOS_SPEW, "Calibrating delay loop...\n");
109 // no udivdi3 because we don't like libgcc. (only in x86emu)
110 // so we count to 1<< 20 and then right shift 20
111 for(count = 0; count < (1<<20); count ++)
116 // make delta be (endhigh - starthigh) + (endlow - startlow)
118 // do it this way to avoid gcc warnings.
119 start = tsc_start.hi;
127 // at this point we have a delta for 1,000,000 outbs. Now rescale for one microsecond.
129 // save this for microsecond timing.
131 printk(BIOS_SPEW, "end %llx, start %llx\n", end, start);
132 printk(BIOS_SPEW, "32-bit delta %ld\n", (unsigned long) delta);
134 printk(BIOS_SPEW, "%s 32-bit result is %ld\n",
141 #endif /* CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2*/
143 void init_timer(void)
145 if (!clocks_per_usec) {
146 clocks_per_usec = calibrate_tsc();
147 printk(BIOS_INFO, "clocks_per_usec: %lu\n", clocks_per_usec);
151 void udelay(unsigned us)
153 unsigned long long count;
154 unsigned long long stop;
155 unsigned long long clocks;
159 clocks *= clocks_per_usec;
161 stop = clocks + count;
162 while(stop > count) {