/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2011-2013
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
 *   ===========================================================================
 */

/** ============================================================================
 *   @n This is an example to benchmark the EDMA3 performance
 */
 
/* =============================================================================
 *  Revision History
 *  ===============
 *  09-Jan-2010 Brighton Feng   File Created
 *  20-Feb-2013 Brighton Feng   Updated for K2
 * ============================================================================
 */

#include <stdio.h>
#include <csl_edma3.h>
#include <cslr_device.h>
#include "K2_common.h"
#include "Mem_Access_performance.h"
#include "common_test.h"

//limit copy size to save test time
#define MAX_COPY_SIZE 	(128*1024)

#define 	A_COUNT 	(16*1024)

//copy very small data unit to measure the overhead (latency) of EDMA transfer.
void edma_overhead_test(Uint32 uiEDMA, Uint32 uiTC)
{   
	int src_index, dst_index;
	CSL_TpccRegs*  EDMACCRegs= gpEDMA_CC_regs[uiEDMA];

	printf("Overhead test with EDMA%d TC%d\n", uiEDMA, uiTC);

	for(src_index=0; src_index<num_mem_test_blocks; src_index++)
		for(dst_index=0; dst_index<num_mem_test_blocks; dst_index++)
		{
			if(src_index==dst_index) //copy inside block
			{
				edma_Throughput_Test(mem_test_blocks[src_index].uiAddress, 
					(mem_test_blocks[src_index].uiAddress+A_COUNT), 
					8, 1, 0, EDMACCRegs, uiTC,
					mem_test_blocks[src_index].type, 
					mem_test_blocks[src_index].type);
			}
			else //copy between blocks
			{
				edma_Throughput_Test(mem_test_blocks[src_index].uiAddress, 
					mem_test_blocks[dst_index].uiAddress, 
					8, 1, 0, EDMACCRegs, uiTC,
					mem_test_blocks[src_index].type, 
					mem_test_blocks[dst_index].type);
			}
		}
}

void edma_performance_test(Uint32 uiEDMA, Uint32 uiTC)
{   
	Uint32 uiByteCnt;
	int src_index, dst_index;
	CSL_TpccRegs*  EDMACCRegs= gpEDMA_CC_regs[uiEDMA];

	printf("Throughput test with EDMA%d TC%d\n", uiEDMA, uiTC);

	for(src_index=0; src_index<num_mem_test_blocks; src_index++)
		for(dst_index=0; dst_index<num_mem_test_blocks; dst_index++)
		{
			if(src_index==dst_index) //copy inside block
			{
				uiByteCnt= mem_test_blocks[src_index].uiByteCnt/2;
				if(uiByteCnt>MAX_COPY_SIZE) //limit the size to save test time
					uiByteCnt= MAX_COPY_SIZE;

				//copy from the first half of the block to the second half of the block
				edma_Throughput_Test(mem_test_blocks[src_index].uiAddress, 
					(mem_test_blocks[src_index].uiAddress+uiByteCnt), 
					A_COUNT, uiByteCnt/A_COUNT, A_COUNT, EDMACCRegs, uiTC,
					mem_test_blocks[src_index].type, 
					mem_test_blocks[src_index].type);
			}
			else //copy between blocks
			{
				//use the size of the smaller block
				uiByteCnt= (mem_test_blocks[src_index].uiByteCnt<mem_test_blocks[dst_index].uiByteCnt)?
					mem_test_blocks[src_index].uiByteCnt:mem_test_blocks[dst_index].uiByteCnt;
				if(uiByteCnt>MAX_COPY_SIZE) //limit the size to save test time
					uiByteCnt= MAX_COPY_SIZE;

				edma_Throughput_Test(mem_test_blocks[src_index].uiAddress, 
					mem_test_blocks[dst_index].uiAddress, 
					A_COUNT, uiByteCnt/A_COUNT, A_COUNT, EDMACCRegs, uiTC,
					mem_test_blocks[src_index].type, 
					mem_test_blocks[dst_index].type);
			}
		}
}

void edma_ACNT_Test(Uint32 uiEDMA, Uint32 uiTC, Uint32 uiSrc, Uint32 uiDst,
	char * srcType, char * dstType)
{   
	Int32 aCnt;
	CSL_TpccRegs*  EDMACCRegs= gpEDMA_CC_regs[uiEDMA];
	
	printf("EDMA ACNT test with EDMA%d TC%d\n", uiEDMA, uiTC);
	aCnt= 1;
	while(aCnt<=(24*1024))
	{
		edma_Throughput_Test (uiSrc, uiDst, aCnt, 1, aCnt, EDMACCRegs, uiTC, srcType, dstType);
		if(aCnt<16)
			aCnt++;
		else if(aCnt<256)
			aCnt+=16;
		else if(aCnt< 512)
			aCnt+=32;
		else if(aCnt< 1024)
			aCnt+=64;
		else if(aCnt< 2048)
			aCnt+=128;
		else if(aCnt< 4096)
			aCnt+=256;
		else if(aCnt< 8096)
			aCnt+=512;
		else
			aCnt+=1024;
	}
}

