]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c
ArmPkg: merge ArmGicV[23]Lib.h into ArmGicLib.h
[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
41fb5d46 5Portions copyright (c) 2011-2015, 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
46EFI_STATUS\r
47EFIAPI\r
48GicV2EnableInterruptSource (\r
49 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
50 IN HARDWARE_INTERRUPT_SOURCE Source\r
51 )\r
52{\r
53 if (Source > mGicNumInterrupts) {\r
54 ASSERT(FALSE);\r
55 return EFI_UNSUPPORTED;\r
56 }\r
57\r
41fb5d46 58 ArmGicEnableInterrupt (mGicDistributorBase, 0, Source);\r
f5241b57
OM
59\r
60 return EFI_SUCCESS;\r
61}\r
62\r
63/**\r
64 Disable interrupt source Source.\r
65\r
66 @param This Instance pointer for this protocol\r
67 @param Source Hardware source of the interrupt\r
68\r
69 @retval EFI_SUCCESS Source interrupt disabled.\r
70 @retval EFI_UNSUPPORTED Source interrupt is not supported\r
71\r
72**/\r
73EFI_STATUS\r
74EFIAPI\r
75GicV2DisableInterruptSource (\r
76 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
77 IN HARDWARE_INTERRUPT_SOURCE Source\r
78 )\r
79{\r
80 if (Source > mGicNumInterrupts) {\r
81 ASSERT(FALSE);\r
82 return EFI_UNSUPPORTED;\r
83 }\r
84\r
41fb5d46 85 ArmGicDisableInterrupt (mGicDistributorBase, 0, Source);\r
f5241b57
OM
86\r
87 return EFI_SUCCESS;\r
88}\r
89\r
90/**\r
91 Return current state of interrupt source Source.\r
92\r
93 @param This Instance pointer for this protocol\r
94 @param Source Hardware source of the interrupt\r
95 @param InterruptState TRUE: source enabled, FALSE: source disabled.\r
96\r
97 @retval EFI_SUCCESS InterruptState is valid\r
98 @retval EFI_UNSUPPORTED Source interrupt is not supported\r
99\r
100**/\r
101EFI_STATUS\r
102EFIAPI\r
103GicV2GetInterruptSourceState (\r
104 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
105 IN HARDWARE_INTERRUPT_SOURCE Source,\r
106 IN BOOLEAN *InterruptState\r
107 )\r
108{\r
109 if (Source > mGicNumInterrupts) {\r
110 ASSERT(FALSE);\r
111 return EFI_UNSUPPORTED;\r
112 }\r
113\r
41fb5d46 114 *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, 0, Source);\r
f5241b57
OM
115\r
116 return EFI_SUCCESS;\r
117}\r
118\r
119/**\r
120 Signal to the hardware that the End Of Interrupt state\r
121 has been reached.\r
122\r
123 @param This Instance pointer for this protocol\r
124 @param Source Hardware source of the interrupt\r
125\r
126 @retval EFI_SUCCESS Source interrupt EOI'ed.\r
127 @retval EFI_UNSUPPORTED Source interrupt is not supported\r
128\r
129**/\r
130EFI_STATUS\r
131EFIAPI\r
132GicV2EndOfInterrupt (\r
133 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
134 IN HARDWARE_INTERRUPT_SOURCE Source\r
135 )\r
136{\r
137 if (Source > mGicNumInterrupts) {\r
138 ASSERT(FALSE);\r
139 return EFI_UNSUPPORTED;\r
140 }\r
141\r
dc63be24 142 ArmGicV2EndOfInterrupt (mGicInterruptInterfaceBase, Source);\r
f5241b57
OM
143 return EFI_SUCCESS;\r
144}\r
145\r
146/**\r
147 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.\r
148\r
149 @param InterruptType Defines the type of interrupt or exception that\r
150 occurred on the processor.This parameter is processor architecture specific.\r
151 @param SystemContext A pointer to the processor context when\r
152 the interrupt occurred on the processor.\r
153\r
154 @return None\r
155\r
156**/\r
157VOID\r
158EFIAPI\r
159GicV2IrqInterruptHandler (\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
dc63be24 167 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);\r
f5241b57
OM
168\r
169 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the number of interrupt (ie: Spurious interrupt).\r
170 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {\r
171 // The special interrupt do not need to be acknowledge\r
172 return;\r
173 }\r
174\r
175 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];\r
176 if (InterruptHandler != NULL) {\r
177 // Call the registered interrupt handler.\r
178 InterruptHandler (GicInterrupt, SystemContext);\r
179 } else {\r
180 DEBUG ((EFI_D_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));\r
181 }\r
182\r
183 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);\r
184}\r
185\r
186//\r
187// The protocol instance produced by this driver\r
188//\r
189EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV2Protocol = {\r
190 RegisterInterruptSource,\r
191 GicV2EnableInterruptSource,\r
192 GicV2DisableInterruptSource,\r
193 GicV2GetInterruptSourceState,\r
194 GicV2EndOfInterrupt\r
195};\r
196\r
197/**\r
198 Shutdown our hardware\r
199\r
200 DXE Core will disable interrupts and turn off the timer and disable interrupts\r
201 after all the event handlers have run.\r
202\r
203 @param[in] Event The Event that is being processed\r
204 @param[in] Context Event Context\r
205**/\r
206VOID\r
207EFIAPI\r
208GicV2ExitBootServicesEvent (\r
209 IN EFI_EVENT Event,\r
210 IN VOID *Context\r
211 )\r
212{\r
213 UINTN Index;\r
214 UINT32 GicInterrupt;\r
215\r
216 // Disable all the interrupts\r
217 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
218 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);\r
219 }\r
220\r
221 // Acknowledge all pending interrupts\r
222 do {\r
dc63be24 223 GicInterrupt = ArmGicV2AcknowledgeInterrupt (mGicInterruptInterfaceBase);\r
f5241b57
OM
224\r
225 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) < mGicNumInterrupts) {\r
226 GicV2EndOfInterrupt (&gHardwareInterruptV2Protocol, GicInterrupt);\r
227 }\r
228 } while (!ARM_GIC_IS_SPECIAL_INTERRUPTS (GicInterrupt));\r
229\r
230 // Disable Gic Interface\r
dc63be24 231 ArmGicV2DisableInterruptInterface (mGicInterruptInterfaceBase);\r
f5241b57
OM
232\r
233 // Disable Gic Distributor\r
dc63be24 234 ArmGicDisableDistributor (mGicDistributorBase);\r
f5241b57
OM
235}\r
236\r
237/**\r
238 Initialize the state information for the CPU Architectural Protocol\r
239\r
240 @param ImageHandle of the loaded driver\r
241 @param SystemTable Pointer to the System Table\r
242\r
243 @retval EFI_SUCCESS Protocol registered\r
244 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
245 @retval EFI_DEVICE_ERROR Hardware problems\r
246\r
247**/\r
248EFI_STATUS\r
249GicV2DxeInitialize (\r
250 IN EFI_HANDLE ImageHandle,\r
251 IN EFI_SYSTEM_TABLE *SystemTable\r
252 )\r
253{\r
254 EFI_STATUS Status;\r
255 UINTN Index;\r
256 UINT32 RegOffset;\r
257 UINTN RegShift;\r
258 UINT32 CpuTarget;\r
259\r
260 // Make sure the Interrupt Controller Protocol is not already installed in the system.\r
261 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
262\r
dc63be24
AB
263 mGicInterruptInterfaceBase = PcdGet32 (PcdGicInterruptInterfaceBase);\r
264 mGicDistributorBase = PcdGet32 (PcdGicDistributorBase);\r
265 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);\r
f5241b57
OM
266\r
267 for (Index = 0; Index < mGicNumInterrupts; Index++) {\r
268 GicV2DisableInterruptSource (&gHardwareInterruptV2Protocol, Index);\r
269\r
270 // Set Priority\r
271 RegOffset = Index / 4;\r
272 RegShift = (Index % 4) * 8;\r
273 MmioAndThenOr32 (\r
dc63be24 274 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),\r
f5241b57
OM
275 ~(0xff << RegShift),\r
276 ARM_GIC_DEFAULT_PRIORITY << RegShift\r
277 );\r
278 }\r
279\r
280 //\r
281 // Targets the interrupts to the Primary Cpu\r
282 //\r
283\r
284 // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading\r
285 // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each\r
286 // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31.\r
287 // More Info in the GIC Specification about "Interrupt Processor Targets Registers"\r
288 //\r
289 // Read the first Interrupt Processor Targets Register (that corresponds to the 4\r
290 // first SGIs)\r
dc63be24 291 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);\r
f5241b57
OM
292\r
293 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value\r
294 // is 0 when we run on a uniprocessor platform.\r
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
dc63be24 298 MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget);\r
f5241b57
OM
299 }\r
300 }\r
301\r
302 // Set binary point reg to 0x7 (no preemption)\r
dc63be24 303 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCBPR, 0x7);\r
f5241b57
OM
304\r
305 // Set priority mask reg to 0xff to allow all priorities through\r
dc63be24 306 MmioWrite32 (mGicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0xff);\r
f5241b57
OM
307\r
308 // Enable gic cpu interface\r
dc63be24 309 ArmGicEnableInterruptInterface (mGicInterruptInterfaceBase);\r
f5241b57
OM
310\r
311 // Enable gic distributor\r
dc63be24 312 ArmGicEnableDistributor (mGicDistributorBase);\r
f5241b57
OM
313\r
314 Status = InstallAndRegisterInterruptService (\r
315 &gHardwareInterruptV2Protocol, GicV2IrqInterruptHandler, GicV2ExitBootServicesEvent);\r
316\r
317 return Status;\r
318}\r