/********************************************************************** * * 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; }