/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2011
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
 *   ===========================================================================
 *   @n Target Platform: EVM
 *  ============================================================================
 *   @desc  Example shows the performance of DSP cores share memory
 * =============================================================================
 *  Revision History
 *  ===============
 *  15-Jan-2011 Brighton Feng   File Created
 * ============================================================================
 */

#include <csl_cacheAux.h>
#include <stdio.h>
#include <csl_edma3.h>
#include <c6x.h>
#include "MEM_Sharing.h"
#include "KeyStone_common.h"
#include "MEM_share_EDMA_Timer_Intc_setup.h"

#define VERIFY 			0

void Edma_Test_Start(void)
{  
	int i, j;
	EdmaTestInfo 	* edma;
	CSL_TPCC_ParamsetRegs * EDMA_PaRAM;
	TDSP_Board_Type DSP_Board_Type;
#if VERIFY
	Uint32 *srcBuff;
	Uint32 *dstBuff;
#endif

	/*DSP core 0 is used to control the EDMA*/
	if(0!=DNUM)
		return;

	DSP_Board_Type= KeyStone_Get_dsp_board_type();
	for(i=0; i<EDMA_TC_NUM; i++)
	{
		edma= &(edmaTestInfo[i]);
		if(0==edma->enabled)
			continue;
			
		/*Assign different core's L2 to different EDMA TC,
		convert local address to global address*/
		if(C6678_EVM==DSP_Board_Type)
		{
			/*core0's L2 for EDMA 1 TC0
			core1's L2 for EDMA 1 TC1
			core2's L2 for EDMA 1 TC2
			core3's L2 for EDMA 1 TC3
			core4's L2 for EDMA 2 TC0
			core5's L2 for EDMA 2 TC1
			core6's L2 for EDMA 2 TC2
			core7's L2 for EDMA 2 TC3*/
			if(i>=2)
			{
				if(edma->srcAddr<0x01000000)
					edma->srcAddr=(edma->srcAddr)+0x10000000+(i-2)*0x01000000;
				if(edma->dstAddr<0x01000000)
					edma->dstAddr=(edma->dstAddr)+0x10000000+(i-2)*0x01000000;
			}
		}
		else if(C6670_EVM==DSP_Board_Type
			||DUAL_NYQUIST_EVM==DSP_Board_Type
			||TCI6614_EVM==DSP_Board_Type)
		{
			/*core0's L2 for EDMA 1 TC0 and TC1
			core1's L2 for EDMA 1 TC2 and TC3
			core2's L2 for EDMA 2 TC0 and TC1
			core3's L2 for EDMA 2 TC2 and TC3*/
			if(i>=2)
			{
				if(edma->srcAddr<0x01000000)
					edma->srcAddr=(edma->srcAddr)+0x10000000+((i-2)/2)*0x01000000;
				if(edma->dstAddr<0x01000000)
					edma->dstAddr=(edma->dstAddr)+0x10000000+((i-2)/2)*0x01000000;
			}
		}
		else
		{
			puts("Unknown DSP board type!");
			return;
		}
		
#if VERIFY
		srcBuff = (Uint32 *)edma->srcAddr;
		dstBuff = (Uint32 *)edma->dstAddr;
		/* Initialize data buffers */
		for (j = 0; j < edma->ACnt/4; j++) 
		{
			srcBuff[j] = edma->dstAddr+(j*4);
			dstBuff[j] = 0xaa;
		}      
		CACHE_wbInvAllL2(CACHE_WAIT);
#endif

		EDMA_PaRAM = &(gEDMACCRegs[edma->EDMA_number]->PARAMSET[edma->TC_channel]);

		EDMA_PaRAM->SRC= (edma->srcAddr);
		EDMA_PaRAM->A_B_CNT= (edma->BCnt<<16)|(edma->ACnt);
		EDMA_PaRAM->DST= (edma->dstAddr);
		EDMA_PaRAM->LINK_BCNTRLD= (edma->BCnt<<16)|0xFFFF;

		//requires re-statistic bandwidth after re-configuration
		edma->reStat= 1;
		edma->start_TSC = 0;
		edma->last_TSC = 0;
		edma->testTimes=0;
		edma->averageBandwidth= 0;
		
		//start EDMA manually
		gEDMACCRegs[edma->EDMA_number]->TPCC_ESR = (1<<edma->TC_channel);
		edma->running= 1;
	}

	return;
}

