]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
036eb5cd6bf6845dd2b03b62c933c1dedaef7251
[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-2015, ARM Ltd. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 Module Name:
16
17 GicV2/ArmGicV2Dxe.c
18
19 Abstract:
20
21 Driver implementing the GicV2 interrupt controller protocol
22
23 --*/
24
25 #include <Library/ArmGicLib.h>
26
27 #include "ArmGicDxe.h"
28
29 #define ARM_GIC_DEFAULT_PRIORITY 0x80
30
31 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol;
32
33 STATIC UINT32 mGicInterruptInterfaceBase;
34 STATIC UINT32 mGicDistributorBase;
35
36 /**
37 Enable interrupt source Source.
38
39 @param This Instance pointer for this protocol
40 @param Source Hardware source of the interrupt
41
42 @retval EFI_SUCCESS Source interrupt enabled.
43 @retval EFI_UNSUPPORTED Source interrupt is not supported
44
45 **/
46 EFI_STATUS
47 EFIAPI
48 GicV2EnableInterruptSource (
49 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
50 IN HARDWARE_INTERRUPT_SOURCE Source
51 )
52 {
53 if (Source >= mGicNumInterrupts) {
54 ASSERT(FALSE);
55 return EFI_UNSUPPORTED;
56 }
57
58 ArmGicEnableInterrupt (mGicDistributorBase, 0, Source);
59
60 return EFI_SUCCESS;
61 }
62
63 /**
64 Disable interrupt source Source.
65
66 @param This Instance pointer for this protocol
67 @param Source Hardware source of the interrupt
68
69 @retval EFI_SUCCESS Source interrupt disabled.
70 @retval EFI_UNSUPPORTED Source interrupt is not supported
71
72 **/
73 EFI_STATUS
74 EFIAPI
75 GicV2DisableInterruptSource (
76 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
77 IN HARDWARE_INTERRUPT_SOURCE Source
78 )
79 {
80 if (Source >= mGicNumInterrupts) {
81 ASSERT(FALSE);
82 return EFI_UNSUPPORTED;
83 }
84
85 ArmGicDisableInterrupt (mGicDistributorBase, 0, Source);
86
87 return EFI_SUCCESS;
88 }
89
90 /**
91 Return current state of interrupt source Source.
92
93 @param This Instance pointer for this protocol
94 @param Source Hardware source of the interrupt
95 @param InterruptState TRUE: source enabled, FALSE: source disabled.
96
97 @retval EFI_SUCCESS InterruptState is valid
98 @retval EFI_UNSUPPORTED Source interrupt is not supported
99
100 **/
101 EFI_STATUS
102 EFIAPI
103 GicV2GetInterruptSourceState (
104 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
105 IN HARDWARE_INTERRUPT_SOURCE Source,
106 IN BOOLEAN *InterruptState
107 )
108 {
109 if (Source >= mGicNumInterrupts) {
110 ASSERT(FALSE);
111 return EFI_UNSUPPORTED;
112 }
113
114 *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, 0, Source);
115
116 return EFI_SUCCESS;
117 }
118
119 /**
120 Signal to the hardware that the End Of Interrupt state
121 has been reached.
122
123 @param This Instance pointer for this protocol
124 @param Source Hardware source of the interrupt
125
126 @retval EFI_SUCCESS Source interrupt EOI'ed.
127 @retval EFI_UNSUPPORTED Source interrupt is not supported
128
129 **/
130 EFI_STATUS
131 EFIAPI
132 GicV2EndOfInterrupt (
133 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
134 IN HARDWARE_INTERRUPT_SOURCE Source
135 )
136 {
137 if (Source >= mGicNumInterrupts) {
138 ASSERT(FALSE);
139 return EFI_UNSUPPORTED;
140 }
141
142 ArmGicV2EndOfInterrupt (mGicInterruptInterfaceBase, Source);
143 return EFI_SUCCESS;
144 }
145
146 /**
147 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
148
149 @param InterruptType Defines the type of interrupt or exception that
150 occurred on the processor.This parameter is 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 VOID
158 EFIAPI
159 GicV2IrqInterruptHandler (
160 IN EFI_EXCEPTION_TYPE InterruptType,
161 IN EFI_SYSTEM_CONTEXT SystemContext
162 )
163 {
164 UINT32 GicInterrupt;
165 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
166
167 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);
168
169 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt).
170 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
171 // The special interrupt do not need to be acknowledge
172 return;
173 }
174
175 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
176 if (InterruptHandler != NULL) {
177 // Call the registered interrupt handler.
178 InterruptHandler (GicInterrupt, SystemContext);
179 } else {
180 DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));
181 }
182
183 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
184 }
185
186 //
187 // The protocol instance produced by this driver
188 //
189 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {
190 RegisterInterruptSource,
191 GicV2EnableInterruptSource,
192 GicV2DisableInterruptSource,
193 GicV2GetInterruptSourceState,
194 GicV2EndOfInterrupt
195 };
196
197 /**
198 Shutdown our hardware
199
200 DXE Core will disable interrupts and turn off the timer and disable interrupts
201 after all the event handlers have run.
202
203 @param[in] Event The Event that is being processed
204 @param[in] Context Event Context
205 **/
206 VOID
207 EFIAPI
208 GicV2ExitBootServicesEvent (
209 IN EFI_EVENT Event,
210 IN VOID *Context
211 )
212 {
213 UINTN Index;
214 UINT32 GicInterrupt;
215
216 // Disable all the interrupts
217 for (Index = 0; Index < mGicNumInterrupts; Index++) {
218 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
219 }
220
221 // Acknowledge all pending interrupts
222 do {
223 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);
224
225 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) < mGicNumInterrupts) {
226 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);
227 }
228 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt));
229
230 // Disable Gic Interface
231 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase);
232
233 // Disable Gic Distributor
234 ArmGicDisableDistributor (mGicDistributorBase);
235 }
236
237 /**
238 Initialize the state information for the CPU Architectural Protocol
239
240 @param ImageHandle of the loaded driver
241 @param SystemTable Pointer to the System Table
242
243 @retval EFI_SUCCESS Protocol registered
244 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
245 @retval EFI_DEVICE_ERROR Hardware problems
246
247 **/
248 EFI_STATUS
249 GicV2DxeInitialize (
250 IN EFI_HANDLE ImageHandle,
251 IN EFI_SYSTEM_TABLE *SystemTable
252 )
253 {
254 EFI_STATUS Status;
255 UINTN Index;
256 UINT32 RegOffset;
257 UINTN RegShift;
258 UINT32 CpuTarget;
259
260 // Make sure the Interrupt Controller Protocol is not already installed in the system.
261 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
262
263 mGicInterruptInterfaceBase = PcdGet32 (PcdGicInterruptInterfaceBase);
264 mGicDistributorBase = PcdGet32 (PcdGicDistributorBase);
265 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
266
267 for (Index = 0; Index < mGicNumInterrupts; Index++) {
268 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);
269
270 // Set Priority
271 RegOffset = Index / 4;
272 RegShift = (Index % 4) * 8;
273 MmioAndThenOr32 (
274 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
275 ~(0xff << RegShift),
276 ARM_GIC_DEFAULT_PRIORITY << RegShift
277 );
278 }
279
280 //
281 // Targets the interrupts to the Primary Cpu
282 //
283
284 // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading
285 // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each
286 // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31.
287 // More Info in the GIC Specification about "Interrupt Processor Targets Registers"
288 //
289 // Read the first Interrupt Processor Targets Register (that corresponds to the 4
290 // first SGIs)
291 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
292
293 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value
294 // is 0 when we run on a uniprocessor platform.
295 if (CpuTarget != 0) {
296 // The 8 first Interrupt Processor Targets Registers are read-only
297 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
298 MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget);
299 }
300 }
301
302 // Set binary point reg to 0x7 (no preemption)
303 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7);
304
305 // Set priority mask reg to 0xff to allow all priorities through
306 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff);
307
308 // Enable gic cpu interface
309 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase);
310
311 // Enable gic distributor
312 ArmGicEnableDistributor (mGicDistributorBase);
313
314 Status = InstallAndRegisterInterruptService (
315 &gHardwareInterruptV2Protocol, GicV2IrqInterruptHandler, GicV2ExitBootServicesEvent);
316
317 return Status;
318 }