/*  ============================================================================
 *   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 and handling for GE
 * =============================================================================
 *  Revision History
 *  ===============
 *  June 11, 2013 Brighton Feng  file created
 * =============================================================================
 */

#include <stdio.h>
#include <csl_cpintc.h>
#include <cslr_pa_ss.h>
#include "K2_common.h"
#include "K2_GE_Init_drv.h"
#include "GE_test.h"
#include "GE_debug.h"
#include "GE_PktDMA_Init.h"
#include "GE_packets_process.h"

extern void Timer_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress);

volatile Uint32 GE_INT_CCNT=0;
/*receive packets in queue pend ISR*/
void GE_Message_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	int i;
	Uint32 uiDescriptor;

	GE_INT_CCNT= CP15_read_CCNT(); 	//save the TSC when the interrupt happens

	//printf("Queue pend interrupt happens at %u\n", GE_INT_CCNT);

	for(i=0; i< GE_NUM_ETHERNET_PORT; i++)
	{
		uiDescriptor= KeyStone_queuePop(GE_RX_DST_Q+i);
		/*queue must be empty before clear queue pend interrupt*/
		while(uiDescriptor)
		{
			Rx_packet_process(i, uiDescriptor);
			uiDescriptor= KeyStone_queuePop(GE_RX_DST_Q+i);
		}
	}
}

void PHY_Link_State_Update(Uint32 link_num)
{
	Uint32 uiPhy_NUM;

	uiPhy_NUM= gpMDIO_regs->USER_GROUP[link_num].USER_PHY_SEL_REG&CSL_MDIO_USER_PHY_SEL_REG_LINKSEL_SHIFT;
	if(gpMDIO_regs->LINK_REG&(1<<uiPhy_NUM))
	{
		printf("Ethernet PHY%d link up. CCNT= 0x%x\n", uiPhy_NUM, CP15_read_CCNT());
		print_GE_link_ability(link_num);
	}
	else
		printf("Ethernet PHY%d link down. CCNT= 0x%x\n", uiPhy_NUM, CP15_read_CCNT());

	/* Clear Interrupt events in MDIO*/
	gpMDIO_regs->LINK_INT_RAW_REG= 1<<uiPhy_NUM;
}

void GE_MISC_MDIO_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiINT_ID;

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

	if(CSL_ARM_GIC_NETCP_MDIO_LINK_INT0==uiINT_ID)
	{
		PHY_Link_State_Update(0);
	}

	if(CSL_ARM_GIC_NETCP_MDIO_LINK_INT1==uiINT_ID)
	{
		PHY_Link_State_Update(1);
	}

	if(CSL_ARM_GIC_NETCP_MISC_INT==uiINT_ID)
	{
#ifdef CSL_PA_SS_INTD_STATUS2_STATUS_HOST_CPSW_STAT0_SYNCD_MASK
		if(gpNetCP_regs->INTD.INTD_STATUS2&CSL_PA_SS_INTD_STATUS2_STATUS_HOST_CPSW_STAT0_SYNCD_MASK)
		{
			puts("GE STATA wraps around");
		}

		if(gpNetCP_regs->INTD.INTD_STATUS2&CSL_PA_SS_INTD_STATUS2_STATUS_HOST_CPSW_STAT1_SYNCD_MASK)
		{
			puts("GE STATB wraps around");
		}

		if(gpNetCP_regs->INTD.INTD_STATUS2&0x20)
		{
			puts("GE STATC wraps around");
		}

		if(gpNetCP_regs->INTD.INTD_STATUS2&0x40)
		{
			puts("GE STATD wraps around");
		}

		/*accumulate the statistics values in the registers to the software data structure.*/
		K2_GE_Accumulate_Statistics();

		gpNetCP_regs->INTD.INTD_STATUS_CLR2= gpNetCP_regs->INTD.INTD_STATUS2;

		//EOI
		gpNetCP_regs->INTD.INTD_EOI= gpNetCP_regs->INTD.INTD_INTR_VECTOR;
#endif
	}
}

void GE_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
	for(i=CSL_ARM_GIC_QMSS_QUE_PEND_658; i<=CSL_ARM_GIC_QMSS_QUE_PEND_665; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, GE_Message_ISR);
	}


	int_cfg.trigger_type= GIC_TRIGGER_TYPE_EDGE;
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_NETCP_MDIO_LINK_INT0), 
		&int_cfg, GE_MISC_MDIO_ISR);
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_NETCP_MDIO_LINK_INT1), 
		&int_cfg, GE_MISC_MDIO_ISR);
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_NETCP_MISC_INT), 
		&int_cfg, GE_MISC_MDIO_ISR);

	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_TIMER_16_INTL+2*CP15_get_CPU_ID()), 
		&int_cfg, Timer_ISR);
}

