Home | History | Annotate | Download | only in InterruptDxe
      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