/** @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
#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
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
}\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
//\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
EnableMask\r
);\r
}\r
- \r
+\r
return RETURN_SUCCESS;\r
}\r
\r
)\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
//\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
\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