/*  ============================================================================
 *     Copyright (C) 2013 Texas Instruments Incorporated.       *
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
 *   ===========================================================================
 */
/** ============================================================================
EDMA test for SPI
 * =============================================================================
 *  Revision History
 *  ===============
 *  23-July-2013 cheng  file created
 *  19-October-2013 Brighton  add more test cases
 * =============================================================================
 */
#include "SPI_EDMA_Test.h"



#pragma DATA_ALIGN(spiEdmaRxBuf, 128) 	/*align to L2 cache line*/
Uint16 spiEdmaRxBuf[SPI_EDMA_TEST_BUF_SIZE/2];
#pragma DATA_ALIGN(spiEdmaTxBuf, 128) 	/*align to L2 cache line*/
Uint16 spiEdmaTxBuf[SPI_EDMA_TEST_BUF_SIZE/2];
Uint32 SPIDAT1_EdmaBuf[SPI_EDMA_TEST_BUF_SIZE/2];

SPI_Data_Format EdmaDataFormat =
{
	/*.delayBetweenTrans_ns = */0,
	/*.ShifDirection        = */SPI_MSB_SHIFT_FIRST,
	/*.disable_CS_timing    = */1,
	/*.clockPolarity        = */SPI_CLOCK_LOW_INACTIVE,
	/*.clockPhase           = */0,
	/*.clockSpeedKHz        = */66000,
	/*.wordLength           = */16
};

SPI_Transfer_Param EdmaTransferParam =
{
	0,     /*Chip select number*/
	2,  /*select one of the 4 SPI formats*/
	SPI_CS_NO_LAST_HOLD, /*hold CS between multiple words*/
	FALSE,  /*Enable the delay counter at the end of the current transaction*/
	2   /*number of bytes per SPI word*/
};

Uint32 EDMA_start_TSC;
void Setup_EDMA_for_SPI(Uint32 uiCC, Uint32 uiChannel, Uint32 uiTC)
{
	EDMA_channel_TC_cfg(gpEDMA_CC_regs[uiCC], uiChannel, uiTC);
	if(uiChannel<32)
	{
		//enable the EDMA channel
		gpEDMA_CC_regs[uiCC]->TPCC_EESR= 1<<(uiChannel);
		//enable the EDMA channel interrupt
		gpEDMA_CC_regs[uiCC]->TPCC_IESR= 1<<(uiChannel);
	}
	else
	{
		//enable the EDMA channel
		gpEDMA_CC_regs[uiCC]->TPCC_EESRH= 1<<(uiChannel-32);
		//enable the EDMA channel interrupt
		gpEDMA_CC_regs[uiCC]->TPCC_IESRH= 1<<(uiChannel-32);
	}	
}

//EDMA initialization for SPI transfer
void SPI_EDMA_Init()
{
    EDMA_init(); 
    
#ifdef DEVICE_C6657
    //SPI0 use EDMA CC1
    Setup_EDMA_for_SPI(CSL_EDMA3CC_2 - 2, CSL_EDMA3CC2_SPIXEVT, 0);
    Setup_EDMA_for_SPI(CSL_EDMA3CC_2 - 2, CSL_EDMA3CC2_SPIREVT, 0);
#else
    //SPI0 use EDMA CC1 
    Setup_EDMA_for_SPI(CSL_EDMA3CC_1, CSL_TPCC1_SPIXEVT, 0);
    Setup_EDMA_for_SPI(CSL_EDMA3CC_1, CSL_TPCC1_SPIREVT, 0);
#endif
}

//initialize source and destination buffers
void SPI_EDMA_BuffInit(Uint8* pucSrcBuf, Uint8* pucDstBuf,Uint32 uiByteLength)
{
    Uint32 uiI;

    for(uiI = 0; uiI < uiByteLength; uiI++)
    {
        *pucSrcBuf++ = (uiI&0xFF);
        *pucDstBuf++ = 0;
    }
    WritebackInvalidCache(pucSrcBuf, uiByteLength);
    WritebackInvalidCache(pucDstBuf, uiByteLength);
}

