/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2013-2014
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
* ============================================================================
 Example to show the initialization of Multicore Navigator for GE test 
 on KeyStone device
* =============================================================================
 *  Revision History
 *  ===============
 *  June 11, 2013 Brighton Feng   File Created
 *  October, 2014 Brighton Feng   Updated for K2E/K2L
 * ============================================================================
 */

#include <stdio.h>
#include <string.h>
#include "K2_common.h"
#include "GE_PktDMA_init.h"
#include "K2_GE_init_drv.h"
#include <csl_qm_queue.h>

#ifdef _BIG_ENDIAN
#ifdef ACC_48_CHANNEL
#include <ti/drv/qmss/firmware/acc48_be_bin.h>
#else
#include <ti/drv/qmss/firmware/acc32_be_bin.h>
#include <ti/drv/qmss/firmware/acc16_be_bin.h>
#endif
#else
#ifdef ACC_48_CHANNEL
#include <ti/drv/qmss/firmware/acc48_le_bin.h>
#else
#include <ti/drv/qmss/firmware/acc32_le_bin.h>
#include <ti/drv/qmss/firmware/acc16_le_bin.h>
#endif
#endif

Uint8 hostDescriptor_MSMC_RAM[MSMC_RAM_HOST_DESCRIPTOR_NUM][GE_DESCRIPTOR_SIZE] __attribute__ ((aligned (128), section ("QMSS_Data.Descriptor_MSMC_RAM")));

Uint8 packetBuffer_MSMC_RAM_Size0[MSMC_RAM_SIZE0_PKT_BUF_NUM][MSMC_RAM_PACKET_BUFFER_SIZE0] __attribute__ ((section ("PacketData.buffer_MSMC_RAM")));
Uint8 packetBuffer_MSMC_RAM_Size1[MSMC_RAM_SIZE1_PKT_BUF_NUM][MSMC_RAM_PACKET_BUFFER_SIZE1] __attribute__ ((section ("PacketData.buffer_MSMC_RAM")));

Uint8 hostDescriptor_DDR[DDR_HOST_DESCRIPTOR_NUM][GE_DESCRIPTOR_SIZE] __attribute__ ((aligned (128), section ("QMSS_Data.Descriptor_DDR")));

Uint8 packetBuffer_DDR_Size0[DDR_SIZE0_PKT_BUF_NUM][DDR_PACKET_BUFFER_SIZE0] __attribute__ ((section ("PacketData.buffer_DDR")));
Uint8 packetBuffer_DDR_Size1[DDR_SIZE1_PKT_BUF_NUM][DDR_PACKET_BUFFER_SIZE1] __attribute__ ((section ("PacketData.buffer_DDR")));

/* descriptor memory region configuration.
descriptor Base address must be specified in ascending order,
no overlap is allowed between regions*/
Qmss_DescMemRegionCfg descMemRegionsCfg[]=
{   /*The base address of descriptor region     Size of each descriptor     Number of descriptors 
                                                16*n,1<=n<=8192             2^(5+n), 0<=n<=15*/
    {(Uint32)hostDescriptor_MSMC_RAM,           GE_DESCRIPTOR_SIZE,       MSMC_RAM_HOST_DESC_LINK_ENTRY_NUM},/*host descriptor in MSMC_RAM*/
    {(Uint32)hostDescriptor_DDR,                GE_DESCRIPTOR_SIZE,       DDR_HOST_DESC_LINK_ENTRY_NUM}/*host descriptor in DDR*/
};

