/******************************************************************************

  Copyright (C), 2010-2013, Texas Instrument.

 ******************************************************************************
  File Name     : Robust_DDR_ECC.c
  Version       : Initial Draft
  Author        : Brighton Feng
  Created       : 2012/11/2
  Last Modified :
  Description   : DDR ECC test example
  Function List :
  History       :
  1.Date        : August 15, 2013
    Author      : Brighton Feng
    Modification: Updated according to new usage notes about spurious errors

******************************************************************************/

#include <stdio.h>
#include <string.h>
#include "KeyStone_common.h"

/*----------------------------------------------*
 * external variables                           *
 *----------------------------------------------*/

/*----------------------------------------------*
 * external routine prototypes                  *
 *----------------------------------------------*/

/*----------------------------------------------*
 * internal routine prototypes                  *
 *----------------------------------------------*/

/*----------------------------------------------*
 * project-wide global variables                *
 *----------------------------------------------*/

/*----------------------------------------------*
 * module-wide global variables                 *
 *----------------------------------------------*/
#define DDR_ECC_TEST_BUF_SIZE_BYTES (32*1024)
#pragma DATA_SECTION (DDR_ECC_Test, "DDRECCData")
#pragma DATA_ALIGN (DDR_ECC_Test, DDR_ECC_TEST_BUF_SIZE_BYTES)
Uint8 DDR_ECC_Test[DDR_ECC_TEST_BUF_SIZE_BYTES];
/*----------------------------------------------*
 * constants                                    *
 *----------------------------------------------*/

/*----------------------------------------------*
 * macros                                       *
 *----------------------------------------------*/

/*----------------------------------------------*
 * routines' implementations                    *
 *----------------------------------------------*/

/*DDR ECC test with DSP core*/
void DDR_ECC_test_core()
{
	Uint8 readValue;

	puts("make the test data space cacheable");
	gpCGEM_regs->MAR[((Uint32)DDR_ECC_Test)/(16*1024*1024)]=1;

	//clear the ECC errot status
	gpDDR_regs->IRQSTATUS_SYS= CSL_EMIF4F_IRQSTATUS_SYS_REG_RD_ECC_ERR_SYS_MASK
		|CSL_EMIF4F_IRQSTATUS_SYS_REG_WR_ECC_ERR_SYS_MASK;

	printf("Fill (STDW, 64-bit aligned) test buffer from 0x%x with 0 ...\n",	DDR_ECC_Test);

	/*memset is implemented with STDW (64-bit aligned). Since L2 cache is enabled, 
	data line will be read into cache, and then new data will be written in the cache*/
	memset((void *)DDR_ECC_Test, 0, 128);

	puts("!!!CACHE_wbInvL2 on the test data buffer, a spurious write ECC error and MDMA error will be generated, these should be ignored in real application...");
	CACHE_wbInvL2((void *)DDR_ECC_Test, 128, CACHE_NOWAIT);
	/*normally, exception is captured about 10~100 cycles after the
	access violation. Dummy operations added here to wait for it.*/
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5"); 	/*NRP should be around the address of this instruction*/
	asm(" nop 5");
    _mfence();
    _mfence();

	printf("read back value = 0x%x\n", DDR_ECC_Test[0]);

	puts("\nmake the test data space non-cacheable");
	gpCGEM_regs->MAR[((Uint32)DDR_ECC_Test)/(16*1024*1024)]=0;

	//clear the ECC errot status
	gpDDR_regs->IRQSTATUS_SYS= CSL_EMIF4F_IRQSTATUS_SYS_REG_RD_ECC_ERR_SYS_MASK
		|CSL_EMIF4F_IRQSTATUS_SYS_REG_WR_ECC_ERR_SYS_MASK;

	printf("Fill (STDW, 64-bit aligned) test buffer from 0x%x with 0 ...\n",	DDR_ECC_Test);

	//memset is implemented with STDW (64-bit aligned), parity will be generated
	memset((void *)DDR_ECC_Test, 0, DDR_ECC_TEST_BUF_SIZE_BYTES);
	
	printf("\nwrite one byte 0x55 to address 0x%x in DDR ECC range ...\n",
		(Uint32)&DDR_ECC_Test[1]);

	DDR_ECC_Test[1]= 0x55;

	printf("read back value at 0x%x ...\n", &DDR_ECC_Test[1]);
	readValue = DDR_ECC_Test[1];
	printf("read back value = 0x%x. ", readValue);
	if(readValue!=0x55)
		printf("data corrupted!!!\n");
	else
		printf("\n");
}

