]> git.proxmox.com Git - mirror_edk2.git/blame - ArmEbPkg/InterruptDxe/InterruptDxe.c
Update the copyright notice format
[mirror_edk2.git] / ArmEbPkg / InterruptDxe / InterruptDxe.c
CommitLineData
1fde2f61 1/*++\r
2\r
cf748a1a
HT
3Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>\r
4Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR> \r
5This program and the accompanying materials \r
1fde2f61 6are licensed and made available under the terms and conditions of the BSD License \r
7which accompanies this distribution. The full text of the license may be found at \r
8http://opensource.org/licenses/bsd-license.php \r
9 \r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
12\r
13Module Name:\r
14\r
15 Gic.c\r
16\r
17Abstract:\r
18\r
19 Driver implementing the GIC interrupt controller protocol\r
20\r
21--*/\r
22\r
23#include <PiDxe.h>\r
24\r
25#include <Library/BaseLib.h>\r
26#include <Library/DebugLib.h>\r
27#include <Library/BaseMemoryLib.h>\r
28#include <Library/UefiBootServicesTableLib.h>\r
29#include <Library/UefiLib.h>\r
30#include <Library/PcdLib.h>\r
31#include <Library/IoLib.h>\r
32\r
33#include <Protocol/Cpu.h>\r
34#include <Protocol/HardwareInterrupt.h>\r
35\r
36\r
37//\r
38// EB board definitions\r
39//\r
40#define EB_GIC1_CPU_INTF_BASE 0x10040000\r
41#define EB_GIC1_DIST_BASE 0x10041000\r
42#define EB_GIC2_CPU_INTF_BASE 0x10050000\r
43#define EB_GIC2_DIST_BASE 0x10051000\r
44#define EB_GIC3_CPU_INTF_BASE 0x10060000\r
45#define EB_GIC3_DIST_BASE 0x10061000\r
46#define EB_GIC4_CPU_INTF_BASE 0x10070000\r
47#define EB_GIC5_DIST_BASE 0x10071000\r
48\r
49// number of interrupts sources supported by each GIC on the EB\r
50#define EB_NUM_GIC_INTERRUPTS 96 \r
51\r
52// number of 32-bit registers needed to represent those interrupts as a bit\r
53// (used for enable set, enable clear, pending set, pending clear, and active regs)\r
54#define EB_NUM_GIC_REG_PER_INT_BITS (EB_NUM_GIC_INTERRUPTS / 32)\r
55\r
56// number of 32-bit registers needed to represent those interrupts as two bits\r
57// (used for configuration reg)\r
58#define EB_NUM_GIC_REG_PER_INT_CFG (EB_NUM_GIC_INTERRUPTS / 16)\r
59\r
60// number of 32-bit registers needed to represent interrupts as 8-bit priority field\r
61// (used for priority regs)\r
62#define EB_NUM_GIC_REG_PER_INT_BYTES (EB_NUM_GIC_INTERRUPTS / 4)\r
63\r
64#define GIC_DEFAULT_PRIORITY 0x80\r
65\r
66//\r
67// GIC definitions\r
68//\r
69\r
70// Distributor\r
71#define GIC_ICDDCR 0x000 // Distributor Control Register\r
72#define GIC_ICDICTR 0x004 // Interrupt Controller Type Register\r
73#define GIC_ICDIIDR 0x008 // Implementer Identification Register\r
74\r
75// each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BITS (see GIC spec)\r
76#define GIC_ICDISR 0x080 // Interrupt Security Registers\r
77#define GIC_ICDISER 0x100 // Interrupt Set-Enable Registers\r
78#define GIC_ICDICER 0x180 // Interrupt Clear-Enable Registers\r
79#define GIC_ICDSPR 0x200 // Interrupt Set-Pending Registers\r
80#define GIC_ICDCPR 0x280 // Interrupt Clear-Pending Registers\r
81#define GIC_ICDABR 0x300 // Active Bit Registers\r
82\r
83// each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BYTES\r
84#define GIC_ICDIPR 0x400 // Interrupt Priority Registers\r
85\r
86// each reg base below repeats for EB_NUM_GIC_INTERRUPTS\r
87#define GIC_ICDIPTR 0x800 // Interrupt Processor Target Registers\r
88#define GIC_ICDICFR 0xC00 // Interrupt Configuration Registers\r
89\r
90// just one of these\r
91#define GIC_ICDSGIR 0xF00 // Software Generated Interrupt Register\r
92\r
93\r
94// Cpu interface\r
95#define GIC_ICCICR 0x00 // CPU Interface Controler Register\r
96#define GIC_ICCPMR 0x04 // Interrupt Priority Mask Register\r
97#define GIC_ICCBPR 0x08 // Binary Point Register\r
98#define GIC_ICCIAR 0x0C // Interrupt Acknowledge Register\r
99#define GIC_ICCEIOR 0x10 // End Of Interrupt Register\r
100#define GIC_ICCRPR 0x14 // Running Priority Register\r
101#define GIC_ICCPIR 0x18 // Highest Pending Interrupt Register\r
102#define GIC_ICCABPR 0x1C // Aliased Binary Point Register\r
103#define GIC_ICCIDR 0xFC // Identification Register\r
104\r
105extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol;\r
106\r
107//\r
108// Notifications\r
109//\r
110VOID *CpuProtocolNotificationToken = NULL;\r
111EFI_EVENT CpuProtocolNotificationEvent = (EFI_EVENT)NULL;\r
112EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;\r
113\r
114\r
115HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[EB_NUM_GIC_INTERRUPTS];\r
116\r
117/**\r
118 Register Handler for the specified interrupt source.\r
119\r
120 @param This Instance pointer for this protocol\r
121 @param Source Hardware source of the interrupt\r
122 @param Handler Callback for interrupt. NULL to unregister\r
123\r
124 @retval EFI_SUCCESS Source was updated to support Handler.\r
125 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
126\r
127**/\r
128EFI_STATUS\r
129EFIAPI\r
130RegisterInterruptSource (\r
131 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
132 IN HARDWARE_INTERRUPT_SOURCE Source,\r
133 IN HARDWARE_INTERRUPT_HANDLER Handler\r
134 )\r
135{\r
136 if (Source > EB_NUM_GIC_INTERRUPTS) {\r
137 ASSERT(FALSE);\r
138 return EFI_UNSUPPORTED;\r
139 } \r
140 \r
141 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {\r
142 return EFI_INVALID_PARAMETER;\r
143 }\r
144\r
145 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {\r
146 return EFI_ALREADY_STARTED;\r
147 }\r
148\r
149 gRegisteredInterruptHandlers[Source] = Handler;\r
150 return This->EnableInterruptSource(This, Source);\r
151}\r
152\r
153\r
154/**\r
155 Enable interrupt source Source.\r
156\r
157 @param This Instance pointer for this protocol\r
158 @param Source Hardware source of the interrupt\r
159\r
160 @retval EFI_SUCCESS Source interrupt enabled.\r
161 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
162\r
163**/\r
164EFI_STATUS\r
165EFIAPI\r
166EnableInterruptSource (\r
167 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
168 IN HARDWARE_INTERRUPT_SOURCE Source\r
169 )\r
170{\r
171 UINT32 RegOffset;\r
172 UINTN RegShift;\r
173 \r
174 if (Source > EB_NUM_GIC_INTERRUPTS) {\r
175 ASSERT(FALSE);\r
176 return EFI_UNSUPPORTED;\r
177 }\r
178 \r
179 // calculate enable register offset and bit position\r
180 RegOffset = Source / 32;\r
181 RegShift = Source % 32;\r
182\r
183 // write set-enable register\r
184 MmioWrite32 (EB_GIC1_DIST_BASE+GIC_ICDISER+(4*RegOffset), 1 << RegShift);\r
185 \r
186 return EFI_SUCCESS;\r
187}\r
188\r
189\r
190/**\r
191 Disable interrupt source Source.\r
192\r
193 @param This Instance pointer for this protocol\r
194 @param Source Hardware source of the interrupt\r
195\r
196 @retval EFI_SUCCESS Source interrupt disabled.\r
197 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
198\r
199**/\r
200EFI_STATUS\r
201EFIAPI\r
202DisableInterruptSource (\r
203 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
204 IN HARDWARE_INTERRUPT_SOURCE Source\r
205 )\r
206{\r
207 UINT32 RegOffset;\r
208 UINTN RegShift;\r
209 \r
210 if (Source > EB_NUM_GIC_INTERRUPTS) {\r
211 ASSERT(FALSE);\r
212 return EFI_UNSUPPORTED;\r
213 }\r
214 \r
215 // calculate enable register offset and bit position\r
216 RegOffset = Source / 32;\r
217 RegShift = Source % 32;\r
218\r
219 // write set-enable register\r
220 MmioWrite32 (EB_GIC1_DIST_BASE+GIC_ICDICER+(4*RegOffset), 1 << RegShift);\r
221 \r
222 return EFI_SUCCESS;\r
223}\r
224\r
225\r
226\r
227/**\r
228 Return current state of interrupt source Source.\r
229\r
230 @param This Instance pointer for this protocol\r
231 @param Source Hardware source of the interrupt\r
232 @param InterruptState TRUE: source enabled, FALSE: source disabled.\r
233\r
234 @retval EFI_SUCCESS InterruptState is valid\r
235 @retval EFI_DEVICE_ERROR InterruptState is not valid\r
236\r
237**/\r
238EFI_STATUS\r
239EFIAPI\r
240GetInterruptSourceState (\r
241 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
242 IN HARDWARE_INTERRUPT_SOURCE Source,\r
243 IN BOOLEAN *InterruptState\r
244 )\r
245{\r
246 UINT32 RegOffset;\r
247 UINTN RegShift;\r
248 \r
249 if (Source > EB_NUM_GIC_INTERRUPTS) {\r
250 ASSERT(FALSE);\r
251 return EFI_UNSUPPORTED;\r
252 }\r
253 \r
254 // calculate enable register offset and bit position\r
255 RegOffset = Source / 32;\r
256 RegShift = Source % 32;\r
257 \r
258 if ((MmioRead32 (EB_GIC1_DIST_BASE+GIC_ICDISER+(4*RegOffset)) & (1<<RegShift)) == 0) {\r
259 *InterruptState = FALSE;\r
260 } else {\r
261 *InterruptState = TRUE;\r
262 }\r
263 \r
264 return EFI_SUCCESS;\r
265}\r
266\r
267/**\r
268 Signal to the hardware that the End Of Intrrupt state \r
269 has been reached.\r
270\r
271 @param This Instance pointer for this protocol\r
272 @param Source Hardware source of the interrupt\r
273\r
274 @retval EFI_SUCCESS Source interrupt EOI'ed.\r
275 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
276\r
277**/\r
278EFI_STATUS\r
279EFIAPI\r
280EndOfInterrupt (\r
281 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
282 IN HARDWARE_INTERRUPT_SOURCE Source\r
283 )\r
284{\r
285 if (Source > EB_NUM_GIC_INTERRUPTS) {\r
286 ASSERT(FALSE);\r
287 return EFI_UNSUPPORTED;\r
288 }\r
289\r
290 MmioWrite32 (EB_GIC1_CPU_INTF_BASE+GIC_ICCEIOR, Source);\r
291 return EFI_SUCCESS;\r
292}\r
293\r
294\r
295/**\r
296 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.\r
297\r
298 @param InterruptType Defines the type of interrupt or exception that\r
299 occurred on the processor.This parameter is processor architecture specific.\r
300 @param SystemContext A pointer to the processor context when\r
301 the interrupt occurred on the processor.\r
302\r
303 @return None\r
304\r
305**/\r
306VOID\r
307EFIAPI\r
308IrqInterruptHandler (\r
309 IN EFI_EXCEPTION_TYPE InterruptType,\r
310 IN EFI_SYSTEM_CONTEXT SystemContext\r
311 )\r
312{\r
313 UINT32 GicInterrupt;\r
314 HARDWARE_INTERRUPT_HANDLER InterruptHandler;\r
315\r
316 GicInterrupt = MmioRead32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCIAR);\r
317 if (GicInterrupt >= EB_NUM_GIC_INTERRUPTS) {\r
318 MmioWrite32 (EB_GIC1_CPU_INTF_BASE+GIC_ICCEIOR, GicInterrupt);\r
319 }\r
320 \r
321 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];\r
322 if (InterruptHandler != NULL) {\r
323 // Call the registered interrupt handler.\r
324 InterruptHandler (GicInterrupt, SystemContext);\r
325 } else {\r
326 DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: %x\n", GicInterrupt));\r
327 }\r
328\r
329 EndOfInterrupt (&gHardwareInterruptProtocol, GicInterrupt);\r
330}\r
331\r
332\r
333//\r
334// Making this global saves a few bytes in image size\r
335//\r
336EFI_HANDLE gHardwareInterruptHandle = NULL;\r
337\r
338//\r
339// The protocol instance produced by this driver\r
340//\r
341EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {\r
342 RegisterInterruptSource,\r
343 EnableInterruptSource,\r
344 DisableInterruptSource,\r
345 GetInterruptSourceState,\r
346 EndOfInterrupt\r
347};\r
348\r
349\r
350/**\r
351 Shutdown our hardware\r
352 \r
353 DXE Core will disable interrupts and turn off the timer and disable interrupts\r
354 after all the event handlers have run.\r
355\r
356 @param[in] Event The Event that is being processed\r
357 @param[in] Context Event Context\r
358**/\r
359VOID\r
360EFIAPI\r
361ExitBootServicesEvent (\r
362 IN EFI_EVENT Event,\r
363 IN VOID *Context\r
364 )\r
365{\r
366 UINTN i;\r
367 \r
368 for (i = 0; i < EB_NUM_GIC_INTERRUPTS; i++) {\r
369 DisableInterruptSource (&gHardwareInterruptProtocol, i);\r
370 }\r
371}\r
372\r
373\r
374//\r
375// Notification routines\r
376//\r
377VOID\r
378CpuProtocolInstalledNotification (\r
379 IN EFI_EVENT Event,\r
380 IN VOID *Context\r
381 )\r
382{\r
383 EFI_STATUS Status;\r
384 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
385 \r
386 //\r
387 // Get the cpu protocol that this driver requires.\r
388 //\r
389 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
390 ASSERT_EFI_ERROR(Status);\r
391\r
392 //\r
393 // Unregister the default exception handler.\r
394 //\r
395 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL);\r
396 ASSERT_EFI_ERROR(Status);\r
397\r
398 //\r
399 // Register to receive interrupts\r
400 //\r
401 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);\r
402 ASSERT_EFI_ERROR(Status);\r
403}\r
404\r
405/**\r
406 Initialize the state information for the CPU Architectural Protocol\r
407\r
408 @param ImageHandle of the loaded driver\r
409 @param SystemTable Pointer to the System Table\r
410\r
411 @retval EFI_SUCCESS Protocol registered\r
412 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
413 @retval EFI_DEVICE_ERROR Hardware problems\r
414\r
415**/\r
416EFI_STATUS\r
417InterruptDxeInitialize (\r
418 IN EFI_HANDLE ImageHandle,\r
419 IN EFI_SYSTEM_TABLE *SystemTable\r
420 )\r
421{\r
422 EFI_STATUS Status;\r
423 UINTN i;\r
424 UINT32 RegOffset;\r
425 UINTN RegShift;\r
426\r
427 \r
428 // Make sure the Interrupt Controller Protocol is not already installed in the system.\r
429 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
430\r
431 for (i = 0; i < EB_NUM_GIC_INTERRUPTS; i++) {\r
432 DisableInterruptSource (&gHardwareInterruptProtocol, i);\r
433 \r
434 // Set Priority \r
435 RegOffset = i / 4;\r
436 RegShift = (i % 4) * 8;\r
437 MmioAndThenOr32 (\r
438 EB_GIC1_DIST_BASE+GIC_ICDIPR+(4*RegOffset), \r
439 ~(0xff << RegShift), \r
440 GIC_DEFAULT_PRIORITY << RegShift\r
441 );\r
442 }\r
443\r
444 // configure interrupts for cpu 0\r
445 for (i = 0; i < EB_NUM_GIC_REG_PER_INT_BYTES; i++) {\r
446 MmioWrite32 (EB_GIC1_DIST_BASE + GIC_ICDIPTR + (i*4), 0x01010101);\r
447 }\r
448\r
449 // set binary point reg to 0x7 (no preemption)\r
450 MmioWrite32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCBPR, 0x7);\r
451\r
452 // set priority mask reg to 0xff to allow all priorities through\r
453 MmioWrite32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCPMR, 0xff);\r
454 \r
455 // enable gic cpu interface\r
456 MmioWrite32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCICR, 0x1);\r
457\r
458 // enable gic distributor\r
459 MmioWrite32 (EB_GIC1_DIST_BASE + GIC_ICCICR, 0x1);\r
460\r
461 \r
462 ZeroMem (&gRegisteredInterruptHandlers, sizeof (gRegisteredInterruptHandlers));\r
463 \r
464 Status = gBS->InstallMultipleProtocolInterfaces (\r
465 &gHardwareInterruptHandle,\r
466 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,\r
467 NULL\r
468 );\r
469 ASSERT_EFI_ERROR (Status);\r
470 \r
471 // Set up to be notified when the Cpu protocol is installed.\r
472 Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuProtocolInstalledNotification, NULL, &CpuProtocolNotificationEvent); \r
473 ASSERT_EFI_ERROR (Status);\r
474\r
475 Status = gBS->RegisterProtocolNotify (&gEfiCpuArchProtocolGuid, CpuProtocolNotificationEvent, (VOID *)&CpuProtocolNotificationToken);\r
476 ASSERT_EFI_ERROR (Status);\r
477\r
478 // Register for an ExitBootServicesEvent\r
479 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);\r
480 ASSERT_EFI_ERROR (Status);\r
481\r
482 return Status;\r
483}\r
484\r