src/: Remove g_ prefixes and _g suffixes from variables
[coreboot.git] / src / drivers / pc80 / pc / i8254.c
blob0b04b393e4aac2944eb0abb300995702789b16ee
1 /*
2 * This file is part of the coreboot project.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <arch/io.h>
15 #include <commonlib/helpers.h>
16 #include <cpu/x86/tsc.h>
17 #include <pc80/i8254.h>
19 /* Initialize i8254 timers */
21 void setup_i8254(void)
23 /* Timer 0 (taken from biosemu) */
24 outb(TIMER0_SEL | WORD_ACCESS | MODE3 | BINARY_COUNT, TIMER_MODE_PORT);
25 outb(0x00, TIMER0_PORT);
26 outb(0x00, TIMER0_PORT);
28 /* Timer 1 */
29 outb(TIMER1_SEL | LOBYTE_ACCESS | MODE3 | BINARY_COUNT,
30 TIMER_MODE_PORT);
31 outb(0x12, TIMER1_PORT);
34 #define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
36 /* ------ Calibrate the TSC -------
37 * Too much 64-bit arithmetic here to do this cleanly in C, and for
38 * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
39 * output busy loop as low as possible. We avoid reading the CTC registers
40 * directly because of the awkward 8-bit access mechanism of the 82C54
41 * device.
44 #define CALIBRATE_INTERVAL ((2*CLOCK_TICK_RATE)/1000) /* 2ms */
45 #define CALIBRATE_DIVISOR (2*1000) /* 2ms / 2000 == 1usec */
47 unsigned long calibrate_tsc_with_pit(void)
49 /* Set the Gate high, disable speaker */
50 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
53 * Now let's take care of CTC channel 2
55 * Set the Gate high, program CTC channel 2 for mode 0,
56 * (interrupt on terminal count mode), binary count,
57 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
59 outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
61 outb(CALIBRATE_INTERVAL & 0xff, 0x42); /* LSB of count */
62 outb(CALIBRATE_INTERVAL >> 8, 0x42); /* MSB of count */
65 tsc_t start;
66 tsc_t end;
67 unsigned long count;
69 start = rdtsc();
70 count = 0;
71 do {
72 count++;
73 } while ((inb(0x61) & 0x20) == 0);
74 end = rdtsc();
76 /* Error: ECTCNEVERSET */
77 if (count <= 1)
78 goto bad_ctc;
80 /* 64-bit subtract - gcc just messes up with long longs */
81 __asm__("subl %2,%0\n\t"
82 "sbbl %3,%1"
83 : "=a" (end.lo), "=d" (end.hi)
84 : "g" (start.lo), "g" (start.hi),
85 "0" (end.lo), "1" (end.hi));
87 /* Error: ECPUTOOFAST */
88 if (end.hi)
89 goto bad_ctc;
92 /* Error: ECPUTOOSLOW */
93 if (end.lo <= CALIBRATE_DIVISOR)
94 goto bad_ctc;
96 return DIV_ROUND_UP(end.lo, CALIBRATE_DIVISOR);
100 * The CTC wasn't reliable: we got a hit on the very first read,
101 * or the CPU was so fast/slow that the quotient wouldn't fit in
102 * 32 bits..
104 bad_ctc:
105 return 0;
108 #if CONFIG(UNKNOWN_TSC_RATE)
109 static u32 timer_tsc;
111 unsigned long tsc_freq_mhz(void)
113 if (timer_tsc > 0)
114 return timer_tsc;
116 timer_tsc = calibrate_tsc_with_pit();
118 /* Set some semi-ridiculous rate if approximation fails. */
119 if (timer_tsc == 0)
120 timer_tsc = 5000;
122 return timer_tsc;
124 #endif