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