3 Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
4 Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Driver implementing the GIC interrupt controller protocol
25 #include <Library/BaseLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiLib.h>
30 #include <Library/PcdLib.h>
31 #include <Library/IoLib.h>
33 #include <Protocol/Cpu.h>
34 #include <Protocol/HardwareInterrupt.h>
38 // EB board definitions
40 #define EB_GIC1_CPU_INTF_BASE 0x10040000
41 #define EB_GIC1_DIST_BASE 0x10041000
42 #define EB_GIC2_CPU_INTF_BASE 0x10050000
43 #define EB_GIC2_DIST_BASE 0x10051000
44 #define EB_GIC3_CPU_INTF_BASE 0x10060000
45 #define EB_GIC3_DIST_BASE 0x10061000
46 #define EB_GIC4_CPU_INTF_BASE 0x10070000
47 #define EB_GIC5_DIST_BASE 0x10071000
49 // number of interrupts sources supported by each GIC on the EB
50 #define EB_NUM_GIC_INTERRUPTS 96
52 // number of 32-bit registers needed to represent those interrupts as a bit
53 // (used for enable set, enable clear, pending set, pending clear, and active regs)
54 #define EB_NUM_GIC_REG_PER_INT_BITS (EB_NUM_GIC_INTERRUPTS / 32)
56 // number of 32-bit registers needed to represent those interrupts as two bits
57 // (used for configuration reg)
58 #define EB_NUM_GIC_REG_PER_INT_CFG (EB_NUM_GIC_INTERRUPTS / 16)
60 // number of 32-bit registers needed to represent interrupts as 8-bit priority field
61 // (used for priority regs)
62 #define EB_NUM_GIC_REG_PER_INT_BYTES (EB_NUM_GIC_INTERRUPTS / 4)
64 #define GIC_DEFAULT_PRIORITY 0x80
71 #define GIC_ICDDCR 0x000 // Distributor Control Register
72 #define GIC_ICDICTR 0x004 // Interrupt Controller Type Register
73 #define GIC_ICDIIDR 0x008 // Implementer Identification Register
75 // each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BITS (see GIC spec)
76 #define GIC_ICDISR 0x080 // Interrupt Security Registers
77 #define GIC_ICDISER 0x100 // Interrupt Set-Enable Registers
78 #define GIC_ICDICER 0x180 // Interrupt Clear-Enable Registers
79 #define GIC_ICDSPR 0x200 // Interrupt Set-Pending Registers
80 #define GIC_ICDCPR 0x280 // Interrupt Clear-Pending Registers
81 #define GIC_ICDABR 0x300 // Active Bit Registers
83 // each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BYTES
84 #define GIC_ICDIPR 0x400 // Interrupt Priority Registers
86 // each reg base below repeats for EB_NUM_GIC_INTERRUPTS
87 #define GIC_ICDIPTR 0x800 // Interrupt Processor Target Registers
88 #define GIC_ICDICFR 0xC00 // Interrupt Configuration Registers
91 #define GIC_ICDSGIR 0xF00 // Software Generated Interrupt Register
95 #define GIC_ICCICR 0x00 // CPU Interface Controler Register
96 #define GIC_ICCPMR 0x04 // Interrupt Priority Mask Register
97 #define GIC_ICCBPR 0x08 // Binary Point Register
98 #define GIC_ICCIAR 0x0C // Interrupt Acknowledge Register
99 #define GIC_ICCEIOR 0x10 // End Of Interrupt Register
100 #define GIC_ICCRPR 0x14 // Running Priority Register
101 #define GIC_ICCPIR 0x18 // Highest Pending Interrupt Register
102 #define GIC_ICCABPR 0x1C // Aliased Binary Point Register
103 #define GIC_ICCIDR 0xFC // Identification Register
105 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol
;
110 VOID
*CpuProtocolNotificationToken
= NULL
;
111 EFI_EVENT CpuProtocolNotificationEvent
= (EFI_EVENT
)NULL
;
112 EFI_EVENT EfiExitBootServicesEvent
= (EFI_EVENT
)NULL
;
115 HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers
[EB_NUM_GIC_INTERRUPTS
];
118 Register Handler for the specified interrupt source.
120 @param This Instance pointer for this protocol
121 @param Source Hardware source of the interrupt
122 @param Handler Callback for interrupt. NULL to unregister
124 @retval EFI_SUCCESS Source was updated to support Handler.
125 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
130 RegisterInterruptSource (
131 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
132 IN HARDWARE_INTERRUPT_SOURCE Source
,
133 IN HARDWARE_INTERRUPT_HANDLER Handler
136 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
138 return EFI_UNSUPPORTED
;
141 if ((Handler
== NULL
) && (gRegisteredInterruptHandlers
[Source
] == NULL
)) {
142 return EFI_INVALID_PARAMETER
;
145 if ((Handler
!= NULL
) && (gRegisteredInterruptHandlers
[Source
] != NULL
)) {
146 return EFI_ALREADY_STARTED
;
149 gRegisteredInterruptHandlers
[Source
] = Handler
;
150 return This
->EnableInterruptSource(This
, Source
);
155 Enable interrupt source Source.
157 @param This Instance pointer for this protocol
158 @param Source Hardware source of the interrupt
160 @retval EFI_SUCCESS Source interrupt enabled.
161 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
166 EnableInterruptSource (
167 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
168 IN HARDWARE_INTERRUPT_SOURCE Source
174 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
176 return EFI_UNSUPPORTED
;
179 // calculate enable register offset and bit position
180 RegOffset
= Source
/ 32;
181 RegShift
= Source
% 32;
183 // write set-enable register
184 MmioWrite32 (EB_GIC1_DIST_BASE
+GIC_ICDISER
+(4*RegOffset
), 1 << RegShift
);
191 Disable interrupt source Source.
193 @param This Instance pointer for this protocol
194 @param Source Hardware source of the interrupt
196 @retval EFI_SUCCESS Source interrupt disabled.
197 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
202 DisableInterruptSource (
203 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
204 IN HARDWARE_INTERRUPT_SOURCE Source
210 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
212 return EFI_UNSUPPORTED
;
215 // calculate enable register offset and bit position
216 RegOffset
= Source
/ 32;
217 RegShift
= Source
% 32;
219 // write set-enable register
220 MmioWrite32 (EB_GIC1_DIST_BASE
+GIC_ICDICER
+(4*RegOffset
), 1 << RegShift
);
228 Return current state of interrupt source Source.
230 @param This Instance pointer for this protocol
231 @param Source Hardware source of the interrupt
232 @param InterruptState TRUE: source enabled, FALSE: source disabled.
234 @retval EFI_SUCCESS InterruptState is valid
235 @retval EFI_DEVICE_ERROR InterruptState is not valid
240 GetInterruptSourceState (
241 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
242 IN HARDWARE_INTERRUPT_SOURCE Source
,
243 IN BOOLEAN
*InterruptState
249 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
251 return EFI_UNSUPPORTED
;
254 // calculate enable register offset and bit position
255 RegOffset
= Source
/ 32;
256 RegShift
= Source
% 32;
258 if ((MmioRead32 (EB_GIC1_DIST_BASE
+GIC_ICDISER
+(4*RegOffset
)) & (1<<RegShift
)) == 0) {
259 *InterruptState
= FALSE
;
261 *InterruptState
= TRUE
;
268 Signal to the hardware that the End Of Intrrupt state
271 @param This Instance pointer for this protocol
272 @param Source Hardware source of the interrupt
274 @retval EFI_SUCCESS Source interrupt EOI'ed.
275 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
281 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
282 IN HARDWARE_INTERRUPT_SOURCE Source
285 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
287 return EFI_UNSUPPORTED
;
290 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+GIC_ICCEIOR
, Source
);
296 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
298 @param InterruptType Defines the type of interrupt or exception that
299 occurred on the processor.This parameter is processor architecture specific.
300 @param SystemContext A pointer to the processor context when
301 the interrupt occurred on the processor.
308 IrqInterruptHandler (
309 IN EFI_EXCEPTION_TYPE InterruptType
,
310 IN EFI_SYSTEM_CONTEXT SystemContext
314 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
316 GicInterrupt
= MmioRead32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCIAR
);
317 if (GicInterrupt
>= EB_NUM_GIC_INTERRUPTS
) {
318 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+GIC_ICCEIOR
, GicInterrupt
);
321 InterruptHandler
= gRegisteredInterruptHandlers
[GicInterrupt
];
322 if (InterruptHandler
!= NULL
) {
323 // Call the registered interrupt handler.
324 InterruptHandler (GicInterrupt
, SystemContext
);
326 DEBUG ((EFI_D_ERROR
, "Spurious GIC interrupt: %x\n", GicInterrupt
));
329 EndOfInterrupt (&gHardwareInterruptProtocol
, GicInterrupt
);
334 // Making this global saves a few bytes in image size
336 EFI_HANDLE gHardwareInterruptHandle
= NULL
;
339 // The protocol instance produced by this driver
341 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol
= {
342 RegisterInterruptSource
,
343 EnableInterruptSource
,
344 DisableInterruptSource
,
345 GetInterruptSourceState
,
351 Shutdown our hardware
353 DXE Core will disable interrupts and turn off the timer and disable interrupts
354 after all the event handlers have run.
356 @param[in] Event The Event that is being processed
357 @param[in] Context Event Context
361 ExitBootServicesEvent (
368 for (i
= 0; i
< EB_NUM_GIC_INTERRUPTS
; i
++) {
369 DisableInterruptSource (&gHardwareInterruptProtocol
, i
);
375 // Notification routines
378 CpuProtocolInstalledNotification (
384 EFI_CPU_ARCH_PROTOCOL
*Cpu
;
387 // Get the cpu protocol that this driver requires.
389 Status
= gBS
->LocateProtocol(&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**)&Cpu
);
390 ASSERT_EFI_ERROR(Status
);
393 // Unregister the default exception handler.
395 Status
= Cpu
->RegisterInterruptHandler(Cpu
, EXCEPT_ARM_IRQ
, NULL
);
396 ASSERT_EFI_ERROR(Status
);
399 // Register to receive interrupts
401 Status
= Cpu
->RegisterInterruptHandler(Cpu
, EXCEPT_ARM_IRQ
, IrqInterruptHandler
);
402 ASSERT_EFI_ERROR(Status
);
406 Initialize the state information for the CPU Architectural Protocol
408 @param ImageHandle of the loaded driver
409 @param SystemTable Pointer to the System Table
411 @retval EFI_SUCCESS Protocol registered
412 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
413 @retval EFI_DEVICE_ERROR Hardware problems
417 InterruptDxeInitialize (
418 IN EFI_HANDLE ImageHandle
,
419 IN EFI_SYSTEM_TABLE
*SystemTable
428 // Make sure the Interrupt Controller Protocol is not already installed in the system.
429 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
431 for (i
= 0; i
< EB_NUM_GIC_INTERRUPTS
; i
++) {
432 DisableInterruptSource (&gHardwareInterruptProtocol
, i
);
436 RegShift
= (i
% 4) * 8;
438 EB_GIC1_DIST_BASE
+GIC_ICDIPR
+(4*RegOffset
),
440 GIC_DEFAULT_PRIORITY
<< RegShift
444 // configure interrupts for cpu 0
445 for (i
= 0; i
< EB_NUM_GIC_REG_PER_INT_BYTES
; i
++) {
446 MmioWrite32 (EB_GIC1_DIST_BASE
+ GIC_ICDIPTR
+ (i
*4), 0x01010101);
449 // set binary point reg to 0x7 (no preemption)
450 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCBPR
, 0x7);
452 // set priority mask reg to 0xff to allow all priorities through
453 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCPMR
, 0xff);
455 // enable gic cpu interface
456 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCICR
, 0x1);
458 // enable gic distributor
459 MmioWrite32 (EB_GIC1_DIST_BASE
+ GIC_ICCICR
, 0x1);
462 ZeroMem (&gRegisteredInterruptHandlers
, sizeof (gRegisteredInterruptHandlers
));
464 Status
= gBS
->InstallMultipleProtocolInterfaces (
465 &gHardwareInterruptHandle
,
466 &gHardwareInterruptProtocolGuid
, &gHardwareInterruptProtocol
,
469 ASSERT_EFI_ERROR (Status
);
471 // Set up to be notified when the Cpu protocol is installed.
472 Status
= gBS
->CreateEvent (EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, CpuProtocolInstalledNotification
, NULL
, &CpuProtocolNotificationEvent
);
473 ASSERT_EFI_ERROR (Status
);
475 Status
= gBS
->RegisterProtocolNotify (&gEfiCpuArchProtocolGuid
, CpuProtocolNotificationEvent
, (VOID
*)&CpuProtocolNotificationToken
);
476 ASSERT_EFI_ERROR (Status
);
478 // Register for an ExitBootServicesEvent
479 Status
= gBS
->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES
, TPL_NOTIFY
, ExitBootServicesEvent
, NULL
, &EfiExitBootServicesEvent
);
480 ASSERT_EFI_ERROR (Status
);