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