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
))
268 "Invalid interrupt trigger type: %d\n", \
272 return EFI_UNSUPPORTED
;
275 Status
= GicGetDistributorIcfgBaseAndBit (
281 if (EFI_ERROR (Status
)) {
285 Status
= GicV2GetInterruptSourceState (
286 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
291 if (EFI_ERROR (Status
)) {
295 Value
= (TriggerType
== EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING
)
296 ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
297 : ARM_GIC_ICDICFR_LEVEL_TRIGGERED
;
299 // Before changing the value, we must disable the interrupt,
300 // otherwise GIC behavior is UNPREDICTABLE.
302 GicV2DisableInterruptSource (
303 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
310 ~(0x1 << Config1Bit
),
314 // Restore interrupt state
316 GicV2EnableInterruptSource (
317 (EFI_HARDWARE_INTERRUPT_PROTOCOL
*)This
,
325 EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol
= {
326 (HARDWARE_INTERRUPT2_REGISTER
)RegisterInterruptSource
,
327 (HARDWARE_INTERRUPT2_ENABLE
)GicV2EnableInterruptSource
,
328 (HARDWARE_INTERRUPT2_DISABLE
)GicV2DisableInterruptSource
,
329 (HARDWARE_INTERRUPT2_INTERRUPT_STATE
)GicV2GetInterruptSourceState
,
330 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT
)GicV2EndOfInterrupt
,
336 Shutdown our hardware
338 DXE Core will disable interrupts and turn off the timer and disable
339 interrupts after all the event handlers have run.
341 @param[in] Event The Event that is being processed
342 @param[in] Context Event Context
347 GicV2ExitBootServicesEvent (
355 // Disable all the interrupts
356 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
357 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
360 // Acknowledge all pending interrupts
362 GicInterrupt
= ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase
);
364 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) < mGicNumInterrupts
) {
365 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol
, GicInterrupt
);
367 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt
));
369 // Disable Gic Interface
370 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase
);
372 // Disable Gic Distributor
373 ArmGicDisableDistributor (mGicDistributorBase
);
377 Initialize the state information for the CPU Architectural Protocol
379 @param ImageHandle of the loaded driver
380 @param SystemTable Pointer to the System Table
382 @retval EFI_SUCCESS Protocol registered
383 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
384 @retval EFI_DEVICE_ERROR Hardware problems
389 IN EFI_HANDLE ImageHandle
,
390 IN EFI_SYSTEM_TABLE
*SystemTable
399 // Make sure the Interrupt Controller Protocol is not already installed in
401 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
403 mGicInterruptInterfaceBase
= PcdGet64 (PcdGicInterruptInterfaceBase
);
404 mGicDistributorBase
= PcdGet64 (PcdGicDistributorBase
);
405 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (mGicDistributorBase
);
407 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
408 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
411 RegOffset
= Index
/ 4;
412 RegShift
= (Index
% 4) * 8;
414 mGicDistributorBase
+ ARM_GIC_ICDIPR
+ (4 * RegOffset
),
416 ARM_GIC_DEFAULT_PRIORITY
<< RegShift
420 // Targets the interrupts to the Primary Cpu
422 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
423 // reading the GIC Distributor Target register. The 8 first GICD_ITARGETSRn
424 // are banked to each connected CPU. These 8 registers hold the CPU targets
425 // fields for interrupts 0-31. More Info in the GIC Specification about
426 // "Interrupt Processor Targets Registers"
428 // Read the first Interrupt Processor Targets Register (that corresponds to
430 CpuTarget
= MmioRead32 (mGicDistributorBase
+ ARM_GIC_ICDIPTR
);
432 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
433 // This value is 0 when we run on a uniprocessor platform.
434 if (CpuTarget
!= 0) {
435 // The 8 first Interrupt Processor Targets Registers are read-only
436 for (Index
= 8; Index
< (mGicNumInterrupts
/ 4); Index
++) {
438 mGicDistributorBase
+ ARM_GIC_ICDIPTR
+ (Index
* 4),
444 // Set binary point reg to 0x7 (no preemption)
445 MmioWrite32 (mGicInterruptInterfaceBase
+ ARM_GIC_ICCBPR
, 0x7);
447 // Set priority mask reg to 0xff to allow all priorities through
448 MmioWrite32 (mGicInterruptInterfaceBase
+ ARM_GIC_ICCPMR
, 0xff);
450 // Enable gic cpu interface
451 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase
);
453 // Enable gic distributor
454 ArmGicEnableDistributor (mGicDistributorBase
);
456 Status
= InstallAndRegisterInterruptService (
457 &gHardwareInterruptV2Protocol
,
458 &gHardwareInterrupt2V2Protocol
,
459 GicV2IrqInterruptHandler
,
460 GicV2ExitBootServicesEvent