Template for Timer Architecture Protocol driver of the ARM flavor
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
#include <Protocol/HardwareInterrupt.h>
#include <Drivers/SP804Timer.h>
-#include <ArmPlatform.h>
+
+#define SP804_TIMER_PERIODIC_BASE ((UINTN)PcdGet32 (PcdSP804TimerPeriodicBase))
+#define SP804_TIMER_METRONOME_BASE ((UINTN)PcdGet32 (PcdSP804TimerMetronomeBase))
+#define SP804_TIMER_PERFORMANCE_BASE ((UINTN)PcdGet32 (PcdSP804TimerPerformanceBase))
// The notification function to call on every timer interrupt.
-volatile EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL;
-EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
+EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL;
+EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
// The current period of the timer interrupt
-volatile UINT64 mTimerPeriod = 0;
+UINT64 mTimerPeriod = 0;
// Cached copy of the Hardware Interrupt protocol instance
EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL;
// Cached interrupt vector
UINTN gVector;
-UINT32 mLastTickCount;
/**
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
// If the interrupt is shared then we must check if this interrupt source is the one associated to this Timer
- if (MmioRead32 (SP804_TIMER0_BASE + SP804_TIMER_MSK_INT_STS_REG) != 0) {
- // clear the periodic interrupt
- MmioWrite32 (SP804_TIMER0_BASE + SP804_TIMER_INT_CLR_REG, 0);
+ if (MmioRead32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_MSK_INT_STS_REG) != 0) {
+ // Clear the periodic interrupt
+ MmioWrite32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_INT_CLR_REG, 0);
- // signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers
+ // Signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers
gInterrupt->EndOfInterrupt (gInterrupt, Source);
if (mTimerNotifyFunction) {
}
/**
- Make sure all ArrmVe Timers are disabled
+ Make sure all Dual Timers are disabled
**/
VOID
EFIAPI
IN VOID *Context
)
{
- // Disable timer 0 if enabled
- if (MmioRead32(SP804_TIMER0_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
- MmioAnd32 (SP804_TIMER0_BASE + SP804_TIMER_CONTROL_REG, 0);
- }
-
- // Disable timer 1 if enabled
- if (MmioRead32(SP804_TIMER1_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
- MmioAnd32 (SP804_TIMER1_BASE + SP804_TIMER_CONTROL_REG, 0);
- }
+ // Disable 'Periodic Operation' timer if enabled
+ if (MmioRead32(SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
+ MmioAnd32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, 0);
+ }
- // Disable timer 2 if enabled
- if (MmioRead32(SP804_TIMER2_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
- MmioAnd32 (SP804_TIMER2_BASE + SP804_TIMER_CONTROL_REG, 0);
- }
+ // Disable 'Metronome/Delay' timer if enabled
+ if (MmioRead32(SP804_TIMER_METRONOME_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
+ MmioAnd32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CONTROL_REG, 0);
+ }
- // Disable timer 3 if enabled
- if (MmioRead32(SP804_TIMER3_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
- MmioAnd32 (SP804_TIMER3_BASE + SP804_TIMER_CONTROL_REG, 0);
- }
+ // Disable 'Performance' timer if enabled
+ if (MmioRead32(SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
+ MmioAnd32 (SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CONTROL_REG, 0);
+ }
}
/**
UINT64 TimerTicks;
// always disable the timer
- MmioAnd32 (SP804_TIMER0_BASE + SP804_TIMER_CONTROL_REG, ~SP804_TIMER_CTRL_ENABLE);
+ MmioAnd32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, ~SP804_TIMER_CTRL_ENABLE);
if (TimerPeriod == 0) {
// Leave timer disabled from above, and...
// Disable timer 0/1 interrupt for a TimerPeriod of 0
Status = gInterrupt->DisableInterruptSource (gInterrupt, gVector);
} else {
- // Convert TimerPeriod into 1MHz clock counts (us units = 100ns units / 10)
+ // Convert TimerPeriod into 1MHz clock counts (us units = 100ns units * 10)
TimerTicks = DivU64x32 (TimerPeriod, 10);
- TimerTicks = MultU64x32 (TimerTicks, PcdGet32(PcdSP804FrequencyInMHz));
+ TimerTicks = MultU64x32 (TimerTicks, PcdGet32(PcdSP804TimerFrequencyInMHz));
// if it's larger than 32-bits, pin to highest value
if (TimerTicks > 0xffffffff) {
-
TimerTicks = 0xffffffff;
-
}
// Program the SP804 timer with the new count value
- MmioWrite32 (SP804_TIMER0_BASE + SP804_TIMER_LOAD_REG, TimerTicks);
+ MmioWrite32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_LOAD_REG, TimerTicks);
// enable the timer
- MmioOr32 (SP804_TIMER0_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_ENABLE);
+ MmioOr32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_ENABLE);
// enable timer 0/1 interrupts
Status = gInterrupt->EnableInterruptSource (gInterrupt, gVector);
EFI_HANDLE Handle = NULL;
EFI_STATUS Status;
+ // Set the interrupt timer number
+ gVector = PcdGet32(PcdSP804TimerPeriodicInterruptNum);
+
// Find the interrupt controller protocol. ASSERT if not found.
Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt);
ASSERT_EFI_ERROR (Status);
- // Configure timer 1 for free running operation, 32 bits, no prescaler, interrupt disabled
- MmioWrite32 (SP804_TIMER1_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_32BIT | SP804_PRESCALE_DIV_1);
-
- // Enable the free running timer
- MmioOr32 (SP804_TIMER1_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_ENABLE);
-
- // Record free running tick value (should be close to 0xffffffff)
- mLastTickCount = MmioRead32 (SP804_TIMER1_BASE + SP804_TIMER_CURRENT_REG);
-
// Disable the timer
Status = TimerDriverSetTimerPeriod (&gTimer, 0);
ASSERT_EFI_ERROR (Status);
// Install interrupt handler
- gVector = PcdGet32(PcdSP804Timer0InterruptNum);
Status = gInterrupt->RegisterInterruptSource (gInterrupt, gVector, TimerInterruptHandler);
ASSERT_EFI_ERROR (Status);
// configure timer 0 for periodic operation, 32 bits, no prescaler, and interrupt enabled
- MmioWrite32 (SP804_TIMER0_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_PERIODIC | SP804_TIMER_CTRL_32BIT | SP804_PRESCALE_DIV_1 | SP804_TIMER_CTRL_INT_ENABLE);
+ MmioWrite32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_PERIODIC | SP804_TIMER_CTRL_32BIT | SP804_PRESCALE_DIV_1 | SP804_TIMER_CTRL_INT_ENABLE);
// Set up default timer
Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); // TIMER_DEFAULT_PERIOD