]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
ArmPkg: Apply uncrustify changes
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / GicV2 / ArmGicV2Dxe.c
1 /*++
2
3 Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
4 Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2011-2017, ARM Ltd. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 Module Name:
10
11 GicV2/ArmGicV2Dxe.c
12
13 Abstract:
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
25 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;
26 extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol;
27
28 STATIC UINT32 mGicInterruptInterfaceBase;
29 STATIC UINT32 mGicDistributorBase;
30
31 /**
32 Enable interrupt source Source.
33
34 @param This Instance pointer for this protocol
35 @param Source Hardware source of the interrupt
36
37 @retval EFI_SUCCESS Source interrupt enabled.
38 @retval EFI_UNSUPPORTED Source interrupt is not supported
39
40 **/
41 STATIC
42 EFI_STATUS
43 EFIAPI
44 GicV2EnableInterruptSource (
45 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
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
59 /**
60 Disable interrupt source Source.
61
62 @param This Instance pointer for this protocol
63 @param Source Hardware source of the interrupt
64
65 @retval EFI_SUCCESS Source interrupt disabled.
66 @retval EFI_UNSUPPORTED Source interrupt is not supported
67
68 **/
69 STATIC
70 EFI_STATUS
71 EFIAPI
72 GicV2DisableInterruptSource (
73 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
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
87 /**
88 Return current state of interrupt source Source.
89
90 @param This Instance pointer for this protocol
91 @param Source Hardware source of the interrupt
92 @param InterruptState TRUE: source enabled, FALSE: source disabled.
93
94 @retval EFI_SUCCESS InterruptState is valid
95 @retval EFI_UNSUPPORTED Source interrupt is not supported
96
97 **/
98 STATIC
99 EFI_STATUS
100 EFIAPI
101 GicV2GetInterruptSourceState (
102 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
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
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 ended successfully.
125 @retval EFI_UNSUPPORTED Source interrupt is not supported
126
127 **/
128 STATIC
129 EFI_STATUS
130 EFIAPI
131 GicV2EndOfInterrupt (
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 ArmGicV2EndOfInterrupt (mGicInterruptInterfaceBase, 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 GicV2IrqInterruptHandler (
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 = 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", GicInterrupt));
183 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
184 }
185 }
186
187 // The protocol instance produced by this driver
188 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {
189 RegisterInterruptSource,
190 GicV2EnableInterruptSource,
191 GicV2DisableInterruptSource,
192 GicV2GetInterruptSourceState,
193 GicV2EndOfInterrupt
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 GicV2GetTriggerType (
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 GicV2SetTriggerType (
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 {
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 (
286 (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
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 (
303 (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
304 Source
305 );
306 }
307
308 MmioAndThenOr32 (
309 RegAddress,
310 ~(0x1 << Config1Bit),
311 Value << Config1Bit
312 );
313
314 // Restore interrupt state
315 if (SourceEnabled) {
316 GicV2EnableInterruptSource (
317 (EFI_HARDWARE_INTERRUPT_PROTOCOL *)This,
318 Source
319 );
320 }
321
322 return EFI_SUCCESS;
323 }
324
325 EFI_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
335 /**
336 Shutdown our hardware
337
338 DXE Core will disable interrupts and turn off the timer and disable
339 interrupts after all the event handlers have run.
340
341 @param[in] Event The Event that is being processed
342 @param[in] Context Event Context
343 **/
344 STATIC
345 VOID
346 EFIAPI
347 GicV2ExitBootServicesEvent (
348 IN EFI_EVENT Event,
349 IN VOID *Context
350 )
351 {
352 UINTN Index;
353 UINT32 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
376 /**
377 Initialize the state information for the CPU Architectural Protocol
378
379 @param ImageHandle of the loaded driver
380 @param SystemTable Pointer to the System Table
381
382 @retval EFI_SUCCESS Protocol registered
383 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
384 @retval EFI_DEVICE_ERROR Hardware problems
385
386 **/
387 EFI_STATUS
388 GicV2DxeInitialize (
389 IN EFI_HANDLE ImageHandle,
390 IN EFI_SYSTEM_TABLE *SystemTable
391 )
392 {
393 EFI_STATUS Status;
394 UINTN Index;
395 UINT32 RegOffset;
396 UINTN 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 mGicInterruptInterfaceBase = PcdGet64 (PcdGicInterruptInterfaceBase);
404 mGicDistributorBase = PcdGet64 (PcdGicDistributorBase);
405 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
406
407 for (Index = 0; Index < mGicNumInterrupts; Index++) {
408 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
409
410 // Set Priority
411 RegOffset = Index / 4;
412 RegShift = (Index % 4) * 8;
413 MmioAndThenOr32 (
414 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
415 ~(0xff << RegShift),
416 ARM_GIC_DEFAULT_PRIORITY << RegShift
417 );
418 }
419
420 // Targets the interrupts to the Primary Cpu
421
422 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
423 // reading the GIC Distributor Target register. The 8 first GICD_ITARGETSRn
424 // are banked to each connected CPU. These 8 registers hold the CPU targets
425 // fields for interrupts 0-31. More Info in the GIC Specification about
426 // "Interrupt Processor Targets Registers"
427
428 // Read the first Interrupt Processor Targets Register (that corresponds to
429 // the 4 first SGIs)
430 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
431
432 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
433 // This value is 0 when we run on a uniprocessor platform.
434 if (CpuTarget != 0) {
435 // The 8 first Interrupt Processor Targets Registers are read-only
436 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
437 MmioWrite32 (
438 mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),
439 CpuTarget
440 );
441 }
442 }
443
444 // Set binary point reg to 0x7 (no preemption)
445 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7);
446
447 // Set priority mask reg to 0xff to allow all priorities through
448 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff);
449
450 // Enable gic cpu interface
451 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase);
452
453 // Enable gic distributor
454 ArmGicEnableDistributor (mGicDistributorBase);
455
456 Status = InstallAndRegisterInterruptService (
457 &gHardwareInterruptV2Protocol,
458 &gHardwareInterrupt2V2Protocol,
459 GicV2IrqInterruptHandler,
460 GicV2ExitBootServicesEvent
461 );
462
463 return Status;
464 }