ARM: UniPhier: add dump command of DDR PHY parameters

This commit adds a dump command of DDR PHY parameters of UniPhier
SoC family.  It might not be used very often for the regular operation
but it would be useful when something goes wrong with DDR memories.

Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
This commit is contained in:
Masahiro Yamada 2014-12-19 20:20:53 +09:00
parent b614e16cc0
commit c67b2afd6b
3 changed files with 237 additions and 0 deletions

View File

@ -65,6 +65,13 @@ config DRAM_INIT
bool
default SPL_BUILD
config CMD_DDRPHY_DUMP
bool "Enable dump command of DDR PHY parameters"
depends on !SPL_BUILD
help
The command "ddrphy" shows the resulting parameters of DDR PHY
training; it is useful for the evaluation of DDR PHY training.
choice
prompt "DDR3 Frequency select"
depends on DRAM_INIT

View File

@ -16,6 +16,7 @@ obj-$(CONFIG_BOARD_EARLY_INIT_R) += board_early_init_r.o
obj-$(CONFIG_BOARD_LATE_INIT) += board_late_init.o
obj-$(CONFIG_UNIPHIER_SMP) += smp.o
obj-$(CONFIG_CMD_PINMON) += cmd_pinmon.o
obj-$(CONFIG_CMD_DDRPHY_DUMP) += cmd_ddrphy.o
obj-y += board_common.o
obj-$(CONFIG_PFC_MICRO_SUPPORT_CARD) += support_card.o

View File

