]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c
ArmPkg/PlatformBootManagerLib: move to BootLogoLib for boot splash support
[mirror_edk2.git] / ArmPkg / Library / ArmArchTimerLib / ArmArchTimerLib.c
index 970bde34cdcd9dfa55d312a043148d0515a890c8..b81293c5cfde0234a56abed42ece062d9dd6fab7 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   Generic ARM implementation of TimerLib.h\r
 \r
-  Copyright (c) 2011-2012, ARM Limited. All rights reserved.\r
-  \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
 \r
 \r
 #include <Base.h>\r
+#include <Library/ArmLib.h>\r
 #include <Library/BaseLib.h>\r
 #include <Library/TimerLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/PcdLib.h>\r
-#include <Library/ArmArchTimerLib.h>\r
-#include <Chipset/ArmV7.h>\r
+#include <Library/ArmGenericTimerCounterLib.h>\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 () & 0xF0) == 0x0) {\r
-      ArmArchTimerSetTimerFreq (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 = ArmArchTimerGetTimerFreq ();\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
@@ -82,17 +123,25 @@ MicroSecondDelay (
   UINT64 TimerTicks64;\r
   UINT64 SystemCounterVal;\r
 \r
-  // Calculate counter ticks that can represent requested delay\r
-  TimerTicks64 = MultU64x32 (MicroSeconds, TICKS_PER_MICRO_SEC);\r
+  // Calculate counter ticks that represent requested delay:\r
+  //  = MicroSeconds x TICKS_PER_MICRO_SEC\r
+  //  = MicroSeconds x Frequency.10^-6\r
+  TimerTicks64 = DivU64x32 (\r
+                   MultU64xN (\r
+                     MicroSeconds,\r
+                     GetPlatformTimerFreq ()\r
+                     ),\r
+                   1000000U\r
+                   );\r
 \r
   // Read System Counter value\r
-  SystemCounterVal = ArmArchTimerGetSystemCount ();\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 = ArmArchTimerGetSystemCount ();\r
+    SystemCounterVal = ArmGenericTimerGetSystemCount ();\r
   }\r
 \r
   return MicroSeconds;\r
@@ -147,7 +196,7 @@ GetPerformanceCounter (
   )\r
 {\r
   // Just return the value of system count\r
-  return ArmArchTimerGetSystemCount ();\r
+  return ArmGenericTimerGetSystemCount ();\r
 }\r
 \r
 /**\r
@@ -181,14 +230,63 @@ GetPerformanceCounterProperties (
   )\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)ArmArchTimerGetTimerFreq ();\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