diff options
Diffstat (limited to 'common/memtest.c')
-rw-r--r-- | common/memtest.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/common/memtest.c b/common/memtest.c new file mode 100644 index 0000000..e7bdb6b --- /dev/null +++ b/common/memtest.c @@ -0,0 +1,369 @@ +/********************************************************************** + * + * 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 'unsigned int'. + * + * + * 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. + **********************************************************************/ + +#define MEM_TEST_DEBUG 0 + +#include <stdio.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. + * + **********************************************************************/ +unsigned int +memTestDataBus(volatile unsigned int * address) +{ + unsigned int pattern; + unsigned int data; + unsigned int ret = 0; + /* + * Perform a walking 1's test at the given address. + */ + for (pattern = 1; pattern != 0; pattern <<= 1) + { + /* + * Write the test pattern. + */ + *address = pattern; + data = *address; + /* + * Read it back (immediately is okay for this test). + */ + if (data != pattern) + { +#if (MEM_TEST_DEBUG) + //printf(" memTestDataBus - write: 0x%8x, read back: 0x%8x\n", pattern, data); + serial_puts(" memTestDataBus - write: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read back: 0x"); + serial_put_hex(data, 32); + serial_puts("\n"); + ret = 1; +#else + return (pattern); +#endif + } + } + return (ret); +} /* 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. + * + **********************************************************************/ +unsigned int +memTestAddressBus(volatile unsigned int * baseAddress, unsigned int nBytes) +{ + unsigned int addressMask = (nBytes/sizeof(unsigned int) - 1); + unsigned int offset; + unsigned int testOffset; + + unsigned int pattern = (unsigned int) 0xAAAAAAAA; + unsigned int antipattern = (unsigned int) 0x55555555; + + unsigned int data1, data2; + + /* align the mask address */ + unsigned int temp_i=1, temp_j=0; + temp_j = addressMask; + do { + temp_i=(temp_i<<1); + temp_j=(temp_j>>1); + }while((temp_j)); + addressMask=((temp_i)-1); + + unsigned int ret = 0; + + /* + * 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) + { + data1 = baseAddress[offset]; + data2 = baseAddress[offset]; + if (data1 != data2) + { +#if (MEM_TEST_DEBUG) + //printf(" memTestAddressBus - read twice different[offset]: 0x%8x-0x%8x\n", data1, data2); + serial_puts(" memTestAddressBus - read twice different[offset]: 0x"); + serial_put_hex(data1, 32); + serial_puts("-0x"); + serial_put_hex(data2, 32); + serial_puts("\n"); +#endif + ret = 1; + } + if (data1 != pattern) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestAddressBus - write[0x%8x]: 0x%8x, read[0x%8x]: 0x%8x\n", \ + offset, pattern, offset, data1); + */ + serial_puts(" memTestAddressBus - write[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(data1, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[offset]); +#endif + } + } + + 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) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestAddressBus2 - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0]: 0x%8x\n", \ + testOffset, antipattern, baseAddress[0]); + */ + serial_puts(" memTestAddressBus2 - write baseAddress[0x"); + serial_put_hex(testOffset, 32); + serial_puts("]: 0x"); + serial_put_hex(antipattern, 32); + serial_puts(", read baseAddress[0]: 0x"); + serial_put_hex(baseAddress[0], 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[testOffset]); +#endif + } + + for (offset = 1; (offset & addressMask) != 0; offset <<= 1) + { + data1 = baseAddress[offset]; + if ((data1 != pattern) && (offset != testOffset)) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestAddressBus3 - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0x%8x]: 0x%8x\n", \ + testOffset, antipattern, testOffset, data1); + */ + serial_puts(" memTestAddressBus3 - write baseAddress[0x"); + serial_put_hex(testOffset, 32); + serial_puts("]: 0x"); + serial_put_hex(antipattern, 32); + serial_puts(", read baseAddress[0x"); + serial_put_hex(testOffset, 32); + serial_puts("]: 0x"); + serial_put_hex(data1, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[testOffset]); +#endif + } + } + + baseAddress[testOffset] = pattern; + } + return (ret); +} /* 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. + * + **********************************************************************/ +/*#define AML_DEBUG_ROM*/ +#if MEM_TEST_DEVICE +unsigned int +memTestDevice(volatile unsigned int * baseAddress, unsigned int nBytes) +{ + + unsigned int offset; + unsigned int nWords = nBytes / sizeof(unsigned int); + unsigned int ret = 0; + unsigned int data; + unsigned int pattern; + unsigned int antipattern; + serial_puts("\nTotal Size 0x"); + serial_put_hex(nBytes, 32); + serial_puts("\n"); + + /* + * Fill memory with a known pattern. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + baseAddress[offset] = pattern; +#ifdef AML_DEBUG_ROM + if ((offset&0x3ffff) == 0) + { + serial_puts("\r0x"); + serial_put_hex(offset<<2, 32); + } +#endif + + } + serial_puts("\n"); + + /* + * Check each location and invert it for the second pass. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + data = baseAddress[offset]; + if ( data!= pattern) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestDevice - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0x%8x]: 0x%8x\n", \ + offset, pattern, offset, data); + */ + serial_puts(" memTestDevice - write baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(data, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[offset]); +#endif + } + + antipattern = ~pattern; + baseAddress[offset] = antipattern; +#ifdef AML_DEBUG_ROM + if ((offset&0x3ffff) == 0) + { + serial_puts("\r0x"); + serial_put_hex((offset<<2), 32); + } +#endif + + } + serial_puts("\n"); + + /* + * Check each location for the inverted pattern and zero it. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + antipattern = ~pattern; + data = baseAddress[offset]; + if (data != antipattern) + { +#if (MEM_TEST_DEBUG) + /*printf(" memTestDevice2 - write baseAddress[0x%8x]: 0x%8x, read baseAddress[0x%8x]: 0x%8x\n", \ + offset, antipattern, offset, data); + */ + serial_puts(" memTestDevice2 - write baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(pattern, 32); + serial_puts(", read baseAddress[0x"); + serial_put_hex(offset, 32); + serial_puts("]: 0x"); + serial_put_hex(data, 32); + serial_puts("\n"); + ret = 1; +#else + return ((unsigned int)(unsigned long) &baseAddress[offset]); +#endif + } +#ifdef AML_DEBUG_ROM + if ((offset&0x3ffff) == 0) + { + serial_puts("\r0x"); + serial_put_hex((offset<<2), 32); + } +#endif + + } +#undef AML_DEBUG_ROM + serial_puts("\n"); + + return (ret); +} /* memTestDevice() */ +#endif// #if MEM_TEST_DEVICE + |