From da9675a241ab9856377b9bd63504b2d5333b3c7a Mon Sep 17 00:00:00 2001 From: oliviermartin Date: Tue, 27 Sep 2011 16:35:16 +0000 Subject: [PATCH] ArmPkg: Add ARM Architectural Timer support ARM Architectural Timer support is defined by the ARM Generic Timer Specification. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12455 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPkg/ArmPkg.dec | 7 + ArmPkg/Drivers/TimerDxe/TimerDxe.c | 379 ++++++++++++++++++ ArmPkg/Drivers/TimerDxe/TimerDxe.inf | 59 +++ ArmPkg/Include/Chipset/ArmV7.h | 7 + ArmPkg/Include/Chipset/ArmV7ArchTimer.h | 138 +++++++ ArmPkg/Include/Library/ArmLib.h | 2 +- ArmPkg/Include/Library/ArmV7ArchTimerLib.h | 115 ++++++ .../Library/ArmArchTimerLib/ArmArchTimerLib.c | 191 +++++++++ .../ArmArchTimerLib/ArmArchTimerLib.inf | 46 +++ ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c | 275 +++++++++++++ .../ArmLib/ArmV7/ArmV7ArchTimerSupport.S | 119 ++++++ .../ArmLib/ArmV7/ArmV7ArchTimerSupport.asm | 119 ++++++ ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf | 4 + ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf | 4 + ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf | 4 + 15 files changed, 1468 insertions(+), 1 deletion(-) create mode 100644 ArmPkg/Drivers/TimerDxe/TimerDxe.c create mode 100644 ArmPkg/Drivers/TimerDxe/TimerDxe.inf create mode 100644 ArmPkg/Include/Chipset/ArmV7ArchTimer.h create mode 100644 ArmPkg/Include/Library/ArmV7ArchTimerLib.h create mode 100644 ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c create mode 100644 ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf create mode 100644 ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c create mode 100644 ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.S create mode 100644 ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.asm diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec index 710e215198..c9bf606666 100644 --- a/ArmPkg/ArmPkg.dec +++ b/ArmPkg/ArmPkg.dec @@ -133,3 +133,10 @@ # The Linux ATAGs are expected to be under 0x4000 (16KB) from the beginning of the System Memory gArmTokenSpaceGuid.PcdArmLinuxAtagMaxOffset|0x4000|UINT32|0x00000020 + # + # ARM Architectural Timer + # + gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|0|UINT32|0x00000034 + # ARM Architectural Timer Interrupt(GIC PPI) number + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|29|UINT32|0x00000035 + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|30|UINT32|0x00000036 diff --git a/ArmPkg/Drivers/TimerDxe/TimerDxe.c b/ArmPkg/Drivers/TimerDxe/TimerDxe.c new file mode 100644 index 0000000000..3cde15ca40 --- /dev/null +++ b/ArmPkg/Drivers/TimerDxe/TimerDxe.c @@ -0,0 +1,379 @@ +/** @file + Timer Architecture Protocol driver of the ARM flavor + + Copyright (c) 2011 ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// The notification function to call on every timer interrupt. +EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL; +EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL; + +// The current period of the timer interrupt +UINT64 mTimerPeriod = 0; + +// Cached copy of the Hardware Interrupt protocol instance +EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL; + +/** + This function registers the handler NotifyFunction so it is called every time + the timer interrupt fires. It also passes the amount of time since the last + handler call to the NotifyFunction. If NotifyFunction is NULL, then the + handler is unregistered. If the handler is registered, then EFI_SUCCESS is + returned. If the CPU does not support registering a timer interrupt handler, + then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler + when a handler is already registered, then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to + register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR + is returned. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param NotifyFunction The function to call when a timer interrupt fires. This + function executes at TPL_HIGH_LEVEL. The DXE Core will + register a handler for the timer interrupt, so it can know + how much time has passed. This information is used to + signal timer based events. NULL will unregister the handler. + @retval EFI_SUCCESS The timer handler was registered. + @retval EFI_UNSUPPORTED The platform does not support timer interrupts. + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already + registered. + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not + previously registered. + @retval EFI_DEVICE_ERROR The timer handler could not be registered. + +**/ +EFI_STATUS +EFIAPI +TimerDriverRegisterHandler ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction + ) +{ + if ((NotifyFunction == NULL) && (mTimerNotifyFunction == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((NotifyFunction != NULL) && (mTimerNotifyFunction != NULL)) { + return EFI_ALREADY_STARTED; + } + + mTimerNotifyFunction = NotifyFunction; + + return EFI_SUCCESS; +} + +/** + Disable the timer +**/ +VOID +EFIAPI +ExitBootServicesEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + ArmArchTimerDisableTimer (); +} + +/** + + This function adjusts the period of timer interrupts to the value specified + by TimerPeriod. If the timer period is updated, then the selected timer + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. + If an error occurs while attempting to update the timer period, then the + timer hardware will be put back in its state prior to this call, and + EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt + is disabled. This is not the same as disabling the CPU's interrupts. + Instead, it must either turn off the timer hardware, or it must adjust the + interrupt controller so that a CPU interrupt is not generated when the timer + interrupt fires. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is + returned. If the timer is programmable, then the timer period + will be rounded up to the nearest timer period that is supported + by the timer hardware. If TimerPeriod is set to 0, then the + timer interrupts will be disabled. + + + @retval EFI_SUCCESS The timer period was changed. + @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. + @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. + +**/ +EFI_STATUS +EFIAPI +TimerDriverSetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +{ + UINT64 TimerTicks; + + // always disable the timer + ArmArchTimerDisableTimer (); + + if (TimerPeriod != 0) { + // Convert TimerPeriod to micro sec units + TimerTicks = DivU64x32 (TimerPeriod, 10); + + TimerTicks = MultU64x32 (TimerPeriod, (PcdGet32(PcdArmArchTimerFreqInHz)/1000000)); + + ArmArchTimerSetTimerVal((UINTN)TimerTicks); + + // Enable the timer + ArmArchTimerEnableTimer (); + } + + // Save the new timer period + mTimerPeriod = TimerPeriod; + return EFI_SUCCESS; +} + +/** + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. If + 0 is returned, then the timer is currently disabled. + + + @retval EFI_SUCCESS The timer period was returned in TimerPeriod. + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +{ + if (TimerPeriod == NULL) { + return EFI_INVALID_PARAMETER; + } + + *TimerPeriod = mTimerPeriod; + return EFI_SUCCESS; +} + +/** + This function generates a soft timer interrupt. If the platform does not support soft + timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned. + If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler() + service, then a soft timer interrupt will be generated. If the timer interrupt is + enabled when this service is called, then the registered handler will be invoked. The + registered handler should not be able to distinguish a hardware-generated timer + interrupt from a software-generated timer interrupt. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS The soft timer interrupt was generated. + @retval EFI_UNSUPPORTED The platform does not support the generation of soft timer interrupts. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGenerateSoftInterrupt ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Interface structure for the Timer Architectural Protocol. + + @par Protocol Description: + This protocol provides the services to initialize a periodic timer + interrupt, and to register a handler that is called each time the timer + interrupt fires. It may also provide a service to adjust the rate of the + periodic timer interrupt. When a timer interrupt occurs, the handler is + passed the amount of time that has passed since the previous timer + interrupt. + + @param RegisterHandler + Registers a handler that will be called each time the + timer interrupt fires. TimerPeriod defines the minimum + time between timer interrupts, so TimerPeriod will also + be the minimum time between calls to the registered + handler. + + @param SetTimerPeriod + Sets the period of the timer interrupt in 100 nS units. + This function is optional, and may return EFI_UNSUPPORTED. + If this function is supported, then the timer period will + be rounded up to the nearest supported timer period. + + + @param GetTimerPeriod + Retrieves the period of the timer interrupt in 100 nS units. + + @param GenerateSoftInterrupt + Generates a soft timer interrupt that simulates the firing of + the timer interrupt. This service can be used to invoke the registered handler if the timer interrupt has been masked for + a period of time. + +**/ +EFI_TIMER_ARCH_PROTOCOL gTimer = { + TimerDriverRegisterHandler, + TimerDriverSetTimerPeriod, + TimerDriverGetTimerPeriod, + TimerDriverGenerateSoftInterrupt +}; + +/** + + C Interrupt Handler called in the interrupt context when Source interrupt is active. + + + @param Source Source of the interrupt. Hardware routing off a specific platform defines + what source means. + + @param SystemContext Pointer to system register context. Mostly used by debuggers and will + update the system context after the return from the interrupt if + modified. Don't change these values unless you know what you are doing + +**/ +VOID +EFIAPI +TimerInterruptHandler ( + IN HARDWARE_INTERRUPT_SOURCE Source, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_TPL OriginalTPL; + + // + // DXE core uses this callback for the EFI timer tick. The DXE core uses locks + // that raise to TPL_HIGH and then restore back to current level. Thus we need + // to make sure TPL level is set to TPL_HIGH while we are handling the timer tick. + // + OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + // Check if the timer interrupt is active + if ((ArmArchTimerGetTimerCtrlReg () ) & ARM_ARCH_TIMER_ISTATUS) { + + // Signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers + gInterrupt->EndOfInterrupt (gInterrupt, Source); + + if (mTimerNotifyFunction) { + mTimerNotifyFunction (mTimerPeriod); + } + + // Reload the Timer + TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); + } + + // Enable timer interrupts + gInterrupt->EnableInterruptSource (gInterrupt, Source); + + gBS->RestoreTPL (OriginalTPL); +} + + +/** + Initialize the state information for the Timer Architectural Protocol and + the Timer Debug support protocol that allows the debugger to break into a + running program. + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +TimerInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HANDLE Handle = NULL; + EFI_STATUS Status; + UINTN TimerCtrlReg; + + if (ArmIsArchTimerImplemented () == 0) { + DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence cann't use this Driver \n")); + ASSERT (0); + } + + // Find the interrupt controller protocol. ASSERT if not found. + Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt); + ASSERT_EFI_ERROR (Status); + + // Disable the timer + Status = TimerDriverSetTimerPeriod (&gTimer, 0); + ASSERT_EFI_ERROR (Status); + + // Install secure and Non-secure interrupt handlers + // Note: Because it is not possible to determine the security state of the + // CPU dynamically, we just install interrupt handler for both sec and non-sec + // timer PPI + Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerSecIntrNum), TimerInterruptHandler); + ASSERT_EFI_ERROR (Status); + + Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerIntrNum), TimerInterruptHandler); + ASSERT_EFI_ERROR (Status); + + // Unmask timer interrupts + TimerCtrlReg = ArmArchTimerGetTimerCtrlReg (); + TimerCtrlReg &= ~ARM_ARCH_TIMER_IMASK; + ArmArchTimerSetTimerCtrlReg (TimerCtrlReg); + + // Set up default timer + Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); // TIMER_DEFAULT_PERIOD + ASSERT_EFI_ERROR (Status); + + // Install the Timer Architectural Protocol onto a new handle + Status = gBS->InstallMultipleProtocolInterfaces( + &Handle, + &gEfiTimerArchProtocolGuid, &gTimer, + NULL + ); + ASSERT_EFI_ERROR(Status); + + // enable Secure timer interrupts + Status = gInterrupt->EnableInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerSecIntrNum)); + + // enable NonSecure timer interrupts + Status = gInterrupt->EnableInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerIntrNum)); + + // Register for an ExitBootServicesEvent + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/ArmPkg/Drivers/TimerDxe/TimerDxe.inf b/ArmPkg/Drivers/TimerDxe/TimerDxe.inf new file mode 100644 index 0000000000..2f807a850b --- /dev/null +++ b/ArmPkg/Drivers/TimerDxe/TimerDxe.inf @@ -0,0 +1,59 @@ +#/** @file +# +# Component discription file for Timer DXE module +# +# Copyright (c) 2009 - 2010, Apple Inc. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmTimerDxe + FILE_GUID = 49ea041e-6752-42ca-b0b1-7344fe2546b7 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = TimerInitialize + +[Sources.common] + TimerDxe.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + +[LibraryClasses] + ArmLib + BaseLib + UefiRuntimeServicesTableLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiDriverEntryPoint + IoLib + +[Guids] + +[Protocols] + gEfiTimerArchProtocolGuid + gHardwareInterruptProtocolGuid + +[Pcd.common] + gEmbeddedTokenSpaceGuid.PcdTimerPeriod + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum + gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz + +[Depex] + gHardwareInterruptProtocolGuid + \ No newline at end of file diff --git a/ArmPkg/Include/Chipset/ArmV7.h b/ArmPkg/Include/Chipset/ArmV7.h index 909686ce36..bb306a5f48 100644 --- a/ArmPkg/Include/Chipset/ArmV7.h +++ b/ArmPkg/Include/Chipset/ArmV7.h @@ -17,6 +17,7 @@ #define __ARM_V7_H__ #include +#include // Domain Access Control Register #define DOMAIN_ACCESS_CONTROL_MASK(a) (3UL << (2 * (a))) @@ -80,6 +81,12 @@ ArmWriteTpidrurw ( UINTN Value ); +UINTN +EFIAPI +ArmIsArchTimerImplemented ( + VOID + ); + UINTN EFIAPI ArmReadIdPfr1 ( diff --git a/ArmPkg/Include/Chipset/ArmV7ArchTimer.h b/ArmPkg/Include/Chipset/ArmV7ArchTimer.h new file mode 100644 index 0000000000..734c8855ee --- /dev/null +++ b/ArmPkg/Include/Chipset/ArmV7ArchTimer.h @@ -0,0 +1,138 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#ifndef __ARMV7_ARCH_TIMER_H_ +#define __ARMV7_ARCH_TIMER_H_ + +UINTN +EFIAPI +ArmReadCntFrq ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntFrq ( + UINTN FreqInHz + ); + +UINT64 +EFIAPI +ArmReadCntPct ( + VOID + ); + +UINTN +EFIAPI +ArmReadCntkCtl ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntkCtl ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntpTval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntpTval ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntpCtl ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntpCtl ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntvTval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvTval ( + UINTN Val + ); + +UINTN +EFIAPI +ArmReadCntvCtl ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvCtl ( + UINTN Val + ); + +UINT64 +EFIAPI +ArmReadCntvCt ( + VOID + ); + +UINT64 +EFIAPI +ArmReadCntpCval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntpCval ( + UINT64 Val + ); + +UINT64 +EFIAPI +ArmReadCntvCval ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvCval ( + UINT64 Val + ); + +UINT64 +EFIAPI +ArmReadCntvOff ( + VOID + ); + +VOID +EFIAPI +ArmWriteCntvOff ( + UINT64 Val + ); + +#endif diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h index e88633e1e9..3ce687244f 100644 --- a/ArmPkg/Include/Library/ArmLib.h +++ b/ArmPkg/Include/Library/ArmLib.h @@ -167,7 +167,7 @@ Cp15CacheInfo ( BOOLEAN EFIAPI -ArmIsMPCore ( +ArmIsMpCore ( VOID ); diff --git a/ArmPkg/Include/Library/ArmV7ArchTimerLib.h b/ArmPkg/Include/Library/ArmV7ArchTimerLib.h new file mode 100644 index 0000000000..d2f4a46c66 --- /dev/null +++ b/ArmPkg/Include/Library/ArmV7ArchTimerLib.h @@ -0,0 +1,115 @@ +/** @file + + Copyright (c) 2011, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ARM_V7_ARCH_TIMER_LIB_H__ +#define __ARM_V7_ARCH_TIMER_LIB_H__ + +#define ARM_ARCH_TIMER_ENABLE (1 << 0) +#define ARM_ARCH_TIMER_IMASK (1 << 1) +#define ARM_ARCH_TIMER_ISTATUS (1 << 2) + +typedef enum { + CntFrq = 0, + CntPct, + CntkCtl, + CntpTval, + CntpCtl, + CntvTval, + CntvCtl, + CntvCt, + CntpCval, + CntvCval, + CntvOff, + CnthCtl, + CnthpTval, + CnthpCtl, + CnthpCval, + RegMaximum +}ARM_ARCH_TIMER_REGS; + +VOID +EFIAPI +ArmArchTimerReadReg ( + IN ARM_ARCH_TIMER_REGS Reg, + OUT VOID *DstBuf + ); + +VOID +EFIAPI +ArmArchTimerWriteReg ( + IN ARM_ARCH_TIMER_REGS Reg, + IN VOID *SrcBuf + ); + +VOID +EFIAPI +ArmArchTimerEnableTimer ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerDisableTimer ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerSetTimerFreq ( + IN UINTN FreqInHz + ); + +UINTN +EFIAPI +ArmArchTimerGetTimerFreq ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerSetTimerVal ( + IN UINTN Val + ); + +UINTN +EFIAPI +ArmArchTimerGetTimerVal ( + VOID + ); + +UINT64 +EFIAPI +ArmArchTimerGetSystemCount ( + VOID + ); + +UINTN +EFIAPI +ArmArchTimerGetTimerCtrlReg ( + VOID + ); + +VOID +EFIAPI +ArmArchTimerSetTimerCtrlReg ( + UINTN Val + ); + +VOID +EFIAPI +ArmArchTimerSetCompareVal ( + IN UINT64 Val + ); + +#endif // __ARM_V7_ARCH_TIMER_LIB_H__ diff --git a/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c b/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c new file mode 100644 index 0000000000..d6f3f1b709 --- /dev/null +++ b/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c @@ -0,0 +1,191 @@ +/** @file + Generic ARM implementation of TimerLib.h + + Copyright (c) 2011, ARM Limited. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include +#include +#include +#include +#include +#include +#include + +#define TICKS_PER_MICRO_SEC (PcdGet32 (PcdArmArchTimerFreqInHz)/1000000U) + +RETURN_STATUS +EFIAPI +ArmArchTimerLibConstructor ( + VOID + ) +{ + // Check if the ARM Generic Timer Extension is implemented + if (ArmIsArchTimerImplemented ()) { + + UINTN TimerFreq; + + // Check if Architectural Timer frequency is valid number (should not be 0) + ASSERT (PcdGet32 (PcdArmArchTimerFreqInHz)); + + // Check if ticks/uS is not 0. The Architectural timer runs at constant + // frequency irrespective of CPU frequency. According to General Timer Ref + // manual lower bound of the frequency is in the range of 1-10MHz + ASSERT (TICKS_PER_MICRO_SEC); + + // If the security extensions are not implemented set Timer Frequency + if ((ArmReadIdPfr1 () & 0xF0)) { + ArmArchTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz)); + } + + // Architectural Timer Frequency must be set in the Secure privileged(if secure extensions are supported) mode. + // If the reset value (0) is returned just ASSERT. + TimerFreq = ArmArchTimerGetTimerFreq (); + ASSERT (TimerFreq); + + } else { + DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, Hence cann't use this library \n")); + ASSERT (0); + } + + return RETURN_SUCCESS; +} + + +/** + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return The value of MicroSeconds inputted. + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + UINT64 TimerTicks64; + UINT64 SystemCounterVal; + + // Calculate counter ticks that can represent requsted delay + TimerTicks64 = MultU64x32 (MicroSeconds, TICKS_PER_MICRO_SEC); + + // Read System Counter value + SystemCounterVal = ArmArchTimerGetSystemCount (); + + TimerTicks64 += SystemCounterVal; + + // Wait until delay count is expired. + while (SystemCounterVal < TimerTicks64) { + SystemCounterVal = ArmArchTimerGetSystemCount (); + } + + return MicroSeconds; +} + + +/** + Stalls the CPU for at least the given number of nanoseconds. + + Stalls the CPU for the number of nanoseconds specified by NanoSeconds. + + When the timer frequency is 1MHz, each tick corresponds to 1 microsecond. + Therefore, the nanosecond delay will be rounded up to the nearest 1 microsecond. + + @param NanoSeconds The minimum number of nanoseconds to delay. + + @return The value of NanoSeconds inputted. + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + UINTN MicroSeconds; + + // Round up to 1us Tick Number + MicroSeconds = NanoSeconds / 1000; + MicroSeconds += ((NanoSeconds % 1000) == 0) ? 0 : 1; + + MicroSecondDelay (MicroSeconds); + + return NanoSeconds; +} + +/** + Retrieves the current value of a 64-bit free running performance counter. + + The counter can either count up by 1 or count down by 1. If the physical + performance counter counts by a larger increment, then the counter values + must be translated. The properties of the counter can be retrieved from + GetPerformanceCounterProperties(). + + @return The current value of the free running performance counter. + +**/ +UINT64 +EFIAPI +GetPerformanceCounter ( + VOID + ) +{ + // Just return the value of system count + return ArmArchTimerGetSystemCount (); +} + +/** + Retrieves the 64-bit frequency in Hz and the range of performance counter + values. + + If StartValue is not NULL, then the value that the performance counter starts + with immediately after is it rolls over is returned in StartValue. If + EndValue is not NULL, then the value that the performance counter end with + immediately before it rolls over is returned in EndValue. The 64-bit + frequency of the performance counter in Hz is always returned. If StartValue + is less than EndValue, then the performance counter counts up. If StartValue + is greater than EndValue, then the performance counter counts down. For + example, a 64-bit free running counter that counts up would have a StartValue + of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter + that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. + + @param StartValue The value the performance counter starts with when it + rolls over. + @param EndValue The value that the performance counter ends with before + it rolls over. + + @return The frequency in Hz. + +**/ +UINT64 +EFIAPI +GetPerformanceCounterProperties ( + OUT UINT64 *StartValue, OPTIONAL + OUT UINT64 *EndValue OPTIONAL + ) +{ + if (StartValue != NULL) { + // Timer starts with the reload value + *StartValue = (UINT64)0ULL ; + } + + if (EndValue != NULL) { + // Timer counts down to 0x0 + *EndValue = 0xFFFFFFFFFFFFFFFF;; + } + + return (UINT64)ArmArchTimerGetTimerFreq (); +} diff --git a/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf b/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf new file mode 100644 index 0000000000..87548b4851 --- /dev/null +++ b/ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf @@ -0,0 +1,46 @@ +#/** @file +# +# Copyright (c) 2011, ARM Limited. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmArchTimerLib + FILE_GUID = 82da1b44-d2d6-4a7d-bbf0-a0cb67964034 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib + CONSTRUCTOR = ArmArchTimerLibConstructor + +[Sources.common] + ArmArchTimerLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + + +[LibraryClasses] + DebugLib + IoLib + ArmLib + BaseLib + +[Protocols] + +[Guids] + +[Pcd] + gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c new file mode 100644 index 0000000000..1cba12d300 --- /dev/null +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimer.c @@ -0,0 +1,275 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include "ArmV7Lib.h" +#include "ArmLibPrivate.h" +#include + +VOID +EFIAPI +ArmArchTimerReadReg ( + IN ARM_ARCH_TIMER_REGS Reg, + OUT VOID *DstBuf + ) +{ + // Check if the Generic/Architecture timer is implemented + if (ArmIsArchTimerImplemented ()) { + + switch (Reg) { + + case CntFrq: + *((UINTN *)DstBuf) = ArmReadCntFrq (); + break; + + case CntPct: + *((UINT64 *)DstBuf) = ArmReadCntPct (); + break; + + case CntkCtl: + *((UINTN *)DstBuf) = ArmReadCntkCtl(); + break; + + case CntpTval: + *((UINTN *)DstBuf) = ArmReadCntpTval (); + break; + + case CntpCtl: + *((UINTN *)DstBuf) = ArmReadCntpCtl (); + break; + + case CntvTval: + *((UINTN *)DstBuf) = ArmReadCntvTval (); + break; + + case CntvCtl: + *((UINTN *)DstBuf) = ArmReadCntvCtl (); + break; + + case CntvCt: + *((UINT64 *)DstBuf) = ArmReadCntvCt (); + break; + + case CntpCval: + *((UINT64 *)DstBuf) = ArmReadCntpCval (); + break; + + case CntvCval: + *((UINT64 *)DstBuf) = ArmReadCntvCval (); + break; + + case CntvOff: + *((UINT64 *)DstBuf) = ArmReadCntvOff (); + break; + + case CnthCtl: + case CnthpTval: + case CnthpCtl: + case CnthpCval: + DEBUG ((EFI_D_ERROR, "The register is related to Hyperviser Mode. Can't perform requested operation\n ")); + break; + + default: + DEBUG ((EFI_D_ERROR, "Unknown ARM Generic Timer register %x. \n ", Reg)); + } + } else { + DEBUG ((EFI_D_ERROR, "Attempt to read ARM Generic Timer registers. But ARM Generic Timer extension is not implemented \n ")); + ASSERT (0); + } +} + +VOID +EFIAPI +ArmArchTimerWriteReg ( + IN ARM_ARCH_TIMER_REGS Reg, + IN VOID *SrcBuf + ) +{ + // Check if the Generic/Architecture timer is implemented + if (ArmIsArchTimerImplemented ()) { + + switch (Reg) { + + case CntFrq: + ArmWriteCntFrq (*((UINTN *)SrcBuf)); + break; + + case CntPct: + DEBUG ((EFI_D_ERROR, "Can't write to Read Only Register: CNTPCT \n")); + break; + + case CntkCtl: + ArmWriteCntkCtl (*((UINTN *)SrcBuf)); + break; + + case CntpTval: + ArmWriteCntpTval (*((UINTN *)SrcBuf)); + break; + + case CntpCtl: + ArmWriteCntpCtl (*((UINTN *)SrcBuf)); + break; + + case CntvTval: + ArmWriteCntvTval (*((UINTN *)SrcBuf)); + break; + + case CntvCtl: + ArmWriteCntvCtl (*((UINTN *)SrcBuf)); + break; + + case CntvCt: + DEBUG ((EFI_D_ERROR, "Can't write to Read Only Register: CNTVCT \n")); + break; + + case CntpCval: + ArmWriteCntpCval (*((UINT64 *)SrcBuf) ); + break; + + case CntvCval: + ArmWriteCntvCval (*((UINT64 *)SrcBuf) ); + break; + + case CntvOff: + ArmWriteCntvOff (*((UINT64 *)SrcBuf)); + break; + + case CnthCtl: + case CnthpTval: + case CnthpCtl: + case CnthpCval: + DEBUG ((EFI_D_ERROR, "The register is related to Hypervisor Mode. Can't perform requested operation\n ")); + break; + + default: + DEBUG ((EFI_D_ERROR, "Unknown ARM Generic Timer register %x. \n ", Reg)); + } + } else { + DEBUG ((EFI_D_ERROR, "Attempt to write to ARM Generic Timer registers. But ARM Generic Timer extension is not implemented \n ")); + ASSERT (0); + } +} + +VOID +EFIAPI +ArmArchTimerEnableTimer ( + VOID + ) +{ + UINTN TimerCtrlReg; + + ArmArchTimerReadReg (CntpCtl, (VOID *)&TimerCtrlReg); + TimerCtrlReg |= ARM_ARCH_TIMER_ENABLE; + ArmArchTimerWriteReg (CntpCtl, (VOID *)&TimerCtrlReg); +} + +VOID +EFIAPI +ArmArchTimerDisableTimer ( + VOID + ) +{ + UINTN TimerCtrlReg; + + ArmArchTimerReadReg (CntpCtl, (VOID *)&TimerCtrlReg); + TimerCtrlReg &= ~ARM_ARCH_TIMER_ENABLE; + ArmArchTimerWriteReg (CntpCtl, (VOID *)&TimerCtrlReg); +} + +VOID +EFIAPI +ArmArchTimerSetTimerFreq ( + IN UINTN FreqInHz + ) +{ + ArmArchTimerWriteReg (CntFrq, (VOID *)&FreqInHz); +} + +UINTN +EFIAPI +ArmArchTimerGetTimerFreq ( + VOID + ) +{ + UINTN ArchTimerFreq = 0; + ArmArchTimerReadReg (CntFrq, (VOID *)&ArchTimerFreq); + return ArchTimerFreq; +} + +UINTN +EFIAPI +ArmArchTimerGetTimerVal ( + VOID + ) +{ + UINTN ArchTimerVal; + ArmArchTimerReadReg (CntpTval, (VOID *)&ArchTimerVal); + return ArchTimerVal; +} + + +VOID +EFIAPI +ArmArchTimerSetTimerVal ( + IN UINTN Val + ) +{ + ArmArchTimerWriteReg (CntpTval, (VOID *)&Val); +} + +UINT64 +EFIAPI +ArmArchTimerGetSystemCount ( + VOID + ) +{ + UINT64 SystemCount; + ArmArchTimerReadReg (CntPct, (VOID *)&SystemCount); + return SystemCount; +} + +UINTN +EFIAPI +ArmArchTimerGetTimerCtrlReg ( + VOID + ) +{ + UINTN Val; + ArmArchTimerReadReg (CntpCtl, (VOID *)&Val); + return Val; +} + +VOID +EFIAPI +ArmArchTimerSetTimerCtrlReg ( + UINTN Val + ) +{ + ArmArchTimerWriteReg (CntpCtl, (VOID *)&Val); +} + +VOID +EFIAPI +ArmArchTimerSetCompareVal ( + IN UINT64 Val + ) +{ + ArmArchTimerWriteReg (CntpCval, (VOID *)&Val); +} diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.S b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.S new file mode 100644 index 0000000000..531d8fd1e0 --- /dev/null +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.S @@ -0,0 +1,119 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2011, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +.text +.align 2 + +GCC_ASM_EXPORT (ArmReadCntFrq) +GCC_ASM_EXPORT (ArmWriteCntFrq) +GCC_ASM_EXPORT (ArmReadCntPct) +GCC_ASM_EXPORT (ArmReadCntkCtl) +GCC_ASM_EXPORT (ArmWriteCntkCtl) +GCC_ASM_EXPORT (ArmReadCntpTval) +GCC_ASM_EXPORT (ArmWriteCntpTval) +GCC_ASM_EXPORT (ArmReadCntpCtl) +GCC_ASM_EXPORT (ArmWriteCntpCtl) +GCC_ASM_EXPORT (ArmReadCntvTval) +GCC_ASM_EXPORT (ArmWriteCntvTval) +GCC_ASM_EXPORT (ArmReadCntvCtl) +GCC_ASM_EXPORT (ArmWriteCntvCtl) +GCC_ASM_EXPORT (ArmReadCntvCt) +GCC_ASM_EXPORT (ArmReadCntpCval) +GCC_ASM_EXPORT (ArmWriteCntpCval) +GCC_ASM_EXPORT (ArmReadCntvCval) +GCC_ASM_EXPORT (ArmWriteCntvCval) +GCC_ASM_EXPORT (ArmReadCntvOff) +GCC_ASM_EXPORT (ArmWriteCntvOff) + +ASM_PFX(ArmReadCntFrq): + mrc p15, 0, r0, c14, c0, 0 @ Read CNTFRQ + bx lr + +ASM_PFX(ArmWriteCntFrq): + mcr p15, 0, r0, c14, c0, 0 @ Write to CNTFRQ + bx lr + +ASM_PFX(ArmReadCntPct): + mrrc p15, 0, r0, r1, c14 @ Read CNTPT (Physical counter register) + bx lr + +ASM_PFX(ArmReadCntkCtl): + mrc p15, 0, r0, c14, c1, 0 @ Read CNTK_CTL (Timer PL1 Control Register) + bx lr + +ASM_PFX(ArmWriteCntkCtl): + mcr p15, 0, r0, c14, c1, 0 @ Write to CNTK_CTL (Timer PL1 Control Register) + bx lr + +ASM_PFX(ArmReadCntpTval): + mrc p15, 0, r0, c14, c2, 0 @ Read CNTP_TVAL (PL1 physical timer value register) + bx lr + +ASM_PFX(ArmWriteCntpTval): + mcr p15, 0, r0, c14, c2, 0 @ Write to CNTP_TVAL (PL1 physical timer value register) + bx lr + +ASM_PFX(ArmReadCntpCtl): + mrc p15, 0, r0, c14, c2, 1 @ Read CNTP_CTL (PL1 Physical Timer Control Register) + bx lr + +ASM_PFX(ArmWriteCntpCtl): + mcr p15, 0, r0, c14, c2, 1 @ Write to CNTP_CTL (PL1 Physical Timer Control Register) + bx lr + +ASM_PFX(ArmReadCntvTval): + mrc p15, 0, r0, c14, c3, 0 @ Read CNTV_TVAL (Virtual Timer Value register) + bx lr + +ASM_PFX(ArmWriteCntvTval): + mcr p15, 0, r0, c14, c3, 0 @ Write to CNTV_TVAL (Virtual Timer Value register) + bx lr + +ASM_PFX(ArmReadCntvCtl): + mrc p15, 0, r0, c14, c3, 1 @ Read CNTV_CTL (Virtual Timer Control Register) + bx lr + +ASM_PFX(ArmWriteCntvCtl): + mcr p15, 0, r0, c14, c3, 1 @ Write to CNTV_CTL (Virtual Timer Control Register) + bx lr + +ASM_PFX(ArmReadCntvCt): + mrrc p15, 1, r0, r1, c14 @ Read CNTVCT (Virtual Count Register) + bx lr + +ASM_PFX(ArmReadCntpCval): + mrrc p15, 2, r0, r1, c14 @ Read CNTP_CTVAL (Physical Timer Compare Value Register) + bx lr + +ASM_PFX(ArmWriteCntpCval): + mcrr p15, 2, r0, r1, c14 @ Write to CNTP_CTVAL (Physical Timer Compare Value Register) + bx lr + +ASM_PFX(ArmReadCntvCval): + mrrc p15, 3, r0, r1, c14 @ Read CNTV_CTVAL (Virtual Timer Compare Value Register) + bx lr + +ASM_PFX(ArmWriteCntvCval): + mcrr p15, 3, r0, r1, c14 @ write to CNTV_CTVAL (Virtual Timer Compare Value Register) + bx lr + +ASM_PFX(ArmReadCntvOff): + mrrc p15, 4, r0, r1, c14 @ Read CNTVOFF (virtual Offset register) + bx lr + +ASM_PFX(ArmWriteCntvOff): + mcrr p15, 4, r0, r1, c14 @ Write to CNTVOFF (Virtual Offset register) + bx lr + +ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.asm b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.asm new file mode 100644 index 0000000000..fc0be1966b --- /dev/null +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7ArchTimerSupport.asm @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) 2011, ARM Limited. All rights reserved. +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +//------------------------------------------------------------------------------ + + EXPORT ArmReadCntFrq + EXPORT ArmWriteCntFrq + EXPORT ArmReadCntPct + EXPORT ArmReadCntkCtl + EXPORT ArmWriteCntkCtl + EXPORT ArmReadCntpTval + EXPORT ArmWriteCntpTval + EXPORT ArmReadCntpCtl + EXPORT ArmWriteCntpCtl + EXPORT ArmReadCntvTval + EXPORT ArmWriteCntvTval + EXPORT ArmReadCntvCtl + EXPORT ArmWriteCntvCtl + EXPORT ArmReadCntvCt + EXPORT ArmReadCntpCval + EXPORT ArmWriteCntpCval + EXPORT ArmReadCntvCval + EXPORT ArmWriteCntvCval + EXPORT ArmReadCntvOff + EXPORT ArmWriteCntvOff + + AREA ArmV7ArchTimerSupport, CODE, READONLY + PRESERVE8 + +ArmReadCntFrq + mrc p15, 0, r0, c14, c0, 0 ; Read CNTFRQ + bx lr + +ArmWriteCntFrq + mcr p15, 0, r0, c14, c0, 0 ; Write to CNTFRQ + bx lr + +ArmReadCntPct + mrrc p15, 0, r0, r1, c14 ; Read CNTPT (Physical counter register) + bx lr + +ArmReadCntkCtl + mrc p15, 0, r0, c14, c1, 0 ; Read CNTK_CTL (Timer PL1 Control Register) + bx lr + +ArmWriteCntkCtl + mcr p15, 0, r0, c14, c1, 0 ; Write to CNTK_CTL (Timer PL1 Control Register) + bx lr + +ArmReadCntpTval + mrc p15, 0, r0, c14, c2, 0 ; Read CNTP_TVAL (PL1 physical timer value register) + bx lr + +ArmWriteCntpTval + mcr p15, 0, r0, c14, c2, 0 ; Write to CNTP_TVAL (PL1 physical timer value register) + bx lr + +ArmReadCntpCtl + mrc p15, 0, r0, c14, c2, 1 ; Read CNTP_CTL (PL1 Physical Timer Control Register) + bx lr + +ArmWriteCntpCtl + mcr p15, 0, r0, c14, c2, 1 ; Write to CNTP_CTL (PL1 Physical Timer Control Register) + bx lr + +ArmReadCntvTval + mrc p15, 0, r0, c14, c3, 0 ; Read CNTV_TVAL (Virtual Timer Value register) + bx lr + +ArmWriteCntvTval + mcr p15, 0, r0, c14, c3, 0 ; Write to CNTV_TVAL (Virtual Timer Value register) + bx lr + +ArmReadCntvCtl + mrc p15, 0, r0, c14, c3, 1 ; Read CNTV_CTL (Virtual Timer Control Register) + bx lr + +ArmWriteCntvCtl + mcr p15, 0, r0, c14, c3, 1 ; Write to CNTV_CTL (Virtual Timer Control Register) + bx lr + +ArmReadCntvCt + mrrc p15, 1, r0, r1, c14 ; Read CNTVCT (Virtual Count Register) + bx lr + +ArmReadCntpCval + mrrc p15, 2, r0, r1, c14 ; Read CNTP_CTVAL (Physical Timer Compare Value Register) + bx lr + +ArmWriteCntpCval + mcrr p15, 2, r0, r1, c14 ; Write to CNTP_CTVAL (Physical Timer Compare Value Register) + bx lr + +ArmReadCntvCval + mrrc p15, 3, r0, r1, c14 ; Read CNTV_CTVAL (Virtual Timer Compare Value Register) + bx lr + +ArmWriteCntvCval + mcrr p15, 3, r0, r1, c14 ; write to CNTV_CTVAL (Virtual Timer Compare Value Register) + bx lr + +ArmReadCntvOff + mrrc p15, 4, r0, r1, c14 ; Read CNTVOFF (virtual Offset register) + bx lr + +ArmWriteCntvOff + mcrr p15, 4, r0, r1, c14 ; Write to CNTVOFF (Virtual Offset register) + bx lr + + END diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf index 2f0ade9b8e..2bc01a9949 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf @@ -35,6 +35,10 @@ ArmV7Lib.c ArmV7Mmu.c + ArmV7ArchTimer.c + ArmV7ArchTimerSupport.S | GCC + ArmV7ArchTimerSupport.asm | RVCT + [Packages] ArmPkg/ArmPkg.dec MdePkg/MdePkg.dec diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf index 6211549742..5fdb044974 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf @@ -34,6 +34,10 @@ ArmV7Lib.c ArmV7Mmu.c + + ArmV7ArchTimer.c + ArmV7ArchTimerSupport.S | GCC + ArmV7ArchTimerSupport.asm | RVCT [Packages] ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf index b7cb450462..9e6f17ec3e 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf @@ -31,6 +31,10 @@ ArmV7Support.asm | RVCT ArmV7Lib.c + + ArmV7ArchTimer.c + ArmV7ArchTimerSupport.S | GCC + ArmV7ArchTimerSupport.asm | RVCT [Packages] ArmPkg/ArmPkg.dec