]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
ArmPkg: Correct small typos
[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 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 = GicV2GetInterruptSourceState (
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 GicV2DisableInterruptSource (
299 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
300 Source
301 );
302 }
303
304 MmioAndThenOr32 (
305 RegAddress,
306 ~(0x1 << Config1Bit),
307 Value << Config1Bit
308 );
309
310 // Restore interrupt state
311 if (SourceEnabled) {
312 GicV2EnableInterruptSource (
313 (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,
314 Source
315 );
316 }
317
318 return EFI_SUCCESS;
319 }
320
321 EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol = {
322 (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,
323 (HARDWARE_INTERRUPT2_ENABLE)GicV2EnableInterruptSource,
324 (HARDWARE_INTERRUPT2_DISABLE)GicV2DisableInterruptSource,
325 (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV2GetInterruptSourceState,
326 (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV2EndOfInterrupt,
327 GicV2GetTriggerType,
328 GicV2SetTriggerType
329 };
330
331 /**
332 Shutdown our hardware
333
334 DXE Core will disable interrupts and turn off the timer and disable
335 interrupts after all the event handlers have run.
336
337 @param[in] Event The Event that is being processed
338 @param[in] Context Event Context
339 **/
340 STATIC
341 VOID
342 EFIAPI
343 GicV2ExitBootServicesEvent (
344 IN EFI_EVENT Event,
345 IN VOID *Context
346 )
347 {
348 UINTN Index;
349 UINT32 GicInterrupt;
350
351 // Disable all the interrupts
352 for (Index = 0; Index < mGicNumInterrupts; Index++) {
353 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
354 }
355
356 // Acknowledge all pending interrupts
357 do {
358 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);
359
360 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) < mGicNumInterrupts) {
361 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
362 }
363 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt));
364
365 // Disable Gic Interface
366 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase);
367
368 // Disable Gic Distributor
369 ArmGicDisableDistributor (mGicDistributorBase);
370 }
371
372 /**
373 Initialize the state information for the CPU Architectural Protocol
374
375 @param ImageHandle of the loaded driver
376 @param SystemTable Pointer to the System Table
377
378 @retval EFI_SUCCESS Protocol registered
379 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
380 @retval EFI_DEVICE_ERROR Hardware problems
381
382 **/
383 EFI_STATUS
384 GicV2DxeInitialize (
385 IN EFI_HANDLE ImageHandle,
386 IN EFI_SYSTEM_TABLE *SystemTable
387 )
388 {
389 EFI_STATUS Status;
390 UINTN Index;
391 UINT32 RegOffset;
392 UINTN RegShift;
393 UINT32 CpuTarget;
394
395 // Make sure the Interrupt Controller Protocol is not already installed in
396 // the system.
397 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
398
399 mGicInterruptInterfaceBase = PcdGet64 (PcdGicInterruptInterfaceBase);
400 mGicDistributorBase = PcdGet64 (PcdGicDistributorBase);
401 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
402
403 for (Index = 0; Index < mGicNumInterrupts; Index++) {
404 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
405
406 // Set Priority
407 RegOffset = Index / 4;
408 RegShift = (Index % 4) * 8;
409 MmioAndThenOr32 (
410 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
411 ~(0xff << RegShift),
412 ARM_GIC_DEFAULT_PRIORITY << RegShift
413 );
414 }
415
416 // Targets the interrupts to the Primary Cpu
417
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 GICD_ITARGETSRn
420 // are banked to each connected CPU. These 8 registers hold the CPU targets
421 // fields for interrupts 0-31. More Info in the GIC Specification about
422 // "Interrupt Processor Targets Registers"
423
424 // Read the first Interrupt Processor Targets Register (that corresponds to
425 // 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
440 // Set binary point reg to 0x7 (no preemption)
441 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7);
442
443 // Set priority mask reg to 0xff to allow all priorities through
444 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff);
445
446 // Enable gic cpu interface
447 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase);
448
449 // Enable gic distributor
450 ArmGicEnableDistributor (mGicDistributorBase);
451
452 Status = InstallAndRegisterInterruptService (
453 &gHardwareInterruptV2Protocol,
454 &gHardwareInterrupt2V2Protocol,
455 GicV2IrqInterruptHandler,
456 GicV2ExitBootServicesEvent
457 );
458
459 return Status;
460 }