]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
ArmPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / GicV3 / ArmGicV3Dxe.c
1 /** @file
2 *
3 * Copyright (c) 2011-2018, ARM Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause-Patent
6 *
7 **/
8
9 #include <Library/ArmGicLib.h>
10
11 #include "ArmGicDxe.h"
12
13 #define ARM_GIC_DEFAULT_PRIORITY 0x80
14
15 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;
16 extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;
17
18 STATIC UINTN mGicDistributorBase;
19 STATIC UINTN mGicRedistributorsBase;
20
21 /**
22 Enable interrupt source Source.
23
24 @param This Instance pointer for this protocol
25 @param Source Hardware source of the interrupt
26
27 @retval EFI_SUCCESS Source interrupt enabled.
28 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
29
30 **/
31 STATIC
32 EFI_STATUS
33 EFIAPI
34 GicV3EnableInterruptSource (
35 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
36 IN HARDWARE_INTERRUPT_SOURCE Source
37 )
38 {
39 if (Source >= mGicNumInterrupts) {
40 ASSERT(FALSE);
41 return EFI_UNSUPPORTED;
42 }
43
44 ArmGicEnableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
45
46 return EFI_SUCCESS;
47 }
48
49 /**
50 Disable interrupt source Source.
51
52 @param This Instance pointer for this protocol
53 @param Source Hardware source of the interrupt
54
55 @retval EFI_SUCCESS Source interrupt disabled.
56 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
57
58 **/
59 STATIC
60 EFI_STATUS
61 EFIAPI
62 GicV3DisableInterruptSource (
63 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
64 IN HARDWARE_INTERRUPT_SOURCE Source
65 )
66 {
67 if (Source >= mGicNumInterrupts) {
68 ASSERT(FALSE);
69 return EFI_UNSUPPORTED;
70 }
71
72 ArmGicDisableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
73
74 return EFI_SUCCESS;
75 }
76
77 /**
78 Return current state of interrupt source Source.
79
80 @param This Instance pointer for this protocol
81 @param Source Hardware source of the interrupt
82 @param InterruptState TRUE: source enabled, FALSE: source disabled.
83
84 @retval EFI_SUCCESS InterruptState is valid
85 @retval EFI_DEVICE_ERROR InterruptState is not valid
86
87 **/
88 STATIC
89 EFI_STATUS
90 EFIAPI
91 GicV3GetInterruptSourceState (
92 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
93 IN HARDWARE_INTERRUPT_SOURCE Source,
94 IN BOOLEAN *InterruptState
95 )
96 {
97 if (Source >= mGicNumInterrupts) {
98 ASSERT(FALSE);
99 return EFI_UNSUPPORTED;
100 }
101
102 *InterruptState = ArmGicIsInterruptEnabled (
103 mGicDistributorBase,
104 mGicRedistributorsBase,
105 Source
106 );
107
108 return EFI_SUCCESS;
109 }
110
111 /**
112 Signal to the hardware that the End Of Interrupt state
113 has been reached.
114
115 @param This Instance pointer for this protocol
116 @param Source Hardware source of the interrupt
117
118 @retval EFI_SUCCESS Source interrupt EOI'ed.
119 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
120
121 **/
122 STATIC
123 EFI_STATUS
124 EFIAPI
125 GicV3EndOfInterrupt (
126 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
127 IN HARDWARE_INTERRUPT_SOURCE Source
128 )
129 {
130 if (Source >= mGicNumInterrupts) {
131 ASSERT(FALSE);
132 return EFI_UNSUPPORTED;
133 }
134
135 ArmGicV3EndOfInterrupt (Source);
136 return EFI_SUCCESS;
137 }
138
139 /**
140 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
141
142 @param InterruptType Defines the type of interrupt or exception that
143 occurred on the processor. This parameter is
144 processor architecture specific.
145 @param SystemContext A pointer to the processor context when
146 the interrupt occurred on the processor.
147
148 @return None
149
150 **/
151 STATIC
152 VOID
153 EFIAPI
154 GicV3IrqInterruptHandler (
155 IN EFI_EXCEPTION_TYPE InterruptType,
156 IN EFI_SYSTEM_CONTEXT SystemContext
157 )
158 {
159 UINT32 GicInterrupt;
160 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
161
162 GicInterrupt = ArmGicV3AcknowledgeInterrupt ();
163
164 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
165 // number of interrupt (ie: Spurious interrupt).
166 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
167 // The special interrupt do not need to be acknowledge
168 return;
169 }
170
171 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
172 if (InterruptHandler != NULL) {
173 // Call the registered interrupt handler.
174 InterruptHandler (GicInterrupt, SystemContext);
175 } else {
176 DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));
177 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, GicInterrupt);
178 }
179 }
180
181 // The protocol instance produced by this driver
182 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {
183 RegisterInterruptSource,
184 GicV3EnableInterruptSource,
185 GicV3DisableInterruptSource,
186 GicV3GetInterruptSourceState,
187 GicV3EndOfInterrupt
188 };
189
190 /**
191 Get interrupt trigger type of an interrupt
192
193 @param This Instance pointer for this protocol
194 @param Source Hardware source of the interrupt.
195 @param TriggerType Returns interrupt trigger type.
196
197 @retval EFI_SUCCESS Source interrupt supported.
198 @retval EFI_UNSUPPORTED Source interrupt is not supported.
199 **/
200 STATIC
201 EFI_STATUS
202 EFIAPI
203 GicV3GetTriggerType (
204 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,
205 IN HARDWARE_INTERRUPT_SOURCE Source,
206 OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType
207 )
208 {
209 UINTN RegAddress;
210 UINTN Config1Bit;
211 EFI_STATUS Status;
212
213 Status = GicGetDistributorIcfgBaseAndBit (
214 Source,
215 &RegAddress,
216 &Config1Bit
217 );
218
219 if (EFI_ERROR (Status)) {
220 return Status;
221 }
222
223 if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {
224 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;
225 } else {
226 *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;
227 }
228
229 return EFI_SUCCESS;
230 }
231
232 /**
233 Set interrupt trigger type of an interrupt
234
235 @param This Instance pointer for this protocol
236 @param Source Hardware source of the interrupt.
237 @param TriggerType Interrupt trigger type.
238
239 @retval EFI_SUCCESS Source interrupt supported.
240 @retval EFI_UNSUPPORTED Source interrupt is not supported.
241 **/
242 STATIC
243 EFI_STATUS
244 EFIAPI
245 GicV3SetTriggerType (
246 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This,
247 IN HARDWARE_INTERRUPT_SOURCE Source,
248 IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType
249 )
250 {
251 UINTN RegAddress;
252 UINTN Config1Bit;
253 UINT32 Value;
254 EFI_STATUS Status;
255 BOOLEAN SourceEnabled;
256
257 if ( (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
258 && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH)) {
259 DEBUG ((DEBUG_ERROR, "Invalid interrupt trigger type: %d\n", \
260 TriggerType));
261 ASSERT (FALSE);
262 return EFI_UNSUPPORTED;
263 }
264
265 Status = GicGetDistributorIcfgBaseAndBit (
266 Source,
267 &RegAddress,
268 &Config1Bit
269 );
270
271 if (EFI_ERROR (Status)) {
272 return Status;
273 }
274
275 Status = GicV3GetInterruptSourceState (
276 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
277 Source,
278 &SourceEnabled
279 );
280
281 if (EFI_ERROR (Status)) {
282 return Status;
283 }
284
285 Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)
286 ? ARM_GIC_ICDICFR_EDGE_TRIGGERED
287 : ARM_GIC_ICDICFR_LEVEL_TRIGGERED;
288
289 // Before changing the value, we must disable the interrupt,
290 // otherwise GIC behavior is UNPREDICTABLE.
291 if (SourceEnabled) {
292 GicV3DisableInterruptSource (
293 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
294 Source
295 );
296 }
297
298 MmioAndThenOr32 (
299 RegAddress,
300 ~(0x1 << Config1Bit),
301 Value << Config1Bit
302 );
303 // Restore interrupt state
304 if (SourceEnabled) {
305 GicV3EnableInterruptSource (
306 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
307 Source
308 );
309 }
310
311 return EFI_SUCCESS;
312 }
313
314 EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol = {
315 (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
316 (HARDWARE_INTERRUPT2_ENABLE)GicV3EnableInterruptSource,
317 (HARDWARE_INTERRUPT2_DISABLE)GicV3DisableInterruptSource,
318 (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV3GetInterruptSourceState,
319 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV3EndOfInterrupt,
320 GicV3GetTriggerType,
321 GicV3SetTriggerType
322 };
323
324 /**
325 Shutdown our hardware
326
327 DXE Core will disable interrupts and turn off the timer and disable interrupts
328 after all the event handlers have run.
329
330 @param[in] Event The Event that is being processed
331 @param[in] Context Event Context
332 **/
333 VOID
334 EFIAPI
335 GicV3ExitBootServicesEvent (
336 IN EFI_EVENT Event,
337 IN VOID *Context
338 )
339 {
340 UINTN Index;
341
342 // Acknowledge all pending interrupts
343 for (Index = 0; Index < mGicNumInterrupts; Index++) {
344 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
345 }
346
347 for (Index = 0; Index < mGicNumInterrupts; Index++) {
348 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, Index);
349 }
350
351 // Disable Gic Interface
352 ArmGicV3DisableInterruptInterface ();
353
354 // Disable Gic Distributor
355 ArmGicDisableDistributor (mGicDistributorBase);
356 }
357
358 /**
359 Initialize the state information for the CPU Architectural Protocol
360
361 @param ImageHandle of the loaded driver
362 @param SystemTable Pointer to the System Table
363
364 @retval EFI_SUCCESS Protocol registered
365 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
366 @retval EFI_DEVICE_ERROR Hardware problems
367
368 **/
369 EFI_STATUS
370 GicV3DxeInitialize (
371 IN EFI_HANDLE ImageHandle,
372 IN EFI_SYSTEM_TABLE *SystemTable
373 )
374 {
375 EFI_STATUS Status;
376 UINTN Index;
377 UINT32 RegOffset;
378 UINTN RegShift;
379 UINT64 CpuTarget;
380 UINT64 MpId;
381
382 // Make sure the Interrupt Controller Protocol is not already installed in
383 // the system.
384 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
385
386 mGicDistributorBase = PcdGet64 (PcdGicDistributorBase);
387 mGicRedistributorsBase = PcdGet64 (PcdGicRedistributorsBase);
388 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
389
390 // We will be driving this GIC in native v3 mode, i.e., with Affinity
391 // Routing enabled. So ensure that the ARE bit is set.
392 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
393 MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE);
394 }
395
396 for (Index = 0; Index < mGicNumInterrupts; Index++) {
397 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
398
399 // Set Priority
400 RegOffset = Index / 4;
401 RegShift = (Index % 4) * 8;
402 MmioAndThenOr32 (
403 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
404 ~(0xff << RegShift),
405 ARM_GIC_DEFAULT_PRIORITY << RegShift
406 );
407 }
408
409 // Targets the interrupts to the Primary Cpu
410
411 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
412 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
413 // reading the GIC Distributor Target register. The 8 first
414 // GICD_ITARGETSRn are banked to each connected CPU. These 8 registers
415 // hold the CPU targets fields for interrupts 0-31. More Info in the GIC
416 // Specification about "Interrupt Processor Targets Registers"
417
418 // Read the first Interrupt Processor Targets Register (that corresponds
419 // to the 4 first SGIs)
420 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
421
422 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
423 // This value is 0 when we run on a uniprocessor platform.
424 if (CpuTarget != 0) {
425 // The 8 first Interrupt Processor Targets Registers are read-only
426 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
427 MmioWrite32 (
428 mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),
429 CpuTarget
430 );
431 }
432 }
433 } else {
434 MpId = ArmReadMpidr ();
435 CpuTarget = MpId &
436 (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3);
437
438 if ((MmioRead32 (
439 mGicDistributorBase + ARM_GIC_ICDDCR
440 ) & ARM_GIC_ICDDCR_DS) != 0) {
441
442 // If the Disable Security (DS) control bit is set, we are dealing with a
443 // GIC that has only one security state. In this case, let's assume we are
444 // executing in non-secure state (which is appropriate for DXE modules)
445 // and that no other firmware has performed any configuration on the GIC.
446 // This means we need to reconfigure all interrupts to non-secure Group 1
447 // first.
448
449 MmioWrite32 (
450 mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR,
451 0xffffffff
452 );
453
454 for (Index = 32; Index < mGicNumInterrupts; Index += 32) {
455 MmioWrite32 (
456 mGicDistributorBase + ARM_GIC_ICDISR + Index / 8,
457 0xffffffff
458 );
459 }
460 }
461
462 // Route the SPIs to the primary CPU. SPIs start at the INTID 32
463 for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) {
464 MmioWrite64 (
465 mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8),
466 CpuTarget
467 );
468 }
469 }
470
471 // Set binary point reg to 0x7 (no preemption)
472 ArmGicV3SetBinaryPointer (0x7);
473
474 // Set priority mask reg to 0xff to allow all priorities through
475 ArmGicV3SetPriorityMask (0xff);
476
477 // Enable gic cpu interface
478 ArmGicV3EnableInterruptInterface ();
479
480 // Enable gic distributor
481 ArmGicEnableDistributor (mGicDistributorBase);
482
483 Status = InstallAndRegisterInterruptService (
484 &gHardwareInterruptV3Protocol,
485 &gHardwareInterrupt2V3Protocol,
486 GicV3IrqInterruptHandler,
487 GicV3ExitBootServicesEvent
488 );
489
490 return Status;
491 }