/*****************************************************************************
*            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 2003, (C) Copyright 2003 Texas Instruments.  All rights reserved.
*
*   File content:        C file
*
*   Filename:            GIC_CTL.c
*
*   Description:         GIC library function configures the MPU interrupt 
*                        handler with basic functions like routing (to fiq 
*                        or irq) ,enabling ,prioritizing, masking each 
*                        interrupt.
*
*   Module name:         GIC
*
*   Module version:      1.0
*
*****************************************************************************/
/*****************************************************************************
* INCLUDE FILES
******************************************************************************
*/

#include "aintc_inth.h"
#include "GIC_ctl.h"
/*
****************************************************************************
* GLOBAL VARIABLES DECLARATIONS
******************************************************************************
*/
Uint32 glbArmVectID = 0xFFFFFFFF;
/*
****************************************************************************
* LOCAL TYPES AND DEFINITIONS
******************************************************************************
*/

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

/*
****************************************************************************
* LOCAL FUNCTIONS PROTOTYPES
******************************************************************************
*/

/*
****************************************************************************
* GIC Distributor FUNCTIONS
******************************************************************************
*/

/****************************************************************************** 
 * Global and Group Enable/Disable (GICD_CTLR) - Assumed Secure Mode
 ******************************************************************************/
ReturnCode_t GICD_Global_Enable_Disable(CSL_Cortexa15GICRegs *gicHandle,
                                        INTH_Group_t         intGroup,
                                        const INTH_Action_t  intAction)
{
    ReturnCode_t retVal = RET_OK;

    if (intAction == INTH_ACTION_ENABLE)
    {
        if (intGroup == INTH_TYPE_GROUP_0)
            gicHandle->GICD.GICD_DCR |= 0x1;
        else if (intGroup == INTH_TYPE_GROUP_1)
            gicHandle->GICD.GICD_DCR |= 0x2;
        else
            retVal = RET_FAIL;
    }
    else if (intAction == INTH_ACTION_DISABLE)
    {
        if (intGroup == INTH_TYPE_GROUP_0)
            gicHandle->GICD.GICD_DCR &= ~(0x1);
        else if (intGroup == INTH_TYPE_GROUP_1)
            gicHandle->GICD.GICD_DCR &= ~(0x2);
        else
            retVal = RET_FAIL;
    }
    else
        retVal = RET_FAIL;

    return retVal;
}

/****************************************************************************** 
 * Enable/Disable Interrupts (GICD_ISENABLEn/GICD_ICENABLEn)
 ******************************************************************************/
#ifndef _SECURE_DEVICE
void GICD_Intr_Enable_Disable(CSL_Cortexa15GICRegs *gicHandle,
                              Uint32               intVector,
                              INTH_Action_t        intAction)
{
    Uint32 regIdx, regOffset;

    /* Compute register index */
    regIdx = intVector >> 5;

    /* Compute register bit */
    regOffset = intVector - (regIdx*32);

    /* Setup Group */
    if (intAction == INTH_ACTION_ENABLE)
    {
        gicHandle->GICD.GICD_ISER[regIdx] = (1 << regOffset);
    }
    else // (intAction == INTH_ACTION_DISABLE)
    {
        gicHandle->GICD.GICD_ICER[regIdx] = (1 << regOffset);
    }
}
#else
Uint32 GICD_Intr_Enable_Disable(unsigned int (*fcn_p)(),
                                Uint32 xgicHandle,
                                Uint32 intVector,
                                Uint32 xintAction)
{
    Uint32 regIdx, regOffset;
    CSL_Cortexa15GICRegs *gicHandle;
    INTH_Action_t  intAction;

    gicHandle = (CSL_Cortexa15GICRegs *) xgicHandle;
    intAction = (INTH_Action_t)xintAction;

    /* Compute register index */
    regIdx = intVector >> 5;

    /* Compute register bit */
    regOffset = intVector - (regIdx*32);

    /* Setup Group */
    if (intAction == INTH_ACTION_ENABLE)
    {
        gicHandle->GICD.GICD_ISER[regIdx] = (1 << regOffset);
    }
    else // (intAction == INTH_ACTION_DISABLE)
    {
        gicHandle->GICD.GICD_ICER[regIdx] = (1 << regOffset);
    }

    return 0; //dummy return for secure call compatibility
}
#endif


