/*
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * \file:   ddr3_test.c
 *
 * \brief:  contains Routines for DDR test application
 *
 *         This file contains the support function for DDR Test application.
 *
 */

/*
 *====================
 * Includes
 *====================
 */
#include "dm8127Board.h"
#include "dm8127_Platform.h"
#include "stdio.h"
#include "ddr3.h"

/*
 *====================
 * Static declarations
 *====================
 */
static UINT8 tx[DDR_RW_SIZE];
static UINT8 rx[DDR_RW_SIZE];

 /*
 *=========================
 * Function implementations
 *=========================
 */
 
/***
 * \brief:  Pattern update function on DDR3 memory
 *
 * \b \Descr: This function write the given pattern into the DDR
 * \n         and verify it. it throw the messeage for a particular
 * \n         memory location if any error or data mismatch happen
 *            to that particular location.
 *
 * \param:  pu32BaseAddr [IN]  starting address of the DDR3 memory.
 * \n       u32Size      [IN]  size of memory location to be written
 * \n       u32Pattern   [IN]  Pattern to be written
 *
 * \return: SUCCESS  on successful memory write and verify
 * \n       FAILED   Memory data error
 */
STATUS ddr3_pattern_test 
(
	UINT32* pu32BaseAddr, 
	UINT32 u32Size, 
	UINT32 u32Pattern
)
{
	STATUS u32RetVal = SUCCESS;
	UINT32 u32Count = 0;
	UINT32* pu32Addr = pu32BaseAddr;
	

	if((0x00000001 == u32Pattern))
	{
	/* ddr3 on EMIF 0 */
		for (u32Count = 0; u32Count < u32Size/4; u32Count++)
		{
			*pu32Addr++ = u32Pattern;
		}
	}
	else
	{
		for (u32Count = 0; u32Count < u32Size/4; u32Count++)
		{
			*pu32Addr++ = u32Pattern;
		}

	}
	/* Verify the pattern written to memory */
	pu32Addr = pu32BaseAddr;
	for (u32Count = 0; u32Count < u32Size/4; u32Count++)
	{
		if (*pu32Addr++ != u32Pattern)
		{
			printf ("Memory cell verification failed at addr 0x%x.\r\n",
					pu32Addr);
			u32RetVal = FAILED;
			break;
		}			
	}
	 
	 return (u32RetVal);
}

/***
 * \brief:  Patter update function on DDR3 memory
 *
 * \b \Descr: This function write the given pattern into the DDR
 * \n         and verify it. it throw the messeage for a particular
 * \n         memory location if any error or data mismatch happen
 * \n         to that particular location.
 *
 * \param:  pu32BaseAddr [IN]  starting address of the DDR3 memory.
 *          u32Size      [IN]  size of memory location to be written
 *          u32Pattern   [IN]  Pattern to be written
 *
 * \return: SUCCESS  on successful memory write and verify
 * \n       FAILED   Memory data error
 */

STATUS ddr3MemoryDatatest
(
	UINT32* pu32BaseAddr, 
	UINT32 u32Size,
	UINT32 U32pattern
)
{
	STATUS u32RetVal = SUCCESS;
	UINT32 u32Count = 0;
	UINT32* pu32Addr = pu32BaseAddr;
	
	if ((0x00000001 == U32pattern))
	{
		/* ddr3 on EMIF 0 */
		for (u32Count = 0; u32Count < u32Size/4; u32Count++)
		{
			*pu32Addr++ = u32Count;
		}

		/* Verify the pattern written to memory */
		pu32Addr = pu32BaseAddr;
		for (u32Count = 0; u32Count < u32Size/4; u32Count++)
		{
			if (*pu32Addr++ != u32Count)
			{
#ifdef DEBUG
				printf ("Incremental pattern Memory cell verification failed "
						"at addr 0x%x.\r\n",pu32Addr);
#else
				platform_write("Incremental pattern Memory cell verification failed "
						       "at addr 0x%x.\r\n",pu32Addr);
#endif

				u32RetVal = FAILED;
				break;
			}
		}
	}
	else
	{
		/* ddr3 on EMIF 0 */
		for (u32Count = 0; u32Count < u32Size/4; u32Count++)
		{
			*pu32Addr++ = U32pattern;
		}

		/* Verify the pattern written to memory */
		pu32Addr = pu32BaseAddr;
		for (u32Count = 0; u32Count < u32Size/4; u32Count++)
		{
			if (*pu32Addr++ != U32pattern)
			{
#ifdef DEBUG
				printf ("Incremental pattern Memory cell verification failed "
						"at addr 0x%x.\r\n",pu32Addr);
#else
				platform_write("Incremental pattern Memory cell verification failed "
						       "at addr 0x%x.\r\n",pu32Addr);
#endif
				u32RetVal = FAILED;
				break;
			}
		}
	}
	 return (u32RetVal);
}

 /***
 * \brief : Routine to test ddr3 memory.
 *
 * \b \Descr: This routine tests the ddr3 by writing into all banks and reading
 *            from it then compares both .This routine takes  ddrctrl as parameter
 *            to select the controller.
 * 
 * \param   ddrctrl   [IN]   To select controller
 *
 * \return  0  for success  - Description
 * \n        1  for error   - Description
 *
 */
