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-2014, ARM Ltd. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 Driver implementing the GicV2 interrupt controller protocol
25 #include "ArmGicDxe.h"
26 #include "GicV2/ArmGicV2Lib.h"
28 #define ARM_GIC_DEFAULT_PRIORITY 0x80
30 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol
;
33 Enable interrupt source Source.
35 @param This Instance pointer for this protocol
36 @param Source Hardware source of the interrupt
38 @retval EFI_SUCCESS Source interrupt enabled.
39 @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 (FixedPcdGet32 (PcdGicDistributorBase
), 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
71 GicV2DisableInterruptSource (
72 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
73 IN HARDWARE_INTERRUPT_SOURCE Source
76 if (Source
> mGicNumInterrupts
) {
78 return EFI_UNSUPPORTED
;
81 ArmGicDisableInterrupt (FixedPcdGet32 (PcdGicDistributorBase
), Source
);
87 Return current state of interrupt source Source.
89 @param This Instance pointer for this protocol
90 @param Source Hardware source of the interrupt
91 @param InterruptState TRUE: source enabled, FALSE: source disabled.
93 @retval EFI_SUCCESS InterruptState is valid
94 @retval EFI_UNSUPPORTED Source interrupt is not supported
99 GicV2GetInterruptSourceState (
100 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
101 IN HARDWARE_INTERRUPT_SOURCE Source
,
102 IN BOOLEAN
*InterruptState
105 if (Source
> mGicNumInterrupts
) {
107 return EFI_UNSUPPORTED
;
110 *InterruptState
= ArmGicIsInterruptEnabled (FixedPcdGet32 (PcdGicDistributorBase
), Source
);
116 Signal to the hardware that the End Of Interrupt state
119 @param This Instance pointer for this protocol
120 @param Source Hardware source of the interrupt
122 @retval EFI_SUCCESS Source interrupt EOI'ed.
123 @retval EFI_UNSUPPORTED Source interrupt is not supported
128 GicV2EndOfInterrupt (
129 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
130 IN HARDWARE_INTERRUPT_SOURCE Source
133 if (Source
> mGicNumInterrupts
) {
135 return EFI_UNSUPPORTED
;
138 ArmGicV2EndOfInterrupt (FixedPcdGet32 (PcdGicInterruptInterfaceBase
), Source
);
143 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
145 @param InterruptType Defines the type of interrupt or exception that
146 occurred on the processor.This parameter is processor architecture specific.
147 @param SystemContext A pointer to the processor context when
148 the interrupt occurred on the processor.
155 GicV2IrqInterruptHandler (
156 IN EFI_EXCEPTION_TYPE InterruptType
,
157 IN EFI_SYSTEM_CONTEXT SystemContext
161 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
163 GicInterrupt
= ArmGicV2AcknowledgeInterrupt (FixedPcdGet32 (PcdGicInterruptInterfaceBase
));
165 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the 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 ((EFI_D_ERROR
, "Spurious GIC interrupt: 0x%x\n", GicInterrupt
));
179 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol
, GicInterrupt
);
183 // The protocol instance produced by this driver
185 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol
= {
186 RegisterInterruptSource
,
187 GicV2EnableInterruptSource
,
188 GicV2DisableInterruptSource
,
189 GicV2GetInterruptSourceState
,
194 Shutdown our hardware
196 DXE Core will disable interrupts and turn off the timer and disable interrupts
197 after all the event handlers have run.
199 @param[in] Event The Event that is being processed
200 @param[in] Context Event Context
204 GicV2ExitBootServicesEvent (
212 // Disable all the interrupts
213 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
214 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
217 // Acknowledge all pending interrupts
219 GicInterrupt
= ArmGicV2AcknowledgeInterrupt (FixedPcdGet32 (PcdGicInterruptInterfaceBase
));
221 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) < mGicNumInterrupts
) {
222 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol
, GicInterrupt
);
224 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt
));
226 // Disable Gic Interface
227 ArmGicV2DisableInterruptInterface (FixedPcdGet32 (PcdGicInterruptInterfaceBase
));
229 // Disable Gic Distributor
230 ArmGicDisableDistributor (FixedPcdGet32 (PcdGicDistributorBase
));
234 Initialize the state information for the CPU Architectural Protocol
236 @param ImageHandle of the loaded driver
237 @param SystemTable Pointer to the System Table
239 @retval EFI_SUCCESS Protocol registered
240 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
241 @retval EFI_DEVICE_ERROR Hardware problems
246 IN EFI_HANDLE ImageHandle
,
247 IN EFI_SYSTEM_TABLE
*SystemTable
256 // Make sure the Interrupt Controller Protocol is not already installed in the system.
257 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
259 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (FixedPcdGet32 (PcdGicDistributorBase
));
261 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
262 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
265 RegOffset
= Index
/ 4;
266 RegShift
= (Index
% 4) * 8;
268 FixedPcdGet32 (PcdGicDistributorBase
) + ARM_GIC_ICDIPR
+ (4 * RegOffset
),
270 ARM_GIC_DEFAULT_PRIORITY
<< RegShift
275 // Targets the interrupts to the Primary Cpu
278 // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading
279 // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each
280 // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31.
281 // More Info in the GIC Specification about "Interrupt Processor Targets Registers"
283 // Read the first Interrupt Processor Targets Register (that corresponds to the 4
285 CpuTarget
= MmioRead32 (FixedPcdGet32 (PcdGicDistributorBase
) + ARM_GIC_ICDIPTR
);
287 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value
288 // is 0 when we run on a uniprocessor platform.
289 if (CpuTarget
!= 0) {
290 // The 8 first Interrupt Processor Targets Registers are read-only
291 for (Index
= 8; Index
< (mGicNumInterrupts
/ 4); Index
++) {
292 MmioWrite32 (FixedPcdGet32 (PcdGicDistributorBase
) + ARM_GIC_ICDIPTR
+ (Index
* 4), CpuTarget
);
296 // Set binary point reg to 0x7 (no preemption)
297 MmioWrite32 (FixedPcdGet32 (PcdGicInterruptInterfaceBase
) + ARM_GIC_ICCBPR
, 0x7);
299 // Set priority mask reg to 0xff to allow all priorities through
300 MmioWrite32 (FixedPcdGet32 (PcdGicInterruptInterfaceBase
) + ARM_GIC_ICCPMR
, 0xff);
302 // Enable gic cpu interface
303 ArmGicEnableInterruptInterface (FixedPcdGet32 (PcdGicInterruptInterfaceBase
));
305 // Enable gic distributor
306 ArmGicEnableDistributor (FixedPcdGet32 (PcdGicDistributorBase
));
308 Status
= InstallAndRegisterInterruptService (
309 &gHardwareInterruptV2Protocol
, GicV2IrqInterruptHandler
, GicV2ExitBootServicesEvent
);