Use ACPI timer for Duet platform.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7264 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
klu2 2009-01-13 18:39:43 +00:00
parent 4e6a198ccc
commit 9be2c306aa
2 changed files with 138 additions and 60 deletions

View File

@ -42,11 +42,15 @@
[Packages] [Packages]
MdePkg/MdePkg.dec MdePkg/MdePkg.dec
DuetPkg/DuetPkg.dec
[LibraryClasses] [LibraryClasses]
BaseLib BaseLib
DebugLib DebugLib
UefiBootServicesTableLib HobLib
IoLib
[Guids]
gEfiAcpiDescriptionGuid
[Protocols]
gEfiMetronomeArchProtocolGuid # ALWAYS_CONSUMED

View File

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