/******************************************************************************
 * Copyright (c) 2010 Texas Instruments Incorporated - http://www.ti.com
 * 
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the   
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 ****************************************************************************
 *
 * Project     EVM
 * @file       Srio_Tst.c
 * 
 * @brief      EVM srio test example functions
 *  
 * @ingroup    EVM_SRIO_TEST
 *
 ****************************************************************************
 *                                                                                          
 * "$Revision: 1.2 $"
 * "$Date: 2011/02/25 19:29:31 $"
 *
 ***************************************************************************/


/****************************************************************************
 *                                 Includes                                 *
 ****************************************************************************/

#include <stdio.h>
#include "evm.h"
#include "srio_util.h"
#include "srio_tst.h"
#include "mydebug.h"
#include "c6x.h"
#pragma diag_suppress 880
#include "csl_srioAux.h"
#pragma diag_default 880
/*INTC include*/
#include <csl_intc.h>
#include <cslr_intc.h>
#include <_csl_intc.h>
#include <csl_intcAux.h>

#ifndef PASS
#define PASS		(1)
#endif

#ifndef FAIL
#define FAIL		(0)
#endif

#define SUCCESS		PASS
#define FAILURE		FAIL

#define TOUT1 0x20000000
#define TOUT2 0x2000
#define TOUT3 0x2000000


// Buffer size used for srio in words
#define BUFSIZE	0xC00

/* Buffer are placed in L2 Memory and aligned */
#pragma DATA_SECTION(SrcBuff, ".SRIOOutDat")
#pragma DATA_ALIGN( SrcBuff,8)
volatile Uint32  SrcBuff[BUFSIZE];

#pragma DATA_SECTION(DstBuff, ".SRIOInDat")
#pragma DATA_ALIGN(DstBuff,8)
volatile Uint32  DstBuff[BUFSIZE];

#pragma DATA_SECTION(DstBuff_ddr, ".ddrmem")
#pragma DATA_ALIGN(DstBuff_ddr,8)
volatile Uint32  DstBuff_ddr[BUFSIZE];

// This define the test setup for each srio possible test
SRIOTST_CONFIG tstconfig[(enum SRIOTST_TYPE)SRIOTST_TYPE_END]={
{0,4,1,4,(enum SRIO_DR)SRIO_DR_5000,SRIOTST_DSP1_BASE_ADDR,SRIOTST_DSP1_BASE_ADDR,1,1,0,0,1,SRIOTST_DSP2_BASE_ADDR,SRIOTST_DSP2_BASE_ADDR,1,1,0,0,1},
{2,0,0,4,(enum SRIO_DR)SRIO_DR_5000,SRIOTST_DSP1_BASE_ADDR,SRIOTST_DSP2_BASE_ADDR,1,0,0,1,1,SRIOTST_DSP2_BASE_ADDR,SRIOTST_DSP1_BASE_ADDR,0,1,1,0,0},
{3,0,0,4,(enum SRIO_DR)SRIO_DR_5000,SRIOTST_DSP1_BASE_ADDR,SRIOTST_DSP2_BASE_ADDR,1,0,0,1,1,SRIOTST_DSP2_BASE_ADDR,SRIOTST_DSP1_BASE_ADDR,0,1,1,0,0},
{2,1,0,4,(enum SRIO_DR)SRIO_DR_5000,SRIOTST_DSP1_BASE_ADDR,SRIOTST_DSP1_BASE_ADDR,1,0,0,1,1,SRIOTST_DSP2_BASE_ADDR,SRIOTST_DSP1_BASE_ADDR,0,1,1,0,0},
{0,0,0,4,(enum SRIO_DR)SRIO_DR_5000,SRIOTST_DSP1_BASE_ADDR,SRIOTST_DSP2_BASE_ADDR,1,0,0,1,1,SRIOTST_DSP2_BASE_ADDR,SRIOTST_DSP1_BASE_ADDR,0,1,1,0,0},
{1,0,0,4,(enum SRIO_DR)SRIO_DR_5000,(SRIOTST_DSP1_BASE_ADDR+1),(SRIOTST_DSP2_BASE_ADDR+1),1,0,0,1,1,(SRIOTST_DSP2_BASE_ADDR+1),(SRIOTST_DSP1_BASE_ADDR+1),0,1,1,0,0},
{0,0,0,4,(enum SRIO_DR)SRIO_DR_5000,SRIOTST_DSP1_BASE_ADDR,SRIOTST_DSP1_BASE_ADDR,1,1,0,0,1,SRIOTST_DSP2_BASE_ADDR,SRIOTST_DSP2_BASE_ADDR,1,1,0,0,1},
{1,0,0,4,(enum SRIO_DR)SRIO_DR_5000,(SRIOTST_DSP1_BASE_ADDR+1),(SRIOTST_DSP1_BASE_ADDR+1),1,1,0,0,1,(SRIOTST_DSP2_BASE_ADDR+1),(SRIOTST_DSP2_BASE_ADDR+1),1,1,0,0,1},
{0,0,0,4,(enum SRIO_DR)SRIO_DR_5000,SRIOTST_DSP1_BASE_ADDR_AMC,SRIOTST_DSP1_BASE_ADDR_AMC,1,1,0,0,1,SRIOTST_DSP2_BASE_ADDR_AMC,SRIOTST_DSP2_BASE_ADDR_AMC,1,1,0,0,1},
{1,0,0,4,(enum SRIO_DR)SRIO_DR_5000,(SRIOTST_DSP1_BASE_ADDR_AMC+1),(SRIOTST_DSP1_BASE_ADDR_AMC+1),1,1,0,0,1,(SRIOTST_DSP2_BASE_ADDR_AMC+1),(SRIOTST_DSP2_BASE_ADDR_AMC+1),1,1,0,0,1},
};
Uint32 LSU_test[16] = {3,2,1,0,7,6,5,4,3,2,1,0,7,6,5,4};

