/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2013
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
 *   ===========================================================================
 */
/** ============================================================================
Interrupts configuration for QMSS
 * =============================================================================
 *  Revision History
 *  ===============
 *  Feb 5, 2013 Brighton Feng  file created
 * =============================================================================
 */

#include <stdio.h>
#include <csl_cpintc.h>
#include "K2_common.h"
#include "K2_Navigator_init_drv.h"

volatile Uint32 intCCNT; 	//CCNT when interrupt happen

void QMSS_INTD_1_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiChannel, uiINT_ID;

	intCCNT= CP15_read_CCNT(); 	//save the CCNT when the interrupt happens

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

	if((uiINT_ID<CSL_ARM_GIC_QMSS_INTD_1_PKTDMA_0)||(uiINT_ID>CSL_ARM_GIC_QMSS_INTD_1_LOW_15))
	{
		printf("QMSS_INTD_1_ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
		return;
	}
	else if(uiINT_ID==CSL_ARM_GIC_QMSS_INTD_1_PKTDMA_0)
	{
		/*clear interrupt status*/
		gpQM_INTD_regs[QMSS_INTD1]->STATUS_CLR_REG4= 1;
		gpQM_INTD_regs[QMSS_INTD1]->INTCNT_REG[0+48]= 1 ;
		gpQM_INTD_regs[QMSS_INTD1]->EOI_REG= 0;

		printf("QMSS PKTDMA Rx SOP Starvation interrupt happens at %u\n", intCCNT);
	}
	else if(uiINT_ID==CSL_ARM_GIC_QMSS_INTD_1_PKTDMA_1)
	{
		/*clear interrupt status*/
		gpQM_INTD_regs[QMSS_INTD1]->STATUS_CLR_REG4= 2;
		gpQM_INTD_regs[QMSS_INTD1]->INTCNT_REG[1+48]= 1 ;
		gpQM_INTD_regs[QMSS_INTD1]->EOI_REG= 1;

		printf("QMSS PKTDMA Rx MOP Starvation interrupt happens at %u\n", intCCNT);
	}
	else if(uiINT_ID<=CSL_ARM_GIC_QMSS_INTD_1_HIGH_31)
	{
		uiChannel= (uiINT_ID-CSL_ARM_GIC_QMSS_INTD_1_HIGH_0);

		/*clear interrupt status*/
		gpQM_INTD_regs[QMSS_INTD1]->STATUS_CLR_REG0= (1<<uiChannel);
		gpQM_INTD_regs[QMSS_INTD1]->INTCNT_REG[uiChannel]= 1 ;
		gpQM_INTD_regs[QMSS_INTD1]->EOI_REG= uiChannel+2;

		printf("QMSS INTD1 high priority queue accumulation channel %d interrupt happens at %u\n", uiChannel, intCCNT);
	}
	else
	{
		uiChannel= (uiINT_ID-CSL_ARM_GIC_QMSS_INTD_1_LOW_0);

		/*clear interrupt status*/
	 	gpQM_INTD_regs[QMSS_INTD1]->STATUS_CLR_REG1= (1<<uiChannel);
		gpQM_INTD_regs[QMSS_INTD1]->INTCNT_REG[uiChannel+32]= 1 ;
		gpQM_INTD_regs[QMSS_INTD1]->EOI_REG= uiChannel+34;
		printf("INTD1 low priority queues accumulation channel %d interrupt happens at %u\n", uiChannel, intCCNT);
	}
}

