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
;
32 UINT32 mGicInterruptInterfaceBase
;
33 UINT32 mGicDistributorBase
;
36 Enable interrupt source Source.
38 @param This Instance pointer for this protocol
39 @param Source Hardware source of the interrupt
41 @retval EFI_SUCCESS Source interrupt enabled.
42 @retval EFI_UNSUPPORTED Source interrupt is not supported
47 GicV2EnableInterruptSource (
48 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
49 IN HARDWARE_INTERRUPT_SOURCE Source
52 if (Source
> mGicNumInterrupts
) {
54 return EFI_UNSUPPORTED
;
57 ArmGicEnableInterrupt (mGicDistributorBase
, Source
);
63 Disable interrupt source Source.
65 @param This Instance pointer for this protocol
66 @param Source Hardware source of the interrupt
68 @retval EFI_SUCCESS Source interrupt disabled.
69 @retval EFI_UNSUPPORTED Source interrupt is not supported
74 GicV2DisableInterruptSource (
75 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
76 IN HARDWARE_INTERRUPT_SOURCE Source
79 if (Source
> mGicNumInterrupts
) {
81 return EFI_UNSUPPORTED
;
84 ArmGicDisableInterrupt (mGicDistributorBase
, Source
);
90 Return current state of interrupt source Source.
92 @param This Instance pointer for this protocol
93 @param Source Hardware source of the interrupt
94 @param InterruptState TRUE: source enabled, FALSE: source disabled.
96 @retval EFI_SUCCESS InterruptState is valid
97 @retval EFI_UNSUPPORTED Source interrupt is not supported
102 GicV2GetInterruptSourceState (
103 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
104 IN HARDWARE_INTERRUPT_SOURCE Source
,
105 IN BOOLEAN
*InterruptState
108 if (Source
> mGicNumInterrupts
) {
110 return EFI_UNSUPPORTED
;
113 *InterruptState
= ArmGicIsInterruptEnabled (mGicDistributorBase
, Source
);
119 Signal to the hardware that the End Of Interrupt state
122 @param This Instance pointer for this protocol
123 @param Source Hardware source of the interrupt
125 @retval EFI_SUCCESS Source interrupt EOI'ed.
126 @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 processor architecture specific.
150 @param SystemContext A pointer to the processor context when
151 the interrupt occurred on the processor.
158 GicV2IrqInterruptHandler (
159 IN EFI_EXCEPTION_TYPE InterruptType
,
160 IN EFI_SYSTEM_CONTEXT SystemContext
164 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
166 GicInterrupt
= ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase
);
168 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt).
169 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) >= mGicNumInterrupts
) {
170 // The special interrupt do not need to be acknowledge
174 InterruptHandler
= gRegisteredInterruptHandlers
[GicInterrupt
];
175 if (InterruptHandler
!= NULL
) {
176 // Call the registered interrupt handler.
177 InterruptHandler (GicInterrupt
, SystemContext
);
179 DEBUG ((EFI_D_ERROR
, "Spurious GIC interrupt: 0x%x\n", GicInterrupt
));
182 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol
, GicInterrupt
);
186 // The protocol instance produced by this driver
188 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol
= {
189 RegisterInterruptSource
,
190 GicV2EnableInterruptSource
,
191 GicV2DisableInterruptSource
,
192 GicV2GetInterruptSourceState
,
197 Shutdown our hardware
199 DXE Core will disable interrupts and turn off the timer and disable interrupts
200 after all the event handlers have run.
202 @param[in] Event The Event that is being processed
203 @param[in] Context Event Context
207 GicV2ExitBootServicesEvent (
215 // Disable all the interrupts
216 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
217 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
220 // Acknowledge all pending interrupts
222 GicInterrupt
= ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase
);
224 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) < mGicNumInterrupts
) {
225 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol
, GicInterrupt
);
227 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt
));
229 // Disable Gic Interface
230 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase
);
232 // Disable Gic Distributor
233 ArmGicDisableDistributor (mGicDistributorBase
);
237 Initialize the state information for the CPU Architectural Protocol
239 @param ImageHandle of the loaded driver
240 @param SystemTable Pointer to the System Table
242 @retval EFI_SUCCESS Protocol registered
243 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
244 @retval EFI_DEVICE_ERROR Hardware problems
249 IN EFI_HANDLE ImageHandle
,
250 IN EFI_SYSTEM_TABLE
*SystemTable
259 // Make sure the Interrupt Controller Protocol is not already installed in the system.
260 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
262 mGicInterruptInterfaceBase
= PcdGet32 (PcdGicInterruptInterfaceBase
);
263 mGicDistributorBase
= PcdGet32 (PcdGicDistributorBase
);
264 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (mGicDistributorBase
);
266 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
267 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol
, Index
);
270 RegOffset
= Index
/ 4;
271 RegShift
= (Index
% 4) * 8;
273 mGicDistributorBase
+ ARM_GIC_ICDIPR
+ (4 * RegOffset
),
275 ARM_GIC_DEFAULT_PRIORITY
<< RegShift
280 // Targets the interrupts to the Primary Cpu
283 // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading
284 // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each
285 // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31.
286 // More Info in the GIC Specification about "Interrupt Processor Targets Registers"
288 // Read the first Interrupt Processor Targets Register (that corresponds to the 4
290 CpuTarget
= MmioRead32 (mGicDistributorBase
+ ARM_GIC_ICDIPTR
);
292 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value
293 // is 0 when we run on a uniprocessor platform.
294 if (CpuTarget
!= 0) {
295 // The 8 first Interrupt Processor Targets Registers are read-only
296 for (Index
= 8; Index
< (mGicNumInterrupts
/ 4); Index
++) {
297 MmioWrite32 (mGicDistributorBase
+ ARM_GIC_ICDIPTR
+ (Index
* 4), CpuTarget
);
301 // Set binary point reg to 0x7 (no preemption)
302 MmioWrite32 (mGicInterruptInterfaceBase
+ ARM_GIC_ICCBPR
, 0x7);
304 // Set priority mask reg to 0xff to allow all priorities through
305 MmioWrite32 (mGicInterruptInterfaceBase
+ ARM_GIC_ICCPMR
, 0xff);
307 // Enable gic cpu interface
308 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase
);
310 // Enable gic distributor
311 ArmGicEnableDistributor (mGicDistributorBase
);
313 Status
= InstallAndRegisterInterruptService (
314 &gHardwareInterruptV2Protocol
, GicV2IrqInterruptHandler
, GicV2ExitBootServicesEvent
);