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