]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
ArmPkg: Correct small typos
[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
b8de64be 118 @retval EFI_SUCCESS Source interrupt ended successfully.\r
5f81082e
OM
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
41fb5d46
OM
377 UINT64 CpuTarget;\r
378 UINT64 MpId;\r
5f81082e 379\r
b0393756
EL
380 // Make sure the Interrupt Controller Protocol is not already installed in\r
381 // the system.\r
5f81082e
OM
382 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
383\r
8a1f2378
DC
384 mGicDistributorBase = PcdGet64 (PcdGicDistributorBase);\r
385 mGicRedistributorsBase = PcdGet64 (PcdGicRedistributorsBase);\r
919697ae 386 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);\r
5f81082e 387\r
f6d46e29
AB
388 // We will be driving this GIC in native v3 mode, i.e., with Affinity\r
389 // Routing enabled. So ensure that the ARE bit is set.\r
f6d46e29
AB
390 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {\r
391 MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE);\r
392 }\r
393\r
5f81082e
OM
394 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
395 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);\r
396\r
397 // Set Priority\r
1159fc32
QN
398 ArmGicSetInterruptPriority (\r
399 mGicDistributorBase,\r
400 mGicRedistributorsBase,\r
401 Index,\r
402 ARM_GIC_DEFAULT_PRIORITY\r
5f81082e
OM
403 );\r
404 }\r
405\r
5f81082e 406 // Targets the interrupts to the Primary Cpu\r
5f81082e 407\r
152ac489 408 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {\r
b0393756
EL
409 // Only Primary CPU will run this code. We can identify our GIC CPU ID by\r
410 // reading the GIC Distributor Target register. The 8 first\r
411 // GICD_ITARGETSRn are banked to each connected CPU. These 8 registers\r
412 // hold the CPU targets fields for interrupts 0-31. More Info in the GIC\r
413 // Specification about "Interrupt Processor Targets Registers"\r
414\r
415 // Read the first Interrupt Processor Targets Register (that corresponds\r
416 // to the 4 first SGIs)\r
152ac489
OM
417 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);\r
418\r
b0393756
EL
419 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.\r
420 // This value is 0 when we run on a uniprocessor platform.\r
152ac489
OM
421 if (CpuTarget != 0) {\r
422 // The 8 first Interrupt Processor Targets Registers are read-only\r
423 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {\r
b0393756
EL
424 MmioWrite32 (\r
425 mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),\r
426 CpuTarget\r
427 );\r
152ac489
OM
428 }\r
429 }\r
430 } else {\r
431 MpId = ArmReadMpidr ();\r
b0393756
EL
432 CpuTarget = MpId &\r
433 (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3);\r
434\r
435 if ((MmioRead32 (\r
436 mGicDistributorBase + ARM_GIC_ICDDCR\r
437 ) & ARM_GIC_ICDDCR_DS) != 0) {\r
41fb5d46 438\r
c7fefb69
AB
439 // If the Disable Security (DS) control bit is set, we are dealing with a\r
440 // GIC that has only one security state. In this case, let's assume we are\r
441 // executing in non-secure state (which is appropriate for DXE modules)\r
442 // and that no other firmware has performed any configuration on the GIC.\r
443 // This means we need to reconfigure all interrupts to non-secure Group 1\r
444 // first.\r
b0393756
EL
445\r
446 MmioWrite32 (\r
447 mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR,\r
448 0xffffffff\r
449 );\r
c7fefb69
AB
450\r
451 for (Index = 32; Index < mGicNumInterrupts; Index += 32) {\r
b0393756
EL
452 MmioWrite32 (\r
453 mGicDistributorBase + ARM_GIC_ICDISR + Index / 8,\r
454 0xffffffff\r
455 );\r
c7fefb69
AB
456 }\r
457 }\r
458\r
152ac489
OM
459 // Route the SPIs to the primary CPU. SPIs start at the INTID 32\r
460 for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) {\r
1bb76029 461 MmioWrite64 (\r
b0393756 462 mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8),\r
b66e38b5 463 CpuTarget\r
b0393756 464 );\r
152ac489 465 }\r
5f81082e
OM
466 }\r
467\r
5f81082e
OM
468 // Set binary point reg to 0x7 (no preemption)\r
469 ArmGicV3SetBinaryPointer (0x7);\r
470\r
471 // Set priority mask reg to 0xff to allow all priorities through\r
472 ArmGicV3SetPriorityMask (0xff);\r
473\r
474 // Enable gic cpu interface\r
475 ArmGicV3EnableInterruptInterface ();\r
476\r
477 // Enable gic distributor\r
478 ArmGicEnableDistributor (mGicDistributorBase);\r
479\r
480 Status = InstallAndRegisterInterruptService (\r
b0393756 481 &gHardwareInterruptV3Protocol,\r
8659306a 482 &gHardwareInterrupt2V3Protocol,\r
b0393756
EL
483 GicV3IrqInterruptHandler,\r
484 GicV3ExitBootServicesEvent\r
485 );\r
5f81082e
OM
486\r
487 return Status;\r
488}\r