302 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			302 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**********************************************************************
 | |
|  *
 | |
|  * Filename:    memtest.c
 | |
|  *
 | |
|  * Description: General-purpose memory testing functions.
 | |
|  *
 | |
|  * Notes:       This software can be easily ported to systems with
 | |
|  *              different data bus widths by redefining 'datum'.
 | |
|  *
 | |
|  *
 | |
|  * Copyright (c) 1998 by Michael Barr.  This software is placed into
 | |
|  * the public domain and may be used for any purpose.  However, this
 | |
|  * notice must not be changed or removed and no warranty is either
 | |
|  * expressed or implied by its publication or distribution.
 | |
|  **********************************************************************/
 | |
| 
 | |
| #include "os_types.h"
 | |
| #include "os_utils.h"
 | |
| #include "dbg_io.h"
 | |
| #include "iot_io.h"
 | |
| #include "iot_clock.h"
 | |
| #include "memtest.h"
 | |
| #include "system.h"
 | |
| #include "ahb.h"
 | |
| #include "ddrc.h"
 | |
| 
 | |
| /**********************************************************************
 | |
|  *
 | |
|  * 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.
 | |
|  *
 | |
|  **********************************************************************/
 | |
| datum
 | |
| memTestDataBus(volatile datum * address)
 | |
