From d4eae7f5feecb47401382e92cf7d3e5430b9dd44 Mon Sep 17 00:00:00 2001 From: Tang Yun ping Date: Fri, 28 Dec 2018 15:38:25 +0800 Subject: [PATCH] cmd: memtester: move some common code to ddr_tester_common.c 1. Moving some common code to ddr_tester_common.c to share with ddr tool. 2. io_map.c get dram bandwidth by using get_ddr_bw(). Change-Id: I90641f35c4474846a2357f4959415bfaa6230769 Signed-off-by: Tang Yun ping --- cmd/memtester/Makefile | 1 + cmd/memtester/ddr_tester_common.c | 154 ++++++++++++++++++++++++++ cmd/memtester/ddr_tester_common.h | 20 ++++ cmd/memtester/io_map.c | 54 ++++----- cmd/memtester/io_map.h | 7 +- cmd/memtester/memtester.c | 175 ++++++++++++++---------------- cmd/memtester/memtester.h | 7 +- 7 files changed, 286 insertions(+), 132 deletions(-) create mode 100644 cmd/memtester/ddr_tester_common.c create mode 100644 cmd/memtester/ddr_tester_common.h diff --git a/cmd/memtester/Makefile b/cmd/memtester/Makefile index ad7f391227..6a4347a57a 100644 --- a/cmd/memtester/Makefile +++ b/cmd/memtester/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CMD_MEMTESTER) += tests.o obj-$(CONFIG_CMD_MEMTESTER) += memtester.o obj-$(CONFIG_CMD_MEMTESTER) += io_map.o +obj-$(CONFIG_CMD_MEMTESTER) += ddr_tester_common.o diff --git a/cmd/memtester/ddr_tester_common.c b/cmd/memtester/ddr_tester_common.c new file mode 100644 index 0000000000..93f9f09e99 --- /dev/null +++ b/cmd/memtester/ddr_tester_common.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include "ddr_tester_common.h" + +DECLARE_GLOBAL_DATA_PTR; + +void write_buf_to_ddr(u32 *buf, u32 buf_len, ulong start_adr, ulong length) +{ + ulong *buful = (ulong *)buf; + ulong *p = (ulong *)start_adr; + u32 i, j; + + buf_len = buf_len / sizeof(ulong) - 1; + + for (i = 0, j = 0; i < length / sizeof(p[0]); i++) { + p[i] = buful[j]; + j++; + j &= buf_len; + } +} + +ulong cmp_buf_data(u32 *buf, u32 buf_len, ulong start_adr, ulong length, + u32 prt_en) +{ + ulong *buful = (ulong *)buf; + volatile unsigned long *p = (volatile unsigned long *)start_adr; + u32 i, j; + ulong reread = 0; + ulong wr_val = 0; + ulong val = 0; + ulong err_adr = 0; + + buf_len = buf_len / sizeof(ulong) - 1; + err_adr = 0; + for (i = 0, j = 0; i < length / sizeof(p[0]); i++) { + val = p[i]; + if (val != buful[j]) { + flush_dcache_range((ulong)&p[i], + (ulong)&p[i] + sizeof(u32)); + reread = p[i]; + err_adr = (ulong)&p[i]; + wr_val = buful[j]; + break; + } + j++; + j &= buf_len; + } + if (err_adr && prt_en) + printf("test fail:address:0x%lx,read:0x%lx," + "reread:0x%lx,expect:0x%lx\n", + err_adr, val, reread, wr_val); + + return err_adr; +} + +void print_memory(void *addr, ulong size) +{ + u32 *p = addr; + u32 i; + + for (i = 0; i < size / 4; i += 4) { + printf("0x%08lx: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + (ulong)&p[i], p[i], p[i + 1], p[i + 2], p[i + 3]); + } +} + +/* print available address for ddr testing in uboot */ +void get_print_available_addr(ulong *start_adr, ulong *length, int print_en) +{ + u32 i, max_bank = 0; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + if (gd->bd->bi_dram[i].start) + max_bank = i + 1; + start_adr[i] = 0; + length[i] = 0; + } + + for (i = 0; i < max_bank; i++) { + start_adr[i] = gd->bd->bi_dram[i].start; + length[i] = gd->bd->bi_dram[i].size; + } + + length[max_bank - 1] = (gd->start_addr_sp - RESERVED_SP_SIZE - + start_adr[max_bank - 1]) & ~0xfff; + if (print_en) { + printf("available memory for test:\n"); + printf(" start end length\n"); + for (i = 0; i < max_bank; i++) + if (start_adr[i]) + printf(" 0x%08lx - 0x%08lx 0x%08lx\n", + start_adr[i], start_adr[i] + length[i], + length[i]); + } +} + +/* + * judge if testing address is available + * arg[0]:start addr, arg[1]:length, return test banks number + */ +int judge_test_addr(ulong *arg, ulong *start_adr, ulong *length) +{ + u32 i, max_bank = 0; + u32 available = 0; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) + if (start_adr[i]) + max_bank = i + 1; + + if (!arg[1]) + return max_bank; + + for (i = 0; i < max_bank; i++) + if (arg[0] >= start_adr[i] && + arg[0] + arg[1] <= start_adr[i] + length[i]) + available |= 1; + if (!available) { + printf("Invalid test address\n"); + } else { + start_adr[0] = arg[0]; + length[0] = arg[1]; + for (i = 1; i < max_bank; i++) { + start_adr[i] = 0; + length[i] = 0; + } + } + + return available; +} + +int set_vdd_logic(u32 uv) +{ + struct udevice *dev; + int ret; + + ret = regulator_get_by_platname("vdd_logic", &dev); + if (ret) { + printf("Cannot set regulator name\n"); + return ret; + } + + /* Slowly raise to max CPU voltage to prevent overshoot */ + ret = regulator_set_value(dev, uv); + udelay(100); /* Must wait for voltage to stabilize, 2mV/us */ + if (ret) + printf("set vdd_logic fail\n"); + return ret; +} + diff --git a/cmd/memtester/ddr_tester_common.h b/cmd/memtester/ddr_tester_common.h new file mode 100644 index 0000000000..2ff3fd7e8d --- /dev/null +++ b/cmd/memtester/ddr_tester_common.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright (C) 2019 Rockchip Electronics Co., Ltd. + */ + +/* Function declaration. */ +#ifndef _CMD_MEMTESTER_DDR_TOOL_COMMON_H +#define _CMD_MEMTESTER_DDR_TOOL_COMMON_H + +/* reserved 1MB for stack */ +#define RESERVED_SP_SIZE 0x100000 + +void write_buf_to_ddr(u32 *buf, u32 buf_len, ulong start_adr, ulong length); +ulong cmp_buf_data(u32 *buf, u32 buf_len, ulong start_adr, + ulong length, u32 prt_en); +void print_memory(void *addr, ulong size); +void get_print_available_addr(ulong *start_adr, ulong *length, int print_en); +int judge_test_addr(ulong *arg, ulong *start_adr, ulong *length); +int set_vdd_logic(u32 uv); +#endif /* _CMD_MEMTESTER_DDR_TOOL_COMMON_H */ diff --git a/cmd/memtester/io_map.c b/cmd/memtester/io_map.c index 88b0d3b66a..ed45a0137e 100644 --- a/cmd/memtester/io_map.c +++ b/cmd/memtester/io_map.c @@ -1,25 +1,16 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Very simple but very effective user-space memory tester. - * Originally by Simon Kirby - * Version 2 by Charles Cazabon - * Version 3 not publicly released. - * Version 4 rewrite: - * Copyright (C) 2004-2012 Charles Cazabon - * Licensed under the terms of the GNU General Public License version 2 (only). - * See the file COPYING for details. - * - * This file contains the functions for the actual tests, called from the - * main routine in memtester.c. See other comments in that file. - * + * (C) Copyright 2019 Rockchip Electronics Co., Ltd. */ + #include +#include #include "io_map.h" -#define IO_TYPE_1_1_16 0 -#define IO_TYPE_1_1_32 1 -#define IO_TYPE_1_2 2 -#define IO_TYPE_2 3 +#define IO_TYPE_1_1_16 0 /* up1 1:1 mode 16bit */ +#define IO_TYPE_1_1_32 1 /* up1 1:1 mode 32bit */ +#define IO_TYPE_1_2 2 /* up1 1:2 mode */ +#define IO_TYPE_2 3 /* up2 */ static u32 io_type; @@ -27,7 +18,7 @@ static u32 io_type; int data_cpu_2_io(void *p, u32 len) { uchar *val = p; - uchar buf[16]; + uchar buf[CPU_2_IO_ALIGN_LEN]; u32 i, j; if ((len % sizeof(buf)) || !len) @@ -56,9 +47,6 @@ int data_cpu_2_io(void *p, u32 len) void data_cpu_2_io_init(void) { - u32 osreg = 0; - u32 bw; - #if defined(CONFIG_ROCKCHIP_RK3036) io_type = IO_TYPE_1_1_16; #elif defined(CONFIG_ROCKCHIP_RK3228) || \ @@ -66,12 +54,16 @@ void data_cpu_2_io_init(void) defined(CONFIG_ROCKCHIP_RK3368) || \ defined(CONFIG_ROCKCHIP_RK3366) io_type = IO_TYPE_1_2; -#elif defined(CONFIG_ROCKCHIP_RK3128) - osreg = 0x200081cc; -#elif defined(CONFIG_ROCKCHIP_RK3288) - osreg = 0xff73009c; -#elif defined(CONFIG_ROCKCHIP_RK3188) - osreg = 0x20004048; +#elif defined(CONFIG_ROCKCHIP_RK3128) || \ + defined(CONFIG_ROCKCHIP_RK3288) || \ + defined(CONFIG_ROCKCHIP_RK3288) + u32 bw; + + bw = get_ddr_bw(); + if (bw == 2) + io_type = IO_TYPE_1_1_32; + else + io_type = IO_TYPE_1_1_16; #elif defined(CONFIG_ROCKCHIP_RK3328) || \ defined(CONFIG_ROCKCHIP_PX30) || \ defined(CONFIG_ROCKCHIP_RK1808) @@ -79,13 +71,5 @@ void data_cpu_2_io_init(void) #else io_type = IO_TYPE_2; #endif - - if (osreg) { - bw = (2 >> ((osreg >> 2) & 0x3)); - if (bw == 2) - io_type = IO_TYPE_1_1_32; - else - io_type = IO_TYPE_1_1_16; - } } diff --git a/cmd/memtester/io_map.h b/cmd/memtester/io_map.h index abcb5d0660..3b17440a16 100644 --- a/cmd/memtester/io_map.h +++ b/cmd/memtester/io_map.h @@ -1,12 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ /* - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - * - * SPDX-License-Identifier: GPL-2.0+ + * Copyright (C) 2019 Rockchip Electronics Co., Ltd. */ #ifndef _CMD_MEMTESTER_IO_MAP_H #define _CMD_MEMTESTER_IO_MAP_H +#define CPU_2_IO_ALIGN_LEN (16) /* 16 byte */ + int data_cpu_2_io(void *p, u32 len); void data_cpu_2_io_init(void); diff --git a/cmd/memtester/memtester.c b/cmd/memtester/memtester.c index 9c35acc16a..3c16569eaf 100644 --- a/cmd/memtester/memtester.c +++ b/cmd/memtester/memtester.c @@ -21,16 +21,12 @@ #include "types.h" #include "tests.h" #include "io_map.h" +#include "ddr_tester_common.h" #define EXIT_FAIL_NONSTARTER 0x01 #define EXIT_FAIL_ADDRESSLINES 0x02 #define EXIT_FAIL_OTHERTEST 0x04 -DECLARE_GLOBAL_DATA_PTR; - -/* reserved sp size 1MB */ -#define RESERVED_SP_SIZE 0x100000 - struct test tests[] = { {"Random Value", test_random_value}, {"Compare XOR", test_xor_comparison}, @@ -57,103 +53,44 @@ struct test tests[] = { int use_phys; off_t physaddrbase; -static int do_memtester(cmd_tbl_t *cmdtp, int flag, int argc, - char *const argv[]) +/* + * arg[0]: test start address + * arg[1]: test length, unit: byte + * testenable: enable test case, if 0 enable all case + * loops: test loops, if 0 endless loop + * err_exit: 1: exit test when found fail. + * return 0: success, other: fail + */ +int doing_memtester(ul *arg, ul testenable, ul loops, ul err_exit) { ul loop, i, j; - ul buf_start; - ul start_adr[2], length[2]; - u32v * bufa[2], *bufb[2]; - ul count[2]; - ul bufsize = 0; - ul loops = 0; - ul testenable = 0; + ul start_adr[CONFIG_NR_DRAM_BANKS], length[CONFIG_NR_DRAM_BANKS]; + u32v * bufa[CONFIG_NR_DRAM_BANKS], *bufb[CONFIG_NR_DRAM_BANKS]; + ul count[CONFIG_NR_DRAM_BANKS]; int exit_code = 0; int abort = 0; + int test_banks; - printf("memtester version " __version__ " (%d-bit)\n", UL_LEN); - printf("Copyright (C) 2001-2012 Charles Cazabon.\n"); - printf("Licensed under the GNU General Public License version 2 (only).\n"); - printf("\n"); + get_print_available_addr(start_adr, length, 0); - start_adr[0] = (size_t)gd->bd->bi_dram[0].start; - if (gd->bd->bi_dram[1].start) { - length[0] = (size_t)gd->bd->bi_dram[0].size; - start_adr[1] = (size_t)gd->bd->bi_dram[1].start; - length[1] = gd->start_addr_sp - RESERVED_SP_SIZE - start_adr[1]; - length[1] &= ~0xfff; - } else { - length[0] = gd->start_addr_sp - RESERVED_SP_SIZE - start_adr[0]; - length[0] &= ~0xfff; - start_adr[1] = 0; - length[1] = 0; + test_banks = judge_test_addr(arg, start_adr, length); + + if (!test_banks) { + printf("unavailable test address\n"); + return -1; } - printf("available memory for test:\n"); - printf(" start end length\n"); - printf(" 0x%08lx - 0x%08lx 0x%08lx\n", - start_adr[0], start_adr[0] + length[0], length[0]); - if (start_adr[1]) - printf(" 0x%08lx - 0x%08lx 0x%08lx\n", - start_adr[1], start_adr[1] + length[1], length[1]); - - if (argc < 2) - return CMD_RET_USAGE; - - if (strict_strtoul(argv[1], 0, &buf_start) < 0) - return CMD_RET_USAGE; - - if (argc > 2) - if (strict_strtoul(argv[2], 0, &bufsize) < 0) - return CMD_RET_USAGE; - - if (argc > 3) - if (strict_strtoul(argv[3], 0, &testenable) < 0) - return CMD_RET_USAGE; - - if (argc > 4) - if (strict_strtoul(argv[4], 0, &loops) < 0) - return CMD_RET_USAGE; - - if (!bufsize) { - /* test all memory */ - for (i = 0; i < 2; i++) { - bufa[i] = (u32v *)start_adr[i]; - bufb[i] = (u32v *)(start_adr[i] + length[i] / 2); - count[i] = length[i] / 2 / sizeof(u32); - } - } else { - bufa[0] = (u32v *)buf_start; - bufb[0] = (u32v *)(buf_start + bufsize / 2); - count[0] = bufsize / 2 / sizeof(u32); - bufa[1] = 0; - if (start_adr[1]) { - if (buf_start < start_adr[0] || - (buf_start >= start_adr[0] + length[0] && - buf_start < start_adr[1]) || - ((buf_start + bufsize > - start_adr[0] + length[0]) && - buf_start + bufsize < start_adr[1]) || - (buf_start + bufsize > - start_adr[1] + length[1])) { - printf("unavailable memory space\n"); - return CMD_RET_FAILURE; - } - } else { - if (buf_start < start_adr[0] || - (buf_start + bufsize > - start_adr[0] + length[0])) { - printf("unavailable memory space\n"); - return CMD_RET_FAILURE; - } - } + for (i = 0; i < ARRAY_SIZE(start_adr); i++) { + bufa[i] = (u32v *)start_adr[i]; + bufb[i] = (u32v *)(start_adr[i] + length[i] / 2); + count[i] = length[i] / 2 / sizeof(u32); } data_cpu_2_io_init(); for (loop = 1; ((!loops) || loop <= loops); loop++) { - for (j = 0; j < 2; j++) { - if (!bufa[j]) + for (j = 0; j < test_banks; j++) { + if (!count[j]) continue; printf("testing:0x%lx - 0x%lx\n", (ul)bufa[j], (ul)bufa[j] + count[j] * 2 * sizeof(u32)); @@ -176,10 +113,14 @@ static int do_memtester(cmd_tbl_t *cmdtp, int flag, int argc, if (testenable && (!((1 << i) & testenable))) continue; printf(" %-20s: ", tests[i].name); - if (!tests[i].fp(bufa[j], bufb[j], count[j])) + if (!tests[i].fp(bufa[j], bufb[j], count[j])) { printf("ok\n"); - else + } else { exit_code |= EXIT_FAIL_OTHERTEST; + if (err_exit) { + goto out; + } + } if (ctrlc()) { abort = 1; break; @@ -192,6 +133,8 @@ static int do_memtester(cmd_tbl_t *cmdtp, int flag, int argc, if (abort) break; } + +out: if (exit_code & EXIT_FAIL_NONSTARTER) printf("Fail: EXIT_FAIL_NONSTARTER\n"); if (exit_code & EXIT_FAIL_ADDRESSLINES) @@ -199,13 +142,58 @@ static int do_memtester(cmd_tbl_t *cmdtp, int flag, int argc, if (exit_code & EXIT_FAIL_OTHERTEST) printf("Fail: EXIT_FAIL_OTHERTEST\n"); + if (exit_code) + return -1; + return 0; +} + +static int do_memtester(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + ul start_adr[CONFIG_NR_DRAM_BANKS], length[CONFIG_NR_DRAM_BANKS]; + ul arg[2]; + ul loops = 0; + ul testenable = 0; + ul err_exit = 0; + + printf("memtester version " __version__ " (%d-bit)\n", UL_LEN); + printf("Copyright (C) 2001-2012 Charles Cazabon.\n"); + printf("Licensed under the GNU General Public License version 2 (only).\n"); + printf("\n"); + + get_print_available_addr(start_adr, length, 1); + + if (argc < 2) + return CMD_RET_USAGE; + + if (strict_strtoul(argv[1], 0, &arg[0]) < 0) + return CMD_RET_USAGE; + + if (argc > 2) + if (strict_strtoul(argv[2], 0, &arg[1]) < 0) + return CMD_RET_USAGE; + + if (argc > 3) + if (strict_strtoul(argv[3], 0, &testenable) < 0) + return CMD_RET_USAGE; + + if (argc > 4) + if (strict_strtoul(argv[4], 0, &err_exit) < 0) + return CMD_RET_USAGE; + + if (argc > 5) + if (strict_strtoul(argv[5], 0, &loops) < 0) + return CMD_RET_USAGE; + + doing_memtester(arg, testenable, loops, err_exit); + printf("Done.\n"); return 0; } -U_BOOT_CMD(memtester, 5, 1, do_memtester, +U_BOOT_CMD(memtester, 6, 1, do_memtester, "do memtester", - "[start length [testenable [loop]]]\n" + "[start length [testenable err_exit [loop]]]\n" "start: start address, should be 4k align\n" "length: test length, should be 4k align, if 0 testing full space\n" "testenable[option]: enable pattern by set bit to 1, null or 0" @@ -228,6 +216,7 @@ U_BOOT_CMD(memtester, 5, 1, do_memtester, " bit15: 8-bit Writes\n" " bit16: 16-bit Writes\n" " example: testenable=0x1000,enable Bit Flip only\n" + "err_exit: if 1 stop testing immediately when finding error\n" "loop[option]: testing loop, if 0 or null endless loop\n" "example:\n" " memtester 0x200000 0x1000000: start address: 0x200000 length:" diff --git a/cmd/memtester/memtester.h b/cmd/memtester/memtester.h index d388b2567d..779a1ece41 100644 --- a/cmd/memtester/memtester.h +++ b/cmd/memtester/memtester.h @@ -13,10 +13,15 @@ * See other comments in that file. * */ - +#ifndef _CMD_MEMTESTER_H +#define _CMD_MEMTESTER_H #include /* extern declarations. */ extern int use_phys; extern off_t physaddrbase; + +int doing_memtester(unsigned long *arg, unsigned long testenable, + unsigned long loops, unsigned long err_exit); +#endif /* _CMD_MEMTESTER_H */