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