3 * Copyright (c) 2011-2018, ARM Limited. All rights reserved.
5 * SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/ArmGicLib.h>
11 #include "ArmGicDxe.h"
13 #define ARM_GIC_DEFAULT_PRIORITY 0x80
15 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol
;
16 extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol
;
18 STATIC UINTN mGicDistributorBase
;
19 STATIC UINTN mGicRedistributorsBase
;
22 Enable interrupt source Source.
24 @param This Instance pointer for this protocol
25 @param Source Hardware source of the interrupt
27 @retval EFI_SUCCESS Source interrupt enabled.
28 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
34 GicV3EnableInterruptSource (
35 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
36 IN HARDWARE_INTERRUPT_SOURCE Source
39 if (Source
>= mGicNumInterrupts
) {
41 return EFI_UNSUPPORTED
;
44 ArmGicEnableInterrupt (mGicDistributorBase
, mGicRedistributorsBase
, Source
);
50 Disable interrupt source Source.
52 @param This Instance pointer for this protocol
53 @param Source Hardware source of the interrupt
55 @retval EFI_SUCCESS Source interrupt disabled.
56 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
62 GicV3DisableInterruptSource (
63 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
64 IN HARDWARE_INTERRUPT_SOURCE Source
67 if (Source
>= mGicNumInterrupts
) {
69 return EFI_UNSUPPORTED
;
72 ArmGicDisableInterrupt (mGicDistributorBase
, mGicRedistributorsBase
, Source
);
78 Return current state of interrupt source Source.
80 @param This Instance pointer for this protocol
81 @param Source Hardware source of the interrupt
82 @param InterruptState TRUE: source enabled, FALSE: source disabled.
84 @retval EFI_SUCCESS InterruptState is valid
85 @retval EFI_DEVICE_ERROR InterruptState is not valid
91 GicV3GetInterruptSourceState (
92 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
93 IN HARDWARE_INTERRUPT_SOURCE Source
,
94 IN BOOLEAN
*InterruptState
97 if (Source
>= mGicNumInterrupts
) {
99 return EFI_UNSUPPORTED
;
102 *InterruptState
= ArmGicIsInterruptEnabled (
104 mGicRedistributorsBase
,
112 Signal to the hardware that the End Of Interrupt state
115 @param This Instance pointer for this protocol
116 @param Source Hardware source of the interrupt
118 @retval EFI_SUCCESS Source interrupt ended successfully.
119 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
125 GicV3EndOfInterrupt (
126 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
127 IN HARDWARE_INTERRUPT_SOURCE Source
130 if (Source
>= mGicNumInterrupts
) {
132 return EFI_UNSUPPORTED
;
135 ArmGicV3EndOfInterrupt (Source
);
140 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
142 @param InterruptType Defines the type of interrupt or exception that
143 occurred on the processor. This parameter is
144 processor architecture specific.
145 @param SystemContext A pointer to the processor context when
146 the interrupt occurred on the processor.
154 GicV3IrqInterruptHandler (
155 IN EFI_EXCEPTION_TYPE InterruptType
,
156 IN EFI_SYSTEM_CONTEXT SystemContext
160 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
162 GicInterrupt
= ArmGicV3AcknowledgeInterrupt ();
164 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
165 // number of interrupt (ie: Spurious interrupt).
166 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) >= mGicNumInterrupts
) {
167 // The special interrupt do not need to be acknowledge
171 InterruptHandler
= gRegisteredInterruptHandlers
[GicInterrupt
];
172 if (InterruptHandler
!= NULL
) {
173 // Call the registered interrupt handler.
174 InterruptHandler (GicInterrupt
, SystemContext
);
176 DEBUG ((DEBUG_ERROR
, "Spurious GIC interrupt: 0x%x\n", GicInterrupt
));
177 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol
, GicInterrupt
);
181 // The protocol instance produced by this driver
182 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol
= {
183 RegisterInterruptSource
,
184 GicV3EnableInterruptSource
,
185 GicV3DisableInterruptSource
,
186 GicV3GetInterruptSourceState
,
191 Get interrupt trigger type of an interrupt
193 @param This Instance pointer for this protocol
194 @param Source Hardware source of the interrupt.
195 @param TriggerType Returns interrupt trigger type.
197 @retval EFI_SUCCESS Source interrupt supported.
198 @retval EFI_UNSUPPORTED Source interrupt is not supported.
203 GicV3GetTriggerType (
204 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL
*This
,
205 IN HARDWARE_INTERRUPT_SOURCE Source
,
206 OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE
*TriggerType
213 Status
= GicGetDistributorIcfgBaseAndBit (
219 if (EFI_ERROR (Status
)) {
223 if ((MmioRead32 (RegAddress
) & (1 << Config1Bit
)) == 0) {
224 *TriggerType
= EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH
;
226 *TriggerType
= EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING
;
233 Set interrupt trigger type of an interrupt
235 @param This Instance pointer for this protocol
236 @param Source Hardware source of the interrupt.
237 @param TriggerType Interrupt trigger type.
239 @retval EFI_SUCCESS Source interrupt supported.
240 @retval EFI_UNSUPPORTED Source interrupt is not supported.
245 GicV3SetTriggerType (
246 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL
*This
,
247 IN HARDWARE_INTERRUPT_SOURCE Source
,
248 IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType
255 BOOLEAN SourceEnabled
;
257 if ( (TriggerType
!= EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING
)
258 && (TriggerType
!= EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH
)) {
259 DEBUG ((DEBUG_ERROR
, "Invalid interrupt trigger type: %d\n", \
262 return EFI_UNSUPPORTED
;
265 Status
= GicGetDistributorIcfgBaseAndBit (
271 if (EFI_ERROR (Status
)) {
275 Status
= GicV3GetInterruptSourceState (
276 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
281 if (EFI_ERROR (Status
)) {
285 Value
= (TriggerType
== EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING
)
286 ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
287 : ARM_GIC_ICDICFR_LEVEL_TRIGGERED
;
289 // Before changing the value, we must disable the interrupt,
290 // otherwise GIC behavior is UNPREDICTABLE.
292 GicV3DisableInterruptSource (
293 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
300 ~(0x1 << Config1Bit
),
303 // Restore interrupt state
305 GicV3EnableInterruptSource (
306 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
314 EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol
= {
315 (HARDWARE_INTERRUPT2_REGISTER
)RegisterInterruptSource
,
316 (HARDWARE_INTERRUPT2_ENABLE
)GicV3EnableInterruptSource
,
317 (HARDWARE_INTERRUPT2_DISABLE
)GicV3DisableInterruptSource
,
318 (HARDWARE_INTERRUPT2_INTERRUPT_STATE
)GicV3GetInterruptSourceState
,
319 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT
)GicV3EndOfInterrupt
,
325 Shutdown our hardware
327 DXE Core will disable interrupts and turn off the timer and disable interrupts
328 after all the event handlers have run.
330 @param[in] Event The Event that is being processed
331 @param[in] Context Event Context
335 GicV3ExitBootServicesEvent (
342 // Acknowledge all pending interrupts
343 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
344 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol
, Index
);
347 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
348 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol
, Index
);
351 // Disable Gic Interface
352 ArmGicV3DisableInterruptInterface ();
354 // Disable Gic Distributor
355 ArmGicDisableDistributor (mGicDistributorBase
);
359 Initialize the state information for the CPU Architectural Protocol
361 @param ImageHandle of the loaded driver
362 @param SystemTable Pointer to the System Table
364 @retval EFI_SUCCESS Protocol registered
365 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
366 @retval EFI_DEVICE_ERROR Hardware problems
371 IN EFI_HANDLE ImageHandle
,
372 IN EFI_SYSTEM_TABLE
*SystemTable
380 // Make sure the Interrupt Controller Protocol is not already installed in
382 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
384 mGicDistributorBase
= PcdGet64 (PcdGicDistributorBase
);
385 mGicRedistributorsBase
= PcdGet64 (PcdGicRedistributorsBase
);
386 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (mGicDistributorBase
);
388 // We will be driving this GIC in native v3 mode, i.e., with Affinity
389 // Routing enabled. So ensure that the ARE bit is set.
390 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
391 MmioOr32 (mGicDistributorBase
+ ARM_GIC_ICDDCR
, ARM_GIC_ICDDCR_ARE
);
394 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
395 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol
, Index
);
398 ArmGicSetInterruptPriority (
400 mGicRedistributorsBase
,
402 ARM_GIC_DEFAULT_PRIORITY
406 // Targets the interrupts to the Primary Cpu
408 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
409 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
410 // reading the GIC Distributor Target register. The 8 first
411 // GICD_ITARGETSRn are banked to each connected CPU. These 8 registers
412 // hold the CPU targets fields for interrupts 0-31. More Info in the GIC
413 // Specification about "Interrupt Processor Targets Registers"
415 // Read the first Interrupt Processor Targets Register (that corresponds
416 // to the 4 first SGIs)
417 CpuTarget
= MmioRead32 (mGicDistributorBase
+ ARM_GIC_ICDIPTR
);
419 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
420 // This value is 0 when we run on a uniprocessor platform.
421 if (CpuTarget
!= 0) {
422 // The 8 first Interrupt Processor Targets Registers are read-only
423 for (Index
= 8; Index
< (mGicNumInterrupts
/ 4); Index
++) {
425 mGicDistributorBase
+ ARM_GIC_ICDIPTR
+ (Index
* 4),
431 MpId
= ArmReadMpidr ();
433 (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
| ARM_CORE_AFF3
);
436 mGicDistributorBase
+ ARM_GIC_ICDDCR
437 ) & ARM_GIC_ICDDCR_DS
) != 0) {
439 // If the Disable Security (DS) control bit is set, we are dealing with a
440 // GIC that has only one security state. In this case, let's assume we are
441 // executing in non-secure state (which is appropriate for DXE modules)
442 // and that no other firmware has performed any configuration on the GIC.
443 // This means we need to reconfigure all interrupts to non-secure Group 1
447 mGicRedistributorsBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GIC_ICDISR
,
451 for (Index
= 32; Index
< mGicNumInterrupts
; Index
+= 32) {
453 mGicDistributorBase
+ ARM_GIC_ICDISR
+ Index
/ 8,
459 // Route the SPIs to the primary CPU. SPIs start at the INTID 32
460 for (Index
= 0; Index
< (mGicNumInterrupts
- 32); Index
++) {
462 mGicDistributorBase
+ ARM_GICD_IROUTER
+ (Index
* 8),
468 // Set binary point reg to 0x7 (no preemption)
469 ArmGicV3SetBinaryPointer (0x7);
471 // Set priority mask reg to 0xff to allow all priorities through
472 ArmGicV3SetPriorityMask (0xff);
474 // Enable gic cpu interface
475 ArmGicV3EnableInterruptInterface ();
477 // Enable gic distributor
478 ArmGicEnableDistributor (mGicDistributorBase
);
480 Status
= InstallAndRegisterInterruptService (
481 &gHardwareInterruptV3Protocol
,
482 &gHardwareInterrupt2V3Protocol
,
483 GicV3IrqInterruptHandler
,
484 GicV3ExitBootServicesEvent