summaryrefslogtreecommitdiff
path: root/chip/ish/hwtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/ish/hwtimer.c')
-rw-r--r--chip/ish/hwtimer.c265
1 files changed, 0 insertions, 265 deletions
diff --git a/chip/ish/hwtimer.c b/chip/ish/hwtimer.c
deleted file mode 100644
index 1259dae7f4..0000000000
--- a/chip/ish/hwtimer.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Copyright 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 for ISH High Precision Event Timers (HPET) */
-
-#include "console.h"
-#include "hpet.h"
-#include "hwtimer.h"
-#include "timer.h"
-#include "registers.h"
-#include "task.h"
-#include "util.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)
-
-static uint32_t last_deadline;
-
-/*
- * The ISH hardware needs at least 25 ticks of leeway to arms the timer.
- * ISH4/5 are the slowest with 32kHz timers, so we wait at least 800us when
- * scheduling events in the future
- */
-#define MINIMUM_EVENT_DELAY_US 800
-
-/*
- * ISH HPET timer HW has latency for interrupt, on ISH5, this latency is about
- * 3 ticks, defined this configuration to calibrate the 'last_deadline' which is
- * updated in event timer interrupt ISR. Without this calibration, we could
- * get negative sleep time in idle task for low power sleep process.
- */
-#define HPET_INT_LATENCY_TICKS 3
-
-/* Scaling helper methods for different ISH chip variants */
-#ifdef CHIP_FAMILY_ISH3
-#define CLOCK_FACTOR 12
-BUILD_ASSERT(CLOCK_FACTOR * SECOND == ISH_HPET_CLK_FREQ);
-
-static inline uint64_t scale_us2ticks(uint64_t us)
-{
- return us * CLOCK_FACTOR;
-}
-
-static inline uint32_t scale_us2ticks_32(uint32_t us)
-{
- /* no optimization for ISH3 */
- return us * CLOCK_FACTOR;
-}
-
-static inline uint64_t scale_ticks2us(uint64_t ticks)
-{
- return ticks / CLOCK_FACTOR;
-}
-
-static inline void wait_while_settling(uint32_t mask)
-{
- /* Do nothing on ISH3, only ISH4 and ISH5 need settling */
-}
-
-#elif defined(CHIP_FAMILY_ISH4) || defined(CHIP_FAMILY_ISH5)
-#define CLOCK_SCALE_BITS 15
-BUILD_ASSERT(BIT(CLOCK_SCALE_BITS) == ISH_HPET_CLK_FREQ);
-
-/* Slow version, for 64-bit precision */
-static inline uint64_t scale_us2ticks(uint64_t us)
-{
- /* ticks = us * ISH_HPET_CLK_FREQ / SECOND */
-
- return (us << CLOCK_SCALE_BITS) / SECOND;
-}
-
-/* Fast version, for 32-bit precision */
-static inline uint32_t scale_us2ticks_32(uint32_t us)
-{
- /*
- * GCC optimizes this shift/divide into multiplication by a
- * magic number
- */
- return (us << CLOCK_SCALE_BITS) / SECOND;
-}
-
-static inline uint64_t scale_ticks2us(uint64_t ticks)
-{
- return (ticks * SECOND) >> CLOCK_SCALE_BITS;
-}
-
-/*
- * HPET Control & Status register may indicate that a value which has
- * been written still needs propogated by hardware. Before updating
- * HPET_TIMER_CONF_CAP(N), be sure to wait on the value settling with
- * the corresponding mask (see hpet.h).
- */
-static inline void wait_while_settling(uint32_t mask)
-{
- /* Wait for timer settings to settle ~ 150us */
- while (HPET_CTRL_STATUS & mask)
- continue;
-}
-
-#else
-#error "Must define CHIP_FAMILY_ISH(3|4|5)"
-#endif
-
-/*
- * The 64-bit read on a 32-bit chip can tear during the read. Ensure that the
- * value returned for 64-bit didn't rollover while we were reading it.
- */
-static inline uint64_t read_main_timer(void)
-{
- timestamp_t t;
- uint32_t hi;
-
- /* need check main counter if valid when exit low power TCG mode */
- wait_while_settling(HPET_MAIN_COUNTER_VALID);
-
- do {
- t.le.hi = HPET_MAIN_COUNTER_64_HI;
- t.le.lo = HPET_MAIN_COUNTER_64_LO;
- hi = HPET_MAIN_COUNTER_64_HI;
- } while (t.le.hi != hi);
-
- return t.val;
-}
-
-void __hw_clock_event_set(uint32_t deadline)
-{
- uint32_t remaining_us;
- uint32_t current_us;
- uint64_t current_ticks;
-
- /* 'current_ticks' is the current absolute 64bit HW timer counter */
- current_ticks = read_main_timer();
-
- /*
- * 'current_us' is the low 32bit part of current time in 64bit micro
- * seconds format, it's can express 2^32 micro seconds in maximum.
- */
- current_us = scale_ticks2us(current_ticks);
-
- /*
- * To ensure HW has enough time to react to the new timer value,
- * we make remaining time not less than 'MINIMUM_EVENT_DELAY_US'
- */
- remaining_us = deadline - current_us;
- remaining_us = MAX(remaining_us, MINIMUM_EVENT_DELAY_US);
-
- /*
- * Set new 64bit absolute timeout ticks to Timer 1 comparator
- * register.
- * For ISH3, this assumes that remaining_us is less than 360 seconds
- * (2^32 us / 12Mhz), otherwise we would need to handle 32-bit rollover
- * of 12Mhz timer comparator value. Watchdog refresh happens at least
- * every 10 seconds.
- */
- wait_while_settling(HPET_T1_CMP_SETTLING);
- HPET_TIMER_COMP(1) = current_ticks + scale_us2ticks_32(remaining_us);
-
- /*
- * Update 'last_deadline' and add calibrate delta due to HPET timer
- * interrupt latency.
- */
- last_deadline = current_us + remaining_us;
- last_deadline += scale_ticks2us(HPET_INT_LATENCY_TICKS);
-
- /* Enable timer interrupt */
- wait_while_settling(HPET_T1_SETTLING);
- HPET_TIMER_CONF_CAP(1) |= HPET_Tn_INT_ENB_CNF;
-}
-
-uint32_t __hw_clock_event_get(void)
-{
- return last_deadline;
-}
-
-void __hw_clock_event_clear(void)
-{
- /*
- * We need to make sure that process_timers is called when the
- * event timer rolls over, set for deadline when
- * process_timers clears the event timer.
- */
- __hw_clock_event_set(0xFFFFFFFF);
-}
-
-uint64_t __hw_clock_source_read64(void)
-{
- return scale_ticks2us(read_main_timer());
-}
-
-void __hw_clock_source_set64(uint64_t timestamp)
-{
- /* Reset both clock and overflow comparators */
- wait_while_settling(HPET_ANY_SETTLING);
- HPET_GENERAL_CONFIG &= ~HPET_ENABLE_CNF;
-
- HPET_MAIN_COUNTER_64 = scale_us2ticks(timestamp);
-
- wait_while_settling(HPET_ANY_SETTLING);
- HPET_GENERAL_CONFIG |= HPET_ENABLE_CNF;
-}
-
-static void hw_clock_event_isr(void)
-{
- /* Clear interrupt */
- wait_while_settling(HPET_INT_STATUS_SETTLING);
- HPET_INTR_CLEAR = BIT(1);
-
- process_timers(0);
-}
-DECLARE_IRQ(ISH_HPET_TIMER1_IRQ, hw_clock_event_isr);
-
-int __hw_clock_source_init64(uint64_t start_t)
-{
- /*
- * Timer 1 is used as an event timer. Timer 0 is unused, as
- * CONFIG_HWTIMER_64BIT is enabled.
- */
- uint32_t timer1_config = 0x00000000;
-
- /* Disable HPET */
- wait_while_settling(HPET_ANY_SETTLING);
- HPET_GENERAL_CONFIG &= ~HPET_ENABLE_CNF;
-
- /* Disable T0 */
- HPET_TIMER_CONF_CAP(0) &= ~HPET_Tn_INT_ENB_CNF;
-
- /* Disable T1 until we get it set up (below) */
- HPET_TIMER_CONF_CAP(1) &= ~HPET_Tn_INT_ENB_CNF;
-
- /* Initialize main counter */
- HPET_MAIN_COUNTER_64 = scale_us2ticks(start_t);
-
- /* Clear any interrupts from previously running image */
- HPET_INTR_CLEAR = BIT(0);
- HPET_INTR_CLEAR = BIT(1);
-
- /* Timer 1 - IRQ routing */
- timer1_config &= ~HPET_Tn_INT_ROUTE_CNF_MASK;
- timer1_config |= (ISH_HPET_TIMER1_IRQ <<
- HPET_Tn_INT_ROUTE_CNF_SHIFT);
-
- /* Level triggered interrupt */
- timer1_config |= HPET_Tn_INT_TYPE_CNF;
-
- /* Initialize last_deadline until an event is scheduled */
- last_deadline = 0xFFFFFFFF;
-
- /* Before enabling, previous values must have settled */
- wait_while_settling(HPET_ANY_SETTLING);
-
- /* Unmask HPET IRQ in IOAPIC */
- task_enable_irq(ISH_HPET_TIMER1_IRQ);
-
- /* Copy timer config to hardware register */
- HPET_TIMER_CONF_CAP(1) |= timer1_config;
-
- /* Enable HPET */
- HPET_GENERAL_CONFIG |= (HPET_ENABLE_CNF | HPET_LEGACY_RT_CNF);
-
- /* Return IRQ value for OS event timer */
- return ISH_HPET_TIMER1_IRQ;
-}