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