From b614e16cc07113dc890ecc83649b89da1bced464 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 19 Dec 2014 20:20:52 +0900 Subject: ARM: UniPhier: add DDR PHY training code This training code provides run-time adjustment of DDR PHY parameters for stable DDR operation. Signed-off-by: Masahiro Yamada --- arch/arm/cpu/armv7/uniphier/Makefile | 1 + arch/arm/cpu/armv7/uniphier/ddrphy_training.c | 144 +++++++++++++++++++++ arch/arm/cpu/armv7/uniphier/ph1-ld4/Makefile | 2 +- arch/arm/cpu/armv7/uniphier/ph1-ld4/ddrphy_init.c | 70 ++++++++++ arch/arm/cpu/armv7/uniphier/ph1-ld4/umc_init.c | 13 ++ arch/arm/cpu/armv7/uniphier/ph1-pro4/Makefile | 2 +- arch/arm/cpu/armv7/uniphier/ph1-pro4/ddrphy_init.c | 70 ++++++++++ arch/arm/cpu/armv7/uniphier/ph1-pro4/umc_init.c | 25 ++++ arch/arm/cpu/armv7/uniphier/ph1-sld8/Makefile | 2 +- arch/arm/cpu/armv7/uniphier/ph1-sld8/ddrphy_init.c | 75 +++++++++++ arch/arm/cpu/armv7/uniphier/ph1-sld8/umc_init.c | 13 ++ 11 files changed, 414 insertions(+), 3 deletions(-) create mode 100644 arch/arm/cpu/armv7/uniphier/ddrphy_training.c create mode 100644 arch/arm/cpu/armv7/uniphier/ph1-ld4/ddrphy_init.c create mode 100644 arch/arm/cpu/armv7/uniphier/ph1-pro4/ddrphy_init.c create mode 100644 arch/arm/cpu/armv7/uniphier/ph1-sld8/ddrphy_init.c (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/uniphier/Makefile b/arch/arm/cpu/armv7/uniphier/Makefile index 4a7b8a9d08..1d8469608b 100644 --- a/arch/arm/cpu/armv7/uniphier/Makefile +++ b/arch/arm/cpu/armv7/uniphier/Makefile @@ -10,6 +10,7 @@ obj-y += reset.o obj-y += cache_uniphier.o obj-$(CONFIG_BOARD_POSTCLK_INIT) += board_postclk_init.o obj-y += dram_init.o +obj-$(CONFIG_DRAM_INIT) += ddrphy_training.o obj-$(CONFIG_DISPLAY_CPUINFO) += cpu_info.o obj-$(CONFIG_BOARD_EARLY_INIT_R) += board_early_init_r.o obj-$(CONFIG_BOARD_LATE_INIT) += board_late_init.o diff --git a/arch/arm/cpu/armv7/uniphier/ddrphy_training.c b/arch/arm/cpu/armv7/uniphier/ddrphy_training.c new file mode 100644 index 0000000000..cc8b8ad648 --- /dev/null +++ b/arch/arm/cpu/armv7/uniphier/ddrphy_training.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2011-2014 Panasonic Corporation + * Author: Masahiro Yamada + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +void ddrphy_prepare_training(struct ddrphy __iomem *phy, int rank) +{ + int dx; + u32 __iomem tmp, *p; + + for (dx = 0; dx < NR_DATX8_PER_DDRPHY; dx++) { + p = &phy->dx[dx].gcr; + + tmp = readl(p); + /* Specify the rank that should be write leveled */ + tmp &= ~DXGCR_WLRKEN_MASK; + tmp |= (1 << (DXGCR_WLRKEN_SHIFT + rank)) & DXGCR_WLRKEN_MASK; + writel(tmp, p); + } + + p = &phy->dtcr; + + tmp = readl(p); + /* Specify the rank used during data bit deskew and eye centering */ + tmp &= ~DTCR_DTRANK_MASK; + tmp |= (rank << DTCR_DTRANK_SHIFT) & DTCR_DTRANK_MASK; + /* Use Multi-Purpose Register for DQS gate training */ + tmp |= DTCR_DTMPR; + /* Specify the rank enabled for data-training */ + tmp &= ~DTCR_RNKEN_MASK; + tmp |= (1 << (DTCR_RNKEN_SHIFT + rank)) & DTCR_RNKEN_MASK; + writel(tmp, p); +} + +struct ddrphy_init_sequence { + char *description; + u32 init_flag; + u32 done_flag; + u32 err_flag; +}; + +static struct ddrphy_init_sequence init_sequence[] = { + { + "DRAM Initialization", + PIR_DRAMRST | PIR_DRAMINIT, + PGSR0_DIDONE, + PGSR0_DIERR + }, + { + "Write Leveling", + PIR_WL, + PGSR0_WLDONE, + PGSR0_WLERR + }, + { + "Read DQS Gate Training", + PIR_QSGATE, + PGSR0_QSGDONE, + PGSR0_QSGERR + }, + { + "Write Leveling Adjustment", + PIR_WLADJ, + PGSR0_WLADONE, + PGSR0_WLAERR + }, + { + "Read Bit Deskew", + PIR_RDDSKW, + PGSR0_RDDONE, + PGSR0_RDERR + }, + { + "Write Bit Deskew", + PIR_WRDSKW, + PGSR0_WDDONE, + PGSR0_WDERR + }, + { + "Read Eye Training", + PIR_RDEYE, + PGSR0_REDONE, + PGSR0_REERR + }, + { + "Write Eye Training", + PIR_WREYE, + PGSR0_WEDONE, + PGSR0_WEERR + } +}; + +int ddrphy_training(struct ddrphy __iomem *phy) +{ + int i; + u32 pgsr0; + u32 init_flag = PIR_INIT; + u32 done_flag = PGSR0_IDONE; + int timeout = 50000; /* 50 msec is long enough */ +#ifdef DISPLAY_ELAPSED_TIME + ulong start = get_timer(0); +#endif + + for (i = 0; i < ARRAY_SIZE(init_sequence); i++) { + init_flag |= init_sequence[i].init_flag; + done_flag |= init_sequence[i].done_flag; + } + + writel(init_flag, &phy->pir); + + do { + if (--timeout < 0) { +#ifndef CONFIG_SPL_BUILD + printf("%s: error: timeout during DDR training\n", + __func__); +#endif + return -1; + } + udelay(1); + pgsr0 = readl(&phy->pgsr[0]); + } while ((pgsr0 & done_flag) != done_flag); + + for (i = 0; i < ARRAY_SIZE(init_sequence); i++) { + if (pgsr0 & init_sequence[i].err_flag) { +#ifndef CONFIG_SPL_BUILD + printf("%s: error: %s failed\n", __func__, + init_sequence[i].description); +#endif + return -1; + } + } + +#ifdef DISPLAY_ELAPSED_TIME + printf("%s: info: elapsed time %ld msec\n", get_timer(start)); +#endif + + return 0; +} diff --git a/arch/arm/cpu/armv7/uniphier/ph1-ld4/Makefile b/arch/arm/cpu/armv7/uniphier/ph1-ld4/Makefile index 5d682d3ca3..8794629b2a 100644 --- a/arch/arm/cpu/armv7/uniphier/ph1-ld4/Makefile +++ b/arch/arm/cpu/armv7/uniphier/ph1-ld4/Makefile @@ -8,4 +8,4 @@ obj-y += boot-mode.o obj-$(CONFIG_SOC_INIT) += bcu_init.o sbc_init.o sg_init.o pll_init.o \ clkrst_init.o obj-$(CONFIG_BOARD_POSTCLK_INIT) += pinctrl.o -obj-$(CONFIG_DRAM_INIT) += pll_spectrum.o umc_init.o +obj-$(CONFIG_DRAM_INIT) += pll_spectrum.o umc_init.o ddrphy_init.o diff --git a/arch/arm/cpu/armv7/uniphier/ph1-ld4/ddrphy_init.c b/arch/arm/cpu/armv7/uniphier/ph1-ld4/ddrphy_init.c new file mode 100644 index 0000000000..60fc5ad6ea --- /dev/null +++ b/arch/arm/cpu/armv7/uniphier/ph1-ld4/ddrphy_init.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 Panasonic Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +void ddrphy_init(struct ddrphy __iomem *phy, int freq, int size) +{ + u32 tmp; + + writel(0x0300c473, &phy->pgcr[1]); + if (freq == 1333) { + writel(0x0a806844, &phy->ptr[0]); + writel(0x208e0124, &phy->ptr[1]); + } else { + writel(0x0c807d04, &phy->ptr[0]); + writel(0x2710015E, &phy->ptr[1]); + } + writel(0x00083DEF, &phy->ptr[2]); + if (freq == 1333) { + writel(0x0f051616, &phy->ptr[3]); + writel(0x06ae08d6, &phy->ptr[4]); + } else { + writel(0x12061A80, &phy->ptr[3]); + writel(0x08027100, &phy->ptr[4]); + } + writel(0xF004001A, &phy->dsgcr); + + /* change the value of the on-die pull-up/pull-down registors */ + tmp = readl(&phy->dxccr); + tmp &= ~0x0ee0; + tmp |= DXCCR_DQSNRES_688_OHM | DXCCR_DQSRES_688_OHM; + writel(tmp, &phy->dxccr); + + writel(0x0000040B, &phy->dcr); + if (freq == 1333) { + writel(0x85589955, &phy->dtpr[0]); + if (size == 1) + writel(0x1a8253c0, &phy->dtpr[1]); + else + writel(0x1a8363c0, &phy->dtpr[1]); + writel(0x5002c200, &phy->dtpr[2]); + writel(0x00000b51, &phy->mr0); + } else { + writel(0x999cbb66, &phy->dtpr[0]); + if (size == 1) + writel(0x1a82dbc0, &phy->dtpr[1]); + else + writel(0x1a878400, &phy->dtpr[1]); + writel(0xa00214f8, &phy->dtpr[2]); + writel(0x00000d71, &phy->mr0); + } + writel(0x00000006, &phy->mr1); + if (freq == 1333) + writel(0x00000290, &phy->mr2); + else + writel(0x00000298, &phy->mr2); + + writel(0x00000800, &phy->mr3); + + while (!(readl(&phy->pgsr[0]) & PGSR0_IDONE)) + ; + + writel(0x0300C473, &phy->pgcr[1]); + writel(0x0000005D, &phy->zq[0].cr[1]); +} diff --git a/arch/arm/cpu/armv7/uniphier/ph1-ld4/umc_init.c b/arch/arm/cpu/armv7/uniphier/ph1-ld4/umc_init.c index ebcbaabf65..87889160a7 100644 --- a/arch/arm/cpu/armv7/uniphier/ph1-ld4/umc_init.c +++ b/arch/arm/cpu/armv7/uniphier/ph1-ld4/umc_init.c @@ -7,6 +7,7 @@ #include #include #include +#include static inline void umc_start_ssif(void __iomem *ssif_base) { @@ -125,6 +126,8 @@ static inline int umc_init_sub(int freq, int size_ch0, int size_ch1) void __iomem *ca_base1 = (void __iomem *)UMC_CA_BASE(1); void __iomem *dramcont0 = (void __iomem *)UMC_DRAMCONT_BASE(0); void __iomem *dramcont1 = (void __iomem *)UMC_DRAMCONT_BASE(1); + void __iomem *phy0_0 = (void __iomem *)DDRPHY_BASE(0, 0); + void __iomem *phy1_0 = (void __iomem *)DDRPHY_BASE(1, 0); umc_dram_init_start(dramcont0); umc_dram_init_start(dramcont1); @@ -133,8 +136,18 @@ static inline int umc_init_sub(int freq, int size_ch0, int size_ch1) writel(0x00000101, dramcont0 + UMC_DIOCTLA); + ddrphy_init(phy0_0, freq, size_ch0); + + ddrphy_prepare_training(phy0_0, 0); + ddrphy_training(phy0_0); + writel(0x00000101, dramcont1 + UMC_DIOCTLA); + ddrphy_init(phy1_0, freq, size_ch1); + + ddrphy_prepare_training(phy1_0, 1); + ddrphy_training(phy1_0); + umc_dramcont_init(dramcont0, ca_base0, size_ch0, freq); umc_dramcont_init(dramcont1, ca_base1, size_ch1, freq); diff --git a/arch/arm/cpu/armv7/uniphier/ph1-pro4/Makefile b/arch/arm/cpu/armv7/uniphier/ph1-pro4/Makefile index fd1c432f4f..cee78781f6 100644 --- a/arch/arm/cpu/armv7/uniphier/ph1-pro4/Makefile +++ b/arch/arm/cpu/armv7/uniphier/ph1-pro4/Makefile @@ -7,4 +7,4 @@ obj-$(if $(CONFIG_OF_CONTROL),,y) += platdevice.o obj-y += boot-mode.o obj-$(CONFIG_SOC_INIT) += sbc_init.o sg_init.o pll_init.o clkrst_init.o obj-$(CONFIG_BOARD_POSTCLK_INIT) += pinctrl.o -obj-$(CONFIG_DRAM_INIT) += pll_spectrum.o umc_init.o +obj-$(CONFIG_DRAM_INIT) += pll_spectrum.o umc_init.o ddrphy_init.o diff --git a/arch/arm/cpu/armv7/uniphier/ph1-pro4/ddrphy_init.c b/arch/arm/cpu/armv7/uniphier/ph1-pro4/ddrphy_init.c new file mode 100644 index 0000000000..c5d1f606cf --- /dev/null +++ b/arch/arm/cpu/armv7/uniphier/ph1-pro4/ddrphy_init.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 Panasonic Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +void ddrphy_init(struct ddrphy __iomem *phy, int freq, int size) +{ + u32 tmp; + + writel(0x0300c473, &phy->pgcr[1]); + if (freq == 1333) { + writel(0x0a806844, &phy->ptr[0]); + writel(0x208e0124, &phy->ptr[1]); + } else { + writel(0x0c807d04, &phy->ptr[0]); + writel(0x2710015E, &phy->ptr[1]); + } + writel(0x00083DEF, &phy->ptr[2]); + if (freq == 1333) { + writel(0x0f051616, &phy->ptr[3]); + writel(0x06ae08d6, &phy->ptr[4]); + } else { + writel(0x12061A80, &phy->ptr[3]); + writel(0x08027100, &phy->ptr[4]); + } + writel(0xF004001A, &phy->dsgcr); + + /* change the value of the on-die pull-up/pull-down registors */ + tmp = readl(&phy->dxccr); + tmp &= ~0x0ee0; + tmp |= DXCCR_DQSNRES_688_OHM | DXCCR_DQSRES_688_OHM; + writel(tmp, &phy->dxccr); + + writel(0x0000040B, &phy->dcr); + if (freq == 1333) { + writel(0x85589955, &phy->dtpr[0]); + if (size == 1) + writel(0x1a8363c0, &phy->dtpr[1]); + else + writel(0x1a8363c0, &phy->dtpr[1]); + writel(0x5002c200, &phy->dtpr[2]); + writel(0x00000b51, &phy->mr0); + } else { + writel(0x999cbb66, &phy->dtpr[0]); + if (size == 1) + writel(0x1a878400, &phy->dtpr[1]); + else + writel(0x1a878400, &phy->dtpr[1]); + writel(0xa00214f8, &phy->dtpr[2]); + writel(0x00000d71, &phy->mr0); + } + writel(0x00000006, &phy->mr1); + if (freq == 1333) + writel(0x00000290, &phy->mr2); + else + writel(0x00000298, &phy->mr2); + + writel(0x00000000, &phy->mr3); + + while (!(readl(&phy->pgsr[0]) & PGSR0_IDONE)) + ; + + writel(0x0300C473, &phy->pgcr[1]); + writel(0x0000005D, &phy->zq[0].cr[1]); +} diff --git a/arch/arm/cpu/armv7/uniphier/ph1-pro4/umc_init.c b/arch/arm/cpu/armv7/uniphier/ph1-pro4/umc_init.c index 328b2f4d9a..1973ab04c2 100644 --- a/arch/arm/cpu/armv7/uniphier/ph1-pro4/umc_init.c +++ b/arch/arm/cpu/armv7/uniphier/ph1-pro4/umc_init.c @@ -7,6 +7,7 @@ #include #include #include +#include static inline void umc_start_ssif(void __iomem *ssif_base) { @@ -94,6 +95,10 @@ static inline int umc_init_sub(int freq, int size_ch0, int size_ch1) void __iomem *ca_base1 = (void __iomem *)UMC_CA_BASE(1); void __iomem *dramcont0 = (void __iomem *)UMC_DRAMCONT_BASE(0); void __iomem *dramcont1 = (void __iomem *)UMC_DRAMCONT_BASE(1); + void __iomem *phy0_0 = (void __iomem *)DDRPHY_BASE(0, 0); + void __iomem *phy0_1 = (void __iomem *)DDRPHY_BASE(0, 1); + void __iomem *phy1_0 = (void __iomem *)DDRPHY_BASE(1, 0); + void __iomem *phy1_1 = (void __iomem *)DDRPHY_BASE(1, 1); umc_dram_init_start(dramcont0); umc_dram_init_start(dramcont1); @@ -102,12 +107,32 @@ static inline int umc_init_sub(int freq, int size_ch0, int size_ch1) writel(0x00000101, dramcont0 + UMC_DIOCTLA); + ddrphy_init(phy0_0, freq, size_ch0); + + ddrphy_prepare_training(phy0_0, 0); + ddrphy_training(phy0_0); + writel(0x00000103, dramcont0 + UMC_DIOCTLA); + ddrphy_init(phy0_1, freq, size_ch0); + + ddrphy_prepare_training(phy0_1, 1); + ddrphy_training(phy0_1); + writel(0x00000101, dramcont1 + UMC_DIOCTLA); + ddrphy_init(phy1_0, freq, size_ch1); + + ddrphy_prepare_training(phy1_0, 0); + ddrphy_training(phy1_0); + writel(0x00000103, dramcont1 + UMC_DIOCTLA); + ddrphy_init(phy1_1, freq, size_ch1); + + ddrphy_prepare_training(phy1_1, 1); + ddrphy_training(phy1_1); + umc_dramcont_init(dramcont0, ca_base0, size_ch0, freq); umc_dramcont_init(dramcont1, ca_base1, size_ch1, freq); diff --git a/arch/arm/cpu/armv7/uniphier/ph1-sld8/Makefile b/arch/arm/cpu/armv7/uniphier/ph1-sld8/Makefile index 5d682d3ca3..8794629b2a 100644 --- a/arch/arm/cpu/armv7/uniphier/ph1-sld8/Makefile +++ b/arch/arm/cpu/armv7/uniphier/ph1-sld8/Makefile @@ -8,4 +8,4 @@ obj-y += boot-mode.o obj-$(CONFIG_SOC_INIT) += bcu_init.o sbc_init.o sg_init.o pll_init.o \ clkrst_init.o obj-$(CONFIG_BOARD_POSTCLK_INIT) += pinctrl.o -obj-$(CONFIG_DRAM_INIT) += pll_spectrum.o umc_init.o +obj-$(CONFIG_DRAM_INIT) += pll_spectrum.o umc_init.o ddrphy_init.o diff --git a/arch/arm/cpu/armv7/uniphier/ph1-sld8/ddrphy_init.c b/arch/arm/cpu/armv7/uniphier/ph1-sld8/ddrphy_init.c new file mode 100644 index 0000000000..a5eafef9a8 --- /dev/null +++ b/arch/arm/cpu/armv7/uniphier/ph1-sld8/ddrphy_init.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 Panasonic Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +void ddrphy_init(struct ddrphy __iomem *phy, int freq, int size) +{ + u32 tmp; + + writel(0x0300c473, &phy->pgcr[1]); + if (freq == 1333) { + writel(0x0a806844, &phy->ptr[0]); + writel(0x208e0124, &phy->ptr[1]); + } else { + writel(0x0c807d04, &phy->ptr[0]); + writel(0x2710015E, &phy->ptr[1]); + } + writel(0x00083DEF, &phy->ptr[2]); + if (freq == 1333) { + writel(0x0f051616, &phy->ptr[3]); + writel(0x06ae08d6, &phy->ptr[4]); + } else { + writel(0x12061A80, &phy->ptr[3]); + writel(0x08027100, &phy->ptr[4]); + } + writel(0xF004001A, &phy->dsgcr); + + /* change the value of the on-die pull-up/pull-down registors */ + tmp = readl(&phy->dxccr); + tmp &= ~0x0ee0; + tmp |= DXCCR_DQSNRES_688_OHM | DXCCR_DQSRES_688_OHM; + writel(tmp, &phy->dxccr); + + writel(0x0000040B, &phy->dcr); + if (freq == 1333) { + writel(0x85589955, &phy->dtpr[0]); + if (size == 1) + writel(0x1a8363c0, &phy->dtpr[1]); + else + writel(0x1a8363c0, &phy->dtpr[1]); + writel(0x5002c200, &phy->dtpr[2]); + writel(0x00000b51, &phy->mr0); + } else { + writel(0x999cbb66, &phy->dtpr[0]); + if (size == 1) + writel(0x1a878400, &phy->dtpr[1]); + else + writel(0x1a878400, &phy->dtpr[1]); + writel(0xa00214f8, &phy->dtpr[2]); + writel(0x00000d71, &phy->mr0); + } + writel(0x00000006, &phy->mr1); + if (freq == 1333) + writel(0x00000290, &phy->mr2); + else + writel(0x00000298, &phy->mr2); + +#ifdef CONFIG_DDR_STANDARD + writel(0x00000000, &phy->mr3); +#else + writel(0x00000800, &phy->mr3); +#endif + + while (!(readl(&phy->pgsr[0]) & PGSR0_IDONE)) + ; + + writel(0x0300C473, &phy->pgcr[1]); + writel(0x0000005D, &phy->zq[0].cr[1]); +} diff --git a/arch/arm/cpu/armv7/uniphier/ph1-sld8/umc_init.c b/arch/arm/cpu/armv7/uniphier/ph1-sld8/umc_init.c index a44f999fbf..2e0f9aeaa5 100644 --- a/arch/arm/cpu/armv7/uniphier/ph1-sld8/umc_init.c +++ b/arch/arm/cpu/armv7/uniphier/ph1-sld8/umc_init.c @@ -7,6 +7,7 @@ #include #include #include +#include static inline void umc_start_ssif(void __iomem *ssif_base) { @@ -105,6 +106,8 @@ static inline int umc_init_sub(int freq, int size_ch0, int size_ch1) void __iomem *ca_base1 = (void __iomem *)UMC_CA_BASE(1); void __iomem *dramcont0 = (void __iomem *)UMC_DRAMCONT_BASE(0); void __iomem *dramcont1 = (void __iomem *)UMC_DRAMCONT_BASE(1); + void __iomem *phy0_0 = (void __iomem *)DDRPHY_BASE(0, 0); + void __iomem *phy1_0 = (void __iomem *)DDRPHY_BASE(1, 0); umc_dram_init_start(dramcont0); umc_dram_init_start(dramcont1); @@ -113,8 +116,18 @@ static inline int umc_init_sub(int freq, int size_ch0, int size_ch1) writel(0x00000101, dramcont0 + UMC_DIOCTLA); + ddrphy_init(phy0_0, freq, size_ch0); + + ddrphy_prepare_training(phy0_0, 0); + ddrphy_training(phy0_0); + writel(0x00000101, dramcont1 + UMC_DIOCTLA); + ddrphy_init(phy1_0, freq, size_ch1); + + ddrphy_prepare_training(phy1_0, 1); + ddrphy_training(phy1_0); + umc_dramcont_init(dramcont0, ca_base0, size_ch0, freq); umc_dramcont_init(dramcont1, ca_base1, size_ch1, freq); -- cgit v1.2.1 From c67b2afd6bdabd49d109884797c1f4881fba742e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 19 Dec 2014 20:20:53 +0900 Subject: 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 --- arch/arm/cpu/armv7/uniphier/Kconfig | 7 + arch/arm/cpu/armv7/uniphier/Makefile | 1 + arch/arm/cpu/armv7/uniphier/cmd_ddrphy.c | 229 +++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 arch/arm/cpu/armv7/uniphier/cmd_ddrphy.c (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/uniphier/Kconfig b/arch/arm/cpu/armv7/uniphier/Kconfig index 97602990aa..0556e4b350 100644 --- a/arch/arm/cpu/armv7/uniphier/Kconfig +++ b/arch/arm/cpu/armv7/uniphier/Kconfig @@ -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 diff --git a/arch/arm/cpu/armv7/uniphier/Makefile b/arch/arm/cpu/armv7/uniphier/Makefile index 1d8469608b..05462320b5 100644 --- a/arch/arm/cpu/armv7/uniphier/Makefile +++ b/arch/arm/cpu/armv7/uniphier/Makefile @@ -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 diff --git a/arch/arm/cpu/armv7/uniphier/cmd_ddrphy.c b/arch/arm/cpu/armv7/uniphier/cmd_ddrphy.c new file mode 100644 index 0000000000..431d9010f1 --- /dev/null +++ b/arch/arm/cpu/armv7/uniphier/cmd_ddrphy.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2014 Panasonic Corporation + * Author: Masahiro Yamada + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +/* 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" +); -- cgit v1.2.1 From 7b77c9ab6fa90ada42185bcc64b7d33812fed35d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 19 Dec 2014 20:20:54 +0900 Subject: ARM: UniPhier: display boot swap pin status by pinmon command This information would be useful enough. Signed-off-by: Masahiro Yamada --- arch/arm/cpu/armv7/uniphier/cmd_pinmon.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/uniphier/cmd_pinmon.c b/arch/arm/cpu/armv7/uniphier/cmd_pinmon.c index eef9f39840..3561b40a33 100644 --- a/arch/arm/cpu/armv7/uniphier/cmd_pinmon.c +++ b/arch/arm/cpu/armv7/uniphier/cmd_pinmon.c @@ -7,6 +7,7 @@ #include #include +#include static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -15,6 +16,8 @@ static int do_pinmon(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) mode_sel = get_boot_mode_sel(); + printf("Boot Swap: %s\n\n", boot_is_swapped() ? "ON" : "OFF"); + puts("Boot Mode Pin:\n"); for (table = boot_device_table; strlen(table->info); table++) { -- cgit v1.2.1