#ifdef CO_30_DIAGS


/************** INCLUDE FILES ****************************/
#include <stdio.h>
#include <diags_defines.h>
#include <bmehwapi.h>

/************** LOCAL MACROS *****************************/

/************** GLOBAL VARIABLES *************************/

/************** EXTERN FUNCTIONS AND VARIABLES ***********/
int testPIORead1 (int BmeNum, unsigned long addr);
void testPIOWrite (int BmeNum, unsigned long addr, unsigned long data);

/* extern tBmeStruct  	BmeStruct[];	*/  		 /* BME objects for direct API */

/************** LOCAL FUNCTION PROTOTYPES ****************/
unsigned int   bup_memTestDataBus(int bmeNum, UINT32 address);
unsigned int * bup_memTestAddressBus (int bmeNum, volatile unsigned int * baseAddress, unsigned int nBytes);
int bup_testDataLinesOrder (int bmeNum);
extern tBmeStruct BmeStruct[];


/********************************************************/
/*            EXPORTED FUNCTION DEFINITIONS             */
/********************************************************/


/**********************************************************************
 *
 * Function:    memTestDataBus()
 *
 * Description: Test the data bus wiring in a memory region by
 *              performing a walking 1's test at a fixed address
 *              within that region.  The address (and hence the
 *              memory region) is selected by the caller.
 *
 * Notes:       
 *
 * Returns:     0 if the test succeeds.  
 *              A non-zero result is the first pattern that failed.
 *
 **********************************************************************/
unsigned int bup_memTestDataBus(int bmeNum, UINT32 address)
{
    unsigned int pattern;

    /*
     * Perform a walking 1's test at the given address.
     */
    for (pattern = 1; pattern != 0; pattern <<= 1)
    {
        /*
         * Write the test pattern.
         */
		testPIOWrite (bmeNum,address,pattern);

        /*
         * Read it back (immediately 
         */
   		if (testPIORead1 (bmeNum,address) != (int) pattern)
        {
            return (pattern);
        }
    }

    return (0);

}   /* memTestDataBus() */


/**********************************************************************
 *
 * Function:    memTestAddressBus()
 *
 * Description: Test the address bus wiring in a memory region by
 *              performing a walking 1's test on the relevant bits
 *              of the address and checking for aliasing. This test
 *              will find single-bit address failures such as stuck
 *              -high, stuck-low, and shorted pins.  The base address
 *              and size of the region are selected by the caller.
 *
 * Returns:     NULL if the test succeeds.  
 *              A non-zero result is the first address at which an
 *              aliasing problem was uncovered.  By examining the
 *              contents of memory, it may be possible to gather
 *              additional information about the problem.
 *
 **********************************************************************/
unsigned int * bup_memTestAddressBus(int bmeNum, volatile unsigned int * baseAddress, unsigned int nBytes)
{

    register unsigned int addressMask = (nBytes/sizeof(unsigned int) - 1);
    register unsigned int offset;
    register unsigned int testOffset;

    register unsigned int pattern     = (unsigned int) 0xAAAAAAAA;
    register unsigned int antipattern = (unsigned int) 0x55555555;
    register int i;

    /*
     * Write the default pattern at each of the power-of-two offsets.
     */
    for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
    {
		testPIOWrite (bmeNum,(UINT32)&(baseAddress[offset]),pattern);
    }

    /* 
     * Check for address bits stuck high.
     */
	testPIOWrite (bmeNum,(UINT32)&(baseAddress[0]),antipattern);


    for (offset = 1,i=2; (offset & addressMask) != 0; offset <<= 1,i++)
    {
		 if (testPIORead1 (bmeNum,(UINT32)&(baseAddress[offset])) != (int)pattern)
		 {
			 DBG0(("Bme %d: **** Address bit %d stuck high\n",bmeNum, i))
			 return ((unsigned int *) (UINT32)&baseAddress[offset]);
		 }
    }

	testPIOWrite (bmeNum,(UINT32)&(baseAddress[0]),pattern);

    /*
     * Check for address bits stuck low or shorted.
     */
    for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1)
    {
		testPIOWrite (bmeNum,(UINT32)&(baseAddress[testOffset]),antipattern);

		if (testPIORead1 (bmeNum,(UINT32)&(baseAddress[0])) != (int)pattern)
		{
			DBG0(("Bme %d: **** Address bit %d stuck low\n",bmeNum, testOffset))
			return ((unsigned int *) (UINT32)&baseAddress[testOffset]);
		}
    }

    return (0);

}   /* memTestAddressBus() */


