3 Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
4 Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2011-2017, ARM Ltd. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
15 Driver implementing the GicV2 interrupt controller protocol
19 #include <Library/ArmGicLib.h>
21 #include "ArmGicDxe.h"
23 #define ARM_GIC_DEFAULT_PRIORITY 0x80
25 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol
;
26 extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol
;
28 STATIC UINT32 mGicInterruptInterfaceBase
;
29 STATIC UINT32 mGicDistributorBase
;
32 Enable interrupt source Source.
34 @param This Instance pointer for this protocol
35 @param Source Hardware source of the interrupt
37 @retval EFI_SUCCESS Source interrupt enabled.
38 @retval EFI_UNSUPPORTED Source interrupt is not supported
44 GicV2EnableInterruptSource (
45 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
46 IN HARDWARE_INTERRUPT_SOURCE Source
49 if (Source
>= mGicNumInterrupts
) {
51 return EFI_UNSUPPORTED
;
54 ArmGicEnableInterrupt (mGicDistributorBase
, 0, Source
);
60 Disable interrupt source Source.
62 @param This Instance pointer for this protocol
63 @param Source Hardware source of the interrupt
65 @retval EFI_SUCCESS Source interrupt disabled.
66 @retval EFI_UNSUPPORTED Source interrupt is not supported
72 GicV2DisableInterruptSource (
73 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
74 IN HARDWARE_INTERRUPT_SOURCE Source
77 if (Source
>= mGicNumInterrupts
) {
79 return EFI_UNSUPPORTED
;
82 ArmGicDisableInterrupt (mGicDistributorBase
, 0, Source
);
88 Return current state of interrupt source Source.
90 @param This Instance pointer for this protocol
91 @param Source Hardware source of the interrupt
92 @param InterruptState TRUE: source enabled, FALSE: source disabled.
94 @retval EFI_SUCCESS InterruptState is valid
95 @retval EFI_UNSUPPORTED Source interrupt is not supported
101 GicV2GetInterruptSourceState (
102 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
103 IN HARDWARE_INTERRUPT_SOURCE Source
,
104 IN BOOLEAN
*InterruptState
107 if (Source
>= mGicNumInterrupts
) {
109 return EFI_UNSUPPORTED
;
112 *InterruptState
= ArmGicIsInterruptEnabled (mGicDistributorBase
, 0, Source
);
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 ended successfully.
125 @retval EFI_UNSUPPORTED Source interrupt is not supported
131 GicV2EndOfInterrupt (
132 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
133 IN HARDWARE_INTERRUPT_SOURCE Source
136 if (Source
>= mGicNumInterrupts
) {
138 return EFI_UNSUPPORTED
;
141 ArmGicV2EndOfInterrupt (mGicInterruptInterfaceBase
, 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 GicV2IrqInterruptHandler (
161 IN EFI_EXCEPTION_TYPE InterruptType
,
162 IN EFI_SYSTEM_CONTEXT SystemContext
166 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
168 GicInterrupt
= ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase
);
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 interrupts do not need to be acknowledged
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 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol
, GicInterrupt
);
187 // The protocol instance produced by this driver
188 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol
= {
189 RegisterInterruptSource
,
190 GicV2EnableInterruptSource
,
191 GicV2DisableInterruptSource
,
192 GicV2GetInterruptSourceState
,
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 GicV2GetTriggerType (
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 GicV2SetTriggerType (
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
= GicV2GetInterruptSourceState (
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 GicV2DisableInterruptSource (
299 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
306 ~(0x1 << Config1Bit
),
310 // Restore interrupt state
312 GicV2EnableInterruptSource (
313 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
321 EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol
= {
322 (HARDWARE_INTERRUPT2_REGISTER
)RegisterInterruptSource
,
323 (HARDWARE_INTERRUPT2_ENABLE
)GicV2EnableInterruptSource
,
324 (HARDWARE_INTERRUPT2_DISABLE
)GicV2DisableInterruptSource
,
325 (HARDWARE_INTERRUPT2_INTERRUPT_STATE
)GicV2GetInterruptSourceState
,
326 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT
)GicV2EndOfInterrupt
,
332 Shutdown our hardware
334 DXE Core will disable interrupts and turn off the timer and disable
335 interrupts after all the event handlers have run.
337 @param[in] Event The Event that is being processed
338 @param[in] Context Event Context
343 GicV2ExitBootServicesEvent (
351 // Disable all the interrupts
352 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
353 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
356 // Acknowledge all pending interrupts
358 GicInterrupt
= ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase
);
360 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) < mGicNumInterrupts
) {
361 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol
, GicInterrupt
);
363 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt
));
365 // Disable Gic Interface
366 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase
);
368 // Disable Gic Distributor
369 ArmGicDisableDistributor (mGicDistributorBase
);
373 Initialize the state information for the CPU Architectural Protocol
375 @param ImageHandle of the loaded driver
376 @param SystemTable Pointer to the System Table
378 @retval EFI_SUCCESS Protocol registered
379 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
380 @retval EFI_DEVICE_ERROR Hardware problems
385 IN EFI_HANDLE ImageHandle
,
386 IN EFI_SYSTEM_TABLE
*SystemTable
395 // Make sure the Interrupt Controller Protocol is not already installed in
397 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
399 mGicInterruptInterfaceBase
= PcdGet64 (PcdGicInterruptInterfaceBase
);
400 mGicDistributorBase
= PcdGet64 (PcdGicDistributorBase
);
401 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (mGicDistributorBase
);
403 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
404 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
407 RegOffset
= Index
/ 4;
408 RegShift
= (Index
% 4) * 8;
410 mGicDistributorBase
+ ARM_GIC_ICDIPR
+ (4 * RegOffset
),
412 ARM_GIC_DEFAULT_PRIORITY
<< RegShift
416 // Targets the interrupts to the Primary Cpu
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 GICD_ITARGETSRn
420 // are banked to each connected CPU. These 8 registers hold the CPU targets
421 // fields for interrupts 0-31. More Info in the GIC Specification about
422 // "Interrupt Processor Targets Registers"
424 // Read the first Interrupt Processor Targets Register (that corresponds to
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 // Set binary point reg to 0x7 (no preemption)
441 MmioWrite32 (mGicInterruptInterfaceBase
+ ARM_GIC_ICCBPR
, 0x7);
443 // Set priority mask reg to 0xff to allow all priorities through
444 MmioWrite32 (mGicInterruptInterfaceBase
+ ARM_GIC_ICCPMR
, 0xff);
446 // Enable gic cpu interface
447 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase
);
449 // Enable gic distributor
450 ArmGicEnableDistributor (mGicDistributorBase
);
452 Status
= InstallAndRegisterInterruptService (
453 &gHardwareInterruptV2Protocol
,
454 &gHardwareInterrupt2V2Protocol
,
455 GicV2IrqInterruptHandler
,
456 GicV2ExitBootServicesEvent