--- /dev/null
+/** @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
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <IndustryStandard/Acpi.h>\r
+\r
+/**\r
+ Internal function to retrieves the 64-bit frequency in Hz.\r
+\r
+ Internal function to retrieves the 64-bit frequency in Hz.\r
+\r
+ @return The frequency in Hz.\r
+\r
+**/\r
+UINT64\r
+InternalGetPerformanceCounterFrequency (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ The constructor function enables ACPI IO space.\r
+\r
+ If ACPI I/O space not enabled, this function will enable it.\r
+ It will always return RETURN_SUCCESS.\r
+\r
+ @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+AcpiTimerLibConstructor (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Bus;\r
+ UINTN Device;\r
+ UINTN Function;\r
+ UINTN EnableRegister;\r
+ UINT8 EnableMask;\r
+\r
+ //\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
+ // specified by PcdAcpiIoPortBaseAddress\r
+ //\r
+ if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+\r
+ //\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
+ ASSERT (PcdGet16 (PcdAcpiIoPciEnableRegisterOffset) != 0xFFFF);\r
+\r
+ //\r
+ // Retrieve the PCD values for the PCI configuration space required to program the ACPI I/O Port Base Address\r
+ //\r
+ Bus = PcdGet8 (PcdAcpiIoPciBusNumber);\r
+ Device = PcdGet8 (PcdAcpiIoPciDeviceNumber);\r
+ Function = PcdGet8 (PcdAcpiIoPciFunctionNumber);\r
+ EnableRegister = PcdGet16 (PcdAcpiIoPciEnableRegisterOffset);\r
+ EnableMask = PcdGet8 (PcdAcpiIoBarEnableMask);\r
+\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
+ PciWrite16 (\r
+ PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)),\r
+ PcdGet16 (PcdAcpiIoPortBaseAddress)\r
+ );\r
+ PciOr8 (\r
+ PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister),\r
+ EnableMask\r
+ );\r
+ }\r
+ \r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Internal function to retrieve the ACPI I/O Port Base Address.\r
+\r
+ Internal function to retrieve the ACPI I/O Port Base Address.\r
+\r
+ @return The 16-bit ACPI I/O Port Base Address.\r
+\r
+**/\r
+UINT16\r
+InternalAcpiGetAcpiTimerIoPort (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 Port;\r
+ \r
+ Port = PcdGet16 (PcdAcpiIoPciBarRegisterOffset);\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
+ // 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
+ PcdGet16 (PcdAcpiIoPciBarRegisterOffset)\r
+ ));\r
+ }\r
+ \r
+ return (Port & ~BIT0) + PcdGet16 (PcdAcpiPm1TmrOffset);\r
+}\r
+\r
+/**\r
+ Stalls the CPU for at least the given number of ticks.\r
+\r
+ Stalls the CPU for at least the given number of ticks. It's invoked by\r
+ MicroSecondDelay() and NanoSecondDelay().\r
+\r
+ @param Delay A period of time to delay in ticks.\r
+\r
+**/\r
+VOID\r
+InternalAcpiDelay (\r
+ IN UINT32 Delay\r
+ )\r
+{\r
+ UINT16 Port;\r
+ UINT32 Ticks;\r
+ UINT32 Times;\r
+\r
+ Port = InternalAcpiGetAcpiTimerIoPort ();\r
+ Times = Delay >> 22;\r
+ Delay &= BIT22 - 1;\r
+ do {\r
+ //\r
+ // The target timer count is calculated here\r
+ //\r
+ Ticks = IoRead32 (Port) + 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
+ CpuPause ();\r
+ }\r
+ } while (Times-- > 0);\r
+}\r
+\r
+/**\r
+ Stalls the CPU for at least the given number of microseconds.\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 MicroSeconds\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+MicroSecondDelay (\r
+ IN UINTN MicroSeconds\r
+ )\r
+{\r
+ InternalAcpiDelay (\r
+ (UINT32)DivU64x32 (\r
+ MultU64x32 (\r
+ MicroSeconds,\r
+ ACPI_TIMER_FREQUENCY\r
+ ),\r
+ 1000000u\r
+ )\r
+ );\r
+ return MicroSeconds;\r
+}\r
+\r
+/**\r
+ Stalls the CPU for at least the given number of nanoseconds.\r
+\r
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
+\r
+ @param NanoSeconds The minimum number of nanoseconds to delay.\r
+\r
+ @return NanoSeconds\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+NanoSecondDelay (\r
+ IN UINTN NanoSeconds\r
+ )\r
+{\r
+ InternalAcpiDelay (\r
+ (UINT32)DivU64x32 (\r
+ MultU64x32 (\r
+ NanoSeconds,\r
+ ACPI_TIMER_FREQUENCY\r
+ ),\r
+ 1000000000u\r
+ )\r
+ );\r
+ return NanoSeconds;\r
+}\r
+\r
+/**\r
+ Retrieves the current value of a 64-bit free running performance counter.\r
+\r
+ Retrieves the current value of a 64-bit free running performance counter. The\r
+ counter can either count up by 1 or count down by 1. If the physical\r
+ performance counter counts by a larger increment, then the counter values\r
+ must be translated. The properties of the counter can be retrieved from\r
+ GetPerformanceCounterProperties().\r
+\r
+ @return The current value of the free running performance counter.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetPerformanceCounter (\r
+ VOID\r
+ )\r
+{\r
+ return AsmReadTsc ();\r
+}\r
+\r
+/**\r
+ Retrieves the 64-bit frequency in Hz and the range of performance counter\r
+ values.\r
+\r
+ If StartValue is not NULL, then the value that the performance counter starts\r
+ with immediately after is it rolls over is returned in StartValue. If\r
+ EndValue is not NULL, then the value that the performance counter end with\r
+ immediately before it rolls over is returned in EndValue. The 64-bit\r
+ frequency of the performance counter in Hz is always returned. If StartValue\r
+ is less than EndValue, then the performance counter counts up. If StartValue\r
+ is greater than EndValue, then the performance counter counts down. For\r
+ example, a 64-bit free running counter that counts up would have a StartValue\r
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter\r
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.\r
+\r
+ @param StartValue The value the performance counter starts with when it\r
+ rolls over.\r
+ @param EndValue The value that the performance counter ends with before\r
+ it rolls over.\r
+\r
+ @return The frequency in Hz.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetPerformanceCounterProperties (\r
+ OUT UINT64 *StartValue, OPTIONAL\r
+ OUT UINT64 *EndValue OPTIONAL\r
+ )\r
+{\r
+ if (StartValue != NULL) {\r
+ *StartValue = 0;\r
+ }\r
+\r
+ if (EndValue != NULL) {\r
+ *EndValue = 0xffffffffffffffffULL;\r
+ }\r
+ return InternalGetPerformanceCounterFrequency ();\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 Frequency;\r
+ UINT64 NanoSeconds;\r
+ UINT64 Remainder;\r
+ INTN Shift;\r
+\r
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);\r
+\r
+ //\r
+ // Ticks\r
+ // Time = --------- x 1,000,000,000\r
+ // Frequency\r
+ //\r
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);\r
+\r
+ //\r
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.\r
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,\r
+ // i.e. highest bit set in Remainder should <= 33.\r
+ //\r
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);\r
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);\r
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);\r
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);\r
+\r
+ return NanoSeconds;\r
+}\r
## This PCD specifies the base address of the HPET timer.\r
gPcAtChipsetPkgTokenSpaceGuid.PcdIoApicBaseAddress|0xFEC00000|UINT32|0x0000000C\r
\r
+[PcdsFixedAtBuild, PcdsPatchableInModule]\r
+ ## Defines the ACPI register set base address.\r
+ # The invalid 0xFFFF is as its default value. It must be configured to the real value. \r
+ # @Prompt ACPI Timer IO Port Address\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress |0xFFFF|UINT16|0x00000010\r
+\r
+ ## Defines the PCI Bus Number of the PCI device that contains the BAR and Enable for ACPI hardware registers.\r
+ # @Prompt ACPI Hardware PCI Bus Number\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber | 0x00| UINT8|0x00000011\r
+\r
+ ## Defines the PCI Device Number of the PCI device that contains the BAR and Enable for ACPI hardware registers.\r
+ # The invalid 0xFF is as its default value. It must be configured to the real value. \r
+ # @Prompt ACPI Hardware PCI Device Number\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber | 0xFF| UINT8|0x00000012\r
+\r
+ ## Defines the PCI Function Number of the PCI device that contains the BAR and Enable for ACPI hardware registers.\r
+ # The invalid 0xFF is as its default value. It must be configured to the real value. \r
+ # @Prompt ACPI Hardware PCI Function Number\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber | 0xFF| UINT8|0x00000013\r
+ \r
+ ## Defines the PCI Register Offset of the PCI device that contains the Enable for ACPI hardware registers.\r
+ # The invalid 0xFFFF is as its default value. It must be configured to the real value. \r
+ # @Prompt ACPI Hardware PCI Register Offset\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset |0xFFFF|UINT16|0x00000014\r
+ \r
+ ## Defines the bit mask that must be set to enable the APIC hardware register BAR.\r
+ # @Prompt ACPI Hardware PCI Bar Enable BitMask\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask | 0x00| UINT8|0x00000015\r
+ \r
+ ## Defines the PCI Register Offset of the PCI device that contains the BAR for ACPI hardware registers.\r
+ # The invalid 0xFFFF is as its default value. It must be configured to the real value. \r
+ # @Prompt ACPI Hardware PCI Bar Register Offset\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset |0xFFFF|UINT16|0x00000016\r
+\r
+ ## Defines the offset to the 32-bit Timer Value register that resides within the ACPI BAR.\r
+ # @Prompt Offset to 32-bit Timer register in ACPI BAR\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset |0x0008|UINT16|0x00000017\r