diff options
Diffstat (limited to 'chip/ish/hwtimer.c')
-rw-r--r-- | chip/ish/hwtimer.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/chip/ish/hwtimer.c b/chip/ish/hwtimer.c new file mode 100644 index 0000000000..13c07decd2 --- /dev/null +++ b/chip/ish/hwtimer.c @@ -0,0 +1,129 @@ +/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Hardware timers driver - HPET */ + +#include "hpet.h" +#include "hwtimer.h" +#include "registers.h" +#include "task.h" + +#define CPUTS(outstr) cputs(CC_CLOCK, outstr) +#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ## args) + +void __hw_clock_event_set(uint32_t deadline) +{ + HPET_TIMER_COMP(1) = HPET_MAIN_COUNTER + deadline; + HPET_TIMER_CONF_CAP(1) |= HPET_Tn_INT_ENB_CNF; +} + +uint32_t __hw_clock_event_get(void) +{ + return 0; +} + +void __hw_clock_event_clear(void) +{ + HPET_TIMER_CONF_CAP(1) &= ~HPET_Tn_INT_ENB_CNF; +} + +uint32_t __hw_clock_source_read(void) +{ + return HPET_MAIN_COUNTER; +} + +void __hw_clock_source_set(uint32_t ts) +{ + HPET_GENERAL_CONFIG &= ~HPET_ENABLE_CNF; + HPET_MAIN_COUNTER = 0x00; + + while (HPET_CTRL_STATUS & HPET_GEN_CONF_STATUS_BIT) + ; + + HPET_GENERAL_CONFIG |= HPET_ENABLE_CNF; +} + +static void __hw_clock_source_irq(int timer_id) +{ + /* Clear interrupt */ + HPET_INTR_CLEAR = (1 << timer_id); + + /* If IRQ is from timer 0, 32-bit timer overflowed */ + process_timers(timer_id == 0); +} + +void __hw_clock_source_irq_0(void) +{ + __hw_clock_source_irq(0); +} +DECLARE_IRQ(ISH_HPET_TIMER0_IRQ, __hw_clock_source_irq_0); + +void __hw_clock_source_irq_1(void) +{ + __hw_clock_source_irq(1); +} +DECLARE_IRQ(ISH_HPET_TIMER1_IRQ, __hw_clock_source_irq_1); + +int __hw_clock_source_init(uint32_t start_t) +{ + + /* + * The timer can only fire interrupt when its value reaches zero. + * Therefore we need two timers: + * - Timer 0 as free running timer + * - Timer 1 as event timer + */ + + /* Disable HPET */ + HPET_GENERAL_CONFIG &= ~HPET_ENABLE_CNF; + HPET_MAIN_COUNTER = 0x00; + + /* Set comparator value */ + HPET_TIMER_COMP(0) = ISH_HPET_CLK_FREQ / ISH_TICKS_PER_SEC; + + /* Wait for timer to settle */ + while (HPET_CTRL_STATUS & HPET_GEN_CONF_STATUS_BIT) + ; + + /* Timer 0 - enable periodic mode */ + HPET_TIMER_CONF_CAP(0) |= HPET_Tn_TYPE_CNF; + HPET_TIMER_CONF_CAP(0) |= HPET_Tn_32MODE_CNF; + + while (HPET_CTRL_STATUS & HPET_T0_CONF_CAP_BIT) + ; + + /* Set IRQ routing */ +#if ISH_HPET_TIMER0_IRQ < 32 + HPET_TIMER_CONF_CAP(0) &= ~HPET_Tn_INT_ROUTE_CNF_MASK; + HPET_TIMER_CONF_CAP(0) |= (ISH_HPET_TIMER0_IRQ << + HPET_Tn_INT_ROUTE_CNF_SHIFT); +#else + HPET_TIMER_CONF_CAP(0) &= ~HPET_Tn_INT_ROUTE_CNF_MASK; +#endif + + while (HPET_CTRL_STATUS & HPET_T0_CONF_CAP_BIT) + ; + + /* Level interrupt */ + HPET_TIMER_CONF_CAP(0) |= HPET_Tn_INT_TYPE_CNF; + HPET_TIMER_CONF_CAP(1) |= HPET_Tn_INT_TYPE_CNF; + + /* Unask HPET IRQ in IOAPIC */ + task_enable_irq(ISH_HPET_TIMER0_IRQ); + task_enable_irq(ISH_HPET_TIMER1_IRQ); + + /* Enable interrupt */ + HPET_TIMER_CONF_CAP(0) |= HPET_Tn_INT_ENB_CNF; + HPET_TIMER_CONF_CAP(1) |= HPET_Tn_INT_ENB_CNF; + + while (HPET_CTRL_STATUS & HPET_T0_CONF_CAP_BIT) + ; + + /* Enable HPET main counter */ + HPET_GENERAL_CONFIG |= HPET_ENABLE_CNF; + + return ISH_HPET_TIMER1_IRQ; /* One shot */ +} |