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 EOI'ed.
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
382 // Make sure the Interrupt Controller Protocol is not already installed in
384 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
386 mGicDistributorBase
= PcdGet64 (PcdGicDistributorBase
);
387 mGicRedistributorsBase
= PcdGet64 (PcdGicRedistributorsBase
);
388 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (mGicDistributorBase
);
390 // We will be driving this GIC in native v3 mode, i.e., with Affinity
391 // Routing enabled. So ensure that the ARE bit is set.
392 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
393 MmioOr32 (mGicDistributorBase
+ ARM_GIC_ICDDCR
, ARM_GIC_ICDDCR_ARE
);
396 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
397 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol
, Index
);
400 RegOffset
= Index
/ 4;
401 RegShift
= (Index
% 4) * 8;
403 mGicDistributorBase
+ ARM_GIC_ICDIPR
+ (4 * RegOffset
),
405 ARM_GIC_DEFAULT_PRIORITY
<< RegShift
409 // Targets the interrupts to the Primary Cpu
411 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
412 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
413 // reading the GIC Distributor Target register. The 8 first
414 // GICD_ITARGETSRn are banked to each connected CPU. These 8 registers
415 // hold the CPU targets fields for interrupts 0-31. More Info in the GIC
416 // Specification about "Interrupt Processor Targets Registers"
418 // Read the first Interrupt Processor Targets Register (that corresponds
419 // to the 4 first SGIs)
420 CpuTarget
= MmioRead32 (mGicDistributorBase
+ ARM_GIC_ICDIPTR
);
422 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
423 // This value is 0 when we run on a uniprocessor platform.
424 if (CpuTarget
!= 0) {
425 // The 8 first Interrupt Processor Targets Registers are read-only
426 for (Index
= 8; Index
< (mGicNumInterrupts
/ 4); Index
++) {
428 mGicDistributorBase
+ ARM_GIC_ICDIPTR
+ (Index
* 4),
434 MpId
= ArmReadMpidr ();
436 (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
| ARM_CORE_AFF3
);
439 mGicDistributorBase
+ ARM_GIC_ICDDCR
440 ) & ARM_GIC_ICDDCR_DS
) != 0) {
442 // If the Disable Security (DS) control bit is set, we are dealing with a
443 // GIC that has only one security state. In this case, let's assume we are
444 // executing in non-secure state (which is appropriate for DXE modules)
445 // and that no other firmware has performed any configuration on the GIC.
446 // This means we need to reconfigure all interrupts to non-secure Group 1
450 mGicRedistributorsBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GIC_ICDISR
,
454 for (Index
= 32; Index
< mGicNumInterrupts
; Index
+= 32) {
456 mGicDistributorBase
+ ARM_GIC_ICDISR
+ Index
/ 8,
462 // Route the SPIs to the primary CPU. SPIs start at the INTID 32
463 for (Index
= 0; Index
< (mGicNumInterrupts
- 32); Index
++) {
465 mGicDistributorBase
+ ARM_GICD_IROUTER
+ (Index
* 8),
471 // Set binary point reg to 0x7 (no preemption)
472 ArmGicV3SetBinaryPointer (0x7);
474 // Set priority mask reg to 0xff to allow all priorities through
475 ArmGicV3SetPriorityMask (0xff);
477 // Enable gic cpu interface
478 ArmGicV3EnableInterruptInterface ();
480 // Enable gic distributor
481 ArmGicEnableDistributor (mGicDistributorBase
);
483 Status
= InstallAndRegisterInterruptService (
484 &gHardwareInterruptV3Protocol
,
485 &gHardwareInterrupt2V3Protocol
,
486 GicV3IrqInterruptHandler
,
487 GicV3ExitBootServicesEvent