#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <ti/csl/csl_chip.h>
#include <ti/csl/src/intc/csl_intc.h>
#include <ti/csl/csl_cpintcAux.h>

#include "Interrupt.h"
//#include "IPC.h"
extern void MEMORY_PROTECT_ISR();

//extern void Test_ISR();

/* CPINTC Instances */
CSL_CPINTC_Handle handle[3] ={0, 0, 0};

/* CPINTC configuration */
cpintcCfg cpintcInfo[MAX_SYSTEM_CPINTC_EVENT] = 
{
  /* inst   event, channel*/
	{0,    7,    64}
};

interruptCfg intInfo[MAX_SYSTEM_VECTOR] = 
{
	/* core   event   vector*/
	{  0,     10,     CSL_INTC_VECTID_4, &MEMORY_PROTECT_ISR},
};

CSL_IntcGlobalEnableState state;
CSL_IntcContext context;
CSL_IntcEventHandlerRecord Record[CSL_INTC_EVENTID_CNT];

CSL_IntcEventHandlerRecord  EventRecord;

CSL_IntcObj     intcObj[16];
CSL_IntcHandle  hintc[16];
uint32_t        coreVector[MAX_CORE_NUM];


/** ============================================================================
 *   @n@b CSL_CPINTC_enableSysInterrupt
 *
 *   @b Description
 *   @n This API generate the system interrupt in the interrupt controller.
 *      
 *   @b Arguments
 *   @verbatim
        hnd        This is the handle to the CPINTC instance.
        sysIntr    System Interrupt which is to be generated.
     @endverbatim
 *
 *   <b> Return Value </b> 
 *       None 
 *
 *   <b> Pre Condition </b>
 *   @n  @a CSL_CPINTC_open() must be called.
 *
 *   <b> Post Condition </b>
 *   @n  The specific System Interrupt is generated.
 *
 *   @b  Writes
 *   @n  CSL_CPINTC_STATUS_SET_INDEX_REG_STATUS_SET_INDEX
 *
 *   @b  Example
 *   @verbatim
        CSL_CPINTCSystemInterrupt     sysIntr;
        CSL_CPINTC_HANDLE             hnd;
        ...
        hnd = CSL_CPINTC_open (0);    // Opens CPINTC Instance 0
        ...
        CSL_CPINTC_generateSysInterrupt (hnd, sysIntr);
        ...
     @endverbatim
 * ===========================================================================
 */
void CSL_CPINTC_generateSysInterrupt 
(
    CSL_CPINTC_Handle           hnd,
    CSL_CPINTCSystemInterrupt   sysIntr
)
{
	/* Generate system interrupt */
    ((CSL_CPINTC_RegsOvly)hnd)->STATUS_SET_INDEX_REG = 
    		CSL_FMK(CPINTC_STATUS_SET_INDEX_REG_STATUS_SET_INDEX, sysIntr);;
}


/**
 *  @b Description
 *  @n  
 *      The functions initializes the INTC module.
 *
 *  @retval
 *      Success -   0
 *  @retval
 *      Error   -   <0
 */
int32_t intcInit()
{
    /* INTC module initialization */
    context.eventhandlerRecord = Record;
    context.numEvtEntries      = CSL_INTC_EVENTID_CNT;
    if (CSL_intcInit (&context) != CSL_SOK) 
        return -1;

    /* Enable NMIs */
    if (CSL_intcGlobalNmiEnable () != CSL_SOK) 
        return -1;
 
    /* Enable global interrupts */
    if (CSL_intcGlobalEnable (&state) != CSL_SOK) 
        return -1;

    /* INTC has been initialized successfully. */
    return 0;
}

int32_t initCPINTC()
{
	uint32_t i;
	uint32_t inst;
	uint32_t event;
	uint32_t channel;
	
	for (i=0; i<MAX_SYSTEM_CPINTC_EVENT; i++)
	{
		inst    = cpintcInfo[i].inst;
		event   = cpintcInfo[i].event;
		channel = cpintcInfo[i].channel;
		
		if (NULL == handle[inst])
		{
			handle[inst] = CSL_CPINTC_open(inst);
		}

		/* Map system interrupt to channel */
		CSL_CPINTC_mapSystemIntrToChannel(handle[inst], event, channel);

		/* It seems there is no requirement to map channel to host interrupt because the mapping is fixed */

		/* Enable system event */
		CSL_CPINTC_enableSysInterrupt(handle[inst], (CSL_CPINTCSystemInterrupt)event);

		/* Enable host interrupt */
		CSL_CPINTC_enableHostInterrupt(handle[inst], (CSL_CPINTCChannel)channel);		
	}


	for (i=0; i<MAX_SYSTEM_CPINTC_EVENT; i++)
	{
		inst    = cpintcInfo[i].inst;
		if (NULL != handle[inst])
		{
			CSL_CPINTC_enableAllHostInterrupt(handle[inst]);
		}
	}
	return 0;
}

/*  @b Description
 *  @n  
 *
 *      Function registers the high priority interrupt.
 *  @retval
 *      Success -   0
 *  @retval
 *      Error   -   <0
 */

int32_t registerInterrupt()
{
	uint32_t i;
	uint32_t event;
	uint32_t vector;
	uint32_t core;
	uint32_t coreID = CSL_chipReadReg (CSL_CHIP_DNUM);
	CSL_IntcEventHandler isr;

	for (i=0; i<MAX_CORE_NUM; i++)
	{
		coreVector[i] = 0;
	}

	for (i=0; i<MAX_SYSTEM_VECTOR; i++)
	{
		core   = intInfo[i].core;
		if (coreID == core)
		{
			event  = intInfo[i].event;
			vector = intInfo[i].vect;
			isr    = intInfo[i].isr;

			if (MAX_CORE_VECTOR <= coreVector[core])
			{
				printf("Core %d Vector Number Exceed\n");
			}

    		hintc[vector] = CSL_intcOpen (&intcObj[vector], event, (CSL_IntcParam*)&vector , NULL);
		    if (hintc[vector] == NULL) 
		    {
		        printf("Error: GEM-INTC Open failed\n");
		        return -1;
		    }

			/* Register an call-back handler which is invoked when the event occurs. */
		    EventRecord.handler = isr;
		    EventRecord.arg = 0;
		    if (CSL_intcPlugEventHandler(hintc[vector],&EventRecord) != CSL_SOK) 
		    {
		        printf("Error: GEM-INTC Plug event handler failed\n");
		        return -1;
		    }

			/* Clearing the events. */
		    if (CSL_intcHwControl(hintc[vector],CSL_INTC_CMD_EVTCLEAR, NULL) != CSL_SOK) 
		    {
		        printf("Error: GEM-INTC CSL_INTC_CMD_EVTCLEAR command failed\n");
		        return -1;
		    }

			/* Enabling the events. */
		    if (CSL_intcHwControl(hintc[vector],CSL_INTC_CMD_EVTENABLE, NULL) != CSL_SOK) 
		    {
		        printf("Error: GEM-INTC CSL_INTC_CMD_EVTENABLE command failed\n");
		        return -1;
		    }
			coreVector[core]++;
		}
	}

    return 0;
}