void QMSS_INTD_2_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiChannel, uiINT_ID;

	intCCNT= CP15_read_CCNT(); 	//save the CCNT when the interrupt happens

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	if((uiINT_ID<CSL_ARM_GIC_QMSS_INTD_2_PKTDMA_0)||(uiINT_ID>CSL_ARM_GIC_QMSS_INTD_2_LOW_15))
	{
		printf("QMSS_INTD_2_ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
		return;
	}
#else
	if((uiINT_ID<CSL_ARM_GIC_QMSS_INTD_2_HIGH_0)||(uiINT_ID>CSL_ARM_GIC_QMSS_INTD_2_LOW_15))
	{
		printf("QMSS_INTD_2_ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
		return;
	}
#endif
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	else if(uiINT_ID==CSL_ARM_GIC_QMSS_INTD_2_PKTDMA_0)
	{
		/*clear interrupt status*/
		gpQM_INTD_regs[QMSS_INTD2]->STATUS_CLR_REG4= 1;
		gpQM_INTD_regs[QMSS_INTD2]->INTCNT_REG[0+48]= 1 ;
		gpQM_INTD_regs[QMSS_INTD2]->EOI_REG= 0;

		printf("QMSS PKTDMA Rx SOP Starvation interrupt happens at %u\n", intCCNT);
	}
	else if(uiINT_ID==CSL_ARM_GIC_QMSS_INTD_2_PKTDMA_1)
	{
		/*clear interrupt status*/
		gpQM_INTD_regs[QMSS_INTD2]->STATUS_CLR_REG4= 2;
		gpQM_INTD_regs[QMSS_INTD2]->INTCNT_REG[1+48]= 1 ;
		gpQM_INTD_regs[QMSS_INTD2]->EOI_REG= 1;

		printf("QMSS PKTDMA Rx MOP Starvation interrupt happens at %u\n", intCCNT);
	}
#endif
	else if(uiINT_ID<=CSL_ARM_GIC_QMSS_INTD_2_HIGH_31)
	{
		uiChannel= (uiINT_ID-CSL_ARM_GIC_QMSS_INTD_2_HIGH_0);

		/*clear interrupt status*/
		gpQM_INTD_regs[QMSS_INTD2]->STATUS_CLR_REG0= (1<<uiChannel);
		gpQM_INTD_regs[QMSS_INTD2]->INTCNT_REG[uiChannel]= 1 ;
		gpQM_INTD_regs[QMSS_INTD2]->EOI_REG= uiChannel+2;

		printf("QMSS INTD2 high priority queue accumulation channel %d interrupt happens at %u\n", uiChannel, intCCNT);
	}
	else
	{
		uiChannel= (uiINT_ID-CSL_ARM_GIC_QMSS_INTD_2_LOW_0);

		/*clear interrupt status*/
	 	gpQM_INTD_regs[QMSS_INTD2]->STATUS_CLR_REG1= (1<<uiChannel);
		gpQM_INTD_regs[QMSS_INTD2]->INTCNT_REG[uiChannel+32]= 1 ;
		gpQM_INTD_regs[QMSS_INTD2]->EOI_REG= uiChannel+34;
		printf("INTD2 low priority queues accumulation channel %d interrupt happens at %u\n", uiChannel, intCCNT);
	}
}

void QueuePendISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiDescriptor;
	Uint32 uiQueue, uiINT_ID;
	
	intCCNT= CP15_read_CCNT(); 	//save the CCNT when the interrupt happens

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	if((uiINT_ID<CSL_ARM_GIC_QMSS_QUE_PEND_658)||(uiINT_ID>CSL_ARM_GIC_QMSS_QUE_PEND_8735))
#else 	//for K2L and K2E
	if((uiINT_ID<CSL_ARM_GIC_QMSS_QUE_PEND_658)||(uiINT_ID>CSL_ARM_GIC_QMSS_QUE_PEND_559))
#endif
	{
		printf("Queue pending ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
		return;
	}
	else 
	{
		if(uiINT_ID<=CSL_ARM_GIC_QMSS_QUE_PEND_665)
		{
			uiQueue= (uiINT_ID-CSL_ARM_GIC_QMSS_QUE_PEND_658+658);
		}
		else
		{
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
			uiQueue= (uiINT_ID-CSL_ARM_GIC_QMSS_QUE_PEND_8704+8704);
#else 	//for K2L and K2E
			uiQueue= (uiINT_ID-CSL_ARM_GIC_QMSS_QUE_PEND_528+528);
#endif
		}
		/*queue must be empty before clear queue pend interrupt*/
		do
		{
			uiDescriptor= KeyStone_queuePop(uiQueue);
		}while(uiDescriptor);
		printf("Queue %d pending interrupt happens at %u\n", uiQueue, intCCNT);
	}
}


void QM_Interrupts_Init(void)
{
	int i;
	GIC_INT_Config int_cfg;

	int_cfg.trigger_type= GIC_TRIGGER_TYPE_LEVEL;
	int_cfg.ucGroupNum= 1; //route QMSS interrupt to group 1, IRQ
	int_cfg.ucPriority= GIC400_PRIORITY_LOWER;

	//setup queue pending interrupts
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	for(i=CSL_ARM_GIC_QMSS_QUE_PEND_658; i<=CSL_ARM_GIC_QMSS_QUE_PEND_8735; i++)
#else 	//for K2L and K2E
	for(i=CSL_ARM_GIC_QMSS_QUE_PEND_658; i<=CSL_ARM_GIC_QMSS_QUE_PEND_559; i++)
#endif
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, QueuePendISR);
	}


	int_cfg.trigger_type= GIC_TRIGGER_TYPE_EDGE;

	//setup Packet DMA interrupts
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_QMSS_INTD_1_PKTDMA_0), 
		&int_cfg, QMSS_INTD_1_ISR);
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_QMSS_INTD_1_PKTDMA_1), 
		&int_cfg, QMSS_INTD_1_ISR);
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_QMSS_INTD_2_PKTDMA_0), 
		&int_cfg, QMSS_INTD_2_ISR);
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_QMSS_INTD_2_PKTDMA_1), 
		&int_cfg, QMSS_INTD_2_ISR);
#endif

	//setup queue accumulation high priority interrupts
	for(i=CSL_ARM_GIC_QMSS_INTD_1_HIGH_0; i<=CSL_ARM_GIC_QMSS_INTD_1_HIGH_31; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, QMSS_INTD_1_ISR);
	}

	for(i=CSL_ARM_GIC_QMSS_INTD_2_HIGH_0; i<=CSL_ARM_GIC_QMSS_INTD_2_HIGH_31; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, QMSS_INTD_2_ISR);
	}


	int_cfg.ucPriority= GIC400_PRIORITY_LOWEST;
	//setup queue accumulation low priority interrupts
	for(i=CSL_ARM_GIC_QMSS_INTD_1_LOW_0; i<=CSL_ARM_GIC_QMSS_INTD_1_LOW_15; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, QMSS_INTD_1_ISR);
	}

	for(i=CSL_ARM_GIC_QMSS_INTD_2_LOW_0; i<=CSL_ARM_GIC_QMSS_INTD_2_LOW_15; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, QMSS_INTD_2_ISR);
	}

}


