1 /** @file 2 Handle OMAP35xx interrupt controller 3 4 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 #include <PiDxe.h> 16 17 #include <Library/BaseLib.h> 18 #include <Library/DebugLib.h> 19 #include <Library/BaseMemoryLib.h> 20 #include <Library/UefiBootServicesTableLib.h> 21 #include <Library/UefiLib.h> 22 #include <Library/PcdLib.h> 23 #include <Library/IoLib.h> 24 #include <Library/ArmLib.h> 25 26 #include <Protocol/Cpu.h> 27 #include <Protocol/HardwareInterrupt.h> 28 29 #include <Omap3530/Omap3530.h> 30 31 // 32 // Notifications 33 // 34 EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL; 35 36 37 HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[INT_NROF_VECTORS]; 38 39 /** 40 Shutdown our hardware 41 42 DXE Core will disable interrupts and turn off the timer and disable interrupts 43 after all the event handlers have run. 44 45 @param[in] Event The Event that is being processed 46 @param[in] Context Event Context 47 **/ 48 VOID 49 EFIAPI 50 ExitBootServicesEvent ( 51 IN EFI_EVENT Event, 52 IN VOID *Context 53 ) 54 { 55 // Disable all interrupts 56 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF); 57 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF); 58 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF); 59 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR); 60 61 // Add code here to disable all FIQs as debugger may have turned one on 62 } 63 64 /** 65 Register Handler for the specified interrupt source. 66 67 @param This Instance pointer for this protocol 68 @param Source Hardware source of the interrupt 69 @param Handler Callback for interrupt. NULL to unregister 70 71 @retval EFI_SUCCESS Source was updated to support Handler. 72 @retval EFI_DEVICE_ERROR Hardware could not be programmed. 73 74 **/ 75 EFI_STATUS 76 EFIAPI 77 RegisterInterruptSource ( 78 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 79 IN HARDWARE_INTERRUPT_SOURCE Source, 80 IN HARDWARE_INTERRUPT_HANDLER Handler 81 ) 82 { 83 if (Source > MAX_VECTOR) { 84 ASSERT(FALSE); 85 return EFI_UNSUPPORTED; 86 } 87 88 if ((MmioRead32 (INTCPS_ILR(Source)) & INTCPS_ILR_FIQ) == INTCPS_ILR_FIQ) { 89 // This vector has been programmed as FIQ so we can't use it for IRQ 90 // EFI does not use FIQ, but the debugger can use it to check for 91 // ctrl-c. So this ASSERT means you have a conflict with the debug agent 92 ASSERT (FALSE); 93 return EFI_UNSUPPORTED; 94 } 95 96 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) { 97 return EFI_INVALID_PARAMETER; 98 } 99 100 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) { 101 return EFI_ALREADY_STARTED; 102 } 103 104 gRegisteredInterruptHandlers[Source] = Handler; 105 return This->EnableInterruptSource(This, Source); 106 } 107 108 109 /** 110 Enable interrupt source Source. 111 112 @param This Instance pointer for this protocol 113 @param Source Hardware source of the interrupt 114 115 @retval EFI_SUCCESS Source interrupt enabled. 116 @retval EFI_DEVICE_ERROR Hardware could not be programmed. 117 118 **/ 119 EFI_STATUS 120 EFIAPI 121 EnableInterruptSource ( 122 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 123 IN HARDWARE_INTERRUPT_SOURCE Source 124 ) 125 { 126 UINTN Bank; 127 UINTN Bit; 128 129 if (Source > MAX_VECTOR) { 130 ASSERT(FALSE); 131 return EFI_UNSUPPORTED; 132 } 133 134 Bank = Source / 32; 135 Bit = 1UL << (Source % 32); 136 137 MmioWrite32 (INTCPS_MIR_CLEAR(Bank), Bit); 138 139 return EFI_SUCCESS; 140 } 141 142 143 /** 144 Disable interrupt source Source. 145 146 @param This Instance pointer for this protocol 147 @param Source Hardware source of the interrupt 148 149 @retval EFI_SUCCESS Source interrupt disabled. 150 @retval EFI_DEVICE_ERROR Hardware could not be programmed. 151 152 **/ 153 EFI_STATUS 154 EFIAPI 155 DisableInterruptSource ( 156 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 157 IN HARDWARE_INTERRUPT_SOURCE Source 158 ) 159 { 160 UINTN Bank; 161 UINTN Bit; 162 163 if (Source > MAX_VECTOR) { 164 ASSERT(FALSE); 165 return EFI_UNSUPPORTED; 166 } 167 168 Bank = Source / 32; 169 Bit = 1UL << (Source % 32); 170 171 MmioWrite32 (INTCPS_MIR_SET(Bank), Bit); 172 173 return EFI_SUCCESS; 174 } 175 176 177 178 /** 179 Return current state of interrupt source Source. 180 181 @param This Instance pointer for this protocol 182 @param Source Hardware source of the interrupt 183 @param InterruptState TRUE: source enabled, FALSE: source disabled. 184 185 @retval EFI_SUCCESS InterruptState is valid 186 @retval EFI_DEVICE_ERROR InterruptState is not valid 187 188 **/ 189 EFI_STATUS 190 EFIAPI 191 GetInterruptSourceState ( 192 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 193 IN HARDWARE_INTERRUPT_SOURCE Source, 194 IN BOOLEAN *InterruptState 195 ) 196 { 197 UINTN Bank; 198 UINTN Bit; 199 200 if (InterruptState == NULL) { 201 return EFI_INVALID_PARAMETER; 202 } 203 204 if (Source > MAX_VECTOR) { 205 ASSERT(FALSE); 206 return EFI_UNSUPPORTED; 207 } 208 209 Bank = Source / 32; 210 Bit = 1UL << (Source % 32); 211 212 if ((MmioRead32(INTCPS_MIR(Bank)) & Bit) == Bit) { 213 *InterruptState = FALSE; 214 } else { 215 *InterruptState = TRUE; 216 } 217 218 return EFI_SUCCESS; 219 } 220 221 /** 222 Signal to the hardware that the End Of Intrrupt state 223 has been reached. 224 225 @param This Instance pointer for this protocol 226 @param Source Hardware source of the interrupt 227 228 @retval EFI_SUCCESS Source interrupt EOI'ed. 229 @retval EFI_DEVICE_ERROR Hardware could not be programmed. 230 231 **/ 232 EFI_STATUS 233 EFIAPI 234 EndOfInterrupt ( 235 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, 236 IN HARDWARE_INTERRUPT_SOURCE Source 237 ) 238 { 239 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR); 240 ArmDataSynchronizationBarrier (); 241 return EFI_SUCCESS; 242 } 243 244 245 /** 246 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs. 247 248 @param InterruptType Defines the type of interrupt or exception that 249 occurred on the processor.This parameter is processor architecture specific. 250 @param SystemContext A pointer to the processor context when 251 the interrupt occurred on the processor. 252 253 @return None 254 255 **/ 256 VOID 257 EFIAPI 258 IrqInterruptHandler ( 259 IN EFI_EXCEPTION_TYPE InterruptType, 260 IN EFI_SYSTEM_CONTEXT SystemContext 261 ) 262 { 263 UINT32 Vector; 264 HARDWARE_INTERRUPT_HANDLER InterruptHandler; 265 266 Vector = MmioRead32 (INTCPS_SIR_IRQ) & INTCPS_SIR_IRQ_MASK; 267 268 // Needed to prevent infinite nesting when Time Driver lowers TPL 269 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR); 270 ArmDataSynchronizationBarrier (); 271 272 InterruptHandler = gRegisteredInterruptHandlers[Vector]; 273 if (InterruptHandler != NULL) { 274 // Call the registered interrupt handler. 275 InterruptHandler (Vector, SystemContext); 276 } 277 278 // Needed to clear after running the handler 279 MmioWrite32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR); 280 ArmDataSynchronizationBarrier (); 281 } 282 283 // 284 // Making this global saves a few bytes in image size 285 // 286 EFI_HANDLE gHardwareInterruptHandle = NULL; 287 288 // 289 // The protocol instance produced by this driver 290 // 291 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = { 292 RegisterInterruptSource, 293 EnableInterruptSource, 294 DisableInterruptSource, 295 GetInterruptSourceState, 296 EndOfInterrupt 297 }; 298 299 /** 300 Initialize the state information for the CPU Architectural Protocol 301 302 @param ImageHandle of the loaded driver 303 @param SystemTable Pointer to the System Table 304 305 @retval EFI_SUCCESS Protocol registered 306 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure 307 @retval EFI_DEVICE_ERROR Hardware problems 308 309 **/ 310 EFI_STATUS 311 InterruptDxeInitialize ( 312 IN EFI_HANDLE ImageHandle, 313 IN EFI_SYSTEM_TABLE *SystemTable 314 ) 315 { 316 EFI_STATUS Status; 317 EFI_CPU_ARCH_PROTOCOL *Cpu; 318 319 // Make sure the Interrupt Controller Protocol is not already installed in the system. 320 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); 321 322 // Make sure all interrupts are disabled by default. 323 MmioWrite32 (INTCPS_MIR(0), 0xFFFFFFFF); 324 MmioWrite32 (INTCPS_MIR(1), 0xFFFFFFFF); 325 MmioWrite32 (INTCPS_MIR(2), 0xFFFFFFFF); 326 MmioOr32 (INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR); 327 328 Status = gBS->InstallMultipleProtocolInterfaces(&gHardwareInterruptHandle, 329 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol, 330 NULL); 331 ASSERT_EFI_ERROR(Status); 332 333 // 334 // Get the CPU protocol that this driver requires. 335 // 336 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); 337 ASSERT_EFI_ERROR(Status); 338 339 // 340 // Unregister the default exception handler. 341 // 342 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL); 343 ASSERT_EFI_ERROR(Status); 344 345 // 346 // Register to receive interrupts 347 // 348 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler); 349 ASSERT_EFI_ERROR(Status); 350 351 // Register for an ExitBootServicesEvent 352 Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); 353 ASSERT_EFI_ERROR(Status); 354 355 return Status; 356 } 357 358