]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-uniphier
authorTom Rini <trini@ti.com>
Tue, 30 Dec 2014 14:11:56 +0000 (09:11 -0500)
committerTom Rini <trini@ti.com>
Tue, 30 Dec 2014 14:11:56 +0000 (09:11 -0500)
15 files changed:
arch/arm/cpu/armv7/uniphier/Kconfig
arch/arm/cpu/armv7/uniphier/Makefile
arch/arm/cpu/armv7/uniphier/cmd_ddrphy.c [new file with mode: 0644]
arch/arm/cpu/armv7/uniphier/cmd_pinmon.c
arch/arm/cpu/armv7/uniphier/ddrphy_training.c [new file with mode: 0644]
arch/arm/cpu/armv7/uniphier/ph1-ld4/Makefile
arch/arm/cpu/armv7/uniphier/ph1-ld4/ddrphy_init.c [new file with mode: 0644]
arch/arm/cpu/armv7/uniphier/ph1-ld4/umc_init.c
arch/arm/cpu/armv7/uniphier/ph1-pro4/Makefile
arch/arm/cpu/armv7/uniphier/ph1-pro4/ddrphy_init.c [new file with mode: 0644]
arch/arm/cpu/armv7/uniphier/ph1-pro4/umc_init.c
arch/arm/cpu/armv7/uniphier/ph1-sld8/Makefile
arch/arm/cpu/armv7/uniphier/ph1-sld8/ddrphy_init.c [new file with mode: 0644]
arch/arm/cpu/armv7/uniphier/ph1-sld8/umc_init.c
arch/arm/include/asm/arch-uniphier/ddrphy-regs.h [new file with mode: 0644]

index 97602990aa8b693bb29fd7ff459ccccc76177e63..0556e4b3509e6b1e8b50d69bb98add96c1fef4f0 100644 (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
index 4a7b8a9d0815a7fd5d87cbfdc69f1238f6889f64..05462320b58c749125f27945639df9e10ad52808 100644 (file)
@@ -10,11 +10,13 @@ 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
 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 (file)
index 0000000..431d901
--- /dev/null
@@ -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"
+);
index eef9f3984079db9a4b4abf7f9433d71d37b78166..3561b40a33196deed9568fcf5fd57ddc1675c07b 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <common.h>
 #include <asm/arch/boot-device.h>
+#include <asm/arch/sbc-regs.h>
 
 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++) {
diff --git a/arch/arm/cpu/armv7/uniphier/ddrphy_training.c b/arch/arm/cpu/armv7/uniphier/ddrphy_training.c
new file mode 100644 (file)
index 0000000..cc8b8ad
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2011-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>
+
+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;
+}
index 5d682d3ca30d69a8b9c06b4f5306910a9c112685..8794629b2ab135938f7931482655a28e07fb9a52 100644 (file)
@@ -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 (file)
index 0000000..60fc5ad
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/ddrphy-regs.h>
+
+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]);
+}
index ebcbaabf65a6df050efb9d618a11a635b19ea15e..87889160a7058c39cdd8c32cea9ec8b82eddbe03 100644 (file)
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <asm/io.h>
 #include <asm/arch/umc-regs.h>
+#include <asm/arch/ddrphy-regs.h>
 
 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);
 
index fd1c432f4f45db7e18cb0519adea6c972ec4c378..cee78781f6326ff8bcbfc1327e2518c6fffca30d 100644 (file)
@@ -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 (file)
index 0000000..c5d1f60
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/ddrphy-regs.h>
+
+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]);
+}
index 328b2f4d9ab1dd35780f5358c5360be3bb3ba003..1973ab04c25e122dc96a826a4b946a60f1bd02ba 100644 (file)
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <asm/io.h>
 #include <asm/arch/umc-regs.h>
+#include <asm/arch/ddrphy-regs.h>
 
 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);
 
index 5d682d3ca30d69a8b9c06b4f5306910a9c112685..8794629b2ab135938f7931482655a28e07fb9a52 100644 (file)
@@ -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 (file)
index 0000000..a5eafef
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <config.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/ddrphy-regs.h>
+
+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]);
+}
index a44f999fbf67c38137149042f6afddb889063c74..2e0f9aeaa5e6300baffdc4ee75252adaf9c1777c 100644 (file)
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <asm/io.h>
 #include <asm/arch/umc-regs.h>
+#include <asm/arch/ddrphy-regs.h>
 
 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);
 