/* INTC Parameter */
CSL_IntcContext intcContext;
CSL_IntcEventHandlerRecord EventHandler[30];
CSL_Status intStat;
CSL_IntcObj intcObj;
CSL_IntcHandle hnd1, hnd2;
CSL_IntcEventHandlerRecord EventRecord1, EventRecord2;
CSL_IntcGlobalEnableState state;
CSL_IntcParam vecId;
CSL_IntcEventId evtId;

Int32 SRIO_Test(Int32 index);

Int32 do_SRIO_Test(Int32 index)
{
    int iResult;

    myprintf("SRIO Test...\r\n",0,0);

    iResult = SRIO_Test(index);

    if (!iResult)
    {
        myprintf("SRIO Test... SUCCESS!\r\n\r\n",0,0); 
    }
    else
    {
        myprintf("SRIO Test... ERROR!\r\n\r\n",0,0);
    }

    return(iResult);
}

Uint32 dbTSCL[1024];
volatile Uint32 dbCnt=1;
Uint32 LSUno=0;
#define SRIO_REGS         ((CSL_SrioRegs *) CSL_SRIO_CONFIG_REGS)
void isr_doorBell()
{
	dbTSCL[dbCnt&0x3FF] = TSCL;
	dbCnt++;
	//SRIO_REGS->LSU_ICSR_ICCR[0].RIO_LSU_ICCR	= 0xFFFFFFFF ;  // clear all pending intr
	SRIO_REGS->DOORBELL_ICSR_ICCR[0].RIO_DOORBELL_ICCR	= 0xFFFFFFFF ;  // clear all pending intr
}