FreeHostQueueCfg freeHostQueueCfgTable[]=
{
    /*free queue number*/       /*address of first descriptor*/                                         /*size of descriptor*/  /*number of descriptors*/   /*address of first buffer*/                     /*size of each buffer*/ 
    {MSMC_RAM_HOST_SIZE0_FDQ,   (Uint32)&hostDescriptor_MSMC_RAM[0][0],                                 GE_DESCRIPTOR_SIZE,   MSMC_RAM_SIZE0_PKT_BUF_NUM, (Uint32)packetBuffer_MSMC_RAM_Size0,            MSMC_RAM_PACKET_BUFFER_SIZE0},/*MSMC_RAM Size0 host Free Descriptor Queue*/
    {MSMC_RAM_HOST_SIZE1_FDQ,   (Uint32)&hostDescriptor_MSMC_RAM[MSMC_RAM_SIZE1_DESC_START_IDX][0],     GE_DESCRIPTOR_SIZE,   MSMC_RAM_SIZE1_PKT_BUF_NUM, (Uint32)packetBuffer_MSMC_RAM_Size1,            MSMC_RAM_PACKET_BUFFER_SIZE1},/*MSMC_RAM Size1 host Free Descriptor Queue*/

    {DDR_HOST_SIZE0_FDQ,        (Uint32)&hostDescriptor_DDR[0][0],                                      GE_DESCRIPTOR_SIZE,   DDR_SIZE0_PKT_BUF_NUM,      (Uint32)packetBuffer_DDR_Size0,                 DDR_PACKET_BUFFER_SIZE0},/*DDR Size0 host Free Descriptor Queue*/
    {DDR_HOST_SIZE1_FDQ,        (Uint32)&hostDescriptor_DDR[DDR_SIZE1_DESC_START_IDX][0],               GE_DESCRIPTOR_SIZE,   DDR_SIZE1_PKT_BUF_NUM,      (Uint32)packetBuffer_DDR_Size1,                 DDR_PACKET_BUFFER_SIZE1}/*DDR Size1 host Free Descriptor Queue*/
};

PktDma_RxFlowCfg flowCfgTable[]=
{
    /*dest_qnum*/ /*sop_offset*/ /*ps_loc*/  /*desc_type*/   /*error retry*/ /*psinfo*/  /*einfo*/  /*size_thresh0(1,2)_en*/ /*size_thresh0,1,2*/ /*fdq0_sz0_qnum*/         /*fdq0_sz1_qnum, sz2_qnum, sz3_qnum*/ /*fdq1_qnum*/           /*fdq2_qnum*/           /*fdq3_qnum*/  /*dest_tag_lo*/ /*dest_tag_hi*/ /*src_tag_lo*/  /*src_tag_hi*/  /*dest_tag_lo_sel*/ /*dest_tag_hi_sel*/ /*src_tag_lo_sel*/  /*src_tag_hi_sel*/
    {GE_RX_DST_Q    ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    DDR_PACKET_BUFFER_SIZE0, 0, 0, DDR_HOST_SIZE0_FDQ,       DDR_HOST_SIZE1_FDQ,       0, 0,   DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,         0,      0,              0,              0,              0,                  0,                  4,                  0},
    {GE_RX_DST_Q+1  ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    MSMC_RAM_PACKET_BUFFER_SIZE0, 0, 0, MSMC_RAM_HOST_SIZE0_FDQ,MSMC_RAM_HOST_SIZE1_FDQ,0, 0,  MSMC_RAM_HOST_SIZE1_FDQ,  MSMC_RAM_HOST_SIZE1_FDQ,  MSMC_RAM_HOST_SIZE1_FDQ,    0,      0,              0,              0,              0,                  0,                  4,                  0},
    {GE_RX_DST_Q+2  ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    DDR_PACKET_BUFFER_SIZE0, 0, 0, DDR_HOST_SIZE0_FDQ,       DDR_HOST_SIZE1_FDQ,       0, 0,   DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,         0,      0,              0,              0,              0,                  0,                  4,                  0},
    {GE_RX_DST_Q+3  ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    DDR_PACKET_BUFFER_SIZE0, 0, 0, DDR_HOST_SIZE0_FDQ,       DDR_HOST_SIZE1_FDQ,       0, 0,   DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,         0,      0,              0,              0,              0,                  0,                  4,                  0},
    {GE_RX_DST_Q+4  ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    DDR_PACKET_BUFFER_SIZE0, 0, 0, DDR_HOST_SIZE0_FDQ,       DDR_HOST_SIZE1_FDQ,       0, 0,   DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,         0,      0,              0,              0,              0,                  0,                  4,                  0},
    {GE_RX_DST_Q+5  ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    DDR_PACKET_BUFFER_SIZE0, 0, 0, DDR_HOST_SIZE0_FDQ,       DDR_HOST_SIZE1_FDQ,       0, 0,   DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,         0,      0,              0,              0,              0,                  0,                  4,                  0},
    {GE_RX_DST_Q+6  ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    DDR_PACKET_BUFFER_SIZE0, 0, 0, DDR_HOST_SIZE0_FDQ,       DDR_HOST_SIZE1_FDQ,       0, 0,   DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,         0,      0,              0,              0,              0,                  0,                  4,                  0},
    {GE_RX_DST_Q+7  ,    0,      0,      Cppi_DescType_HOST,     0,          1,          0,          1, 0, 0,    DDR_PACKET_BUFFER_SIZE0, 0, 0, DDR_HOST_SIZE0_FDQ,       DDR_HOST_SIZE1_FDQ,       0, 0,   DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,       DDR_HOST_SIZE1_FDQ,         0,      0,              0,              0,              0,                  0,                  4,                  0}
};