| {
 | |
|     datum pattern;
 | |
| 
 | |
| 
 | |
|     /*
 | |
|      * Perform a walking 1's test at the given address.
 | |
|      */
 | |
|     for (pattern = 1; pattern != 0; pattern <<= 1)
 | |
|     {
 | |
|         /*
 | |
|          * Write the test pattern.
 | |
|          */
 | |
|         *address = pattern;
 | |
| 
 | |
|         /*
 | |
|          * Read it back (immediately is okay for this test).
 | |
|          */
 | |
|         if (*address != 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.
 | |
|  *
 | |
|  * Notes:       For best results, the selected base address should
 | |
|  *              have enough LSB 0's to guarantee single address bit
 | |
|  *              changes.  For example, to test a 64-Kbyte region,
 | |
|  *              select a base address on a 64-Kbyte boundary.  Also,
 | |
|  *              select the region size as a power-of-two--if at all
 | |
|  *              possible.
 | |
|  *
 | |
|  * 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.
 | |
|  *
 | |
|  **********************************************************************/
 | |
| datum *
 | |
| memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes)
 | |
| {
 | |
|     unsigned long addressMask = (nBytes/sizeof(datum) - 1);
 | |
|     unsigned long offset;
 | |
|     unsigned long testOffset;
 | |
| 
 | |
|     datum pattern     = (datum) 0xAAAAAAAA;
 | |
|     datum antipattern = (datum) 0x55555555;
 | |
| 
 | |
| 
 | |
|     /*
 | |
|      * Write the default pattern at each of the power-of-two offsets.
 | |
|      */
 | |
|     for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
 | |
|     {
 | |
|         baseAddress[offset] = pattern;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Check for address bits stuck high.
 | |
|      */
 | |
|     testOffset = 0;
 | |
|     baseAddress[testOffset] = antipattern;
 | |
| 
 | |
|     for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
 | |
|     {
 | |
|         if (baseAddress[offset] != pattern)
 | |
|         {
 | |
|             return ((datum *) &baseAddress[offset]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     baseAddress[testOffset] = pattern;
 | |
| 
 | |
|     /*
 | |
|      * Check for address bits stuck low or shorted.
 | |
|      */
 | |
|     for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1)
 | |
|     {
 | |
|         baseAddress[testOffset] = antipattern;
 | |
| 
 | |
|         if (baseAddress[0] != pattern)
 | |
|         {
 | |
|             return ((datum *) &baseAddress[testOffset]);
 | |
|         }
 | |
| 
 | |
|         for (offset = 1; (offset & addressMask) != 0; offset <<= 1)
 | |
|         {
 | |
|             if ((baseAddress[offset] != pattern) && (offset != testOffset))
 | |
|             {
 | |
|                 return ((datum *) &baseAddress[testOffset]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         baseAddress[testOffset] = pattern;
 | |
|     }
 | |
| 
 | |
|     return (NULL);
 | |
| 
 | |
| }   /* memTestAddressBus() */
 | |
| 
 | |
| 
 | |
| /**********************************************************************
 | |
|  *
 | |
|  * Function:    memTestDevice()
 | |
|  *
 | |
|  * Description: Test the integrity of a physical memory device by
 | |
|  *              performing an increment/decrement test over the
 | |
|  *              entire region.  In the process every storage bit
 | |
|  *              in the device is tested as a zero and a one.  The
 | |
|  *              base address and the size of the region are
 | |
|  *              selected by the caller.
 | |
|  *
 | |
|  * Notes:
 | |
|  *
 | |
|  * Returns:     NULL if the test succeeds.
 | |
|  *
 | |
|  *              A non-zero result is the first address at which an
 | |
|  *              incorrect value was read back.  By examining the
 | |
|  *              contents of memory, it may be possible to gather
 | |
|  *              additional information about the problem.
 | |
|  *
 | |
|  **********************************************************************/
 | |
| 
 | |
| datum *
 | |
| memTestDevice(volatile datum * baseAddress, unsigned long nBytes)
 | |
| {
 | |
|     unsigned long offset;
 | |
|     unsigned long nWords = nBytes / sizeof(datum);
 | |
| 
 | |
|     datum pattern;
 | |
|     datum antipattern;
 | |
| 
 | |
| 
 | |
|     /*
 | |
|      * Fill memory with a known pattern.
 | |
|      */
 | |
|     for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
 | |
|     {
 | |
|         baseAddress[offset] = pattern;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /*
 | |
|      * Check each location and invert it for the second pass.
 | |
|      */
 | |
|     for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
 | |
|     {
 | |
|         if (baseAddress[offset] != pattern)
 | |
|         {
 | |
|             return ((datum *) &baseAddress[offset]);
 | |
|         }
 | |
| 
 | |
|         antipattern = ~pattern;
 | |
|         baseAddress[offset] = antipattern;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Check each location for the inverted pattern and zero it.
 | |
|      */
 | |
|     for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++)
 | |
|     {
 | |
|         antipattern = ~pattern;
 | |
|         if (baseAddress[offset] != antipattern)
 | |
|         {
 | |
|             return ((datum *) &baseAddress[offset]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return (NULL);
 | |
| 
 | |
| }   /* memTestDevice() */
 | |
| 
 | |
| 
 | |
| int
 | |
| memTest(void)
 | |
| {
 | |
|     #define BASE_ADDRESS  (volatile datum *) 0x18000000
 | |
|     #define NUM_BYTES     (8 * 1024 * 1024)
 | |
| 
 | |
|     volatile datum* addr = NULL;
 | |
|     if (memTestDataBus(BASE_ADDRESS) != 0)
 | |
|     {
 | |
|         iot_printf("data bus failed....\n");
 | |
|         return (-1);
 | |
|     }
 | |
| 
 | |
|     addr = memTestAddressBus(BASE_ADDRESS, NUM_BYTES);
 | |
| 
 | |
|     if( addr != NULL)
 | |
|     {
 | |
|         iot_printf("address failed:0x%x\n", addr);
 | |
|         return (-1);
 | |
|     }
 | |
| 
 | |
|     addr = memTestDevice(BASE_ADDRESS, NUM_BYTES);
 | |
| 
 | |
|     if( addr != NULL)
 | |
|     {
 | |
|         iot_printf("device failed:0x%x\n", addr);
 | |
|         return (-1);
 | |
|     }
 | |
| 
 | |
|     return (0);
 | |
| }   /* memTest() */
 | |
| 
 | |
| int main(void)
 | |
| {
 | |
|     int test_result = 0;
 | |
| 
 | |
|     dbg_uart_init();
 | |
| 
 | |
|     // disable cache
 | |
|     ahb_cache_disable();
 | |
|     //ddr init;
 | |
|     ddr_cache_init();
 | |
|     // enable ahb cache
 | |
|     ahb_cache_enable();
 | |
|     //ahb_cache_reset();
 | |
|     //enable dmc cache;
 | |
|     ahb_dmc_cache_enable();
 | |
|      //cache space init;
 | |
|     ahb_cache_fill_valid_space();
 | |
| 
 | |
|     test_result = memTest();
 | |
|     if (0 == test_result) {
 | |
|         iot_printf("memory test passed....\n");
 | |
|     } else {
 | |
|         iot_printf("memory test failed....\n");
 | |
|     }
 | |
| 
 | |
|     iot_printf("MEMTEST VERSION(HEX): 11.0.1.1\n");
 | |
|     iot_printf("build date: "__DATE__". time: "__TIME__".\r\n");
 | |
| 
 | |
|     if (0 == test_result) {
 | |
|         iot_printf("restart by software after test passed.\n");
 | |
|         iot_delay_us_cpu_cycle(100000);
 | |
|         system_restart_chip_by_soft();
 | |
|     }
 | |
| 
 | |
|     while(1);
 | |
| 
 | |
|     return 0;
 | |
| }
 |