TianoCore EDK2 master
Loading...
Searching...
No Matches
ArmGicV2Dxe.c
1/*++
2
3Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
4Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5Portions copyright (c) 2011-2023, Arm Ltd. All rights reserved.<BR>
6
7SPDX-License-Identifier: BSD-2-Clause-Patent
8
9Module Name:
10
11 GicV2/ArmGicV2Dxe.c
12
13Abstract:
14
15 Driver implementing the GicV2 interrupt controller protocol
16
17--*/
18
19#include <Library/ArmGicLib.h>
20
21#include "ArmGicDxe.h"
22
23#define ARM_GIC_DEFAULT_PRIORITY 0x80
24
25extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;
26extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol;
27
28STATIC UINTN mGicInterruptInterfaceBase;
29STATIC UINTN mGicDistributorBase;
30
43EFIAPI
44GicV2EnableInterruptSource (
46 IN HARDWARE_INTERRUPT_SOURCE Source
47 )
48{
49 if (Source >= mGicNumInterrupts) {
50 ASSERT (FALSE);
51 return EFI_UNSUPPORTED;
52 }
53
54 ArmGicEnableInterrupt (mGicDistributorBase, 0, Source);
55
56 return EFI_SUCCESS;
57}
58
71EFIAPI
72GicV2DisableInterruptSource (
74 IN HARDWARE_INTERRUPT_SOURCE Source
75 )
76{
77 if (Source >= mGicNumInterrupts) {
78 ASSERT (FALSE);
79 return EFI_UNSUPPORTED;
80 }
81
82 ArmGicDisableInterrupt (mGicDistributorBase, 0, Source);
83
84 return EFI_SUCCESS;
85}
86
100EFIAPI
101GicV2GetInterruptSourceState (
103 IN HARDWARE_INTERRUPT_SOURCE Source,
104 IN BOOLEAN *InterruptState
105 )
106{
107 if (Source >= mGicNumInterrupts) {
108 ASSERT (FALSE);
109 return EFI_UNSUPPORTED;
110 }
111
112 *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, 0, Source);
113
114 return EFI_SUCCESS;
115}
116
128STATIC
130EFIAPI
131GicV2EndOfInterrupt (
133 IN HARDWARE_INTERRUPT_SOURCE Source
134 )
135{
136 if (Source >= mGicNumInterrupts) {
137 ASSERT (FALSE);
138 return EFI_UNSUPPORTED;
139 }
140
141 ArmGicV2EndOfInterrupt (mGicInterruptInterfaceBase, Source);
142 return EFI_SUCCESS;
143}
144
157STATIC
158VOID
159EFIAPI
160GicV2IrqInterruptHandler (
161 IN EFI_EXCEPTION_TYPE InterruptType,
162 IN EFI_SYSTEM_CONTEXT SystemContext
163 )
164{
165 UINTN GicInterrupt;
166 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
167
168 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);
169
170 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
171 // number of interrupt (ie: Spurious interrupt).
172 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
173 // The special interrupts do not need to be acknowledged
174 return;
175 }
176
177 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
178 if (InterruptHandler != NULL) {
179 // Call the registered interrupt handler.
180 InterruptHandler (GicInterrupt, SystemContext);
181 } else {
182 DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", (UINT32)GicInterrupt));
183 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
184 }
185}
186
187// The protocol instance produced by this driver
188EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {
189 RegisterInterruptSource,
190 GicV2EnableInterruptSource,
191 GicV2DisableInterruptSource,
192 GicV2GetInterruptSourceState,
193 GicV2EndOfInterrupt
194};
195
206STATIC
208EFIAPI
209GicV2GetTriggerType (
211 IN HARDWARE_INTERRUPT_SOURCE Source,
212 OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType
213 )
214{
215 UINTN RegAddress;
216 UINTN Config1Bit;
217 EFI_STATUS Status;
218
219 Status = GicGetDistributorIcfgBaseAndBit (
220 Source,
221 &RegAddress,
222 &Config1Bit
223 );
224
225 if (EFI_ERROR (Status)) {
226 return Status;
227 }
228
229 if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {
230 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;
231 } else {
232 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;
233 }
234
235 return EFI_SUCCESS;
236}
237
248STATIC
250EFIAPI
251GicV2SetTriggerType (
253 IN HARDWARE_INTERRUPT_SOURCE Source,
254 IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType
255 )
256{
257 UINTN RegAddress;
258 UINTN Config1Bit;
259 UINT32 Value;
260 EFI_STATUS Status;
261 BOOLEAN SourceEnabled;
262
263 if ( (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
264 && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH))
265 {
266 DEBUG ((
267 DEBUG_ERROR,
268 "Invalid interrupt trigger type: %d\n", \
269 TriggerType
270 ));
271 ASSERT (FALSE);
272 return EFI_UNSUPPORTED;
273 }
274
275 Status = GicGetDistributorIcfgBaseAndBit (
276 Source,
277 &RegAddress,
278 &Config1Bit
279 );
280
281 if (EFI_ERROR (Status)) {
282 return Status;
283 }
284
285 Status = GicV2GetInterruptSourceState (
287 Source,
288 &SourceEnabled
289 );
290
291 if (EFI_ERROR (Status)) {
292 return Status;
293 }
294
295 Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
296 ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
297 : ARM_GIC_ICDICFR_LEVEL_TRIGGERED;
298
299 // Before changing the value, we must disable the interrupt,
300 // otherwise GIC behavior is UNPREDICTABLE.
301 if (SourceEnabled) {
302 GicV2DisableInterruptSource (
304 Source
305 );
306 }
307
309 RegAddress,
310 ~(0x1 << Config1Bit),
311 Value << Config1Bit
312 );
313
314 // Restore interrupt state
315 if (SourceEnabled) {
316 GicV2EnableInterruptSource (
318 Source
319 );
320 }
321
322 return EFI_SUCCESS;
323}
324
325EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol = {
326 (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
327 (HARDWARE_INTERRUPT2_ENABLE)GicV2EnableInterruptSource,
328 (HARDWARE_INTERRUPT2_DISABLE)GicV2DisableInterruptSource,
329 (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV2GetInterruptSourceState,
330 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV2EndOfInterrupt,
331 GicV2GetTriggerType,
332 GicV2SetTriggerType
333};
334
344STATIC
345VOID
346EFIAPI
347GicV2ExitBootServicesEvent (
348 IN EFI_EVENT Event,
349 IN VOID *Context
350 )
351{
352 UINTN Index;
353 UINTN GicInterrupt;
354
355 // Disable all the interrupts
356 for (Index = 0; Index < mGicNumInterrupts; Index++) {
357 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
358 }
359
360 // Acknowledge all pending interrupts
361 do {
362 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);
363
364 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) < mGicNumInterrupts) {
365 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
366 }
367 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt));
368
369 // Disable Gic Interface
370 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase);
371
372 // Disable Gic Distributor
373 ArmGicDisableDistributor (mGicDistributorBase);
374}
375
388GicV2DxeInitialize (
389 IN EFI_HANDLE ImageHandle,
390 IN EFI_SYSTEM_TABLE *SystemTable
391 )
392{
393 EFI_STATUS Status;
394 UINTN Index;
395 UINT32 RegOffset;
396 UINT8 RegShift;
397 UINT32 CpuTarget;
398
399 // Make sure the Interrupt Controller Protocol is not already installed in
400 // the system.
401 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
402
403 ASSERT (PcdGet64 (PcdGicInterruptInterfaceBase) <= MAX_UINTN);
404 ASSERT (PcdGet64 (PcdGicDistributorBase) <= MAX_UINTN);
405
406 mGicInterruptInterfaceBase = (UINTN)PcdGet64 (PcdGicInterruptInterfaceBase);
407 mGicDistributorBase = (UINTN)PcdGet64 (PcdGicDistributorBase);
408 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
409
410 for (Index = 0; Index < mGicNumInterrupts; Index++) {
411 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
412
413 // Set Priority
414 RegOffset = (UINT32)(Index / 4);
415 RegShift = (UINT8)((Index % 4) * 8);
417 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
418 ~(0xff << RegShift),
419 ARM_GIC_DEFAULT_PRIORITY << RegShift
420 );
421 }
422
423 // Targets the interrupts to the Primary Cpu
424
425 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
426 // reading the GIC Distributor Target register. The 8 first GICD_ITARGETSRn
427 // are banked to each connected CPU. These 8 registers hold the CPU targets
428 // fields for interrupts 0-31. More Info in the GIC Specification about
429 // "Interrupt Processor Targets Registers"
430
431 // Read the first Interrupt Processor Targets Register (that corresponds to
432 // the 4 first SGIs)
433 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
434
435 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
436 // This value is 0 when we run on a uniprocessor platform.
437 if (CpuTarget != 0) {
438 // The 8 first Interrupt Processor Targets Registers are read-only
439 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
441 mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),
442 CpuTarget
443 );
444 }
445 }
446
447 // Set binary point reg to 0x7 (no preemption)
448 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7);
449
450 // Set priority mask reg to 0xff to allow all priorities through
451 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff);
452
453 // Enable gic cpu interface
454 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase);
455
456 // Enable gic distributor
457 ArmGicEnableDistributor (mGicDistributorBase);
458
459 Status = InstallAndRegisterInterruptService (
460 &gHardwareInterruptV2Protocol,
461 &gHardwareInterrupt2V2Protocol,
462 GicV2IrqInterruptHandler,
463 GicV2ExitBootServicesEvent
464 );
465
466 return Status;
467}
UINT64 UINTN
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_DISABLE)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_REGISTER)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source, IN HARDWARE_INTERRUPT_HANDLER Handler)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_END_OF_INTERRUPT)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_ENABLE)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source)
EFI_STATUS(EFIAPI * HARDWARE_INTERRUPT2_INTERRUPT_STATE)(IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, IN HARDWARE_INTERRUPT_SOURCE Source, IN BOOLEAN *InterruptState)
VOID(EFIAPI * HARDWARE_INTERRUPT_HANDLER)(IN HARDWARE_INTERRUPT_SOURCE Source, IN EFI_SYSTEM_CONTEXT SystemContext)
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition: IoLib.c:262
UINT32 EFIAPI MmioAndThenOr32(IN UINTN Address, IN UINT32 AndData, IN UINT32 OrData)
Definition: IoHighLevel.c:1845
UINT32 EFIAPI MmioWrite32(IN UINTN Address, IN UINT32 Value)
Definition: IoLib.c:309
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
Definition: DebugLib.h:535
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112