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