]> git.proxmox.com Git - mirror_edk2.git/blob - BeagleBoardPkg/TimerDxe/Timer.c
32ba09c1eb3c15c7abada76716357e47aea7ffa1
[mirror_edk2.git] / BeagleBoardPkg / TimerDxe / Timer.c
1 /** @file
2 Template for Timer Architecture Protocol driver of the ARM flavor
3
4 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
5
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
10
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.
13
14 **/
15
16
17 #include <PiDxe.h>
18
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>
27
28 #include <Protocol/Timer.h>
29 #include <Protocol/HardwareInterrupt.h>
30 #include <Protocol/TimerDebugSupport.h>
31
32 #include <Omap3530/Omap3530.h>
33
34
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;
38
39
40 // The current period of the timer interrupt
41 volatile UINT64 mTimerPeriod = 0;
42
43 // Cached copy of the Hardware Interrupt protocol instance
44 EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL;
45
46 // Cached registers
47 volatile UINT32 TISR;
48 volatile UINT32 TCLR;
49 volatile UINT32 TLDR;
50 volatile UINT32 TCRR;
51 volatile UINT32 TIER;
52
53 // Cached interrupt vector
54 volatile UINTN gVector;
55
56 VOID
57 EFIAPI
58 TimerInterruptHandler (
59 IN HARDWARE_INTERRUPT_SOURCE Source,
60 IN EFI_SYSTEM_CONTEXT SystemContext
61 )
62 {
63 if (mTimerPeriodicCallback) {
64 mTimerPeriodicCallback(SystemContext);
65 }
66
67 if (mTimerNotifyFunction) {
68 mTimerNotifyFunction(mTimerPeriod);
69 }
70
71 // Clear all timer interrupts
72 MmioWrite32(TISR, TISR_CLEAR_ALL);
73
74 // Poll interrupt status bits to ensure clearing
75 while ((MmioRead32(TISR) & TISR_ALL_INTERRUPT_MASK) != TISR_NO_INTERRUPTS_PENDING);
76 }
77
78 EFI_STATUS
79 EFIAPI
80 TimerDriverRegisterHandler (
81 IN EFI_TIMER_ARCH_PROTOCOL *This,
82 IN EFI_TIMER_NOTIFY NotifyFunction
83 )
84 {
85 if ((NotifyFunction == NULL) && (mTimerNotifyFunction == NULL)) {
86 return EFI_INVALID_PARAMETER;
87 }
88
89 if ((NotifyFunction != NULL) && (mTimerNotifyFunction != NULL)) {
90 return EFI_ALREADY_STARTED;
91 }
92
93 mTimerNotifyFunction = NotifyFunction;
94
95 return EFI_SUCCESS;
96 }
97
98 EFI_STATUS
99 EFIAPI
100 TimerDriverSetTimerPeriod (
101 IN EFI_TIMER_ARCH_PROTOCOL *This,
102 IN UINT64 TimerPeriod
103 )
104 {
105 EFI_STATUS Status;
106 UINT64 TimerCount;
107 INT32 LoadValue;
108
109 if (TimerPeriod == 0) {
110 // Turn off GPTIMER3
111 MmioWrite32(TCLR, TCLR_ST_OFF);
112
113 Status = gInterrupt->DisableInterruptSource(gInterrupt, gVector);
114 } else {
115 // Calculate required timer count
116 TimerCount = DivU64x32(TimerPeriod * 100, PcdGet32(PcdEmbeddedFdPerformanceCounterPeriodInNanoseconds));
117
118 // Set GPTIMER3 Load register
119 LoadValue = (INT32) -TimerCount;
120 MmioWrite32(TLDR, LoadValue);
121 MmioWrite32(TCRR, LoadValue);
122
123 // Enable Overflow interrupt
124 MmioWrite32(TIER, TIER_TCAR_IT_DISABLE | TIER_OVF_IT_ENABLE | TIER_MAT_IT_DISABLE);
125
126 // Turn on GPTIMER3, it will reload at overflow
127 MmioWrite32(TCLR, TCLR_AR_AUTORELOAD | TCLR_ST_ON);
128
129 Status = gInterrupt->EnableInterruptSource(gInterrupt, gVector);
130 }
131
132 //
133 // Save the new timer period
134 //
135 mTimerPeriod = TimerPeriod;
136 return Status;
137 }
138
139 EFI_STATUS
140 EFIAPI
141 TimerDriverGetTimerPeriod (
142 IN EFI_TIMER_ARCH_PROTOCOL *This,
143 OUT UINT64 *TimerPeriod
144 )
145 {
146 if (TimerPeriod == NULL) {
147 return EFI_INVALID_PARAMETER;
148 }
149
150 *TimerPeriod = mTimerPeriod;
151 return EFI_SUCCESS;
152 }
153
154 EFI_STATUS
155 EFIAPI
156 TimerDriverGenerateSoftInterrupt (
157 IN EFI_TIMER_ARCH_PROTOCOL *This
158 )
159 {
160 return EFI_UNSUPPORTED;
161 }
162
163 EFI_STATUS
164 EFIAPI
165 TimerDriverRegisterPeriodicCallback (
166 IN TIMER_DEBUG_SUPPORT_PROTOCOL *This,
167 IN EFI_PERIODIC_CALLBACK PeriodicCallback
168 )
169 {
170 if ((PeriodicCallback == NULL) && (mTimerPeriodicCallback == NULL)) {
171 return EFI_INVALID_PARAMETER;
172 }
173
174 if ((PeriodicCallback != NULL) && (mTimerPeriodicCallback != NULL)) {
175 return EFI_ALREADY_STARTED;
176 }
177
178 mTimerPeriodicCallback = PeriodicCallback;
179
180 return EFI_SUCCESS;
181 }
182
183 EFI_TIMER_ARCH_PROTOCOL gTimer = {
184 TimerDriverRegisterHandler,
185 TimerDriverSetTimerPeriod,
186 TimerDriverGetTimerPeriod,
187 TimerDriverGenerateSoftInterrupt
188 };
189
190 TIMER_DEBUG_SUPPORT_PROTOCOL gTimerDebugSupport = {
191 TimerDriverRegisterPeriodicCallback
192 };
193
194 EFI_STATUS
195 EFIAPI
196 TimerInitialize (
197 IN EFI_HANDLE ImageHandle,
198 IN EFI_SYSTEM_TABLE *SystemTable
199 )
200 {
201 EFI_HANDLE Handle = NULL;
202 EFI_STATUS Status;
203 UINT32 TimerBaseAddress;
204
205 // Find the interrupt controller protocol. ASSERT if not found.
206 Status = gBS->LocateProtocol(&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt);
207 ASSERT_EFI_ERROR (Status);
208
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;
216
217 // Disable the timer
218 Status = TimerDriverSetTimerPeriod(&gTimer, 0);
219 ASSERT_EFI_ERROR (Status);
220
221 // Install interrupt handler
222 gVector = InterruptVectorForTimer(FixedPcdGet32(PcdBeagleArchTimer));
223 Status = gInterrupt->RegisterInterruptSource(gInterrupt, gVector, TimerInterruptHandler);
224 ASSERT_EFI_ERROR (Status);
225
226 // Set up default timer
227 Status = TimerDriverSetTimerPeriod(&gTimer, FixedPcdGet32(PcdTimerPeriod));
228 ASSERT_EFI_ERROR (Status);
229
230 // Install the Timer Architectural Protocol onto a new handle
231 Status = gBS->InstallMultipleProtocolInterfaces(&Handle,
232 &gEfiTimerArchProtocolGuid, &gTimer,
233 &gTimerDebugSupportProtocolGuid, &gTimerDebugSupport,
234 NULL);
235 ASSERT_EFI_ERROR(Status);
236
237 return Status;
238 }
239