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