72135c24520ba25f56ba6b67c29f24ebf14b9a8a
[mirror_edk2.git] / Omap35xxPkg / InterruptDxe / HardwareInterrupt.c
1 /** @file
2 Handle OMAP35xx interrupt controller
3
4 Copyright (c) 2008-2010, 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 #include <PiDxe.h>
16
17 #include <Library/BaseLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiLib.h>
22 #include <Library/PcdLib.h>
23 #include <Library/IoLib.h>
24 #include <Library/ArmLib.h>
25
26 #include <Protocol/Cpu.h>
27 #include <Protocol/HardwareInterrupt.h>
28
29 #include <Omap3530/Omap3530.h>
30
31 //
32 // Notifications
33 //
34 VOID *CpuProtocolNotificationToken = NULL;
35 EFI_EVENT CpuProtocolNotificationEvent = (EFI_EVENT)NULL;
36 EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
37
38
39 HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[INT_NROF_VECTORS];
40
41 /**
42 Shutdown our hardware
43
44 DXE Core will disable interrupts and turn off the timer and disable interrupts
45 after all the event handlers have run.
46
47 @param[in] Event The Event that is being processed
48 @param[in] Context Event Context
49 **/
50 VOID
51 EFIAPI
52 ExitBootServicesEvent (
53 IN EFI_EVENT Event,
54 IN VOID *Context
55 )
56 {
57 // Disable all interrupts
58 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
59 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
60 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
61 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
62
63 // Add code here to disable all FIQs as debugger may have turned one on
64 }
65
66 /**
67 Register Handler for the specified interrupt source.
68
69 @param This Instance pointer for this protocol
70 @param Source Hardware source of the interrupt
71 @param Handler Callback for interrupt. NULL to unregister
72
73 @retval EFI_SUCCESS Source was updated to support Handler.
74 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
75
76 **/
77 EFI_STATUS
78 EFIAPI
79 RegisterInterruptSource (
80 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
81 IN HARDWARE_INTERRUPT_SOURCE Source,
82 IN HARDWARE_INTERRUPT_HANDLER Handler
83 )
84 {
85 if (Source > MAX_VECTOR) {
86 ASSERT(FALSE);
87 return EFI_UNSUPPORTED;
88 }
89
90 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
91 return EFI_INVALID_PARAMETER;
92 }
93
94 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
95 return EFI_ALREADY_STARTED;
96 }
97
98 gRegisteredInterruptHandlers[Source] = Handler;
99 return This->EnableInterruptSource(This, Source);
100 }
101
102
103 /**
104 Enable interrupt source Source.
105
106 @param This Instance pointer for this protocol
107 @param Source Hardware source of the interrupt
108
109 @retval EFI_SUCCESS Source interrupt enabled.
110 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
111
112 **/
113 EFI_STATUS
114 EFIAPI
115 EnableInterruptSource (
116 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
117 IN HARDWARE_INTERRUPT_SOURCE Source
118 )
119 {
120 UINTN Bank;
121 UINTN Bit;
122
123 if (Source > MAX_VECTOR) {
124 ASSERT(FALSE);
125 return EFI_UNSUPPORTED;
126 }
127
128 Bank = Source / 32;
129 Bit = 1UL << (Source % 32);
130
131 MmioWrite32 (INTCPS_MIR_CLEAR(Bank), Bit);
132
133 return EFI_SUCCESS;
134 }
135
136
137 /**
138 Disable interrupt source Source.
139
140 @param This Instance pointer for this protocol
141 @param Source Hardware source of the interrupt
142
143 @retval EFI_SUCCESS Source interrupt disabled.
144 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
145
146 **/
147 EFI_STATUS
148 EFIAPI
149 DisableInterruptSource (
150 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
151 IN HARDWARE_INTERRUPT_SOURCE Source
152 )
153 {
154 UINTN Bank;
155 UINTN Bit;
156
157 if (Source > MAX_VECTOR) {
158 ASSERT(FALSE);
159 return EFI_UNSUPPORTED;
160 }
161
162 Bank = Source / 32;
163 Bit = 1UL << (Source % 32);
164
165 MmioWrite32 (INTCPS_MIR_SET(Bank), Bit);
166
167 return EFI_SUCCESS;
168 }
169
170
171
172 /**
173 Return current state of interrupt source Source.
174
175 @param This Instance pointer for this protocol
176 @param Source Hardware source of the interrupt
177 @param InterruptState TRUE: source enabled, FALSE: source disabled.
178
179 @retval EFI_SUCCESS InterruptState is valid
180 @retval EFI_DEVICE_ERROR InterruptState is not valid
181
182 **/
183 EFI_STATUS
184 EFIAPI
185 GetInterruptSourceState (
186 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
187 IN HARDWARE_INTERRUPT_SOURCE Source,
188 IN BOOLEAN *InterruptState
189 )
190 {
191 UINTN Bank;
192 UINTN Bit;
193
194 if (InterruptState == NULL) {
195 return EFI_INVALID_PARAMETER;
196 }
197
198 if (Source > MAX_VECTOR) {
199 ASSERT(FALSE);
200 return EFI_UNSUPPORTED;
201 }
202
203 Bank = Source / 32;
204 Bit = 1UL << (Source % 32);
205
206 if ((MmioRead32 (INTCPS_MIR(Bank)) & Bit) == Bit) {
207 *InterruptState = FALSE;
208 } else {
209 *InterruptState = TRUE;
210 }
211
212 return EFI_SUCCESS;
213 }
214
215 /**
216 Signal to the hardware that the End Of Intrrupt state
217 has been reached.
218
219 @param This Instance pointer for this protocol
220 @param Source Hardware source of the interrupt
221
222 @retval EFI_SUCCESS Source interrupt EOI'ed.
223 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
224
225 **/
226 EFI_STATUS
227 EFIAPI
228 EndOfInterrupt (
229 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
230 IN HARDWARE_INTERRUPT_SOURCE Source
231 )
232 {
233 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
234 ArmDataSyncronizationBarrier ();
235 return EFI_SUCCESS;
236 }
237
238
239 /**
240 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
241
242 @param InterruptType Defines the type of interrupt or exception that
243 occurred on the processor.This parameter is processor architecture specific.
244 @param SystemContext A pointer to the processor context when
245 the interrupt occurred on the processor.
246
247 @return None
248
249 **/
250 VOID
251 EFIAPI
252 IrqInterruptHandler (
253 IN EFI_EXCEPTION_TYPE InterruptType,
254 IN EFI_SYSTEM_CONTEXT SystemContext
255 )
256 {
257 UINT32 Vector;
258 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
259
260 Vector = MmioRead32 (INTCPS_SIR_IRQ) & INTCPS_SIR_IRQ_MASK;
261
262 // Needed to prevent infinite nesting when Time Driver lowers TPL
263 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
264 ArmDataSyncronizationBarrier ();
265
266 InterruptHandler = gRegisteredInterruptHandlers[Vector];
267 if (InterruptHandler != NULL) {
268 // Call the registered interrupt handler.
269 InterruptHandler (Vector, SystemContext);
270 }
271
272 // Needed to clear after running the handler
273 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
274 ArmDataSyncronizationBarrier ();
275 }
276
277 //
278 // Making this global saves a few bytes in image size
279 //
280 EFI_HANDLE gHardwareInterruptHandle = NULL;
281
282 //
283 // The protocol instance produced by this driver
284 //
285 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {
286 RegisterInterruptSource,
287 EnableInterruptSource,
288 DisableInterruptSource,
289 GetInterruptSourceState,
290 EndOfInterrupt
291 };
292
293 //
294 // Notification routines
295 //
296 VOID
297 CpuProtocolInstalledNotification (
298 IN EFI_EVENT Event,
299 IN VOID *Context
300 )
301 {
302 EFI_STATUS Status;
303 EFI_CPU_ARCH_PROTOCOL *Cpu;
304
305 //
306 // Get the cpu protocol that this driver requires.
307 //
308 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
309 ASSERT_EFI_ERROR(Status);
310
311 //
312 // Unregister the default exception handler.
313 //
314 Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ, NULL);
315 ASSERT_EFI_ERROR(Status);
316
317 //
318 // Register to receive interrupts
319 //
320 Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);
321 ASSERT_EFI_ERROR(Status);
322 }
323
324 /**
325 Initialize the state information for the CPU Architectural Protocol
326
327 @param ImageHandle of the loaded driver
328 @param SystemTable Pointer to the System Table
329
330 @retval EFI_SUCCESS Protocol registered
331 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
332 @retval EFI_DEVICE_ERROR Hardware problems
333
334 **/
335 EFI_STATUS
336 InterruptDxeInitialize (
337 IN EFI_HANDLE ImageHandle,
338 IN EFI_SYSTEM_TABLE *SystemTable
339 )
340 {
341 EFI_STATUS Status;
342
343 // Make sure the Interrupt Controller Protocol is not already installed in the system.
344 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
345
346 // Make sure all interrupts are disabled by default.
347 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
348 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
349 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
350 MmioOr32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
351
352 Status = gBS->InstallMultipleProtocolInterfaces(&gHardwareInterruptHandle,
353 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,
354 NULL);
355 ASSERT_EFI_ERROR(Status);
356
357 // Set up to be notified when the Cpu protocol is installed.
358 Status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuProtocolInstalledNotification, NULL, &CpuProtocolNotificationEvent);
359 ASSERT_EFI_ERROR(Status);
360
361 Status = gBS->RegisterProtocolNotify(&gEfiCpuArchProtocolGuid, CpuProtocolNotificationEvent, (VOID *)&CpuProtocolNotificationToken);
362 ASSERT_EFI_ERROR(Status);
363
364 // Register for an ExitBootServicesEvent
365 Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
366 ASSERT_EFI_ERROR(Status);
367
368 return Status;
369 }
370