summaryrefslogtreecommitdiff
path: root/BeagleBoardPkg/TimerDxe/Timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'BeagleBoardPkg/TimerDxe/Timer.c')
-rw-r--r--BeagleBoardPkg/TimerDxe/Timer.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/BeagleBoardPkg/TimerDxe/Timer.c b/BeagleBoardPkg/TimerDxe/Timer.c
new file mode 100644
index 0000000000..32ba09c1eb
--- /dev/null
+++ b/BeagleBoardPkg/TimerDxe/Timer.c
@@ -0,0 +1,239 @@
+/** @file
+ Template for Timer Architecture Protocol driver of the ARM flavor
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ 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 <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 <Library/OmapLib.h>
+
+#include <Protocol/Timer.h>
+#include <Protocol/HardwareInterrupt.h>
+#include <Protocol/TimerDebugSupport.h>
+
+#include <Omap3530/Omap3530.h>
+
+
+// The notification function to call on every timer interrupt.
+volatile EFI_TIMER_NOTIFY mTimerNotifyFunction = (EFI_TIMER_NOTIFY)NULL;
+volatile EFI_PERIODIC_CALLBACK mTimerPeriodicCallback = (EFI_PERIODIC_CALLBACK)NULL;
+
+
+// The current period of the timer interrupt
+volatile UINT64 mTimerPeriod = 0;
+
+// Cached copy of the Hardware Interrupt protocol instance
+EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL;
+
+// Cached registers
+volatile UINT32 TISR;
+volatile UINT32 TCLR;
+volatile UINT32 TLDR;
+volatile UINT32 TCRR;
+volatile UINT32 TIER;
+
+// Cached interrupt vector
+volatile UINTN gVector;
+
+VOID
+EFIAPI
+TimerInterruptHandler (
+ IN HARDWARE_INTERRUPT_SOURCE Source,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (mTimerPeriodicCallback) {
+ mTimerPeriodicCallback(SystemContext);
+ }
+
+ if (mTimerNotifyFunction) {
+ mTimerNotifyFunction(mTimerPeriod);
+ }
+
+ // Clear all timer interrupts
+ MmioWrite32(TISR, TISR_CLEAR_ALL);
+
+ // Poll interrupt status bits to ensure clearing
+ while ((MmioRead32(TISR) & TISR_ALL_INTERRUPT_MASK) != TISR_NO_INTERRUPTS_PENDING);
+}
+
+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;
+}
+
+EFI_STATUS
+EFIAPI
+TimerDriverSetTimerPeriod (
+ IN EFI_TIMER_ARCH_PROTOCOL *This,
+ IN UINT64 TimerPeriod
+ )
+{
+ EFI_STATUS Status;
+ UINT64 TimerCount;
+ INT32 LoadValue;
+
+ if (TimerPeriod == 0) {
+ // Turn off GPTIMER3
+ MmioWrite32(TCLR, TCLR_ST_OFF);
+
+ Status = gInterrupt->DisableInterruptSource(gInterrupt, gVector);
+ } else {
+ // Calculate required timer count
+ TimerCount = DivU64x32(TimerPeriod * 100, PcdGet32(PcdEmbeddedFdPerformanceCounterPeriodInNanoseconds));
+
+ // Set GPTIMER3 Load register
+ LoadValue = (INT32) -TimerCount;
+ MmioWrite32(TLDR, LoadValue);
+ MmioWrite32(TCRR, LoadValue);
+
+ // Enable Overflow interrupt
+ MmioWrite32(TIER, TIER_TCAR_IT_DISABLE | TIER_OVF_IT_ENABLE | TIER_MAT_IT_DISABLE);
+
+ // Turn on GPTIMER3, it will reload at overflow
+ MmioWrite32(TCLR, TCLR_AR_AUTORELOAD | TCLR_ST_ON);
+
+ Status = gInterrupt->EnableInterruptSource(gInterrupt, gVector);
+ }
+
+ //
+ // Save the new timer period
+ //
+ mTimerPeriod = TimerPeriod;
+ return Status;
+}
+
+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;
+}
+
+EFI_STATUS
+EFIAPI
+TimerDriverGenerateSoftInterrupt (
+ IN EFI_TIMER_ARCH_PROTOCOL *This
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+TimerDriverRegisterPeriodicCallback (
+ IN TIMER_DEBUG_SUPPORT_PROTOCOL *This,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ )
+{
+ if ((PeriodicCallback == NULL) && (mTimerPeriodicCallback == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((PeriodicCallback != NULL) && (mTimerPeriodicCallback != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mTimerPeriodicCallback = PeriodicCallback;
+
+ return EFI_SUCCESS;
+}
+
+EFI_TIMER_ARCH_PROTOCOL gTimer = {
+ TimerDriverRegisterHandler,
+ TimerDriverSetTimerPeriod,
+ TimerDriverGetTimerPeriod,
+ TimerDriverGenerateSoftInterrupt
+};
+
+TIMER_DEBUG_SUPPORT_PROTOCOL gTimerDebugSupport = {
+ TimerDriverRegisterPeriodicCallback
+};
+
+EFI_STATUS
+EFIAPI
+TimerInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HANDLE Handle = NULL;
+ EFI_STATUS Status;
+ UINT32 TimerBaseAddress;
+
+ // Find the interrupt controller protocol. ASSERT if not found.
+ Status = gBS->LocateProtocol(&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt);
+ ASSERT_EFI_ERROR (Status);
+
+ // Set up the timer registers
+ TimerBaseAddress = TimerBase(FixedPcdGet32(PcdBeagleArchTimer));
+ TISR = TimerBaseAddress + GPTIMER_TISR;
+ TCLR = TimerBaseAddress + GPTIMER_TCLR;
+ TLDR = TimerBaseAddress + GPTIMER_TLDR;
+ TCRR = TimerBaseAddress + GPTIMER_TCRR;
+ TIER = TimerBaseAddress + GPTIMER_TIER;
+
+ // Disable the timer
+ Status = TimerDriverSetTimerPeriod(&gTimer, 0);
+ ASSERT_EFI_ERROR (Status);
+
+ // Install interrupt handler
+ gVector = InterruptVectorForTimer(FixedPcdGet32(PcdBeagleArchTimer));
+ Status = gInterrupt->RegisterInterruptSource(gInterrupt, gVector, TimerInterruptHandler);
+ ASSERT_EFI_ERROR (Status);
+
+ // Set up default timer
+ Status = TimerDriverSetTimerPeriod(&gTimer, FixedPcdGet32(PcdTimerPeriod));
+ ASSERT_EFI_ERROR (Status);
+
+ // Install the Timer Architectural Protocol onto a new handle
+ Status = gBS->InstallMultipleProtocolInterfaces(&Handle,
+ &gEfiTimerArchProtocolGuid, &gTimer,
+ &gTimerDebugSupportProtocolGuid, &gTimerDebugSupport,
+ NULL);
+ ASSERT_EFI_ERROR(Status);
+
+ return Status;
+}
+