/** @file\r
- Timer Library functions built upon local APIC on IA32/x64.\r
+ Timer Library functions built upon ACPI on IA32/x64.\r
+ \r
+ ACPI power management timer is a 24-bit or 32-bit fixed rate free running count-up\r
+ timer that runs off a 3.579545 MHz clock. \r
+ When startup, Duet will check the FADT to determine whether the PM timer is a \r
+ 32-bit or 25-bit timer.\r
\r
Copyright (c) 2006 - 2007, Intel Corporation<BR>\r
All rights reserved. This program and the accompanying materials\r
#include <Library/TimerLib.h>\r
#include <Library/BaseLib.h>\r
#include <Library/DebugLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Guid/AcpiDescription.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
\r
-#include <Protocol/Metronome.h>\r
+EFI_ACPI_DESCRIPTION *gAcpiDesc = NULL;\r
\r
/**\r
-EFI_METRONOME_ARCH_PROTOCOL *gDuetMetronome = NULL;\r
-\r
-EFI_METRONOME_ARCH_PROTOCOL*\r
-GetMetronomeArchProtocol (\r
- VOID\r
- )\r
+ Internal function to get Acpi information from HOB.\r
+ \r
+ @return Pointer to ACPI description structure.\r
+**/\r
+EFI_ACPI_DESCRIPTION*\r
+InternalGetApciDescrptionTable (\r
+ VOID\r
+ )\r
{\r
- if (gDuetMetronome == NULL) {\r
- gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID**) &gDuetMetronome);\r
+ EFI_PEI_HOB_POINTERS GuidHob;\r
+ \r
+ if (gAcpiDesc != NULL) {\r
+ return gAcpiDesc;\r
}\r
\r
- return gDuetMetronome;\r
-} \r
+ GuidHob.Raw = GetFirstGuidHob (&gEfiAcpiDescriptionGuid);\r
+ if (GuidHob.Raw != NULL) {\r
+ gAcpiDesc = GET_GUID_HOB_DATA (GuidHob.Guid);\r
+ DEBUG ((EFI_D_INFO, "ACPI Timer: PM_TMR_BLK.RegisterBitWidth = 0x%X\n", gAcpiDesc->PM_TMR_BLK.RegisterBitWidth));\r
+ DEBUG ((EFI_D_INFO, "ACPI Timer: PM_TMR_BLK.Address = 0x%X\n", gAcpiDesc->PM_TMR_BLK.Address));\r
+ return gAcpiDesc;\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Fail to get Acpi description table from hob\n"));\r
+ return NULL;\r
+ }\r
+}\r
+\r
+/**\r
+ Internal function to read the current tick counter of ACPI.\r
+\r
+ @return The tick counter read.\r
+\r
**/\r
+STATIC\r
+UINT32\r
+InternalAcpiGetTimerTick (\r
+ VOID\r
+ )\r
+{\r
+ return IoRead32 ((UINTN)gAcpiDesc->PM_TMR_BLK.Address);\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
+STATIC\r
+VOID\r
+InternalAcpiDelay (\r
+ IN UINT32 Delay\r
+ )\r
+{\r
+ UINT32 Ticks;\r
+ UINT32 Times;\r
+\r
+ Times = Delay >> (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2);\r
+ Delay &= (1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2)) - 1;\r
+ do {\r
+ //\r
+ // The target timer count is calculated here\r
+ //\r
+ Ticks = InternalAcpiGetTimerTick () + Delay;\r
+ Delay = 1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2);\r
+ //\r
+ // Wait until time out\r
+ // Delay >= 2^23 (if ACPI provide 24-bit timer) or Delay >= 2^31 (if ACPI\r
+ // provide 32-bit timer) could not be handled by this function\r
+ // Timer wrap-arounds are handled correctly by this function\r
+ //\r
+ while (((Ticks - InternalAcpiGetTimerTick ()) & (1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 1))) == 0) {\r
+ CpuPause ();\r
+ }\r
+ } while (Times-- > 0);\r
+}\r
\r
/**\r
Stalls the CPU for at least the given number of microseconds.\r
IN UINTN MicroSeconds\r
)\r
{\r
- gBS->Stall (MicroSeconds);\r
-/**\r
- EFI_METRONOME_ARCH_PROTOCOL *mMetronome;\r
- UINT32 Counter;\r
- UINTN Remainder; \r
- \r
- if ((mMetronome = GetMetronomeArchProtocol()) == NULL) {\r
+\r
+ if (InternalGetApciDescrptionTable() == NULL) {\r
return MicroSeconds;\r
}\r
- \r
- //\r
- // Calculate the number of ticks by dividing the number of microseconds by\r
- // the TickPeriod.\r
- // Calculation is based on 100ns unit.\r
- //\r
- Counter = (UINT32) DivU64x32Remainder (\r
- MicroSeconds * 10,\r
- mMetronome->TickPeriod,\r
- &Remainder\r
- );\r
- //\r
- // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick\r
- // periods, thus attempting to ensure Microseconds of stall time.\r
- //\r
- if (Remainder != 0) {\r
- Counter++;\r
- }\r
-\r
- mMetronome->WaitForTick (mMetronome, Counter);\r
-**/\r
+ \r
+ InternalAcpiDelay (\r
+ (UINT32)DivU64x32 (\r
+ MultU64x32 (\r
+ MicroSeconds,\r
+ 3579545\r
+ ),\r
+ 1000000u\r
+ )\r
+ );\r
return MicroSeconds;\r
}\r
\r
IN UINTN NanoSeconds\r
)\r
{\r
- //\r
- // Duet platform need *not* this interface.\r
- //\r
- //ASSERT (FALSE);\r
- return 0;\r
+ if (InternalGetApciDescrptionTable() == NULL) {\r
+ return NanoSeconds;\r
+ }\r
+ \r
+ InternalAcpiDelay (\r
+ (UINT32)DivU64x32 (\r
+ MultU64x32 (\r
+ NanoSeconds,\r
+ 3579545\r
+ ),\r
+ 1000000000u\r
+ )\r
+ );\r
+ return NanoSeconds;\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- //\r
- // Duet platform need *not* this interface.\r
- //\r
- //ASSERT (FALSE);\r
- return 0;\r
+ if (InternalGetApciDescrptionTable() == NULL) {\r
+ return 0;\r
+ }\r
+ \r
+ return (UINT64)InternalAcpiGetTimerTick ();\r
}\r
\r
/**\r
OUT UINT64 *EndValue OPTIONAL\r
)\r
{\r
- //\r
- // Duet platform need *not* this interface.\r
- //\r
- //ASSERT (FALSE);\r
- return 0;\r
+ if (InternalGetApciDescrptionTable() == NULL) {\r
+ return 0;\r
+ }\r
+ \r
+ if (StartValue != NULL) {\r
+ *StartValue = 0;\r
+ }\r
+\r
+ if (EndValue != NULL) {\r
+ *EndValue = (1 << gAcpiDesc->PM_TMR_BLK.RegisterBitWidth) - 1;\r
+ }\r
+\r
+ return 3579545;\r
}\r