diff options
Diffstat (limited to 'src/soc/mediatek/mt8173/memory.c')
-rw-r--r-- | src/soc/mediatek/mt8173/memory.c | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/src/soc/mediatek/mt8173/memory.c b/src/soc/mediatek/mt8173/memory.c new file mode 100644 index 0000000000..3db9df869e --- /dev/null +++ b/src/soc/mediatek/mt8173/memory.c @@ -0,0 +1,357 @@ +/* + * 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 <arch/io.h> +#include <assert.h> +#include <console/console.h> +#include <soc/addressmap.h> +#include <soc/dramc_register.h> +#include <soc/dramc_pi_api.h> +#include <soc/emi.h> +#include <soc/pll.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 +}; + +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); + } +} |