HardwareInterrupt.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /** @file
  2. Handle OMAP35xx interrupt controller
  3. Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <PiDxe.h>
  7. #include <Library/BaseLib.h>
  8. #include <Library/DebugLib.h>
  9. #include <Library/BaseMemoryLib.h>
  10. #include <Library/UefiBootServicesTableLib.h>
  11. #include <Library/UefiLib.h>
  12. #include <Library/PcdLib.h>
  13. #include <Library/IoLib.h>
  14. #include <Library/ArmLib.h>
  15. #include <Protocol/Cpu.h>
  16. #include <Protocol/HardwareInterrupt.h>
  17. #include <Omap3530/Omap3530.h>
  18. //
  19. // Notifications
  20. //
  21. EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
  22. HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[INT_NROF_VECTORS];
  23. /**
  24. Shutdown our hardware
  25. DXE Core will disable interrupts and turn off the timer and disable interrupts
  26. after all the event handlers have run.
  27. @param[in] Event The Event that is being processed
  28. @param[in] Context Event Context
  29. **/
  30. VOID
  31. EFIAPI
  32. ExitBootServicesEvent (
  33. IN EFI_EVENT Event,
  34. IN VOID *Context
  35. )
  36. {
  37. // Disable all interrupts
  38. MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
  39. MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
  40. MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
  41. MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
  42. // Add code here to disable all FIQs as debugger may have turned one on
  43. }
  44. /**
  45. Register Handler for the specified interrupt source.
  46. @param This Instance pointer for this protocol
  47. @param Source Hardware source of the interrupt
  48. @param Handler Callback for interrupt. NULL to unregister
  49. @retval EFI_SUCCESS Source was updated to support Handler.
  50. @retval EFI_DEVICE_ERROR Hardware could not be programmed.
  51. **/
  52. EFI_STATUS
  53. EFIAPI
  54. RegisterInterruptSource (
  55. IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
  56. IN HARDWARE_INTERRUPT_SOURCE Source,
  57. IN HARDWARE_INTERRUPT_HANDLER Handler
  58. )
  59. {
  60. if (Source > MAX_VECTOR) {
  61. ASSERT(FALSE);
  62. return EFI_UNSUPPORTED;
  63. }
  64. if ((MmioRead32 (INTCPS_ILR(Source)) & INTCPS_ILR_FIQ) == INTCPS_ILR_FIQ) {
  65. // This vector has been programmed as FIQ so we can't use it for IRQ
  66. // EFI does not use FIQ, but the debugger can use it to check for
  67. // ctrl-c. So this ASSERT means you have a conflict with the debug agent
  68. ASSERT (FALSE);
  69. return EFI_UNSUPPORTED;
  70. }
  71. if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
  72. return EFI_INVALID_PARAMETER;
  73. }
  74. if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
  75. return EFI_ALREADY_STARTED;
  76. }
  77. gRegisteredInterruptHandlers[Source] = Handler;
  78. return This->EnableInterruptSource(This, Source);
  79. }
  80. /**
  81. Enable interrupt source Source.
  82. @param This Instance pointer for this protocol
  83. @param Source Hardware source of the interrupt
  84. @retval EFI_SUCCESS Source interrupt enabled.
  85. @retval EFI_DEVICE_ERROR Hardware could not be programmed.
  86. **/
  87. EFI_STATUS
  88. EFIAPI
  89. EnableInterruptSource (
  90. IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
  91. IN HARDWARE_INTERRUPT_SOURCE Source
  92. )
  93. {
  94. UINTN Bank;
  95. UINTN Bit;
  96. if (Source > MAX_VECTOR) {
  97. ASSERT(FALSE);
  98. return EFI_UNSUPPORTED;
  99. }
  100. Bank = Source / 32;
  101. Bit = 1UL << (Source % 32);
  102. MmioWrite32 (INTCPS_MIR_CLEAR(Bank), Bit);
  103. return EFI_SUCCESS;
  104. }
  105. /**
  106. Disable interrupt source Source.
  107. @param This Instance pointer for this protocol
  108. @param Source Hardware source of the interrupt
  109. @retval EFI_SUCCESS Source interrupt disabled.
  110. @retval EFI_DEVICE_ERROR Hardware could not be programmed.
  111. **/
  112. EFI_STATUS
  113. EFIAPI
  114. DisableInterruptSource (
  115. IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
  116. IN HARDWARE_INTERRUPT_SOURCE Source
  117. )
  118. {
  119. UINTN Bank;
  120. UINTN Bit;
  121. if (Source > MAX_VECTOR) {
  122. ASSERT(FALSE);
  123. return EFI_UNSUPPORTED;
  124. }
  125. Bank = Source / 32;
  126. Bit = 1UL << (Source % 32);
  127. MmioWrite32 (INTCPS_MIR_SET(Bank), Bit);
  128. return EFI_SUCCESS;
  129. }
  130. /**
  131. Return current state of interrupt source Source.
  132. @param This Instance pointer for this protocol
  133. @param Source Hardware source of the interrupt
  134. @param InterruptState TRUE: source enabled, FALSE: source disabled.
  135. @retval EFI_SUCCESS InterruptState is valid
  136. @retval EFI_DEVICE_ERROR InterruptState is not valid
  137. **/
  138. EFI_STATUS
  139. EFIAPI
  140. GetInterruptSourceState (
  141. IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
  142. IN HARDWARE_INTERRUPT_SOURCE Source,
  143. IN BOOLEAN *InterruptState
  144. )
  145. {
  146. UINTN Bank;
  147. UINTN Bit;
  148. if (InterruptState == NULL) {
  149. return EFI_INVALID_PARAMETER;
  150. }
  151. if (Source > MAX_VECTOR) {
  152. ASSERT(FALSE);
  153. return EFI_UNSUPPORTED;
  154. }
  155. Bank = Source / 32;
  156. Bit = 1UL << (Source % 32);
  157. if ((MmioRead32(INTCPS_MIR(Bank)) & Bit) == Bit) {
  158. *InterruptState = FALSE;
  159. } else {
  160. *InterruptState = TRUE;
  161. }
  162. return EFI_SUCCESS;
  163. }
  164. /**
  165. Signal to the hardware that the End Of Intrrupt state
  166. has been reached.
  167. @param This Instance pointer for this protocol
  168. @param Source Hardware source of the interrupt
  169. @retval EFI_SUCCESS Source interrupt EOI'ed.
  170. @retval EFI_DEVICE_ERROR Hardware could not be programmed.
  171. **/
  172. EFI_STATUS
  173. EFIAPI
  174. EndOfInterrupt (
  175. IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
  176. IN HARDWARE_INTERRUPT_SOURCE Source
  177. )
  178. {
  179. MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
  180. ArmDataSynchronizationBarrier ();
  181. return EFI_SUCCESS;
  182. }
  183. /**
  184. EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
  185. @param InterruptType Defines the type of interrupt or exception that
  186. occurred on the processor.This parameter is processor architecture specific.
  187. @param SystemContext A pointer to the processor context when
  188. the interrupt occurred on the processor.
  189. @return None
  190. **/
  191. VOID
  192. EFIAPI
  193. IrqInterruptHandler (
  194. IN EFI_EXCEPTION_TYPE InterruptType,
  195. IN EFI_SYSTEM_CONTEXT SystemContext
  196. )
  197. {
  198. UINT32 Vector;
  199. HARDWARE_INTERRUPT_HANDLER InterruptHandler;
  200. Vector = MmioRead32 (INTCPS_SIR_IRQ) & INTCPS_SIR_IRQ_MASK;
  201. // Needed to prevent infinite nesting when Time Driver lowers TPL
  202. MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
  203. ArmDataSynchronizationBarrier ();
  204. InterruptHandler = gRegisteredInterruptHandlers[Vector];
  205. if (InterruptHandler != NULL) {
  206. // Call the registered interrupt handler.
  207. InterruptHandler (Vector, SystemContext);
  208. }
  209. // Needed to clear after running the handler
  210. MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
  211. ArmDataSynchronizationBarrier ();
  212. }
  213. //
  214. // Making this global saves a few bytes in image size
  215. //
  216. EFI_HANDLE gHardwareInterruptHandle = NULL;
  217. //
  218. // The protocol instance produced by this driver
  219. //
  220. EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {
  221. RegisterInterruptSource,
  222. EnableInterruptSource,
  223. DisableInterruptSource,
  224. GetInterruptSourceState,
  225. EndOfInterrupt
  226. };
  227. STATIC VOID *mCpuArchProtocolNotifyEventRegistration;
  228. STATIC
  229. VOID
  230. EFIAPI
  231. CpuArchEventProtocolNotify (
  232. IN EFI_EVENT Event,
  233. IN VOID *Context
  234. )
  235. {
  236. EFI_CPU_ARCH_PROTOCOL *Cpu;
  237. EFI_STATUS Status;
  238. //
  239. // Get the CPU protocol that this driver requires.
  240. //
  241. Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
  242. if (EFI_ERROR (Status)) {
  243. DEBUG ((DEBUG_ERROR, "%a: gBS->LocateProtocol() - %r\n", __FUNCTION__,
  244. Status));
  245. ASSERT (FALSE);
  246. return;
  247. }
  248. //
  249. // Unregister the default exception handler.
  250. //
  251. Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ, NULL);
  252. if (EFI_ERROR (Status)) {
  253. DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",
  254. __FUNCTION__, Status));
  255. ASSERT (FALSE);
  256. return;
  257. }
  258. //
  259. // Register to receive interrupts
  260. //
  261. Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ,
  262. IrqInterruptHandler);
  263. if (EFI_ERROR (Status)) {
  264. DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",
  265. __FUNCTION__, Status));
  266. ASSERT (FALSE);
  267. return;
  268. }
  269. }
  270. /**
  271. Initialize the state information for the CPU Architectural Protocol
  272. @param ImageHandle of the loaded driver
  273. @param SystemTable Pointer to the System Table
  274. @retval EFI_SUCCESS Protocol registered
  275. @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
  276. @retval EFI_DEVICE_ERROR Hardware problems
  277. **/
  278. EFI_STATUS
  279. InterruptDxeInitialize (
  280. IN EFI_HANDLE ImageHandle,
  281. IN EFI_SYSTEM_TABLE *SystemTable
  282. )
  283. {
  284. EFI_STATUS Status;
  285. EFI_EVENT CpuArchEvent;
  286. // Make sure the Interrupt Controller Protocol is not already installed in the system.
  287. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
  288. // Make sure all interrupts are disabled by default.
  289. MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
  290. MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
  291. MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
  292. MmioOr32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
  293. Status = gBS->InstallMultipleProtocolInterfaces(&gHardwareInterruptHandle,
  294. &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,
  295. NULL);
  296. ASSERT_EFI_ERROR(Status);
  297. //
  298. // Install the interrupt handler as soon as the CPU arch protocol appears.
  299. //
  300. CpuArchEvent = EfiCreateProtocolNotifyEvent (
  301. &gEfiCpuArchProtocolGuid,
  302. TPL_CALLBACK,
  303. CpuArchEventProtocolNotify,
  304. NULL,
  305. &mCpuArchProtocolNotifyEventRegistration
  306. );
  307. ASSERT (CpuArchEvent != NULL);
  308. // Register for an ExitBootServicesEvent
  309. Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
  310. if (EFI_ERROR (Status)) {
  311. ASSERT_EFI_ERROR (Status);
  312. gBS->CloseEvent (CpuArchEvent);
  313. }
  314. return Status;
  315. }