/********************************************************/
/* FUNCTION: int bup_testDataLinesOrder (int bmeNum)    */
/********************************************************/
// This is to check if the data lines d0 to d15 are connected in the corrct order (not flipped)
// fill 0x12345678 and 0xAB0000CD to consecutive 32 bit locations
// zero out two consec. dest 32 bit locations, DMA 1 byte from the base address to a that address
// expect to see only one byte (0x12000000 or 0x00000078) depending on big or little endian
// then dma 5 bytes from the source to dest. expect to see only 1 byte in the 2nd dest. loc
// 0xAB000000 or 0x000000CD depending on big or little endian

int bup_testDataLinesOrder (int bmeNum)
{
    int CCRval, i, data1;
    // write 0x12345678 and AB0000CD to adjacent locations
    testPIOWrite (bmeNum, DMA_TEST_START_ADDR, 0x12345678);
    testPIOWrite (bmeNum, DMA_TEST_START_ADDR+4, 0xAB0000CD);
    // write 0 to the destination addresses
    testPIOWrite (bmeNum, DMA_TEST_START_ADDR+0x100, 0x0);
    testPIOWrite (bmeNum, DMA_TEST_START_ADDR+0x104, 0x0);
    // setup and start 1 byte dma
    testPIOWrite (bmeNum, DMA_ECR(0, DMA_CH_0), DMA_ECR_SW_REQ);	 /*set software DMA request*/
    testPIOWrite (bmeNum, DMA_SAR(0, DMA_CH_0), DMA_TEST_START_ADDR);	 /*set source address*/
    testPIOWrite (bmeNum, DMA_DAR(0, DMA_CH_0), DMA_TEST_START_ADDR+0x100);	 /*set dest address*/
    CCRval = DMA_CCR_CH_EN | DMA_CCR_START; // DMA 1 byte
    testPIOWrite (bmeNum, DMA_CCR(0, DMA_CH_0), CCRval);  /*Load DMA ccr register to start DMA*/

    data1 = testPIORead1 (bmeNum, DMA_CCR(0, DMA_CH_0));
    i = 0;
    while (!(data1 & DMA_CCR_DONE))  /*polling for DMA done bit*/
    {
        BUP_DELAY_MS(20);
        data1 = testPIORead1 (bmeNum, DMA_CCR(0, DMA_CH_0));
        i++;
        if (i == DMA_WAIT_LOOP_TIMEOUT)
        {
            DBG0(("Bme %d: timeout waiting for 1 byte dma done in data bus check\n", bmeNum))
            return -1;
        }
    }

    data1 = testPIORead1 (bmeNum, DMA_TEST_START_ADDR+0x100);
#if (HOST_ENDIANESS==BIG_ENDIAN)
    if (0x12000000 != data1)
#elif (HOST_ENDIANESS==LITTLE_ENDIAN)
    if (0x00000078 != data1)
#endif
    {
        DBG2(("Read 0x%x instead of 0x12000000 (assuming big endian)\n", data1))
        DBG0(("Bme %d: Data bus lines not connected in the correct order! TEST FAILED\n", bmeNum))
        return -1;
    }

    // setup and start 5 byte dma
    testPIOWrite (bmeNum, DMA_ECR(0, DMA_CH_0), DMA_ECR_SW_REQ);	 /*set software DMA request*/
    testPIOWrite (bmeNum, DMA_SAR(0, DMA_CH_0), DMA_TEST_START_ADDR);	 /*set source address*/
    testPIOWrite (bmeNum, DMA_DAR(0, DMA_CH_0), DMA_TEST_START_ADDR+0x100);	 /*set dest address*/
    CCRval = DMA_CCR_CH_EN | DMA_CCR_START | ((5-1) << 16); // DMA 5 bytes
    testPIOWrite (bmeNum, DMA_CCR(0, DMA_CH_0), CCRval);  /*Load DMA ccr register to start DMA*/

    data1 = testPIORead1 (bmeNum, DMA_CCR(0, DMA_CH_0));
    i = 0;
    while (!(data1 & DMA_CCR_DONE))  /*polling for DMA done bit*/
    {
        BUP_DELAY_MS(20);
        data1 = testPIORead1 (bmeNum, DMA_CCR(0, DMA_CH_0));
        i++;
        if (i == DMA_WAIT_LOOP_TIMEOUT)
        {
            DBG0(("Bme %d: timeout waiting for 5 byte dma done in data bus check\n", bmeNum))
            return -1;
        }
    }
    data1 = testPIORead1 (bmeNum, DMA_TEST_START_ADDR+0x104);
#if (HOST_ENDIANESS==BIG_ENDIAN)
    if ((int) 0xAB000000 != data1)
#elif (HOST_ENDIANESS==LITTLE_ENDIAN)
    if ((int) 0x000000CD != data1)
#endif
    {
        DBG2(("Read 0x%x instead of 0xAB000000 (assuming big endian)\n", data1))
        DBG0(("Bme %d: Data bus lines not connected in the correct order! TEST FAILED\n",bmeNum))
        return -1;
    }

    DBG1(("Bme %d: Data lines order check passed\n", bmeNum))
    return 0;
}


