]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/PL390Gic/PL390GicDxe.c
ARM Packages: Fixed line endings
[mirror_edk2.git] / ArmPkg / Drivers / PL390Gic / PL390GicDxe.c
CommitLineData
1e57a462 1/*++\r
2\r
3Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>\r
4Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>\r
5Portions copyright (c) 2011-2012, ARM Ltd. All rights reserved.<BR> \r
6\r
7This program and the accompanying materials \r
8are licensed and made available under the terms and conditions of the BSD License \r
9which accompanies this distribution. The full text of the license may be found at \r
10http://opensource.org/licenses/bsd-license.php \r
11 \r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
14\r
15Module Name:\r
16\r
17 Gic.c\r
18\r
19Abstract:\r
20\r
21 Driver implementing the GIC interrupt controller protocol\r
22\r
23--*/\r
24\r
25#include <PiDxe.h>\r
26\r
27#include <Library/BaseLib.h>\r
28#include <Library/DebugLib.h>\r
29#include <Library/BaseMemoryLib.h>\r
30#include <Library/MemoryAllocationLib.h>\r
31#include <Library/UefiBootServicesTableLib.h>\r
32#include <Library/UefiLib.h>\r
33#include <Library/PcdLib.h>\r
34#include <Library/IoLib.h>\r
35#include <Library/ArmGicLib.h>\r
36\r
37#include <Protocol/Cpu.h>\r
38#include <Protocol/HardwareInterrupt.h>\r
39\r
40#define ARM_GIC_DEFAULT_PRIORITY 0x80\r
41\r
42extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol;\r
43\r
44//\r
45// Notifications\r
46//\r
47EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;\r
48\r
49// Maximum Number of Interrupts\r
50UINTN mGicNumInterrupts = 0;\r
51\r
52HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;\r
53\r
54/**\r
55 Register Handler for the specified interrupt source.\r
56\r
57 @param This Instance pointer for this protocol\r
58 @param Source Hardware source of the interrupt\r
59 @param Handler Callback for interrupt. NULL to unregister\r
60\r
61 @retval EFI_SUCCESS Source was updated to support Handler.\r
62 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
63\r
64**/\r
65EFI_STATUS\r
66EFIAPI\r
67RegisterInterruptSource (\r
68 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
69 IN HARDWARE_INTERRUPT_SOURCE Source,\r
70 IN HARDWARE_INTERRUPT_HANDLER Handler\r
71 )\r
72{\r
73 if (Source > mGicNumInterrupts) {\r
74 ASSERT(FALSE);\r
75 return EFI_UNSUPPORTED;\r
76 }\r
77 \r
78 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {\r
79 return EFI_INVALID_PARAMETER;\r
80 }\r
81\r
82 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {\r
83 return EFI_ALREADY_STARTED;\r
84 }\r
85\r
86 gRegisteredInterruptHandlers[Source] = Handler;\r
87\r
88 // If the interrupt handler is unregistered then disable the interrupt\r
89 if (NULL == Handler){\r
90 return This->DisableInterruptSource (This, Source);\r
91 } else {\r
92 return This->EnableInterruptSource (This, Source);\r
93 }\r
94}\r
95\r
96/**\r
97 Enable interrupt source Source.\r
98\r
99 @param This Instance pointer for this protocol\r
100 @param Source Hardware source of the interrupt\r
101\r
102 @retval EFI_SUCCESS Source interrupt enabled.\r
103 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
104\r
105**/\r
106EFI_STATUS\r
107EFIAPI\r
108EnableInterruptSource (\r
109 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
110 IN HARDWARE_INTERRUPT_SOURCE Source\r
111 )\r
112{\r
113 UINT32 RegOffset;\r
114 UINTN RegShift;\r
115 \r
116 if (Source > mGicNumInterrupts) {\r
117 ASSERT(FALSE);\r
118 return EFI_UNSUPPORTED;\r
119 }\r
120 \r
121 // Calculate enable register offset and bit position\r
122 RegOffset = Source / 32;\r
123 RegShift = Source % 32;\r
124\r
125 // Write set-enable register\r
126 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset), 1 << RegShift);\r
127 \r
128 return EFI_SUCCESS;\r
129}\r
130\r
131/**\r
132 Disable interrupt source Source.\r
133\r
134 @param This Instance pointer for this protocol\r
135 @param Source Hardware source of the interrupt\r
136\r
137 @retval EFI_SUCCESS Source interrupt disabled.\r
138 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
139\r
140**/\r
141EFI_STATUS\r
142EFIAPI\r
143DisableInterruptSource (\r
144 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
145 IN HARDWARE_INTERRUPT_SOURCE Source\r
146 )\r
147{\r
148 UINT32 RegOffset;\r
149 UINTN RegShift;\r
150 \r
151 if (Source > mGicNumInterrupts) {\r
152 ASSERT(FALSE);\r
153 return EFI_UNSUPPORTED;\r
154 }\r
155 \r
156 // Calculate enable register offset and bit position\r
157 RegOffset = Source / 32;\r
158 RegShift = Source % 32;\r
159\r
160 // Write set-enable register\r
161 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDICER + (4*RegOffset), 1 << RegShift);\r
162 \r
163 return EFI_SUCCESS;\r
164}\r
165\r
166/**\r
167 Return current state of interrupt source Source.\r
168\r
169 @param This Instance pointer for this protocol\r
170 @param Source Hardware source of the interrupt\r
171 @param InterruptState TRUE: source enabled, FALSE: source disabled.\r
172\r
173 @retval EFI_SUCCESS InterruptState is valid\r
174 @retval EFI_DEVICE_ERROR InterruptState is not valid\r
175\r
176**/\r
177EFI_STATUS\r
178EFIAPI\r
179GetInterruptSourceState (\r
180 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
181 IN HARDWARE_INTERRUPT_SOURCE Source,\r
182 IN BOOLEAN *InterruptState\r
183 )\r
184{\r
185 UINT32 RegOffset;\r
186 UINTN RegShift;\r
187 \r
188 if (Source > mGicNumInterrupts) {\r
189 ASSERT(FALSE);\r
190 return EFI_UNSUPPORTED;\r
191 }\r
192 \r
193 // calculate enable register offset and bit position\r
194 RegOffset = Source / 32;\r
195 RegShift = Source % 32;\r
196 \r
197 if ((MmioRead32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset)) & (1<<RegShift)) == 0) {\r
198 *InterruptState = FALSE;\r
199 } else {\r
200 *InterruptState = TRUE;\r
201 }\r
202 \r
203 return EFI_SUCCESS;\r
204}\r
205\r
206/**\r
207 Signal to the hardware that the End Of Intrrupt state \r
208 has been reached.\r
209\r
210 @param This Instance pointer for this protocol\r
211 @param Source Hardware source of the interrupt\r
212\r
213 @retval EFI_SUCCESS Source interrupt EOI'ed.\r
214 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
215\r
216**/\r
217EFI_STATUS\r
218EFIAPI\r
219EndOfInterrupt (\r
220 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
221 IN HARDWARE_INTERRUPT_SOURCE Source\r
222 )\r
223{\r
224 if (Source > mGicNumInterrupts) {\r
225 ASSERT(FALSE);\r
226 return EFI_UNSUPPORTED;\r
227 }\r
228\r
229 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCEIOR, Source);\r
230 return EFI_SUCCESS;\r
231}\r
232\r
233/**\r
234 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.\r
235\r
236 @param InterruptType Defines the type of interrupt or exception that\r
237 occurred on the processor.This parameter is processor architecture specific.\r
238 @param SystemContext A pointer to the processor context when\r
239 the interrupt occurred on the processor.\r
240\r
241 @return None\r
242\r
243**/\r
244VOID\r
245EFIAPI\r
246IrqInterruptHandler (\r
247 IN EFI_EXCEPTION_TYPE InterruptType,\r
248 IN EFI_SYSTEM_CONTEXT SystemContext\r
249 )\r
250{\r
251 UINT32 GicInterrupt;\r
252 HARDWARE_INTERRUPT_HANDLER InterruptHandler;\r
253\r
254 GicInterrupt = MmioRead32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCIAR);\r
255\r
256 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt).\r
257 if (GicInterrupt >= mGicNumInterrupts) {\r
258 // The special interrupt do not need to be acknowledge\r
259 return;\r
260 }\r
261 \r
262 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];\r
263 if (InterruptHandler != NULL) {\r
264 // Call the registered interrupt handler.\r
265 InterruptHandler (GicInterrupt, SystemContext);\r
266 } else {\r
267 DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));\r
268 }\r
269\r
270 EndOfInterrupt (&gHardwareInterruptProtocol, GicInterrupt);\r
271}\r
272\r
273//\r
274// Making this global saves a few bytes in image size\r
275//\r
276EFI_HANDLE gHardwareInterruptHandle = NULL;\r
277\r
278//\r
279// The protocol instance produced by this driver\r
280//\r
281EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {\r
282 RegisterInterruptSource,\r
283 EnableInterruptSource,\r
284 DisableInterruptSource,\r
285 GetInterruptSourceState,\r
286 EndOfInterrupt\r
287};\r
288\r
289/**\r
290 Shutdown our hardware\r
291 \r
292 DXE Core will disable interrupts and turn off the timer and disable interrupts\r
293 after all the event handlers have run.\r
294\r
295 @param[in] Event The Event that is being processed\r
296 @param[in] Context Event Context\r
297**/\r
298VOID\r
299EFIAPI\r
300ExitBootServicesEvent (\r
301 IN EFI_EVENT Event,\r
302 IN VOID *Context\r
303 )\r
304{\r
305 UINTN Index;\r
306 \r
307 // Acknowledge all pending interrupts\r
308 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
309 DisableInterruptSource (&gHardwareInterruptProtocol, Index);\r
310 }\r
311\r
312 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
313 EndOfInterrupt (&gHardwareInterruptProtocol, Index);\r
314 }\r
315\r
316 // Disable Gic Interface\r
317 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x0);\r
318 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0x0);\r
319\r
320 // Disable Gic Distributor\r
321 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x0);\r
322}\r
323\r
324/**\r
325 Initialize the state information for the CPU Architectural Protocol\r
326\r
327 @param ImageHandle of the loaded driver\r
328 @param SystemTable Pointer to the System Table\r
329\r
330 @retval EFI_SUCCESS Protocol registered\r
331 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
332 @retval EFI_DEVICE_ERROR Hardware problems\r
333\r
334**/\r
335EFI_STATUS\r
336InterruptDxeInitialize (\r
337 IN EFI_HANDLE ImageHandle,\r
338 IN EFI_SYSTEM_TABLE *SystemTable\r
339 )\r
340{\r
341 EFI_STATUS Status;\r
342 UINTN Index;\r
343 UINT32 RegOffset;\r
344 UINTN RegShift;\r
345 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
346 UINT32 CpuTarget;\r
347 \r
348 // Check PcdGicPrimaryCoreId has been set in case the Primary Core is not the core 0 of Cluster 0\r
349 DEBUG_CODE_BEGIN();\r
350 if ((PcdGet32(PcdArmPrimaryCore) != 0) && (PcdGet32 (PcdGicPrimaryCoreId) == 0)) {\r
351 DEBUG((EFI_D_WARN,"Warning: the PCD PcdGicPrimaryCoreId does not seem to be set up for the configuration.\n"));\r
352 }\r
353 DEBUG_CODE_END();\r
354\r
355 // Make sure the Interrupt Controller Protocol is not already installed in the system.\r
356 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
357\r
358 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase));\r
359\r
360 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
361 DisableInterruptSource (&gHardwareInterruptProtocol, Index);\r
362 \r
363 // Set Priority \r
364 RegOffset = Index / 4;\r
365 RegShift = (Index % 4) * 8;\r
366 MmioAndThenOr32 (\r
367 PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPR + (4*RegOffset),\r
368 ~(0xff << RegShift), \r
369 ARM_GIC_DEFAULT_PRIORITY << RegShift\r
370 );\r
371 }\r
372\r
373 // Configure interrupts for Primary Cpu\r
374 CpuTarget = (1 << PcdGet32 (PcdGicPrimaryCoreId));\r
375 CpuTarget |= (CpuTarget << 24) | (CpuTarget << 16) | (CpuTarget << 8);\r
376 for (Index = 0; Index < (mGicNumInterrupts / 4); Index++) {\r
377 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPTR + (Index*4), CpuTarget);\r
378 }\r
379\r
380 // Set binary point reg to 0x7 (no preemption)\r
381 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCBPR, 0x7);\r
382\r
383 // Set priority mask reg to 0xff to allow all priorities through\r
384 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0xff);\r
385 \r
386 // Enable gic cpu interface\r
387 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x1);\r
388\r
389 // Enable gic distributor\r
390 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x1);\r
391 \r
392 // Initialize the array for the Interrupt Handlers\r
393 gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);\r
394 \r
395 Status = gBS->InstallMultipleProtocolInterfaces (\r
396 &gHardwareInterruptHandle,\r
397 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,\r
398 NULL\r
399 );\r
400 ASSERT_EFI_ERROR (Status);\r
401 \r
402 //\r
403 // Get the CPU protocol that this driver requires.\r
404 //\r
405 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
406 ASSERT_EFI_ERROR(Status);\r
407\r
408 //\r
409 // Unregister the default exception handler.\r
410 //\r
411 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL);\r
412 ASSERT_EFI_ERROR(Status);\r
413\r
414 //\r
415 // Register to receive interrupts\r
416 //\r
417 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);\r
418 ASSERT_EFI_ERROR(Status);\r
419\r
420 // Register for an ExitBootServicesEvent\r
421 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);\r
422 ASSERT_EFI_ERROR (Status);\r
423\r
424 return Status;\r
425}\r