mirror of
https://github.com/revyos/th1520-vendor-uboot.git
synced 2026-06-21 09:02:25 +02:00
1196 lines
28 KiB
C
1196 lines
28 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright(C) 2021 Alibaba Communications Inc.
|
|
* Author: David Li <liyong.li@alibaba-inc.com>
|
|
*/
|
|
/*
|
|
* Memory Bits Scan Functions
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <console.h>
|
|
#include <bootretry.h>
|
|
#include <cli.h>
|
|
#include <command.h>
|
|
#include <console.h>
|
|
#include <hash.h>
|
|
#include <mapmem.h>
|
|
#include <watchdog.h>
|
|
#include <asm/io.h>
|
|
#include <linux/compiler.h>
|
|
#include <asm/asm.h>
|
|
#include <asm/csr.h>
|
|
|
|
#define ONE 0x00000001L
|
|
#define rand() get_timer(0)*100000
|
|
#define rand32() ((unsigned int) rand() | ( (unsigned int) rand() << 16))
|
|
#if (ULONG_MAX == 4294967295UL)
|
|
#define rand_ul() rand32()
|
|
#define UL_ONEBITS 0xffffffff
|
|
#define UL_LEN 32
|
|
#define CHECKERBOARD1 0x55555555
|
|
#define CHECKERBOARD2 0xaaaaaaaa
|
|
#define UL_BYTE(x) ((x | x << 8 | x << 16 | x << 24))
|
|
#elif (ULONG_MAX == 18446744073709551615ULL)
|
|
#define rand64() (((ul) rand32()) << 32 | ((ul) rand32()))
|
|
#define rand_ul() rand64()
|
|
#define ul ulong
|
|
#define UL_ONEBITS 0xffffffffffffffffUL
|
|
#define UL_LEN 64
|
|
#define CHECKERBOARD1 0x5555555555555555
|
|
#define CHECKERBOARD2 0xaaaaaaaaaaaaaaaa
|
|
#define UL_BYTE(x) (((ul)x | (ul)x<<8 | (ul)x<<16 | (ul)x<<24 | (ul)x<<32 | (ul)x<<40 | (ul)x<<48 | (ul)x<<56))
|
|
#else
|
|
#error long on this platform is not 32 or 64 bits
|
|
#endif
|
|
|
|
#define DISPLAY_COUNT 1000000
|
|
|
|
#define BYTE_PER_CACHELINE 64
|
|
#define BIT_PER_BYTE 8
|
|
|
|
typedef unsigned long volatile ulv;
|
|
int use_phys = 1;
|
|
off_t physaddrbase = 0;
|
|
|
|
extern unsigned long get_ddr_density(void);
|
|
extern char* get_ddr_type(void);
|
|
extern void lp4_mrw(int addr, int wdata, int dch, int rank);
|
|
extern int lp4_mrr(int addr, int dch, int rank);
|
|
extern int lp4_set_ron(int ron);
|
|
extern void ddr_sysreg_wr(unsigned long int addr,unsigned int wr_data);
|
|
extern void ddr_phy0_reg_wr(unsigned long int addr,unsigned int wr_data);
|
|
extern void ddr_phy1_reg_wr(unsigned long int addr,unsigned int wr_data);
|
|
extern unsigned int ddr_sysreg_rd(unsigned long int addr);
|
|
extern unsigned int ddr_phy0_reg_rd(unsigned long int addr);
|
|
extern unsigned int ddr_phy1_reg_rd(unsigned long int addr);
|
|
#ifdef CONFIG_CMD_MEMTEST
|
|
extern ulong mem_test_alt(vu_long *buf, ulong start_addr, ulong end_addr,
|
|
vu_long *dummy);
|
|
extern ulong mem_test_quick(vu_long *buf, ulong start_addr, ulong end_addr,
|
|
vu_long pattern, int iteration);
|
|
#endif
|
|
extern void flush_dcache_range(unsigned long start, unsigned long end);
|
|
extern void invalidate_dcache_range(unsigned long start, unsigned long end);
|
|
extern void invalid_dcache_range(unsigned long start, unsigned long end);
|
|
|
|
#ifdef CONFIG_CMD_MEMTEST
|
|
int test_stuck_address(ulv *bufa, ulong count);
|
|
int test_random_value(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_xor_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_sub_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_mul_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_div_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_or_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_and_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_seqinc_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_solidbits_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_blockseq_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_checkerboard_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_bitspread_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_bitflip_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_walkbits0_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
int test_walkbits1_comparison(ulv *bufa, ulv *bufb, ulong count);
|
|
|
|
enum test_index {
|
|
IDX_STUCK = 0,
|
|
IDX_RANDOM,
|
|
IDX_XOR,
|
|
IDX_SUB,
|
|
IDX_MUL,
|
|
IDX_DIV,
|
|
IDX_OR,
|
|
IDX_AND,
|
|
IDX_SEQINC,
|
|
IDX_SOLIDBITS,
|
|
IDX_BLOCKSEQ,
|
|
IDX_CHECKBOARD,
|
|
IDX_BITSPREAD,
|
|
IDX_BITFLIP,
|
|
IDX_WALKONE,
|
|
IDX_WALKZERO,
|
|
IDX_MTEST = 20,
|
|
IDX_MTESTALT,
|
|
};
|
|
#endif
|
|
|
|
static inline void _l2cache_ciall(void)
|
|
{
|
|
asm volatile (".long 0x0170000b");
|
|
}
|
|
static inline void _l2cache_iall(void)
|
|
{
|
|
asm volatile (".long 0x0160000b");
|
|
}
|
|
|
|
static int print_heartbeat(ulong cnt)
|
|
{
|
|
if(cnt % DISPLAY_COUNT == 0)
|
|
{
|
|
printf("\r> \r");
|
|
}
|
|
else if(cnt % DISPLAY_COUNT == DISPLAY_COUNT/2)
|
|
{
|
|
printf("\r>>\r");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_CMD_MEMTEST
|
|
int compare_regions(ulv *bufa, ulv *bufb, ulong count) {
|
|
int r = 0;
|
|
ulong i;
|
|
ulong cnt;
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
off_t physaddr;
|
|
|
|
cnt = 0;
|
|
for (i = 0; i < count; i++, p1++, p2++) {
|
|
if (*p1 != *p2) {
|
|
if (use_phys) {
|
|
physaddr = physaddrbase + (i * sizeof(ulong));
|
|
fprintf(stderr,
|
|
"FAILURE: 0x%08lx != 0x%08lx at physical address "
|
|
"0x%08lx.\n",
|
|
(ulong) *p1, (ulong) *p2, physaddr);
|
|
} else {
|
|
fprintf(stderr,
|
|
"FAILURE: 0x%08lx != 0x%08lx at offset 0x%08lx.\n",
|
|
(ulong) *p1, (ulong) *p2, (ulong) (i * sizeof(ulong)));
|
|
}
|
|
r = -1;
|
|
}
|
|
print_heartbeat(cnt++);
|
|
}
|
|
return r;
|
|
}
|
|
static int do_bits_test(int argc, char * const argv[], enum test_index cmd)
|
|
{
|
|
ulong start, end, count, size;
|
|
ulv *bufa, *bufb;
|
|
ulong iteration_limit = 0;
|
|
ulong pattern = 0;
|
|
int ret;
|
|
ulong errs = 0; /* number of errors, or -1 if interrupted */
|
|
int iteration;
|
|
|
|
start = CONFIG_SYS_MEMTEST_START;
|
|
end = CONFIG_SYS_MEMTEST_START + 0x100000;
|
|
|
|
if (argc > 1)
|
|
if (strict_strtoul(argv[1], 16, &start) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (argc > 2)
|
|
if (strict_strtoul(argv[2], 16, &end) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (argc > 3)
|
|
if (strict_strtoul(argv[3], 16, &pattern) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (argc > 4)
|
|
if (strict_strtoul(argv[4], 16, &iteration_limit) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
if ((start < CONFIG_SYS_MEMTEST_START) || (end > CONFIG_SYS_MEMTEST_END)) {
|
|
printf("Refusing to do invalid region test\n");
|
|
//return -1;
|
|
}
|
|
|
|
printf("Testing [0x%9lx ... 0x%9lx]\n", start, end);
|
|
size = end-start+1;
|
|
bufa = map_sysmem(start, size/2);
|
|
bufb = map_sysmem(start+size/2, size/2);
|
|
count = size / 2 / sizeof(ulv);
|
|
for (iteration = 0;
|
|
!iteration_limit || iteration < iteration_limit;
|
|
iteration++) {
|
|
if (ctrlc()) {
|
|
errs = -1UL;
|
|
break;
|
|
}
|
|
|
|
printf("Iteration: %6d\r", iteration + 1);
|
|
debug("\n");
|
|
switch(cmd) {
|
|
case IDX_STUCK:
|
|
printf("begin to stuck test\n");
|
|
errs = test_stuck_address(bufa, count);
|
|
break;
|
|
case IDX_RANDOM:
|
|
printf("begin to random test\n");
|
|
errs = test_random_value(bufa, bufb, count);
|
|
break;
|
|
case IDX_XOR:
|
|
printf("begin to xor test\n");
|
|
errs = test_xor_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_SUB:
|
|
printf("begin to sub test\n");
|
|
errs = test_sub_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_MUL:
|
|
printf("begin to mul test\n");
|
|
errs = test_mul_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_DIV:
|
|
printf("begin to div test\n");
|
|
errs = test_div_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_OR:
|
|
printf("begin to or test\n");
|
|
errs = test_or_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_AND:
|
|
printf("begin to and test\n");
|
|
errs = test_and_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_SEQINC:
|
|
printf("begin to seqinc test\n");
|
|
errs = test_seqinc_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_SOLIDBITS:
|
|
printf("begin to solidbits test\n");
|
|
errs = test_solidbits_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_BLOCKSEQ:
|
|
printf("begin to blockseq test\n");
|
|
errs = test_blockseq_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_WALKZERO:
|
|
printf("begin to walkbits0 test\n");
|
|
errs = test_walkbits0_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_WALKONE:
|
|
printf("begin to walkbits1 test\n");
|
|
errs = test_walkbits1_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_BITSPREAD:
|
|
printf("begin to bitspread test\n");
|
|
errs = test_bitspread_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_BITFLIP:
|
|
printf("begin to bitflip test\n");
|
|
errs = test_bitflip_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_CHECKBOARD:
|
|
printf("begin to checkerboard test\n");
|
|
errs = test_checkerboard_comparison(bufa, bufb, count);
|
|
break;
|
|
case IDX_MTESTALT:
|
|
printf("begin to mtest_alt test\n");
|
|
errs = mem_test_alt(bufa, start, start+size/2, bufb);
|
|
break;
|
|
case IDX_MTEST:
|
|
printf("begin to mtest test\n");
|
|
errs = mem_test_quick(bufa, start, end, pattern, 10);
|
|
break;
|
|
default:
|
|
printf("default: begin to bitspread test\n");
|
|
errs = test_bitspread_comparison(bufa, bufb, count);
|
|
break;
|
|
|
|
}
|
|
|
|
if (errs == -1)
|
|
break;
|
|
}
|
|
|
|
{
|
|
void *vbufa = (void *)bufa;
|
|
void *vbufb = (void *)bufb;
|
|
|
|
unmap_sysmem(vbufa);
|
|
unmap_sysmem(vbufb);
|
|
}
|
|
|
|
if (errs == -1) {
|
|
/* Memory test was aborted - write a newline to finish off */
|
|
putc('\n');
|
|
ret = 1;
|
|
} else {
|
|
printf("Tested %d iteration(s) with %lu errors.\n",
|
|
iteration, errs);
|
|
ret = errs != 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_stuck_address(ulv *bufa, ulong count) {
|
|
ulv *p1 = bufa;
|
|
unsigned int j;
|
|
ulong i;
|
|
off_t physaddr;
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
p1 = (ulv *) bufa;
|
|
for (i = 0; i < count; i++) {
|
|
*p1 = ((j + i) % 2) == 0 ? (ul) p1 : ~((ul) p1);
|
|
*p1++;
|
|
}
|
|
p1 = (ulv *) bufa;
|
|
for (i = 0; i < count; i++, p1++) {
|
|
if (*p1 != (((j + i) % 2) == 0 ? (ul) p1 : ~((ul) p1))) {
|
|
if (use_phys) {
|
|
physaddr = physaddrbase + (i * sizeof(ul));
|
|
fprintf(stderr,
|
|
"FAILURE: possible bad address line at physical "
|
|
"address 0x%08lx.\n",
|
|
physaddr);
|
|
} else {
|
|
fprintf(stderr,
|
|
"FAILURE: possible bad address line at offset "
|
|
"0x%08lx.\n",
|
|
(ul) (i * sizeof(ul)));
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_mem_stuck(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_STUCK);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_random_value(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ = *p2++ = rand_ul();
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_random(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_RANDOM);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_xor_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
ul q = rand_ul();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ ^= q;
|
|
*p2++ ^= q;
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_xor(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_XOR);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_sub_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
ul q = rand_ul();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ -= q;
|
|
*p2++ -= q;
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_sub(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_SUB);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_mul_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
ul q = rand_ul();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ *= q;
|
|
*p2++ *= q;
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_mul(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_MUL);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_div_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
ul q = rand_ul();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (!q) {
|
|
q++;
|
|
}
|
|
*p1++ /= q;
|
|
*p2++ /= q;
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_div(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_DIV);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_or_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
ul q = rand_ul();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ |= q;
|
|
*p2++ |= q;
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_or(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_OR);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_and_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
ul q = rand_ul();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ &= q;
|
|
*p2++ &= q;
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_and(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_AND);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_seqinc_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
ulong i;
|
|
ul q = rand_ul();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ = *p2++ = (i + q);
|
|
}
|
|
return compare_regions(bufa, bufb, count);
|
|
}
|
|
|
|
static int do_mem_seqinc(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_SEQINC);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_blockseq_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
unsigned int j;
|
|
ulong i;
|
|
|
|
for (j = 0; j < 256; j++) {
|
|
p1 = (ulv *) bufa;
|
|
p2 = (ulv *) bufb;
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ = *p2++ = (ul) UL_BYTE(j);
|
|
}
|
|
if (compare_regions(bufa, bufb, count)) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_mem_blockseq(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_BLOCKSEQ);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_walkbits0_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
unsigned int j;
|
|
ulong i;
|
|
ulong cnt;
|
|
for (j = 0; j < UL_LEN * 2; j++) {
|
|
p1 = (ulv *) bufa;
|
|
p2 = (ulv *) bufb;
|
|
cnt = 0;
|
|
for (i = 0; i < count; i++) {
|
|
if (j < UL_LEN) { /* Walk it up. */
|
|
*p1++ = *p2++ = ONE << j;
|
|
} else { /* Walk it back down. */
|
|
*p1++ = *p2++ = ONE << (UL_LEN * 2 - j - 1);
|
|
}
|
|
print_heartbeat(cnt++);
|
|
}
|
|
if (compare_regions(bufa, bufb, count)) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_mem_walkbits0(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_WALKZERO);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int test_walkbits1_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
unsigned int j;
|
|
ulong i;
|
|
ulong cnt;
|
|
for (j = 0; j < UL_LEN * 2; j++) {
|
|
p1 = (ulv *) bufa;
|
|
p2 = (ulv *) bufb;
|
|
cnt = 0;
|
|
for (i = 0; i < count; i++) {
|
|
if (j < UL_LEN) { /* Walk it up. */
|
|
*p1++ = *p2++ = UL_ONEBITS ^ (ONE << j);
|
|
} else { /* Walk it back down. */
|
|
*p1++ = *p2++ = UL_ONEBITS ^ (ONE << (UL_LEN * 2 - j - 1));
|
|
}
|
|
print_heartbeat(cnt++);
|
|
}
|
|
if (compare_regions(bufa, bufb, count)) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
static int do_mem_walkbits1(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_WALKONE);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_bitspread_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
unsigned int j;
|
|
ulong i;
|
|
ulong cnt;
|
|
for (j = 0; j < UL_LEN * 2; j++) {
|
|
p1 = (ulv *) bufa;
|
|
p2 = (ulv *) bufb;
|
|
cnt = 0;
|
|
for (i = 0; i < count; i++) {
|
|
if (j < UL_LEN) { /* Walk it up. */
|
|
*p1++ = *p2++ = (i % 2 == 0)
|
|
? (ONE << j) | (ONE << (j + 2))
|
|
: UL_ONEBITS ^ ((ONE << j)
|
|
| (ONE << (j + 2)));
|
|
} else { /* Walk it back down. */
|
|
*p1++ = *p2++ = (i % 2 == 0)
|
|
? (ONE << (UL_LEN * 2 - 1 - j)) | (ONE << (UL_LEN * 2 + 1 - j))
|
|
: UL_ONEBITS ^ (ONE << (UL_LEN * 2 - 1 - j)
|
|
| (ONE << (UL_LEN * 2 + 1 - j)));
|
|
}
|
|
print_heartbeat(cnt++);
|
|
}
|
|
if (compare_regions(bufa, bufb, count)) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
static int do_mem_bitspread(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_BITSPREAD);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_bitflip_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
unsigned int j, k;
|
|
ulong q;
|
|
ulong i;
|
|
ulong cnt;
|
|
for (k = 0; k < UL_LEN; k++) {
|
|
q = ONE << k;
|
|
for (j = 0; j < 8; j++) {
|
|
q = ~q;
|
|
p1 = (ulv *) bufa;
|
|
p2 = (ulv *) bufb;
|
|
cnt = 0;
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
|
|
print_heartbeat(cnt++);
|
|
}
|
|
if (compare_regions(bufa, bufb, count)) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_mem_bitflip(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_BITFLIP);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_solidbits_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
unsigned int j;
|
|
ulong q;
|
|
ulong i;
|
|
ulong cnt;
|
|
|
|
for (j = 0; j < 64; j++) {
|
|
q = (j % 2) == 0 ? UL_ONEBITS : 0;
|
|
p1 = (ulv *) bufa;
|
|
p2 = (ulv *) bufb;
|
|
cnt=0;
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
|
|
print_heartbeat(cnt++);
|
|
}
|
|
if (compare_regions(bufa, bufb, count)) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_mem_solidbits(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_SOLIDBITS);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int test_checkerboard_comparison(ulv *bufa, ulv *bufb, ulong count) {
|
|
ulv *p1 = bufa;
|
|
ulv *p2 = bufb;
|
|
unsigned int j;
|
|
ulong q;
|
|
ulong cnt;
|
|
ulong i;
|
|
|
|
for (j = 0; j < 64; j++) {
|
|
q = (j % 2) == 0 ? CHECKERBOARD1 : CHECKERBOARD2;
|
|
p1 = (ulv *) bufa;
|
|
p2 = (ulv *) bufb;
|
|
cnt=0;
|
|
for (i = 0; i < count; i++) {
|
|
*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
|
|
print_heartbeat(cnt++);
|
|
}
|
|
if (compare_regions(bufa, bufb, count)) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_mem_checkerboard(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_CHECKBOARD);
|
|
|
|
return ret;
|
|
}
|
|
static int do_mem_stress_test(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
printf("ddr stress test suite\n");
|
|
|
|
_l2cache_ciall();
|
|
ret = do_bits_test(argc, argv, IDX_MTEST);
|
|
ret = do_bits_test(argc, argv, IDX_MTESTALT);
|
|
ret = do_bits_test(argc, argv, IDX_STUCK);
|
|
ret = do_bits_test(argc, argv, IDX_RANDOM);
|
|
ret = do_bits_test(argc, argv, IDX_XOR);
|
|
ret = do_bits_test(argc, argv, IDX_SUB);
|
|
ret = do_bits_test(argc, argv, IDX_MUL);
|
|
ret = do_bits_test(argc, argv, IDX_DIV);
|
|
ret = do_bits_test(argc, argv, IDX_OR);
|
|
ret = do_bits_test(argc, argv, IDX_AND);
|
|
ret = do_bits_test(argc, argv, IDX_SEQINC);
|
|
ret = do_bits_test(argc, argv, IDX_SOLIDBITS);
|
|
ret = do_bits_test(argc, argv, IDX_BLOCKSEQ);
|
|
ret = do_bits_test(argc, argv, IDX_CHECKBOARD);
|
|
ret = do_bits_test(argc, argv, IDX_BITSPREAD);
|
|
ret = do_bits_test(argc, argv, IDX_BITFLIP);
|
|
ret = do_bits_test(argc, argv, IDX_WALKONE);
|
|
ret = do_bits_test(argc, argv, IDX_WALKZERO);
|
|
|
|
return ret;
|
|
}
|
|
#endif // CONFIG_CMD_MEMTEST
|
|
|
|
|
|
/*
|
|
* 0x1 - Select rank 0 only
|
|
* 0x2 - Select rank 1 only
|
|
* 0x5 - Select rank 0 and 1
|
|
*/
|
|
static int get_device_mr(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
ulong dch = 0;
|
|
ulong rank = 1;
|
|
int data = -1;
|
|
|
|
if (argc != 4) {
|
|
printf("should be 3 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[2], 16, &dch) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[3], 16, &rank) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
data = lp4_mrr((int)addr, (int)dch, (int)rank);
|
|
|
|
printf("Get MR register: addr=%x, dch=%d, rank=%d, MR_vaule=0x%x\n",
|
|
(int)addr, (int)dch, (int)rank, data);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* 0x1 - Select rank 0 only
|
|
* 0x2 - Select rank 1 only
|
|
* 0x5 - Select rank 0 and 1
|
|
*/
|
|
static int set_device_mr(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
ulong data = 0;
|
|
ulong dch = 0;
|
|
ulong rank = 1;
|
|
|
|
if (argc != 5) {
|
|
printf("should be 4 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[2], 16, &data) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[3], 16, &dch) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[4], 16, &rank) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
printf("Set MR register: addr=%x, data=%x, dch=%d, rank=%d\n",
|
|
(int)addr, (int)data, (int)dch, (int)rank);
|
|
|
|
lp4_mrw((int)addr, (int)data, (int)dch, (int)rank);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int set_device_ron(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong ron = 0;
|
|
|
|
if (argc != 2) {
|
|
printf("should be 1 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &ron) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
printf("Set ron register: ron=%d\n",
|
|
(int)ron);
|
|
|
|
lp4_set_ron((int)ron);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int do_ddr_sysreg_rd(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
unsigned int data = 0;
|
|
|
|
if (argc != 2) {
|
|
printf("should be 1 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
data = ddr_sysreg_rd(addr);
|
|
|
|
printf("ddr_sysreg_rd: addr=%lx, data=%x\n", addr, data);
|
|
|
|
return ret;
|
|
}
|
|
static int do_ddr_sysreg_wr(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
ulong data = 0;
|
|
|
|
if (argc != 3) {
|
|
printf("should be 2 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[2], 16, &data) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
ddr_sysreg_wr(addr, (unsigned int)data);
|
|
|
|
return ret;
|
|
}
|
|
static int do_ddr_phy0_reg_rd(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
unsigned int data = 0;
|
|
|
|
if (argc != 2) {
|
|
printf("should be 1 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
data = ddr_phy0_reg_rd(addr);
|
|
|
|
printf("ddr_phy_reg_rd: addr=%lx, data=%x\n", addr, data);
|
|
|
|
return ret;
|
|
}
|
|
static int do_ddr_phy0_reg_wr(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
ulong data = 0;
|
|
|
|
if (argc != 3) {
|
|
printf("should be 2 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[2], 16, &data) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
ddr_phy0_reg_wr(addr, (unsigned int)data);
|
|
|
|
return ret;
|
|
}
|
|
static int do_ddr_phy1_reg_rd(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
unsigned int data = 0;
|
|
|
|
if (argc != 2) {
|
|
printf("should be 1 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
data = ddr_phy1_reg_rd(addr);
|
|
|
|
printf("ddr_phy1_reg_rd: addr=%lx, data=%x\n", addr, data);
|
|
|
|
return ret;
|
|
}
|
|
static int do_ddr_phy1_reg_wr(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
int ret = 0;
|
|
ulong addr = 0;
|
|
ulong data = 0;
|
|
|
|
if (argc != 3) {
|
|
printf("should be 2 input parameters!!!");
|
|
return CMD_RET_USAGE;
|
|
}
|
|
if (strict_strtoul(argv[1], 16, &addr) < 0)
|
|
return CMD_RET_USAGE;
|
|
if (strict_strtoul(argv[2], 16, &data) < 0)
|
|
return CMD_RET_USAGE;
|
|
|
|
ddr_phy1_reg_wr(addr, (unsigned int)data);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
Clear&invalid L2cache
|
|
*/
|
|
static int do_l2cache_ciall(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
_l2cache_ciall();
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_CMD_MEMTEST
|
|
U_BOOT_CMD(
|
|
stuck_address, 5, 1, do_mem_stuck,
|
|
"Stuck Address test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
random_value, 5, 1, do_mem_random,
|
|
"Random Value test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
compare_xor, 5, 1, do_mem_xor,
|
|
"Compare XOR test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
compare_sub, 5, 1, do_mem_sub,
|
|
"Compare SUB test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
compare_mul, 5, 1, do_mem_mul,
|
|
"Compare MUL test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
compare_div, 5, 1, do_mem_div,
|
|
"Compare DIV test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
compare_or, 5, 1, do_mem_or,
|
|
"Compare OR test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
compare_and, 5, 1, do_mem_and,
|
|
"Compare AND test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
seqinc, 5, 1, do_mem_seqinc,
|
|
"Sequential Increment test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
solidbits, 5, 1, do_mem_solidbits,
|
|
"Solid bits test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
blockseq, 5, 1, do_mem_blockseq,
|
|
"Block Sequential test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
checkerboard, 5, 1, do_mem_checkerboard,
|
|
"Checker Board test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
bitspread, 5, 1, do_mem_bitspread,
|
|
"Bit Spread test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
bitflip, 5, 1, do_mem_bitflip,
|
|
"Bit Flip test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
walkbits1, 5, 1, do_mem_walkbits1,
|
|
"Walking Ones test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
walkbits0, 5, 1, do_mem_walkbits0,
|
|
"Walking Zeroes test",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
U_BOOT_CMD(
|
|
stress_test, 5, 1, do_mem_stress_test,
|
|
"SolidBits, BitSpread, BitFlip, WalkBits Zero, WalkBits One, CheckerBoard, mtest_alt, mtest",
|
|
"[start end [pattern [iterations]]]"
|
|
);
|
|
#endif // CONFIG_CMD_MEMTEST
|
|
U_BOOT_CMD(
|
|
setmr, 5, 1, set_device_mr,
|
|
"set ddr MR register",
|
|
"addr data dch(phy id) rank"
|
|
);
|
|
U_BOOT_CMD(
|
|
getmr, 4, 1, get_device_mr,
|
|
"get ddr MR register",
|
|
"addr dch(phy id) rank"
|
|
);
|
|
U_BOOT_CMD(
|
|
setron, 2, 1, set_device_ron,
|
|
"set ddr ron register",
|
|
"ron"
|
|
);
|
|
U_BOOT_CMD(
|
|
ddr_sysreg_rd, 2, 1, do_ddr_sysreg_rd,
|
|
"read ddr sys reg",
|
|
"addr"
|
|
);
|
|
U_BOOT_CMD(
|
|
ddr_sysreg_wr, 3, 1, do_ddr_sysreg_wr,
|
|
"write ddr sys reg",
|
|
"addr wdata"
|
|
);
|
|
U_BOOT_CMD(
|
|
ddr_phy0_reg_rd, 2, 1, do_ddr_phy0_reg_rd,
|
|
"read ddr phy0 reg",
|
|
"addr"
|
|
);
|
|
U_BOOT_CMD(
|
|
ddr_phy0_reg_wr, 3, 1, do_ddr_phy0_reg_wr,
|
|
"write ddr phy0 reg",
|
|
"addr wdata"
|
|
);
|
|
U_BOOT_CMD(
|
|
ddr_phy1_reg_rd, 2, 1, do_ddr_phy1_reg_rd,
|
|
"read ddr phy1 reg",
|
|
"addr"
|
|
);
|
|
U_BOOT_CMD(
|
|
ddr_phy1_reg_wr, 3, 1, do_ddr_phy1_reg_wr,
|
|
"write ddr phy1 reg",
|
|
"addr wdata"
|
|
);
|
|
U_BOOT_CMD(
|
|
l2cache_ciall, 3, 1, do_l2cache_ciall,
|
|
"clear & invlid l2 cache",
|
|
""
|
|
);
|
|
|
|
|