/********************************************************/
/* FUNCTION: int bup_memTestAddrData (int bmeNum)       */
/********************************************************/
// Call both the data and address bus tests, and return 0 if both pass.

int bup_memTestAddrData (int bmeNum)
{
    int addr;

    if ((addr = (UINT32)bup_memTestAddressBus(bmeNum, (int*)BME_SDRAM_MEMBASE, gBmeMemSz[bmeNum])))
    {
		DBG0(("Bme %d: Memory Address Bus Test FAILED at address: 0x%x\n",bmeNum, addr))
		return -1;
    } else {
		DBG1(("Bme %d: Memory Address Bus Test Passed\n", bmeNum))
    }

	if ((addr = bup_memTestDataBus(bmeNum, BME_SDRAM_MEMBASE)))
	{
		int i =0;
		while (addr) {
			addr >>=1;
			i++;
		}
		DBG0(("Bme %d: Memory Data Bus Test FAILED at data bit : %d\n",bmeNum, i-1))
		return -1;
	} else {
		DBG1(("Bme %d: Memory Data Bus Test Passed\n",bmeNum))
    }

    // check if the data lines are connected in the correct order
	addr = bup_testDataLinesOrder (bmeNum);
    if (addr)
        return -1;
    
    DBG1(("SDRAM ADDRESS & DATA BUS TESTS PASSED\n"))

	return 0;
}

/********************************************************/
/* FUNCTION: unsigned int detectBmeMemSize (int bmeNum) */
/********************************************************/
// Write 0, 1, 2.. at every 1 MB boundary, ie, write 0 at 0x40000000, 1 at 0x40100000 etc.
// Every time a write is done (except at the base address), read back the value at the
// base address which was written zero initially. As the memory address aliases to zero
// after the full available memory is written, the first non-zero number read back at
// the base address gives the size of the memory in megabytes.

