/* $Header: <fileName>.c    <lastVersionNumber>    <lastEditionDate> 
 * =============================================================================
 *
 *            TEXAS INSTRUMENTS INCORPORATED PROPRIETARY INFORMATION
 *
 *  Property of Texas Instruments
 *  For Unrestricted Internal Use Only 
 *  Unauthorized reproduction and/or distribution is strictly
 *  prohibited.
 *  This product is protected under copyright law and trade secret law  
 *  as an unpublished work.
 *  Created 2008, (C) Copyright 2008 Texas Instruments.  All rights 
 *  reserved.
 */
/**
 *  @Component    INTH - Interrupt (IRQ) handler library component
 *
 *  @Filename     INTH.c
 *
 *  @Description  Interrupt handling utilities
 *
 *//*======================================================================== */

/* ============================================================================
* STANDARD INCLUDE FILES
* =============================================================================
*/

/* ============================================================================
* PROJECT SPECIFIC INCLUDE FILES
* =============================================================================
*/
#include "aintc_inth.h"
#include "GIC_ctl.h"


/* ============================================================================
* GLOBAL VARIABLES DECLARATIONS
* =============================================================================
*/

/* ============================================================================
* LOCAL TYPES AND DEFINITIONS
* =============================================================================
*/

/* number of interrupt handlers */
#define INTH_INT_TABLE_SIZE     NUM_GIC400_INTC_EVENTS

/* number max of interrupt handlers */
#define INTH_INT_NUM_MAX          INTH_INT_TABLE_SIZE - 1

/* ============================================================================
* LOCAL VARIABLES DECLARATIONS
* =============================================================================
*/

static CSL_Cortexa15GICRegs *ptrGIC400_Handle = 0;

static INTH_Handler_t inth_IrqHandler[INTH_INT_TABLE_SIZE];

/* array of interrupt counter */
static Uint32 inth_IrqCount[INTH_INT_TABLE_SIZE];
  
/* ============================================================================
* LOCAL FUNCTIONS PROTOTYPES
* =============================================================================
*/

/* ============================================================================
* FUNCTIONS
* =============================================================================
*/
ReturnCode_t INTH_InitHandler( void )
{
    ReturnCode_t returnCode = RET_OK;
    Uint32 index;

    /* Setup Global structure pointer */
    ptrGIC400_Handle = (CSL_Cortexa15GICRegs *) 0x02561000;

    /* Init GIC */
    GIC_Init(ptrGIC400_Handle);

    /* for all interrupts */
    for (index = 0; index < INTH_INT_TABLE_SIZE; index++)
    {
        /* initialise int handler and count value */
        inth_IrqCount[index] = 0;
        inth_IrqHandler[index] = 0;
    }

    return returnCode;

} /* INTH_InitHandler() */


/*==================== Function Separator =============================*/

ReturnCode_t INTH_RegisterHandler( const Uint32          intVector,
                                   const INTH_Handler_t    intHandler)
{
    ReturnCode_t returnCode = RET_OK;

    /* reset counter and install handler */
    inth_IrqCount[intVector] = 0;
    inth_IrqHandler[intVector] = intHandler;
   
    return returnCode;

} /* INTH_RegisterHandler() */

/*==================== Function Separator =============================*/

ReturnCode_t INTH_SetupInterrupt( const Uint32             intVector,
                                  const INTH_Handler_t     intHandler,
                                  Uint8                    intTargetId,
                                  //const INTH_Group_t     intGroup,
                                  const INTH_Priority_t    intPriority)
{
    ReturnCode_t returnCode = RET_OK;
    Uint8      intTargetMask;

    // If not a SPI then target is not used. Set it to a valid number
    if (intVector < 31)
        intTargetId = 0;

    /* NOTE: Currently does not support interrupt broadcast */
    if (intTargetId < INTH_MAX_CORE_NUM)
    {
        /* Setup Group */
        // NOTE: For now map all events to Group-1
#ifndef _SECURE_DEVICE
        GICD_Set_Intr_Group(ptrGIC400_Handle, intVector, INTH_TYPE_GROUP_1);
#else
        go_secure(GICD_Set_Intr_Group,
                  (Uint32)ptrGIC400_Handle, 
                  intVector, 
                  (Uint32) INTH_TYPE_GROUP_1);
#endif
    
        /* Setup Priority */
        GICD_Set_Group1_Intr_Priority(ptrGIC400_Handle, intVector, intPriority);
    
        /* Setup targets only for SPIs */
        if (intVector > 31)
        {
            /* Setup Targets */
            intTargetMask = 1 << intTargetId; 
#ifndef _SECURE_DEVICE
            GICD_Set_Intr_Targets(ptrGIC400_Handle, intVector, intTargetMask);
#else
            go_secure(GICD_Set_Intr_Targets,
                  (Uint32)ptrGIC400_Handle, intVector, (Uint32)intTargetMask);
#endif
        }
    
        /* reset counter and install handler */
        inth_IrqCount[intVector] = 0;
        inth_IrqHandler[intVector] = intHandler;
    }
    else
    {
        returnCode = RET_PARAM_OUT_OF_RANGE;
    }

    return returnCode;

} /* INTH_SetupInterrupt() */

/*==================== Function Separator =============================*/

ReturnCode_t INTH_EnableInterrupt( const Uint32 intVector)
{
    ReturnCode_t returnCode = RET_OK;

    /* Enable Interrupt */
#ifndef _SECURE_DEVICE
    GICD_Intr_Enable_Disable(ptrGIC400_Handle, intVector, INTH_ACTION_ENABLE);
#else
    go_secure(GICD_Intr_Enable_Disable,
               (Uint32)ptrGIC400_Handle, intVector, (Uint32)INTH_ACTION_ENABLE);
#endif

    return returnCode;

} /* INTH_EnableInterrupt() */

