]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/PL390Gic/PL390GicDxe.c
ARM Packages: Minor typo, mispellings and coding style changes
[mirror_edk2.git] / ArmPkg / Drivers / PL390Gic / PL390GicDxe.c
CommitLineData
1bfda055 1/*++
2
3Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
1bccfbe5 4Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5Portions copyright (c) 2011-2012, ARM Ltd. All rights reserved.<BR>
e9f7c58f 6
1bfda055 7This program and the accompanying materials
8are licensed and made available under the terms and conditions of the BSD License
9which accompanies this distribution. The full text of the license may be found at
10http://opensource.org/licenses/bsd-license.php
11
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15Module Name:
16
17 Gic.c
18
19Abstract:
20
21 Driver implementing the GIC interrupt controller protocol
22
23--*/
24
25#include <PiDxe.h>
26
27#include <Library/BaseLib.h>
28#include <Library/DebugLib.h>
29#include <Library/BaseMemoryLib.h>
e9f7c58f 30#include <Library/MemoryAllocationLib.h>
1bfda055 31#include <Library/UefiBootServicesTableLib.h>
32#include <Library/UefiLib.h>
33#include <Library/PcdLib.h>
34#include <Library/IoLib.h>
55a0d64b 35#include <Library/ArmGicLib.h>
1bfda055 36
37#include <Protocol/Cpu.h>
38#include <Protocol/HardwareInterrupt.h>
39
55a0d64b 40#define ARM_GIC_DEFAULT_PRIORITY 0x80
1bfda055 41
42extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol;
43
44//
45// Notifications
46//
1bfda055 47EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
48
e9f7c58f 49// Maximum Number of Interrupts
50UINTN mGicNumInterrupts = 0;
51
52HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;
1bfda055 53
54/**
55 Register Handler for the specified interrupt source.
56
57 @param This Instance pointer for this protocol
58 @param Source Hardware source of the interrupt
59 @param Handler Callback for interrupt. NULL to unregister
60
61 @retval EFI_SUCCESS Source was updated to support Handler.
62 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
63
64**/
65EFI_STATUS
66EFIAPI
67RegisterInterruptSource (
68 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
69 IN HARDWARE_INTERRUPT_SOURCE Source,
70 IN HARDWARE_INTERRUPT_HANDLER Handler
71 )
72{
e9f7c58f 73 if (Source > mGicNumInterrupts) {
1bfda055 74 ASSERT(FALSE);
75 return EFI_UNSUPPORTED;
43f69915 76 }
1bfda055 77
78 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {
79 return EFI_INVALID_PARAMETER;
80 }
81
82 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {
83 return EFI_ALREADY_STARTED;
84 }
85
86 gRegisteredInterruptHandlers[Source] = Handler;
43f69915 87
88 // If the interrupt handler is unregistered then disable the interrupt
89 if (NULL == Handler){
90 return This->DisableInterruptSource (This, Source);
91 } else {
92 return This->EnableInterruptSource (This, Source);
93 }
1bfda055 94}
95
96/**
97 Enable interrupt source Source.
98
99 @param This Instance pointer for this protocol
100 @param Source Hardware source of the interrupt
101
102 @retval EFI_SUCCESS Source interrupt enabled.
103 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
104
105**/
106EFI_STATUS
107EFIAPI
108EnableInterruptSource (
109 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
110 IN HARDWARE_INTERRUPT_SOURCE Source
111 )
112{
113 UINT32 RegOffset;
114 UINTN RegShift;
115
e9f7c58f 116 if (Source > mGicNumInterrupts) {
1bfda055 117 ASSERT(FALSE);
118 return EFI_UNSUPPORTED;
119 }
120
b34e4db3 121 // Calculate enable register offset and bit position
1bfda055 122 RegOffset = Source / 32;
123 RegShift = Source % 32;
124
b34e4db3 125 // Write set-enable register
55a0d64b 126 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset), 1 << RegShift);
1bfda055 127
128 return EFI_SUCCESS;
129}
130
131/**
132 Disable interrupt source Source.
133
134 @param This Instance pointer for this protocol
135 @param Source Hardware source of the interrupt
136
137 @retval EFI_SUCCESS Source interrupt disabled.
138 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
139
140**/
141EFI_STATUS
142EFIAPI
143DisableInterruptSource (
144 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
145 IN HARDWARE_INTERRUPT_SOURCE Source
146 )
147{
148 UINT32 RegOffset;
149 UINTN RegShift;
150
e9f7c58f 151 if (Source > mGicNumInterrupts) {
1bfda055 152 ASSERT(FALSE);
153 return EFI_UNSUPPORTED;
154 }
155
9e2b420e 156 // Calculate enable register offset and bit position
1bfda055 157 RegOffset = Source / 32;
158 RegShift = Source % 32;
159
9e2b420e 160 // Write set-enable register
55a0d64b 161 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDICER + (4*RegOffset), 1 << RegShift);
1bfda055 162
163 return EFI_SUCCESS;
164}
165
166/**
167 Return current state of interrupt source Source.
168
169 @param This Instance pointer for this protocol
170 @param Source Hardware source of the interrupt
171 @param InterruptState TRUE: source enabled, FALSE: source disabled.
172
173 @retval EFI_SUCCESS InterruptState is valid
174 @retval EFI_DEVICE_ERROR InterruptState is not valid
175
176**/
177EFI_STATUS
178EFIAPI
179GetInterruptSourceState (
180 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
181 IN HARDWARE_INTERRUPT_SOURCE Source,
182 IN BOOLEAN *InterruptState
183 )
184{
185 UINT32 RegOffset;
186 UINTN RegShift;
187
e9f7c58f 188 if (Source > mGicNumInterrupts) {
1bfda055 189 ASSERT(FALSE);
190 return EFI_UNSUPPORTED;
191 }
192
193 // calculate enable register offset and bit position
194 RegOffset = Source / 32;
195 RegShift = Source % 32;
196
55a0d64b 197 if ((MmioRead32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDISER + (4*RegOffset)) & (1<<RegShift)) == 0) {
1bfda055 198 *InterruptState = FALSE;
199 } else {
200 *InterruptState = TRUE;
201 }
202
203 return EFI_SUCCESS;
204}
205
206/**
207 Signal to the hardware that the End Of Intrrupt state
208 has been reached.
209
210 @param This Instance pointer for this protocol
211 @param Source Hardware source of the interrupt
212
213 @retval EFI_SUCCESS Source interrupt EOI'ed.
214 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
215
216**/
217EFI_STATUS
218EFIAPI
219EndOfInterrupt (
220 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
221 IN HARDWARE_INTERRUPT_SOURCE Source
222 )
223{
e9f7c58f 224 if (Source > mGicNumInterrupts) {
1bfda055 225 ASSERT(FALSE);
226 return EFI_UNSUPPORTED;
227 }
228
55a0d64b 229 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCEIOR, Source);
1bfda055 230 return EFI_SUCCESS;
231}
232
233/**
234 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
235
236 @param InterruptType Defines the type of interrupt or exception that
237 occurred on the processor.This parameter is processor architecture specific.
238 @param SystemContext A pointer to the processor context when
239 the interrupt occurred on the processor.
240
241 @return None
242
243**/
244VOID
245EFIAPI
246IrqInterruptHandler (
247 IN EFI_EXCEPTION_TYPE InterruptType,
248 IN EFI_SYSTEM_CONTEXT SystemContext
249 )
250{
251 UINT32 GicInterrupt;
252 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
253
55a0d64b 254 GicInterrupt = MmioRead32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCIAR);
645890ba 255
256 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt).
e9f7c58f 257 if (GicInterrupt >= mGicNumInterrupts) {
645890ba 258 // The special interrupt do not need to be acknowledge
fe93eba0 259 return;
1bfda055 260 }
261
262 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
263 if (InterruptHandler != NULL) {
264 // Call the registered interrupt handler.
265 InterruptHandler (GicInterrupt, SystemContext);
266 } else {
267 DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));
268 }
269
270 EndOfInterrupt (&gHardwareInterruptProtocol, GicInterrupt);
271}
272
273//
274// Making this global saves a few bytes in image size
275//
276EFI_HANDLE gHardwareInterruptHandle = NULL;
277
278//
279// The protocol instance produced by this driver
280//
281EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {
282 RegisterInterruptSource,
283 EnableInterruptSource,
284 DisableInterruptSource,
285 GetInterruptSourceState,
286 EndOfInterrupt
287};
288
289/**
290 Shutdown our hardware
291
292 DXE Core will disable interrupts and turn off the timer and disable interrupts
293 after all the event handlers have run.
294
295 @param[in] Event The Event that is being processed
296 @param[in] Context Event Context
297**/
298VOID
299EFIAPI
300ExitBootServicesEvent (
301 IN EFI_EVENT Event,
302 IN VOID *Context
303 )
304{
d7b6c49b 305 UINTN Index;
1bfda055 306
1bfda055 307 // Acknowledge all pending interrupts
e9f7c58f 308 for (Index = 0; Index < mGicNumInterrupts; Index++) {
d7b6c49b 309 DisableInterruptSource (&gHardwareInterruptProtocol, Index);
1bfda055 310 }
311
e9f7c58f 312 for (Index = 0; Index < mGicNumInterrupts; Index++) {
d7b6c49b 313 EndOfInterrupt (&gHardwareInterruptProtocol, Index);
1bfda055 314 }
315
316 // Disable Gic Interface
55a0d64b 317 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x0);
318 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0x0);
1bfda055 319
320 // Disable Gic Distributor
55a0d64b 321 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x0);
1bfda055 322}
323
1bfda055 324/**
325 Initialize the state information for the CPU Architectural Protocol
326
327 @param ImageHandle of the loaded driver
328 @param SystemTable Pointer to the System Table
329
330 @retval EFI_SUCCESS Protocol registered
331 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
332 @retval EFI_DEVICE_ERROR Hardware problems
333
334**/
335EFI_STATUS
336InterruptDxeInitialize (
337 IN EFI_HANDLE ImageHandle,
338 IN EFI_SYSTEM_TABLE *SystemTable
339 )
340{
d7b6c49b 341 EFI_STATUS Status;
342 UINTN Index;
343 UINT32 RegOffset;
344 UINTN RegShift;
345 EFI_CPU_ARCH_PROTOCOL *Cpu;
d6950399 346 UINT32 CpuTarget;
1bfda055 347
d6950399 348 // Check PcdGicPrimaryCoreId has been set in case the Primary Core is not the core 0 of Cluster 0
349 DEBUG_CODE_BEGIN();
350 if ((PcdGet32(PcdArmPrimaryCore) != 0) && (PcdGet32 (PcdGicPrimaryCoreId) == 0)) {
351 DEBUG((EFI_D_WARN,"Warning: the PCD PcdGicPrimaryCoreId does not seem to be set up for the configuration.\n"));
352 }
353 DEBUG_CODE_END();
354
1bfda055 355 // Make sure the Interrupt Controller Protocol is not already installed in the system.
356 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
357
e9f7c58f 358 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (PcdGet32(PcdGicDistributorBase));
359
360 for (Index = 0; Index < mGicNumInterrupts; Index++) {
d7b6c49b 361 DisableInterruptSource (&gHardwareInterruptProtocol, Index);
1bfda055 362
363 // Set Priority
d7b6c49b 364 RegOffset = Index / 4;
365 RegShift = (Index % 4) * 8;
1bfda055 366 MmioAndThenOr32 (
55a0d64b 367 PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPR + (4*RegOffset),
1bfda055 368 ~(0xff << RegShift),
55a0d64b 369 ARM_GIC_DEFAULT_PRIORITY << RegShift
1bfda055 370 );
371 }
372
d6950399 373 // Configure interrupts for Primary Cpu
374 CpuTarget = (1 << PcdGet32 (PcdGicPrimaryCoreId));
375 CpuTarget |= (CpuTarget << 24) | (CpuTarget << 16) | (CpuTarget << 8);
e9f7c58f 376 for (Index = 0; Index < (mGicNumInterrupts / 4); Index++) {
d6950399 377 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDIPTR + (Index*4), CpuTarget);
1bfda055 378 }
379
9e2b420e 380 // Set binary point reg to 0x7 (no preemption)
55a0d64b 381 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCBPR, 0x7);
1bfda055 382
9e2b420e 383 // Set priority mask reg to 0xff to allow all priorities through
55a0d64b 384 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCPMR, 0xff);
1bfda055 385
9e2b420e 386 // Enable gic cpu interface
55a0d64b 387 MmioWrite32 (PcdGet32(PcdGicInterruptInterfaceBase) + ARM_GIC_ICCICR, 0x1);
1bfda055 388
9e2b420e 389 // Enable gic distributor
55a0d64b 390 MmioWrite32 (PcdGet32(PcdGicDistributorBase) + ARM_GIC_ICDDCR, 0x1);
1bfda055 391
e9f7c58f 392 // Initialize the array for the Interrupt Handlers
393 gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);
1bfda055 394
395 Status = gBS->InstallMultipleProtocolInterfaces (
396 &gHardwareInterruptHandle,
397 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,
398 NULL
399 );
400 ASSERT_EFI_ERROR (Status);
401
d7b6c49b 402 //
403 // Get the CPU protocol that this driver requires.
404 //
405 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);
406 ASSERT_EFI_ERROR(Status);
1bfda055 407
d7b6c49b 408 //
409 // Unregister the default exception handler.
410 //
411 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL);
412 ASSERT_EFI_ERROR(Status);
413
414 //
415 // Register to receive interrupts
416 //
417 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);
418 ASSERT_EFI_ERROR(Status);
1bfda055 419
420 // Register for an ExitBootServicesEvent
421 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);
422 ASSERT_EFI_ERROR (Status);
423
424 return Status;
425}