unsigned int detectBmeMemSize (int bmeNum)
{
    #define ONE_MEGA_BYTE   (0x100000)

    int writeData = 0;
    int writeAddr;
    int readData = 0xFFFFFFFF;

    for (writeAddr = BME_SDRAM_MEMBASE;
            writeAddr < (int) (BME_SDRAM_MEMBASE + BME_SDRAM_MEM_ADDR_SPACE);
            writeAddr += ONE_MEGA_BYTE)
    {
        testPIOWrite (bmeNum, writeAddr, writeData);
        if (writeData)
        {
            readData = testPIORead1 (bmeNum, BME_SDRAM_MEMBASE);
            if (readData)
                break;
        }
        writeData++;
    }
    if (readData)
        gBmeMemSz[bmeNum] = readData * ONE_MEGA_BYTE;
    else
        gBmeMemSz[bmeNum] = BME_SDRAM_MEM_ADDR_SPACE;

    return (gBmeMemSz[bmeNum]);
}

//----------------------------------------------------------------------------

/**********************************************************/
/* FUNCTION: int bup_write_read_whole_memory (int bmeNum) */
/**********************************************************/
// Write incremented walking ones & zeros to the whole bme memory and read
// back, from the host, using HIC-PIO with address auto-increment.
// The memory size and base address are taken from the gBmeMemSz[] array
// and BME_SDRAM_MEMBASE macro respectively.

int bup_write_read_whole_memory (int bmeNum)
{
	UINT32 EvenData = 0xaaaaaaaa;
	UINT32 OddData = 0x55555555;
	int i;
	int MemSize = gBmeMemSz[bmeNum]/4;
    UINT32 filldata[2];
    tBmeStruct *pBme;
    UINT32 readVal;

    pBme = &BmeStruct[bmeNum];
	DBG1(("Bme %d: Full Memory R/W Walking 1s & 0s test\n", bmeNum))
	DBG1(("Total memory being tested: %d Megabytes\tBase Address: 0x%lX\n",
                gBmeMemSz[bmeNum]/0x100000, BME_SDRAM_MEMBASE))
    DBG1(("Writing to memory. This may take a few minutes...\n"))

    filldata[0] = EvenData;
    filldata[1] = OddData;

    testPIOWrite (bmeNum, BME_SDRAM_MEMBASE, filldata[0]);
    filldata[0]++;

	//write whole SDRAM
	for (i=1; i<MemSize; i++)
    {
        bmePioWriteNextLoc (pBme, (BYTE *)&filldata[i%2]);
        //testPIOWrite (bmeNum, BME_SDRAM_MEMBASE + i*4, filldata[i%2]);

        filldata[i%2]++;

        if (!(i%0x10000)) DBG1(("w"))
    }
    DBG1(("\n"))

    DBG1(("Reading from memory. This may take a few minutes...\n"));

    filldata[0] = EvenData;
    filldata[1] = OddData;

    readVal = testPIORead1 (bmeNum, BME_SDRAM_MEMBASE);
    if (readVal != filldata[0])
    {
        DBG0(("Bme %d: Full memory read/write test FAILED: loc 0x%lx\n", bmeNum, BME_SDRAM_MEMBASE))
        return -1;
    }
    filldata[0]++;

    //read whole SDRAM
	for (i=1; i<MemSize; i++)
    {
        bmePioReadNextLoc (pBme, (BYTE *)&readVal);
        //readVal = testPIORead1 (bmeNum, BME_SDRAM_MEMBASE + i*4);

        if (readVal != filldata[i%2])
        {
            DBG0(("Bme %d: Full memory read/write test FAILED: loc 0x%lx\n", bmeNum, BME_SDRAM_MEMBASE+i*4))
            return -1;
        }
        filldata[i%2]++;

        if (!(i%0x10000)) DBG1(("r"))
    }
    DBG1(("\n"))

    DBG1(("WALKING 1s & 0s SDRAM READ/WRITE TEST PASSED on BME %d\n", bmeNum))
    return 0;
}

#endif //CO_30_DIAGS