/*DDR ECC test with EDMA*/
void DDR_ECC_test_EDMA()
{
	int i;
	unsigned long long srcValue, dstValue;

	puts("make the test data space non-cacheable");
	gpCGEM_regs->MAR[((Uint32)DDR_ECC_Test)/(16*1024*1024)]=0;

	//clear the ECC errot status
	gpDDR_regs->IRQSTATUS_SYS= CSL_EMIF4F_IRQSTATUS_SYS_REG_RD_ECC_ERR_SYS_MASK
		|CSL_EMIF4F_IRQSTATUS_SYS_REG_WR_ECC_ERR_SYS_MASK;

	printf("EDMA copy 128 byte from source buffer (0x%x) to destination buffer (0x%x) ...\n",
		(Uint32)&DDR_ECC_Test[DDR_ECC_TEST_BUF_SIZE_BYTES/2], (Uint32)&DDR_ECC_Test[0]);

	EDMA_copy((Uint32)&DDR_ECC_Test[DDR_ECC_TEST_BUF_SIZE_BYTES/2], (Uint32)&DDR_ECC_Test[0], 128, EDMA_CC2_CH0, DMA_WAIT);

	printf("read back source value =0x%x, destination value =0x%x.\n",
		*(unsigned long long *)&DDR_ECC_Test[DDR_ECC_TEST_BUF_SIZE_BYTES/2+64],
		*(unsigned long long *)&DDR_ECC_Test[64]);

	printf("\n!!!EDMA copy one byte from source buffer (0x%x) to destination buffer (0x%x) ...\n",
		(Uint32)&DDR_ECC_Test[0],(Uint32)&DDR_ECC_Test[DDR_ECC_TEST_BUF_SIZE_BYTES/2]);

	EDMA_copy((Uint32)&DDR_ECC_Test[0], (Uint32)&DDR_ECC_Test[DDR_ECC_TEST_BUF_SIZE_BYTES/2], 
		1, EDMA_CC2_CH0, DMA_NO_WAIT);
	for(i=0;i<100; i++)
	{
	 	/*normally, exception is captured about 10~100 cycles after the
		access violation. Dummy operations added here to wait for it.*/
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5");
		asm(" nop 5"); 	/*NRP should be around the address of this instruction*/
		asm(" nop 5");
	}
	EDMA_wait(EDMA_CC2_CH0);
	
	puts("\n!!!read source and destination value with DSP core to check the corrupted data...");
	srcValue= *(unsigned long long *)&DDR_ECC_Test[0];
	dstValue= *(unsigned long long *)&DDR_ECC_Test[DDR_ECC_TEST_BUF_SIZE_BYTES/2];
	
 	/*normally, exception is captured about 10~100 cycles after the
	access violation. Dummy operations added here to wait for it.*/
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5");
	asm(" nop 5"); 	/*NRP should be around the address of this instruction*/
	asm(" nop 5");

	printf("read back source value =0x%llx, destination value=0x%llx\n",
		srcValue, dstValue);

}

/*****************************************************************************
 Prototype    : DDR_ECC_test
 Description  : DDR ECC test example
 Input        : None
 Output       : None
 Return Value : 
 
  History        :
  1.Date         : 2012/11/2
    Author       : Brighton Feng
    Modification : Created function

*****************************************************************************/
void DDR_ECC_test()
{
	TDSP_Board_Type DSP_Board_Type= KeyStone_Get_dsp_board_type();
	CACHE_L2Size L2Size;
	
	puts("===================-DDR ECC test-================================");
	if(TCI6614_EVM != DSP_Board_Type)
	{
		puts("DDR ECC is not supported on this board.");	
		return;
	}

	/*fill the test buffer in multiple of 64-bit and aligned, 
	to generate initial parity value for ECC.
	This should be done with EDMA instead of DSP core if cache is enabled.*/
	EDMA_fill((Uint32)DDR_ECC_Test, 0, DDR_ECC_TEST_BUF_SIZE_BYTES, EDMA_CC2_CH0, DMA_WAIT);

	L2Size = CACHE_getL2Size(); //save size of L2 cache
	CACHE_setL2Size(CACHE_128KCACHE);

	puts("-----------DDR ECC test with DSP core--------------");
	DDR_ECC_test_core(); 	/*DDR ECC test with DSP core*/

	puts("-----------DDR ECC test with EDMA------------------");
	DDR_ECC_test_EDMA(); 	/*DDR ECC test with EDMA*/

    CACHE_setL2Size(L2Size); //restore size of L2 cache
}