char * FDQ_str[]=
{
    "MSMC_RAM_HOST_SIZE0_FDQ",      
    "MSMC_RAM_HOST_SIZE1_FDQ",      
    "DDR_HOST_SIZE0_FDQ",      
    "DDR_HOST_SIZE1_FDQ"      
};

char * flow_str[]=
{
	"FLOW_PORT0_TO_DDR",
	"FLOW_PORT1_TO_MSMC_RAM",
	"FLOW_PORT3_TO_DDR",
	"FLOW_PORT4_TO_DDR",
	"FLOW_PORT5_TO_DDR",
	"FLOW_PORT6_TO_DDR",
	"FLOW_PORT7_TO_DDR"
};

Uint32 uiUsedDescRegionNum;
Uint32 uiInitialHostFdqNum;
Uint32 uiUsedRxFlowNum;

/*Descriptor accumulation buffer*/
Uint32 uiaDescriptorAccumulationList[GE_NUM_ETHERNET_PORT][(MAX_ACCU_PAGE_SIZE+1)*2];

/*ping/pong switch of descriptor accumulation buffer*/
Uint32 uiAccPingPong[GE_NUM_ETHERNET_PORT]; 	
Uint32 uiAccPageSize[GE_NUM_ETHERNET_PORT];
void GE_QMSS_Accumulation_config(Uint8 channel, Uint16 pageSize,
	Qmss_AccPacingMode  interruptPacingMode)
{
	Qmss_AccCmdCfg hiQuAccCfg;

	uiAccPingPong[channel]=0;

	if(MAX_ACCU_PAGE_SIZE<pageSize)
		pageSize= MAX_ACCU_PAGE_SIZE;
	uiAccPageSize[channel]= pageSize;

	hiQuAccCfg.channel = channel;
	hiQuAccCfg.command = Qmss_AccCmd_ENABLE_CHANNEL;
	hiQuAccCfg.queueEnMask = 1;
	hiQuAccCfg.listAddress = (uiaDescriptorAccumulationList[channel]);
	hiQuAccCfg.queMgrIndex = GE_RX_DST_Q+channel;
	hiQuAccCfg.maxPageEntries = pageSize+1;
	hiQuAccCfg.timerLoadCount = 5;
	hiQuAccCfg.interruptPacingMode = interruptPacingMode;
	hiQuAccCfg.listEntrySize = Qmss_AccEntrySize_REG_D;
	hiQuAccCfg.listCountMode = Qmss_AccCountMode_ENTRY_COUNT;
	hiQuAccCfg.multiQueueMode = Qmss_AccQueueMode_SINGLE_QUEUE;
	KeyStone_Qmss_Config_Acc_Channel(QMSS_PDSP1, &hiQuAccCfg);

}

/*must be called after GE PSC enabled*/
void GE_PktDMA_init()
{
	int i, j;
	
	uiUsedDescRegionNum= sizeof(descMemRegionsCfg)/sizeof(Qmss_DescMemRegionCfg);
	uiInitialHostFdqNum= sizeof(freeHostQueueCfgTable)/sizeof(FreeHostQueueCfg);
	uiUsedRxFlowNum= sizeof(flowCfgTable)/sizeof(PktDma_RxFlowCfg);

	/*-----------------QMSS queue configuration------------------*/
	K2_QMSS_Linking_RAM_init(QMSS_QM1, QMSS_INTERNAL_LINKING_RAM_ADDRESS,
		QMSS_NUM_INTERNAL_LINKING_ENTRY, 0, 0);
	K2_QMSS_Descriptor_Regions_init(QMSS_QM1, 0, 0, uiUsedDescRegionNum, descMemRegionsCfg);

#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	K2_QMSS_Linking_RAM_init(QMSS_QM2, QMSS_INTERNAL_LINKING_RAM_ADDRESS,
		QMSS_NUM_INTERNAL_LINKING_ENTRY, 0, 0);
	K2_QMSS_Descriptor_Regions_init(QMSS_QM2, 0, 0, uiUsedDescRegionNum, descMemRegionsCfg);
