aboutsummaryrefslogtreecommitdiff
path: root/src/soc/mediatek/mt8173/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/mediatek/mt8173/memory.c')
-rw-r--r--src/soc/mediatek/mt8173/memory.c357
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);
+ }
+}