SINT16 ddr3_rw_test
(
	SINT16 ddrCtrl
)
{
    SINT16 i, j;
    UINT8* p8;
    UINT8 * src, *dst;
    UINT32 ddr_base, ddr_size, ddr_banks;

    if (DDR0_CTRL == ddrCtrl)
    {
		ddr_base = DDR0_BASE;
		ddr_size = DDR0_SIZE;
		ddr_banks = DDR0_BANK_NUM;
    }
    else if (DDR1_CTRL == ddrCtrl)
    {
		ddr_base = DDR1_BASE;
		ddr_size = DDR1_SIZE;
		ddr_banks = DDR1_BANK_NUM;
    }

    /* Write the known patterns to all banks of the DDR */
    for ( i = 0; i < ddr_banks; i++)
    {
        /* Create the test pattern */
        p8 = ( UINT8* )tx;
        for ( j = 0 ; j < DDR_RW_SIZE ; j++ )
            *p8++ = ( UINT8 )( j + i );

		/* Write the size of DDR_RW_SIZE to the bank of ddr3 memory */
		src = tx;
		dst = (UINT8 *) (ddr_base + i * (ddr_size/ddr_banks)); /* 16 MB */
		ddr3_write ((UINT16 *)src, (UINT16 *)dst, DDR_RW_SIZE);
    }

    /* Clear the receive buffer */
    for ( j = 0 ; j < DDR_RW_SIZE ; j++ )
        rx[j] = 0;

    /* Read and verify ddr3 */
    for ( i = 0 ; i < ddr_banks ; i++ )
    {
        /* Read a ddr3 bank */
		src = (UINT8 *)(ddr_base + i * (ddr_size/ddr_banks));
		//dst = rx;
        ddr3_read((UINT16 *)src, (UINT16 *)rx/*dst*/, DDR_RW_SIZE);

        /* Check the pattern */
        p8 = ( UINT8* )rx;
        for ( j = 0 ; j < DDR_RW_SIZE ; j++ )
            if ( ( *p8++ ) != ( UINT8 )( i + j ) )
                return 1;  // Fail
    }

    return 0;
}

/***
 * \brief: Routine to test the ddr3 with cache_enable option
 *
 * \b \Descr: This routine takes cache_enable option as a parameter and does DDR
 *            read write tests.
 *
 * \param: cache_enable [IN] cache_enable if required
 *
 * \return: SUCCESS for success  - Description
 * \n       FAILED for error   - Description
 *
 */
 