Uint32 t0,t1,t2;
Int32 SRIO_Test(Int32 index)
{
	Uint32 testerrors = 0;
	Int32 i0,i1,i2,retcode;
	Uint8 dspid;
    // Compute srio byte length according to buffer size
    Int32 byte_count = (BUFSIZE<<2); //0xC00=3072W  = 12288B
    volatile Int32 iTout;
    Int32 port,mode,loopback,config;
    enum SRIO_DR datarate;
    Uint16 srcid,destid;
    Uint8 sent1st,wait1st,sent2nd,wait2nd,compare;

	
    // WARNING: When used inside multitask OS, BSL calls must be made in
    // an initalization routine (before multitasking is active), or in any
    // other task that will prevent to be preempt. All BSL functions are not
    // OS multitask awared...

    // Verify is correct evm binary bsl version
    if ((retcode=EVM_checkbslversion(EVM_BSLVERSION))!=EVM_INITOK)
    {
        // Problem unmatching binary bsl version
        return(retcode);
    }
 
    // Initialize DSP for EVM module (usually done by GEL file)
    // If no GEL file is used for init, uncomment this part
    //if ((retcode=EVM_preinit(7,7,0,8))!=EVM_INITOK)
    //{
    //    // Problem cannot open evm
    //    return(retcode);
    //}

    // Initialize EVM module
    // Must always be the first BSL functions called
    if ((retcode=EVM_init())!=EVM_INITOK)
    {
        // Problem cannot open evm
        return(retcode);
    }

	// Get our dsp identification
	if ((retcode = EVM_dspid(&dspid))!=EVM_INITOK)
	{
        // Problem cannot get dsp ID
        return(retcode);
	}


	/*setup interrupt*/
    myprintf("configure INTC Configuration...\r\n",0,0);

    intcContext.eventhandlerRecord = EventHandler;
    intcContext.numEvtEntries = 10;
    if (CSL_intcInit(&intcContext) != CSL_SOK) {
        myprintf("Error: INTC initialization failed\r\n",0,0);
        return -1;
    }	

    /* System event 20 */
    evtId = 20;
    vecId = 8;
    hnd1 = CSL_intcOpen(&intcObj, evtId, &vecId, &intStat);
    if (hnd1 == NULL) {
        printf("Error: INTC Open for SRIO failed\n");
        return -1;
    }
    EventRecord1.handler = (CSL_IntcEventHandler) & isr_doorBell;
    EventRecord1.arg = (void *)vecId;
    if (CSL_intcPlugEventHandler(hnd1, &EventRecord1) != CSL_SOK) {
        printf("Error: INTC Plug event handler failed\n");
        return -1;
    }

    /* Clear the before event */
    if (CSL_intcHwControl(hnd1, CSL_INTC_CMD_EVTCLEAR, NULL) != CSL_SOK) {
        printf("Error: INTC CSL_INTC_CMD_EVTCLEAR command for SRIO failed\n");
        return -1;
    }
    /* Enable the event */
    if (CSL_intcHwControl(hnd1, CSL_INTC_CMD_EVTENABLE, NULL) != CSL_SOK) {
        printf("Error: INTC CSL_INTC_CMD_EVTENABLE command for SRIO failed\n");
        return -1;
    }	

    if (CSL_intcGlobalNmiEnable() != CSL_SOK) {
        printf("Error: GEM-INTC global NMI enable failed\n");
        return -1;
    }
    if ((intStat = CSL_intcGlobalEnable(&state)) != CSL_SOK) {
        printf("Error: GEM-INTC global enable failed\n");
        return -1;
    }
	
	myprintf("SRIO test on DSP%d, test config #%d\r\n",dspid,index);
	
    // Check if this board revision support these tests
#if defined(EVMBOARD_VARIANT00) || defined(EVMBOARD_VARIANT01) || defined(EVMBOARD_VARIANT02) || defined(EVMBOARD_VARIANT03) 
   	if (index >= SRIOTST_INTERDSP_SWITCH_1X_P0)
   	{
   	    myprintf("Test not supported on this board revision!\r\n",0,0);
   	    return(0);
   	}
#endif

    // Get the test common parameters
    port =  tstconfig[index].port;   
    mode = tstconfig[index].mode;
    loopback =  tstconfig[index].loopback;
    config = tstconfig[index].config;
    datarate = tstconfig[index].datarate;
       
    // Get the test other parameters according to which dsp we are
   	srcid = tstconfig[index].dsp[dspid].srcid;
   	destid = tstconfig[index].dsp[dspid].destid;
   	sent1st = tstconfig[index].dsp[dspid].sent1st;
   	wait1st = tstconfig[index].dsp[dspid].wait1st;
   	sent2nd = tstconfig[index].dsp[dspid].sent2nd;
   	wait2nd = tstconfig[index].dsp[dspid].wait2nd;
   	compare = tstconfig[index].dsp[dspid].compare;
    
	//myprintf("Source ID: 0x%04X, Destination ID: 0x%04X\r\n",srcid,destid);
	//myprintf("Port: %01d, Datarate: %04d\r\n",port,datarate);
	//myprintf("Mode: %01d, DSP Internal loopback: %c\r\n",mode,loopback?'Y':'N');

	// Configure the srio port
    if ((retcode=Srio_Init(config,mode,datarate,0,loopback,srcid))!=0)
    {
        myprintf("Error#10: error initializing srio code:%d\r\n",retcode,0);
        // Problem cannot init srio correctly
        return(retcode);
    }
    
    // Wait for all configured ports to wait or until timeout
    if ((retcode=Srio_CheckForLink(config,mode,TOUT3))!=0)
    {
        myprintf("Error#11: error linking srio ports code:%d\r\n",retcode,0);
        // Problem cannot link srio ports correctly
        return(retcode);
    }
	
	// Initialize all the source and dest buffers
    for(i0 = 0; i0 < BUFSIZE; i0++)
	{
		SrcBuff[i0] = 0x03020100 + (i0 * 0x04040404);
		DstBuff[i0] = 0x0A0A0A0A;
		DstBuff_ddr[i0] = 0x0A0A0A0A;
	}	

	 // Wait a delay to make sure the other is ready: sync two DSPs
	 iTout= TOUT2;   


	byte_count=BUFSIZE;
	if(dspid == 1)//tx side
	{
		TSCL = 0;
	    while(1)
	    {
	    	asm("	NOP 5");
	    }
	}else if(dspid == 0)//rx side
	{
		int overhead = 0;
		printf("Start external loopback test\r\n");

		//send one doorBell to start
		LSUno = 0;
		TSCL = 0;
		
		Srio_DoorBell(0, port, destid);
		t0 = TSCL;
		while(dbCnt < 2)
		{
			asm("	NOP 5");
		}

		LSUno= 1;
		t0 = TSCL;
		Srio_DoorBell(0, port, destid);
		while(dbCnt < 3)
		{
			asm("	NOP 5");
		}
		printf("\r\nDoorBell Overhead, %d\r\n\r\n", (dbTSCL[2]-t0));	
		overhead = dbTSCL[2]-t0;

		byte_count = 512;
		printf("Packet Size(Byte), Test Round, LSU,  TX Time, RX Time, Consumed Cycles, Date Rate(Mbps)\r\n"); 
		for(i1 = 0;i1<4;i1++)

		{
		dbCnt = 0;//reset dbCnt		
		dbTSCL[dbCnt]= TSCL;
		dbCnt = 1;
		byte_count <<=1;;

		
		for(i0 = 0;i0<8;i0++)
		{
			Int32 dbi = -1;
			if(i0==7)
				dbi = 0;
			LSUno = LSU_test[i0];
			if (Srio_Transfer((Uint32)SrcBuff, (Uint32)0x80000000+(i0*byte_count), byte_count, SRIO_REQ_NREAD, port, destid,dbi)!=0)
	    		{
            			myprintf("Error#01: while transferring packet at step#1\r\n",0,0);
            			testerrors++;
	    		}	
				
			//while(dbCnt < (i0+2));
			for(i2=0;i2<50;i2++)
			{
				asm("	NOP 5");  
				asm("	NOP 5"); 
			}
		}

		while(dbCnt < 2)
		{
			asm("	NOP 5"); 
		}

		#if 0
		
		for(i0 = 0;i0<dbCnt-1;i0++)
		{
			float ftime;
			if(dbTSCL[i0+1]>dbTSCL[i0])
				ftime = (float)(dbTSCL[i0+1]-dbTSCL[i0]-overhead);
			else
				ftime = (float)(dbTSCL[i0+1]+(0xFFFFFFFF-dbTSCL[i0])-overhead);
			printf("%6d, %2d, %2d, %12u, %12u, %8u, %5.1f\r\n",byte_count, i0,LSU_test[i0], dbTSCL[i0], \
				dbTSCL[i0+1], (Uint32)ftime, byte_count*8.*983/ftime);
		}
		printf("\r\n");
		#else
		{	
			float ftime;
			if(dbTSCL[1]>dbTSCL[0])
				ftime = (float)(dbTSCL[dbCnt-1]-dbTSCL[0]-overhead);
			else
				ftime = (float)(dbTSCL[dbCnt-1]+(0xFFFFFFFF-dbTSCL[0])-overhead);
			printf("%5d, %2d, %12u, %12u, %8u, %8.5f\r\n", byte_count, 8,\
				dbTSCL[0], dbTSCL[dbCnt-1], (Uint32)ftime, byte_count*8.*(dbCnt-1)/ftime);
			}
		#endif
		}

		while(1);
	}
		return testerrors;

}


