Kyösti Mälkki has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/36507 )
Change subject: cpu/x86: Move calibrate_tsc_with_pit() to drivers/pc80 ......................................................................
cpu/x86: Move calibrate_tsc_with_pit() to drivers/pc80
Change-Id: Ia8d8dc23ee0b51d62c83f5ba640b3a9aea4e744b Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- M src/cpu/x86/tsc/delay_tsc.c M src/drivers/pc80/pc/Makefile.inc M src/drivers/pc80/pc/i8254.c M src/include/pc80/i8254.h 4 files changed, 84 insertions(+), 80 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/07/36507/1
diff --git a/src/cpu/x86/tsc/delay_tsc.c b/src/cpu/x86/tsc/delay_tsc.c index 0784822..29cd37e 100644 --- a/src/cpu/x86/tsc/delay_tsc.c +++ b/src/cpu/x86/tsc/delay_tsc.c @@ -12,90 +12,12 @@ */
#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 8c348e3..1b26984 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,10 @@ 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 +smm-y += i8254.c + endif diff --git a/src/drivers/pc80/pc/i8254.c b/src/drivers/pc80/pc/i8254.c index 53d880c..8e15d4d 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 @@ ; } #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 794945c..21e47c2 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 */