cpu/x86: Move calibrate_tsc_with_pit() to drivers/pc80
Change-Id: Ia8d8dc23ee0b51d62c83f5ba640b3a9aea4e744b Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/36507 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Marshall Dawson <marshalldawson3rd@gmail.com>
This commit is contained in:
parent
e1c0cb737c
commit
432516586e
|
@ -12,90 +12,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <arch/early_variables.h>
|
#include <arch/early_variables.h>
|
||||||
#include <console/console.h>
|
|
||||||
#include <arch/io.h>
|
|
||||||
#include <cpu/x86/tsc.h>
|
#include <cpu/x86/tsc.h>
|
||||||
|
#include <pc80/i8254.h>
|
||||||
#include <smp/spinlock.h>
|
#include <smp/spinlock.h>
|
||||||
#include <delay.h>
|
#include <delay.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
|
||||||
static unsigned long clocks_per_usec CAR_GLOBAL;
|
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)
|
static unsigned long calibrate_tsc(void)
|
||||||
{
|
{
|
||||||
if (CONFIG(TSC_CONSTANT_RATE))
|
if (CONFIG(TSC_CONSTANT_RATE))
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
ifeq ($(CONFIG_ARCH_X86),y)
|
ifeq ($(CONFIG_ARCH_X86),y)
|
||||||
|
|
||||||
ramstage-y += isa-dma.c
|
ramstage-y += isa-dma.c
|
||||||
ramstage-y += i8254.c
|
|
||||||
ramstage-y += i8259.c
|
ramstage-y += i8259.c
|
||||||
ramstage-$(CONFIG_UDELAY_IO) += udelay_io.c
|
ramstage-$(CONFIG_UDELAY_IO) += udelay_io.c
|
||||||
romstage-$(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
|
ramstage-$(CONFIG_SPKMODEM) += spkmodem.c
|
||||||
romstage-$(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
|
endif
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
|
#include <commonlib/helpers.h>
|
||||||
|
#include <cpu/x86/tsc.h>
|
||||||
#include <pc80/i8254.h>
|
#include <pc80/i8254.h>
|
||||||
|
|
||||||
/* Initialize i8254 timers */
|
/* Initialize i8254 timers */
|
||||||
|
@ -46,3 +48,77 @@ void udelay(int usecs)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -55,5 +55,6 @@
|
||||||
#define PPCB_T2GATE 0x01 /* Bit 0 */
|
#define PPCB_T2GATE 0x01 /* Bit 0 */
|
||||||
|
|
||||||
void setup_i8254(void);
|
void setup_i8254(void);
|
||||||
|
unsigned long calibrate_tsc_with_pit(void);
|
||||||
|
|
||||||
#endif /* PC80_I8254_H */
|
#endif /* PC80_I8254_H */
|
||||||
|
|
Loading…
Reference in New Issue