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