mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-31 02:51:26 +00:00
This change includes - Configuring the HPET timer based on the spec (IA-PC HPET (High Precision Event Timers) Specification 1.0a) - Two timers used: HPET Timer0 (free running periodic timer) HPET Timer1 (event based non-periodic timer) - HPET interrupts are routed to ISH via IOAPIC - Both the timers are functional BUG=None BRANCH=None TEST=`Build ISH and verify the timer interrupt via various console cmds` Change-Id: Ib5ca24d05790868430a2cfa72ca73f5bd6a5fea3 Signed-off-by: Divagar Mohandass <divagar.mohandass@intel.com> Signed-off-by: Kyoung Kim <kyoung.il.kim@intel.com> Reviewed-on: https://chromium-review.googlesource.com/453858 Reviewed-by: Aaron Durbin <adurbin@chromium.org>
138 lines
3.2 KiB
C
138 lines
3.2 KiB
C
/* 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 "console.h"
|
|
#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)
|
|
|
|
static uint32_t last_deadline;
|
|
|
|
/* TODO: Conform to EC API
|
|
* ISH supports 32KHz and 12MHz clock sources.
|
|
* EC expects timer value in 1MHz.
|
|
* Scale the values and support it.
|
|
*/
|
|
|
|
void __hw_clock_event_set(uint32_t deadline)
|
|
{
|
|
last_deadline = deadline;
|
|
HPET_TIMER_COMP(1) = deadline;
|
|
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)
|
|
{
|
|
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 = ts;
|
|
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
|
|
*/
|
|
|
|
uint32_t timer0_config = 0x00000000;
|
|
uint32_t timer1_config = 0x00000000;
|
|
|
|
/* Disable HPET */
|
|
HPET_GENERAL_CONFIG &= ~HPET_ENABLE_CNF;
|
|
HPET_MAIN_COUNTER = start_t;
|
|
|
|
/* Set comparator value */
|
|
HPET_TIMER_COMP(0) = 0XFFFFFFFF;
|
|
|
|
/* Timer 0 - enable periodic mode */
|
|
timer0_config |= HPET_Tn_TYPE_CNF;
|
|
timer0_config |= HPET_Tn_32MODE_CNF;
|
|
timer0_config |= HPET_Tn_VAL_SET_CNF;
|
|
|
|
/* Timer 0 - IRQ routing */
|
|
timer0_config &= ~HPET_Tn_INT_ROUTE_CNF_MASK;
|
|
timer0_config |= (ISH_HPET_TIMER0_IRQ <<
|
|
HPET_Tn_INT_ROUTE_CNF_SHIFT);
|
|
|
|
/* 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 */
|
|
timer0_config |= HPET_Tn_INT_TYPE_CNF;
|
|
timer1_config |= HPET_Tn_INT_TYPE_CNF;
|
|
|
|
/* Enable interrupt */
|
|
timer0_config |= HPET_Tn_INT_ENB_CNF;
|
|
timer1_config |= HPET_Tn_INT_ENB_CNF;
|
|
|
|
/* Unask HPET IRQ in IOAPIC */
|
|
task_enable_irq(ISH_HPET_TIMER0_IRQ);
|
|
task_enable_irq(ISH_HPET_TIMER1_IRQ);
|
|
|
|
/* Set timer 0/1 config */
|
|
HPET_TIMER_CONF_CAP(0) |= timer0_config;
|
|
HPET_TIMER_CONF_CAP(1) |= timer1_config;
|
|
|
|
#if defined CONFIG_ISH_40
|
|
/* Wait for timer to settle. required for ISH 4 */
|
|
while (HPET_CTRL_STATUS & HPET_T_CONF_CAP_BIT)
|
|
;
|
|
#endif
|
|
|
|
/* Enable HPET main counter */
|
|
HPET_GENERAL_CONFIG |= HPET_ENABLE_CNF;
|
|
|
|
return ISH_HPET_TIMER1_IRQ;
|
|
}
|