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