--- /dev/null
+/** @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