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