381 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			381 lines
		
	
	
		
			10 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 "chip_reg_base.h"
 | 
						|
#include "ahb.h"
 | 
						|
#include "smc.h"
 | 
						|
#include "sram.h"
 | 
						|
#include "clk.h"
 | 
						|
#include "system.h"
 | 
						|
 | 
						|
#define PSRAM_BASE_ADDRESS  (volatile datum *) ICACHE0_SMC_RAM_BASEADDR
 | 
						|
 | 
						|
#define RAM0_BASE_ADDRESS   (volatile datum *) (0x10000000);
 | 
						|
#define RAM0_NUM_BYTES      (0x10000800 - 0x10000000)
 | 
						|
 | 
						|
#define RAM1_BASE_ADDRESS   (volatile datum *) (0x1000c800);
 | 
						|
#define RAM1_NUM_BYTES      (0x10070000 - 0x1000c800)
 | 
						|
 | 
						|
typedef enum {
 | 
						|
    sizeType_0MB    = 0x00,
 | 
						|
    sizeType_1MB    = 0x01,
 | 
						|
    sizeType_2MB    = 0x02,
 | 
						|
    sizeType_4MB    = 0x04,
 | 
						|
    sizeType_8MB    = 0x08,
 | 
						|
    sizeType_max    = 0xFF
 | 
						|
} sizeType;
 | 
						|
 | 
						|
/**********************************************************************
 | 
						|
 *
 | 
						|
 * 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(datum *base_addr, uint32_t num_bytes)
 | 
						|
{
 | 
						|
    volatile datum* addr = NULL;
 | 
						|
    if (memTestDataBus(base_addr) != 0)
 | 
						|
    {
 | 
						|
        iot_printf("data bus failed....\n");
 | 
						|
        return (-1);
 | 
						|
    }
 | 
						|
    addr = memTestAddressBus(base_addr, num_bytes);
 | 
						|
    if( addr != NULL)
 | 
						|
    {
 | 
						|
        iot_printf("address failed:0x%x\n", addr);
 | 
						|
        return (-2);
 | 
						|
    }
 | 
						|
    addr = memTestDevice(base_addr, num_bytes);
 | 
						|
    if( addr != NULL)
 | 
						|
    {
 | 
						|
        iot_printf("device failed:0x%x\n", addr);
 | 
						|
        return (-3);
 | 
						|
    }
 | 
						|
 | 
						|
    return (0);
 | 
						|
}   /* memTest() */
 | 
						|
 | 
						|
 | 
						|
uint8_t memTestGetPsramSize(void)
 | 
						|
{
 | 
						|
    uint8_t i;
 | 
						|
    uint32_t addr_test, data_test, data;
 | 
						|
 | 
						|
    cache_clear(0);
 | 
						|
    *(volatile uint32_t *)(ICACHE0_SMC_RAM_BASEADDR) = 0x0;
 | 
						|
    cache_flush(0, 0x00, 32);
 | 
						|
 | 
						|
    for (i = 0; i < sizeType_max; i++) {
 | 
						|
        addr_test = 0x100000 * i;
 | 
						|
        uint8_t temp = i ^ 0x55;
 | 
						|
        data_test = (temp << 24) | (temp << 16) | (temp << 8) | temp;
 | 
						|
        *(volatile uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test) = data_test;
 | 
						|
        cache_flush(0, addr_test, 32);
 | 
						|
 | 
						|
        cache_clear(0);
 | 
						|
        data = *(volatile uint32_t *)(ICACHE0_SMC_RAM_BASEADDR);
 | 
						|
        if (addr_test == 0x00) {
 | 
						|
            if (data != data_test) {
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            if (data == data_test) {
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (i == sizeType_max) {
 | 
						|
        return sizeType_8MB;
 | 
						|
    }
 | 
						|
 | 
						|
    return i;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int main(void)
 | 
						|
{
 | 
						|
    uint8_t psram_size = 0;
 | 
						|
    volatile datum *base_addr;
 | 
						|
    uint32_t num_bytes;
 | 
						|
    int ret;
 | 
						|
    int test_result = 0;
 | 
						|
 | 
						|
    clk_core_freq_set(CPU_FREQ_150M);
 | 
						|
    dbg_uart_init();
 | 
						|
 | 
						|
    ahb_cache_disable();
 | 
						|
    ahb_set_cache_buffer_mode();
 | 
						|
    ahb_cache_enable();
 | 
						|
    ahb_cache_fill_valid_space();
 | 
						|
 | 
						|
    ahb_emc_disable();
 | 
						|
    ahb_emc_enable();
 | 
						|
    ahb_emc_reset();
 | 
						|
 | 
						|
    sram_qspi_init();
 | 
						|
    sram_qspi_enter();
 | 
						|
    hal_smc_qspi_quad_cfg(0);
 | 
						|
 | 
						|
    base_addr = RAM0_BASE_ADDRESS;
 | 
						|
    num_bytes = RAM0_NUM_BYTES;
 | 
						|
    if (0 != (ret = memTest((datum*)base_addr, num_bytes))) {
 | 
						|
        test_result |= (1 << 0);
 | 
						|
        iot_printf("ram0 test failed(%d).\n", ret);
 | 
						|
    }
 | 
						|
 | 
						|
    base_addr = RAM1_BASE_ADDRESS;
 | 
						|
    num_bytes = RAM1_NUM_BYTES;
 | 
						|
    if (0 != (ret = memTest((datum*)base_addr, num_bytes))) {
 | 
						|
        test_result |= (1 << 1);
 | 
						|
        iot_printf("ram1 test failed(%d).\n", ret);
 | 
						|
    }
 | 
						|
 | 
						|
    psram_size = memTestGetPsramSize();
 | 
						|
    iot_printf("psram size = %dMB\r\n", psram_size);
 | 
						|
    if (psram_size > 0) {
 | 
						|
        base_addr = PSRAM_BASE_ADDRESS;
 | 
						|
        num_bytes = psram_size * 1024 * 1024;
 | 
						|
        if (0 != (ret = memTest((datum*)base_addr, num_bytes))) {
 | 
						|
            test_result |= (1 << 2);
 | 
						|
            iot_printf("psram test failed(%d).\n", ret);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (test_result) {
 | 
						|
        iot_printf("memory test failed....\n");
 | 
						|
        iot_printf("failed code = 0x%08x\n", test_result);
 | 
						|
    } else {
 | 
						|
        iot_printf("memory test passed....\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;
 | 
						|
}
 |