/*********************************************************************
 *
 *  Copyright (C) 2004  Freescale Semiconductors, Inc.
 *  All Rights Reserved.
 *  You are hereby granted a copyright license to use
 *  the SOFTWARE so int as this entire notice is
 *  retained without alteration in any modified and/or redistributed
 *  versions, and that such modified versions are clearly identified
 *  as such. No licenses are granted by implication, estoppel or
 *  otherwise under any patents or trademarks of Freescale
 *  Semiconductors Inc. This software is provided on an "AS IS"
 *  basis and without warranty.
 *
 *  To the maximum extent permitted by applicable law, FREESCALE
 *  DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING
 *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
 *  PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH REGARD TO THE
 *  SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) AND ANY
 *  ACCOMPANYING WRITTEN MATERIALS.
 *
 *  To the maximum extent permitted by applicable law, IN NO EVENT
 *  SHALL FREESCALE BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING
 *  WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS
 *  INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY
 *  LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
 *
 *  Freescale assumes no responsibility for the maintenance and support
 *  of this software
 ********************************************************************/
/*********************************************************************
 *
 *  DESCRIPTION : L2 Cache Tests on Starter Kit
 *
 ********************************************************************/
/* DDR Data */
#define DDR_LOC				0x01000000	/* 1MB reserved size in front for DDR */
#define DDR_SIZE			0x07000000	/* Memory size of DDR, should > 1MB */
#define DEST				DDR_LOC
#define SRC					0x02000000

/* Time Factors */
#define ONE_TICKET_MHz		50000       /* CONFIG_SYS_CLK (333333333) / 8000 */
#define THROUGHPUT_Hz		1049		/* 1024 * 1024 / 1000 */

/* Size copied for small copy test */
#define SMALL_SIZE			0x100

/*************************/
/*  function prototypes  */
/*************************/
/* Timing varible */
unsigned int * tbu_tbl;
/* Timimg Functions */
int dump_tbu(unsigned int * r3);
int dump_tbl(unsigned int * r3);
unsigned int get_time(unsigned int ulTickStarth, unsigned int ulTickStartl, unsigned int ulTickCounth, unsigned int ulTickCountl);

/* Tests */
void BSPPM_TestCalc(unsigned int ulRunNums);
void BSPPM_TestCopySmall(unsigned int ulRunNums);
void BSPPM_TestCopyBig(unsigned int ulRunNums,unsigned int ulCopySize);

/* memcpy function */
void * memcpy(void * dest,const void *src,unsigned int count);

int main(int argc, char *argv[])
{	
	printf("\nL2 Cache Tests on Starter Kit\n\n");
	printf("%-20s%-12s%-12s%-12s%-12s%-20s\n", "BSPPM_Test", "Iteration", "Size", "Time(Tick)", "Time(ms)", "Throughput(MB/s)");
	printf("-----------------------------------------------------------------------------------\n\n");
	
	/* CPU calculating power test */
	printf("%-20s", "CPU_Calc.\n");
	putc('\n');
	printf("%-20s", "\0");
    BSPPM_TestCalc(10);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	putc('\n');

   /* L2 Cache test (copying size < L2Cache)*/
    printf("%-20s", "L2_Cache_CopySmall\n");
	putc('\n');
    printf("%-20s", "\0");
    BSPPM_TestCopySmall(100);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	printf("%-20s", "\0");
    BSPPM_TestCopySmall(200);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	putc('\n');
 
    /* L2 Cache test (copying size > L2Cache)*/
    printf("%-20s", "L2_Cache_CopyBig\n");
	putc('\n');
    printf("%-20s", "\0");
    BSPPM_TestCopyBig(100, 0x10000);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	printf("%-20s", "\0");
    BSPPM_TestCopyBig(100, 0x20000);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	printf("%-20s", "\0");
    BSPPM_TestCopyBig(100, 0x40000);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	printf("%-20s", "\0");
    BSPPM_TestCopyBig(100, 0x60000);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	printf("%-20s", "\0");
    BSPPM_TestCopyBig(100, 0x80000);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	printf("%-20s", "\0");
	BSPPM_TestCopyBig(10, 0x100000);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}
	printf("%-20s", "\0");
	BSPPM_TestCopyBig(10, 0x200000);
	if (tstc()){
		printf("\n*** Abort\n\n");
		getc();
		return 0;
	}

	putc('\n');
	printf("End_of_Test.\n\n");
	
	return 1;
}


/* Timimg Functions */
int dump_tbu(unsigned int * r3)
{
   asm("mfspr 10, 269");	// TBU
   asm("isync");
   asm("stw 10, 0(3)");
   return *((unsigned int*) r3);
}

int dump_tbl(unsigned int * r3)
{
	asm("mfspr 10, 268");	// TBL
	asm("isync");
	asm("stw 10, 0(3)");
	return *((unsigned int*) r3);
}