#endif

	KeyStone_Host_Descriptor_Queues_init(freeHostQueueCfgTable, uiInitialHostFdqNum);

	/*-----------------QMSS PDSP fireware configuration------------------*/
#ifdef _BIG_ENDIAN
#ifdef ACC_48_CHANNEL
	KeyStone_Qmss_Download_Firmware(QMSS_PDSP1, &acc48_be, sizeof(acc48_be));
#else
	KeyStone_Qmss_Download_Firmware(QMSS_PDSP1, &acc32_be, sizeof(acc32_be));
	KeyStone_Qmss_Download_Firmware(QMSS_PDSP2, &acc16_be, sizeof(acc16_be));
#endif
#else
#ifdef ACC_48_CHANNEL
	KeyStone_Qmss_Download_Firmware(QMSS_PDSP1, &acc48_le, sizeof(acc48_le));
#else
	KeyStone_Qmss_Download_Firmware(QMSS_PDSP1, &acc32_le, sizeof(acc32_le));
	KeyStone_Qmss_Download_Firmware(QMSS_PDSP2, &acc16_le, sizeof(acc16_le));
#endif
#endif
	gpQM_INTD_regs[0]->STATUS_CLR_REG0= 0xFFFFFFFF;
	gpQM_INTD_regs[0]->STATUS_CLR_REG1= 0xFFFF;

	KeyStone_Qmss_Config_Reclaim_Queue (QMSS_PDSP1, RECLAMATION_QUEUE);
	
	/*-----------------GE PktDMA configuration------------------*/
	KeyStone_pktDma_Global_Control(gpNetCP_DMA_CfgRegs, 256, 5, 5);

	gpNetCP_DMA_CfgRegs->EMULATION_CONTROL_REG=
		(0<<CSL_CPPIDMA_GLOBAL_CONFIG_EMULATION_CONTROL_REG_LOOPBACK_EN_SHIFT) /*1->For Packet DMA loopback test only*/
		|(1<<CSL_CPPIDMA_GLOBAL_CONFIG_EMULATION_CONTROL_REG_SOFT_SHIFT)
		|(0<<CSL_CPPIDMA_GLOBAL_CONFIG_EMULATION_CONTROL_REG_FREE_SHIFT);
#if defined(DEVICE_K2H) || defined(DEVICE_K2K)
	for(i=0; i< GE_NUM_ETHERNET_PORT; i++)
		KeyStone_pktDma_RxCh_enable(gpNetCP_DMA_RxChCfgRegs, GE_DIRECT_RX_PORT1_CHANNEL+i);
	KeyStone_pktDma_RxCh_enable(gpNetCP_DMA_RxChCfgRegs, GE_DIRECT_TX_CHANNEL);//For Packet DMA loopback test only
	KeyStone_pktDma_TxCh_enable(gpNetCP_DMA_TxChCfgRegs, GE_DIRECT_TX_CHANNEL);
	
	KeyStone_pktDma_configureRxFlow(
			&gpNetCP_DMA_RxFlowCfgRegs->RX_FLOW_CONFIG[GE_DIRECT_RX_PORT1_CHANNEL], flowCfgTable, uiUsedRxFlowNum);
#else 	//K2E or K2L
	for(i=0; i< GE_NUM_ETHERNET_PORT; i++)
		for(j=0; j< 8; j++) 	//for eight priority
		{
			KeyStone_pktDma_RxCh_enable(gpNetCP_DMA_RxChCfgRegs, GE_DIRECT_RX_PORT1_CHANNEL+8*i+j);
			KeyStone_pktDma_configureRxFlow(
					&gpNetCP_DMA_RxFlowCfgRegs->RX_FLOW_CONFIG[GE_DIRECT_RX_PORT1_CHANNEL+8*i+j], &flowCfgTable[i], 1);
		}	

	for(j=0; j< 8; j++) 	//for eight priority
	{
		KeyStone_pktDma_TxCh_enable(gpNetCP_DMA_TxChCfgRegs, GE_DIRECT_TX_CHANNEL+j);
	}	