@ -0,0 +1,229 @@
/*
* Copyright (C) 2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/ddrphy-regs.h>
/* Select either decimal or hexadecimal */
#if 1
#define PRINTF_FORMAT "%2d"
#else
#define PRINTF_FORMAT "%02x"
#endif
/* field separator */
#define FS " "
static u32 read_bdl(struct ddrphy_datx8 __iomem *dx, int index)
{
return (readl(&dx->bdlr[index / 5]) >> (index % 5 * 6)) & 0x3f;
}
static void dump_loop(void (*callback)(struct ddrphy_datx8 __iomem *))
{
int ch, p, dx;
struct ddrphy __iomem *phy;
for (ch = 0; ch < NR_DDRCH; ch++) {
for (p = 0; p < NR_DDRPHY_PER_CH; p++) {
phy = (struct ddrphy __iomem *)DDRPHY_BASE(ch, p);
for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) {
printf("CH%dP%dDX%d:", ch, p, dx);
(*callback)(&phy->dx[dx]);
printf("\n");
}
}
}
}
static void __wbdl_dump(struct ddrphy_datx8 __iomem *dx)
{
int i;
for (i = 0; i < 10; i++)
printf(FS PRINTF_FORMAT, read_bdl(dx, i));
printf(FS "(+" PRINTF_FORMAT ")", readl(&dx->lcdlr[1]) & 0xff);
}
void wbdl_dump(void)
{
printf("\n--- Write Bit Delay Line ---\n");
printf(" DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DM DQS (WDQD)\n");
dump_loop(&__wbdl_dump);
}
static void __rbdl_dump(struct ddrphy_datx8 __iomem *dx)
{
int i;
for (i = 15; i < 24; i++)
printf(FS PRINTF_FORMAT, read_bdl(dx, i));
printf(FS "(+" PRINTF_FORMAT ")", (readl(&dx->lcdlr[1]) >> 8) & 0xff);
}
void rbdl_dump(void)
{
printf("\n--- Read Bit Delay Line ---\n");
printf(" DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7 DM (RDQSD)\n");
dump_loop(&__rbdl_dump);
}
static void __wld_dump(struct ddrphy_datx8 __iomem *dx)
{
int rank;
u32 lcdlr0 = readl(&dx->lcdlr[0]);
u32 gtr = readl(&dx->gtr);
for (rank = 0; rank < 4; rank++) {
u32 wld = (lcdlr0 >> (8 * rank)) & 0xff; /* Delay */
u32 wlsl = (gtr >> (12 + 2 * rank)) & 0x3; /* System Latency */
printf(FS PRINTF_FORMAT "%sT", wld,
wlsl == 0 ? "-1" : wlsl == 1 ? "+0" : "+1");
}
}
void wld_dump(void)
{
printf("\n--- Write Leveling Delay ---\n");
printf(" Rank0 Rank1 Rank2 Rank3\n");
dump_loop(&__wld_dump);
}
static void __dqsgd_dump(struct ddrphy_datx8 __iomem *dx)
{
int rank;
u32 lcdlr2 = readl(&dx->lcdlr[2]);
u32 gtr = readl(&dx->gtr);
for (rank = 0; rank < 4; rank++) {
u32 dqsgd = (lcdlr2 >> (8 * rank)) & 0xff; /* Delay */
u32 dgsl = (gtr >> (3 * rank)) & 0x7; /* System Latency */
printf(FS PRINTF_FORMAT "+%dT", dqsgd, dgsl);
}
}
void dqsgd_dump(void)
{
printf("\n--- DQS Gating Delay ---\n");
printf(" Rank0 Rank1 Rank2 Rank3\n");
dump_loop(&__dqsgd_dump);
}
static void __mdl_dump(struct ddrphy_datx8 __iomem *dx)
{
int i;
u32 mdl = readl(&dx->mdlr);
for (i = 0; i < 3; i++)
printf(FS PRINTF_FORMAT, (mdl >> (8 * i)) & 0xff);
}
void mdl_dump(void)
{
printf("\n--- Master Delay Line ---\n");
printf(" IPRD TPRD MDLD\n");
dump_loop(&__mdl_dump);
}
#define REG_DUMP(x) \
{ u32 __iomem *p = &phy->x; printf("%3d: %-10s: %p : %08x\n", \
p - (u32 *)phy, #x, p, readl(p)); }
void reg_dump(void)
{
int ch, p;
struct ddrphy __iomem *phy;
printf("\n--- DDR PHY registers ---\n");
for (ch = 0; ch < NR_DDRCH; ch++) {
for (p = 0; p < NR_DDRPHY_PER_CH; p++) {
printf("== Ch%d, PHY%d ==\n", ch, p);
printf(" No: Name : Address : Data\n");
phy = (struct ddrphy __iomem *)DDRPHY_BASE(ch, p);
REG_DUMP(ridr);
REG_DUMP(pir);
REG_DUMP(pgcr[0]);
REG_DUMP(pgcr[1]);
REG_DUMP(pgsr[0]);
REG_DUMP(pgsr[1]);
REG_DUMP(pllcr);
REG_DUMP(ptr[0]);
REG_DUMP(ptr[1]);
REG_DUMP(ptr[2]);
REG_DUMP(ptr[3]);
REG_DUMP(ptr[4]);
REG_DUMP(acmdlr);
REG_DUMP(acbdlr);
REG_DUMP(dxccr);
REG_DUMP(dsgcr);
REG_DUMP(dcr);
REG_DUMP(dtpr[0]);
REG_DUMP(dtpr[1]);
REG_DUMP(dtpr[2]);
REG_DUMP(mr0);
REG_DUMP(mr1);
REG_DUMP(mr2);
REG_DUMP(mr3);
REG_DUMP(dx[0].gcr);
REG_DUMP(dx[0].gtr);
REG_DUMP(dx[1].gcr);
REG_DUMP(dx[1].gtr);
}
}
}
static int do_ddr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
char *cmd = argv[1];
if (argc == 1)
cmd = "all";
if (!strcmp(cmd, "wbdl") || !strcmp(cmd, "all"))
wbdl_dump();
if (!strcmp(cmd, "rbdl") || !strcmp(cmd, "all"))
rbdl_dump();
if (!strcmp(cmd, "wld") || !strcmp(cmd, "all"))
wld_dump();
if (!strcmp(cmd, "dqsgd") || !strcmp(cmd, "all"))
dqsgd_dump();
if (!strcmp(cmd, "mdl") || !strcmp(cmd, "all"))
mdl_dump();
if (!strcmp(cmd, "reg") || !strcmp(cmd, "all"))
reg_dump();
return 0;
}
U_BOOT_CMD(
ddr, 2, 1, do_ddr,
"UniPhier DDR PHY parameters dumper",
"- dump all of the followings\n"
"ddr wbdl - dump Write Bit Delay\n"
"ddr rbdl - dump Read Bit Delay\n"
"ddr wld - dump Write Leveling\n"
"ddr dqsgd - dump DQS Gating Delay\n"
"ddr mdl - dump Master Delay Line\n"
"ddr reg - dump registers\n"
);