#include <Library/UefiLib.h>\r
#include <Library/PcdLib.h>\r
#include <Library/IoLib.h>\r
-#include <Library/ArmArchTimerLib.h>\r
+#include <Library/ArmGenericTimerCounterLib.h>\r
+#include <Library/ArmArchTimer.h>\r
\r
#include <Protocol/Timer.h>\r
#include <Protocol/HardwareInterrupt.h>\r
\r
// The current period of the timer interrupt\r
UINT64 mTimerPeriod = 0;\r
+// The latest Timer Tick calculated for mTimerPeriod\r
+UINT64 mTimerTicks = 0;\r
+// Number of elapsed period since the last Timer interrupt\r
+UINT64 mElapsedPeriod = 1;\r
\r
// Cached copy of the Hardware Interrupt protocol instance\r
EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL;\r
IN VOID *Context\r
)\r
{\r
- ArmArchTimerDisableTimer ();\r
+ ArmGenericTimerDisableTimer ();\r
}\r
\r
/**\r
IN UINT64 TimerPeriod\r
)\r
{\r
+ UINT64 CounterValue;\r
UINT64 TimerTicks;\r
+ EFI_TPL OriginalTPL;\r
\r
// Always disable the timer\r
- ArmArchTimerDisableTimer ();\r
+ ArmGenericTimerDisableTimer ();\r
\r
if (TimerPeriod != 0) {\r
- // TimerTicks = TimerPeriod in 1ms unit x Frequency.10^-3\r
- // = TimerPeriod.10^-4 x Frequency.10^-3\r
- // = (TimerPeriod x Frequency) x 10^-7\r
+ // mTimerTicks = TimerPeriod in 1ms unit x Frequency.10^-3\r
+ // = TimerPeriod.10^-4 x Frequency.10^-3\r
+ // = (TimerPeriod x Frequency) x 10^-7\r
TimerTicks = MultU64x32 (TimerPeriod, FixedPcdGet32 (PcdArmArchTimerFreqInHz));\r
TimerTicks = DivU64x32 (TimerTicks, 10000000U);\r
\r
- ArmArchTimerSetTimerVal ((UINTN)TimerTicks);\r
+ // Raise TPL to update the mTimerTicks and mTimerPeriod to ensure these values\r
+ // are coherent in the interrupt handler\r
+ OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ mTimerTicks = TimerTicks;\r
+ mTimerPeriod = TimerPeriod;\r
+ mElapsedPeriod = 1;\r
+\r
+ gBS->RestoreTPL (OriginalTPL);\r
+\r
+ // Get value of the current timer\r
+ CounterValue = ArmGenericTimerGetSystemCount ();\r
+ // Set the interrupt in Current Time + mTimerTick\r
+ ArmGenericTimerSetCompareVal (CounterValue + mTimerTicks);\r
\r
// Enable the timer\r
- ArmArchTimerEnableTimer ();\r
+ ArmGenericTimerEnableTimer ();\r
+ } else {\r
+ // Save the new timer period\r
+ mTimerPeriod = TimerPeriod;\r
+ // Reset the elapsed period\r
+ mElapsedPeriod = 1;\r
}\r
\r
- // Save the new timer period\r
- mTimerPeriod = TimerPeriod;\r
return EFI_SUCCESS;\r
}\r
\r
)\r
{\r
EFI_TPL OriginalTPL;\r
+ UINT64 CurrentValue;\r
+ UINT64 CompareValue;\r
\r
//\r
// DXE core uses this callback for the EFI timer tick. The DXE core uses locks\r
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
\r
// Check if the timer interrupt is active\r
- if ((ArmArchTimerGetTimerCtrlReg () ) & ARM_ARCH_TIMER_ISTATUS) {\r
+ if ((ArmGenericTimerGetTimerCtrlReg () ) & ARM_ARCH_TIMER_ISTATUS) {\r
\r
// Signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers\r
gInterrupt->EndOfInterrupt (gInterrupt, Source);\r
\r
if (mTimerNotifyFunction) {\r
- mTimerNotifyFunction (mTimerPeriod);\r
+ mTimerNotifyFunction (mTimerPeriod * mElapsedPeriod);\r
}\r
\r
+ //\r
// Reload the Timer\r
- TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod));\r
+ //\r
+\r
+ // Get current counter value\r
+ CurrentValue = ArmGenericTimerGetSystemCount ();\r
+ // Get the counter value to compare with\r
+ CompareValue = ArmGenericTimerGetCompareVal ();\r
+\r
+ // This loop is needed in case we missed interrupts (eg: case when the interrupt handling\r
+ // has taken longer than mTickPeriod).\r
+ // Note: Physical Counter is counting up\r
+ mElapsedPeriod = 0;\r
+ do {\r
+ CompareValue += mTimerTicks;\r
+ mElapsedPeriod++;\r
+ } while (CompareValue < CurrentValue);\r
+\r
+ // Set next compare value\r
+ ArmGenericTimerSetCompareVal (CompareValue);\r
}\r
\r
// Enable timer interrupts\r
ASSERT_EFI_ERROR (Status);\r
\r
// Disable the timer\r
- TimerCtrlReg = ArmArchTimerGetTimerCtrlReg ();\r
+ TimerCtrlReg = ArmGenericTimerGetTimerCtrlReg ();\r
TimerCtrlReg |= ARM_ARCH_TIMER_IMASK;\r
TimerCtrlReg &= ~ARM_ARCH_TIMER_ENABLE;\r
- ArmArchTimerSetTimerCtrlReg (TimerCtrlReg);\r
+ ArmGenericTimerSetTimerCtrlReg (TimerCtrlReg);\r
Status = TimerDriverSetTimerPeriod (&gTimer, 0);\r
ASSERT_EFI_ERROR (Status);\r
\r
// Note: Because it is not possible to determine the security state of the\r
// CPU dynamically, we just install interrupt handler for both sec and non-sec\r
// timer PPI\r
+ Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerVirtIntrNum), TimerInterruptHandler);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerHypIntrNum), TimerInterruptHandler);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerSecIntrNum), TimerInterruptHandler);\r
ASSERT_EFI_ERROR (Status);\r
\r
\r
// Everything is ready, unmask and enable timer interrupts\r
TimerCtrlReg = ARM_ARCH_TIMER_ENABLE;\r
- ArmArchTimerSetTimerCtrlReg (TimerCtrlReg);\r
+ ArmGenericTimerSetTimerCtrlReg (TimerCtrlReg);\r
\r
// Register for an ExitBootServicesEvent\r
Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);\r