diff --git a/arch/arm/include/asm/arch-uniphier/ddrphy-regs.h b/arch/arm/include/asm/arch-uniphier/ddrphy-regs.h
new file mode 100644 (file)
index 0000000..484559c
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * UniPhier DDR PHY registers
+ *
+ * Copyright (C) 2014 Panasonic Corporation
+ *   Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef ARCH_DDRPHY_REGS_H
+#define ARCH_DDRPHY_REGS_H
+
+#include <linux/compiler.h>
+
+#ifndef __ASSEMBLY__
+
+struct ddrphy {
+       u32 ridr;               /* Revision Identification Register */
+       u32 pir;                /* PHY Initialixation Register */
+       u32 pgcr[2];            /* PHY General Configuration Register */
+       u32 pgsr[2];            /* PHY General Status Register */
+       u32 pllcr;              /* PLL Control Register */
+       u32 ptr[5];             /* PHY Timing Register */
+       u32 acmdlr;             /* AC Master Delay Line Register */
+       u32 acbdlr;             /* AC Bit Delay Line Register */
+       u32 aciocr;             /* AC I/O Configuration Register */
+       u32 dxccr;              /* DATX8 Common Configuration Register */
+       u32 dsgcr;              /* DDR System General Configuration Register */
+       u32 dcr;                /* DRAM Configuration Register */
+       u32 dtpr[3];            /* DRAM Timing Parameters Register */
+       u32 mr0;                /* Mode Register 0 */
+       u32 mr1;                /* Mode Register 1 */
+       u32 mr2;                /* Mode Register 2 */
+       u32 mr3;                /* Mode Register 3 */
+       u32 odtcr;              /* ODT Configuration Register */
+       u32 dtcr;               /* Data Training Configuration Register */
+       u32 dtar[4];            /* Data Training Address Register */
+       u32 dtdr[2];            /* Data Training Data Register */
+       u32 dtedr[2];           /* Data Training Eye Data Register */
+       u32 rsv0[13];           /* Reserved */
+       u32 dcuar;              /* DCU Address Register */
+       u32 dcudr;              /* DCU Data Register */
+       u32 dcurr;              /* DCU Run Register */
+       u32 dculr;              /* DCU Loop Register */
+       u32 dcugcr;             /* DCU General Configuration Register */
+       u32 dcutpr;             /* DCU Timing Parameters Register */
+       u32 dcusr[2];           /* DCU Status Register */
+       u32 rsv1[8];            /* Reserved */
+       u32 bistrr;             /* BIST Run Register */
+       u32 bistwcr;            /* BIST Word Count Register */
+       u32 bistmskr[3];        /* BIST Mask Register */
+       u32 bistlsr;            /* BIST LFSR Sed Register */
+       u32 bistar[3];          /* BIST Address Register */
+       u32 bistudpr;           /* BIST User Data Pattern Register */
+       u32 bistgsr;            /* BIST General Status Register */
+       u32 bistwer;            /* BIST Word Error Register */
+       u32 bistber[4];         /* BIST Bit Error Register */
+       u32 bistwcsr;           /* BIST Word Count Status Register */
+       u32 bistfwr[3];         /* BIST Fail Word Register */
+       u32 rsv2[10];           /* Reserved */
+       u32 gpr[2];             /* General Purpose Register */
+       struct ddrphy_zq {      /* ZQ */
+               u32 cr[2];      /* Impedance Control Register */
+               u32 sr[2];      /* Impedance Status Register */
+       } zq[4];
+       struct ddrphy_datx8 {   /* DATX8 */
+               u32 gcr;        /* General Configuration Register */
+               u32 gsr[2];     /* General Status Register */
+               u32 bdlr[5];    /* Bit Delay Line Register */
+               u32 lcdlr[3];   /* Local Calibrated Delay Line Register */
+               u32 mdlr;       /* Master Delay Line Register */
+               u32 gtr;        /* General Timing Register */
+               u32 rsv[3];     /* Reserved */
+       } dx[9];
+} __packed;
+
+#endif /* __ASSEMBLY__ */
+
+#define PIR_INIT               (1 <<  0)       /* Initialization Trigger */
+#define PIR_ZCAL               (1 <<  1)       /* Impedance Calibration */
+#define PIR_PLLINIT            (1 <<  4)       /* PLL Initialization */
+#define PIR_DCAL               (1 <<  5)       /* DDL Calibration */
+#define PIR_PHYRST             (1 <<  6)       /* PHY Reset */
+#define PIR_DRAMRST            (1 <<  7)       /* DRAM Reset */
+#define PIR_DRAMINIT           (1 <<  8)       /* DRAM Initialization */
+#define PIR_WL                 (1 <<  9)       /* Write Leveling */
+#define PIR_QSGATE             (1 << 10)       /* Read DQS Gate Training */
+#define PIR_WLADJ              (1 << 11)       /* Write Leveling Adjust */
+#define PIR_RDDSKW             (1 << 12)       /* Read Data Bit Deskew */
+#define PIR_WRDSKW             (1 << 13)       /* Write Data Bit Deskew */
+#define PIR_RDEYE              (1 << 14)       /* Read Data Eye Training */
+#define PIR_WREYE              (1 << 15)       /* Write Data Eye Training */
+#define PIR_LOCKBYP            (1 << 28)       /* PLL Lock Bypass */
+#define PIR_DCALBYP            (1 << 29)       /* DDL Calibration Bypass */
+#define PIR_ZCALBYP            (1 << 30)       /* Impedance Calib Bypass */
+#define PIR_INITBYP            (1 << 31)       /* Initialization Bypass */
+
+#define PGSR0_IDONE            (1 <<  0)       /* Initialization Done */
+#define PGSR0_PLDONE           (1 <<  1)       /* PLL Lock Done */
+#define PGSR0_DCDONE           (1 <<  2)       /* DDL Calibration Done */
+#define PGSR0_ZCDONE           (1 <<  3)       /* Impedance Calibration Done */
+#define PGSR0_DIDONE           (1 <<  4)       /* DRAM Initialization Done */
+#define PGSR0_WLDONE           (1 <<  5)       /* Write Leveling Done */
+#define PGSR0_QSGDONE          (1 <<  6)       /* DQS Gate Training Done */
+#define PGSR0_WLADONE          (1 <<  7)       /* Write Leveling Adjust Done */
+#define PGSR0_RDDONE           (1 <<  8)       /* Read Bit Deskew Done */
+#define PGSR0_WDDONE           (1 <<  9)       /* Write Bit Deskew Done */
+#define PGSR0_REDONE           (1 << 10)       /* Read Eye Training Done */
+#define PGSR0_WEDONE           (1 << 11)       /* Write Eye Training Done */
+#define PGSR0_IERR             (1 << 16)       /* Initialization Error */
+#define PGSR0_PLERR            (1 << 17)       /* PLL Lock Error */
+#define PGSR0_DCERR            (1 << 18)       /* DDL Calibration Error */
+#define PGSR0_ZCERR            (1 << 19)       /* Impedance Calib Error */
+#define PGSR0_DIERR            (1 << 20)       /* DRAM Initialization Error */
+#define PGSR0_WLERR            (1 << 21)       /* Write Leveling Error */
+#define PGSR0_QSGERR           (1 << 22)       /* DQS Gate Training Error */
+#define PGSR0_WLAERR           (1 << 23)       /* Write Leveling Adj Error */
+#define PGSR0_RDERR            (1 << 24)       /* Read Bit Deskew Error */
+#define PGSR0_WDERR            (1 << 25)       /* Write Bit Deskew Error */
+#define PGSR0_REERR            (1 << 26)       /* Read Eye Training Error */
+#define PGSR0_WEERR            (1 << 27)       /* Write Eye Training Error */
+#define PGSR0_DTERR_SHIFT      28              /* Data Training Error Status*/
+#define PGSR0_DTERR            (7 << (PGSR0_DTERR_SHIFT))
+#define PGSR0_APLOCK           (1 << 31)       /* AC PLL Lock */
+
+#define DXCCR_DQSRES_OPEN      (0 << 5)
+#define DXCCR_DQSRES_688_OHM   (1 << 5)
+#define DXCCR_DQSRES_611_OHM   (2 << 5)
+#define DXCCR_DQSRES_550_OHM   (3 << 5)
+#define DXCCR_DQSRES_500_OHM   (4 << 5)
+#define DXCCR_DQSRES_458_OHM   (5 << 5)
+#define DXCCR_DQSRES_393_OHM   (6 << 5)
+#define DXCCR_DQSRES_344_OHM   (7 << 5)
+
+#define DXCCR_DQSNRES_OPEN     (0 << 9)
+#define DXCCR_DQSNRES_688_OHM  (1 << 9)
+#define DXCCR_DQSNRES_611_OHM  (2 << 9)
+#define DXCCR_DQSNRES_550_OHM  (3 << 9)
+#define DXCCR_DQSNRES_500_OHM  (4 << 9)
+#define DXCCR_DQSNRES_458_OHM  (5 << 9)
+#define DXCCR_DQSNRES_393_OHM  (6 << 9)
+#define DXCCR_DQSNRES_344_OHM  (7 << 9)
+
+#define DTCR_DTRANK_SHIFT      4               /* Data Training Rank */
+#define DTCR_DTRANK_MASK       (0x3 << (DTCR_DTRANK_SHIFT))
+#define DTCR_DTMPR             (1 << 6)        /* Data Training using MPR */
+#define DTCR_RNKEN_SHIFT       24              /* Rank Enable */
+#define DTCR_RNKEN_MASK                (0xf << (DTCR_RNKEN_SHIFT))
+
+#define DXGCR_WLRKEN_SHIFT     26              /* Write Level Rank Enable */
+#define DXGCR_WLRKEN_MASK      (0xf << (DXGCR_WLRKEN_SHIFT))
+
+/* SoC-specific parameters */
+#define NR_DATX8_PER_DDRPHY    2
+
+#if defined(CONFIG_MACH_PH1_LD4) || defined(CONFIG_MACH_PH1_SLD8)
+#define NR_DDRPHY_PER_CH               1
+#else
+#define NR_DDRPHY_PER_CH               2
+#endif
+
+#define NR_DDRCH               2
+
+#define DDRPHY_BASE(ch, phy)   (0x5bc01000 + 0x200000 * (ch) + 0x1000 * (phy))
+
+#ifndef __ASSEMBLY__
+void ddrphy_init(struct ddrphy __iomem *phy, int freq, int size);
+void ddrphy_prepare_training(struct ddrphy __iomem *phy, int rank);
+int ddrphy_training(struct ddrphy __iomem *phy);
+#endif
+
+#endif /* ARCH_DDRPHY_REGS_H */