blob: 0ddedb4c79c744fe547dece709cb6fbbd94e4500 [file] [log] [blame]
andrewfisha3f98642010-01-28 21:32:01 +00001/** @file
andrewfish026c3d32010-02-24 22:38:46 +00002 Handle OMAP35xx interrupt controller
andrewfisha3f98642010-01-28 21:32:01 +00003
hhtian3d706432010-04-29 12:46:45 +00004 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
andrewfisha3f98642010-01-28 21:32:01 +00005
hhtian3d706432010-04-29 12:46:45 +00006 This program and the accompanying materials
andrewfisha3f98642010-01-28 21:32:01 +00007 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>
andrewfish026c3d32010-02-24 22:38:46 +000024#include <Library/ArmLib.h>
andrewfisha3f98642010-01-28 21:32:01 +000025
26#include <Protocol/Cpu.h>
27#include <Protocol/HardwareInterrupt.h>
28
29#include <Omap3530/Omap3530.h>
30
31//
32// Notifications
33//
34VOID *CpuProtocolNotificationToken = NULL;
35EFI_EVENT CpuProtocolNotificationEvent = (EFI_EVENT)NULL;
36EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
37
38
39HARDWARE_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**/
50VOID
51EFIAPI
52ExitBootServicesEvent (
53 IN EFI_EVENT Event,
54 IN VOID *Context
55 )
56{
57 // Disable all interrupts
andrewfish026e30c2010-02-15 20:40:51 +000058 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
59 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
60 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
61 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
andrewfish43263282010-04-03 00:34:19 +000062
63 // Add code here to disable all FIQs as debugger may have turned one on
andrewfisha3f98642010-01-28 21:32:01 +000064}
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**/
77EFI_STATUS
78EFIAPI
79RegisterInterruptSource (
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
andrewfishe9fc14b2010-04-13 22:30:42 +000090 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
andrewfisha3f98642010-01-28 21:32:01 +000098 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**/
121EFI_STATUS
122EFIAPI
123EnableInterruptSource (
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
andrewfish026e30c2010-02-15 20:40:51 +0000139 MmioWrite32 (INTCPS_MIR_CLEAR(Bank), Bit);
andrewfisha3f98642010-01-28 21:32:01 +0000140
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**/
155EFI_STATUS
156EFIAPI
andrewfish026c3d32010-02-24 22:38:46 +0000157DisableInterruptSource (
andrewfisha3f98642010-01-28 21:32:01 +0000158 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
andrewfish026e30c2010-02-15 20:40:51 +0000173 MmioWrite32 (INTCPS_MIR_SET(Bank), Bit);
andrewfisha3f98642010-01-28 21:32:01 +0000174
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**/
191EFI_STATUS
192EFIAPI
193GetInterruptSourceState (
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
andrewfishe9fc14b2010-04-13 22:30:42 +0000214 if ((MmioRead32(INTCPS_MIR(Bank)) & Bit) == Bit) {
andrewfisha3f98642010-01-28 21:32:01 +0000215 *InterruptState = FALSE;
216 } else {
217 *InterruptState = TRUE;
218 }
219
220 return EFI_SUCCESS;
221}
222
andrewfish026c3d32010-02-24 22:38:46 +0000223/**
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**/
234EFI_STATUS
235EFIAPI
236EndOfInterrupt (
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}
andrewfisha3f98642010-01-28 21:32:01 +0000245
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**/
258VOID
259EFIAPI
260IrqInterruptHandler (
261 IN EFI_EXCEPTION_TYPE InterruptType,
262 IN EFI_SYSTEM_CONTEXT SystemContext
263 )
264{
265 UINT32 Vector;
266 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
267
andrewfish026c3d32010-02-24 22:38:46 +0000268 Vector = MmioRead32 (INTCPS_SIR_IRQ) & INTCPS_SIR_IRQ_MASK;
andrewfisha3f98642010-01-28 21:32:01 +0000269
270 // Needed to prevent infinite nesting when Time Driver lowers TPL
andrewfish026e30c2010-02-15 20:40:51 +0000271 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
andrewfish026c3d32010-02-24 22:38:46 +0000272 ArmDataSyncronizationBarrier ();
273
andrewfisha3f98642010-01-28 21:32:01 +0000274 InterruptHandler = gRegisteredInterruptHandlers[Vector];
275 if (InterruptHandler != NULL) {
276 // Call the registered interrupt handler.
andrewfish026c3d32010-02-24 22:38:46 +0000277 InterruptHandler (Vector, SystemContext);
andrewfisha3f98642010-01-28 21:32:01 +0000278 }
279
280 // Needed to clear after running the handler
andrewfish026e30c2010-02-15 20:40:51 +0000281 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
andrewfish026c3d32010-02-24 22:38:46 +0000282 ArmDataSyncronizationBarrier ();
andrewfisha3f98642010-01-28 21:32:01 +0000283}
284
285//
286// Making this global saves a few bytes in image size
287//
288EFI_HANDLE gHardwareInterruptHandle = NULL;
289
290//
291// The protocol instance produced by this driver
292//
293EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {
294 RegisterInterruptSource,
295 EnableInterruptSource,
296 DisableInterruptSource,
andrewfish026c3d32010-02-24 22:38:46 +0000297 GetInterruptSourceState,
298 EndOfInterrupt
andrewfisha3f98642010-01-28 21:32:01 +0000299};
300
301//
302// Notification routines
303//
304VOID
305CpuProtocolInstalledNotification (
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 //
andrewfish026c3d32010-02-24 22:38:46 +0000316 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
andrewfisha3f98642010-01-28 21:32:01 +0000317 ASSERT_EFI_ERROR(Status);
318
319 //
320 // Unregister the default exception handler.
321 //
andrewfish026c3d32010-02-24 22:38:46 +0000322 Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ, NULL);
andrewfisha3f98642010-01-28 21:32:01 +0000323 ASSERT_EFI_ERROR(Status);
324
325 //
326 // Register to receive interrupts
327 //
andrewfish026c3d32010-02-24 22:38:46 +0000328 Status = Cpu->RegisterInterruptHandler (Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);
andrewfisha3f98642010-01-28 21:32:01 +0000329 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**/
343EFI_STATUS
344InterruptDxeInitialize (
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.
andrewfish026e30c2010-02-15 20:40:51 +0000355 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF);
356 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF);
357 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF);
andrewfish41d47802010-03-05 00:57:07 +0000358 MmioOr32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);
andrewfisha3f98642010-01-28 21:32:01 +0000359
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