timer: hpet: enable 64 bit mode for better usages
Get longer maximum timeout Make HPET counter usable as timestamp Signed-off-by: Dong Wang <dong.d.wang@intel.com>
This commit is contained in:
parent
f6f521b927
commit
eeb15aa393
1 changed files with 50 additions and 37 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 Intel Corporation
|
* Copyright (c) 2018-2021 Intel Corporation
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -95,13 +95,15 @@ DEVICE_MMIO_TOPLEVEL_STATIC(hpet_regs, DT_DRV_INST(0));
|
||||||
#define INTR_STATUS_REG HPET_REG_ADDR(0x20)
|
#define INTR_STATUS_REG HPET_REG_ADDR(0x20)
|
||||||
|
|
||||||
/* Main Counter Register */
|
/* Main Counter Register */
|
||||||
#define MAIN_COUNTER_REG HPET_REG_ADDR(0xf0)
|
#define MAIN_COUNTER_LOW_REG HPET_REG_ADDR(0xf0)
|
||||||
|
#define MAIN_COUNTER_HIGH_REG HPET_REG_ADDR(0xf4)
|
||||||
|
|
||||||
/* Timer 0 Configuration and Capabilities register */
|
/* Timer 0 Configuration and Capabilities register */
|
||||||
#define TIMER0_CONF_REG HPET_REG_ADDR(0x100)
|
#define TIMER0_CONF_REG HPET_REG_ADDR(0x100)
|
||||||
|
|
||||||
/* Timer 0 Comparator Register */
|
/* Timer 0 Comparator Register */
|
||||||
#define TIMER0_COMPARATOR_REG HPET_REG_ADDR(0x108)
|
#define TIMER0_COMPARATOR_LOW_REG HPET_REG_ADDR(0x108)
|
||||||
|
#define TIMER0_COMPARATOR_HIGH_REG HPET_REG_ADDR(0x10c)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Setup memory mappings needed to access HPET registers.
|
* @brief Setup memory mappings needed to access HPET registers.
|
||||||
|
@ -119,9 +121,17 @@ static inline void hpet_mmio_init(void)
|
||||||
*
|
*
|
||||||
* @return Value of Main Counter
|
* @return Value of Main Counter
|
||||||
*/
|
*/
|
||||||
static inline uint32_t hpet_counter_get(void)
|
static inline uint64_t hpet_counter_get(void)
|
||||||
{
|
{
|
||||||
return sys_read32(MAIN_COUNTER_REG);
|
uint32_t high;
|
||||||
|
uint32_t low;
|
||||||
|
|
||||||
|
do {
|
||||||
|
high = sys_read32(MAIN_COUNTER_HIGH_REG);
|
||||||
|
low = sys_read32(MAIN_COUNTER_LOW_REG);
|
||||||
|
} while (high != sys_read32(MAIN_COUNTER_HIGH_REG));
|
||||||
|
|
||||||
|
return ((uint64_t)high << 32) | low;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -208,9 +218,14 @@ static inline void hpet_timer_conf_set(uint32_t val)
|
||||||
*
|
*
|
||||||
* @param val Value to be written to the register
|
* @param val Value to be written to the register
|
||||||
*/
|
*/
|
||||||
static inline void hpet_timer_comparator_set(uint32_t val)
|
static inline void hpet_timer_comparator_set(uint64_t val)
|
||||||
{
|
{
|
||||||
sys_write32(val, TIMER0_COMPARATOR_REG);
|
#if CONFIG_X86_64
|
||||||
|
sys_write64(val, TIMER0_COMPARATOR_LOW_REG);
|
||||||
|
#else
|
||||||
|
sys_write32((uint32_t)val, TIMER0_COMPARATOR_LOW_REG);
|
||||||
|
sys_write32((uint32_t)(val >> 32), TIMER0_COMPARATOR_HIGH_REG);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* HPET_USE_CUSTOM_REG_ACCESS_FUNCS */
|
#endif /* HPET_USE_CUSTOM_REG_ACCESS_FUNCS */
|
||||||
|
|
||||||
|
@ -224,22 +239,18 @@ static inline void hpet_timer_comparator_set(uint32_t val)
|
||||||
#define HPET_CMP_MIN_DELAY (1000)
|
#define HPET_CMP_MIN_DELAY (1000)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_TICKS 0x7FFFFFFFUL
|
|
||||||
|
|
||||||
static __pinned_bss struct k_spinlock lock;
|
static __pinned_bss struct k_spinlock lock;
|
||||||
static __pinned_bss unsigned int last_count;
|
static __pinned_bss uint64_t last_count;
|
||||||
|
|
||||||
#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME
|
#ifdef CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME
|
||||||
static __pinned_bss unsigned int cyc_per_tick;
|
static __pinned_bss unsigned int cyc_per_tick;
|
||||||
static __pinned_bss unsigned int max_ticks;
|
|
||||||
#else
|
#else
|
||||||
#define cyc_per_tick \
|
#define cyc_per_tick \
|
||||||
(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
|
(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
|
||||||
|
|
||||||
#define max_ticks \
|
|
||||||
((MAX_TICKS - cyc_per_tick) / cyc_per_tick)
|
|
||||||
#endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */
|
#endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */
|
||||||
|
|
||||||
|
#define HPET_MAX_TICKS ((int32_t)0x7fffffff)
|
||||||
|
|
||||||
__isr
|
__isr
|
||||||
static void hpet_isr(const void *arg)
|
static void hpet_isr(const void *arg)
|
||||||
{
|
{
|
||||||
|
@ -247,7 +258,7 @@ static void hpet_isr(const void *arg)
|
||||||
|
|
||||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||||
|
|
||||||
uint32_t now = hpet_counter_get();
|
uint64_t now = hpet_counter_get();
|
||||||
|
|
||||||
#if ((DT_INST_IRQ(0, sense) & IRQ_TYPE_LEVEL) == IRQ_TYPE_LEVEL)
|
#if ((DT_INST_IRQ(0, sense) & IRQ_TYPE_LEVEL) == IRQ_TYPE_LEVEL)
|
||||||
/*
|
/*
|
||||||
|
@ -265,27 +276,27 @@ static void hpet_isr(const void *arg)
|
||||||
* on the other CPU, despite the HPET being
|
* on the other CPU, despite the HPET being
|
||||||
* theoretically a global device.
|
* theoretically a global device.
|
||||||
*/
|
*/
|
||||||
int32_t diff = (int32_t)(now - last_count);
|
int64_t diff = (int64_t)(now - last_count);
|
||||||
|
|
||||||
if (last_count && diff < 0) {
|
if (last_count && diff < 0) {
|
||||||
now = last_count;
|
now = last_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint32_t dticks = (now - last_count) / cyc_per_tick;
|
uint32_t dticks = (uint32_t)((now - last_count) / cyc_per_tick);
|
||||||
|
|
||||||
last_count += dticks * cyc_per_tick;
|
last_count += (uint64_t)dticks * cyc_per_tick;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
uint32_t next = last_count + cyc_per_tick;
|
uint64_t next = last_count + cyc_per_tick;
|
||||||
|
|
||||||
if ((int32_t)(next - now) < HPET_CMP_MIN_DELAY) {
|
if ((int64_t)(next - now) < HPET_CMP_MIN_DELAY) {
|
||||||
next += cyc_per_tick;
|
next = now + HPET_CMP_MIN_DELAY;
|
||||||
}
|
}
|
||||||
hpet_timer_comparator_set(next);
|
hpet_timer_comparator_set(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
k_spin_unlock(&lock, key);
|
k_spin_unlock(&lock, key);
|
||||||
sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? dticks : 1);
|
sys_clock_announce(dticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
__pinned_func
|
__pinned_func
|
||||||
|
@ -326,12 +337,8 @@ int sys_clock_driver_init(const struct device *dev)
|
||||||
hz = (uint32_t)(HPET_COUNTER_CLK_PERIOD / hpet_counter_clk_period_get());
|
hz = (uint32_t)(HPET_COUNTER_CLK_PERIOD / hpet_counter_clk_period_get());
|
||||||
z_clock_hw_cycles_per_sec = hz;
|
z_clock_hw_cycles_per_sec = hz;
|
||||||
cyc_per_tick = hz / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
|
cyc_per_tick = hz / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
|
||||||
|
|
||||||
max_ticks = (MAX_TICKS - cyc_per_tick) / cyc_per_tick;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
last_count = hpet_counter_get();
|
|
||||||
|
|
||||||
/* Note: we set the legacy routing bit, because otherwise
|
/* Note: we set the legacy routing bit, because otherwise
|
||||||
* nothing in Zephyr disables the PIT which then fires
|
* nothing in Zephyr disables the PIT which then fires
|
||||||
* interrupts into the same IRQ. But that means we're then
|
* interrupts into the same IRQ. But that means we're then
|
||||||
|
@ -345,11 +352,16 @@ int sys_clock_driver_init(const struct device *dev)
|
||||||
reg = hpet_timer_conf_get();
|
reg = hpet_timer_conf_get();
|
||||||
reg &= ~TIMER_CONF_PERIODIC;
|
reg &= ~TIMER_CONF_PERIODIC;
|
||||||
reg &= ~TIMER_CONF_FSB_EN;
|
reg &= ~TIMER_CONF_FSB_EN;
|
||||||
reg |= TIMER_CONF_MODE32;
|
reg &= ~TIMER_CONF_MODE32;
|
||||||
reg |= TIMER_CONF_INT_ENABLE;
|
reg |= TIMER_CONF_INT_ENABLE;
|
||||||
hpet_timer_conf_set(reg);
|
hpet_timer_conf_set(reg);
|
||||||
|
|
||||||
|
last_count = hpet_counter_get();
|
||||||
|
if (cyc_per_tick >= HPET_CMP_MIN_DELAY) {
|
||||||
hpet_timer_comparator_set(last_count + cyc_per_tick);
|
hpet_timer_comparator_set(last_count + cyc_per_tick);
|
||||||
|
} else {
|
||||||
|
hpet_timer_comparator_set(last_count + HPET_CMP_MIN_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -378,15 +390,15 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks = ticks == K_TICKS_FOREVER ? max_ticks : ticks;
|
ticks = ticks == K_TICKS_FOREVER ? HPET_MAX_TICKS : ticks;
|
||||||
ticks = CLAMP(ticks - 1, 0, (int32_t)max_ticks);
|
ticks = CLAMP(ticks - 1, 0, HPET_MAX_TICKS);
|
||||||
|
|
||||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||||
uint32_t now = hpet_counter_get(), cyc, adj;
|
uint64_t now = hpet_counter_get(), cyc, adj;
|
||||||
uint32_t max_cyc = max_ticks * cyc_per_tick;
|
uint64_t max_cyc = (uint64_t)HPET_MAX_TICKS * cyc_per_tick;
|
||||||
|
|
||||||
/* Round up to next tick boundary. */
|
/* Round up to next tick boundary. */
|
||||||
cyc = ticks * cyc_per_tick;
|
cyc = (uint64_t)ticks * cyc_per_tick;
|
||||||
adj = (now - last_count) + (cyc_per_tick - 1);
|
adj = (now - last_count) + (cyc_per_tick - 1);
|
||||||
if (cyc <= max_cyc - adj) {
|
if (cyc <= max_cyc - adj) {
|
||||||
cyc += adj;
|
cyc += adj;
|
||||||
|
@ -396,8 +408,8 @@ void sys_clock_set_timeout(int32_t ticks, bool idle)
|
||||||
cyc = (cyc / cyc_per_tick) * cyc_per_tick;
|
cyc = (cyc / cyc_per_tick) * cyc_per_tick;
|
||||||
cyc += last_count;
|
cyc += last_count;
|
||||||
|
|
||||||
if ((cyc - now) < HPET_CMP_MIN_DELAY) {
|
if ((int64_t)(cyc - now) < HPET_CMP_MIN_DELAY) {
|
||||||
cyc += cyc_per_tick;
|
cyc = now + HPET_CMP_MIN_DELAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
hpet_timer_comparator_set(cyc);
|
hpet_timer_comparator_set(cyc);
|
||||||
|
@ -413,7 +425,8 @@ uint32_t sys_clock_elapsed(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||||
uint32_t ret = (hpet_counter_get() - last_count) / cyc_per_tick;
|
uint64_t now = hpet_counter_get();
|
||||||
|
uint32_t ret = (uint32_t)((now - last_count) / cyc_per_tick);
|
||||||
|
|
||||||
k_spin_unlock(&lock, key);
|
k_spin_unlock(&lock, key);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -422,7 +435,7 @@ uint32_t sys_clock_elapsed(void)
|
||||||
__pinned_func
|
__pinned_func
|
||||||
uint32_t sys_clock_cycle_get_32(void)
|
uint32_t sys_clock_cycle_get_32(void)
|
||||||
{
|
{
|
||||||
return hpet_counter_get();
|
return (uint32_t)hpet_counter_get();
|
||||||
}
|
}
|
||||||
|
|
||||||
__pinned_func
|
__pinned_func
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue