/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2011 - 2014
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
* ============================================================================
Memory Test Example on KeyStone device
* =============================================================================
 *  Revision History
 *  ===============
 *  11-Jan-2011 Brighton Feng   File Created
 *  1-Feb-2013 Brighton Feng   Update for K2
 *  12-July-2013 Brighton Feng   Update for K2 ARM
 * ============================================================================
 */
#include <stdio.h>
#include <string.h>
#include "CP15.h"
#include "K2_Board_Init.h"
#include "mem_test_DMA.h"
#include "mem_test_CPU.h"
#include "K2_common.h"
#include "common_test.h"

#define MSMC_RAM_MEM_TEST 	1
#define OSR_MEM_TEST		1
#define DDR3A_MEM_TEST 		1
#define DDR3B_MEM_TEST 		1
#define TEST_BY_CPU 	    1
#define TEST_BY_DMA			1

/*the test may only run on one core or on multiple cores.
To run the test on single core, the program should be loaded and
on core 0 only.
If only run the test on single core, the maximum DDR3A test size is 2GB, 
and maximum DDR3 size be tested is 512MB.
To run the test on multiple cores, the program should be loaded and
run on all cores simultaneously.*/
#define SINGLE_CORE_TEST 	0

/*test infinitely. For burning test*/
#define TEST_INFINITELY 	0

/*Enable ECC for DDR test*/
#define DDR_ECC_ENABLE 		0

//MMU memory ranges tables
MMU_Memory_Map_Range memory_ranges[]=
{
	{//MSMC RAM
    .uiVirtualAddress   = 0x0C000000,
    .ullPhysicalAddress = 0x0C000000,
    .uiByteCnt          = MSMC_RAM_SIZE_BYTES,
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_X,
    .shareAttr          = MMU_MEM_ATTR_OUTER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	},                     
	{//DDR3A               
    .uiVirtualAddress   = 0x80000000,
    .ullPhysicalAddress = 0x800000000ULL, 	//this field may be modified by code at runtime
#if (DDR3A_SIZE_BYTES>0x80000000ULL)
    .uiByteCnt          = 0x80000000, 	
#else
    .uiByteCnt          = DDR3A_SIZE_BYTES, 	
#endif
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_XN,
    .shareAttr          = MMU_MEM_ATTR_OUTER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	}
#if (2==CSL_DDR3_PER_CNT)
	,{//DDR3B
    .uiVirtualAddress   = 0x60000000,
    .ullPhysicalAddress = 0x60000000, 	//this field may be modified by code at run time
    .uiByteCnt          = 0x20000000,
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_XN,
    .shareAttr          = MMU_MEM_ATTR_INNER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	}
#endif
#ifdef CSL_OSR_DATA 	//for K2L only
	,{//OSR
    .uiVirtualAddress   = CSL_OSR_DATA,
    .ullPhysicalAddress = CSL_OSR_DATA,
    .uiByteCnt          = 0x00200000,
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_XN,
    .shareAttr          = MMU_MEM_ATTR_INNER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	}
#endif
};

MMU_Long_Format_Config mmu_cfg=
{
	.memory_map        = memory_ranges,
	.uiNumMemMapRanges = sizeof(memory_ranges)/sizeof(MMU_Memory_Map_Range),
	.ullpMMU3rdLevelTT = NULL, 	//No level 3 translation table
	.bAlignCheck       = TRUE,
	.tableCacheAttr    = MMU_TAB_ATTR_CACHE_WB_WA,
	.tableShareAttr	   = MMU_MEM_ATTR_INNER_SHARE,
};

int iFailedTimes=0, iPassedTimes=0;
unsigned int uiMSMC_RAM_StartAddress, uiMSMC_RAM_EndAddress;
#ifdef CSL_OSR_DATA 	//for K2L
unsigned int uiOSRStartAddress, uiOSREndAddress;
#endif
unsigned int uiDDR_B_EndAddress, uiDDR_A_EndAddress;
unsigned int uiInit_done= 0;

#define DMA_BUF_SIZE 	(32*1024)
unsigned char dma_buf[DMA_BUF_SIZE];

void pass_fail_count(int iResult) 
{
	if(iResult)
		iFailedTimes++;
	else
		iPassedTimes++;
	printf("Passed Times: %8d \t\tFailed Times: %8d \n", iPassedTimes, iFailedTimes);
}