/*======================================================*/
/*
use core1 for EDMA0 test
use core2 for EDMA1 test
use core3 for EDMA2 test
other cores are not used for EDMA interrupt handling
*/
int edma_sys_event_num[3]={36, 6, 22};
Uint32 uiUnexpectIntCnt=0;
Uint32 uiSysIntNoIprCnt=0;
Uint32 uiIntCnt=0;
#if 0
void interrupt EDMA_ISR()
{
	Int32 i, j, aCnt;
	Uint32 uiTestTimes, uiDstAddress, uiTC_channel;
	Uint32 IPR, SysEventFlag;
	Uint32 uiSysEventNum, uiHostIntNum;
	Uint32  tscl, tsch;
	EdmaTestInfo 	* edma;
	CSL_TpccRegs*  EDMACCRegs;
#if VERIFY
	Uint32 *dstBuff;
#endif
	uiSysEventNum= edma_sys_event_num[DNUM-1];
	uiHostIntNum= uiEdma_host_event_num[DNUM-1];
	EDMACCRegs= gEDMACCRegs[DNUM-1];
	
	IPR= EDMACCRegs->TPCC_IPR;
	SysEventFlag= (cpIntc0Regs->ENA_STATUS_REG[uiSysEventNum>>5])
		&(1<<(uiSysEventNum&31));

	uiIntCnt++;
	if(0==IPR)
	{
		uiUnexpectIntCnt++;

		/* Clear the status of the edma system event*/
		if(SysEventFlag)
			KeyStone_CIC_clear_system_event(cpIntc0Regs, uiSysEventNum);
		
		return;
	}

	/* Disable the host interrupt */
	KeyStone_CIC_disable_host_int(cpIntc0Regs, uiHostIntNum);

	while(IPR||SysEventFlag)
	{
		/* Clear the status of the edma system event*/
		KeyStone_CIC_clear_system_event(cpIntc0Regs, uiSysEventNum);

		//clear EDMA interrupt flag
		EDMACCRegs->TPCC_ICR=IPR;

		for(i=0; i<EDMA_TC_NUM; i++)
		{
			edma= &(edmaTestInfo[i]);
			uiTC_channel= edma->TC_channel;
			if((edma->EDMA_number==(DNUM-1))&&
				(IPR&(1<<uiTC_channel)))
			{
				if(edma->enabled)
				{
					/* Manually trigger the channel 
					kick off another transfer*/
					EDMACCRegs->TPCC_ESR = (1<<uiTC_channel);
				}
				else
					edma->running= 0;

				if(edma->reStat)		
				{
					/* save the TSC for next iteration */
					tscl= TSCL;
					tsch= TSCH;
					edma->start_TSC = _itoll(tsch, tscl);
					edma->reStat=0;
					edma->testTimes=0;
					edma->averageBandwidth= 0;
				}
				else
				{
					uiTestTimes= edma->testTimes+1;
					edma->testTimes= uiTestTimes;
					tscl= TSCL;
					tsch= TSCH;
					edma->last_TSC= _itoll(tsch, tscl);				
				}

#if VERIFY
				aCnt= edma->ACnt;
				uiDstAddress= edma->dstAddr;
				
				dstBuff= (Uint32 *)uiDstAddress;
				CACHE_wbInvAllL2(CACHE_WAIT);
				/* Verify data transfered */
				for (j = 0; j < aCnt/4; j++) {
					if(dstBuff[j] != (uiDstAddress+j*4))
					{
						printf("EDMA data transfer failed at 0x%x, expect 0x%x, read 0x%x\n", 
							dstBuff+j, (uiDstAddress+j*4), dstBuff[j]);
						break;
					}
				}
#endif
			}
		}

		SysEventFlag= (cpIntc0Regs->ENA_STATUS_REG[uiSysEventNum>>5])
			&(1<<(uiSysEventNum&31));
		IPR= EDMACCRegs->TPCC_IPR;
	}

	SysEventFlag= (cpIntc0Regs->ENA_STATUS_REG[uiSysEventNum>>5])
		&(1<<(uiSysEventNum&31));
	if(SysEventFlag)
	{
		uiSysIntNoIprCnt++;
	}

	/* Enable the host interrupt */
	KeyStone_CIC_enable_host_int(cpIntc0Regs, uiHostIntNum);

	return;  
}
#else
void interrupt EDMA_ISR()
{
	Int32 i, j, aCnt;
	Uint32 uiTestTimes, uiDstAddress, uiTC_channel;
	Uint32 IPR, SysEventFlag;
	Uint32 uiSysEventNum, uiHostIntNum;
	Uint32  tscl, tsch;
	EdmaTestInfo 	* edma;
	CSL_TpccRegs*  EDMACCRegs;
#if VERIFY
	Uint32 *dstBuff;
#endif
	uiSysEventNum= edma_sys_event_num[DNUM-1];
	uiHostIntNum= uiEdma_host_event_num[DNUM-1];
	EDMACCRegs= gEDMACCRegs[DNUM-1];
	
	IPR= EDMACCRegs->TPCC_IPR;
	SysEventFlag= (cpIntc0Regs->ENA_STATUS_REG[uiSysEventNum>>5])
		&(1<<(uiSysEventNum&31));

	uiIntCnt++;
	if(0==IPR)
	{
		uiUnexpectIntCnt++;

		/* Clear the status of the edma system event*/
		if(SysEventFlag)
			KeyStone_CIC_clear_system_event(cpIntc0Regs, uiSysEventNum);
		
		return;
	}

	/* Disable the host interrupt */
	KeyStone_CIC_disable_host_int(cpIntc0Regs, uiHostIntNum);

	/* Clear the status of the edma system event*/
	KeyStone_CIC_clear_system_event(cpIntc0Regs, uiSysEventNum);
	
	while(IPR)
	{

		//clear EDMA interrupt flag
		EDMACCRegs->TPCC_ICR=IPR;

		for(i=0; i<EDMA_TC_NUM; i++)
		{
			edma= &(edmaTestInfo[i]);
			uiTC_channel= edma->TC_channel;
			if((edma->EDMA_number==(DNUM-1))&&
				(IPR&(1<<uiTC_channel)))
			{
				if(edma->enabled)
				{
					/* Manually trigger the channel 
					kick off another transfer*/
					EDMACCRegs->TPCC_ESR = (1<<uiTC_channel);
				}
				else
					edma->running= 0;

				if(edma->reStat)		
				{
					/* save the TSC for next iteration */
					tscl= TSCL;
					tsch= TSCH;
					edma->start_TSC = _itoll(tsch, tscl);
					edma->reStat=0;
					edma->testTimes=0;
					edma->averageBandwidth= 0;
				}
				else
				{
					uiTestTimes= edma->testTimes+1;
					edma->testTimes= uiTestTimes;
					tscl= TSCL;
					tsch= TSCH;
					edma->last_TSC= _itoll(tsch, tscl);				
				}

#if VERIFY
				aCnt= edma->ACnt;
				uiDstAddress= edma->dstAddr;
				
				dstBuff= (Uint32 *)uiDstAddress;
				CACHE_wbInvAllL2(CACHE_WAIT);
				/* Verify data transfered */
				for (j = 0; j < aCnt/4; j++) {
					if(dstBuff[j] != (uiDstAddress+j*4))
					{
						printf("EDMA data transfer failed at 0x%x, expect 0x%x, read 0x%x\n", 
							dstBuff+j, (uiDstAddress+j*4), dstBuff[j]);
						break;
					}
				}
#endif
			}
		}

		IPR= EDMACCRegs->TPCC_IPR;
	}

	//added by xj
	KeyStone_CIC_clear_system_event(cpIntc0Regs, uiSysEventNum);

	SysEventFlag= (cpIntc0Regs->ENA_STATUS_REG[uiSysEventNum>>5])
		&(1<<(uiSysEventNum&31));
	if(SysEventFlag)
	{
		uiSysIntNoIprCnt++;
	}

	/* Enable the host interrupt */
	KeyStone_CIC_enable_host_int(cpIntc0Regs, uiHostIntNum);

	return;  
}
#endif

