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