void KeyStone_memory_bus_test(unsigned int uiBaseAddress,
	unsigned int uiDataBusWidth, unsigned int uiNumBytes, char * mem_name)
{
	Uint32 uiFailCount;
	
	printf("\n%s bus test at %lld cycle\n", mem_name, get_64_bit_cycle_count());

	//Test memory buses		
	uiFailCount  = Memory_Data_Bus_Test(uiBaseAddress, uiDataBusWidth);
#if (DDR_ECC_ENABLE==0)
	uiFailCount += Memory_Address_Bus_Test(uiBaseAddress, uiNumBytes, 1);
#endif
	pass_fail_count(uiFailCount);

}
void KeyStone_memory_test(unsigned int uiStartAddress, 
	unsigned int uiStopAddress, unsigned int uiStep, char * mem_name)
{
	printf("\n%s memory test at %lld cycle\n", mem_name, get_64_bit_cycle_count());
	pass_fail_count(CPU_MEM_Test(uiStartAddress, uiStopAddress, uiStep)); 
}

void KeyStone_memory_EDMA_test(unsigned int uiStartAddress, 
	unsigned int uiStopAddress, unsigned int uiStep, char * mem_name)
{
	printf("\n%s memory test with EDMA at %lld cycle\n", mem_name, get_64_bit_cycle_count());
	pass_fail_count(EDMA_MEM_Test(uiStartAddress, uiStopAddress,
			(Uint32)dma_buf, DMA_BUF_SIZE));
}

