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