aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Kconfig6
-rw-r--r--src/clock.c31
-rw-r--r--src/pciinit.c5
-rw-r--r--src/util.h1
4 files changed, 43 insertions, 0 deletions
diff --git a/src/Kconfig b/src/Kconfig
index 6de3e715..b5dd63bd 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -222,6 +222,12 @@ menu "Hardware support"
default y
help
Initialize the Memory Type Range Registers (on emulators).
+ config PMTIMER
+ depends on !COREBOOT
+ bool "Use ACPI timer"
+ default y
+ help
+ Use the ACPI timer instead of the TSC for timekeeping (on qemu).
endmenu
menu "BIOS interfaces"
diff --git a/src/clock.c b/src/clock.c
index 69e9f178..71b913e5 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -129,11 +129,42 @@ emulate_tsc(void)
return ret;
}
+u16 pmtimer_ioport VAR16VISIBLE;
+u32 pmtimer_wraps VARLOW;
+u32 pmtimer_last VARLOW;
+
+void pmtimer_init(u16 ioport, u32 khz)
+{
+ if (!CONFIG_PMTIMER)
+ return;
+ dprintf(1, "Using pmtimer, ioport 0x%x, freq %d kHz\n", ioport, khz);
+ SET_GLOBAL(pmtimer_ioport, ioport);
+ SET_GLOBAL(cpu_khz, khz);
+}
+
+static u64 pmtimer_get(void)
+{
+ u16 ioport = GET_GLOBAL(pmtimer_ioport);
+ u32 wraps = GET_LOW(pmtimer_wraps);
+ u32 pmtimer = inl(ioport) & 0xffffff;
+
+ if (pmtimer < GET_LOW(pmtimer_last)) {
+ wraps++;
+ SET_LOW(pmtimer_wraps, wraps);
+ }
+ SET_LOW(pmtimer_last, pmtimer);
+
+ dprintf(9, "pmtimer: %u:%u\n", wraps, pmtimer);
+ return (u64)wraps << 24 | pmtimer;
+}
+
static u64
get_tsc(void)
{
if (unlikely(GET_GLOBAL(no_tsc)))
return emulate_tsc();
+ if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport))
+ return pmtimer_get();
return rdtscll();
}
diff --git a/src/pciinit.c b/src/pciinit.c
index 68f302a2..31115ee5 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -180,6 +180,9 @@ static const struct pci_device_id pci_class_tbl[] = {
PCI_DEVICE_END,
};
+/* PM Timer ticks per second (HZ) */
+#define PM_TIMER_FREQUENCY 3579545
+
/* PIIX4 Power Management device (for ACPI) */
static void piix4_pm_init(struct pci_device *pci, void *arg)
{
@@ -191,6 +194,8 @@ static void piix4_pm_init(struct pci_device *pci, void *arg)
pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */
pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1);
pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */
+
+ pmtimer_init(PORT_ACPI_PM_BASE + 0x08, PM_TIMER_FREQUENCY / 1000);
}
static const struct pci_device_id pci_device_tbl[] = {
diff --git a/src/util.h b/src/util.h
index 062eea3f..7723bb17 100644
--- a/src/util.h
+++ b/src/util.h
@@ -282,6 +282,7 @@ void lpt_setup(void);
// clock.c
#define PIT_TICK_RATE 1193180 // Underlying HZ of PIT
#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+void pmtimer_init(u16 ioport, u32 khz);
int check_tsc(u64 end);
void timer_setup(void);
void ndelay(u32 count);