]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
ArmPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / GicV2 / ArmGicV2Dxe.c
CommitLineData
f5241b57
OM
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
b0393756 5Portions copyright (c) 2011-2017, ARM Ltd. All rights reserved.<BR>\r
f5241b57 6\r
4059386c 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
f5241b57
OM
8\r
9Module Name:\r
10\r
11 GicV2/ArmGicV2Dxe.c\r
12\r
13Abstract:\r
14\r
15 Driver implementing the GicV2 interrupt controller protocol\r
16\r
17--*/\r
18\r
bce29e30
AB
19#include <Library/ArmGicLib.h>\r
20\r
f5241b57 21#include "ArmGicDxe.h"\r
f5241b57
OM
22\r
23#define ARM_GIC_DEFAULT_PRIORITY 0x80\r
24\r
25extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;\r
8659306a 26extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol;\r
f5241b57 27\r
5f81082e
OM
28STATIC UINT32 mGicInterruptInterfaceBase;\r
29STATIC UINT32 mGicDistributorBase;\r
dc63be24 30\r
f5241b57
OM
31/**\r
32 Enable interrupt source Source.\r
33\r
34 @param This Instance pointer for this protocol\r
35 @param Source Hardware source of the interrupt\r
36\r
37 @retval EFI_SUCCESS Source interrupt enabled.\r
38 @retval EFI_UNSUPPORTED Source interrupt is not supported\r
39\r
40**/\r
b0393756 41STATIC\r
f5241b57
OM
42EFI_STATUS\r
43EFIAPI\r
44GicV2EnableInterruptSource (\r
45 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
46 IN HARDWARE_INTERRUPT_SOURCE Source\r
47 )\r
48{\r
599f004b 49 if (Source >= mGicNumInterrupts) {\r
f5241b57
OM
50 ASSERT(FALSE);\r
51 return EFI_UNSUPPORTED;\r
52 }\r
53\r
41fb5d46 54 ArmGicEnableInterrupt (mGicDistributorBase, 0, Source);\r
f5241b57
OM
55\r
56 return EFI_SUCCESS;\r
57}\r
58\r
59/**\r
60 Disable interrupt source Source.\r
61\r
62 @param This Instance pointer for this protocol\r
63 @param Source Hardware source of the interrupt\r
64\r
65 @retval EFI_SUCCESS Source interrupt disabled.\r
66 @retval EFI_UNSUPPORTED Source interrupt is not supported\r
67\r
68**/\r
b0393756 69STATIC\r
f5241b57
OM
70EFI_STATUS\r
71EFIAPI\r
72GicV2DisableInterruptSource (\r
73 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
74 IN HARDWARE_INTERRUPT_SOURCE Source\r
75 )\r
76{\r
599f004b 77 if (Source >= mGicNumInterrupts) {\r
f5241b57
OM
78 ASSERT(FALSE);\r
79 return EFI_UNSUPPORTED;\r
80 }\r
81\r
41fb5d46 82 ArmGicDisableInterrupt (mGicDistributorBase, 0, Source);\r
f5241b57
OM
83\r
84 return EFI_SUCCESS;\r
85}\r
86\r
87/**\r
88 Return current state of interrupt source Source.\r
89\r
90 @param This Instance pointer for this protocol\r
91 @param Source Hardware source of the interrupt\r
92 @param InterruptState TRUE: source enabled, FALSE: source disabled.\r
93\r
94 @retval EFI_SUCCESS InterruptState is valid\r
95 @retval EFI_UNSUPPORTED Source interrupt is not supported\r
96\r
97**/\r
b0393756 98STATIC\r
f5241b57
OM
99EFI_STATUS\r
100EFIAPI\r
101GicV2GetInterruptSourceState (\r
102 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
103 IN HARDWARE_INTERRUPT_SOURCE Source,\r
104 IN BOOLEAN *InterruptState\r
105 )\r
106{\r
599f004b 107 if (Source >= mGicNumInterrupts) {\r
f5241b57
OM
108 ASSERT(FALSE);\r
109 return EFI_UNSUPPORTED;\r
110 }\r
111\r
41fb5d46 112 *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, 0, Source);\r
f5241b57
OM
113\r
114 return EFI_SUCCESS;\r
115}\r
116\r
117/**\r
118 Signal to the hardware that the End Of Interrupt state\r
119 has been reached.\r
120\r
121 @param This Instance pointer for this protocol\r
122 @param Source Hardware source of the interrupt\r
123\r
124 @retval EFI_SUCCESS Source interrupt EOI'ed.\r
125 @retval EFI_UNSUPPORTED Source interrupt is not supported\r
126\r
127**/\r
b0393756 128STATIC\r
f5241b57
OM
129EFI_STATUS\r
130EFIAPI\r
131GicV2EndOfInterrupt (\r
132 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
133 IN HARDWARE_INTERRUPT_SOURCE Source\r
134 )\r
135{\r
599f004b 136 if (Source >= mGicNumInterrupts) {\r
f5241b57
OM
137 ASSERT(FALSE);\r
138 return EFI_UNSUPPORTED;\r
139 }\r
140\r
dc63be24 141 ArmGicV2EndOfInterrupt (mGicInterruptInterfaceBase, Source);\r
f5241b57
OM
142 return EFI_SUCCESS;\r
143}\r
144\r
145/**\r
146 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.\r
147\r
148 @param InterruptType Defines the type of interrupt or exception that\r
b0393756
EL
149 occurred on the processor.This parameter is\r
150 processor architecture specific.\r
f5241b57
OM
151 @param SystemContext A pointer to the processor context when\r
152 the interrupt occurred on the processor.\r
153\r
154 @return None\r
155\r
156**/\r
b0393756 157STATIC\r
f5241b57
OM
158VOID\r
159EFIAPI\r
160GicV2IrqInterruptHandler (\r
161 IN EFI_EXCEPTION_TYPE InterruptType,\r
162 IN EFI_SYSTEM_CONTEXT SystemContext\r
163 )\r
164{\r
165 UINT32 GicInterrupt;\r
166 HARDWARE_INTERRUPT_HANDLER InterruptHandler;\r
167\r
dc63be24 168 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);\r
f5241b57 169\r
b0393756
EL
170 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the\r
171 // number of interrupt (ie: Spurious interrupt).\r
f5241b57 172 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {\r
b0393756 173 // The special interrupts do not need to be acknowledged\r
f5241b57
OM
174 return;\r
175 }\r
176\r
177 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];\r
178 if (InterruptHandler != NULL) {\r
179 // Call the registered interrupt handler.\r
180 InterruptHandler (GicInterrupt, SystemContext);\r
181 } else {\r
b0393756 182 DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));\r
7989300d 183 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);\r
f5241b57 184 }\r
f5241b57
OM
185}\r
186\r
f5241b57 187// The protocol instance produced by this driver\r
f5241b57
OM
188EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {\r
189 RegisterInterruptSource,\r
190 GicV2EnableInterruptSource,\r
191 GicV2DisableInterruptSource,\r
192 GicV2GetInterruptSourceState,\r
193 GicV2EndOfInterrupt\r
194};\r
195\r
8659306a
AB
196/**\r
197 Get interrupt trigger type of an interrupt\r
198\r
199 @param This Instance pointer for this protocol\r
200 @param Source Hardware source of the interrupt.\r
201 @param TriggerType Returns interrupt trigger type.\r
202\r
203 @retval EFI_SUCCESS Source interrupt supported.\r
204 @retval EFI_UNSUPPORTED Source interrupt is not supported.\r
205**/\r
206STATIC\r
207EFI_STATUS\r
208EFIAPI\r
209GicV2GetTriggerType (\r
210 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,\r
211 IN HARDWARE_INTERRUPT_SOURCE Source,\r
212 OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType\r
213 )\r
214{\r
215 UINTN RegAddress;\r
216 UINTN Config1Bit;\r
217 EFI_STATUS Status;\r
218\r
219 Status = GicGetDistributorIcfgBaseAndBit (\r
220 Source,\r
221 &RegAddress,\r
222 &Config1Bit\r
223 );\r
224\r
225 if (EFI_ERROR (Status)) {\r
226 return Status;\r
227 }\r
228\r
229 if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {\r
230 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;\r
231 } else {\r
232 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;\r
233 }\r
234\r
235 return EFI_SUCCESS;\r
236}\r
237\r
238/**\r
239 Set interrupt trigger type of an interrupt\r
240\r
241 @param This Instance pointer for this protocol\r
242 @param Source Hardware source of the interrupt.\r
243 @param TriggerType Interrupt trigger type.\r
244\r
245 @retval EFI_SUCCESS Source interrupt supported.\r
246 @retval EFI_UNSUPPORTED Source interrupt is not supported.\r
247**/\r
248STATIC\r
249EFI_STATUS\r
250EFIAPI\r
251GicV2SetTriggerType (\r
252 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,\r
253 IN HARDWARE_INTERRUPT_SOURCE Source,\r
254 IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType\r
255 )\r
256{\r
257 UINTN RegAddress;\r
258 UINTN Config1Bit;\r
259 UINT32 Value;\r
260 EFI_STATUS Status;\r
261 BOOLEAN SourceEnabled;\r
262\r
263 if ( (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)\r
264 && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH)) {\r
265 DEBUG ((DEBUG_ERROR, "Invalid interrupt trigger type: %d\n", \\r
266 TriggerType));\r
267 ASSERT (FALSE);\r
268 return EFI_UNSUPPORTED;\r
269 }\r
270\r
271 Status = GicGetDistributorIcfgBaseAndBit (\r
272 Source,\r
273 &RegAddress,\r
274 &Config1Bit\r
275 );\r
276\r
277 if (EFI_ERROR (Status)) {\r
278 return Status;\r
279 }\r
280\r
281 Status = GicV2GetInterruptSourceState (\r
282 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,\r
283 Source,\r
284 &SourceEnabled\r
285 );\r
286\r
287 if (EFI_ERROR (Status)) {\r
288 return Status;\r
289 }\r
290\r
291 Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)\r
292 ? ARM_GIC_ICDICFR_EDGE_TRIGGERED\r
293 : ARM_GIC_ICDICFR_LEVEL_TRIGGERED;\r
294\r
295 // Before changing the value, we must disable the interrupt,\r
296 // otherwise GIC behavior is UNPREDICTABLE.\r
297 if (SourceEnabled) {\r
298 GicV2DisableInterruptSource (\r
299 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,\r
300 Source\r
301 );\r
302 }\r
303\r
304 MmioAndThenOr32 (\r
305 RegAddress,\r
306 ~(0x1 << Config1Bit),\r
307 Value << Config1Bit\r
308 );\r
309\r
310 // Restore interrupt state\r
311 if (SourceEnabled) {\r
312 GicV2EnableInterruptSource (\r
313 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,\r
314 Source\r
315 );\r
316 }\r
317\r
318 return EFI_SUCCESS;\r
319}\r
320\r
321EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol = {\r
322 (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,\r
323 (HARDWARE_INTERRUPT2_ENABLE)GicV2EnableInterruptSource,\r
324 (HARDWARE_INTERRUPT2_DISABLE)GicV2DisableInterruptSource,\r
325 (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV2GetInterruptSourceState,\r
326 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV2EndOfInterrupt,\r
327 GicV2GetTriggerType,\r
328 GicV2SetTriggerType\r
329};\r
330\r
f5241b57
OM
331/**\r
332 Shutdown our hardware\r
333\r
b0393756
EL
334 DXE Core will disable interrupts and turn off the timer and disable\r
335 interrupts after all the event handlers have run.\r
f5241b57
OM
336\r
337 @param[in] Event The Event that is being processed\r
338 @param[in] Context Event Context\r
339**/\r
b0393756 340STATIC\r
f5241b57
OM
341VOID\r
342EFIAPI\r
343GicV2ExitBootServicesEvent (\r
344 IN EFI_EVENT Event,\r
345 IN VOID *Context\r
346 )\r
347{\r
348 UINTN Index;\r
349 UINT32 GicInterrupt;\r
350\r
351 // Disable all the interrupts\r
352 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
353 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);\r
354 }\r
355\r
356 // Acknowledge all pending interrupts\r
357 do {\r
dc63be24 358 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);\r
f5241b57
OM
359\r
360 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) < mGicNumInterrupts) {\r
361 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);\r
362 }\r
363 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt));\r
364\r
365 // Disable Gic Interface\r
dc63be24 366 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase);\r
f5241b57
OM
367\r
368 // Disable Gic Distributor\r
dc63be24 369 ArmGicDisableDistributor (mGicDistributorBase);\r
f5241b57
OM
370}\r
371\r
372/**\r
373 Initialize the state information for the CPU Architectural Protocol\r
374\r
375 @param ImageHandle of the loaded driver\r
376 @param SystemTable Pointer to the System Table\r
377\r
378 @retval EFI_SUCCESS Protocol registered\r
379 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
380 @retval EFI_DEVICE_ERROR Hardware problems\r
381\r
382**/\r
383EFI_STATUS\r
384GicV2DxeInitialize (\r
385 IN EFI_HANDLE ImageHandle,\r
386 IN EFI_SYSTEM_TABLE *SystemTable\r
387 )\r
388{\r
389 EFI_STATUS Status;\r
390 UINTN Index;\r
391 UINT32 RegOffset;\r
392 UINTN RegShift;\r
393 UINT32 CpuTarget;\r
394\r
b0393756
EL
395 // Make sure the Interrupt Controller Protocol is not already installed in\r
396 // the system.\r
f5241b57
OM
397 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
398\r
8a1f2378
DC
399 mGicInterruptInterfaceBase = PcdGet64 (PcdGicInterruptInterfaceBase);\r
400 mGicDistributorBase = PcdGet64 (PcdGicDistributorBase);\r
dc63be24 401 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);\r
f5241b57
OM
402\r
403 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
404 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);\r
405\r
406 // Set Priority\r
407 RegOffset = Index / 4;\r
408 RegShift = (Index % 4) * 8;\r
409 MmioAndThenOr32 (\r
dc63be24 410 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),\r
f5241b57
OM
411 ~(0xff << RegShift),\r
412 ARM_GIC_DEFAULT_PRIORITY << RegShift\r
413 );\r
414 }\r
415\r
f5241b57 416 // Targets the interrupts to the Primary Cpu\r
b0393756
EL
417\r
418 // Only Primary CPU will run this code. We can identify our GIC CPU ID by\r
419 // reading the GIC Distributor Target register. The 8 first GICD_ITARGETSRn\r
420 // are banked to each connected CPU. These 8 registers hold the CPU targets\r
421 // fields for interrupts 0-31. More Info in the GIC Specification about\r
422 // "Interrupt Processor Targets Registers"\r
423\r
424 // Read the first Interrupt Processor Targets Register (that corresponds to\r
425 // the 4 first SGIs)\r
dc63be24 426 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);\r
f5241b57 427\r
b0393756
EL
428 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.\r
429 // This value is 0 when we run on a uniprocessor platform.\r
f5241b57
OM
430 if (CpuTarget != 0) {\r
431 // The 8 first Interrupt Processor Targets Registers are read-only\r
432 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {\r
b0393756
EL
433 MmioWrite32 (\r
434 mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),\r
435 CpuTarget\r
436 );\r
f5241b57
OM
437 }\r
438 }\r
439\r
440 // Set binary point reg to 0x7 (no preemption)\r
dc63be24 441 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7);\r
f5241b57
OM
442\r
443 // Set priority mask reg to 0xff to allow all priorities through\r
dc63be24 444 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff);\r
f5241b57
OM
445\r
446 // Enable gic cpu interface\r
dc63be24 447 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase);\r
f5241b57
OM
448\r
449 // Enable gic distributor\r
dc63be24 450 ArmGicEnableDistributor (mGicDistributorBase);\r
f5241b57
OM
451\r
452 Status = InstallAndRegisterInterruptService (\r
b0393756 453 &gHardwareInterruptV2Protocol,\r
8659306a 454 &gHardwareInterrupt2V2Protocol,\r
b0393756
EL
455 GicV2IrqInterruptHandler,\r
456 GicV2ExitBootServicesEvent\r
457 );\r
f5241b57
OM
458\r
459 return Status;\r
460}\r