//check the result of EDMA
void SPI_EDMA_Check(Uint8* pucSrcBuf, Uint8* pucDstBuf, 
	Uint32 uiByteLength)
{   
    Uint32  uiTpccNum;
    Uint32  uiSpiEdmaTxCh;
    Uint32  uiSpiEdmaRxCh;
    Uint32  uiI, uiCycles, uiThroughput;
    Uint8   srcData, dstData;

#ifdef DEVICE_C6657
    uiTpccNum = CSL_EDMA3CC_2 - 2; //here get the EDMA index
	uiSpiEdmaTxCh = CSL_EDMA3CC2_SPIXEVT;
	uiSpiEdmaRxCh = CSL_EDMA3CC2_SPIREVT;
#else
	uiTpccNum = CSL_EDMA3CC_1;
	uiSpiEdmaTxCh = CSL_TPCC1_SPIXEVT;
	uiSpiEdmaRxCh = CSL_TPCC1_SPIREVT;
#endif

    /* Wait for completion */
    if(uiSpiEdmaTxCh<32)
	    while ((gpEDMA_CC_regs[uiTpccNum]->TPCC_IPR&(1<<(uiSpiEdmaTxCh))) ==0);
	else
	    while ((gpEDMA_CC_regs[uiTpccNum]->TPCC_IPRH&(1<<(uiSpiEdmaTxCh-32))) ==0);
    if(uiSpiEdmaRxCh<32)
	    while ((gpEDMA_CC_regs[uiTpccNum]->TPCC_IPR&(1<<(uiSpiEdmaRxCh))) ==0);
	else
	    while ((gpEDMA_CC_regs[uiTpccNum]->TPCC_IPRH&(1<<(uiSpiEdmaRxCh-32))) ==0);
	uiCycles= TSC_count_cycle_from(EDMA_start_TSC);

    for(uiI = 0; uiI < uiByteLength; uiI++)
    {
    	srcData= *pucSrcBuf++;
    	dstData= *pucDstBuf++;
        if(srcData!= dstData)
        {
        	printf("data error at byte %d, source data = 0x%x, destination data = 0x%x\n",
        		uiI, srcData, dstData);
            return;
        }
    }

    uiThroughput = (unsigned long long)uiByteLength*8*gDSP_Core_Speed_Hz/
    	((unsigned long long)uiCycles*1000000);

	printf("SPI EDMA loopback test passed. Throughput= %dMbps\n",uiThroughput);
}

void SPI_EDMA_test()
{
	Uint32 numDataWord= SPI_EDMA_TEST_BUF_SIZE/EdmaTransferParam.byteOfWord;

    SPI_EDMA_BuffInit((Uint8*)spiEdmaTxBuf,(Uint8*)spiEdmaRxBuf,
    	sizeof(spiEdmaRxBuf));   

    /*EDMA write to SPIDAT0 */
#ifdef SPIDAT0_EDMA_TEST    
    KeyStone_set_SPIDAT1_format(&EdmaTransferParam);
    EDMA_start_TSC = TSCL;
    KeyStone_SPI_EDMA_TxRx((Uint8*)spiEdmaTxBuf, (Uint8*)spiEdmaRxBuf, 
    numDataWord, EdmaTransferParam.byteOfWord, EDMA_TO_SPIDAT0_2_bytes);
#else
    /*EDMA write to SPIDAT1  */	
	KeyStone_SPIDAT1_buffer_construct((Uint8*)spiEdmaTxBuf, 
		SPIDAT1_EdmaBuf, numDataWord, &EdmaTransferParam);

	EDMA_start_TSC = TSCL;
	KeyStone_SPI_EDMA_TxRx((Uint8*)SPIDAT1_EdmaBuf, (Uint8*)spiEdmaRxBuf, 
		numDataWord, EdmaTransferParam.byteOfWord, EDMA_TO_SPIDAT1_4_bytes);
#endif

    SPI_EDMA_Check((Uint8*)spiEdmaTxBuf,(Uint8*)spiEdmaRxBuf,
    	sizeof(spiEdmaRxBuf));

}

