]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BeagleBoardPkg/InterruptDxe/HardwareInterrupt.c
Adding support for BeagleBoard.
[mirror_edk2.git] / BeagleBoardPkg / InterruptDxe / HardwareInterrupt.c
diff --git a/BeagleBoardPkg/InterruptDxe/HardwareInterrupt.c b/BeagleBoardPkg/InterruptDxe/HardwareInterrupt.c
new file mode 100644 (file)
index 0000000..97361ff
--- /dev/null
@@ -0,0 +1,339 @@
+/** @file\r
+  Template for Metronome Architecture Protocol driver of the ARM flavor\r
+\r
+  Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
+  \r
+  All rights reserved. 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
+**/\r
+#include <PiDxe.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+#include <Protocol/HardwareInterrupt.h>\r
+\r
+#include <Omap3530/Omap3530.h>\r
+\r
+//\r
+// Notifications\r
+//\r
+VOID      *CpuProtocolNotificationToken = NULL;\r
+EFI_EVENT CpuProtocolNotificationEvent  = (EFI_EVENT)NULL;\r
+EFI_EVENT EfiExitBootServicesEvent      = (EFI_EVENT)NULL;\r
+\r
+\r
+HARDWARE_INTERRUPT_HANDLER  gRegisteredInterruptHandlers[INT_NROF_VECTORS];\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
+  // Disable all interrupts\r
+  MmioWrite32(INTCPS_MIR(0), 0xFFFFFFFF);\r
+  MmioWrite32(INTCPS_MIR(1), 0xFFFFFFFF);\r
+  MmioWrite32(INTCPS_MIR(2), 0xFFFFFFFF);\r
+  MmioWrite32(INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
+}\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 > MAX_VECTOR) {\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
+  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
+  UINTN Bank;\r
+  UINTN Bit;\r
+  \r
+  if (Source > MAX_VECTOR) {\r
+    ASSERT(FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  Bank = Source / 32;\r
+  Bit  = 1UL << (Source % 32);\r
+  \r
+  MmioWrite32(INTCPS_MIR_CLEAR(Bank), Bit);\r
+  \r
+  return EFI_SUCCESS;\r
+}\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
+  UINTN Bank;\r
+  UINTN Bit;\r
+  \r
+  if (Source > MAX_VECTOR) {\r
+    ASSERT(FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  Bank = Source / 32;\r
+  Bit  = 1UL << (Source % 32);\r
+  \r
+  MmioWrite32(INTCPS_MIR_SET(Bank), Bit);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\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
+  UINTN Bank;\r
+  UINTN Bit;\r
+  \r
+  if (InterruptState == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if (Source > MAX_VECTOR) {\r
+    ASSERT(FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Bank = Source / 32;\r
+  Bit  = 1UL << (Source % 32);\r
+    \r
+  if ((MmioRead32(INTCPS_MIR(Bank)) & Bit) == Bit) {\r
+    *InterruptState = FALSE;\r
+  } else {\r
+    *InterruptState = TRUE;\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\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                     Vector;\r
+  HARDWARE_INTERRUPT_HANDLER InterruptHandler;\r
+  \r
+  Vector = MmioRead32(INTCPS_SIR_IRQ) & INTCPS_SIR_IRQ_MASK;\r
+\r
+  InterruptHandler = gRegisteredInterruptHandlers[Vector];\r
+  if (InterruptHandler != NULL) {\r
+    // Call the registered interrupt handler.\r
+    InterruptHandler(Vector, SystemContext);\r
+  }\r
+  \r
+  MmioWrite32(INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\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
+};\r
+\r
+//\r
+// Notification routines\r
+//\r
+VOID\r
+CpuProtocolInstalledNotification (\r
+  IN EFI_EVENT   Event,\r
+  IN VOID        *Context\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_CPU_ARCH_PROTOCOL   *Cpu;\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, EXCEPT_ARM_IRQ, NULL);\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  //\r
+  // Register to receive interrupts\r
+  //\r
+  Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);\r
+  ASSERT_EFI_ERROR(Status);\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
+\r
+  // Make sure the Interrupt Controller Protocol is not already installed in the system.\r
+  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
+\r
+  // Make sure all interrupts are disabled by default.\r
+  MmioWrite32(INTCPS_MIR(0), 0xFFFFFFFF);\r
+  MmioWrite32(INTCPS_MIR(1), 0xFFFFFFFF);\r
+  MmioWrite32(INTCPS_MIR(2), 0xFFFFFFFF);\r
+  MmioWrite32(INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
\r
+  Status = gBS->InstallMultipleProtocolInterfaces(&gHardwareInterruptHandle,\r
+                                                  &gHardwareInterruptProtocolGuid,   &gHardwareInterruptProtocol,\r
+                                                  NULL);\r
+  ASSERT_EFI_ERROR(Status);\r
+  \r
+  // Set up to be notified when the Cpu protocol is installed.\r
+  Status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuProtocolInstalledNotification, NULL, &CpuProtocolNotificationEvent);    \r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  Status = gBS->RegisterProtocolNotify(&gEfiCpuArchProtocolGuid, CpuProtocolNotificationEvent, (VOID *)&CpuProtocolNotificationToken);\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
+\r