/****************************************************************************** 
 * Level/Edge triggered event config (GICD_ICFGRn)
 * NOTE: This setup will eventually be performed by boot ROM
 ******************************************************************************/
void GICD_SetTriggerType(CSL_Cortexa15GICRegs *gicHandle)
{
    int regIdx;

    /* Setup events as edge/pulse triggered */
    /* Regs 0 and 1 are for SGIs and PPIs respectively and are READ ONLY */
    for (regIdx=2; regIdx < (NUM_GIC400_INTC_EVENTS/16); regIdx++) 
    {
        if (regIdx != 3)
        {
            gicHandle->GICD.GICD_ICFGR[regIdx] = 0xAAAAAAAA;//0x55555555;
        }
    }

    /* Events 52 - 57 are level triggered */
    gicHandle->GICD.GICD_ICFGR[3] = 0xAAA555AA;//0x55555555;//

    //DSB
    asm("  sub r0,r0,r0");
    asm("  mcr p15, #0, r0, c7, c10, #4");
}


/****************************************************************************** 
 * Generate SGI (GICD_SGIR)
 ******************************************************************************/
ReturnCode_t GICD_TriggerSGI(CSL_Cortexa15GICRegs         *gicHandle,
                             const Uint8                sgiID, 
                             const INTH_SGI_Target_Mode_t trgtType, 
                             const Uint8                trgtList)
{
    Uint32 sgirVal = 0;
    ReturnCode_t retVal = RET_OK;

    if (sgiID >= MAX_GIC_SGI)
    {
        retVal = RET_INVALID_ID;
    }
    else if (trgtType >= TARGET_KIND_MAX)
    {
        retVal = RET_PARAM_OUT_OF_RANGE;
    }
    else
    {
        sgirVal = sgiID                                                       | 
                  CSL_CORTEXA15_GICD_SGIR_SATT_MASK                           |
                  (trgtList << CSL_CORTEXA15_GICD_SGIR_CPUTARGETLIST_SHIFT)   | 
                  (trgtType << CSL_CORTEXA15_GICD_SGIR_TARGETLISTFILTER_SHIFT);

        gicHandle->GICD.GICD_SGIR = sgirVal;
    }

    return retVal;
}

/*
 * Set pending int (GICD_ISPENDRn)
 */
ReturnCode_t GICD_Set_Pending(CSL_Cortexa15GICRegs *gicHandle, 
                              Uint32 intVector)
{
    Uint32 regIdx, regOffset;
    ReturnCode_t retVal = RET_OK;

    if (intVector < 16)
    {
        retVal = RET_INVALID_ID;
    }
    else
    {
        /* Compute register index */
        regIdx = intVector >> 5;
    
        /* Compute register bit */
        regOffset = intVector - (regIdx*32);
    
        /* Set state to Pending */
        gicHandle->GICD.GICD_ISPR[regIdx] |= (1 << regOffset);
    }

    return retVal;
}

/*
 * Clear Pending state (GICD_ICPENDRn)
 */
ReturnCode_t GICD_Clear_Pending(CSL_Cortexa15GICRegs *gicHandle, 
                                Uint32 intVector)
{
    Uint32 regIdx, regOffset;
    ReturnCode_t retVal = RET_OK;

    if (intVector < 16)
    {
        retVal = RET_INVALID_ID;
    }
    else
    {
        /* Compute register index */
        regIdx = intVector >> 5;
    
        /* Compute register bit */
        regOffset = intVector - (regIdx*32);
    
        /* Set state to Pending */
        gicHandle->GICD.GICD_ICPR[regIdx] |= (1 << regOffset);
    }

    return retVal;
}

/*
 * Set int to ACTIVE state(GICD_ISACTIVERn)
 */
void GICD_Set_Active(CSL_Cortexa15GICRegs *gicHandle, Uint32 intVector)
{
    Uint32 regIdx, regOffset;

    /* Compute register index */
    regIdx = intVector >> 5;

    /* Compute register bit */
    regOffset = intVector - (regIdx*32);
    
    /* Set state to Pending */
    gicHandle->GICD.GICD_ISACTIVER[regIdx] |= (1 << regOffset);
}