/*==================== Function Separator =============================*/

ReturnCode_t INTH_DisableInterrupt( const Uint32 intVector)
{

    ReturnCode_t returnCode = RET_OK;

    /* Disable Interrupt */
#ifndef _SECURE_DEVICE
    GICD_Intr_Enable_Disable(ptrGIC400_Handle, intVector, INTH_ACTION_DISABLE);
#else
    go_secure(GICD_Intr_Enable_Disable,
              (Uint32)ptrGIC400_Handle, intVector, (Uint32)INTH_ACTION_DISABLE);
#endif

    return returnCode;

} /* INTH_DisableInterrupt() */

/*==================== Function Separator =============================*/

ReturnCode_t INTH_GetIntCount( const Uint32   intVector,
                               Uint32 *const pIntCount  )
{

    ReturnCode_t returnCode = RET_OK;
   
    /* return count value */
    *pIntCount = inth_IrqCount[intVector];

    return returnCode;

} /* INTH_GetIntCount() */

/*==================== Function Separator =============================*/

ReturnCode_t INTH_GetIntHandler( const Uint32   intVector,
                                 INTH_Handler_t *const pIntHandler )
{

    ReturnCode_t returnCode = RET_OK;
   
    /* return count value */
    *pIntHandler = inth_IrqHandler[intVector];
    return returnCode;

} /* INTH_GetIntCount() */

/*==================== Function Separator =============================*/

ReturnCode_t INTH_SetSwInt( const Uint8                sgiId,
                            const INTH_SGI_Target_Mode_t trgtType, 
                            const  Uint8               trgtList)
{
    ReturnCode_t returnCode = RET_OK;

    /* Setup & trigger SGI */
    returnCode = GICD_TriggerSGI(ptrGIC400_Handle, sgiId, trgtType, trgtList);

    return returnCode;
}

/*==================== Function Separator =============================*/

ReturnCode_t INTH_ClearIntCount( const Uint32 intVector )
{

    ReturnCode_t returnCode = RET_OK;
   
    /* return count value */
    inth_IrqCount[intVector] = 0;

    return returnCode;

} /* INTH_ClearIntCount() */


/*==================== Function Separator =============================*/

void INTH_SetEndOfInt(Uint32 eoiVal)
{
    GICC_EndOfInt(ptrGIC400_Handle, eoiVal);   // Write to EOI
}

/*==================== Function Separator =============================*/

void INTH_DeactivateInt(Uint32 dirVal)
{
    GICC_DeactInt(ptrGIC400_Handle, dirVal);   // Write to DIR
}

/*==================== Function Separator =============================*/

ReturnCode_t INTH_Set_Pending(Uint32 intVector)
{
    return GICD_Set_Pending(ptrGIC400_Handle, intVector);
}

/*==================== Function Separator =============================*/

ReturnCode_t INTH_Clear_Pending(Uint32 intVector)
{
    return GICD_Clear_Pending(ptrGIC400_Handle, intVector);
}

/*==================== Function Separator =============================*/

void INTH_Set_Active(Uint32 intVector)
{
    GICD_Set_Active(ptrGIC400_Handle, intVector);
}

/*==================== Function Separator =============================*/

void INTH_Clear_Active(Uint32 intVector)
{
    GICD_Clear_Active(ptrGIC400_Handle, intVector);
}

/*==================== Function Separator =============================*/

void INTH_IRQHandler( void )
{
    Uint32 vecId = 0;
    Uint32 vecIdx = 0;

    /* Get pending interrupt */  
#ifndef _SECURE_DEVICE
    vecId = GICC_GetIntId(ptrGIC400_Handle);
#else
    go_secure(GICC_GetIntId,(Uint32)ptrGIC400_Handle, (Uint32)&vecId);
#endif

    vecIdx = (vecId & 0x3FF);  // Mask off CPU bits in case of SGI

    /* increment interrupt counter */
    inth_IrqCount[vecIdx]++;

    /* if an interrupt handler has been registered */
    if (inth_IrqHandler[vecIdx])
    {
        /* call registered interrupt handler */
        inth_IrqHandler[vecIdx](vecId);
    }

    /* Enable for Valid next IRQ   
     * TODO: Probably should be  called from int handler */ 
    GICC_EndOfInt(ptrGIC400_Handle, vecId);   // Write to EOI
    //GICC_DeactInt(ptrGIC400_Handle, vecId);   // Write to DIR

    return; 

}  /* INTH_IRQHandler() */
 
/*==================== Function Separator =============================*/

#if 0
//#pragma INTERRUPT(INTH_FIQHandler, fiq)
void INTH_FIQHandler( void )
{
    uint16_t lvInterrupt;

    /* Get pending interrupt */
    INTCTL_Ack (INTCPS_U_BASE,        /* BaseAddress */
                INTCTL_FIQ,           /* Interrupt kind */
                &lvInterrupt);        /* Interrupt Id */

    /* increment interrupt counter */
    inth_IrqCount[lvInterrupt]++;

    /* if an interrupt handler has been registered */
    if (inth_IrqHandler[lvInterrupt])
    {
        /* call regitered interrupt handler */
        inth_IrqHandler[lvInterrupt](lvInterrupt);
    }

    /* Enable for Valid next IRQ*/
    INTCTL_ValidNext(INTCPS_U_BASE,    /* BaseAddress */
                     INTCTL_FIQ);     /* Interrupt kind */
   return;

}  /* INTH_FIQHandler() */
#endif


/* EOF */
