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