]> 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 d1cd0c8e6e3c9c2de0a8e3fe5156dec91ab1dc83..b81293c5cfde0234a56abed42ece062d9dd6fab7 100644 (file)
@@ -1,7 +1,7 @@
 /** @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
 #include <Library/TimerLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/PcdLib.h>\r
-#include <Library/ArmArchTimerLib.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 () & ARM_PFR1_SEC) == 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