mirror of https://github.com/acidanthera/audk.git
ArmPlatformPkg: remove unused SP804 driver and TimerLib implementation
None of the platforms we support use these so remove them. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
This commit is contained in:
parent
134f669b2a
commit
a8406340bd
|
@ -86,13 +86,6 @@
|
|||
# ARM Primecells
|
||||
#
|
||||
|
||||
## SP804 DualTimer
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerFrequencyInMHz|1|UINT32|0x0000001D
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerPeriodicInterruptNum|0|UINT32|0x0000001E
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerPeriodicBase|0|UINT32|0x0000002A
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerPerformanceBase|0|UINT32|0x0000002B
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerMetronomeBase|0|UINT32|0x0000002C
|
||||
|
||||
## SP805 Watchdog
|
||||
gArmPlatformTokenSpaceGuid.PcdSP805WatchdogBase|0x0|UINT32|0x00000023
|
||||
gArmPlatformTokenSpaceGuid.PcdSP805WatchdogClockFrequencyInHz|32000|UINT32|0x00000021
|
||||
|
|
|
@ -1,395 +0,0 @@
|
|||
/** @file
|
||||
Template for Timer Architecture Protocol driver of the ARM flavor
|
||||
|
||||
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
||||
Copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.<BR>
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
#include <PiDxe.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
|
||||
#include <Protocol/Timer.h>
|
||||
#include <Protocol/HardwareInterrupt.h>
|
||||
|
||||
#include <Drivers/SP804Timer.h>
|
||||
|
||||
#define SP804_TIMER_PERIODIC_BASE ((UINTN)PcdGet32 (PcdSP804TimerPeriodicBase))
|
||||
#define SP804_TIMER_METRONOME_BASE ((UINTN)PcdGet32 (PcdSP804TimerMetronomeBase))
|
||||
#define SP804_TIMER_PERFORMANCE_BASE ((UINTN)PcdGet32 (PcdSP804TimerPerformanceBase))
|
||||
|
||||
// The notification function to call on every timer interrupt.
|
||||
EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL;
|
||||
EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
|
||||
|
||||
// The current period of the timer interrupt
|
||||
UINT64 mTimerPeriod = 0;
|
||||
|
||||
// Cached copy of the Hardware Interrupt protocol instance
|
||||
EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL;
|
||||
|
||||
// Cached interrupt vector
|
||||
UINTN gVector;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
C Interrupt Handler called in the interrupt context when Source interrupt is active.
|
||||
|
||||
|
||||
@param Source Source of the interrupt. Hardware routing off a specific platform defines
|
||||
what source means.
|
||||
|
||||
@param SystemContext Pointer to system register context. Mostly used by debuggers and will
|
||||
update the system context after the return from the interrupt if
|
||||
modified. Don't change these values unless you know what you are doing
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
TimerInterruptHandler (
|
||||
IN HARDWARE_INTERRUPT_SOURCE Source,
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||
)
|
||||
{
|
||||
EFI_TPL OriginalTPL;
|
||||
|
||||
//
|
||||
// DXE core uses this callback for the EFI timer tick. The DXE core uses locks
|
||||
// that raise to TPL_HIGH and then restore back to current level. Thus we need
|
||||
// to make sure TPL level is set to TPL_HIGH while we are handling the timer tick.
|
||||
//
|
||||
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
||||
|
||||
// If the interrupt is shared then we must check if this interrupt source is the one associated to this Timer
|
||||
if (MmioRead32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_MSK_INT_STS_REG) != 0) {
|
||||
// Clear the periodic interrupt
|
||||
MmioWrite32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_INT_CLR_REG, 0);
|
||||
|
||||
// Signal end of interrupt early to help avoid losing subsequent ticks from long duration handlers
|
||||
gInterrupt->EndOfInterrupt (gInterrupt, Source);
|
||||
|
||||
if (mTimerNotifyFunction) {
|
||||
mTimerNotifyFunction (mTimerPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
gBS->RestoreTPL (OriginalTPL);
|
||||
}
|
||||
|
||||
/**
|
||||
This function registers the handler NotifyFunction so it is called every time
|
||||
the timer interrupt fires. It also passes the amount of time since the last
|
||||
handler call to the NotifyFunction. If NotifyFunction is NULL, then the
|
||||
handler is unregistered. If the handler is registered, then EFI_SUCCESS is
|
||||
returned. If the CPU does not support registering a timer interrupt handler,
|
||||
then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler
|
||||
when a handler is already registered, then EFI_ALREADY_STARTED is returned.
|
||||
If an attempt is made to unregister a handler when a handler is not registered,
|
||||
then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to
|
||||
register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR
|
||||
is returned.
|
||||
|
||||
@param This The EFI_TIMER_ARCH_PROTOCOL instance.
|
||||
@param NotifyFunction The function to call when a timer interrupt fires. This
|
||||
function executes at TPL_HIGH_LEVEL. The DXE Core will
|
||||
register a handler for the timer interrupt, so it can know
|
||||
how much time has passed. This information is used to
|
||||
signal timer based events. NULL will unregister the handler.
|
||||
@retval EFI_SUCCESS The timer handler was registered.
|
||||
@retval EFI_UNSUPPORTED The platform does not support timer interrupts.
|
||||
@retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already
|
||||
registered.
|
||||
@retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not
|
||||
previously registered.
|
||||
@retval EFI_DEVICE_ERROR The timer handler could not be registered.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
TimerDriverRegisterHandler (
|
||||
IN EFI_TIMER_ARCH_PROTOCOL *This,
|
||||
IN EFI_TIMER_NOTIFY NotifyFunction
|
||||
)
|
||||
{
|
||||
if ((NotifyFunction == NULL) && (mTimerNotifyFunction == NULL)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((NotifyFunction != NULL) && (mTimerNotifyFunction != NULL)) {
|
||||
return EFI_ALREADY_STARTED;
|
||||
}
|
||||
|
||||
mTimerNotifyFunction = NotifyFunction;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Make sure all Dual Timers are disabled
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
ExitBootServicesEvent (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
// Disable 'Periodic Operation' timer if enabled
|
||||
if (MmioRead32(SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
|
||||
MmioAnd32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, 0);
|
||||
}
|
||||
|
||||
// Disable 'Metronome/Delay' timer if enabled
|
||||
if (MmioRead32(SP804_TIMER_METRONOME_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
|
||||
MmioAnd32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CONTROL_REG, 0);
|
||||
}
|
||||
|
||||
// Disable 'Performance' timer if enabled
|
||||
if (MmioRead32(SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) {
|
||||
MmioAnd32 (SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CONTROL_REG, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
This function adjusts the period of timer interrupts to the value specified
|
||||
by TimerPeriod. If the timer period is updated, then the selected timer
|
||||
period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If
|
||||
the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
|
||||
If an error occurs while attempting to update the timer period, then the
|
||||
timer hardware will be put back in its state prior to this call, and
|
||||
EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt
|
||||
is disabled. This is not the same as disabling the CPU's interrupts.
|
||||
Instead, it must either turn off the timer hardware, or it must adjust the
|
||||
interrupt controller so that a CPU interrupt is not generated when the timer
|
||||
interrupt fires.
|
||||
|
||||
@param This The EFI_TIMER_ARCH_PROTOCOL instance.
|
||||
@param TimerPeriod The rate to program the timer interrupt in 100 nS units. If
|
||||
the timer hardware is not programmable, then EFI_UNSUPPORTED is
|
||||
returned. If the timer is programmable, then the timer period
|
||||
will be rounded up to the nearest timer period that is supported
|
||||
by the timer hardware. If TimerPeriod is set to 0, then the
|
||||
timer interrupts will be disabled.
|
||||
|
||||
|
||||
@retval EFI_SUCCESS The timer period was changed.
|
||||
@retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt.
|
||||
@retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
TimerDriverSetTimerPeriod (
|
||||
IN EFI_TIMER_ARCH_PROTOCOL *This,
|
||||
IN UINT64 TimerPeriod
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT64 TimerTicks;
|
||||
|
||||
// always disable the timer
|
||||
MmioAnd32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, ~SP804_TIMER_CTRL_ENABLE);
|
||||
|
||||
if (TimerPeriod == 0) {
|
||||
// Leave timer disabled from above, and...
|
||||
|
||||
// Disable timer 0/1 interrupt for a TimerPeriod of 0
|
||||
Status = gInterrupt->DisableInterruptSource (gInterrupt, gVector);
|
||||
} else {
|
||||
// Convert TimerPeriod into 1MHz clock counts (us units = 100ns units * 10)
|
||||
TimerTicks = DivU64x32 (TimerPeriod, 10);
|
||||
TimerTicks = MultU64x32 (TimerTicks, PcdGet32(PcdSP804TimerFrequencyInMHz));
|
||||
|
||||
// if it's larger than 32-bits, pin to highest value
|
||||
if (TimerTicks > 0xffffffff) {
|
||||
TimerTicks = 0xffffffff;
|
||||
}
|
||||
|
||||
// Program the SP804 timer with the new count value
|
||||
MmioWrite32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_LOAD_REG, TimerTicks);
|
||||
|
||||
// enable the timer
|
||||
MmioOr32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_ENABLE);
|
||||
|
||||
// enable timer 0/1 interrupts
|
||||
Status = gInterrupt->EnableInterruptSource (gInterrupt, gVector);
|
||||
}
|
||||
|
||||
// Save the new timer period
|
||||
mTimerPeriod = TimerPeriod;
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
This function retrieves the period of timer interrupts in 100 ns units,
|
||||
returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod
|
||||
is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is
|
||||
returned, then the timer is currently disabled.
|
||||
|
||||
@param This The EFI_TIMER_ARCH_PROTOCOL instance.
|
||||
@param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. If
|
||||
0 is returned, then the timer is currently disabled.
|
||||
|
||||
|
||||
@retval EFI_SUCCESS The timer period was returned in TimerPeriod.
|
||||
@retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
TimerDriverGetTimerPeriod (
|
||||
IN EFI_TIMER_ARCH_PROTOCOL *This,
|
||||
OUT UINT64 *TimerPeriod
|
||||
)
|
||||
{
|
||||
if (TimerPeriod == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*TimerPeriod = mTimerPeriod;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This function generates a soft timer interrupt. If the platform does not support soft
|
||||
timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
|
||||
If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler()
|
||||
service, then a soft timer interrupt will be generated. If the timer interrupt is
|
||||
enabled when this service is called, then the registered handler will be invoked. The
|
||||
registered handler should not be able to distinguish a hardware-generated timer
|
||||
interrupt from a software-generated timer interrupt.
|
||||
|
||||
@param This The EFI_TIMER_ARCH_PROTOCOL instance.
|
||||
|
||||
@retval EFI_SUCCESS The soft timer interrupt was generated.
|
||||
@retval EFI_UNSUPPORTED The platform does not support the generation of soft timer interrupts.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
TimerDriverGenerateSoftInterrupt (
|
||||
IN EFI_TIMER_ARCH_PROTOCOL *This
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
Interface structure for the Timer Architectural Protocol.
|
||||
|
||||
@par Protocol Description:
|
||||
This protocol provides the services to initialize a periodic timer
|
||||
interrupt, and to register a handler that is called each time the timer
|
||||
interrupt fires. It may also provide a service to adjust the rate of the
|
||||
periodic timer interrupt. When a timer interrupt occurs, the handler is
|
||||
passed the amount of time that has passed since the previous timer
|
||||
interrupt.
|
||||
|
||||
@param RegisterHandler
|
||||
Registers a handler that will be called each time the
|
||||
timer interrupt fires. TimerPeriod defines the minimum
|
||||
time between timer interrupts, so TimerPeriod will also
|
||||
be the minimum time between calls to the registered
|
||||
handler.
|
||||
|
||||
@param SetTimerPeriod
|
||||
Sets the period of the timer interrupt in 100 nS units.
|
||||
This function is optional, and may return EFI_UNSUPPORTED.
|
||||
If this function is supported, then the timer period will
|
||||
be rounded up to the nearest supported timer period.
|
||||
|
||||
|
||||
@param GetTimerPeriod
|
||||
Retrieves the period of the timer interrupt in 100 nS units.
|
||||
|
||||
@param GenerateSoftInterrupt
|
||||
Generates a soft timer interrupt that simulates the firing of
|
||||
the timer interrupt. This service can be used to invoke the registered handler if the timer interrupt has been masked for
|
||||
a period of time.
|
||||
|
||||
**/
|
||||
EFI_TIMER_ARCH_PROTOCOL gTimer = {
|
||||
TimerDriverRegisterHandler,
|
||||
TimerDriverSetTimerPeriod,
|
||||
TimerDriverGetTimerPeriod,
|
||||
TimerDriverGenerateSoftInterrupt
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Initialize the state information for the Timer Architectural Protocol and
|
||||
the Timer Debug support protocol that allows the debugger to break into a
|
||||
running program.
|
||||
|
||||
@param ImageHandle of the loaded driver
|
||||
@param SystemTable Pointer to the System Table
|
||||
|
||||
@retval EFI_SUCCESS Protocol registered
|
||||
@retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
|
||||
@retval EFI_DEVICE_ERROR Hardware problems
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
TimerInitialize (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_HANDLE Handle = NULL;
|
||||
EFI_STATUS Status;
|
||||
|
||||
// Set the interrupt timer number
|
||||
gVector = PcdGet32(PcdSP804TimerPeriodicInterruptNum);
|
||||
|
||||
// Find the interrupt controller protocol. ASSERT if not found.
|
||||
Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// Disable the timer
|
||||
Status = TimerDriverSetTimerPeriod (&gTimer, 0);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// Install interrupt handler
|
||||
Status = gInterrupt->RegisterInterruptSource (gInterrupt, gVector, TimerInterruptHandler);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// configure timer 0 for periodic operation, 32 bits, no prescaler, and interrupt enabled
|
||||
MmioWrite32 (SP804_TIMER_PERIODIC_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_PERIODIC | SP804_TIMER_CTRL_32BIT | SP804_PRESCALE_DIV_1 | SP804_TIMER_CTRL_INT_ENABLE);
|
||||
|
||||
// Set up default timer
|
||||
Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); // TIMER_DEFAULT_PERIOD
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// Install the Timer Architectural Protocol onto a new handle
|
||||
Status = gBS->InstallMultipleProtocolInterfaces(
|
||||
&Handle,
|
||||
&gEfiTimerArchProtocolGuid, &gTimer,
|
||||
NULL
|
||||
);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
|
||||
// Register for an ExitBootServicesEvent
|
||||
Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
#/** @file
|
||||
#
|
||||
# Component description file for Timer module
|
||||
#
|
||||
# Copyright (c) 2009 - 2010, Apple Inc. All rights reserved.<BR>
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
#**/
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = ArmVeTimerDxe
|
||||
FILE_GUID = a73d663d-a491-4278-9a69-9521be3379f2
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
|
||||
ENTRY_POINT = TimerInitialize
|
||||
|
||||
[Sources.common]
|
||||
SP804Timer.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
EmbeddedPkg/EmbeddedPkg.dec
|
||||
ArmPkg/ArmPkg.dec
|
||||
ArmPlatformPkg/ArmPlatformPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
UefiRuntimeServicesTableLib
|
||||
UefiLib
|
||||
UefiBootServicesTableLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
UefiDriverEntryPoint
|
||||
IoLib
|
||||
|
||||
[Guids]
|
||||
|
||||
[Protocols]
|
||||
gEfiTimerArchProtocolGuid
|
||||
gHardwareInterruptProtocolGuid
|
||||
|
||||
[Pcd.common]
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerFrequencyInMHz
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerPeriodicInterruptNum
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerPeriodicBase
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerPerformanceBase
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerMetronomeBase
|
||||
gEmbeddedTokenSpaceGuid.PcdTimerPeriod
|
||||
|
||||
[Depex]
|
||||
gHardwareInterruptProtocolGuid
|
|
@ -1,57 +0,0 @@
|
|||
/** @file
|
||||
*
|
||||
* Copyright (c) 2011, ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are licensed and made available under the terms and conditions of the BSD License
|
||||
* which accompanies this distribution. The full text of the license may be found at
|
||||
* http://opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
#ifndef _SP804_TIMER_H__
|
||||
#define _SP804_TIMER_H__
|
||||
|
||||
// SP804 Timer constants
|
||||
// Note: The SP804 Timer module comprises two timers, Timer_0 and Timer_1
|
||||
// These timers are identical and all their registers have an offset of 0x20
|
||||
// i.e. SP804_TIMER_0_LOAD_REG = 0x00 and SP804_TIMER_1_LOAD_REG = 0x20
|
||||
// Therefore, define all registers only once and adjust the base addresses by 0x20
|
||||
#define SP804_TIMER_LOAD_REG 0x00
|
||||
#define SP804_TIMER_CURRENT_REG 0x04
|
||||
#define SP804_TIMER_CONTROL_REG 0x08
|
||||
#define SP804_TIMER_INT_CLR_REG 0x0C
|
||||
#define SP804_TIMER_RAW_INT_STS_REG 0x10
|
||||
#define SP804_TIMER_MSK_INT_STS_REG 0x14
|
||||
#define SP804_TIMER_BG_LOAD_REG 0x18
|
||||
|
||||
// Timer control register bit definitions
|
||||
#define SP804_TIMER_CTRL_ONESHOT BIT0
|
||||
#define SP804_TIMER_CTRL_32BIT BIT1
|
||||
#define SP804_TIMER_CTRL_PRESCALE_MASK (BIT3|BIT2)
|
||||
#define SP804_PRESCALE_DIV_1 0
|
||||
#define SP804_PRESCALE_DIV_16 BIT2
|
||||
#define SP804_PRESCALE_DIV_256 BIT3
|
||||
#define SP804_TIMER_CTRL_INT_ENABLE BIT5
|
||||
#define SP804_TIMER_CTRL_PERIODIC BIT6
|
||||
#define SP804_TIMER_CTRL_ENABLE BIT7
|
||||
|
||||
// Other SP804 Timer definitions
|
||||
#define SP804_MAX_TICKS 0xFFFFFFFF
|
||||
|
||||
// SP810 System Controller constants
|
||||
#define SP810_SYS_CTRL_REG 0x00
|
||||
#define SP810_SYS_CTRL_TIMER0_TIMCLK BIT15 // 0=REFCLK, 1=TIMCLK
|
||||
#define SP810_SYS_CTRL_TIMER0_EN BIT16
|
||||
#define SP810_SYS_CTRL_TIMER1_TIMCLK BIT17 // 0=REFCLK, 1=TIMCLK
|
||||
#define SP810_SYS_CTRL_TIMER1_EN BIT18
|
||||
#define SP810_SYS_CTRL_TIMER2_TIMCLK BIT19 // 0=REFCLK, 1=TIMCLK
|
||||
#define SP810_SYS_CTRL_TIMER2_EN BIT20
|
||||
#define SP810_SYS_CTRL_TIMER3_TIMCLK BIT21 // 0=REFCLK, 1=TIMCLK
|
||||
#define SP810_SYS_CTRL_TIMER3_EN BIT22
|
||||
|
||||
#endif
|
|
@ -1,256 +0,0 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
|
||||
Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/TimerLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
#include <Drivers/SP804Timer.h>
|
||||
|
||||
#define SP804_TIMER_METRONOME_BASE ((UINTN)PcdGet32 (PcdSP804TimerMetronomeBase))
|
||||
#define SP804_TIMER_PERFORMANCE_BASE ((UINTN)PcdGet32 (PcdSP804TimerPerformanceBase))
|
||||
|
||||
// Setup SP810's Timer2 for managing delay functions. And Timer3 for Performance counter
|
||||
// Note: ArmVE's Timer0 and Timer1 are used by TimerDxe.
|
||||
RETURN_STATUS
|
||||
EFIAPI
|
||||
TimerConstructor (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// Check if the Metronome Timer is already initialized
|
||||
if ((MmioRead32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) == 0) {
|
||||
// Configure the Metronome Timer for free running operation, 32 bits, no prescaler, and interrupt disabled
|
||||
MmioWrite32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_32BIT | SP804_PRESCALE_DIV_1);
|
||||
|
||||
// Start the Metronome Timer ticking
|
||||
MmioOr32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_ENABLE);
|
||||
}
|
||||
|
||||
// Check if the Performance Timer is already initialized
|
||||
if ((MmioRead32 (SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CONTROL_REG) & SP804_TIMER_CTRL_ENABLE) == 0) {
|
||||
// Configure the Performance timer for free running operation, 32 bits, no prescaler, interrupt disabled
|
||||
MmioWrite32 (SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_32BIT | SP804_PRESCALE_DIV_1);
|
||||
|
||||
// Start the Performance Timer ticking
|
||||
MmioOr32 (SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CONTROL_REG, SP804_TIMER_CTRL_ENABLE);
|
||||
}
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Stalls the CPU for at least the given number of microseconds.
|
||||
|
||||
Stalls the CPU for the number of microseconds specified by MicroSeconds.
|
||||
The hardware timer is 32 bits.
|
||||
The maximum possible delay is (0xFFFFFFFF / TimerFrequencyMHz), i.e. ([32bits] / FreqInMHz)
|
||||
For example:
|
||||
+----------------+------------+----------+----------+
|
||||
| TimerFrequency | MaxDelay | MaxDelay | MaxDelay |
|
||||
| (MHz) | (us) | (s) | (min) |
|
||||
+----------------+------------+----------+----------+
|
||||
| 1 | 0xFFFFFFFF | 4294 | 71.5 |
|
||||
| 5 | 0x33333333 | 859 | 14.3 |
|
||||
| 10 | 0x19999999 | 429 | 7.2 |
|
||||
| 50 | 0x051EB851 | 86 | 1.4 |
|
||||
+----------------+------------+----------+----------+
|
||||
If it becomes necessary to support higher delays, then consider using the
|
||||
real time clock.
|
||||
|
||||
During this delay, the cpu is not yielded to any other process, with one exception:
|
||||
events that are triggered off a timer and which execute at a higher TPL than
|
||||
this function. These events may call MicroSecondDelay (or NanoSecondDelay) to
|
||||
fulfil their own needs.
|
||||
Therefore, this function must be re-entrant, as it may be interrupted and re-started.
|
||||
|
||||
@param MicroSeconds The minimum number of microseconds to delay.
|
||||
|
||||
@return The value of MicroSeconds inputted.
|
||||
|
||||
**/
|
||||
UINTN
|
||||
EFIAPI
|
||||
MicroSecondDelay (
|
||||
IN UINTN MicroSeconds
|
||||
)
|
||||
{
|
||||
UINT64 DelayTicks64; // Convert from microseconds to timer ticks, more bits to detect over-range conditions.
|
||||
UINTN DelayTicks; // Convert from microseconds to timer ticks, native size for general calculations.
|
||||
UINTN StartTicks; // Timer value snapshot at the start of the delay
|
||||
UINTN TargetTicks; // Timer value to signal the end of the delay
|
||||
UINTN CurrentTicks; // Current value of the 64-bit timer value at any given moment
|
||||
|
||||
// If we snapshot the timer at the start of the delay function then we minimise unaccounted overheads.
|
||||
StartTicks = MmioRead32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CURRENT_REG);
|
||||
|
||||
// We are operating at the limit of 32bits. For the range checking work in 64 bits to avoid overflows.
|
||||
DelayTicks64 = MultU64x32((UINT64)MicroSeconds, PcdGet32(PcdSP804TimerFrequencyInMHz));
|
||||
|
||||
// We are limited to 32 bits.
|
||||
// If the specified delay is exactly equal to the max range of the timer,
|
||||
// then the start will be equal to the stop plus one timer overflow (wrap-around).
|
||||
// To avoid having to check for that, reduce the maximum acceptable range by 1 tick,
|
||||
// i.e. reject delays equal or greater than the max range of the timer.
|
||||
if (DelayTicks64 >= (UINT64)SP804_MAX_TICKS) {
|
||||
DEBUG((EFI_D_ERROR,"MicroSecondDelay: ERROR: MicroSeconds=%d exceed SP804 count range. Max MicroSeconds=%d\n",
|
||||
MicroSeconds,
|
||||
((UINTN)SP804_MAX_TICKS/PcdGet32(PcdSP804TimerFrequencyInMHz))));
|
||||
}
|
||||
ASSERT(DelayTicks64 < (UINT64)SP804_MAX_TICKS);
|
||||
|
||||
// From now on do calculations only in native bit size.
|
||||
DelayTicks = (UINTN)DelayTicks64;
|
||||
|
||||
// Calculate the target value of the timer.
|
||||
|
||||
//Note: SP804 timer is counting down
|
||||
if (StartTicks >= DelayTicks) {
|
||||
// In this case we do not expect a wrap-around of the timer to occur.
|
||||
// CurrentTicks must be less than StartTicks and higher than TargetTicks.
|
||||
// If this is not the case, then the delay has been reached and may even have been exceeded if this
|
||||
// function was suspended by a higher priority interrupt.
|
||||
|
||||
TargetTicks = StartTicks - DelayTicks;
|
||||
|
||||
do {
|
||||
CurrentTicks = MmioRead32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CURRENT_REG);
|
||||
} while ((CurrentTicks > TargetTicks) && (CurrentTicks <= StartTicks));
|
||||
|
||||
} else {
|
||||
// In this case TargetTicks is larger than StartTicks.
|
||||
// This means we expect a wrap-around of the timer to occur and we must wait for it.
|
||||
// Before the wrap-around, CurrentTicks must be less than StartTicks and less than TargetTicks.
|
||||
// After the wrap-around, CurrentTicks must be larger than StartTicks and larger than TargetTicks.
|
||||
// If this is not the case, then the delay has been reached and may even have been exceeded if this
|
||||
// function was suspended by a higher priority interrupt.
|
||||
|
||||
// The order of operations is essential to avoid arithmetic overflow problems
|
||||
TargetTicks = ((UINTN)SP804_MAX_TICKS - DelayTicks) + StartTicks;
|
||||
|
||||
// First wait for the wrap-around to occur
|
||||
do {
|
||||
CurrentTicks = MmioRead32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CURRENT_REG);
|
||||
} while (CurrentTicks <= StartTicks);
|
||||
|
||||
// Then wait for the target
|
||||
do {
|
||||
CurrentTicks = MmioRead32 (SP804_TIMER_METRONOME_BASE + SP804_TIMER_CURRENT_REG);
|
||||
} while (CurrentTicks > TargetTicks);
|
||||
}
|
||||
|
||||
return MicroSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
Stalls the CPU for at least the given number of nanoseconds.
|
||||
|
||||
Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
|
||||
|
||||
When the timer frequency is 1MHz, each tick corresponds to 1 microsecond.
|
||||
Therefore, the nanosecond delay will be rounded up to the nearest 1 microsecond.
|
||||
|
||||
@param NanoSeconds The minimum number of nanoseconds to delay.
|
||||
|
||||
@return The value of NanoSeconds inputted.
|
||||
|
||||
**/
|
||||
UINTN
|
||||
EFIAPI
|
||||
NanoSecondDelay (
|
||||
IN UINTN NanoSeconds
|
||||
)
|
||||
{
|
||||
UINTN MicroSeconds;
|
||||
|
||||
// Round up to 1us Tick Number
|
||||
MicroSeconds = NanoSeconds / 1000;
|
||||
MicroSeconds += ((NanoSeconds % 1000) == 0) ? 0 : 1;
|
||||
|
||||
MicroSecondDelay (MicroSeconds);
|
||||
|
||||
return NanoSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieves the current value of a 64-bit free running performance counter.
|
||||
|
||||
The counter can either count up by 1 or count down by 1. If the physical
|
||||
performance counter counts by a larger increment, then the counter values
|
||||
must be translated. The properties of the counter can be retrieved from
|
||||
GetPerformanceCounterProperties().
|
||||
|
||||
@return The current value of the free running performance counter.
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
GetPerformanceCounter (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// Free running 64-bit/32-bit counter is needed here.
|
||||
// Don't think we need this to boot, just to do performance profile
|
||||
UINT64 Value;
|
||||
Value = MmioRead32 (SP804_TIMER_PERFORMANCE_BASE + SP804_TIMER_CURRENT_REG);
|
||||
return Value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Retrieves the 64-bit frequency in Hz and the range of performance counter
|
||||
values.
|
||||
|
||||
If StartValue is not NULL, then the value that the performance counter starts
|
||||
with immediately after is it rolls over is returned in StartValue. If
|
||||
EndValue is not NULL, then the value that the performance counter end with
|
||||
immediately before it rolls over is returned in EndValue. The 64-bit
|
||||
frequency of the performance counter in Hz is always returned. If StartValue
|
||||
is less than EndValue, then the performance counter counts up. If StartValue
|
||||
is greater than EndValue, then the performance counter counts down. For
|
||||
example, a 64-bit free running counter that counts up would have a StartValue
|
||||
of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
|
||||
that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
|
||||
|
||||
@param StartValue The value the performance counter starts with when it
|
||||
rolls over.
|
||||
@param EndValue The value that the performance counter ends with before
|
||||
it rolls over.
|
||||
|
||||
@return The frequency in Hz.
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
GetPerformanceCounterProperties (
|
||||
OUT UINT64 *StartValue, OPTIONAL
|
||||
OUT UINT64 *EndValue OPTIONAL
|
||||
)
|
||||
{
|
||||
if (StartValue != NULL) {
|
||||
// Timer starts with the reload value
|
||||
*StartValue = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
if (EndValue != NULL) {
|
||||
// Timer counts down to 0x0
|
||||
*EndValue = (UINT64)0ULL;
|
||||
}
|
||||
|
||||
return PcdGet64 (PcdEmbeddedPerformanceCounterFrequencyInHz);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
#/** @file
|
||||
# Timer library implementation
|
||||
#
|
||||
#
|
||||
# Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
#**/
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = SP804TimerLib
|
||||
FILE_GUID = 09cefa99-0d07-487f-a651-fb44f094b1c7
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = TimerLib
|
||||
|
||||
CONSTRUCTOR = TimerConstructor
|
||||
|
||||
[Sources.common]
|
||||
SP804TimerLib.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
ArmPkg/ArmPkg.dec
|
||||
ArmPlatformPkg/ArmPlatformPkg.dec
|
||||
EmbeddedPkg/EmbeddedPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
IoLib
|
||||
BaseLib
|
||||
|
||||
[Pcd]
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerFrequencyInMHz
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerPerformanceBase
|
||||
gArmPlatformTokenSpaceGuid.PcdSP804TimerMetronomeBase
|
||||
gEmbeddedTokenSpaceGuid.PcdEmbeddedPerformanceCounterFrequencyInHz
|
Loading…
Reference in New Issue