2 Portions copyright (c) 2010, Apple Inc. All rights reserved.
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 Copyright (c) 2009, Hewlett-Packard Company
16 All rights reserved. This program and the accompanying materials
17 are licensed and made available under the terms and conditions of the BSD License
18 which accompanies this distribution. The full text of the license may be found at
19 http://opensource.org/licenses/bsd-license.php
21 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
22 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
30 Driver implementing the GIC interrupt controller protocol
36 #include <Library/BaseLib.h>
37 #include <Library/DebugLib.h>
38 #include <Library/BaseMemoryLib.h>
39 #include <Library/UefiBootServicesTableLib.h>
40 #include <Library/UefiLib.h>
41 #include <Library/PcdLib.h>
42 #include <Library/IoLib.h>
44 #include <Protocol/Cpu.h>
45 #include <Protocol/HardwareInterrupt.h>
49 // EB board definitions
51 #define EB_GIC1_CPU_INTF_BASE 0x10040000
52 #define EB_GIC1_DIST_BASE 0x10041000
53 #define EB_GIC2_CPU_INTF_BASE 0x10050000
54 #define EB_GIC2_DIST_BASE 0x10051000
55 #define EB_GIC3_CPU_INTF_BASE 0x10060000
56 #define EB_GIC3_DIST_BASE 0x10061000
57 #define EB_GIC4_CPU_INTF_BASE 0x10070000
58 #define EB_GIC5_DIST_BASE 0x10071000
60 // number of interrupts sources supported by each GIC on the EB
61 #define EB_NUM_GIC_INTERRUPTS 96
63 // number of 32-bit registers needed to represent those interrupts as a bit
64 // (used for enable set, enable clear, pending set, pending clear, and active regs)
65 #define EB_NUM_GIC_REG_PER_INT_BITS (EB_NUM_GIC_INTERRUPTS / 32)
67 // number of 32-bit registers needed to represent those interrupts as two bits
68 // (used for configuration reg)
69 #define EB_NUM_GIC_REG_PER_INT_CFG (EB_NUM_GIC_INTERRUPTS / 16)
71 // number of 32-bit registers needed to represent interrupts as 8-bit priority field
72 // (used for priority regs)
73 #define EB_NUM_GIC_REG_PER_INT_BYTES (EB_NUM_GIC_INTERRUPTS / 4)
75 #define GIC_DEFAULT_PRIORITY 0x80
82 #define GIC_ICDDCR 0x000 // Distributor Control Register
83 #define GIC_ICDICTR 0x004 // Interrupt Controller Type Register
84 #define GIC_ICDIIDR 0x008 // Implementer Identification Register
86 // each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BITS (see GIC spec)
87 #define GIC_ICDISR 0x080 // Interrupt Security Registers
88 #define GIC_ICDISER 0x100 // Interrupt Set-Enable Registers
89 #define GIC_ICDICER 0x180 // Interrupt Clear-Enable Registers
90 #define GIC_ICDSPR 0x200 // Interrupt Set-Pending Registers
91 #define GIC_ICDCPR 0x280 // Interrupt Clear-Pending Registers
92 #define GIC_ICDABR 0x300 // Active Bit Registers
94 // each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BYTES
95 #define GIC_ICDIPR 0x400 // Interrupt Priority Registers
97 // each reg base below repeats for EB_NUM_GIC_INTERRUPTS
98 #define GIC_ICDIPTR 0x800 // Interrupt Processor Target Registers
99 #define GIC_ICDICFR 0xC00 // Interrupt Configuration Registers
102 #define GIC_ICDSGIR 0xF00 // Software Generated Interrupt Register
106 #define GIC_ICCICR 0x00 // CPU Interface Controler Register
107 #define GIC_ICCPMR 0x04 // Interrupt Priority Mask Register
108 #define GIC_ICCBPR 0x08 // Binary Point Register
109 #define GIC_ICCIAR 0x0C // Interrupt Acknowledge Register
110 #define GIC_ICCEIOR 0x10 // End Of Interrupt Register
111 #define GIC_ICCRPR 0x14 // Running Priority Register
112 #define GIC_ICCPIR 0x18 // Highest Pending Interrupt Register
113 #define GIC_ICCABPR 0x1C // Aliased Binary Point Register
114 #define GIC_ICCIDR 0xFC // Identification Register
116 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol
;
121 VOID
*CpuProtocolNotificationToken
= NULL
;
122 EFI_EVENT CpuProtocolNotificationEvent
= (EFI_EVENT
)NULL
;
123 EFI_EVENT EfiExitBootServicesEvent
= (EFI_EVENT
)NULL
;
126 HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers
[EB_NUM_GIC_INTERRUPTS
];
129 Register Handler for the specified interrupt source.
131 @param This Instance pointer for this protocol
132 @param Source Hardware source of the interrupt
133 @param Handler Callback for interrupt. NULL to unregister
135 @retval EFI_SUCCESS Source was updated to support Handler.
136 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
141 RegisterInterruptSource (
142 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
143 IN HARDWARE_INTERRUPT_SOURCE Source
,
144 IN HARDWARE_INTERRUPT_HANDLER Handler
147 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
149 return EFI_UNSUPPORTED
;
152 if ((Handler
== NULL
) && (gRegisteredInterruptHandlers
[Source
] == NULL
)) {
153 return EFI_INVALID_PARAMETER
;
156 if ((Handler
!= NULL
) && (gRegisteredInterruptHandlers
[Source
] != NULL
)) {
157 return EFI_ALREADY_STARTED
;
160 gRegisteredInterruptHandlers
[Source
] = Handler
;
161 return This
->EnableInterruptSource(This
, Source
);
166 Enable interrupt source Source.
168 @param This Instance pointer for this protocol
169 @param Source Hardware source of the interrupt
171 @retval EFI_SUCCESS Source interrupt enabled.
172 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
177 EnableInterruptSource (
178 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
179 IN HARDWARE_INTERRUPT_SOURCE Source
185 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
187 return EFI_UNSUPPORTED
;
190 // calculate enable register offset and bit position
191 RegOffset
= Source
/ 32;
192 RegShift
= Source
% 32;
194 // write set-enable register
195 MmioWrite32 (EB_GIC1_DIST_BASE
+GIC_ICDISER
+(4*RegOffset
), 1 << RegShift
);
202 Disable interrupt source Source.
204 @param This Instance pointer for this protocol
205 @param Source Hardware source of the interrupt
207 @retval EFI_SUCCESS Source interrupt disabled.
208 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
213 DisableInterruptSource (
214 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
215 IN HARDWARE_INTERRUPT_SOURCE Source
221 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
223 return EFI_UNSUPPORTED
;
226 // calculate enable register offset and bit position
227 RegOffset
= Source
/ 32;
228 RegShift
= Source
% 32;
230 // write set-enable register
231 MmioWrite32 (EB_GIC1_DIST_BASE
+GIC_ICDICER
+(4*RegOffset
), 1 << RegShift
);
239 Return current state of interrupt source Source.
241 @param This Instance pointer for this protocol
242 @param Source Hardware source of the interrupt
243 @param InterruptState TRUE: source enabled, FALSE: source disabled.
245 @retval EFI_SUCCESS InterruptState is valid
246 @retval EFI_DEVICE_ERROR InterruptState is not valid
251 GetInterruptSourceState (
252 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
253 IN HARDWARE_INTERRUPT_SOURCE Source
,
254 IN BOOLEAN
*InterruptState
260 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
262 return EFI_UNSUPPORTED
;
265 // calculate enable register offset and bit position
266 RegOffset
= Source
/ 32;
267 RegShift
= Source
% 32;
269 if ((MmioRead32 (EB_GIC1_DIST_BASE
+GIC_ICDISER
+(4*RegOffset
)) & (1<<RegShift
)) == 0) {
270 *InterruptState
= FALSE
;
272 *InterruptState
= TRUE
;
279 Signal to the hardware that the End Of Intrrupt state
282 @param This Instance pointer for this protocol
283 @param Source Hardware source of the interrupt
285 @retval EFI_SUCCESS Source interrupt EOI'ed.
286 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
292 IN EFI_HARDWARE_INTERRUPT_PROTOCOL
*This
,
293 IN HARDWARE_INTERRUPT_SOURCE Source
296 if (Source
> EB_NUM_GIC_INTERRUPTS
) {
298 return EFI_UNSUPPORTED
;
301 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+GIC_ICCEIOR
, Source
);
307 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
309 @param InterruptType Defines the type of interrupt or exception that
310 occurred on the processor.This parameter is processor architecture specific.
311 @param SystemContext A pointer to the processor context when
312 the interrupt occurred on the processor.
319 IrqInterruptHandler (
320 IN EFI_EXCEPTION_TYPE InterruptType
,
321 IN EFI_SYSTEM_CONTEXT SystemContext
325 HARDWARE_INTERRUPT_HANDLER InterruptHandler
;
327 GicInterrupt
= MmioRead32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCIAR
);
328 if (GicInterrupt
>= EB_NUM_GIC_INTERRUPTS
) {
329 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+GIC_ICCEIOR
, GicInterrupt
);
332 InterruptHandler
= gRegisteredInterruptHandlers
[GicInterrupt
];
333 if (InterruptHandler
!= NULL
) {
334 // Call the registered interrupt handler.
335 InterruptHandler (GicInterrupt
, SystemContext
);
337 DEBUG ((EFI_D_ERROR
, "Spurious GIC interrupt: %x\n", GicInterrupt
));
340 EndOfInterrupt (&gHardwareInterruptProtocol
, GicInterrupt
);
345 // Making this global saves a few bytes in image size
347 EFI_HANDLE gHardwareInterruptHandle
= NULL
;
350 // The protocol instance produced by this driver
352 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol
= {
353 RegisterInterruptSource
,
354 EnableInterruptSource
,
355 DisableInterruptSource
,
356 GetInterruptSourceState
,
362 Shutdown our hardware
364 DXE Core will disable interrupts and turn off the timer and disable interrupts
365 after all the event handlers have run.
367 @param[in] Event The Event that is being processed
368 @param[in] Context Event Context
372 ExitBootServicesEvent (
379 for (i
= 0; i
< EB_NUM_GIC_INTERRUPTS
; i
++) {
380 DisableInterruptSource (&gHardwareInterruptProtocol
, i
);
386 // Notification routines
389 CpuProtocolInstalledNotification (
395 EFI_CPU_ARCH_PROTOCOL
*Cpu
;
398 // Get the cpu protocol that this driver requires.
400 Status
= gBS
->LocateProtocol(&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**)&Cpu
);
401 ASSERT_EFI_ERROR(Status
);
404 // Unregister the default exception handler.
406 Status
= Cpu
->RegisterInterruptHandler(Cpu
, EXCEPT_ARM_IRQ
, NULL
);
407 ASSERT_EFI_ERROR(Status
);
410 // Register to receive interrupts
412 Status
= Cpu
->RegisterInterruptHandler(Cpu
, EXCEPT_ARM_IRQ
, IrqInterruptHandler
);
413 ASSERT_EFI_ERROR(Status
);
417 Initialize the state information for the CPU Architectural Protocol
419 @param ImageHandle of the loaded driver
420 @param SystemTable Pointer to the System Table
422 @retval EFI_SUCCESS Protocol registered
423 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
424 @retval EFI_DEVICE_ERROR Hardware problems
428 InterruptDxeInitialize (
429 IN EFI_HANDLE ImageHandle
,
430 IN EFI_SYSTEM_TABLE
*SystemTable
439 // Make sure the Interrupt Controller Protocol is not already installed in the system.
440 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL
, &gHardwareInterruptProtocolGuid
);
442 for (i
= 0; i
< EB_NUM_GIC_INTERRUPTS
; i
++) {
443 DisableInterruptSource (&gHardwareInterruptProtocol
, i
);
447 RegShift
= (i
% 4) * 8;
449 EB_GIC1_DIST_BASE
+GIC_ICDIPR
+(4*RegOffset
),
451 GIC_DEFAULT_PRIORITY
<< RegShift
455 // configure interrupts for cpu 0
456 for (i
= 0; i
< EB_NUM_GIC_REG_PER_INT_BYTES
; i
++) {
457 MmioWrite32 (EB_GIC1_DIST_BASE
+ GIC_ICDIPTR
+ (i
*4), 0x01010101);
460 // set binary point reg to 0x7 (no preemption)
461 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCBPR
, 0x7);
463 // set priority mask reg to 0xff to allow all priorities through
464 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCPMR
, 0xff);
466 // enable gic cpu interface
467 MmioWrite32 (EB_GIC1_CPU_INTF_BASE
+ GIC_ICCICR
, 0x1);
469 // enable gic distributor
470 MmioWrite32 (EB_GIC1_DIST_BASE
+ GIC_ICCICR
, 0x1);
473 ZeroMem (&gRegisteredInterruptHandlers
, sizeof (gRegisteredInterruptHandlers
));
475 Status
= gBS
->InstallMultipleProtocolInterfaces (
476 &gHardwareInterruptHandle
,
477 &gHardwareInterruptProtocolGuid
, &gHardwareInterruptProtocol
,
480 ASSERT_EFI_ERROR (Status
);
482 // Set up to be notified when the Cpu protocol is installed.
483 Status
= gBS
->CreateEvent (EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
, CpuProtocolInstalledNotification
, NULL
, &CpuProtocolNotificationEvent
);
484 ASSERT_EFI_ERROR (Status
);
486 Status
= gBS
->RegisterProtocolNotify (&gEfiCpuArchProtocolGuid
, CpuProtocolNotificationEvent
, (VOID
*)&CpuProtocolNotificationToken
);
487 ASSERT_EFI_ERROR (Status
);
489 // Register for an ExitBootServicesEvent
490 Status
= gBS
->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES
, TPL_NOTIFY
, ExitBootServicesEvent
, NULL
, &EfiExitBootServicesEvent
);
491 ASSERT_EFI_ERROR (Status
);