/*
 * Clear ACTIVE state for int. (GICD_ICACTIVERn)
 */
void GICD_Clear_Active(CSL_Cortexa15GICRegs *gicHandle, Uint32 intVector)
{
    Uint32 regIdx, regOffset;

    /* Compute register index */
    regIdx = intVector >> 5;

    /* Compute register bit */
    regOffset = intVector - (regIdx*32);
    
    /* Set state to Pending */
    gicHandle->GICD.GICD_ICACTIVER[regIdx] |= (1 << regOffset);
}



/****************************************************************************** 
 * Map iterrupt to group.
 ******************************************************************************/
#ifndef _SECURE_DEVICE
void  GICD_Set_Intr_Group(CSL_Cortexa15GICRegs *gicHandle,
                          Uint32               intVector,
                          INTH_Group_t         intGroup)
{
    Uint32 regIdx, regOffset;

    /* Compute register index */
    regIdx = intVector >> 5;

    /* Compute register bit */
    regOffset = intVector - (regIdx*32);

    /* Setup Group */
    if (intGroup == INTH_TYPE_GROUP_0)
        gicHandle->GICD.GICD_IGRP[regIdx] &= ~(1 << regOffset);
    else // (intGroup == INTH_TYPE_GROUP_1)
        gicHandle->GICD.GICD_IGRP[regIdx] |= (1 << regOffset);
}
#else
Uint32 GICD_Set_Intr_Group(unsigned int (*fcn_p)(),
                           Uint32 xgicHandle,
                           Uint32 intVector,
                           Uint32 xintGroup)
{
    Uint32 regIdx, regOffset;
    CSL_Cortexa15GICRegs *gicHandle;
    INTH_Group_t   intGroup;

    gicHandle = (CSL_Cortexa15GICRegs *) xgicHandle;

    intGroup = (INTH_Group_t) xintGroup;

    /* Compute register index */
    regIdx = intVector >> 5;

    /* Compute register bit */
    regOffset = intVector - (regIdx*32);

    /* Setup Group */
    if (intGroup == INTH_TYPE_GROUP_0)
        gicHandle->GICD.GICD_IGRP[regIdx] &= ~(1 << regOffset);
    else // (intGroup == INTH_TYPE_GROUP_1)
        gicHandle->GICD.GICD_IGRP[regIdx] |= (1 << regOffset);

    return 0; //dummy return for secure call compatibility
}
#endif

/****************************************************************************** 
 * Set Group1 Interrupt Priority.
 ******************************************************************************/
void GICD_Set_Group1_Intr_Priority(CSL_Cortexa15GICRegs  *gicHandle,
                                   const Uint32        intVector,
                                   const INTH_Priority_t intPriority)
{
    Uint32 regIdx, regOffset;
    Uint32 regVal = 0x80;

    /* Compute register index */
    regIdx = intVector >> 2;

    /* Compute register byte */
    regOffset = (intVector - (regIdx * 4));

    regVal |= ((intPriority & 0x0F) << 3);

    // Write Priority value
    regByteWrite((Uint32)&gicHandle->GICD.GICD_IPRIORITYR[regIdx],
                                                        regOffset, regVal);
}

/****************************************************************************** 
 * Set Targets for interrupt. (Assumed Secure access)
 ******************************************************************************/
#ifndef _SECURE_DEVICE
void GICD_Set_Intr_Targets(CSL_Cortexa15GICRegs *gicHandle,
                           Uint32               intVector,
                           Uint8                intTargetMask)
{
    Uint32 regIdx, regOffset;

    /* Compute register index */
    regIdx = intVector >> 2;

    /* Compute register byte */
    regOffset = (intVector - (regIdx * 4));

    // Write Priority value
    regByteWrite((Uint32)&gicHandle->GICD.GICD_IPTARGETR[regIdx],
                                                  regOffset, intTargetMask);
}
#else
Uint32 GICD_Set_Intr_Targets(unsigned int (*fcn_p)(),
                             Uint32 xgicHandle,
                             Uint32 intVector,
                             Uint32 xintTargetMask)
{
    Uint32 regIdx, regOffset;
    CSL_Cortexa15GICRegs *gicHandle;
    Uint8        intTargetMask;

    gicHandle = (CSL_Cortexa15GICRegs *) xgicHandle;
    intTargetMask = (Uint8)xintTargetMask;

    /* Compute register index */
    regIdx = intVector >> 2;

    /* Compute register byte */
    regOffset = (intVector - (regIdx * 4));

    // Write Priority value
    regByteWrite((Uint32)&gicHandle->GICD.GICD_IPTARGETR[regIdx],
                                                  regOffset, intTargetMask);

    return 0; //dummy return for secure call compatibility
}
#endif
/****************************************************************************** 
 * Initialize GIC Distributor
 ******************************************************************************/
