/** @file\r
Generic ARM implementation of TimerLib.h\r
\r
- Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
+ Copyright (c) 2011-2016, ARM Limited. All rights reserved.\r
\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
\r
#define TICKS_PER_MICRO_SEC (PcdGet32 (PcdArmArchTimerFreqInHz)/1000000U)\r
\r
+// Select appropriate multiply function for platform architecture.\r
+#ifdef MDE_CPU_ARM\r
+#define MultU64xN MultU64x32\r
+#else\r
+#define MultU64xN MultU64x64\r
+#endif\r
+\r
+\r
RETURN_STATUS\r
EFIAPI\r
TimerConstructor (\r
VOID\r
)\r
{\r
- // Check if the ARM Generic Timer Extension is implemented\r
+ //\r
+ // Check if the ARM Generic Timer Extension is implemented.\r
+ //\r
if (ArmIsArchTimerImplemented ()) {\r
\r
- UINTN TimerFreq;\r
-\r
- // Check if Architectural Timer frequency is valid number (should not be 0)\r
- ASSERT (PcdGet32 (PcdArmArchTimerFreqInHz));\r
-\r
- // Check if ticks/uS is not 0. The Architectural timer runs at constant\r
- // frequency irrespective of CPU frequency. According to General Timer Ref\r
- // manual lower bound of the frequency is in the range of 1-10MHz\r
- ASSERT (TICKS_PER_MICRO_SEC);\r
+ //\r
+ // Check if Architectural Timer frequency is pre-determined by the platform\r
+ // (ie. nonzero).\r
+ //\r
+ if (PcdGet32 (PcdArmArchTimerFreqInHz) != 0) {\r
+ //\r
+ // Check if ticks/uS is not 0. The Architectural timer runs at constant\r
+ // frequency, irrespective of CPU frequency. According to Generic Timer\r
+ // Ref manual, lower bound of the frequency is in the range of 1-10MHz.\r
+ //\r
+ ASSERT (TICKS_PER_MICRO_SEC);\r
\r
#ifdef MDE_CPU_ARM\r
- // Only set the frequency for ARMv7. We expect the secure firmware to have already do it\r
- // If the security extensions are not implemented set Timer Frequency\r
- if ((ArmReadIdPfr1 () & ARM_PFR1_SEC) == 0x0) {\r
- ArmGenericTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz));\r
- }\r
+ //\r
+ // Only set the frequency for ARMv7. We expect the secure firmware to\r
+ // have already done it.\r
+ // If the security extension is not implemented, set Timer Frequency\r
+ // here.\r
+ //\r
+ if ((ArmReadIdPfr1 () & ARM_PFR1_SEC) == 0x0) {\r
+ ArmGenericTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz));\r
+ }\r
#endif\r
+ }\r
\r
- // Architectural Timer Frequency must be set in the Secure privileged(if secure extensions are supported) mode.\r
- // If the reset value (0) is returned just ASSERT.\r
- TimerFreq = ArmGenericTimerGetTimerFreq ();\r
- ASSERT (TimerFreq != 0);\r
+ //\r
+ // Architectural Timer Frequency must be set in Secure privileged\r
+ // mode (if secure extension is supported).\r
+ // If the reset value (0) is returned, just ASSERT.\r
+ //\r
+ ASSERT (ArmGenericTimerGetTimerFreq () != 0);\r
\r
} else {\r
- DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library can not be used.\n"));\r
+ DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library cannot be used.\n"));\r
ASSERT (0);\r
}\r
\r
return RETURN_SUCCESS;\r
}\r
\r
+/**\r
+ A local utility function that returns the PCD value, if specified.\r
+ Otherwise it defaults to ArmGenericTimerGetTimerFreq.\r
+\r
+ @return The timer frequency.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+EFIAPI\r
+GetPlatformTimerFreq (\r
+ )\r
+{\r
+ UINTN TimerFreq;\r
+\r
+ TimerFreq = PcdGet32 (PcdArmArchTimerFreqInHz);\r
+ if (TimerFreq == 0) {\r
+ TimerFreq = ArmGenericTimerGetTimerFreq ();\r
+ }\r
+ return TimerFreq;\r
+}\r
+\r
\r
/**\r
Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
\r
@param MicroSeconds The minimum number of microseconds to delay.\r
\r
- @return The value of MicroSeconds inputted.\r
+ @return The value of MicroSeconds input.\r
\r
**/\r
UINTN\r
UINT64 TimerTicks64;\r
UINT64 SystemCounterVal;\r
\r
- // Calculate counter ticks that can represent requested delay:\r
+ // Calculate counter ticks that represent requested delay:\r
// = MicroSeconds x TICKS_PER_MICRO_SEC\r
// = MicroSeconds x Frequency.10^-6\r
- TimerTicks64 = ((UINT64)MicroSeconds * PcdGet32 (PcdArmArchTimerFreqInHz)) / 1000000U;\r
+ TimerTicks64 = DivU64x32 (\r
+ MultU64xN (\r
+ MicroSeconds,\r
+ GetPlatformTimerFreq ()\r
+ ),\r
+ 1000000U\r
+ );\r
\r
// Read System Counter value\r
SystemCounterVal = ArmGenericTimerGetSystemCount ();\r
\r
TimerTicks64 += SystemCounterVal;\r
\r
- // Wait until delay count is expired.\r
+ // Wait until delay count expires.\r
while (SystemCounterVal < TimerTicks64) {\r
SystemCounterVal = ArmGenericTimerGetSystemCount ();\r
}\r
\r
@param NanoSeconds The minimum number of nanoseconds to delay.\r
\r
- @return The value of NanoSeconds inputed.\r
+ @return The value of NanoSeconds inputted.\r
\r
**/\r
UINTN\r
)\r
{\r
if (StartValue != NULL) {\r
- // Timer starts with the reload value\r
+ // Timer starts at 0\r
*StartValue = (UINT64)0ULL ;\r
}\r
\r
if (EndValue != NULL) {\r
- // Timer counts down to 0x0\r
+ // Timer counts up.\r
*EndValue = 0xFFFFFFFFFFFFFFFFUL;\r
}\r
\r
return (UINT64)ArmGenericTimerGetTimerFreq ();\r
}\r
+\r
+/**\r
+ Converts elapsed ticks of performance counter to time in nanoseconds.\r
+\r
+ This function converts the elapsed ticks of running performance counter to\r
+ time value in unit of nanoseconds.\r
+\r
+ @param Ticks The number of elapsed ticks of running performance counter.\r
+\r
+ @return The elapsed time in nanoseconds.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetTimeInNanoSecond (\r
+ IN UINT64 Ticks\r
+ )\r
+{\r
+ UINT64 NanoSeconds;\r
+ UINT32 Remainder;\r
+ UINT32 TimerFreq;\r
+\r
+ TimerFreq = GetPlatformTimerFreq ();\r
+ //\r
+ // Ticks\r
+ // Time = --------- x 1,000,000,000\r
+ // Frequency\r
+ //\r
+ NanoSeconds = MultU64xN (\r
+ DivU64x32Remainder (\r
+ Ticks,\r
+ TimerFreq,\r
+ &Remainder),\r
+ 1000000000U\r
+ );\r
+\r
+ //\r
+ // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)\r
+ // will not overflow 64-bit.\r
+ //\r
+ NanoSeconds += DivU64x32 (\r
+ MultU64xN (\r
+ (UINT64) Remainder,\r
+ 1000000000U),\r
+ TimerFreq\r
+ );\r
+\r
+ return NanoSeconds;\r
+}\r