unsigned int get_time(unsigned int ulTickStarth, unsigned int ulTickStartl, unsigned int ulTickCounth, unsigned int ulTickCountl)
{
	unsigned int time_ms = 0;
	
//	printf("%-12lu%-12lu%-12lu%-12lu", ulTickStarth, ulTickStartl, ulTickCounth, ulTickCountl);
	
	if (ulTickCounth == ulTickStarth){
		time_ms = (ulTickCountl - ulTickStartl) / ONE_TICKET_MHz;
		printf("%-12lu", ulTickCountl - ulTickStartl);
		printf("%-12lu", time_ms);
	}
	else if (ulTickCounth > ulTickStarth){
		time_ms = (ulTickCounth - ulTickStarth - 1) * (0xFFFFFFFFUL / ONE_TICKET_MHz) + (0xFFFFFFFFUL - ulTickStartl + ulTickCountl + 1) / ONE_TICKET_MHz;
		if ((ulTickCounth - ulTickStarth) > 1)
			printf("%-1lu%-11lu", (ulTickCounth - ulTickStarth - 1), (0xFFFFFFFF - ulTickStartl + ulTickCountl + 1));
		else printf("%-12lu", (0xFFFFFFFF - ulTickStartl + ulTickCountl + 1));
		printf("%-12lu", time_ms);
	}
	else{
		printf("%-36s", "Error...");
	}

	return time_ms;
	
}

/* Tests */
void BSPPM_TestCalc(unsigned int ulRunNums)
{ 
    unsigned int i = 0;
  
    unsigned int ulRunCount = 0;
    unsigned int ulTickStarth = 0;
    unsigned int ulTickStartl = 0;
    unsigned int ulTickCounth = 0;
    unsigned int ulTickCountl = 0;

    unsigned int ulNum1 = 0;
    unsigned int ulNum2 = 0;
    unsigned int ulNum3 = 0;
    
    printf("%-12lu", ulRunNums);
	printf("%-12s", "N/A");
   	
   	ulTickStarth = dump_tbu(tbu_tbl);
   	ulTickStartl = dump_tbl(tbu_tbl);
   	
	for (ulRunCount = 0; ulRunCount < ulRunNums; ulRunCount++){
		for (i = 0; i < 0xFFFFFF; i++){
        	ulNum2 = ulNum1 + i;
        	ulNum3 = ulNum2 + ulNum1;
        	ulNum1++;
     	}
     }

   	ulTickCountl = dump_tbl(tbu_tbl);
   	ulTickCounth = dump_tbu(tbu_tbl);
	
	get_time(ulTickStarth, ulTickStartl, ulTickCounth, ulTickCountl);
	printf("%-12s", "N/A");
	putc('\n');

}

void BSPPM_TestCopySmall(unsigned int ulRunNums)
{ 
    unsigned int i = 0;
   
    unsigned int ulRunCount = 0;
    unsigned int ulTickStarth = 0;
    unsigned int ulTickStartl = 0;
    unsigned int ulTickCounth = 0;
    unsigned int ulTickCountl = 0;

	unsigned int time_ms = 0;
//	unsigned int src_addr = DDR_LOC + SMALL_SIZE;
	
	printf("%-12lu", ulRunNums * 0xFFFF);
    printf("%-12lu", SMALL_SIZE);
    
   	ulTickStarth = dump_tbu(tbu_tbl);
	ulTickStartl = dump_tbl(tbu_tbl);
//	src_addr = DDR_LOC + SMALL_SIZE;

	for (ulRunCount = 0; ulRunCount < ulRunNums; ulRunCount++){
    	for (i = 0; i < 0xffff; i++){
            memcpy(DEST, SRC ,SMALL_SIZE);
        }
	}

   	ulTickCountl = dump_tbl(tbu_tbl);
   	ulTickCounth = dump_tbu(tbu_tbl);

	if (time_ms = get_time(ulTickStarth, ulTickStartl, ulTickCounth, ulTickCountl)){
		printf("%-12lu", ulRunNums * 0xFFFF / THROUGHPUT_Hz * SMALL_SIZE / time_ms);
	}	
	putc('\n');
	
}


void BSPPM_TestCopyBig(const unsigned int ulRunNums,unsigned int ulCopySize )
{ 
    unsigned int i = 0;
   
    unsigned int ulRunCount = 0;    
    unsigned int ulTickStarth = 0;
    unsigned int ulTickStartl = 0;
    unsigned int ulTickCounth = 0;
    unsigned int ulTickCountl = 0;
//    unsigned int src_addr = DDR_LOC;
    unsigned int time_ms = 0;

	printf("%-12lu", ulRunNums * 0xF);
    printf("%-12lu", ulCopySize);
    
//    src_addr += ulCopySize;
    
   	ulTickStarth = dump_tbu(tbu_tbl);
    ulTickStartl = dump_tbl(tbu_tbl);
    
	for (ulRunCount = 0; ulRunCount < ulRunNums; ulRunCount++){
		for (i = 0; i < 0xF; i++)
			memcpy(DEST, SRC, ulCopySize);

	}

   	ulTickCountl = dump_tbl(tbu_tbl);
   	ulTickCounth = dump_tbu(tbu_tbl);

	if (time_ms = get_time(ulTickStarth, ulTickStartl, ulTickCounth, ulTickCountl)){
		printf("%-12lu", ulCopySize / THROUGHPUT_Hz * ulRunNums * 0xF / time_ms);
	}	
	putc('\n');

}

/**
 * memcpy - Copy one area of memory to another
 * @dest: Where to copy to
 * @src: Where to copy from
 * @count: The size of the area.
 *
 * You should not use this function to access IO space, use memcpy_toio()
 * or memcpy_fromio() instead.
 */
void * memcpy(void * dest,const void *src,unsigned int count)
{
	//char *tmp = (char *) dest, *s = (char *) src;
	int *tmp = (int *) dest, *s = (int *) src;
	
	count = count/4;
	
	while (count--)
		*tmp++ = *s++;

	return dest;
}