/* * This file is part of the coreboot project. * * Copyright 2015 MediaTek Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include 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 }; static int complex_mem_test(unsigned int start, unsigned int len) { unsigned char *mem8_base = (unsigned char *)(uintptr_t)start; unsigned short *mem16_base = (unsigned short *)(uintptr_t)start; unsigned int *mem32_base = (unsigned int *)(uintptr_t)start; unsigned int *mem_base = (unsigned int *)(uintptr_t)start; unsigned char pattern8; unsigned short pattern16; unsigned int i, j, size, pattern32; unsigned int value; 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; } else { mem32_base[i] = PATTERNF; } } /* verify the tied bits (tied low) */ for (i = 0; i < size; i++) { if (mem32_base[i] != PATTERNF) { return -2; } else 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; } else { 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; } else { 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; } else { 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; } else { 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; } else { 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; } else { 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; } else { 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 */ i = (unsigned int)(uintptr_t)mem_base; while (i < (unsigned int)(uintptr_t)mem_base + (size << 2)) { *((unsigned char *)(uintptr_t)i) = PATTERNB; i += 1; *((unsigned char *)(uintptr_t)i) = PATTERNA; i += 1; *((unsigned short *)(uintptr_t)i) = PATTERNC; i += 2; *((unsigned int *)(uintptr_t)i) = PATTERNE; i += 4; *((unsigned short *)(uintptr_t)i) = PATTERND; i += 2; *((unsigned char *)(uintptr_t)i) = PATTERN9; i += 1; *((unsigned char *)(uintptr_t)i) = PATTERN8; i += 1; *((unsigned int *)(uintptr_t)i) = PATTERNE; i += 4; *((unsigned char *)(uintptr_t)i) = PATTERNB; i += 1; *((unsigned char *)(uintptr_t)i) = PATTERNA; i += 1; *((unsigned short *)(uintptr_t)i) = PATTERNC; i += 2; *((unsigned int *)(uintptr_t)i) = PATTERNE; i += 4; *((unsigned short *)(uintptr_t)i) = PATTERND; i += 2; *((unsigned char *)(uintptr_t)i) = PATTERN9; i += 1; *((unsigned char *)(uintptr_t)i) = PATTERN8; i += 1; *((unsigned int *)(uintptr_t)i) = PATTERNE; i += 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; } void mt_mem_init(const struct mt8173_sdram_params *sdram_params) { int i = 0; /* init mempll */ mem_pll_init(sdram_params); /* memory calibration */ mt_set_emi(sdram_params); if (IS_ENABLED(CONFIG_MEMORY_TEST)) { /* * do memory test: * set memory scan range 0x2000 * larger test length, longer system boot up time */ i = complex_mem_test(DDR_BASE, 0x2000); printk(BIOS_DEBUG, "[MEM] complex R/W mem test %s : %d\n", (i == 0) ? "pass" : "fail", i); ASSERT(i == 0); } }