-/*++
-
-Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
-Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-Module Name:
-
- Gic.c
-
-Abstract:
-
- Driver implementing the GIC interrupt controller protocol
-
---*/
-
-#include <PiDxe.h>
-
-#include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiLib.h>
-#include <Library/PcdLib.h>
-#include <Library/IoLib.h>
-
-#include <Protocol/Cpu.h>
-#include <Protocol/HardwareInterrupt.h>
-
-#include <Drivers/PL390Gic.h>
-
-// number of 32-bit registers needed to represent those interrupts as a bit
-// (used for enable set, enable clear, pending set, pending clear, and active regs)
-#define GIC_NUM_REG_PER_INT_BITS (PcdGet32(PcdGicNumInterrupts) / 32)
-
-// number of 32-bit registers needed to represent those interrupts as two bits
-// (used for configuration reg)
-#define GIC_NUM_REG_PER_INT_CFG (PcdGet32(PcdGicNumInterrupts) / 16)
-
-// number of 32-bit registers needed to represent interrupts as 8-bit priority field
-// (used for priority regs)
-#define GIC_NUM_REG_PER_INT_BYTES (PcdGet32(PcdGicNumInterrupts) / 4)
-
-#define GIC_DEFAULT_PRIORITY 0x80
-
-extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol;
-
-//
-// Notifications
-//
-VOID *CpuProtocolNotificationToken = NULL;
-EFI_EVENT CpuProtocolNotificationEvent = (EFI_EVENT)NULL;
-EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
-
-HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[FixedPcdGet32(PcdGicNumInterrupts)];
-
-/**
- Register Handler for the specified interrupt source.
-
- @param This Instance pointer for this protocol
- @param Source Hardware source of the interrupt
- @param Handler Callback for interrupt. NULL to unregister
-
- @retval EFI_SUCCESS Source was updated to support Handler.
- @retval EFI_DEVICE_ERROR Hardware could not be programmed.
-
-**/
-EFI_STATUS
-EFIAPI
-RegisterInterruptSource (
- IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
- IN HARDWARE_INTERRUPT_SOURCE Source,
- IN HARDWARE_INTERRUPT_HANDLER Handler
- )
-{
- if (Source > PcdGet32(PcdGicNumInterrupts)) {
- ASSERT(FALSE);
- return EFI_UNSUPPORTED;
- }
-
- if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
- return EFI_ALREADY_STARTED;
- }
-
- gRegisteredInterruptHandlers[Source] = Handler;
- return This->EnableInterruptSource(This, Source);
-}
-
-/**
- Enable interrupt source Source.
-
- @param This Instance pointer for this protocol
- @param Source Hardware source of the interrupt
-
- @retval EFI_SUCCESS Source interrupt enabled.
- @retval EFI_DEVICE_ERROR Hardware could not be programmed.
-
-**/
-EFI_STATUS
-EFIAPI
-EnableInterruptSource (
- IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
- IN HARDWARE_INTERRUPT_SOURCE Source
- )
-{
- UINT32 RegOffset;
- UINTN RegShift;
-
- if (Source > PcdGet32(PcdGicNumInterrupts)) {
- ASSERT(FALSE);
- return EFI_UNSUPPORTED;
- }
-
- // calculate enable register offset and bit position
- RegOffset = Source / 32;
- RegShift = Source % 32;
-
- // write set-enable register
- MmioWrite32 (PcdGet32(PcdGicDistributorBase) + GIC_ICDISER+(4*RegOffset), 1 << RegShift);
-
- return EFI_SUCCESS;
-}
-
-/**
- Disable interrupt source Source.
-
- @param This Instance pointer for this protocol
- @param Source Hardware source of the interrupt
-
- @retval EFI_SUCCESS Source interrupt disabled.
- @retval EFI_DEVICE_ERROR Hardware could not be programmed.
-
-**/
-EFI_STATUS
-EFIAPI
-DisableInterruptSource (
- IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
- IN HARDWARE_INTERRUPT_SOURCE Source
- )
-{
- UINT32 RegOffset;
- UINTN RegShift;
-
- if (Source > PcdGet32(PcdGicNumInterrupts)) {
- ASSERT(FALSE);
- return EFI_UNSUPPORTED;
- }
-
- // calculate enable register offset and bit position
- RegOffset = Source / 32;
- RegShift = Source % 32;
-
- // write set-enable register
- MmioWrite32 (PcdGet32(PcdGicDistributorBase) + GIC_ICDICER+(4*RegOffset), 1 << RegShift);
-
- return EFI_SUCCESS;
-}
-
-/**
- Return current state of interrupt source Source.
-
- @param This Instance pointer for this protocol
- @param Source Hardware source of the interrupt
- @param InterruptState TRUE: source enabled, FALSE: source disabled.
-
- @retval EFI_SUCCESS InterruptState is valid
- @retval EFI_DEVICE_ERROR InterruptState is not valid
-
-**/
-EFI_STATUS
-EFIAPI
-GetInterruptSourceState (
- IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
- IN HARDWARE_INTERRUPT_SOURCE Source,
- IN BOOLEAN *InterruptState
- )
-{
- UINT32 RegOffset;
- UINTN RegShift;
-
- if (Source > PcdGet32(PcdGicNumInterrupts)) {
- ASSERT(FALSE);
- return EFI_UNSUPPORTED;
- }
-
- // calculate enable register offset and bit position
- RegOffset = Source / 32;
- RegShift = Source % 32;
-
- if ((MmioRead32 (PcdGet32(PcdGicDistributorBase) + GIC_ICDISER+(4*RegOffset)) & (1<<RegShift)) == 0) {
- *InterruptState = FALSE;
- } else {
- *InterruptState = TRUE;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Signal to the hardware that the End Of Intrrupt state
- has been reached.
-
- @param This Instance pointer for this protocol
- @param Source Hardware source of the interrupt
-
- @retval EFI_SUCCESS Source interrupt EOI'ed.
- @retval EFI_DEVICE_ERROR Hardware could not be programmed.
-
-**/
-EFI_STATUS
-EFIAPI
-EndOfInterrupt (
- IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
- IN HARDWARE_INTERRUPT_SOURCE Source
- )
-{
- if (Source > PcdGet32(PcdGicNumInterrupts)) {
- ASSERT(FALSE);
- return EFI_UNSUPPORTED;
- }
-
- MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCEIOR, Source);
- return EFI_SUCCESS;
-}
-
-/**
- EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
-
- @param InterruptType Defines the type of interrupt or exception that
- occurred on the processor.This parameter is processor architecture specific.
- @param SystemContext A pointer to the processor context when
- the interrupt occurred on the processor.
-
- @return None
-
-**/
-VOID
-EFIAPI
-IrqInterruptHandler (
- IN EFI_EXCEPTION_TYPE InterruptType,
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
-{
- UINT32 GicInterrupt;
- HARDWARE_INTERRUPT_HANDLER InterruptHandler;
-
- GicInterrupt = MmioRead32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCIAR);
- if (GicInterrupt >= PcdGet32(PcdGicNumInterrupts)) {
- MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCEIOR, GicInterrupt);
- return;
- }
-
- InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
- if (InterruptHandler != NULL) {
- // Call the registered interrupt handler.
- InterruptHandler (GicInterrupt, SystemContext);
- } else {
- DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));
- }
-
- EndOfInterrupt (&gHardwareInterruptProtocol, GicInterrupt);
-}
-
-//
-// Making this global saves a few bytes in image size
-//
-EFI_HANDLE gHardwareInterruptHandle = NULL;
-
-//
-// The protocol instance produced by this driver
-//
-EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {
- RegisterInterruptSource,
- EnableInterruptSource,
- DisableInterruptSource,
- GetInterruptSourceState,
- EndOfInterrupt
-};
-
-/**
- Shutdown our hardware
-
- DXE Core will disable interrupts and turn off the timer and disable interrupts
- after all the event handlers have run.
-
- @param[in] Event The Event that is being processed
- @param[in] Context Event Context
-**/
-VOID
-EFIAPI
-ExitBootServicesEvent (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- UINTN i;
-
- for (i = 0; i < PcdGet32(PcdGicNumInterrupts); i++) {
- DisableInterruptSource (&gHardwareInterruptProtocol, i);
- }
-
- // Acknowledge all pending interrupts
- for (i = 0; i < PcdGet32(PcdGicNumInterrupts); i++) {
- DisableInterruptSource (&gHardwareInterruptProtocol, i);
- }
-
- for (i = 0; i < PcdGet32(PcdGicNumInterrupts); i++) {
- EndOfInterrupt (&gHardwareInterruptProtocol, i);
- }
-
- // Disable Gic Interface
- MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCICR, 0x0);
- MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCPMR, 0x0);
-
- // Disable Gic Distributor
- MmioWrite32 (PcdGet32(PcdGicDistributorBase) + GIC_ICDDCR, 0x0);
-}
-
-//
-// Notification routines
-//
-VOID
-CpuProtocolInstalledNotification (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_CPU_ARCH_PROTOCOL *Cpu;
-
- //
- // Get the cpu protocol that this driver requires.
- //
- Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
- ASSERT_EFI_ERROR(Status);
-
- //
- // Unregister the default exception handler.
- //
- Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL);
- ASSERT_EFI_ERROR(Status);
-
- //
- // Register to receive interrupts
- //
- Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);
- ASSERT_EFI_ERROR(Status);
-}
-
-/**
- Initialize the state information for the CPU Architectural Protocol
-
- @param ImageHandle of the loaded driver
- @param SystemTable Pointer to the System Table
-
- @retval EFI_SUCCESS Protocol registered
- @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
- @retval EFI_DEVICE_ERROR Hardware problems
-
-**/
-EFI_STATUS
-InterruptDxeInitialize (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- UINTN i;
- UINT32 RegOffset;
- UINTN RegShift;
-
- // Make sure the Interrupt Controller Protocol is not already installed in the system.
- ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
-
- for (i = 0; i < PcdGet32(PcdGicNumInterrupts); i++) {
- DisableInterruptSource (&gHardwareInterruptProtocol, i);
-
- // Set Priority
- RegOffset = i / 4;
- RegShift = (i % 4) * 8;
- MmioAndThenOr32 (
- PcdGet32(PcdGicDistributorBase) + GIC_ICDIPR+(4*RegOffset),
- ~(0xff << RegShift),
- GIC_DEFAULT_PRIORITY << RegShift
- );
- }
-
- // configure interrupts for cpu 0
- for (i = 0; i < GIC_NUM_REG_PER_INT_BYTES; i++) {
- MmioWrite32 (PcdGet32(PcdGicDistributorBase) + GIC_ICDIPTR + (i*4), 0x01010101);
- }
-
- // set binary point reg to 0x7 (no preemption)
- MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCBPR, 0x7);
-
- // set priority mask reg to 0xff to allow all priorities through
- MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCPMR, 0xff);
-
- // enable gic cpu interface
- MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + GIC_ICCICR, 0x1);
-
- // enable gic distributor
- MmioWrite32 (PcdGet32(PcdGicDistributorBase) + GIC_ICDDCR, 0x1);
-
- ZeroMem (&gRegisteredInterruptHandlers, sizeof (gRegisteredInterruptHandlers));
-
- Status = gBS->InstallMultipleProtocolInterfaces (
- &gHardwareInterruptHandle,
- &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- // Set up to be notified when the Cpu protocol is installed.
- Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuProtocolInstalledNotification, NULL, &CpuProtocolNotificationEvent);
- ASSERT_EFI_ERROR (Status);
-
- Status = gBS->RegisterProtocolNotify (&gEfiCpuArchProtocolGuid, CpuProtocolNotificationEvent, (VOID *)&CpuProtocolNotificationToken);
- ASSERT_EFI_ERROR (Status);
-
- // Register for an ExitBootServicesEvent
- Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/*++\r
+\r
+Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>\r
+Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>\r
+Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR> \r
+\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+ Gic.c\r
+\r
+Abstract:\r
+\r
+ Driver implementing the GIC interrupt controller protocol\r
+\r
+--*/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Library/ArmLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/ArmGicLib.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+#include <Protocol/HardwareInterrupt.h>\r
+\r
+#define ARM_GIC_DEFAULT_PRIORITY 0x80\r
+\r
+extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol;\r
+\r
+//\r
+// Notifications\r
+//\r
+EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;\r
+\r
+// Maximum Number of Interrupts\r
+UINTN mGicNumInterrupts = 0;\r
+\r
+HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;\r
+\r
+/**\r
+ Register Handler for the specified interrupt source.\r
+\r
+ @param This Instance pointer for this protocol\r
+ @param Source Hardware source of the interrupt\r
+ @param Handler Callback for interrupt. NULL to unregister\r
+\r
+ @retval EFI_SUCCESS Source was updated to support Handler.\r
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterInterruptSource (\r
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
+ IN HARDWARE_INTERRUPT_SOURCE Source,\r
+ IN HARDWARE_INTERRUPT_HANDLER Handler\r
+ )\r
+{\r
+ if (Source > mGicNumInterrupts) {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ gRegisteredInterruptHandlers[Source] = Handler;\r
+\r
+ // If the interrupt handler is unregistered then disable the interrupt\r
+ if (NULL == Handler){\r
+ return This->DisableInterruptSource (This, Source);\r
+ } else {\r
+ return This->EnableInterruptSource (This, Source);\r
+ }\r
+}\r
+\r
+/**\r
+ Enable interrupt source Source.\r
+\r
+ @param This Instance pointer for this protocol\r
+ @param Source Hardware source of the interrupt\r
+\r
+ @retval EFI_SUCCESS Source interrupt enabled.\r
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableInterruptSource (\r
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
+ IN HARDWARE_INTERRUPT_SOURCE Source\r
+ )\r
+{\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ \r
+ if (Source > mGicNumInterrupts) {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ // Calculate enable register offset and bit position\r
+ RegOffset = Source / 32;\r
+ RegShift = Source % 32;\r
+\r
+ // Write set-enable register\r
+ MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset), 1 << RegShift);\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Disable interrupt source Source.\r
+\r
+ @param This Instance pointer for this protocol\r
+ @param Source Hardware source of the interrupt\r
+\r
+ @retval EFI_SUCCESS Source interrupt disabled.\r
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DisableInterruptSource (\r
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
+ IN HARDWARE_INTERRUPT_SOURCE Source\r
+ )\r
+{\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ \r
+ if (Source > mGicNumInterrupts) {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ // Calculate enable register offset and bit position\r
+ RegOffset = Source / 32;\r
+ RegShift = Source % 32;\r
+\r
+ // Write set-enable register\r
+ MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDICER + (4*RegOffset), 1 << RegShift);\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return current state of interrupt source Source.\r
+\r
+ @param This Instance pointer for this protocol\r
+ @param Source Hardware source of the interrupt\r
+ @param InterruptState TRUE: source enabled, FALSE: source disabled.\r
+\r
+ @retval EFI_SUCCESS InterruptState is valid\r
+ @retval EFI_DEVICE_ERROR InterruptState is not valid\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetInterruptSourceState (\r
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
+ IN HARDWARE_INTERRUPT_SOURCE Source,\r
+ IN BOOLEAN *InterruptState\r
+ )\r
+{\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ \r
+ if (Source > mGicNumInterrupts) {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ // calculate enable register offset and bit position\r
+ RegOffset = Source / 32;\r
+ RegShift = Source % 32;\r
+ \r
+ if ((MmioRead32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset)) & (1<<RegShift)) == 0) {\r
+ *InterruptState = FALSE;\r
+ } else {\r
+ *InterruptState = TRUE;\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Signal to the hardware that the End Of Intrrupt state \r
+ has been reached.\r
+\r
+ @param This Instance pointer for this protocol\r
+ @param Source Hardware source of the interrupt\r
+\r
+ @retval EFI_SUCCESS Source interrupt EOI'ed.\r
+ @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EndOfInterrupt (\r
+ IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
+ IN HARDWARE_INTERRUPT_SOURCE Source\r
+ )\r
+{\r
+ if (Source > mGicNumInterrupts) {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCEIOR, Source);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.\r
+\r
+ @param InterruptType Defines the type of interrupt or exception that\r
+ occurred on the processor.This parameter is processor architecture specific.\r
+ @param SystemContext A pointer to the processor context when\r
+ the interrupt occurred on the processor.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IrqInterruptHandler (\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ UINT32 GicInterrupt;\r
+ HARDWARE_INTERRUPT_HANDLER InterruptHandler;\r
+\r
+ GicInterrupt = MmioRead32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCIAR);\r
+\r
+ // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt).\r
+ if (GicInterrupt >= mGicNumInterrupts) {\r
+ // The special interrupt do not need to be acknowledge\r
+ return;\r
+ }\r
+ \r
+ InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];\r
+ if (InterruptHandler != NULL) {\r
+ // Call the registered interrupt handler.\r
+ InterruptHandler (GicInterrupt, SystemContext);\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));\r
+ }\r
+\r
+ EndOfInterrupt (&gHardwareInterruptProtocol, GicInterrupt);\r
+}\r
+\r
+//\r
+// Making this global saves a few bytes in image size\r
+//\r
+EFI_HANDLE gHardwareInterruptHandle = NULL;\r
+\r
+//\r
+// The protocol instance produced by this driver\r
+//\r
+EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {\r
+ RegisterInterruptSource,\r
+ EnableInterruptSource,\r
+ DisableInterruptSource,\r
+ GetInterruptSourceState,\r
+ EndOfInterrupt\r
+};\r
+\r
+/**\r
+ Shutdown our hardware\r
+ \r
+ DXE Core will disable interrupts and turn off the timer and disable interrupts\r
+ after all the event handlers have run.\r
+\r
+ @param[in] Event The Event that is being processed\r
+ @param[in] Context Event Context\r
+**/\r
+VOID\r
+EFIAPI\r
+ExitBootServicesEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UINTN Index;\r
+ \r
+ // Acknowledge all pending interrupts\r
+ for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
+ DisableInterruptSource (&gHardwareInterruptProtocol, Index);\r
+ }\r
+\r
+ for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
+ EndOfInterrupt (&gHardwareInterruptProtocol, Index);\r
+ }\r
+\r
+ // Disable Gic Interface\r
+ MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x0);\r
+ MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0x0);\r
+\r
+ // Disable Gic Distributor\r
+ MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x0);\r
+}\r
+\r
+/**\r
+ Initialize the state information for the CPU Architectural Protocol\r
+\r
+ @param ImageHandle of the loaded driver\r
+ @param SystemTable Pointer to the System Table\r
+\r
+ @retval EFI_SUCCESS Protocol registered\r
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
+ @retval EFI_DEVICE_ERROR Hardware problems\r
+\r
+**/\r
+EFI_STATUS\r
+InterruptDxeInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ EFI_CPU_ARCH_PROTOCOL *Cpu;\r
+ UINT32 CpuTarget;\r
+ \r
+ // Check PcdGicPrimaryCoreId has been set in case the Primary Core is not the core 0 of Cluster 0\r
+ DEBUG_CODE_BEGIN();\r
+ if ((PcdGet32(PcdArmPrimaryCore) != 0) && (PcdGet32 (PcdGicPrimaryCoreId) == 0)) {\r
+ DEBUG((EFI_D_WARN,"Warning: the PCD PcdGicPrimaryCoreId does not seem to be set up for the configuration.\n"));\r
+ }\r
+ DEBUG_CODE_END();\r
+\r
+ // Make sure the Interrupt Controller Protocol is not already installed in the system.\r
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
+\r
+ mGicNumInterrupts = ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase));\r
+\r
+ for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
+ DisableInterruptSource (&gHardwareInterruptProtocol, Index);\r
+ \r
+ // Set Priority \r
+ RegOffset = Index / 4;\r
+ RegShift = (Index % 4) * 8;\r
+ MmioAndThenOr32 (\r
+ PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPR + (4*RegOffset),\r
+ ~(0xff << RegShift), \r
+ ARM_GIC_DEFAULT_PRIORITY << RegShift\r
+ );\r
+ }\r
+\r
+ //\r
+ // Targets the interrupts to the Primary Cpu\r
+ //\r
+\r
+ // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading\r
+ // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each\r
+ // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31.\r
+ // More Info in the GIC Specification about "Interrupt Processor Targets Registers"\r
+ //\r
+ // Read the first Interrupt Processor Targets Register (that corresponds to the 4\r
+ // first SGIs)\r
+ CpuTarget = MmioRead32 (PcdGet32 (PcdGicDistributorBase) + ARM_GIC_ICDIPTR);\r
+\r
+ // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value\r
+ // cannot be 0.\r
+ ASSERT (CpuTarget != 0);\r
+\r
+ // The 8 first Interrupt Processor Targets Registers are read-only\r
+ for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {\r
+ MmioWrite32 (PcdGet32 (PcdGicDistributorBase) + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget);\r
+ }\r
+\r
+ // Set binary point reg to 0x7 (no preemption)\r
+ MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCBPR, 0x7);\r
+\r
+ // Set priority mask reg to 0xff to allow all priorities through\r
+ MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0xff);\r
+ \r
+ // Enable gic cpu interface\r
+ MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x1);\r
+\r
+ // Enable gic distributor\r
+ MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x1);\r
+ \r
+ // Initialize the array for the Interrupt Handlers\r
+ gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);\r
+ \r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &gHardwareInterruptHandle,\r
+ &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ //\r
+ // Get the CPU protocol that this driver requires.\r
+ //\r
+ Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ //\r
+ // Unregister the default exception handler.\r
+ //\r
+ Status = Cpu->RegisterInterruptHandler(Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ //\r
+ // Register to receive interrupts\r
+ //\r
+ Status = Cpu->RegisterInterruptHandler(Cpu, ARM_ARCH_EXCEPTION_IRQ, IrqInterruptHandler);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ // Register for an ExitBootServicesEvent\r
+ Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r