/*End address of used MSMC is defined in lds file*/
extern Uint32 MSMC_used_end;
int main()
{
	DDR3_ECC_Config DDR_ECC_cfg;
	Uint32 uiNum_cores;
#if (2==CSL_DDR3_PER_CNT)
	Uint32 uiDDR_B_Size, uiDDR_B_TotalSize;
#endif
	unsigned long long ullDDR_A_Size, ullDDR_A_TotalSize;
	volatile unsigned int * uipInit_done;

	Uint32 uiCPU_ID= CP15_get_CPU_ID();

	//printf("CPU_ID=%d\n", uiCPU_ID);

	/*common initialization for internal modules in K2 device 
	enable GIC, memory protection interrupts, EDC for MSMC RAM */
	K2_common_device_init();
	/*initialize GIC interface for CPU, enable IRQ, FIQ, PMU*/
	K2_common_CPU_init();
	KeyStone_Exception_cfg(TRUE);

	EDMA_init();
	K2_SMS_MPAX_init(PRIVID_ARM_COREPAC, MSMC_SHARE);
	K2_SES_MPAX_init(PRIVID_ARM_COREPAC, MSMC_SHARE);

#ifdef CSL_OSR_DATA 	//for K2L
	//enable OSR for test
	KeyStone_enable_PSC_module(CSL_PSC_PD_OSR, CSL_PSC_LPSC_OSR);
#endif

#if SINGLE_CORE_TEST
	uiNum_cores= 1;
#else
	uiNum_cores= NUMBER_ARM_CORES;
#endif

	/*allocate EDMA TCs between cores sequentially*/
	allocate_EDMA_TC(uiCPU_ID, uiNum_cores);

	uipInit_done= &uiInit_done;

	if(0==uiCPU_ID) //PLL and DDR initialization is done by core 0
	{
		//Main core speed= MAIN_PLL_REF_CLK_MHZ*MAIN_PLL_MULTIPLIER/MAIN_PLL_DIVISOR
		KeyStone_main_PLL_init(MAIN_PLL_REF_CLK_MHZ, MAIN_PLL_MULTIPLIER, MAIN_PLL_DIVISOR);
		//KeyStone_main_PLL_init(122.88, 8, 1);

#ifndef DEVICE_K2E 	//K2E only has main PLL for both ARM and DSP cores
		//ARM core speed= ARM_PLL_REF_CLK_MHZ*ARM_PLL_MULTIPLIER/ARM_PLL_DIVISOR
		K2_ARM_PLL_init(ARM_PLL_REF_CLK_MHZ, ARM_PLL_MULTIPLIER, ARM_PLL_DIVISOR);
		//K2_ARM_PLL_init(125, 8, 1);
#endif

		//DDR configuration
	memset((void *)&DDR_ECC_cfg, 0, sizeof(DDR_ECC_cfg));
#if DDR_ECC_ENABLE
	DDR_ECC_cfg.addressRange[0].startAddr= 0x00000000;
	DDR_ECC_cfg.addressRange[0].byteCnt=   0x08000000;
	DDR_ECC_cfg.addressRange[1].startAddr= 0x10000000;
	DDR_ECC_cfg.addressRange[1].byteCnt=   0x08000000;
	DDR_ECC_cfg.rangeMode= EN_ECC_WITHIN_DEFINED_RANGES;
#endif
#if (DDR3A_MEM_TEST)
		K2_DDR3A_config(NULL, &DDR_ECC_cfg);
#endif
#if (DDR3B_MEM_TEST)
#if (2==CSL_DDR3_PER_CNT)
		K2_DDR3B_config(NULL, &DDR_ECC_cfg);
#endif
#endif
		uiInit_done= 1;
	}
	else
	{//other cores wait for core 0 done.
		while(0==*uipInit_done);
	}
	
	/*End address of used MSMC is defined in lds file*/
	uiMSMC_RAM_StartAddress= (Uint32)(&MSMC_used_end);
	uiMSMC_RAM_StartAddress= (uiMSMC_RAM_StartAddress+15)&0xFFFFFFF0; //round up
	uiMSMC_RAM_EndAddress  = 0x0C000000+ MSMC_RAM_SIZE_BYTES-BOOT_USED_MSMC_RAM_SIZE_BYTES;

#ifdef CSL_OSR_DATA 	//for K2L
	/*OSR equally divided between cores for this test*/
	uiOSRStartAddress= CSL_OSR_DATA+uiCPU_ID*CSL_OSR_DATA_SIZE/uiNum_cores;
	uiOSREndAddress  = CSL_OSR_DATA+(uiCPU_ID+1)*CSL_OSR_DATA_SIZE/uiNum_cores;
#endif

	/*DDR size may different on different board*/
#if (2==CSL_DDR3_PER_CNT)
	uiDDR_B_TotalSize= DDR3B_SIZE_BYTES;
#endif
	ullDDR_A_TotalSize= (unsigned long long)DDR3A_SIZE_BYTES;

#if (2==CSL_DDR3_PER_CNT)
	/*equally divided between cores for this test*/
	uiDDR_B_Size= uiDDR_B_TotalSize/uiNum_cores;
	if(uiDDR_B_Size>0x20000000)
			uiDDR_B_Size=0x20000000;
	uiDDR_B_EndAddress= 0x60000000+ uiDDR_B_Size;

	memory_ranges[2].ullPhysicalAddress= 0x60000000+(uiCPU_ID*uiDDR_B_Size);
	memory_ranges[2].uiByteCnt         = uiDDR_B_Size;
#endif

	ullDDR_A_Size= ullDDR_A_TotalSize/uiNum_cores;
	if(ullDDR_A_Size>=0x80000000)
	{
			ullDDR_A_Size=0x80000000;
			uiDDR_A_EndAddress= 0xFFFFFFF0;
	}
	else
		uiDDR_A_EndAddress= 0x80000000+ ullDDR_A_Size;

	memory_ranges[1].ullPhysicalAddress= 0x800000000ULL+(uiCPU_ID*ullDDR_A_Size);
	memory_ranges[1].uiByteCnt         = ullDDR_A_Size;

	/*MMU configure for ARM core*/
	MMU_long_format_init(&mmu_cfg);
#if TEST_INFINITELY
	while(1) 	/*test infinitely*/
#endif
	{
		printf("Memory Test Start at %lld cycle\n", get_64_bit_cycle_count());

		puts("\nDisable instruction and data cache.");
		CP15_ICacheDisable();
		CP15_DCacheDisable();

#if (MSMC_RAM_MEM_TEST&TEST_BY_CPU)
	if(0==uiCPU_ID) //MSMC RAM only tested by core 0
		KeyStone_memory_bus_test(0x0C100000, 256*4,	0x00100000, "MSMC RAM");
#endif

#if (defined(CSL_OSR_DATA)&&OSR_MEM_TEST&&TEST_BY_CPU) 	//for K2L
		KeyStone_memory_bus_test(uiOSRStartAddress, 128, 
			uiOSREndAddress-uiOSRStartAddress, "OSR");
#endif

#if (DDR3A_MEM_TEST&TEST_BY_CPU)
		KeyStone_memory_bus_test(0x80000000, 64, 
			ullDDR_A_Size, "DDR3A");
#endif

#if (DDR3B_MEM_TEST&TEST_BY_CPU&(2==CSL_DDR3_PER_CNT))
		KeyStone_memory_bus_test(0x60000000, 64, 
			uiDDR_B_Size, "DDR3B");
#endif

		puts("\nEnable Instruction cache only.");
		CP15_ICacheEnable();

#if (MSMC_RAM_MEM_TEST&TEST_BY_CPU)
	if(0==uiCPU_ID) //MSMC RAM only tested by core 0
		KeyStone_memory_test(uiMSMC_RAM_StartAddress, uiMSMC_RAM_EndAddress, 1, "MSMC RAM");
#endif
#if (DDR3B_MEM_TEST&TEST_BY_CPU&(2==CSL_DDR3_PER_CNT))
		KeyStone_memory_test(0x60000000, 0x60000000+1024, 1, "DDR3B");
#endif
#if (defined(CSL_OSR_DATA)&&OSR_MEM_TEST&&TEST_BY_CPU) 	//for K2L
		KeyStone_memory_test(uiOSRStartAddress, uiOSREndAddress, 1, "OSR");
#endif
#if (DDR3A_MEM_TEST&TEST_BY_CPU)
		KeyStone_memory_test(0x80000000, 0x80000000+1024, 1, "DDR3A");
#endif

		puts("\nEnable both data and instruction cache.");
		CP15_DCacheEnable();

#if (MSMC_RAM_MEM_TEST&TEST_BY_DMA)
	if(0==uiCPU_ID) //MSMC RAM only tested by core 0
		KeyStone_memory_EDMA_test(uiMSMC_RAM_StartAddress, uiMSMC_RAM_EndAddress, 1, "MSMC RAM");
#endif
#if (MSMC_RAM_MEM_TEST&TEST_BY_CPU)
	if(0==uiCPU_ID) //MSMC RAM only tested by core 0
		KeyStone_memory_test(uiMSMC_RAM_StartAddress, uiMSMC_RAM_EndAddress, 1, "MSMC RAM");
#endif
#if (defined(CSL_OSR_DATA)&&OSR_MEM_TEST&&TEST_BY_DMA) 	//for K2L
		KeyStone_memory_EDMA_test(uiOSRStartAddress, uiOSREndAddress, 1, "OSR");
#endif
#if (defined(CSL_OSR_DATA)&&OSR_MEM_TEST&&TEST_BY_CPU) 	//for K2L
		KeyStone_memory_test(uiOSRStartAddress, uiOSREndAddress, 1, "OSR");
#endif
#if (DDR3B_MEM_TEST&TEST_BY_DMA&(2==CSL_DDR3_PER_CNT))
		//EDMA can only access upto 0x20000000 bytes in DDR3B
		if(uiDDR_B_Size*(uiCPU_ID+1)<=0x20000000) 	
		{
			KeyStone_memory_EDMA_test(0x60000000+uiDDR_B_Size*uiCPU_ID, 0x60000000+uiDDR_B_Size*(uiCPU_ID+1), 1, "DDR3B");
		}
#endif
#if (DDR3A_MEM_TEST&TEST_BY_DMA)
		//EDMA can only access upto 0x80000000 bytes in DDR3A
		if(ullDDR_A_Size*(uiCPU_ID+1)<=0x80000000) 	
		{
			KeyStone_memory_EDMA_test(0x80000000+ullDDR_A_Size*uiCPU_ID, 0x80000000+ullDDR_A_Size*(uiCPU_ID+1), 1, "DDR3A");
		}
#endif
#if (DDR3B_MEM_TEST&TEST_BY_CPU&(2==CSL_DDR3_PER_CNT))
    if(uiDDR_B_Size*uiCPU_ID>=0x20000000) //cover the range can not be accessed by EDMA
		KeyStone_memory_test(0x60000000, uiDDR_B_EndAddress, 1, "DDR3B");
    else  //only cover the cache path
		KeyStone_memory_test(0x60000000, 0x60000000+4*1024*1024, 1, "DDR3B");
#endif
#if (DDR3A_MEM_TEST&TEST_BY_CPU)
    if(ullDDR_A_Size*uiCPU_ID>=0x80000000) //cover the range can not be accessed by EDMA
		KeyStone_memory_test(0x80000000, uiDDR_A_EndAddress, 1, "DDR3A");
    else  //only cover the cache path
		KeyStone_memory_test(0x80000000, 0x80000000+4*1024*1024, 1, "DDR3A");
#endif

		printf("Memory test complete at %lld cycle\n", get_64_bit_cycle_count());
	}
}

