]> git.proxmox.com Git - mirror_edk2.git/blobdiff - PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c
PcAtChipsetPkg: AcpiTimerLib: Added StandaloneMm instance of AcpiTimerLib
[mirror_edk2.git] / PcAtChipsetPkg / Library / AcpiTimerLib / AcpiTimerLib.c
index 19fdd76df6d34fec7cd5d73f9527c34becbcd35a..0a49093dbf267bef45806b349093ae014deac868 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
   ACPI Timer implements one instance of Timer Library.\r
 \r
-  Copyright (c) 2013 -2014, Intel Corporation. All rights reserved.<BR>\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
+  Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -21,6 +15,8 @@
 #include <Library/DebugLib.h>\r
 #include <IndustryStandard/Acpi.h>\r
 \r
+GUID mFrequencyHobGuid = { 0x3fca54f6, 0xe1a2, 0x4b20, { 0xbe, 0x76, 0x92, 0x6b, 0x4b, 0x48, 0xbf, 0xaa }};\r
+\r
 /**\r
   Internal function to retrieves the 64-bit frequency in Hz.\r
 \r
@@ -56,14 +52,14 @@ AcpiTimerLibConstructor (
   UINT8   EnableMask;\r
 \r
   //\r
-  // ASSERT for the invalid PCD values. They must be configured to the real value. \r
+  // ASSERT for the invalid PCD values. They must be configured to the real value.\r
   //\r
   ASSERT (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0xFFFF);\r
   ASSERT (PcdGet16 (PcdAcpiIoPortBaseAddress)      != 0xFFFF);\r
 \r
   //\r
-  // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then \r
-  // no PCI register programming is required to enable access to the the ACPI registers\r
+  // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then\r
+  // no PCI register programming is required to enable access to the ACPI registers\r
   // specified by PcdAcpiIoPortBaseAddress\r
   //\r
   if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) {\r
@@ -71,7 +67,7 @@ AcpiTimerLibConstructor (
   }\r
 \r
   //\r
-  // ASSERT for the invalid PCD values. They must be configured to the real value. \r
+  // ASSERT for the invalid PCD values. They must be configured to the real value.\r
   //\r
   ASSERT (PcdGet8  (PcdAcpiIoPciDeviceNumber)   != 0xFF);\r
   ASSERT (PcdGet8  (PcdAcpiIoPciFunctionNumber) != 0xFF);\r
@@ -89,7 +85,7 @@ AcpiTimerLibConstructor (
   //\r
   // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it.\r
   //\r
-  if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister) & EnableMask) != EnableMask)) {\r
+  if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister)) & EnableMask) != EnableMask) {\r
     PciWrite16 (\r
       PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)),\r
       PcdGet16 (PcdAcpiIoPortBaseAddress)\r
@@ -99,7 +95,7 @@ AcpiTimerLibConstructor (
       EnableMask\r
       );\r
   }\r
-  \r
+\r
   return RETURN_SUCCESS;\r
 }\r
 \r
@@ -117,24 +113,24 @@ InternalAcpiGetAcpiTimerIoPort (
   )\r
 {\r
   UINT16  Port;\r
-  \r
-  Port = PcdGet16 (PcdAcpiIoPciBarRegisterOffset);\r
-  \r
+\r
+  Port = PcdGet16 (PcdAcpiIoPortBaseAddress);\r
+\r
   //\r
-  // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then \r
-  // read the PCI register for the APCI BAR value in case the BAR has been programmed to a \r
+  // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then\r
+  // read the PCI register for the ACPI BAR value in case the BAR has been programmed to a\r
   // value other than PcdAcpiIoPortBaseAddress\r
   //\r
   if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0x0000) {\r
     Port = PciRead16 (PCI_LIB_ADDRESS (\r
-                        PcdGet8  (PcdAcpiIoPciBusNumber), \r
-                        PcdGet8  (PcdAcpiIoPciDeviceNumber), \r
-                        PcdGet8  (PcdAcpiIoPciFunctionNumber), \r
+                        PcdGet8  (PcdAcpiIoPciBusNumber),\r
+                        PcdGet8  (PcdAcpiIoPciDeviceNumber),\r
+                        PcdGet8  (PcdAcpiIoPciFunctionNumber),\r
                         PcdGet16 (PcdAcpiIoPciBarRegisterOffset)\r
                         ));\r
   }\r
-  \r
-  return (Port & ~BIT0) + PcdGet16 (PcdAcpiPm1TmrOffset);\r
+\r
+  return (Port & PcdGet16 (PcdAcpiIoPortBaseAddressMask)) + PcdGet16 (PcdAcpiPm1TmrOffset);\r
 }\r
 \r
 /**\r
@@ -162,14 +158,14 @@ InternalAcpiDelay (
     //\r
     // The target timer count is calculated here\r
     //\r
-    Ticks = IoRead32 (Port) + Delay;\r
+    Ticks = IoBitFieldRead32 (Port, 0, 23) + Delay;\r
     Delay = BIT22;\r
     //\r
     // Wait until time out\r
     // Delay >= 2^23 could not be handled by this function\r
     // Timer wrap-arounds are handled correctly by this function\r
     //\r
-    while (((Ticks - IoRead32 (Port)) & BIT23) == 0) {\r
+    while (((Ticks - IoBitFieldRead32 (Port, 0, 23)) & BIT23) == 0) {\r
       CpuPause ();\r
     }\r
   } while (Times-- > 0);\r
@@ -335,3 +331,63 @@ GetTimeInNanoSecond (
 \r
   return NanoSeconds;\r
 }\r
+\r
+/**\r
+  Calculate TSC frequency.\r
+\r
+  The TSC counting frequency is determined by comparing how far it counts\r
+  during a 101.4 us period as determined by the ACPI timer.\r
+  The ACPI timer is used because it counts at a known frequency.\r
+  The TSC is sampled, followed by waiting 363 counts of the ACPI timer,\r
+  or 101.4 us. The TSC is then sampled again. The difference multiplied by\r
+  9861 is the TSC frequency. There will be a small error because of the\r
+  overhead of reading the ACPI timer. An attempt is made to determine and\r
+  compensate for this error.\r
+\r
+  @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalCalculateTscFrequency (\r
+  VOID\r
+  )\r
+{\r
+  UINT64      StartTSC;\r
+  UINT64      EndTSC;\r
+  UINT16      TimerAddr;\r
+  UINT32      Ticks;\r
+  UINT64      TscFrequency;\r
+  BOOLEAN     InterruptState;\r
+\r
+  InterruptState = SaveAndDisableInterrupts ();\r
+\r
+  TimerAddr = InternalAcpiGetAcpiTimerIoPort ();\r
+  //\r
+  // Compute the number of ticks to wait to measure TSC frequency.\r
+  // Use 363 * 9861 = 3579543 Hz which is within 2 Hz of ACPI_TIMER_FREQUENCY.\r
+  // 363 counts is a calibration time of 101.4 uS.\r
+  //\r
+  Ticks = IoBitFieldRead32 (TimerAddr, 0, 23) + 363;\r
+\r
+  StartTSC = AsmReadTsc ();                                         // Get base value for the TSC\r
+  //\r
+  // Wait until the ACPI timer has counted 101.4 us.\r
+  // Timer wrap-arounds are handled correctly by this function.\r
+  // When the current ACPI timer value is greater than 'Ticks',\r
+  // the while loop will exit.\r
+  //\r
+  while (((Ticks - IoBitFieldRead32 (TimerAddr, 0, 23)) & BIT23) == 0) {\r
+    CpuPause();\r
+  }\r
+  EndTSC = AsmReadTsc ();                                           // TSC value 101.4 us later\r
+\r
+  TscFrequency = MultU64x32 (\r
+                   (EndTSC - StartTSC),                             // Number of TSC counts in 101.4 us\r
+                   9861                                             // Number of 101.4 us in a second\r
+                   );\r
+\r
+  SetInterruptState (InterruptState);\r
+\r
+  return TscFrequency;\r
+}\r
+\r