a3f98646 |
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 |
026e30c4 |
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 |
a3f98646 |
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 |
026e30c4 |
128 | MmioWrite32 (INTCPS_MIR_CLEAR(Bank), Bit);\r |
a3f98646 |
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 |
026e30c4 |
162 | MmioWrite32 (INTCPS_MIR_SET(Bank), Bit);\r |
a3f98646 |
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 |
026e30c4 |
238 | MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r |
a3f98646 |
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 |
026e30c4 |
247 | MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r |
a3f98646 |
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 |
026e30c4 |
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 |
a3f98646 |
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 |