STATUS  DDR3_test
(
	void * cache_enable
)
{
	STATUS u32RetVal = SUCCESS;
//#ifdef DDR_PRE_COMPLIANCE
	UINT32 ddr_size;
	ddr_size = 0x100000;
//#endif

	Uart_stringSend("\r\n==================================="
					"\r\n        DDR3 Test                  "
					"\r\n===================================\r\n");


#ifdef PRE_COMPLIANCE


	Uart_stringSend("\r\nDDR3 test performs Multiple pattern test "
			        "on the 1MB of the DDR memory\r\nfrom starting "
			        "location of the DDR memory\r\n"
			        "This test write the pattern on the DDR memory verify after\r\n"
			        "reading the data, In case of any error memory location will display\r\n");

    platform_write("\nRunning DDR3 Sequential Memory Read/Write Test\n");
    u32RetVal = ddr3_pattern_test ((UINT32*)DDR0_BASE, ddr_size, 0xA5A5A5A5);
	if (SUCCESS != u32RetVal)
	{
		platform_write ("DDR3 Sequential Memory Read/Write Test failed\r\n");
		u32RetVal = FAILED;
	}
	else
		platform_write ("DDR3 Sequential Memory Read/Write Test passed\r\n");

#else    // not compiliance


#if DISABLE
    if (*cache_enable)
    {
#ifdef DEBUG
        /* Check how to enable the cache */
    	printf("ddr3_test: TO DO - Enable the cache here\n");
#endif
    }
    else
    {
#ifdef DEBUG
        /* TO DO - Check how to disable the cache */
	printf("ddr3_test: TODO - Disable the cache here\n");
#endif
    }
#endif


	Uart_stringSend("\r\nDDR3 test performs Multiple pattern test "
			        "on the 2GB of the DDR memory\r\nfrom starting "
			        "location of the DDR memory\r\n"
			        "This test write the pattern on the DDR memory verify after\r\n"
			        "reading the data, In case of any error memory location will display\r\n");
    /* DDR3 Test execution */
#ifdef DEBUG
    printf ("Carrying out Incremental pattern test for DDR[0].\r\n");
#else
    Uart_stringSend("Carrying out Incremental pattern test for DDR[0]...\r\n");
#endif
	u32RetVal = ddr3MemoryDatatest ((UINT32*)DDR0_BASE, DDR0_SIZE, (UINT32)0x00000001);
	if (SUCCESS != u32RetVal)
	{
#ifdef DEBUG
		printf ("Incremental Pattern write Test failed for DDR[0].\r\n");
#else
		Uart_stringSend("Incremental Pattern write Test failed for DDR[0].\r\n");
#endif
	}

#ifdef DEBUG
	printf ("Carrying out Fixed pattern 0xA5A5A5A5 for DDR[0].\r\n");
#else
    Uart_stringSend("Carrying out Fixed pattern 0xA5A5A5A5 for DDR[0]...\r\n");
#endif
	u32RetVal = ddr3MemoryDatatest ((UINT32*)DDR0_BASE, DDR0_SIZE,(UINT32)0xA5A5A5A5);
	if (SUCCESS != u32RetVal)
	{
#ifdef DEBUG
		printf ("Fixed Pattern 0xA5A5A5A5 write Test failed for DDR[0]\r\n");
#else
		Uart_stringSend ("Fixed Pattern 0xA5A5A5A5 write Test failed for DDR[0]\r\n");
#endif
	}


#ifdef DEBUG
	printf ("Carrying out Fixed pattern 0XFFFFFFFF for DDR[0]..\r\n");
#else
    Uart_stringSend("Carrying out Fixed pattern 0XFFFFFFFF for DDR[0]...\r\n");
#endif

	u32RetVal = ddr3MemoryDatatest ((UINT32*)DDR0_BASE, DDR0_SIZE,(UINT32)0xFFFFFFFF);
	if (SUCCESS != u32RetVal)
	{
#ifdef DEBUG
		printf ("Fixed Pattern 0xFFFFFFFF write Test failed for DDR[0]\r\n");
#else
		Uart_stringSend ("Fixed Pattern 0xFFFFFFFF write Test failed for DDR[0]\r\n");
#endif

	}


#ifdef DEBUG
    printf ("Carrying out Incremental pattern test for DDR[1].\r\n");
#else
    Uart_stringSend("Carrying out Incremental pattern test for DDR[1]...\r\n");
#endif
	u32RetVal = ddr3MemoryDatatest ((UINT32*)DDR1_BASE, DDR1_SIZE, (UINT32)0x00000001);
	if (SUCCESS != u32RetVal)
	{
#ifdef DEBUG
		printf ("Incremental Pattern write Test failed for DDR[1].\r\n");
#else
		Uart_stringSend("Incremental Pattern write Test failed for DDR[1].\r\n");
#endif
	}


#ifdef DEBUG
	printf ("Carrying out Fixed pattern 0xA5A5A5A5 for DDR[1].\r\n");
#else
    Uart_stringSend("Carrying out Fixed pattern 0xA5A5A5A5 for DDR[1]...\r\n");
#endif
	u32RetVal = ddr3MemoryDatatest ((UINT32*)DDR1_BASE, DDR1_SIZE,(UINT32)0xA5A5A5A5);
	if (SUCCESS != u32RetVal)
	{
#ifdef DEBUG
		printf ("Fixed Pattern 0xA5A5A5A5 write Test failed for DDR[1]\r\n");
#else
		Uart_stringSend ("Fixed Pattern 0xA5A5A5A5 write Test failed for DDR[1]\r\n");
#endif
	}


#ifdef DEBUG
	printf ("Carrying out Fixed pattern 0XFFFFFFFF for DDR[1]..\r\n");
#else
    Uart_stringSend("Carrying out Fixed pattern 0XFFFFFFFF for DDR[1]...\r\n");
#endif
	u32RetVal = ddr3MemoryDatatest ((UINT32*)DDR1_BASE, DDR1_SIZE,(UINT32)0xFFFFFFFF);
	if (SUCCESS != u32RetVal)
	{
#ifdef DEBUG
		printf ("Fixed Pattern 0xFFFFFFFF write Test failed for DDR[1]\r\n");
#else
		Uart_stringSend ("Fixed Pattern 0xFFFFFFFF write Test failed for DDR[1]\r\n");
#endif
	}
#endif
	Uart_stringSend("\r\n-------------------------X-----------------------------");
    return u32RetVal;
}