void edma_ACNTxBCNT_Test(Uint32 uiEDMA, Uint32 uiTC)
{   
	Int32 bCnt,aCnt;
	CSL_TpccRegs*  EDMACCRegs= gpEDMA_CC_regs[uiEDMA];
	
	printf("EDMA ACNTxBCNT test with EDMA%d TC%d\n", uiEDMA, uiTC);
	for(bCnt=1; bCnt<= 4; bCnt++)
	{
		aCnt=1;
		while(aCnt<=(24*1024))
		{
			//MSMC RAM->DDR
			edma_Throughput_Test(MSMC_RAM_TEST_BASE_ADDR, DDR3A_TEST_BASE_ADDR,
				aCnt, bCnt, aCnt, EDMACCRegs, uiTC, "MSMC RAM", "DDR3A");
			if(aCnt<16)
				aCnt++;
			else if(aCnt<256)
				aCnt+=16;
			else if(aCnt< 512)
				aCnt+=32;
			else if(aCnt< 1024)
				aCnt+=64;
			else if(aCnt< 2048)
				aCnt+=128;
			else if(aCnt< 4096)
				aCnt+=256;
			else if(aCnt< 8096)
				aCnt+=512;
			else
				aCnt+=1024;
		}
	}   
}
void edma_Index_Test(Uint32 uiEDMA, Uint32 uiTC)
{   
	Int32 index,aCnt, bCnt;
	CSL_TpccRegs*  EDMACCRegs= gpEDMA_CC_regs[uiEDMA];
	
	printf("EDMA Index test with EDMA%d TC%d\n", uiEDMA, uiTC);
	aCnt=1;
	while(aCnt<=(8*1024))
	{
		bCnt=MSMC_RAM_TEST_SPACE_SIZE/aCnt;
		if(bCnt>1024)
			bCnt=1024;
		//MSMC RAM->DDR
		edma_Throughput_Test (MSMC_RAM_TEST_BASE_ADDR, DDR3A_TEST_BASE_ADDR, 
			aCnt, bCnt, 0, EDMACCRegs, uiTC, "MSMC RAM", "DDR3A");
		if(aCnt<16)
			aCnt++;
		else if(aCnt<256)
			aCnt+=16;
		else if(aCnt< 512)
			aCnt+=64;
		else if(aCnt< 1024)
			aCnt+=256;
		else
			aCnt+=512;
	}
	aCnt=1;
	while(aCnt<=(8*1024))
	{
		bCnt=MSMC_RAM_TEST_SPACE_SIZE/aCnt;
		if(bCnt>1024)
			bCnt=1024;
		//MSMC RAM->DDR
		edma_Throughput_Test (MSMC_RAM_TEST_BASE_ADDR, DDR3A_TEST_BASE_ADDR, 
			aCnt, bCnt, aCnt, EDMACCRegs, uiTC, "MSMC RAM", "DDR3A");
		if(aCnt<16)
			aCnt++;
		else if(aCnt<256)
			aCnt+=16;
		else if(aCnt< 512)
			aCnt+=64;
		else if(aCnt< 1024)
			aCnt+=256;
		else
			aCnt+=512;
	}
	for(index=1; index<= 128; index*=4)
	{
		aCnt=1;
		while(aCnt<=(8*1024))
		{
			bCnt=MSMC_RAM_TEST_SPACE_SIZE/(aCnt+index);
			if(bCnt>1024)
				bCnt=1024;
			//MSMC RAM->DDR
			edma_Throughput_Test (MSMC_RAM_TEST_BASE_ADDR, DDR3A_TEST_BASE_ADDR, 
				aCnt, bCnt, aCnt+index, EDMACCRegs, uiTC, "MSMC RAM", "DDR3A");
			if(aCnt<16)
				aCnt++;
			else if(aCnt<256)
				aCnt+=16;
			else if(aCnt< 512)
				aCnt+=64;
			else if(aCnt< 1024)
				aCnt+=256;
			else
				aCnt+=512;
		}
	}   
}


void edma_test(void)
{  
	int i;
	
#if 0
	for(i=0; i<CSL_EDMACC_0_NUM_TC; i++)
		edma_overhead_test(0, i);
	for(i=0; i<CSL_EDMACC_1_NUM_TC; i++)
		edma_overhead_test(1, i);
	for(i=0; i<CSL_EDMACC_2_NUM_TC; i++)
		edma_overhead_test(2, i);
#if (NUM_EDMA_CC>3)
	for(i=0; i<CSL_EDMACC_3_NUM_TC; i++)
		edma_overhead_test(3, i);
	for(i=0; i<CSL_EDMACC_4_NUM_TC; i++)
		edma_overhead_test(4, i);
#endif
#endif

	for(i=0; i<CSL_EDMACC_0_NUM_TC; i++)
		edma_performance_test(0, i);
	for(i=0; i<CSL_EDMACC_1_NUM_TC; i++)
		edma_performance_test(1, i);
	for(i=0; i<CSL_EDMACC_2_NUM_TC; i++)
		edma_performance_test(2, i);
#if (NUM_EDMA_CC>3)
	for(i=0; i<CSL_EDMACC_3_NUM_TC; i++)
		edma_performance_test(3, i);
	for(i=0; i<CSL_EDMACC_4_NUM_TC; i++)
		edma_performance_test(4, i);
#endif

#if 1
	//MSMC RAM -> DDR3A
	edma_ACNT_Test(0, 0, MSMC_RAM_TEST_BASE_ADDR, DDR3A_TEST_BASE_ADDR,
		"MSMC RAM", "DDR3A");
	//DDR3A -> MSMC RAM
	edma_ACNT_Test(0, 0, DDR3A_TEST_BASE_ADDR, MSMC_RAM_TEST_BASE_ADDR,
		"DDR3A", "MSMC RAM");

	edma_ACNTxBCNT_Test(0, 0);
	//edma_ACNTxBCNT_Test(1, 0);
	//edma_ACNTxBCNT_Test(2, 0);

	edma_Index_Test(0, 0);
	//edma_Index_Test(1, 0);
	//edma_Index_Test(2, 0);
#endif

	puts("EDMA test complete");
    return;
}

