2 Template for Timer Architecture Protocol driver of the ARM flavor
4 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/UefiLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/IoLib.h>
26 #include <Library/OmapLib.h>
28 #include <Protocol/Timer.h>
29 #include <Protocol/HardwareInterrupt.h>
30 #include <Protocol/TimerDebugSupport.h>
32 #include <Omap3530/Omap3530.h>
35 // The notification function to call on every timer interrupt.
36 volatile EFI_TIMER_NOTIFY mTimerNotifyFunction
= (EFI_TIMER_NOTIFY
)NULL
;
37 volatile EFI_PERIODIC_CALLBACK mTimerPeriodicCallback
= (EFI_PERIODIC_CALLBACK
)NULL
;
40 // The current period of the timer interrupt
41 volatile UINT64 mTimerPeriod
= 0;
43 // Cached copy of the Hardware Interrupt protocol instance
44 EFI_HARDWARE_INTERRUPT_PROTOCOL
*gInterrupt
= NULL
;
53 // Cached interrupt vector
54 volatile UINTN gVector
;
58 TimerInterruptHandler (
59 IN HARDWARE_INTERRUPT_SOURCE Source
,
60 IN EFI_SYSTEM_CONTEXT SystemContext
63 if (mTimerPeriodicCallback
) {
64 mTimerPeriodicCallback(SystemContext
);
67 if (mTimerNotifyFunction
) {
68 mTimerNotifyFunction(mTimerPeriod
);
71 // Clear all timer interrupts
72 MmioWrite32(TISR
, TISR_CLEAR_ALL
);
74 // Poll interrupt status bits to ensure clearing
75 while ((MmioRead32(TISR
) & TISR_ALL_INTERRUPT_MASK
) != TISR_NO_INTERRUPTS_PENDING
);
80 TimerDriverRegisterHandler (
81 IN EFI_TIMER_ARCH_PROTOCOL
*This
,
82 IN EFI_TIMER_NOTIFY NotifyFunction
85 if ((NotifyFunction
== NULL
) && (mTimerNotifyFunction
== NULL
)) {
86 return EFI_INVALID_PARAMETER
;
89 if ((NotifyFunction
!= NULL
) && (mTimerNotifyFunction
!= NULL
)) {
90 return EFI_ALREADY_STARTED
;
93 mTimerNotifyFunction
= NotifyFunction
;
100 TimerDriverSetTimerPeriod (
101 IN EFI_TIMER_ARCH_PROTOCOL
*This
,
102 IN UINT64 TimerPeriod
109 if (TimerPeriod
== 0) {
111 MmioWrite32(TCLR
, TCLR_ST_OFF
);
113 Status
= gInterrupt
->DisableInterruptSource(gInterrupt
, gVector
);
115 // Calculate required timer count
116 TimerCount
= DivU64x32(TimerPeriod
* 100, PcdGet32(PcdEmbeddedFdPerformanceCounterPeriodInNanoseconds
));
118 // Set GPTIMER3 Load register
119 LoadValue
= (INT32
) -TimerCount
;
120 MmioWrite32(TLDR
, LoadValue
);
121 MmioWrite32(TCRR
, LoadValue
);
123 // Enable Overflow interrupt
124 MmioWrite32(TIER
, TIER_TCAR_IT_DISABLE
| TIER_OVF_IT_ENABLE
| TIER_MAT_IT_DISABLE
);
126 // Turn on GPTIMER3, it will reload at overflow
127 MmioWrite32(TCLR
, TCLR_AR_AUTORELOAD
| TCLR_ST_ON
);
129 Status
= gInterrupt
->EnableInterruptSource(gInterrupt
, gVector
);
133 // Save the new timer period
135 mTimerPeriod
= TimerPeriod
;
141 TimerDriverGetTimerPeriod (
142 IN EFI_TIMER_ARCH_PROTOCOL
*This
,
143 OUT UINT64
*TimerPeriod
146 if (TimerPeriod
== NULL
) {
147 return EFI_INVALID_PARAMETER
;
150 *TimerPeriod
= mTimerPeriod
;
156 TimerDriverGenerateSoftInterrupt (
157 IN EFI_TIMER_ARCH_PROTOCOL
*This
160 return EFI_UNSUPPORTED
;
165 TimerDriverRegisterPeriodicCallback (
166 IN TIMER_DEBUG_SUPPORT_PROTOCOL
*This
,
167 IN EFI_PERIODIC_CALLBACK PeriodicCallback
170 if ((PeriodicCallback
== NULL
) && (mTimerPeriodicCallback
== NULL
)) {
171 return EFI_INVALID_PARAMETER
;
174 if ((PeriodicCallback
!= NULL
) && (mTimerPeriodicCallback
!= NULL
)) {
175 return EFI_ALREADY_STARTED
;
178 mTimerPeriodicCallback
= PeriodicCallback
;
183 EFI_TIMER_ARCH_PROTOCOL gTimer
= {
184 TimerDriverRegisterHandler
,
185 TimerDriverSetTimerPeriod
,
186 TimerDriverGetTimerPeriod
,
187 TimerDriverGenerateSoftInterrupt
190 TIMER_DEBUG_SUPPORT_PROTOCOL gTimerDebugSupport
= {
191 TimerDriverRegisterPeriodicCallback
197 IN EFI_HANDLE ImageHandle
,
198 IN EFI_SYSTEM_TABLE
*SystemTable
201 EFI_HANDLE Handle
= NULL
;
203 UINT32 TimerBaseAddress
;
205 // Find the interrupt controller protocol. ASSERT if not found.
206 Status
= gBS
->LocateProtocol(&gHardwareInterruptProtocolGuid
, NULL
, (VOID
**)&gInterrupt
);
207 ASSERT_EFI_ERROR (Status
);
209 // Set up the timer registers
210 TimerBaseAddress
= TimerBase(FixedPcdGet32(PcdBeagleArchTimer
));
211 TISR
= TimerBaseAddress
+ GPTIMER_TISR
;
212 TCLR
= TimerBaseAddress
+ GPTIMER_TCLR
;
213 TLDR
= TimerBaseAddress
+ GPTIMER_TLDR
;
214 TCRR
= TimerBaseAddress
+ GPTIMER_TCRR
;
215 TIER
= TimerBaseAddress
+ GPTIMER_TIER
;
218 Status
= TimerDriverSetTimerPeriod(&gTimer
, 0);
219 ASSERT_EFI_ERROR (Status
);
221 // Install interrupt handler
222 gVector
= InterruptVectorForTimer(FixedPcdGet32(PcdBeagleArchTimer
));
223 Status
= gInterrupt
->RegisterInterruptSource(gInterrupt
, gVector
, TimerInterruptHandler
);
224 ASSERT_EFI_ERROR (Status
);
226 // Set up default timer
227 Status
= TimerDriverSetTimerPeriod(&gTimer
, FixedPcdGet32(PcdTimerPeriod
));
228 ASSERT_EFI_ERROR (Status
);
230 // Install the Timer Architectural Protocol onto a new handle
231 Status
= gBS
->InstallMultipleProtocolInterfaces(&Handle
,
232 &gEfiTimerArchProtocolGuid
, &gTimer
,
233 &gTimerDebugSupportProtocolGuid
, &gTimerDebugSupport
,
235 ASSERT_EFI_ERROR(Status
);