bin_header_debug: add memory, 'ir' and 'training' commands
** this is patch #6 in bin_header_debug series of patches
- add 'md', 'mw', 'mm', 'cmp', 'cp', 'ir' and 'training'
commands to prompt mode for debug and testing purposes
Change-Id: I2cf8638d57f94e14a20e98c879da4e9be5eb5462
Signed-off-by: Bassel Saba <basselsa@marvell.com>
Reviewed-on: http://vgitil04.il.marvell.com:8080/19707
Tested-by: Star_Automation <star@marvell.com>
Reviewed-by: Omri Itach <omrii@marvell.com>
diff --git a/tools/marvell/bin_hdr/platform/Makefile b/tools/marvell/bin_hdr/platform/Makefile
index 2a8e885..250e385 100755
--- a/tools/marvell/bin_hdr/platform/Makefile
+++ b/tools/marvell/bin_hdr/platform/Makefile
@@ -80,7 +80,7 @@
CSRC_DRV = $(DRV)/mv_uart.c $(DRV)/mv_twsi.c $(DRV)/mv_time.c
CSRC_UTILS = $(UTILS)/utils.c $(UTILS)/printf.c $(UTILS)/mvHwsSiliconIf.c
CSRC_SYS_ENV = $(SYS_ENV)/mvSysEnvLib.c
-CSRC_BIN_HDR_DEBUG = $(BIN_HDR_DEBUG)/debug.c $(BIN_HDR_DEBUG)/lib_utils.c $(BIN_HDR_DEBUG)/command.c
+CSRC_BIN_HDR_DEBUG = $(BIN_HDR_DEBUG)/debug.c $(BIN_HDR_DEBUG)/lib_utils.c $(BIN_HDR_DEBUG)/command.c $(BIN_HDR_DEBUG)/mem.c
ifeq "$(CONFIG_ALLEYCAT3)" "y"
CSRC_UTILS += $(UTILS)/mv_seq_exec_ext.c
diff --git a/tools/marvell/bin_hdr/platform/utils/debug/command.c b/tools/marvell/bin_hdr/platform/utils/debug/command.c
index 319d230..a253aaf 100644
--- a/tools/marvell/bin_hdr/platform/utils/debug/command.c
+++ b/tools/marvell/bin_hdr/platform/utils/debug/command.c
@@ -69,6 +69,14 @@
#include "printf.h"
int do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_mm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_cmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int ir_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int training_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_mtest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
/* Commands Table
* Every new command is added here, Thus it must be declared in
@@ -78,7 +86,15 @@
* { "hello", 2, hello_world, "prints hello world", ""}
*/
cmd_tbl_t commands[] = {
- { "?", 2, do_help, "prints help message of command", "command-name"}
+ { "?", 2, do_help, "prints help message of command", "command-name"},
+ { "md", 3, do_mem_md, "memory display", "[.b, .w, .l] address [# of objects]"},
+ { "mw", 4, do_mem_mw, "memory write (fill)", "[.b, .w, .l] address value [count]"},
+ { "mm", 2, do_mem_mm, "memory modify (auto-incrementing address)", "[.b, .w, .l] address"},
+ { "cmp", 4, do_mem_cmp, "memory compare", "[.b, .w, .l] addr1 addr2 count"},
+ { "cp", 4, do_mem_cp, "memory copy", "[.b, .w, .l] source target count"},
+ { "ir", 2, ir_cmd, "ir - reading and changing MV internal register values.\n", "address"},
+ { "training", 1, training_cmd, "training - prints the results of the DDR3 Training.\n"},
+ { "mtest", 5, do_mem_mtest, "simple RAM read/write test", "[start [end [pattern [iterations]]]]"}
};
/* local functions definitions */
@@ -109,6 +125,14 @@
return 0;
}
+int do_mem_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_mm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_cmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int ir_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int training_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+int do_mem_mtest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
/*******************************************************************************
* cmd_get_data_size
diff --git a/tools/marvell/bin_hdr/platform/utils/debug/command.h b/tools/marvell/bin_hdr/platform/utils/debug/command.h
index f4d2b90..18f7b9b 100644
--- a/tools/marvell/bin_hdr/platform/utils/debug/command.h
+++ b/tools/marvell/bin_hdr/platform/utils/debug/command.h
@@ -66,6 +66,7 @@
#include "mvUart.h"
#define CONFIG_SYS_MAXARGS 8
+#define CMD_FLAG_REPEAT 0x0001
struct cmd_tbl_s {
char *name; /* Command Name */
diff --git a/tools/marvell/bin_hdr/platform/utils/debug/mem.c b/tools/marvell/bin_hdr/platform/utils/debug/mem.c
new file mode 100644
index 0000000..1a6651d
--- /dev/null
+++ b/tools/marvell/bin_hdr/platform/utils/debug/mem.c
@@ -0,0 +1,703 @@
+#include "command.h"
+#include "printf.h"
+#include "mvUart.h"
+#include "lib_utils.h"
+#include "mv_os.h"
+#include "soc_spec.h"
+#include "ddr3_hws_hw_training_def.h"
+#include "stdint.h"
+
+
+#define DISP_LINE_LEN 16
+#define MAX_LINE_LENGTH_BYTES (64)
+#define DEFAULT_LINE_LENGTH_BYTES (16)
+#define REG_PHY_DATA 0
+#define CONFIG_SYS_MEMTEST_START 0x00400000
+#define CONFIG_SYS_MEMTEST_END 0x007fffff
+
+static unsigned int dp_last_addr, dp_last_size;
+static unsigned int dp_last_length = 0x40;
+static unsigned int mm_last_addr, mm_last_size;
+
+/*******************************************************************************
+* printHex
+*
+* DESCRIPTION:
+* Prints unsigned value in hex with specified width
+*
+* INPUT:
+* x - value to print
+* width - data value width. May be 2, 4, or 8.
+*
+*******************************************************************************/
+static void printHex(MV_U32 x, unsigned int width)
+{
+ switch (width) {
+ case 8:
+ mvPrintf(" %08x", x);
+ break;
+ case 4:
+ mvPrintf(" %04x", x);
+ break;
+ default:
+ mvPrintf(" %02x", x);
+ break;
+ }
+}
+
+/*******************************************************************************
+* print_buffer
+*
+* DESCRIPTION:
+* Print data buffer in hex and ascii form to the terminal.
+* data reads are buffered so that each memory address is only read once.
+* Useful when displaying the contents of volatile registers.
+*
+* INPUT:
+* addr - Starting address to display at start of line
+* data - pointer to data buffer
+* width - data value width. May be 1, 2, or 4.
+* count - number of values to display
+* linelen - Number of values to print per line
+* specify 0 for default length
+*
+*******************************************************************************/
+void print_buffer(unsigned long addr, void *data, unsigned int width, unsigned int count, unsigned int linelen)
+{
+ /* linebuf as a union causes proper alignment */
+ union linebuf {
+ MV_U32 ui[MAX_LINE_LENGTH_BYTES/sizeof(MV_U32) + 1];
+ MV_U16 us[MAX_LINE_LENGTH_BYTES/sizeof(MV_U16) + 1];
+ MV_U8 uc[MAX_LINE_LENGTH_BYTES/sizeof(MV_U8) + 1];
+ } lb;
+ int i;
+
+ if (linelen*width > MAX_LINE_LENGTH_BYTES)
+ linelen = MAX_LINE_LENGTH_BYTES / width;
+ if (linelen < 1)
+ linelen = DEFAULT_LINE_LENGTH_BYTES / width;
+
+ while (count) {
+ mvPrintf("%08lx:", addr);
+
+ /* check for overflow condition */
+ if (count < linelen)
+ linelen = count;
+
+ /* Copy from memory into linebuf and print hex values */
+ for (i = 0; i < linelen; i++) {
+ MV_U32 x;
+ if (width == 4)
+ x = lb.ui[i] = *(volatile MV_U32*)data;
+ else if (width == 2)
+ x = lb.us[i] = *(volatile MV_U16*)data;
+ else
+ x = lb.uc[i] = *(volatile MV_U8*)data;
+ printHex(x, width*2);
+ data += width;
+ }
+
+ /* Print data in ASCII characters */
+ for (i = 0; i < linelen * width; i++) {
+ if (!isprint(lb.uc[i]) || lb.uc[i] >= 0x80)
+ lb.uc[i] = '.';
+ }
+ lb.uc[i] = '\0';
+ mvPrintf(" %s\n", lb.uc);
+
+ /* update references */
+ addr += linelen * width;
+ count -= linelen;
+ }
+}
+
+/*******************************************************************************
+* align_address
+*
+* DESCRIPTION:
+* Unaligned memory access Workaround:
+* if size = long/word, & address not aligned to long/word (respectively)
+* align address to meet requested size
+*
+* INPUT:
+* addr - address in memory to align (1/2/4)
+* size - size in bytes
+*
+* RETURN:
+* the aligned address
+*
+*******************************************************************************/
+static unsigned long align_address(unsigned long addr, int size)
+{
+
+ if ((size > 1) && (addr % size > 0)) {
+ mvPrintf("Error: Requested unaligned memory address (0x%x)\n", (unsigned int)addr);
+ addr &= ~(size - 1);
+ mvPrintf("Using aligned address (0x%x)\n", (unsigned int)addr);
+ }
+ return addr;
+}
+
+/*******************************************************************************
+* do_mem_md
+*
+* DESCRIPTION:
+* The command allows the user to display memory values
+*
+*******************************************************************************/
+int do_mem_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr, length;
+ int size;
+ int rc = 0;
+ /* We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ addr = dp_last_addr;
+ size = dp_last_size;
+ length = dp_last_length;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /* New command specified. Check for a size specification.
+ * Defaults to long if no or incorrect specification.
+ */
+ size = cmd_get_data_size(argv[0], 4);
+ if (size < 0)
+ return 1;
+
+ /* Address is specified since argc > 1
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ /* If another parameter, it is the length to display.
+ * Length is the number of objects, not number of bytes.
+ */
+ if (argc > 2)
+ length = simple_strtoul(argv[2], NULL, 16);
+ }
+
+ addr = align_address(addr, size);
+ /* Print the lines. */
+ print_buffer(addr, (void *)addr, size, length, DISP_LINE_LEN/size);
+ addr += size*length;
+
+
+ dp_last_addr = addr;
+ dp_last_length = length;
+ dp_last_size = size;
+ return rc;
+}
+
+/*******************************************************************************
+* do_mem_mw
+*
+* DESCRIPTION:
+* The command allows the user to write to memory
+*
+*******************************************************************************/
+int do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr, writeval, count;
+ int size;
+
+ if ((argc < 3) || (argc > 4))
+ return CMD_RET_USAGE;
+
+ /* Check for size specification.
+ */
+ size = cmd_get_data_size(argv[0], 4);
+ if (size < 1)
+ return 1;
+
+ /* Address is specified since argc > 1
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ addr = align_address(addr, size);
+
+ /* Get the value to write.
+ */
+ writeval = simple_strtoul(argv[2], NULL, 16);
+
+ /* Count ? */
+ if (argc == 4)
+ count = simple_strtoul(argv[3], NULL, 16);
+ else
+ count = 1;
+
+ while (count-- > 0) {
+ if (size == 4)
+ *((unsigned long *)addr) = (unsigned long)writeval;
+ else if (size == 2)
+ *((unsigned short *)addr) = (unsigned short)writeval;
+ else
+ *((unsigned char *)addr) = (unsigned char)writeval;
+ addr += size;
+ }
+ return 0;
+}
+
+static int mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
+{
+ unsigned long addr, i;
+ int nbytes, size;
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ /* We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ addr = mm_last_addr;
+ size = mm_last_size;
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /* New command specified. Check for a size specification.
+ * Defaults to long if no or incorrect specification.
+ */
+ size = cmd_get_data_size(argv[0], 4);
+ if (size < 0)
+ return 1;
+
+ /* Address is specified since argc > 1
+ */
+ addr = simple_strtoul(argv[1], NULL, 16);
+ }
+
+
+ addr = align_address(addr, size);
+
+ /* Print the address, followed by value. Then accept input for
+ * the next value. A non-converted value exits.
+ */
+ do {
+ mvPrintf("%08lx:", addr);
+ if (size == 4)
+ mvPrintf(" %08x", *((unsigned int *)addr));
+ else if (size == 2)
+ mvPrintf(" %04x", *((unsigned short *)addr));
+ else
+ mvPrintf(" %02x", *((unsigned char *)addr));
+
+ nbytes = readline(" ? ");
+ if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+ /* <CR> pressed as only input, don't modify current
+ * location and move to next. "-" pressed will go back.
+ */
+ if (incrflag)
+ addr += nbytes ? -size : size;
+ nbytes = 1;
+ } else {
+ char *endp;
+ i = simple_strtoul(console_buffer, &endp, 16);
+ nbytes = endp - console_buffer;
+ if (nbytes) {
+ if (size == 4)
+ *((unsigned int *)addr) = i;
+ else if (size == 2)
+ *((unsigned short *)addr) = i;
+ else
+ *((unsigned char *)addr) = i;
+ if (incrflag)
+ addr += size;
+ }
+ }
+ } while (nbytes);
+
+ mm_last_addr = addr;
+ mm_last_size = size;
+ return 0;
+}
+
+/*******************************************************************************
+* do_mem_mm
+*
+* DESCRIPTION:
+* The command allows the user to modify bytes in memory
+*
+*******************************************************************************/
+int do_mem_mm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return mod_mem(cmdtp, 1, flag, argc, argv);
+}
+
+/*******************************************************************************
+* do_mem_cmp
+*
+* DESCRIPTION:
+* The command allows the user to compare bytes in memory
+*
+*******************************************************************************/
+int do_mem_cmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr1, addr2, count, ngood;
+ int size;
+ int rcode = 0;
+ const char *type;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ /* Check for size specification.
+ */
+ size = cmd_get_data_size(argv[0], 4);
+ if (size < 0)
+ return 1;
+
+ type = size == 4 ? "word" : size == 2 ? "halfword" : "byte";
+
+ addr1 = simple_strtoul(argv[1], NULL, 16);
+
+ addr2 = simple_strtoul(argv[2], NULL, 16);
+
+ addr1 = align_address(addr1, size);
+ addr2 = align_address(addr2, size);
+
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ for (ngood = 0; ngood < count; ++ngood) {
+ unsigned long word1, word2;
+ if (size == 4) {
+ word1 = *(unsigned long *)addr1;
+ word2 = *(unsigned long *)addr2;
+ } else if (size == 2) {
+ word1 = *(unsigned short *)addr1;
+ word2 = *(unsigned short *)addr2;
+ } else {
+ word1 = *(unsigned char *)addr1;
+ word2 = *(unsigned char *)addr2;
+ }
+ if (word1 != word2) {
+ mvPrintf("%s at 0x%08lx (%#0*lx) != %s at 0x%08lx (%#0*lx)\n",
+ type, addr1, size, word1,
+ type, addr2, size, word2);
+ rcode = 1;
+ break;
+ }
+
+ addr1 += size;
+ addr2 += size;
+ }
+
+ mvPrintf("Total of %ld %s(s) were the same\n", ngood, type);
+ return rcode;
+}
+
+/*******************************************************************************
+* do_mem_cp
+*
+* DESCRIPTION:
+* The command allows the user to copy bytes from/to memory
+*
+*******************************************************************************/
+int do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long addr, dest, count;
+ int size;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ /* Check for size specification.
+ */
+ size = cmd_get_data_size(argv[0], 4);
+ if (size < 0)
+ return 1;
+
+ addr = simple_strtoul(argv[1], NULL, 16);
+
+ dest = simple_strtoul(argv[2], NULL, 16);
+
+ addr = align_address(addr, size);
+ dest = align_address(dest, size);
+
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if (count == 0) {
+ mvPrintf("Zero length ???\n");
+ return 1;
+ }
+ while (count-- > 0) {
+ if (size == 4)
+ *((unsigned long *)dest) = *((unsigned long *)addr);
+ else if (size == 2)
+ *((unsigned short *)dest) = *((unsigned short *)addr);
+ else
+ *((unsigned char *)dest) = *((unsigned char *)addr);
+ addr += size;
+ dest += size;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+* ir_cmd
+*
+* DESCRIPTION:
+* The command allows the user to view the contents of the MV
+* internal registers and modify them.
+*
+*******************************************************************************/
+int ir_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ MV_U32 regNum = 0x0, regVal, regValTmp, res;
+ MV_8 regValBin[40];
+ MV_8 cmd[40];
+ int i;
+ int j = 0, flagm = 0;
+
+ if (argc == 2)
+ regNum = simple_strtoul(argv[1], NULL, 16);
+ else {
+ mvPrintf("Usage:\n%s\n", cmdtp->usage);
+ return 0;
+ }
+
+ regVal = MV_REG_READ(regNum + INTER_REGS_BASE);
+ regValTmp = regVal;
+ mvPrintf("Internal register 0x%x value : 0x%x\n ", regNum, regVal);
+ mvPrintf("\n 31 24 16 8 0");
+ mvPrintf("\n | | | | |\nOLD: ");
+
+ for (i = 31; i >= 0; i--) {
+ if (regValTmp > 0) {
+ res = regValTmp % 2;
+ regValTmp = (regValTmp - res) / 2;
+ if (res == 0)
+ regValBin[i] = '0';
+ else
+ regValBin[i] = '1';
+ } else
+ regValBin[i] = '0';
+ }
+
+ for (i = 0; i < 32; i++) {
+ mvPrintf("%c", regValBin[i]);
+ if ((((i+1) % 4) == 0) && (i > 1) && (i < 31))
+ mvPrintf("-");
+ }
+
+ readline("\nNEW: ");
+ strcpy(cmd, console_buffer);
+ if ((cmd[0] == '0') && (cmd[1] == 'x')) {
+ regVal = simple_strtoul(cmd, NULL, 16);
+ flagm = 1;
+ } else {
+ for (i = 0; i < 40; i++) {
+ if (cmd[i] == '\0')
+ break;
+ if (i == 4 || i == 9 || i == 14 || i == 19 || i == 24 || i == 29 || i == 34)
+ continue;
+ if (cmd[i] == '1') {
+ regVal = regVal | (0x80000000 >> j);
+ flagm = 1;
+ } else if (cmd[i] == '0') {
+ regVal = regVal & (~(0x80000000 >> j));
+ flagm = 1;
+ }
+ j++;
+ }
+ }
+
+ if (flagm == 1) {
+ MV_REG_WRITE(regNum + INTER_REGS_BASE, regVal);
+ mvPrintf("\nNew value = 0x%x\n\n", MV_REG_READ(regNum +
+ INTER_REGS_BASE));
+ }
+ return 1;
+}
+
+unsigned int trainingReadPhyReg(int uiRegAddr, int uiPup, int type)
+{
+ unsigned int uiReg;
+ unsigned int addrLow = 0x3F & uiRegAddr;
+ unsigned int addrHi = ((0xC0 & uiRegAddr) >> 6);
+
+ uiReg = (1 << 31) + (uiPup << 22) + (type << 26) + (addrHi << 28) + (addrLow << 16);
+ MV_REG_WRITE(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, uiReg & 0x7FFFFFFF);
+ MV_REG_WRITE(REG_PHY_REGISTRY_FILE_ACCESS_ADDR, uiReg);
+
+ do {
+ uiReg = ((MV_REG_READ(REG_PHY_REGISTRY_FILE_ACCESS_ADDR)) & (1 << 31));
+ } while (uiReg); /* Wait for '0' to mark the end of the transaction */
+
+ uiReg = MV_REG_READ(REG_PHY_REGISTRY_FILE_ACCESS_ADDR);
+ uiReg = uiReg & 0xFFFF;
+
+ return uiReg;
+}
+
+/*******************************************************************************
+* training_cmd
+*
+* DESCRIPTION:
+* The command prints the results of the DDR3 Training
+*
+*******************************************************************************/
+int training_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ MV_U32 uiCsEna, uiCs, uiReg, uiPup, uiPhase, uiDelay;
+ MV_U32 uiRdRdyDly, uiRdSmplDly, uiDq, uiCentralTxRes, uiCentralRxRes;
+ MV_U32 uiPupNum;
+
+ uiCsEna = MV_REG_READ(REG_DDR3_RANK_CTRL_ADDR) & 0xF;
+ mvPrintf("DDR3 Training results:\n");
+
+ uiPupNum = 5;
+
+ for (uiCs = 0; uiCs < 4; uiCs++) {
+ if (uiCsEna & (1 << uiCs)) {
+ mvPrintf("CS: %d\n", uiCs);
+ for (uiPup = 0; uiPup < uiPupNum; uiPup++) {
+ uiReg = trainingReadPhyReg(0 + uiCs*4, uiPup, REG_PHY_DATA);
+ uiPhase = (uiReg >> 6) & 0x7;
+ uiDelay = uiReg & 0x1F;
+ mvPrintf("Write Leveling: PUP: %d, Phase: %d, Delay: %d\n", uiPup, uiPhase, uiDelay);
+ }
+
+ for (uiPup = 0; uiPup < uiPupNum; uiPup++) {
+ uiReg = trainingReadPhyReg(2 + uiCs*4, uiPup, REG_PHY_DATA);
+ uiPhase = (uiReg >> 6) & 0x7;
+ uiDelay = uiReg & 0x1F;
+ mvPrintf("Read Leveling: PUP: %d, Phase: %d, Delay: %d\n", uiPup, uiPhase, uiDelay);
+ }
+
+ uiRdRdyDly = ((MV_REG_READ(REG_READ_DATA_READY_DELAYS_ADDR) >> (8*uiCs)) & 0x1F);
+ uiRdSmplDly = ((MV_REG_READ(REG_READ_DATA_SAMPLE_DELAYS_ADDR) >> (8*uiCs)) & 0x1F);
+ mvPrintf("Read Sample Delay:\t%d\n", uiRdSmplDly);
+ mvPrintf("Read Ready Delay:\t%d\n", uiRdRdyDly);
+
+ /* PBS */
+ if (uiCs == 0) {
+ for (uiPup = 0; uiPup < uiPupNum; uiPup++) {
+ for (uiDq = 0; uiDq < 10; uiDq++) {
+ if (uiDq == 9)
+ uiDq++;
+
+ uiReg = trainingReadPhyReg(0x10+uiDq+uiCs*0x12, uiPup, REG_PHY_DATA);
+ uiDelay = uiReg & 0x1F;
+
+ if (uiDq == 0)
+ mvPrintf("PBS TX: PUP: %d: ", uiPup);
+ mvPrintf("%d ", uiDelay);
+ }
+ mvPrintf("\n");
+ }
+ for (uiPup = 0; uiPup < uiPupNum; uiPup++) {
+ for (uiDq = 0; uiDq < 9; uiDq++) {
+ uiReg = trainingReadPhyReg(0x50 + uiDq + uiCs*0x12,
+ uiPup, REG_PHY_DATA);
+ uiDelay = uiReg & 0x1F;
+
+ if (uiDq == 0)
+ mvPrintf("PBS RX: PUP: %d: ", uiPup);
+ mvPrintf("%d ", uiDelay);
+ }
+ mvPrintf("\n");
+ }
+ }
+
+ /*Read Centralization windows sizes for Scratch PHY registers*/
+ for (uiPup = 0; uiPup < uiPupNum; uiPup++) {
+ uiReg = trainingReadPhyReg(0xC0 + uiCs, uiPup, REG_PHY_DATA);
+ uiCentralRxRes = uiReg >> 5;
+ uiCentralTxRes = uiReg & 0x1F;
+ mvPrintf("Central window size for PUP %d is %d(RX) and %d(TX)\n",
+ uiPup, uiCentralRxRes, uiCentralTxRes);
+ }
+ }
+ }
+ return 1;
+}
+
+/*******************************************************************************
+* do_mem_mtest
+*
+* DESCRIPTION:
+* Perform a memory test. A more complete alternative test can be
+* configured using CONFIG_SYS_ALT_MEMTEST.
+*
+*******************************************************************************/
+int do_mem_mtest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ volatile unsigned long *addr, *start, *end;
+ unsigned long val;
+ unsigned long readback;
+ unsigned long errs = 0;
+ int iterations = 1;
+ int iteration_limit;
+ unsigned long incr;
+ unsigned long pattern;
+
+ if (argc > 1)
+ start = (unsigned long *)simple_strtoul(argv[1], NULL, 16);
+ else
+ start = (unsigned long *)CONFIG_SYS_MEMTEST_START;
+
+ if (argc > 2)
+ end = (unsigned long *)simple_strtoul(argv[2], NULL, 16);
+ else
+ end = (unsigned long *)(CONFIG_SYS_MEMTEST_END);
+
+ start = (unsigned long *)align_address((unsigned long)start, 4);
+ end = (unsigned long *)align_address((unsigned long)end, 4);
+
+ if (argc > 3)
+ pattern = (unsigned long)simple_strtoul(argv[3], NULL, 16);
+ else
+ pattern = 0;
+
+ if (argc > 4)
+ iteration_limit = (unsigned long)simple_strtoul(argv[4], NULL, 16);
+ else
+ iteration_limit = 0;
+
+ incr = 1;
+ for (;;) {
+ if (iteration_limit && iterations > iteration_limit) {
+ mvPrintf("Tested %d iteration(s) with %lu errors.\n",
+ iterations-1, errs);
+ return errs != 0;
+ }
+ ++iterations;
+
+ mvPrintf("\rPattern %08lX Writing...", pattern);
+ mvPrintf("%12s", "");
+ mvPrintf("\b\b\b\b\b\b\b\b\b\b");
+
+ for (addr = start, val = pattern; addr < end; addr++) {
+ *addr = val;
+ val += incr;
+ }
+
+ mvPrintf("Reading...");
+
+ for (addr = start, val = pattern; addr < end; addr++) {
+ readback = *addr;
+ if (readback != val) {
+ mvPrintf("\nMem error @");
+ mvPrintf(" 0x%08X: found %08lX, expected %08lX\n",
+ (unsigned int)(uintptr_t)addr, readback, val);
+ errs++;
+ }
+ val += incr;
+ }
+
+ /*
+ * Flip the pattern each time to make lots of zeros and
+ * then, the next time, lots of ones. We decrement
+ * the "negative" patterns and increment the "positive"
+ * patterns to preserve this feature.
+ */
+ if (pattern & 0x80000000)
+ pattern = -pattern; /* complement & increment */
+ else
+ pattern = ~pattern;
+
+ incr = -incr;
+ }
+ return 0; /* not reached */
+}