3 * Copyright (c) 2011-2017, ARM Limited. All rights reserved.
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <Library/ArmGicLib.h>
17 #include "ArmGicDxe.h"
19 #define ARM_GIC_DEFAULT_PRIORITY 0x80
21 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol
;
22 extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol
;
24 STATIC UINTN mGicDistributorBase
;
25 STATIC UINTN mGicRedistributorsBase
;
28 Enable interrupt source Source.
30 @param This Instance pointer for this protocol
31 @param Source Hardware source of the interrupt
33 @retval EFI_SUCCESS Source interrupt enabled.
34 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
40 GicV3EnableInterruptSource (
41 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
42 IN HARDWARE_INTERRUPT_SOURCE Source
45 if (Source
>= mGicNumInterrupts
) {
47 return EFI_UNSUPPORTED
;
50 ArmGicEnableInterrupt (mGicDistributorBase
, mGicRedistributorsBase
, Source
);
56 Disable interrupt source Source.
58 @param This Instance pointer for this protocol
59 @param Source Hardware source of the interrupt
61 @retval EFI_SUCCESS Source interrupt disabled.
62 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
68 GicV3DisableInterruptSource (
69 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
70 IN HARDWARE_INTERRUPT_SOURCE Source
73 if (Source
>= mGicNumInterrupts
) {
75 return EFI_UNSUPPORTED
;
78 ArmGicDisableInterrupt (mGicDistributorBase
, mGicRedistributorsBase
, Source
);
84 Return current state of interrupt source Source.
86 @param This Instance pointer for this protocol
87 @param Source Hardware source of the interrupt
88 @param InterruptState TRUE: source enabled, FALSE: source disabled.
90 @retval EFI_SUCCESS InterruptState is valid
91 @retval EFI_DEVICE_ERROR InterruptState is not valid
97 GicV3GetInterruptSourceState (
98 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
99 IN HARDWARE_INTERRUPT_SOURCE Source
,
100 IN BOOLEAN
*InterruptState
103 if (Source
>= mGicNumInterrupts
) {
105 return EFI_UNSUPPORTED
;
108 *InterruptState
= ArmGicIsInterruptEnabled (
110 mGicRedistributorsBase
,
118 Signal to the hardware that the End Of Interrupt state
121 @param This Instance pointer for this protocol
122 @param Source Hardware source of the interrupt
124 @retval EFI_SUCCESS Source interrupt EOI'ed.
125 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
131 GicV3EndOfInterrupt (
132 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
133 IN HARDWARE_INTERRUPT_SOURCE Source
136 if (Source
>= mGicNumInterrupts
) {
138 return EFI_UNSUPPORTED
;
141 ArmGicV3EndOfInterrupt (Source
);
146 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
148 @param InterruptType Defines the type of interrupt or exception that
149 occurred on the processor. This parameter is
150 processor architecture specific.
151 @param SystemContext A pointer to the processor context when
152 the interrupt occurred on the processor.
160 GicV3IrqInterruptHandler (
161 IN EFI_EXCEPTION_TYPE InterruptType
,
162 IN EFI_SYSTEM_CONTEXT SystemContext
166 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
168 GicInterrupt
= ArmGicV3AcknowledgeInterrupt ();
170 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
171 // number of interrupt (ie: Spurious interrupt).
172 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) >= mGicNumInterrupts
) {
173 // The special interrupt do not need to be acknowledge
177 InterruptHandler
= gRegisteredInterruptHandlers
[GicInterrupt
];
178 if (InterruptHandler
!= NULL
) {
179 // Call the registered interrupt handler.
180 InterruptHandler (GicInterrupt
, SystemContext
);
182 DEBUG ((DEBUG_ERROR
, "Spurious GIC interrupt: 0x%x\n", GicInterrupt
));
183 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol
, GicInterrupt
);
187 // The protocol instance produced by this driver
188 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol
= {
189 RegisterInterruptSource
,
190 GicV3EnableInterruptSource
,
191 GicV3DisableInterruptSource
,
192 GicV3GetInterruptSourceState
,
197 Get interrupt trigger type of an interrupt
199 @param This Instance pointer for this protocol
200 @param Source Hardware source of the interrupt.
201 @param TriggerType Returns interrupt trigger type.
203 @retval EFI_SUCCESS Source interrupt supported.
204 @retval EFI_UNSUPPORTED Source interrupt is not supported.
209 GicV3GetTriggerType (
210 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL
*This
,
211 IN HARDWARE_INTERRUPT_SOURCE Source
,
212 OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE
*TriggerType
219 Status
= GicGetDistributorIcfgBaseAndBit (
225 if (EFI_ERROR (Status
)) {
229 if ((MmioRead32 (RegAddress
) & (1 << Config1Bit
)) == 0) {
230 *TriggerType
= EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH
;
232 *TriggerType
= EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING
;
239 Set interrupt trigger type of an interrupt
241 @param This Instance pointer for this protocol
242 @param Source Hardware source of the interrupt.
243 @param TriggerType Interrupt trigger type.
245 @retval EFI_SUCCESS Source interrupt supported.
246 @retval EFI_UNSUPPORTED Source interrupt is not supported.
251 GicV3SetTriggerType (
252 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL
*This
,
253 IN HARDWARE_INTERRUPT_SOURCE Source
,
254 IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType
261 BOOLEAN SourceEnabled
;
263 if ( (TriggerType
!= EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING
)
264 && (TriggerType
!= EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH
)) {
265 DEBUG ((DEBUG_ERROR
, "Invalid interrupt trigger type: %d\n", \
268 return EFI_UNSUPPORTED
;
271 Status
= GicGetDistributorIcfgBaseAndBit (
277 if (EFI_ERROR (Status
)) {
281 Status
= GicV3GetInterruptSourceState (
282 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
287 if (EFI_ERROR (Status
)) {
291 Value
= (TriggerType
== EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING
)
292 ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
293 : ARM_GIC_ICDICFR_LEVEL_TRIGGERED
;
295 // Before changing the value, we must disable the interrupt,
296 // otherwise GIC behavior is UNPREDICTABLE.
298 GicV3DisableInterruptSource (
299 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
306 ~(0x1 << Config1Bit
),
309 // Restore interrupt state
311 GicV3EnableInterruptSource (
312 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
320 EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol
= {
321 (HARDWARE_INTERRUPT2_REGISTER
)RegisterInterruptSource
,
322 (HARDWARE_INTERRUPT2_ENABLE
)GicV3EnableInterruptSource
,
323 (HARDWARE_INTERRUPT2_DISABLE
)GicV3DisableInterruptSource
,
324 (HARDWARE_INTERRUPT2_INTERRUPT_STATE
)GicV3GetInterruptSourceState
,
325 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT
)GicV3EndOfInterrupt
,
331 Shutdown our hardware
333 DXE Core will disable interrupts and turn off the timer and disable interrupts
334 after all the event handlers have run.
336 @param[in] Event The Event that is being processed
337 @param[in] Context Event Context
341 GicV3ExitBootServicesEvent (
348 // Acknowledge all pending interrupts
349 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
350 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol
, Index
);
353 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
354 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol
, Index
);
357 // Disable Gic Interface
358 ArmGicV3DisableInterruptInterface ();
360 // Disable Gic Distributor
361 ArmGicDisableDistributor (mGicDistributorBase
);
365 Initialize the state information for the CPU Architectural Protocol
367 @param ImageHandle of the loaded driver
368 @param SystemTable Pointer to the System Table
370 @retval EFI_SUCCESS Protocol registered
371 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
372 @retval EFI_DEVICE_ERROR Hardware problems
377 IN EFI_HANDLE ImageHandle
,
378 IN EFI_SYSTEM_TABLE
*SystemTable
388 // Make sure the Interrupt Controller Protocol is not already installed in
390 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
392 mGicDistributorBase
= PcdGet64 (PcdGicDistributorBase
);
393 mGicRedistributorsBase
= PcdGet64 (PcdGicRedistributorsBase
);
394 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (mGicDistributorBase
);
396 // We will be driving this GIC in native v3 mode, i.e., with Affinity
397 // Routing enabled. So ensure that the ARE bit is set.
398 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
399 MmioOr32 (mGicDistributorBase
+ ARM_GIC_ICDDCR
, ARM_GIC_ICDDCR_ARE
);
402 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
403 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol
, Index
);
406 RegOffset
= Index
/ 4;
407 RegShift
= (Index
% 4) * 8;
409 mGicDistributorBase
+ ARM_GIC_ICDIPR
+ (4 * RegOffset
),
411 ARM_GIC_DEFAULT_PRIORITY
<< RegShift
415 // Targets the interrupts to the Primary Cpu
417 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy
)) {
418 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
419 // reading the GIC Distributor Target register. The 8 first
420 // GICD_ITARGETSRn are banked to each connected CPU. These 8 registers
421 // hold the CPU targets fields for interrupts 0-31. More Info in the GIC
422 // Specification about "Interrupt Processor Targets Registers"
424 // Read the first Interrupt Processor Targets Register (that corresponds
425 // to the 4 first SGIs)
426 CpuTarget
= MmioRead32 (mGicDistributorBase
+ ARM_GIC_ICDIPTR
);
428 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
429 // This value is 0 when we run on a uniprocessor platform.
430 if (CpuTarget
!= 0) {
431 // The 8 first Interrupt Processor Targets Registers are read-only
432 for (Index
= 8; Index
< (mGicNumInterrupts
/ 4); Index
++) {
434 mGicDistributorBase
+ ARM_GIC_ICDIPTR
+ (Index
* 4),
440 MpId
= ArmReadMpidr ();
442 (ARM_CORE_AFF0
| ARM_CORE_AFF1
| ARM_CORE_AFF2
| ARM_CORE_AFF3
);
445 mGicDistributorBase
+ ARM_GIC_ICDDCR
446 ) & ARM_GIC_ICDDCR_DS
) != 0) {
448 // If the Disable Security (DS) control bit is set, we are dealing with a
449 // GIC that has only one security state. In this case, let's assume we are
450 // executing in non-secure state (which is appropriate for DXE modules)
451 // and that no other firmware has performed any configuration on the GIC.
452 // This means we need to reconfigure all interrupts to non-secure Group 1
456 mGicRedistributorsBase
+ ARM_GICR_CTLR_FRAME_SIZE
+ ARM_GIC_ICDISR
,
460 for (Index
= 32; Index
< mGicNumInterrupts
; Index
+= 32) {
462 mGicDistributorBase
+ ARM_GIC_ICDISR
+ Index
/ 8,
468 // Route the SPIs to the primary CPU. SPIs start at the INTID 32
469 for (Index
= 0; Index
< (mGicNumInterrupts
- 32); Index
++) {
471 mGicDistributorBase
+ ARM_GICD_IROUTER
+ (Index
* 8),
472 CpuTarget
| ARM_GICD_IROUTER_IRM
477 // Set binary point reg to 0x7 (no preemption)
478 ArmGicV3SetBinaryPointer (0x7);
480 // Set priority mask reg to 0xff to allow all priorities through
481 ArmGicV3SetPriorityMask (0xff);
483 // Enable gic cpu interface
484 ArmGicV3EnableInterruptInterface ();
486 // Enable gic distributor
487 ArmGicEnableDistributor (mGicDistributorBase
);
489 Status
= InstallAndRegisterInterruptService (
490 &gHardwareInterruptV3Protocol
,
491 &gHardwareInterrupt2V3Protocol
,
492 GicV3IrqInterruptHandler
,
493 GicV3ExitBootServicesEvent