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