]> git.proxmox.com Git - mirror_edk2.git/blob - ArmEbPkg/InterruptDxe/InterruptDxe.c
Update the copyright notice format
[mirror_edk2.git] / ArmEbPkg / InterruptDxe / InterruptDxe.c
1 /*++
2
3 Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
4 Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 Module Name:
14
15 Gic.c
16
17 Abstract:
18
19 Driver implementing the GIC interrupt controller protocol
20
21 --*/
22
23 #include <PiDxe.h>
24
25 #include <Library/BaseLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiLib.h>
30 #include <Library/PcdLib.h>
31 #include <Library/IoLib.h>
32
33 #include <Protocol/Cpu.h>
34 #include <Protocol/HardwareInterrupt.h>
35
36
37 //
38 // EB board definitions
39 //
40 #define EB_GIC1_CPU_INTF_BASE 0x10040000
41 #define EB_GIC1_DIST_BASE 0x10041000
42 #define EB_GIC2_CPU_INTF_BASE 0x10050000
43 #define EB_GIC2_DIST_BASE 0x10051000
44 #define EB_GIC3_CPU_INTF_BASE 0x10060000
45 #define EB_GIC3_DIST_BASE 0x10061000
46 #define EB_GIC4_CPU_INTF_BASE 0x10070000
47 #define EB_GIC5_DIST_BASE 0x10071000
48
49 // number of interrupts sources supported by each GIC on the EB
50 #define EB_NUM_GIC_INTERRUPTS 96
51
52 // number of 32-bit registers needed to represent those interrupts as a bit
53 // (used for enable set, enable clear, pending set, pending clear, and active regs)
54 #define EB_NUM_GIC_REG_PER_INT_BITS (EB_NUM_GIC_INTERRUPTS / 32)
55
56 // number of 32-bit registers needed to represent those interrupts as two bits
57 // (used for configuration reg)
58 #define EB_NUM_GIC_REG_PER_INT_CFG (EB_NUM_GIC_INTERRUPTS / 16)
59
60 // number of 32-bit registers needed to represent interrupts as 8-bit priority field
61 // (used for priority regs)
62 #define EB_NUM_GIC_REG_PER_INT_BYTES (EB_NUM_GIC_INTERRUPTS / 4)
63
64 #define GIC_DEFAULT_PRIORITY 0x80
65
66 //
67 // GIC definitions
68 //
69
70 // Distributor
71 #define GIC_ICDDCR 0x000 // Distributor Control Register
72 #define GIC_ICDICTR 0x004 // Interrupt Controller Type Register
73 #define GIC_ICDIIDR 0x008 // Implementer Identification Register
74
75 // each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BITS (see GIC spec)
76 #define GIC_ICDISR 0x080 // Interrupt Security Registers
77 #define GIC_ICDISER 0x100 // Interrupt Set-Enable Registers
78 #define GIC_ICDICER 0x180 // Interrupt Clear-Enable Registers
79 #define GIC_ICDSPR 0x200 // Interrupt Set-Pending Registers
80 #define GIC_ICDCPR 0x280 // Interrupt Clear-Pending Registers
81 #define GIC_ICDABR 0x300 // Active Bit Registers
82
83 // each reg base below repeats for EB_NUM_GIC_REG_PER_INT_BYTES
84 #define GIC_ICDIPR 0x400 // Interrupt Priority Registers
85
86 // each reg base below repeats for EB_NUM_GIC_INTERRUPTS
87 #define GIC_ICDIPTR 0x800 // Interrupt Processor Target Registers
88 #define GIC_ICDICFR 0xC00 // Interrupt Configuration Registers
89
90 // just one of these
91 #define GIC_ICDSGIR 0xF00 // Software Generated Interrupt Register
92
93
94 // Cpu interface
95 #define GIC_ICCICR 0x00 // CPU Interface Controler Register
96 #define GIC_ICCPMR 0x04 // Interrupt Priority Mask Register
97 #define GIC_ICCBPR 0x08 // Binary Point Register
98 #define GIC_ICCIAR 0x0C // Interrupt Acknowledge Register
99 #define GIC_ICCEIOR 0x10 // End Of Interrupt Register
100 #define GIC_ICCRPR 0x14 // Running Priority Register
101 #define GIC_ICCPIR 0x18 // Highest Pending Interrupt Register
102 #define GIC_ICCABPR 0x1C // Aliased Binary Point Register
103 #define GIC_ICCIDR 0xFC // Identification Register
104
105 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol;
106
107 //
108 // Notifications
109 //
110 VOID *CpuProtocolNotificationToken = NULL;
111 EFI_EVENT CpuProtocolNotificationEvent = (EFI_EVENT)NULL;
112 EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
113
114
115 HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[EB_NUM_GIC_INTERRUPTS];
116
117 /**
118 Register Handler for the specified interrupt source.
119
120 @param This Instance pointer for this protocol
121 @param Source Hardware source of the interrupt
122 @param Handler Callback for interrupt. NULL to unregister
123
124 @retval EFI_SUCCESS Source was updated to support Handler.
125 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
126
127 **/
128 EFI_STATUS
129 EFIAPI
130 RegisterInterruptSource (
131 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
132 IN HARDWARE_INTERRUPT_SOURCE Source,
133 IN HARDWARE_INTERRUPT_HANDLER Handler
134 )
135 {
136 if (Source > EB_NUM_GIC_INTERRUPTS) {
137 ASSERT(FALSE);
138 return EFI_UNSUPPORTED;
139 }
140
141 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
142 return EFI_INVALID_PARAMETER;
143 }
144
145 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
146 return EFI_ALREADY_STARTED;
147 }
148
149 gRegisteredInterruptHandlers[Source] = Handler;
150 return This->EnableInterruptSource(This, Source);
151 }
152
153
154 /**
155 Enable interrupt source Source.
156
157 @param This Instance pointer for this protocol
158 @param Source Hardware source of the interrupt
159
160 @retval EFI_SUCCESS Source interrupt enabled.
161 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
162
163 **/
164 EFI_STATUS
165 EFIAPI
166 EnableInterruptSource (
167 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
168 IN HARDWARE_INTERRUPT_SOURCE Source
169 )
170 {
171 UINT32 RegOffset;
172 UINTN RegShift;
173
174 if (Source > EB_NUM_GIC_INTERRUPTS) {
175 ASSERT(FALSE);
176 return EFI_UNSUPPORTED;
177 }
178
179 // calculate enable register offset and bit position
180 RegOffset = Source / 32;
181 RegShift = Source % 32;
182
183 // write set-enable register
184 MmioWrite32 (EB_GIC1_DIST_BASE+GIC_ICDISER+(4*RegOffset), 1 << RegShift);
185
186 return EFI_SUCCESS;
187 }
188
189
190 /**
191 Disable interrupt source Source.
192
193 @param This Instance pointer for this protocol
194 @param Source Hardware source of the interrupt
195
196 @retval EFI_SUCCESS Source interrupt disabled.
197 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
198
199 **/
200 EFI_STATUS
201 EFIAPI
202 DisableInterruptSource (
203 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
204 IN HARDWARE_INTERRUPT_SOURCE Source
205 )
206 {
207 UINT32 RegOffset;
208 UINTN RegShift;
209
210 if (Source > EB_NUM_GIC_INTERRUPTS) {
211 ASSERT(FALSE);
212 return EFI_UNSUPPORTED;
213 }
214
215 // calculate enable register offset and bit position
216 RegOffset = Source / 32;
217 RegShift = Source % 32;
218
219 // write set-enable register
220 MmioWrite32 (EB_GIC1_DIST_BASE+GIC_ICDICER+(4*RegOffset), 1 << RegShift);
221
222 return EFI_SUCCESS;
223 }
224
225
226
227 /**
228 Return current state of interrupt source Source.
229
230 @param This Instance pointer for this protocol
231 @param Source Hardware source of the interrupt
232 @param InterruptState TRUE: source enabled, FALSE: source disabled.
233
234 @retval EFI_SUCCESS InterruptState is valid
235 @retval EFI_DEVICE_ERROR InterruptState is not valid
236
237 **/
238 EFI_STATUS
239 EFIAPI
240 GetInterruptSourceState (
241 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
242 IN HARDWARE_INTERRUPT_SOURCE Source,
243 IN BOOLEAN *InterruptState
244 )
245 {
246 UINT32 RegOffset;
247 UINTN RegShift;
248
249 if (Source > EB_NUM_GIC_INTERRUPTS) {
250 ASSERT(FALSE);
251 return EFI_UNSUPPORTED;
252 }
253
254 // calculate enable register offset and bit position
255 RegOffset = Source / 32;
256 RegShift = Source % 32;
257
258 if ((MmioRead32 (EB_GIC1_DIST_BASE+GIC_ICDISER+(4*RegOffset)) & (1<<RegShift)) == 0) {
259 *InterruptState = FALSE;
260 } else {
261 *InterruptState = TRUE;
262 }
263
264 return EFI_SUCCESS;
265 }
266
267 /**
268 Signal to the hardware that the End Of Intrrupt state
269 has been reached.
270
271 @param This Instance pointer for this protocol
272 @param Source Hardware source of the interrupt
273
274 @retval EFI_SUCCESS Source interrupt EOI'ed.
275 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
276
277 **/
278 EFI_STATUS
279 EFIAPI
280 EndOfInterrupt (
281 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
282 IN HARDWARE_INTERRUPT_SOURCE Source
283 )
284 {
285 if (Source > EB_NUM_GIC_INTERRUPTS) {
286 ASSERT(FALSE);
287 return EFI_UNSUPPORTED;
288 }
289
290 MmioWrite32 (EB_GIC1_CPU_INTF_BASE+GIC_ICCEIOR, Source);
291 return EFI_SUCCESS;
292 }
293
294
295 /**
296 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
297
298 @param InterruptType Defines the type of interrupt or exception that
299 occurred on the processor.This parameter is processor architecture specific.
300 @param SystemContext A pointer to the processor context when
301 the interrupt occurred on the processor.
302
303 @return None
304
305 **/
306 VOID
307 EFIAPI
308 IrqInterruptHandler (
309 IN EFI_EXCEPTION_TYPE InterruptType,
310 IN EFI_SYSTEM_CONTEXT SystemContext
311 )
312 {
313 UINT32 GicInterrupt;
314 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
315
316 GicInterrupt = MmioRead32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCIAR);
317 if (GicInterrupt >= EB_NUM_GIC_INTERRUPTS) {
318 MmioWrite32 (EB_GIC1_CPU_INTF_BASE+GIC_ICCEIOR, GicInterrupt);
319 }
320
321 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
322 if (InterruptHandler != NULL) {
323 // Call the registered interrupt handler.
324 InterruptHandler (GicInterrupt, SystemContext);
325 } else {
326 DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: %x\n", GicInterrupt));
327 }
328
329 EndOfInterrupt (&gHardwareInterruptProtocol, GicInterrupt);
330 }
331
332
333 //
334 // Making this global saves a few bytes in image size
335 //
336 EFI_HANDLE gHardwareInterruptHandle = NULL;
337
338 //
339 // The protocol instance produced by this driver
340 //
341 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {
342 RegisterInterruptSource,
343 EnableInterruptSource,
344 DisableInterruptSource,
345 GetInterruptSourceState,
346 EndOfInterrupt
347 };
348
349
350 /**
351 Shutdown our hardware
352
353 DXE Core will disable interrupts and turn off the timer and disable interrupts
354 after all the event handlers have run.
355
356 @param[in] Event The Event that is being processed
357 @param[in] Context Event Context
358 **/
359 VOID
360 EFIAPI
361 ExitBootServicesEvent (
362 IN EFI_EVENT Event,
363 IN VOID *Context
364 )
365 {
366 UINTN i;
367
368 for (i = 0; i < EB_NUM_GIC_INTERRUPTS; i++) {
369 DisableInterruptSource (&gHardwareInterruptProtocol, i);
370 }
371 }
372
373
374 //
375 // Notification routines
376 //
377 VOID
378 CpuProtocolInstalledNotification (
379 IN EFI_EVENT Event,
380 IN VOID *Context
381 )
382 {
383 EFI_STATUS Status;
384 EFI_CPU_ARCH_PROTOCOL *Cpu;
385
386 //
387 // Get the cpu protocol that this driver requires.
388 //
389 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
390 ASSERT_EFI_ERROR(Status);
391
392 //
393 // Unregister the default exception handler.
394 //
395 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL);
396 ASSERT_EFI_ERROR(Status);
397
398 //
399 // Register to receive interrupts
400 //
401 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);
402 ASSERT_EFI_ERROR(Status);
403 }
404
405 /**
406 Initialize the state information for the CPU Architectural Protocol
407
408 @param ImageHandle of the loaded driver
409 @param SystemTable Pointer to the System Table
410
411 @retval EFI_SUCCESS Protocol registered
412 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
413 @retval EFI_DEVICE_ERROR Hardware problems
414
415 **/
416 EFI_STATUS
417 InterruptDxeInitialize (
418 IN EFI_HANDLE ImageHandle,
419 IN EFI_SYSTEM_TABLE *SystemTable
420 )
421 {
422 EFI_STATUS Status;
423 UINTN i;
424 UINT32 RegOffset;
425 UINTN RegShift;
426
427
428 // Make sure the Interrupt Controller Protocol is not already installed in the system.
429 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
430
431 for (i = 0; i < EB_NUM_GIC_INTERRUPTS; i++) {
432 DisableInterruptSource (&gHardwareInterruptProtocol, i);
433
434 // Set Priority
435 RegOffset = i / 4;
436 RegShift = (i % 4) * 8;
437 MmioAndThenOr32 (
438 EB_GIC1_DIST_BASE+GIC_ICDIPR+(4*RegOffset),
439 ~(0xff << RegShift),
440 GIC_DEFAULT_PRIORITY << RegShift
441 );
442 }
443
444 // configure interrupts for cpu 0
445 for (i = 0; i < EB_NUM_GIC_REG_PER_INT_BYTES; i++) {
446 MmioWrite32 (EB_GIC1_DIST_BASE + GIC_ICDIPTR + (i*4), 0x01010101);
447 }
448
449 // set binary point reg to 0x7 (no preemption)
450 MmioWrite32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCBPR, 0x7);
451
452 // set priority mask reg to 0xff to allow all priorities through
453 MmioWrite32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCPMR, 0xff);
454
455 // enable gic cpu interface
456 MmioWrite32 (EB_GIC1_CPU_INTF_BASE + GIC_ICCICR, 0x1);
457
458 // enable gic distributor
459 MmioWrite32 (EB_GIC1_DIST_BASE + GIC_ICCICR, 0x1);
460
461
462 ZeroMem (&gRegisteredInterruptHandlers, sizeof (gRegisteredInterruptHandlers));
463
464 Status = gBS->InstallMultipleProtocolInterfaces (
465 &gHardwareInterruptHandle,
466 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,
467 NULL
468 );
469 ASSERT_EFI_ERROR (Status);
470
471 // Set up to be notified when the Cpu protocol is installed.
472 Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuProtocolInstalledNotification, NULL, &CpuProtocolNotificationEvent);
473 ASSERT_EFI_ERROR (Status);
474
475 Status = gBS->RegisterProtocolNotify (&gEfiCpuArchProtocolGuid, CpuProtocolNotificationEvent, (VOID *)&CpuProtocolNotificationToken);
476 ASSERT_EFI_ERROR (Status);
477
478 // Register for an ExitBootServicesEvent
479 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
480 ASSERT_EFI_ERROR (Status);
481
482 return Status;
483 }
484