Adapt HPET driver to work with QEMU

Qemu implements HPET so that it is connected to IRQ 2, which makes
necessary to use it in legacy emulation mode.

Add legacy emulation mode to HPET driver.

Change the way the HPET driver is initialized. QEMU requires that
the mode (one shot or periodic) gets set prior loading comparator
value.

Add debugging mode to HPET driver to ease the next port.

Change-Id: I668325d5968451585519a08b6c41863cf6e37f88
Signed-off-by: Dmitriy Korovkin <dmitriy.korovkin@windriver.com>
This commit is contained in:
Dmitriy Korovkin 2015-07-24 13:50:31 -04:00 committed by Anas Nashif
commit 8b0271dd2c
3 changed files with 60 additions and 11 deletions

View file

@ -41,6 +41,22 @@ config HPET_TIMER
This option selects High Precision Event Timer (HPET) as a
system timer.
config HPET_TIMER_LEGACY_EMULATION
bool "HPET timer legacy emulation mode"
default n
depends on HPET_TIMER
help
This option switches HPET to legacy emulation mode.
In this mode 8254 PIT is disabled, HPET timer0 is connected
to IOAPIC IRQ2, timer1 -- to IOAPIC IRQ8.
config HPET_TIMER_DEBUG
bool "Enable HPET debug output"
default n
depends on HPET_TIMER && PRINTK
help
This option enables HPET debugging output.
config LOAPIC_TIMER
bool "LOAPIC timer"
depends on LOAPIC && X86_32

View file

@ -204,6 +204,13 @@ static uint32_t main_count_expected_value = 0;
extern uint32_t _hw_irq_to_c_handler_latency;
#endif
#ifdef CONFIG_HPET_TIMER_DEBUG
#include <misc/printk.h>
#define PRINTK(...) printk(__VA_ARGS__)
#else
#define PRINTK(...)
#endif
#ifdef TIMER_SUPPORTS_TICKLESS
/* additional globals, locals, and forward declarations */
@ -546,33 +553,59 @@ int _sys_clock_driver_init(struct device *device)
counter_load_value = (uint32_t)(tickFempto / hpetClockPeriod);
PRINTK("\n\nHPET: configuration: 0x%x, clock period: 0x%x (%d pico-s)\n",
(uint32_t)(*_HPET_GENERAL_CAPS),
(uint32_t)hpetClockPeriod, (uint32_t)hpetClockPeriod / 1000);
PRINTK("HPET: timer0: available interrupts mask 0x%x\n",
(uint32_t)(*_HPET_TIMER0_CONFIG_CAPS >> 32));
/* Initialize "sys_clock_hw_cycles_per_tick" */
sys_clock_hw_cycles_per_tick = counter_load_value;
/*
* Set the comparator register for timer0. The write to the comparator
* register is allowed due to setting the HPET_Tn_VAL_SET_CNF bit.
*/
*_HPET_TIMER0_CONFIG_CAPS |= HPET_Tn_VAL_SET_CNF;
*_HPET_TIMER0_COMPARATOR = counter_load_value;
#ifdef CONFIG_INT_LATENCY_BENCHMARK
main_count_first_irq_value = counter_load_value;
main_count_expected_value = main_count_first_irq_value;
#endif
#ifndef TIMER_SUPPORTS_TICKLESS
/* set timer0 to periodic mode, ready to expire every tick */
#ifdef CONFIG_HPET_TIMER_LEGACY_EMULATION
/*
* Configure HPET replace legacy 8254 timer.
* In this case the timer0 interrupt is routed to IRQ2
* and legacy timer generates no interrupts
*/
*_HPET_GENERAL_CONFIG |= HPET_LEGACY_RT_CNF;
#endif /* CONFIG_HPET_TIMER_LEGACY_EMULATION */
*_HPET_TIMER0_CONFIG_CAPS |= HPET_Tn_TYPE_CNF;
#ifndef TIMER_SUPPORTS_TICKLESS
/*
* Set timer0 to periodic mode, ready to expire every tick
* Setting 32-bit mode during the first load of the comparator
* value is required to work around some hardware that otherwise
* does not work properly.
*/
*_HPET_TIMER0_CONFIG_CAPS |= HPET_Tn_TYPE_CNF | HPET_Tn_32MODE_CNF;
#else
/* set timer0 to one-shot mode, ready to expire on the first tick */
*_HPET_TIMER0_CONFIG_CAPS &= ~HPET_Tn_TYPE_CNF;
#endif /* !TIMER_SUPPORTS_TICKLESS */
/*
* Set the comparator register for timer0. The write to the comparator
* register is allowed due to setting the HPET_Tn_VAL_SET_CNF bit.
*/
*_HPET_TIMER0_CONFIG_CAPS |= HPET_Tn_VAL_SET_CNF;
*_HPET_TIMER0_COMPARATOR = counter_load_value;
/*
* After the comparator is loaded, 32-bit mode can be safely
* switched off
*/
*_HPET_TIMER0_CONFIG_CAPS &= ~HPET_Tn_32MODE_CNF;
/*
* Route interrupts to the I/O APIC. If HPET_Tn_INT_TYPE_CNF is set this
* means edge triggered interrupt mode is utilized; Otherwise level

View file

@ -25,7 +25,7 @@ QEMU_BIOS ?= /usr/share/qemu
QEMU_CPU_TYPE_x86 = qemu32
QEMU_FLAGS_x86 = -m 32 -cpu $(QEMU_CPU_TYPE_x86) \
-no-reboot -nographic -display none -net none \
-clock dynticks -no-acpi -balloon none -no-hpet \
-clock dynticks -no-acpi -balloon none \
-L $(QEMU_BIOS) -bios bios.bin \
-machine type=pc-0.14
QEMU_x86 = qemu-system-i386