From da9675a241ab9856377b9bd63504b2d5333b3c7a Mon Sep 17 00:00:00 2001 From: oliviermartin Date: Tue, 27 Sep 2011 16:35:16 +0000 Subject: 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/Library/ArmArchTimerLib/ArmArchTimerLib.c | 191 +++++++++++++++++++++ ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf | 46 +++++ 2 files changed, 237 insertions(+) create mode 100644 ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c create mode 100644 ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf (limited to 'ArmPkg/Library/ArmArchTimerLib') 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 -- cgit v1.2.3