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