]> git.proxmox.com Git - mirror_edk2.git/blob - Omap35xxPkg/InterruptDxe/HardwareInterrupt.c
Omap35xxPkg: Replace BSD License with BSD+Patent License
[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 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9 #include <PiDxe.h>
10
11 #include <Library/BaseLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/UefiLib.h>
16 #include <Library/PcdLib.h>
17 #include <Library/IoLib.h>
18 #include <Library/ArmLib.h>
19
20 #include <Protocol/Cpu.h>
21 #include <Protocol/HardwareInterrupt.h>
22
23 #include <Omap3530/Omap3530.h>
24
25 //
26 // Notifications
27 //
28 EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
29
30
31 HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[INT_NROF_VECTORS];
32
33 /**
34 Shutdown our hardware
35
36 DXE Core will disable interrupts and turn off the timer and disable interrupts
37 after all the event handlers have run.
38
39 @param[in] Event The Event that is being processed
40 @param[in] Context Event Context
41 **/
42 VOID
43 EFIAPI
44 ExitBootServicesEvent (
45 IN EFI_EVENT Event,
46 IN VOID *Context
47 )
48 {
49 // Disable all interrupts
50 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
51 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
52 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
53 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
54
55 // Add code here to disable all FIQs as debugger may have turned one on
56 }
57
58 /**
59 Register Handler for the specified interrupt source.
60
61 @param This Instance pointer for this protocol
62 @param Source Hardware source of the interrupt
63 @param Handler Callback for interrupt. NULL to unregister
64
65 @retval EFI_SUCCESS Source was updated to support Handler.
66 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
67
68 **/
69 EFI_STATUS
70 EFIAPI
71 RegisterInterruptSource (
72 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
73 IN HARDWARE_INTERRUPT_SOURCE Source,
74 IN HARDWARE_INTERRUPT_HANDLER Handler
75 )
76 {
77 if (Source > MAX_VECTOR) {
78 ASSERT(FALSE);
79 return EFI_UNSUPPORTED;
80 }
81
82 if ((MmioRead32 (INTCPS_ILR(Source)) & INTCPS_ILR_FIQ) == INTCPS_ILR_FIQ) {
83 // This vector has been programmed as FIQ so we can't use it for IRQ
84 // EFI does not use FIQ, but the debugger can use it to check for
85 // ctrl-c. So this ASSERT means you have a conflict with the debug agent
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 ArmDataSynchronizationBarrier ();
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 ArmDataSynchronizationBarrier ();
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 ArmDataSynchronizationBarrier ();
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 STATIC VOID *mCpuArchProtocolNotifyEventRegistration;
294
295 STATIC
296 VOID
297 EFIAPI
298 CpuArchEventProtocolNotify (
299 IN EFI_EVENT Event,
300 IN VOID *Context
301 )
302 {
303 EFI_CPU_ARCH_PROTOCOL *Cpu;
304 EFI_STATUS Status;
305
306 //
307 // Get the CPU protocol that this driver requires.
308 //
309 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
310 if (EFI_ERROR (Status)) {
311 DEBUG ((DEBUG_ERROR, "%a: gBS->LocateProtocol() - %r\n", __FUNCTION__,
312 Status));
313 ASSERT (FALSE);
314 return;
315 }
316
317 //
318 // Unregister the default exception handler.
319 //
320 Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ, NULL);
321 if (EFI_ERROR (Status)) {
322 DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",
323 __FUNCTION__, Status));
324 ASSERT (FALSE);
325 return;
326 }
327
328 //
329 // Register to receive interrupts
330 //
331 Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ,
332 IrqInterruptHandler);
333 if (EFI_ERROR (Status)) {
334 DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",
335 __FUNCTION__, Status));
336 ASSERT (FALSE);
337 return;
338 }
339 }
340
341 /**
342 Initialize the state information for the CPU Architectural Protocol
343
344 @param ImageHandle of the loaded driver
345 @param SystemTable Pointer to the System Table
346
347 @retval EFI_SUCCESS Protocol registered
348 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
349 @retval EFI_DEVICE_ERROR Hardware problems
350
351 **/
352 EFI_STATUS
353 InterruptDxeInitialize (
354 IN EFI_HANDLE ImageHandle,
355 IN EFI_SYSTEM_TABLE *SystemTable
356 )
357 {
358 EFI_STATUS Status;
359 EFI_EVENT CpuArchEvent;
360
361 // Make sure the Interrupt Controller Protocol is not already installed in the system.
362 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
363
364 // Make sure all interrupts are disabled by default.
365 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
366 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
367 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
368 MmioOr32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
369
370 Status = gBS->InstallMultipleProtocolInterfaces(&gHardwareInterruptHandle,
371 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,
372 NULL);
373 ASSERT_EFI_ERROR(Status);
374
375 //
376 // Install the interrupt handler as soon as the CPU arch protocol appears.
377 //
378 CpuArchEvent = EfiCreateProtocolNotifyEvent (
379 &gEfiCpuArchProtocolGuid,
380 TPL_CALLBACK,
381 CpuArchEventProtocolNotify,
382 NULL,
383 &mCpuArchProtocolNotifyEventRegistration
384 );
385 ASSERT (CpuArchEvent != NULL);
386
387 // Register for an ExitBootServicesEvent
388 Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
389 if (EFI_ERROR (Status)) {
390 ASSERT_EFI_ERROR (Status);
391 gBS->CloseEvent (CpuArchEvent);
392 }
393
394 return Status;
395 }
396