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