#endif

	//for(i=0; i< GE_NUM_ETHERNET_PORT; i++)
		//GE_QMSS_Accumulation_config(i, 1, Qmss_AccPacingMode_NONE);
}

/*check the descriptors in the queue, for debug purpose*/
void GE_Check_Free_Queues()
{
	int i, j;
	Uint32 uiQuNum, uiEntryCount, uiDescriptorNumber, uiDescriptor;
	
	__asm__(" ISB");
	for(i=0; i<uiInitialHostFdqNum; i++)
	{
		uiQuNum= freeHostQueueCfgTable[i].uiFreeQuNum;
		uiEntryCount= gpQueueStatusConfigRegs[uiQuNum].REG_A_EntryCount;
		uiDescriptorNumber= freeHostQueueCfgTable[i].uiDescriptorNumber;
		if(uiEntryCount!= uiDescriptorNumber)
		{
			printf("number of descriptors in host queue %s (%d) changed from %d to %d\n",
				FDQ_str[i], uiQuNum, uiDescriptorNumber, uiEntryCount);
#if 0
			//printf some descriptors in the queue
			for(j= 0; j<uiEntryCount&&j<10; j++)
			{	
				uiDescriptor= gpQueueManageRegs[uiQuNum].REG_D_Descriptor;
				printf("0x%x->", uiDescriptor);
				gpQueueManageVBUSM[uiQuNum].REG_D_Descriptor= uiDescriptor;
			}
			if(j<10)
				puts("NULL");
			else
				puts("...");
#endif
		}
	}

}

void GE_recycle_queue(Uint32 uiSrcQueue)
{
	Uint32 uiDescriptor;
	uiDescriptor= KeyStone_queuePop(uiSrcQueue);
	while(uiDescriptor)
	{
		/*descriptor Reclamation*/
		KeyStone_queuePush(RECLAMATION_QUEUE, uiDescriptor|FETCH_SIZE_32);

		uiDescriptor= KeyStone_queuePop(uiSrcQueue);
	}
}

/*check the descriptors in the queue, for debug purpose*/
void GE_Check_TxRx_Queues(Bool bRecycle)
{
	int i;
	Uint32 uiQuNum, uiEntryCount;
	
	__asm__(" ISB");

	uiEntryCount= 
		gpQueueStatusConfigRegs[GE_DIRECT_TX_QUEUE].REG_A_EntryCount;
	if(uiEntryCount)
	{
		if(bRecycle)
			GE_recycle_queue(GE_DIRECT_TX_QUEUE);			
		printf("TX queue %d entry count = %d\n", GE_DIRECT_TX_QUEUE, uiEntryCount);
	}

	for(i=0; i<uiUsedRxFlowNum; i++)
	{
		uiQuNum= flowCfgTable[i].rx_dest_qnum;
		uiEntryCount= gpQueueStatusConfigRegs[uiQuNum].REG_A_EntryCount;
		if(uiEntryCount)
		{
			if(bRecycle)
				GE_recycle_queue(uiQuNum);			
			printf("number of descriptors in RX queue %d = %d\n", 
				uiQuNum, uiEntryCount);
		}
	}

	uiEntryCount= 
		gpQueueStatusConfigRegs[0].REG_A_EntryCount;
	if(uiEntryCount)
	{
		if(bRecycle)
			GE_recycle_queue(0);			
		printf("Queue 0 entry count = %d\n", uiEntryCount);
	}
}

void GE_Check_Queue(Uint32 uiQIdx, Uint32 uiExpectEntryCount)
{
	Uint32 uiEntryCount;
	
	__asm__(" ISB");
	uiEntryCount= 
		gpQueueStatusConfigRegs[uiQIdx].REG_A_EntryCount;
	if(uiEntryCount!=uiExpectEntryCount)
		printf("queue %d entry count = %d\n", uiQIdx, uiEntryCount);
}
