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 GIC interrupt controller protocol
27 #include <Library/BaseLib.h>
28 #include <Library/BaseMemoryLib.h>
29 #include <Library/UefiLib.h>
30 #include <Library/PcdLib.h>
31 #include <Library/IoLib.h>
32 #include <Library/ArmGicLib.h>
34 #include "ArmGicDxe.h"
36 #define ARM_GIC_DEFAULT_PRIORITY 0x80
38 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol
;
41 Enable interrupt source Source.
43 @param This Instance pointer for this protocol
44 @param Source Hardware source of the interrupt
46 @retval EFI_SUCCESS Source interrupt enabled.
47 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
52 EnableInterruptSource (
53 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
54 IN HARDWARE_INTERRUPT_SOURCE Source
57 if (Source
> mGicNumInterrupts
) {
59 return EFI_UNSUPPORTED
;
62 ArmGicEnableInterrupt (FixedPcdGet32 (PcdGicDistributorBase
), Source
);
68 Disable interrupt source Source.
70 @param This Instance pointer for this protocol
71 @param Source Hardware source of the interrupt
73 @retval EFI_SUCCESS Source interrupt disabled.
74 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
79 DisableInterruptSource (
80 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
81 IN HARDWARE_INTERRUPT_SOURCE Source
84 if (Source
> mGicNumInterrupts
) {
86 return EFI_UNSUPPORTED
;
89 ArmGicDisableInterrupt (PcdGet32(PcdGicDistributorBase
), Source
);
95 Return current state of interrupt source Source.
97 @param This Instance pointer for this protocol
98 @param Source Hardware source of the interrupt
99 @param InterruptState TRUE: source enabled, FALSE: source disabled.
101 @retval EFI_SUCCESS InterruptState is valid
102 @retval EFI_DEVICE_ERROR InterruptState is not valid
107 GetInterruptSourceState (
108 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
109 IN HARDWARE_INTERRUPT_SOURCE Source
,
110 IN BOOLEAN
*InterruptState
113 if (Source
> mGicNumInterrupts
) {
115 return EFI_UNSUPPORTED
;
118 *InterruptState
= ArmGicIsInterruptEnabled (PcdGet32(PcdGicDistributorBase
), Source
);
124 Signal to the hardware that the End Of Intrrupt state
127 @param This Instance pointer for this protocol
128 @param Source Hardware source of the interrupt
130 @retval EFI_SUCCESS Source interrupt EOI'ed.
131 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
137 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
138 IN HARDWARE_INTERRUPT_SOURCE Source
141 if (Source
> mGicNumInterrupts
) {
143 return EFI_UNSUPPORTED
;
146 ArmGicEndOfInterrupt (PcdGet32(PcdGicInterruptInterfaceBase
), Source
);
151 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
153 @param InterruptType Defines the type of interrupt or exception that
154 occurred on the processor.This parameter is processor architecture specific.
155 @param SystemContext A pointer to the processor context when
156 the interrupt occurred on the processor.
163 IrqInterruptHandler (
164 IN EFI_EXCEPTION_TYPE InterruptType
,
165 IN EFI_SYSTEM_CONTEXT SystemContext
169 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
171 GicInterrupt
= ArmGicAcknowledgeInterrupt (PcdGet32(PcdGicInterruptInterfaceBase
));
173 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt).
174 if ((GicInterrupt
& ARM_GIC_ICCIAR_ACKINTID
) >= mGicNumInterrupts
) {
175 // The special interrupt do not need to be acknowledge
179 InterruptHandler
= gRegisteredInterruptHandlers
[GicInterrupt
];
180 if (InterruptHandler
!= NULL
) {
181 // Call the registered interrupt handler.
182 InterruptHandler (GicInterrupt
, SystemContext
);
184 DEBUG ((EFI_D_ERROR
, "Spurious GIC interrupt: 0x%x\n", GicInterrupt
));
187 EndOfInterrupt (&gHardwareInterruptProtocol
, GicInterrupt
);
191 // The protocol instance produced by this driver
193 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol
= {
194 RegisterInterruptSource
,
195 EnableInterruptSource
,
196 DisableInterruptSource
,
197 GetInterruptSourceState
,
202 Shutdown our hardware
204 DXE Core will disable interrupts and turn off the timer and disable interrupts
205 after all the event handlers have run.
207 @param[in] Event The Event that is being processed
208 @param[in] Context Event Context
212 ExitBootServicesEvent (
219 // Acknowledge all pending interrupts
220 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
221 DisableInterruptSource (&gHardwareInterruptProtocol
, Index
);
224 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
225 EndOfInterrupt (&gHardwareInterruptProtocol
, Index
);
228 // Disable Gic Interface
229 ArmGicDisableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase
));
231 // Disable Gic Distributor
232 ArmGicDisableDistributor (PcdGet32(PcdGicDistributorBase
));
236 Initialize the state information for the CPU Architectural Protocol
238 @param ImageHandle of the loaded driver
239 @param SystemTable Pointer to the System Table
241 @retval EFI_SUCCESS Protocol registered
242 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
243 @retval EFI_DEVICE_ERROR Hardware problems
247 InterruptDxeInitialize (
248 IN EFI_HANDLE ImageHandle
,
249 IN EFI_SYSTEM_TABLE
*SystemTable
258 // Make sure the Interrupt Controller Protocol is not already installed in the system.
259 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
261 mGicNumInterrupts
= ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase
));
263 for (Index
= 0; Index
< mGicNumInterrupts
; Index
++) {
264 DisableInterruptSource (&gHardwareInterruptProtocol
, Index
);
267 RegOffset
= Index
/ 4;
268 RegShift
= (Index
% 4) * 8;
270 PcdGet32(PcdGicDistributorBase
) + ARM_GIC_ICDIPR
+ (4*RegOffset
),
272 ARM_GIC_DEFAULT_PRIORITY
<< RegShift
277 // Targets the interrupts to the Primary Cpu
280 // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading
281 // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each
282 // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31.
283 // More Info in the GIC Specification about "Interrupt Processor Targets Registers"
285 // Read the first Interrupt Processor Targets Register (that corresponds to the 4
287 CpuTarget
= MmioRead32 (PcdGet32 (PcdGicDistributorBase
) + ARM_GIC_ICDIPTR
);
289 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value
290 // is 0 when we run on a uniprocessor platform.
291 if (CpuTarget
!= 0) {
292 // The 8 first Interrupt Processor Targets Registers are read-only
293 for (Index
= 8; Index
< (mGicNumInterrupts
/ 4); Index
++) {
294 MmioWrite32 (PcdGet32 (PcdGicDistributorBase
) + ARM_GIC_ICDIPTR
+ (Index
* 4), CpuTarget
);
298 // Set binary point reg to 0x7 (no preemption)
299 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase
) + ARM_GIC_ICCBPR
, 0x7);
301 // Set priority mask reg to 0xff to allow all priorities through
302 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase
) + ARM_GIC_ICCPMR
, 0xff);
304 // Enable gic cpu interface
305 ArmGicEnableInterruptInterface (PcdGet32(PcdGicInterruptInterfaceBase
));
307 // Enable gic distributor
308 ArmGicEnableDistributor (PcdGet32(PcdGicDistributorBase
));
310 Status
= InstallAndRegisterInterruptService (
311 &gHardwareInterruptProtocol
, IrqInterruptHandler
, ExitBootServicesEvent
);