| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* This file is part of the coreboot project. */ |
| |
| #include <soc/emi.h> |
| |
| enum { |
| /* test patterns */ |
| PATTERN0 = 0x00000000, |
| PATTERN1 = 0x5A5A5A5A, |
| PATTERN2 = 0xA5A5A5A5, |
| PATTERN3 = 0xA5A5A500, |
| PATTERN4 = 0xA500A500, |
| PATTERN5 = 0xA5000000, |
| PATTERN6 = 0xFFFF0000, |
| PATTERN7 = 0x0000FFFF, |
| PATTERN8 = 0x00000012, |
| PATTERN9 = 0x00000034, |
| PATTERNA = 0x00000056, |
| PATTERNB = 0x00000078, |
| PATTERNC = 0x00001234, |
| PATTERND = 0x00005678, |
| PATTERNE = 0x12345678, |
| PATTERNF = 0xFFFFFFFF |
| }; |
| |
| int complex_mem_test(u8 *start, unsigned int len) |
| { |
| unsigned char *mem8_base = (unsigned char *)start; |
| unsigned short *mem16_base = (unsigned short *)start; |
| unsigned int *mem32_base = (unsigned int *)start; |
| unsigned int *mem_base = (unsigned int *)start; |
| unsigned char pattern8; |
| unsigned short pattern16; |
| unsigned int i, j, size, pattern32; |
| unsigned int value; |
| uintptr_t p; |
| |
| size = len >> 2; |
| |
| /* verify the tied bits (tied high) */ |
| for (i = 0; i < size; i++) |
| mem32_base[i] = PATTERN0; |
| |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERN0) |
| return -1; |
| |
| mem32_base[i] = PATTERNF; |
| } |
| |
| /* verify the tied bits (tied low) */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERNF) |
| return -2; |
| mem32_base[i] = PATTERN0; |
| } |
| |
| /* verify pattern 1 (0x00~0xff) */ |
| pattern8 = PATTERN0; |
| for (i = 0; i < len; i++) |
| mem8_base[i] = pattern8++; |
| pattern8 = PATTERN0; |
| for (i = 0; i < len; i++) { |
| if (mem8_base[i] != pattern8++) |
| return -3; |
| } |
| |
| /* verify pattern 2 (0x00~0xff) */ |
| pattern8 = PATTERN0; |
| for (i = j = 0; i < len; i += 2, j++) { |
| if (mem8_base[i] == pattern8) |
| mem16_base[j] = pattern8; |
| if (mem16_base[j] != pattern8) |
| return -4; |
| |
| pattern8 += 2; |
| } |
| |
| /* verify pattern 3 (0x00~0xffff) */ |
| pattern16 = PATTERN0; |
| for (i = 0; i < (len >> 1); i++) |
| mem16_base[i] = pattern16++; |
| pattern16 = PATTERN0; |
| for (i = 0; i < (len >> 1); i++) { |
| if (mem16_base[i] != pattern16++) |
| return -5; |
| } |
| |
| /* verify pattern 4 (0x00~0xffffffff) */ |
| pattern32 = PATTERN0; |
| for (i = 0; i < (len >> 2); i++) |
| mem32_base[i] = pattern32++; |
| pattern32 = PATTERN0; |
| for (i = 0; i < (len >> 2); i++) { |
| if (mem32_base[i] != pattern32++) |
| return -6; |
| } |
| |
| /* pattern 5: filling memory range with 0x12345678 */ |
| for (i = 0; i < size; i++) |
| mem32_base[i] = PATTERNE; |
| |
| /* read check then fill memory with a5a5a5a5 pattern */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERNE) |
| return -7; |
| |
| mem32_base[i] = PATTERN2; |
| } |
| |
| /* read check then fill memory with 00 byte pattern at offset 0h */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERN2) |
| return -8; |
| |
| mem8_base[i * 4] = PATTERN0; |
| } |
| |
| /* read check then fill memory with 00 byte pattern at offset 2h */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERN3) |
| return -9; |
| |
| mem8_base[i * 4 + 2] = PATTERN0; |
| } |
| |
| /* read check then fill memory with 00 byte pattern at offset 1h */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERN4) |
| return -10; |
| |
| mem8_base[i * 4 + 1] = PATTERN0; |
| } |
| |
| /* read check then fill memory with 00 byte pattern at offset 3h */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERN5) |
| return -11; |
| |
| mem8_base[i * 4 + 3] = PATTERN0; |
| } |
| |
| /* read check then fill memory with ffff word pattern at offset 1h */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERN0) |
| return -12; |
| |
| mem16_base[i * 2 + 1] = PATTERN7; |
| } |
| |
| /* read check then fill memory with ffff word pattern at offset 0h */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERN6) |
| return -13; |
| |
| mem16_base[i * 2] = PATTERN7; |
| } |
| |
| /* read check */ |
| for (i = 0; i < size; i++) { |
| if (mem32_base[i] != PATTERNF) |
| return -14; |
| } |
| |
| /* stage 1 => write 0 */ |
| for (i = 0; i < size; i++) |
| mem_base[i] = PATTERN1; |
| |
| /* stage 2 => read 0, write 0xf */ |
| for (i = 0; i < size; i++) { |
| value = mem_base[i]; |
| |
| if (value != PATTERN1) |
| return -15; |
| |
| mem_base[i] = PATTERN2; |
| } |
| |
| /* stage 3 => read 0xf, write 0 */ |
| for (i = 0; i < size; i++) { |
| value = mem_base[i]; |
| if (value != PATTERN2) |
| return -16; |
| |
| mem_base[i] = PATTERN1; |
| } |
| |
| /* stage 4 => read 0, write 0xf */ |
| for (i = 0; i < size; i++) { |
| value = mem_base[i]; |
| if (value != PATTERN1) |
| return -17; |
| |
| mem_base[i] = PATTERN2; |
| } |
| |
| /* stage 5 => read 0xf, write 0 */ |
| for (i = 0; i < size; i++) { |
| value = mem_base[i]; |
| if (value != PATTERN2) |
| return -18; |
| |
| mem_base[i] = PATTERN1; |
| } |
| |
| /* stage 6 => read 0 */ |
| for (i = 0; i < size; i++) { |
| value = mem_base[i]; |
| if (value != PATTERN1) |
| return -19; |
| } |
| |
| /* 1/2/4-byte combination test */ |
| p = (uintptr_t)mem_base; |
| |
| while (p < (uintptr_t)mem_base + (size << 2)) { |
| *((unsigned char *)p) = PATTERNB; |
| p += 1; |
| *((unsigned char *)p) = PATTERNA; |
| p += 1; |
| *((unsigned short *)p) = PATTERNC; |
| p += 2; |
| *((unsigned int *)p) = PATTERNE; |
| p += 4; |
| *((unsigned short *)p) = PATTERND; |
| p += 2; |
| *((unsigned char *)p) = PATTERN9; |
| p += 1; |
| *((unsigned char *)p) = PATTERN8; |
| p += 1; |
| *((unsigned int *)p) = PATTERNE; |
| p += 4; |
| *((unsigned char *)p) = PATTERNB; |
| p += 1; |
| *((unsigned char *)p) = PATTERNA; |
| p += 1; |
| *((unsigned short *)p) = PATTERNC; |
| p += 2; |
| *((unsigned int *)p) = PATTERNE; |
| p += 4; |
| *((unsigned short *)p) = PATTERND; |
| p += 2; |
| *((unsigned char *)p) = PATTERN9; |
| p += 1; |
| *((unsigned char *)p) = PATTERN8; |
| p += 1; |
| *((unsigned int *)p) = PATTERNE; |
| p += 4; |
| } |
| |
| for (i = 0; i < size; i++) { |
| value = mem_base[i]; |
| if (value != PATTERNE) |
| return -20; |
| } |
| |
| /* verify pattern 1 (0x00~0xff) */ |
| pattern8 = PATTERN0; |
| mem8_base[0] = pattern8; |
| for (i = 0; i < size * 4; i++) { |
| unsigned char waddr8, raddr8; |
| |
| waddr8 = i + 1; |
| raddr8 = i; |
| if (i < size * 4 - 1) |
| mem8_base[waddr8] = pattern8 + 1; |
| if (mem8_base[raddr8] != pattern8) |
| return -21; |
| |
| pattern8++; |
| } |
| |
| /* verify pattern 2 (0x00~0xffff) */ |
| pattern16 = PATTERN0; |
| mem16_base[0] = pattern16; |
| for (i = 0; i < size * 2; i++) { |
| if (i < size * 2 - 1) |
| mem16_base[i + 1] = pattern16 + 1; |
| if (mem16_base[i] != pattern16) |
| return -22; |
| |
| pattern16++; |
| } |
| |
| /* verify pattern 3 (0x00~0xffffffff) */ |
| pattern32 = PATTERN0; |
| mem32_base[0] = pattern32; |
| for (i = 0; i < size; i++) { |
| if (i < size - 1) |
| mem32_base[i + 1] = pattern32 + 1; |
| if (mem32_base[i] != pattern32) |
| return -23; |
| |
| pattern32++; |
| } |
| |
| return 0; |
| } |