#ifndef _SECURE_DEVICE
Uint32 GICD_InitDistributor(CSL_Cortexa15GICRegs *gicHandle)
{
    ReturnCode_t retVal = RET_OK;

    /* Enable global interrupt forwarding from distributor */
    retVal |= GICD_Global_Enable_Disable(gicHandle, 
                                         INTH_TYPE_GROUP_0, 
                                         INTH_ACTION_ENABLE); 

    retVal |= GICD_Global_Enable_Disable(gicHandle, 
                                         INTH_TYPE_GROUP_1, 
                                         INTH_ACTION_ENABLE); 

    /* Config level/edge triggered  <===  BootROM ???? */
    GICD_SetTriggerType(gicHandle);

    return (Uint32) retVal;
}
#else
Uint32 GICD_InitDistributor(unsigned int (*fcn_p)(), 
                            CSL_Cortexa15GICRegs *gicHandle)
{
    ReturnCode_t retVal = RET_OK;

    /* Enable global interrupt forwarding from distributor */
    retVal |= GICD_Global_Enable_Disable(gicHandle, 
                                         INTH_TYPE_GROUP_0, 
                                         INTH_ACTION_ENABLE); 

    retVal |= GICD_Global_Enable_Disable(gicHandle, 
                                         INTH_TYPE_GROUP_1, 
                                         INTH_ACTION_ENABLE); 

    /* Config level/edge triggered  <===  BootROM ???? */
    GICD_SetTriggerType(gicHandle);

    return (Uint32) retVal;
}
#endif

/*
****************************************************************************
* GIC CPU Interface FUNCTIONS
******************************************************************************
*/

/*******************************************************************
 * Initialize GIC CPU INterface - (Assumed Secure Mode)
 *
 *  GICC_CTLR
 *
 *  EnableGrp0    - 1 (Enable)
 *  EnableGrp1    - 1 (Enable)
 *  AckCtl        - 0
 *  FIQEn         - 1 (Group0 routed to FIQ)
 *  CBPR          - 0
 *  FIQBypDisGrp0 - 0 (Don't Care)
 *  IRQBypDisGrp0 - 0 (Don't Care)
 *  FIQBypDisGrp1 - 0 (Don't Care)
 *  IRQBypDisGrp1 - 0 (Don't Care)
 *  EOImodeS      - 0 (Priority drop and deactivation not seperated)
 *  EOImodeNS     - 0 (Priority drop and deactivation not seperated)
 ******************************************************************/
#ifndef _SECURE_DEVICE
void GICC_InitCPUInterface(CSL_Cortexa15GICRegs *gicHandle)
{
    Uint32 giccCtrlVal = CSL_CORTEXA15_GICC_ICR_RESETVAL;

    giccCtrlVal = CSL_CORTEXA15_GICC_ICR_ENABLES_MASK  | 
                  CSL_CORTEXA15_GICC_ICR_ENABLENS_MASK | 
                  //CSL_CORTEXA15_GICC_ICR_ACKCTL_MASK   |
                  CSL_CORTEXA15_GICC_ICR_FIQEN_MASK;//    |
                  //CSL_CORTEXA15_GICC_ICR_EOIMODES_MASK |
                  //CSL_CORTEXA15_GICC_ICR_EOIMODENS_MASK;

    /* Init interface controller */
    gicHandle->GICC.GICC_ICR = giccCtrlVal;

    /* Set PMR to 0xFF */
    gicHandle->GICC.GICC_PMR = 0xFF;
}
#else
Uint32 GICC_InitCPUInterface(unsigned int (*fcn_p)(),
                             CSL_Cortexa15GICRegs *gicHandle)
{
    Uint32 giccCtrlVal = CSL_CORTEXA15_GICC_ICR_RESETVAL;

    giccCtrlVal = CSL_CORTEXA15_GICC_ICR_ENABLES_MASK  | 
                  CSL_CORTEXA15_GICC_ICR_ENABLENS_MASK | 
                  //CSL_CORTEXA15_GICC_ICR_ACKCTL_MASK   |
                  CSL_CORTEXA15_GICC_ICR_FIQEN_MASK;//    |
                  //CSL_CORTEXA15_GICC_ICR_EOIMODES_MASK |
                  //CSL_CORTEXA15_GICC_ICR_EOIMODENS_MASK;

    /* Init interface controller */
    gicHandle->GICC.GICC_ICR = giccCtrlVal;

    /* Set PMR to 0xFF */
    gicHandle->GICC.GICC_PMR = 0xFF;

    return 0;  //Dummy return
}
#endif

