]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.c
When SOURCE_DEBUG_ENABLE is set, a TimerLib is linked into the SEC Phase to support...
[mirror_edk2.git] / OvmfPkg / Library / AcpiTimerLib / AcpiTimerLib.c
index 7f41a869d87e1778693e5642c5b972c754915aea..c6441281b4b6b750a976bade3e3336e4e3bddc76 100644 (file)
@@ -1,25 +1,64 @@
 /** @file\r
   ACPI Timer implements one instance of Timer Library.\r
 \r
-  Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>\r
+\r
   This program and the accompanying materials are\r
   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
+\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
 \r
-**/ \r
+**/\r
 \r
 #include <Base.h>\r
 #include <Library/TimerLib.h>\r
 #include <Library/BaseLib.h>\r
 #include <Library/IoLib.h>\r
 #include <Library/PciLib.h>\r
-\r
-#define ACPI_TIMER_FREQUENCY   3579545\r
-#define ACPI_TIMER_COUNT_SIZE  0x01000000\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <IndustryStandard/Pci22.h>\r
+#include <IndustryStandard/Acpi.h>\r
+\r
+//\r
+// PCI Location of PIIX4 Power Management PCI Configuration Registers\r
+//\r
+#define PIIX4_POWER_MANAGEMENT_BUS       0x00\r
+#define PIIX4_POWER_MANAGEMENT_DEVICE    0x01\r
+#define PIIX4_POWER_MANAGEMENT_FUNCTION  0x03\r
+\r
+//\r
+// Macro to access PIIX4 Power Management PCI Configuration Registers\r
+//\r
+#define PIIX4_PCI_POWER_MANAGEMENT_REGISTER(Register) \\r
+  PCI_LIB_ADDRESS (                                   \\r
+    PIIX4_POWER_MANAGEMENT_BUS,                       \\r
+    PIIX4_POWER_MANAGEMENT_DEVICE,                    \\r
+    PIIX4_POWER_MANAGEMENT_FUNCTION,                  \\r
+    Register                                          \\r
+    )\r
+\r
+//\r
+// PIIX4 Power Management PCI Configuration Registers\r
+//\r
+#define PMBA                PIIX4_PCI_POWER_MANAGEMENT_REGISTER (0x40)\r
+#define   PMBA_RTE          BIT0\r
+#define PMREGMISC           PIIX4_PCI_POWER_MANAGEMENT_REGISTER (0x80)\r
+#define   PMIOSE            BIT0\r
+\r
+//\r
+// The ACPI Time in the PIIX4 is a 24-bit counter\r
+//\r
+#define ACPI_TIMER_COUNT_SIZE  BIT24\r
+\r
+//\r
+// Offset in the PIIX4 Power Management Base Address to the ACPI Timer \r
+//\r
+#define ACPI_TIMER_OFFSET      0x8\r
 \r
 /**\r
   The constructor function enables ACPI IO space.\r
@@ -36,17 +75,23 @@ AcpiTimerLibConstructor (
   VOID\r
   )\r
 {\r
-  UINT8 Device;\r
-\r
-  Device = 1;\r
-  // Device = 7;\r
-\r
   //\r
-  // ACPI Timer enable is in Bus 0, Device ?, Function 3\r
+  // Check to see if the PIIX4 Power Management Base Address is already enabled\r
   //\r
-  PciOr8         (PCI_LIB_ADDRESS (0,Device,3,0x04), 0x01);\r
-  PciAndThenOr32 (PCI_LIB_ADDRESS (0,Device,3,0x40), (UINT32) ~0xfc0, 0x400);\r
-  PciOr8         (PCI_LIB_ADDRESS (0,Device,3,0x80), 0x01);  return RETURN_SUCCESS;\r
+  if ((PciRead8 (PMREGMISC) & PMIOSE) == 0) {\r
+    //\r
+    // If the PIIX4 Power Management Base Address is not programmed, \r
+    // then program the PIIX4 Power Management Base Address from a PCD.\r
+    //\r
+    PciAndThenOr32 (PMBA, (UINT32)(~0x0000FFC0), PcdGet16 (PcdAcpiPmBaseAddress));\r
+\r
+    //\r
+    // Enable PMBA I/O port decodes in PMREGMISC\r
+    //\r
+    PciOr8 (PMREGMISC, PMIOSE);\r
+  }\r
+  \r
+  return RETURN_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -57,13 +102,15 @@ AcpiTimerLibConstructor (
   @return The tick counter read.\r
 \r
 **/\r
-STATIC\r
 UINT32\r
 InternalAcpiGetTimerTick (\r
   VOID\r
   )\r
 {\r
-  return IoRead32 (0x408);\r
+  //\r
+  //   Read PMBA to read and return the current ACPI timer value.\r
+  //\r
+  return IoRead32 ((PciRead32 (PMBA) & ~PMBA_RTE) + ACPI_TIMER_OFFSET);\r
 }\r
 \r
 /**\r
@@ -75,7 +122,6 @@ InternalAcpiGetTimerTick (
   @param  Delay     A period of time to delay in ticks.\r
 \r
 **/\r
-STATIC\r
 VOID\r
 InternalAcpiDelay (\r
   IN      UINT32                    Delay\r
@@ -220,3 +266,39 @@ GetPerformanceCounterProperties (
 \r
   return ACPI_TIMER_FREQUENCY;\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
+\r
+  //\r
+  //          Ticks\r
+  // Time = --------- x 1,000,000,000\r
+  //        Frequency\r
+  //\r
+  NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, ACPI_TIMER_FREQUENCY, &Remainder), 1000000000u);\r
+\r
+  //\r
+  // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)\r
+  // will not overflow 64-bit.\r
+  //\r
+  NanoSeconds += DivU64x32 (MultU64x32 ((UINT64) Remainder, 1000000000u), ACPI_TIMER_FREQUENCY);\r
+\r
+  return NanoSeconds;\r
+}\r