Cleanup SerailIO drivers to have a device path and use PCD settings for various stuff...
[mirror_edk2.git] / Omap35xxPkg / InterruptDxe / HardwareInterrupt.c
1 /** @file\r
2   Template for Metronome Architecture Protocol driver of the ARM flavor\r
3 \r
4   Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
5   \r
6   All rights reserved. This program and the accompanying materials\r
7   are licensed and made available under the terms and conditions of the BSD License\r
8   which accompanies this distribution.  The full text of the license may be found at\r
9   http://opensource.org/licenses/bsd-license.php\r
10 \r
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 #include <PiDxe.h>\r
16 \r
17 #include <Library/BaseLib.h>\r
18 #include <Library/DebugLib.h>\r
19 #include <Library/BaseMemoryLib.h>\r
20 #include <Library/UefiBootServicesTableLib.h>\r
21 #include <Library/UefiLib.h>\r
22 #include <Library/PcdLib.h>\r
23 #include <Library/IoLib.h>\r
24 \r
25 #include <Protocol/Cpu.h>\r
26 #include <Protocol/HardwareInterrupt.h>\r
27 \r
28 #include <Omap3530/Omap3530.h>\r
29 \r
30 //\r
31 // Notifications\r
32 //\r
33 VOID      *CpuProtocolNotificationToken = NULL;\r
34 EFI_EVENT CpuProtocolNotificationEvent  = (EFI_EVENT)NULL;\r
35 EFI_EVENT EfiExitBootServicesEvent      = (EFI_EVENT)NULL;\r
36 \r
37 \r
38 HARDWARE_INTERRUPT_HANDLER  gRegisteredInterruptHandlers[INT_NROF_VECTORS];\r
39 \r
40 /**\r
41   Shutdown our hardware\r
42   \r
43   DXE Core will disable interrupts and turn off the timer and disable interrupts\r
44   after all the event handlers have run.\r
45 \r
46   @param[in]  Event   The Event that is being processed\r
47   @param[in]  Context Event Context\r
48 **/\r
49 VOID\r
50 EFIAPI\r
51 ExitBootServicesEvent (\r
52   IN EFI_EVENT  Event,\r
53   IN VOID       *Context\r
54   )\r
55 {\r
56   // Disable all interrupts\r
57   MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);\r
58   MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);\r
59   MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);\r
60   MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
61 }\r
62 \r
63 /**\r
64   Register Handler for the specified interrupt source.\r
65 \r
66   @param This     Instance pointer for this protocol\r
67   @param Source   Hardware source of the interrupt\r
68   @param Handler  Callback for interrupt. NULL to unregister\r
69 \r
70   @retval EFI_SUCCESS Source was updated to support Handler.\r
71   @retval EFI_DEVICE_ERROR  Hardware could not be programmed.\r
72 \r
73 **/\r
74 EFI_STATUS\r
75 EFIAPI\r
76 RegisterInterruptSource (\r
77   IN EFI_HARDWARE_INTERRUPT_PROTOCOL    *This,\r
78   IN HARDWARE_INTERRUPT_SOURCE          Source,\r
79   IN HARDWARE_INTERRUPT_HANDLER         Handler\r
80   )\r
81 {\r
82   if (Source > MAX_VECTOR) {\r
83     ASSERT(FALSE);\r
84     return EFI_UNSUPPORTED;\r
85   } \r
86   \r
87   if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {\r
88     return EFI_INVALID_PARAMETER;\r
89   }\r
90 \r
91   if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {\r
92     return EFI_ALREADY_STARTED;\r
93   }\r
94 \r
95   gRegisteredInterruptHandlers[Source] = Handler;\r
96   return This->EnableInterruptSource(This, Source);\r
97 }\r
98 \r
99 \r
100 /**\r
101   Enable interrupt source Source.\r
102 \r
103   @param This     Instance pointer for this protocol\r
104   @param Source   Hardware source of the interrupt\r
105 \r
106   @retval EFI_SUCCESS       Source interrupt enabled.\r
107   @retval EFI_DEVICE_ERROR  Hardware could not be programmed.\r
108 \r
109 **/\r
110 EFI_STATUS\r
111 EFIAPI\r
112 EnableInterruptSource (\r
113   IN EFI_HARDWARE_INTERRUPT_PROTOCOL    *This,\r
114   IN HARDWARE_INTERRUPT_SOURCE          Source\r
115   )\r
116 {\r
117   UINTN Bank;\r
118   UINTN Bit;\r
119   \r
120   if (Source > MAX_VECTOR) {\r
121     ASSERT(FALSE);\r
122     return EFI_UNSUPPORTED;\r
123   }\r
124   \r
125   Bank = Source / 32;\r
126   Bit  = 1UL << (Source % 32);\r
127   \r
128   MmioWrite32 (INTCPS_MIR_CLEAR(Bank), Bit);\r
129   \r
130   return EFI_SUCCESS;\r
131 }\r
132 \r
133 \r
134 /**\r
135   Disable interrupt source Source.\r
136 \r
137   @param This     Instance pointer for this protocol\r
138   @param Source   Hardware source of the interrupt\r
139 \r
140   @retval EFI_SUCCESS       Source interrupt disabled.\r
141   @retval EFI_DEVICE_ERROR  Hardware could not be programmed.\r
142 \r
143 **/\r
144 EFI_STATUS\r
145 EFIAPI\r
146 DisableInterruptSource(\r
147   IN EFI_HARDWARE_INTERRUPT_PROTOCOL    *This,\r
148   IN HARDWARE_INTERRUPT_SOURCE          Source\r
149   )\r
150 {\r
151   UINTN Bank;\r
152   UINTN Bit;\r
153   \r
154   if (Source > MAX_VECTOR) {\r
155     ASSERT(FALSE);\r
156     return EFI_UNSUPPORTED;\r
157   }\r
158   \r
159   Bank = Source / 32;\r
160   Bit  = 1UL << (Source % 32);\r
161   \r
162   MmioWrite32 (INTCPS_MIR_SET(Bank), Bit);\r
163   \r
164   return EFI_SUCCESS;\r
165 }\r
166 \r
167 \r
168 \r
169 /**\r
170   Return current state of interrupt source Source.\r
171 \r
172   @param This     Instance pointer for this protocol\r
173   @param Source   Hardware source of the interrupt\r
174   @param InterruptState  TRUE: source enabled, FALSE: source disabled.\r
175 \r
176   @retval EFI_SUCCESS       InterruptState is valid\r
177   @retval EFI_DEVICE_ERROR  InterruptState is not valid\r
178 \r
179 **/\r
180 EFI_STATUS\r
181 EFIAPI\r
182 GetInterruptSourceState (\r
183   IN EFI_HARDWARE_INTERRUPT_PROTOCOL    *This,\r
184   IN HARDWARE_INTERRUPT_SOURCE          Source,\r
185   IN BOOLEAN                            *InterruptState\r
186   )\r
187 {\r
188   UINTN Bank;\r
189   UINTN Bit;\r
190   \r
191   if (InterruptState == NULL) {\r
192     return EFI_INVALID_PARAMETER;\r
193   }\r
194   \r
195   if (Source > MAX_VECTOR) {\r
196     ASSERT(FALSE);\r
197     return EFI_UNSUPPORTED;\r
198   }\r
199 \r
200   Bank = Source / 32;\r
201   Bit  = 1UL << (Source % 32);\r
202     \r
203   if ((MmioRead32(INTCPS_MIR(Bank)) & Bit) == Bit) {\r
204     *InterruptState = FALSE;\r
205   } else {\r
206     *InterruptState = TRUE;\r
207   }\r
208   \r
209   return EFI_SUCCESS;\r
210 }\r
211 \r
212 \r
213 \r
214 /**\r
215   EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.\r
216 \r
217   @param  InterruptType    Defines the type of interrupt or exception that\r
218                            occurred on the processor.This parameter is processor architecture specific.\r
219   @param  SystemContext    A pointer to the processor context when\r
220                            the interrupt occurred on the processor.\r
221 \r
222   @return None\r
223 \r
224 **/\r
225 VOID\r
226 EFIAPI\r
227 IrqInterruptHandler (\r
228   IN EFI_EXCEPTION_TYPE           InterruptType,\r
229   IN EFI_SYSTEM_CONTEXT           SystemContext\r
230   )\r
231 {\r
232   UINT32                     Vector;\r
233   HARDWARE_INTERRUPT_HANDLER InterruptHandler;\r
234   \r
235   Vector = MmioRead32(INTCPS_SIR_IRQ) & INTCPS_SIR_IRQ_MASK;\r
236 \r
237   // Needed to prevent infinite nesting when Time Driver lowers TPL\r
238   MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
239 \r
240   InterruptHandler = gRegisteredInterruptHandlers[Vector];\r
241   if (InterruptHandler != NULL) {\r
242     // Call the registered interrupt handler.\r
243     InterruptHandler(Vector, SystemContext);\r
244   }\r
245   \r
246   // Needed to clear after running the handler\r
247   MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
248 }\r
249 \r
250 //\r
251 // Making this global saves a few bytes in image size\r
252 //\r
253 EFI_HANDLE  gHardwareInterruptHandle = NULL;\r
254 \r
255 //\r
256 // The protocol instance produced by this driver\r
257 //\r
258 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {\r
259   RegisterInterruptSource,\r
260   EnableInterruptSource,\r
261   DisableInterruptSource,\r
262   GetInterruptSourceState\r
263 };\r
264 \r
265 //\r
266 // Notification routines\r
267 //\r
268 VOID\r
269 CpuProtocolInstalledNotification (\r
270   IN EFI_EVENT   Event,\r
271   IN VOID        *Context\r
272   )\r
273 {\r
274   EFI_STATUS              Status;\r
275   EFI_CPU_ARCH_PROTOCOL   *Cpu;\r
276   \r
277   //\r
278   // Get the cpu protocol that this driver requires.\r
279   //\r
280   Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
281   ASSERT_EFI_ERROR(Status);\r
282 \r
283   //\r
284   // Unregister the default exception handler.\r
285   //\r
286   Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL);\r
287   ASSERT_EFI_ERROR(Status);\r
288 \r
289   //\r
290   // Register to receive interrupts\r
291   //\r
292   Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);\r
293   ASSERT_EFI_ERROR(Status);\r
294 }\r
295 \r
296 /**\r
297   Initialize the state information for the CPU Architectural Protocol\r
298 \r
299   @param  ImageHandle   of the loaded driver\r
300   @param  SystemTable   Pointer to the System Table\r
301 \r
302   @retval EFI_SUCCESS           Protocol registered\r
303   @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure\r
304   @retval EFI_DEVICE_ERROR      Hardware problems\r
305 \r
306 **/\r
307 EFI_STATUS\r
308 InterruptDxeInitialize (\r
309   IN EFI_HANDLE         ImageHandle,\r
310   IN EFI_SYSTEM_TABLE   *SystemTable\r
311   )\r
312 {\r
313   EFI_STATUS  Status;\r
314 \r
315   // Make sure the Interrupt Controller Protocol is not already installed in the system.\r
316   ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
317 \r
318   // Make sure all interrupts are disabled by default.\r
319   MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);\r
320   MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);\r
321   MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);\r
322   MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
323  \r
324   Status = gBS->InstallMultipleProtocolInterfaces(&gHardwareInterruptHandle,\r
325                                                   &gHardwareInterruptProtocolGuid,   &gHardwareInterruptProtocol,\r
326                                                   NULL);\r
327   ASSERT_EFI_ERROR(Status);\r
328   \r
329   // Set up to be notified when the Cpu protocol is installed.\r
330   Status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuProtocolInstalledNotification, NULL, &CpuProtocolNotificationEvent);    \r
331   ASSERT_EFI_ERROR(Status);\r
332 \r
333   Status = gBS->RegisterProtocolNotify(&gEfiCpuArchProtocolGuid, CpuProtocolNotificationEvent, (VOID *)&CpuProtocolNotificationToken);\r
334   ASSERT_EFI_ERROR(Status);\r
335 \r
336   // Register for an ExitBootServicesEvent\r
337   Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);\r
338   ASSERT_EFI_ERROR(Status);\r
339 \r
340   return Status;\r
341 }\r
342 \r