/*
 * Acknowledge interrupt (GICC_IAR/GICC_AIAR)
 */
#ifndef _SECURE_DEVICE
Uint32 GICC_GetIntId(CSL_Cortexa15GICRegs *gicHandle)
{
    /*
     * NOTE:
     * =====
     * On a non-secure Keystone2 device all transactions recieved 
     * by GIC-400 are marked as secure transactions.
     *
     * (From GIC-400 ARM)
     * For a GICv2 implementation:
     *    A GROUP 0 interrupt is acknowledged by a read of GICC_IAR, 
     *    or a Secure read of GICC_IAR if the * implementation includes 
     *    the GIC Security Extensions
     *
     *    A GROUP 1 interrupt is acknowledged by a read of GICC_AIAR, 
     *    or a Non-secure read of GICC_IAR if the implementation includes 
     *    the GIC Security Extensions
     */
    glbArmVectID = gicHandle->GICC.GICC_AIAR & 0x1FFF;
    return glbArmVectID;
}
#else
Uint32 GICC_GetIntId(unsigned int (*fcn_p)(),Uint32 xgicHandle, Uint32 xvecId)
{
    CSL_Cortexa15GICRegs *gicHandle;
    Uint32 *vecId = (Uint32 *) xvecId;

    gicHandle = (CSL_Cortexa15GICRegs *) xgicHandle;
    *vecId = (gicHandle->GICC.GICC_AIAR & 0x1FFF);
    glbArmVectID = *vecId;
    return *vecId;
}
#endif


/*
 * Signal End-of-Interrupt (GICC_EOIR/GICC_AEOIR)
 */
void GICC_EndOfInt(CSL_Cortexa15GICRegs *gicHandle, Uint32 eoiId)
{
    /*
     * NOTE:
     * =====
     * On a non-secure Keystone2 device all transactions recieved 
     * by GIC-400 are marked as secure transactions.
     *
     * (From GIC-400 ARM)
     * A Non-secure write to GICC_EOIR must correspond to the most recent 
     * Non-secure read of GICC_IAR
     *
     * A Secure write to the GICC_AEOIR must correspond to the most recent 
     * Secure read of the GICC_AIAR.
     * 
     */
    gicHandle->GICC.GICC_AEOIR = eoiId;
}

/*
 * Deactivate Interrupt (GICC_DIR)
 */
void GICC_DeactInt(CSL_Cortexa15GICRegs *gicHandle, Uint32 eoiId)
{
    gicHandle->GICC.GICC_DIR = eoiId;
}


/***************************************************************************
 * GIC Interface Functions 
 **************************************************************************/

void GIC_Init(CSL_Cortexa15GICRegs *gicHandle)
{

    /* Init Distributor */
#ifndef _SECURE_DEVICE
    GICD_InitDistributor(gicHandle);
#else
    go_secure(GICD_InitDistributor,gicHandle);
   
    /* Setup non-secure copy */
    GICD_Global_Enable_Disable(gicHandle, 
                               INTH_TYPE_GROUP_1, 
                               INTH_ACTION_ENABLE); 
#endif


    /* Init CPU Interface */
#ifndef _SECURE_DEVICE
    GICC_InitCPUInterface(gicHandle);
#else
    go_secure(GICC_InitCPUInterface,gicHandle);
#endif
}

