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