summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/x86/tsc/delay_tsc.c78
-rw-r--r--src/drivers/pc80/pc/Makefile.inc8
-rw-r--r--src/drivers/pc80/pc/i8254.c76
-rw-r--r--src/include/pc80/i8254.h1
4 files changed, 85 insertions, 78 deletions
diff --git a/src/cpu/x86/tsc/delay_tsc.c b/src/cpu/x86/tsc/delay_tsc.c
index 0784822b30..afcd1d1f7d 100644
--- a/src/cpu/x86/tsc/delay_tsc.c
+++ b/src/cpu/x86/tsc/delay_tsc.c
@@ -12,90 +12,14 @@
*/
#include <arch/early_variables.h>
-#include <console/console.h>
-#include <arch/io.h>
#include <cpu/x86/tsc.h>
+#include <pc80/i8254.h>
#include <smp/spinlock.h>
#include <delay.h>
#include <thread.h>
static unsigned long clocks_per_usec CAR_GLOBAL;
-#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
-
-/* ------ Calibrate the TSC -------
- * Too much 64-bit arithmetic here to do this cleanly in C, and for
- * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
- * output busy loop as low as possible. We avoid reading the CTC registers
- * directly because of the awkward 8-bit access mechanism of the 82C54
- * device.
- */
-
-#define CALIBRATE_INTERVAL ((2*CLOCK_TICK_RATE)/1000) /* 2ms */
-#define CALIBRATE_DIVISOR (2*1000) /* 2ms / 2000 == 1usec */
-
-static unsigned long calibrate_tsc_with_pit(void)
-{
- /* Set the Gate high, disable speaker */
- outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
- /*
- * Now let's take care of CTC channel 2
- *
- * Set the Gate high, program CTC channel 2 for mode 0,
- * (interrupt on terminal count mode), binary count,
- * load 5 * LATCH count, (LSB and MSB) to begin countdown.
- */
- outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
-
- outb(CALIBRATE_INTERVAL & 0xff, 0x42); /* LSB of count */
- outb(CALIBRATE_INTERVAL >> 8, 0x42); /* MSB of count */
-
- {
- tsc_t start;
- tsc_t end;
- unsigned long count;
-
- start = rdtsc();
- count = 0;
- do {
- count++;
- } while ((inb(0x61) & 0x20) == 0);
- end = rdtsc();
-
- /* Error: ECTCNEVERSET */
- if (count <= 1)
- goto bad_ctc;
-
- /* 64-bit subtract - gcc just messes up with long longs */
- __asm__("subl %2,%0\n\t"
- "sbbl %3,%1"
- : "=a" (end.lo), "=d" (end.hi)
- : "g" (start.lo), "g" (start.hi),
- "0" (end.lo), "1" (end.hi));
-
- /* Error: ECPUTOOFAST */
- if (end.hi)
- goto bad_ctc;
-
-
- /* Error: ECPUTOOSLOW */
- if (end.lo <= CALIBRATE_DIVISOR)
- goto bad_ctc;
-
- return DIV_ROUND_UP(end.lo, CALIBRATE_DIVISOR);
- }
-
- /*
- * The CTC wasn't reliable: we got a hit on the very first read,
- * or the CPU was so fast/slow that the quotient wouldn't fit in
- * 32 bits..
- */
-bad_ctc:
- printk(BIOS_ERR, "bad_ctc\n");
- return 0;
-}
-
static unsigned long calibrate_tsc(void)
{
if (CONFIG(TSC_CONSTANT_RATE))
diff --git a/src/drivers/pc80/pc/Makefile.inc b/src/drivers/pc80/pc/Makefile.inc
index 8c348e323e..bd56cd43a1 100644
--- a/src/drivers/pc80/pc/Makefile.inc
+++ b/src/drivers/pc80/pc/Makefile.inc
@@ -1,7 +1,6 @@
ifeq ($(CONFIG_ARCH_X86),y)
ramstage-y += isa-dma.c
-ramstage-y += i8254.c
ramstage-y += i8259.c
ramstage-$(CONFIG_UDELAY_IO) += udelay_io.c
romstage-$(CONFIG_UDELAY_IO) += udelay_io.c
@@ -9,4 +8,11 @@ ramstage-y += keyboard.c
ramstage-$(CONFIG_SPKMODEM) += spkmodem.c
romstage-$(CONFIG_SPKMODEM) += spkmodem.c
+bootblock-y += i8254.c
+verstage-y += i8254.c
+romstage-y += i8254.c
+ramstage-y += i8254.c
+postcar-y += i8254.c
+smm-y += i8254.c
+
endif
diff --git a/src/drivers/pc80/pc/i8254.c b/src/drivers/pc80/pc/i8254.c
index 53d880cc79..8e15d4ded1 100644
--- a/src/drivers/pc80/pc/i8254.c
+++ b/src/drivers/pc80/pc/i8254.c
@@ -12,6 +12,8 @@
*/
#include <arch/io.h>
+#include <commonlib/helpers.h>
+#include <cpu/x86/tsc.h>
#include <pc80/i8254.h>
/* Initialize i8254 timers */
@@ -46,3 +48,77 @@ void udelay(int usecs)
;
}
#endif
+
+#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
+
+/* ------ Calibrate the TSC -------
+ * Too much 64-bit arithmetic here to do this cleanly in C, and for
+ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
+ * output busy loop as low as possible. We avoid reading the CTC registers
+ * directly because of the awkward 8-bit access mechanism of the 82C54
+ * device.
+ */
+
+#define CALIBRATE_INTERVAL ((2*CLOCK_TICK_RATE)/1000) /* 2ms */
+#define CALIBRATE_DIVISOR (2*1000) /* 2ms / 2000 == 1usec */
+
+unsigned long calibrate_tsc_with_pit(void)
+{
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ /*
+ * Now let's take care of CTC channel 2
+ *
+ * Set the Gate high, program CTC channel 2 for mode 0,
+ * (interrupt on terminal count mode), binary count,
+ * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+ */
+ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
+
+ outb(CALIBRATE_INTERVAL & 0xff, 0x42); /* LSB of count */
+ outb(CALIBRATE_INTERVAL >> 8, 0x42); /* MSB of count */
+
+ {
+ tsc_t start;
+ tsc_t end;
+ unsigned long count;
+
+ start = rdtsc();
+ count = 0;
+ do {
+ count++;
+ } while ((inb(0x61) & 0x20) == 0);
+ end = rdtsc();
+
+ /* Error: ECTCNEVERSET */
+ if (count <= 1)
+ goto bad_ctc;
+
+ /* 64-bit subtract - gcc just messes up with long longs */
+ __asm__("subl %2,%0\n\t"
+ "sbbl %3,%1"
+ : "=a" (end.lo), "=d" (end.hi)
+ : "g" (start.lo), "g" (start.hi),
+ "0" (end.lo), "1" (end.hi));
+
+ /* Error: ECPUTOOFAST */
+ if (end.hi)
+ goto bad_ctc;
+
+
+ /* Error: ECPUTOOSLOW */
+ if (end.lo <= CALIBRATE_DIVISOR)
+ goto bad_ctc;
+
+ return DIV_ROUND_UP(end.lo, CALIBRATE_DIVISOR);
+ }
+
+ /*
+ * The CTC wasn't reliable: we got a hit on the very first read,
+ * or the CPU was so fast/slow that the quotient wouldn't fit in
+ * 32 bits..
+ */
+bad_ctc:
+ return 0;
+}
diff --git a/src/include/pc80/i8254.h b/src/include/pc80/i8254.h
index 794945c244..21e47c2ece 100644
--- a/src/include/pc80/i8254.h
+++ b/src/include/pc80/i8254.h
@@ -55,5 +55,6 @@
#define PPCB_T2GATE 0x01 /* Bit 0 */
void setup_i8254(void);
+unsigned long calibrate_tsc_with_pit(void);
#endif /* PC80_I8254_H */