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]
MdePkg/MdePkg.dec
DuetPkg/DuetPkg.dec
[LibraryClasses]
BaseLib
DebugLib
UefiBootServicesTableLib
[Protocols]
gEfiMetronomeArchProtocolGuid # ALWAYS_CONSUMED
HobLib
IoLib
[Guids]
gEfiAcpiDescriptionGuid

View File

@ -1,5 +1,10 @@
/** @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>
All rights reserved. This program and the accompanying materials
@ -16,25 +21,93 @@
#include <Library/TimerLib.h>
#include <Library/BaseLib.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;
EFI_METRONOME_ARCH_PROTOCOL*
GetMetronomeArchProtocol (
VOID
)
Internal function to get Acpi information from HOB.
@return Pointer to ACPI description structure.
**/
EFI_ACPI_DESCRIPTION*
InternalGetApciDescrptionTable (
VOID
)
{
if (gDuetMetronome == NULL) {
gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID**) &gDuetMetronome);
EFI_PEI_HOB_POINTERS GuidHob;
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.
@ -52,36 +125,20 @@ MicroSecondDelay (
IN UINTN MicroSeconds
)
{
gBS->Stall (MicroSeconds);
/**
EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
UINT32 Counter;
UINTN Remainder;
if ((mMetronome = GetMetronomeArchProtocol()) == NULL) {
if (InternalGetApciDescrptionTable() == NULL) {
return MicroSeconds;
}
//
// Calculate the number of ticks by dividing the number of microseconds by
// the TickPeriod.
// Calculation is based on 100ns unit.
//
Counter = (UINT32) DivU64x32Remainder (
MicroSeconds * 10,
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);
**/
InternalAcpiDelay (
(UINT32)DivU64x32 (
MultU64x32 (
MicroSeconds,
3579545
),
1000000u
)
);
return MicroSeconds;
}
@ -101,11 +158,20 @@ NanoSecondDelay (
IN UINTN NanoSeconds
)
{
//
// Duet platform need *not* this interface.
//
//ASSERT (FALSE);
return 0;
if (InternalGetApciDescrptionTable() == NULL) {
return NanoSeconds;
}
InternalAcpiDelay (
(UINT32)DivU64x32 (
MultU64x32 (
NanoSeconds,
3579545
),
1000000000u
)
);
return NanoSeconds;
}
/**
@ -126,11 +192,11 @@ GetPerformanceCounter (
VOID
)
{
//
// Duet platform need *not* this interface.
//
//ASSERT (FALSE);
return 0;
if (InternalGetApciDescrptionTable() == NULL) {
return 0;
}
return (UINT64)InternalAcpiGetTimerTick ();
}
/**
@ -163,9 +229,17 @@ GetPerformanceCounterProperties (
OUT UINT64 *EndValue OPTIONAL
)
{
//
// Duet platform need *not* this interface.
//
//ASSERT (FALSE);
return 0;
if (InternalGetApciDescrptionTable() == NULL) {
return 0;
}
if (StartValue != NULL) {
*StartValue = 0;
}
if (EndValue != NULL) {
*EndValue = (1 << gAcpiDesc->PM_TMR_BLK.RegisterBitWidth) - 1;
}
return 3579545;
}