summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-uniphier/dram
diff options
context:
space:
mode:
authorMasahiro Yamada <yamada.masahiro@socionext.com>2015-12-17 17:47:47 +0900
committerMasahiro Yamada <yamada.masahiro@socionext.com>2015-12-23 00:08:55 +0900
commit33886693b645dd737a21065c095eac2ce7cbd956 (patch)
treebdd10aea1dccdfe0d5bbc87d7acac616ab3c12e6 /arch/arm/mach-uniphier/dram
parent6e1550fa7cb37061abcb3de13e69b859f8fd75cb (diff)
downloadtalos-obmc-uboot-33886693b645dd737a21065c095eac2ce7cbd956.tar.gz
talos-obmc-uboot-33886693b645dd737a21065c095eac2ce7cbd956.zip
ARM: uniphier: merge umc/ and ddrphy/ into a single directory
The UMC (Universal Memory Controller) and the DDR PHY block are highly related to each other. It is better to have both code in the same directory. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Diffstat (limited to 'arch/arm/mach-uniphier/dram')
-rw-r--r--arch/arm/mach-uniphier/dram/Makefile10
-rw-r--r--arch/arm/mach-uniphier/dram/ddrphy-ph1-ld4.c72
-rw-r--r--arch/arm/mach-uniphier/dram/ddrphy-ph1-pro4.c72
-rw-r--r--arch/arm/mach-uniphier/dram/ddrphy-ph1-sld8.c77
-rw-r--r--arch/arm/mach-uniphier/dram/ddrphy-training.c140
-rw-r--r--arch/arm/mach-uniphier/dram/umc-ph1-ld4.c175
-rw-r--r--arch/arm/mach-uniphier/dram/umc-ph1-pro4.c161
-rw-r--r--arch/arm/mach-uniphier/dram/umc-ph1-sld8.c155
8 files changed, 862 insertions, 0 deletions
diff --git a/arch/arm/mach-uniphier/dram/Makefile b/arch/arm/mach-uniphier/dram/Makefile
new file mode 100644
index 0000000000..d3a767b525
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/Makefile
@@ -0,0 +1,10 @@
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_ARCH_UNIPHIER_PH1_LD4) += umc-ph1-ld4.o \
+ ddrphy-training.o ddrphy-ph1-ld4.o
+obj-$(CONFIG_ARCH_UNIPHIER_PH1_PRO4) += umc-ph1-pro4.o \
+ ddrphy-training.o ddrphy-ph1-pro4.o
+obj-$(CONFIG_ARCH_UNIPHIER_PH1_SLD8) += umc-ph1-sld8.o \
+ ddrphy-training.o ddrphy-ph1-sld8.o
diff --git a/arch/arm/mach-uniphier/dram/ddrphy-ph1-ld4.c b/arch/arm/mach-uniphier/dram/ddrphy-ph1-ld4.c
new file mode 100644
index 0000000000..991d9294fd
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/ddrphy-ph1-ld4.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <mach/ddrphy-regs.h>
+
+int ph1_ld4_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]);
+
+ return 0;
+}
diff --git a/arch/arm/mach-uniphier/dram/ddrphy-ph1-pro4.c b/arch/arm/mach-uniphier/dram/ddrphy-ph1-pro4.c
new file mode 100644
index 0000000000..bc47ba3280
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/ddrphy-ph1-pro4.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <mach/ddrphy-regs.h>
+
+int ph1_pro4_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]);
+
+ return 0;
+}
diff --git a/arch/arm/mach-uniphier/dram/ddrphy-ph1-sld8.c b/arch/arm/mach-uniphier/dram/ddrphy-ph1-sld8.c
new file mode 100644
index 0000000000..39024a09d5
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/ddrphy-ph1-sld8.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <mach/ddrphy-regs.h>
+
+int ph1_sld8_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]);
+
+ return 0;
+}
diff --git a/arch/arm/mach-uniphier/dram/ddrphy-training.c b/arch/arm/mach-uniphier/dram/ddrphy-training.c
new file mode 100644
index 0000000000..4852f2dec8
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/ddrphy-training.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <mach/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_RANKEN_MASK;
+ tmp |= (1 << (DTCR_RANKEN_SHIFT + rank)) & DTCR_RANKEN_MASK;
+ writel(tmp, p);
+}
+
+struct ddrphy_init_sequence {
+ char *description;
+ u32 init_flag;
+ u32 done_flag;
+ u32 err_flag;
+};
+
+static const 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) {
+ printf("%s: error: timeout during DDR training\n",
+ __func__);
+ return -ETIMEDOUT;
+ }
+ 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) {
+ printf("%s: error: %s failed\n", __func__,
+ init_sequence[i].description);
+ return -EIO;
+ }
+ }
+
+#ifdef DISPLAY_ELAPSED_TIME
+ printf("%s: info: elapsed time %ld msec\n", get_timer(start));
+#endif
+
+ return 0;
+}
diff --git a/arch/arm/mach-uniphier/dram/umc-ph1-ld4.c b/arch/arm/mach-uniphier/dram/umc-ph1-ld4.c
new file mode 100644
index 0000000000..81246850b3
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/umc-ph1-ld4.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <mach/init.h>
+#include <mach/umc-regs.h>
+#include <mach/ddrphy-regs.h>
+
+static void umc_start_ssif(void __iomem *ssif_base)
+{
+ writel(0x00000000, ssif_base + 0x0000b004);
+ writel(0xffffffff, ssif_base + 0x0000c004);
+ writel(0x000fffcf, ssif_base + 0x0000c008);
+ writel(0x00000001, ssif_base + 0x0000b000);
+ writel(0x00000001, ssif_base + 0x0000c000);
+ writel(0x03010101, ssif_base + UMC_MDMCHSEL);
+ writel(0x03010100, ssif_base + UMC_DMDCHSEL);
+
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_FETCH);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_WC);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_RC);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_DST);
+
+ writel(0x00000001, ssif_base + UMC_CPURST);
+ writel(0x00000001, ssif_base + UMC_IDSRST);
+ writel(0x00000001, ssif_base + UMC_IXMRST);
+ writel(0x00000001, ssif_base + UMC_MDMRST);
+ writel(0x00000001, ssif_base + UMC_MDDRST);
+ writel(0x00000001, ssif_base + UMC_SIORST);
+ writel(0x00000001, ssif_base + UMC_VIORST);
+ writel(0x00000001, ssif_base + UMC_FRCRST);
+ writel(0x00000001, ssif_base + UMC_RGLRST);
+ writel(0x00000001, ssif_base + UMC_AIORST);
+ writel(0x00000001, ssif_base + UMC_DMDRST);
+}
+
+static void umc_dramcont_init(void __iomem *dramcont, void __iomem *ca_base,
+ int size, int freq)
+{
+ if (freq == 1333) {
+ writel(0x45990b11, dramcont + UMC_CMDCTLA);
+ writel(0x16958924, dramcont + UMC_CMDCTLB);
+ writel(0x5101046A, dramcont + UMC_INITCTLA);
+
+ if (size == 1)
+ writel(0x27028B0A, dramcont + UMC_INITCTLB);
+ else if (size == 2)
+ writel(0x38028B0A, dramcont + UMC_INITCTLB);
+
+ writel(0x000FF0FF, dramcont + UMC_INITCTLC);
+ writel(0x00000b51, dramcont + UMC_DRMMR0);
+ } else if (freq == 1600) {
+ writel(0x36BB0F17, dramcont + UMC_CMDCTLA);
+ writel(0x18C6AA24, dramcont + UMC_CMDCTLB);
+ writel(0x5101387F, dramcont + UMC_INITCTLA);
+
+ if (size == 1)
+ writel(0x2F030D3F, dramcont + UMC_INITCTLB);
+ else if (size == 2)
+ writel(0x43030D3F, dramcont + UMC_INITCTLB);
+
+ writel(0x00FF00FF, dramcont + UMC_INITCTLC);
+ writel(0x00000d71, dramcont + UMC_DRMMR0);
+ }
+
+ writel(0x00000006, dramcont + UMC_DRMMR1);
+
+ if (freq == 1333)
+ writel(0x00000290, dramcont + UMC_DRMMR2);
+ else if (freq == 1600)
+ writel(0x00000298, dramcont + UMC_DRMMR2);
+
+ writel(0x00000800, dramcont + UMC_DRMMR3);
+
+ if (freq == 1333) {
+ if (size == 1)
+ writel(0x00240512, dramcont + UMC_SPCCTLA);
+ else if (size == 2)
+ writel(0x00350512, dramcont + UMC_SPCCTLA);
+
+ writel(0x00ff0006, dramcont + UMC_SPCCTLB);
+ writel(0x000a00ac, dramcont + UMC_RDATACTL_D0);
+ } else if (freq == 1600) {
+ if (size == 1)
+ writel(0x002B0617, dramcont + UMC_SPCCTLA);
+ else if (size == 2)
+ writel(0x003F0617, dramcont + UMC_SPCCTLA);
+
+ writel(0x00ff0008, dramcont + UMC_SPCCTLB);
+ writel(0x000c00ae, dramcont + UMC_RDATACTL_D0);
+ }
+
+ writel(0x04060806, dramcont + UMC_WDATACTL_D0);
+ writel(0x04a02000, dramcont + UMC_DATASET);
+ writel(0x00000000, ca_base + 0x2300);
+ writel(0x00400020, dramcont + UMC_DCCGCTL);
+ writel(0x00000003, dramcont + 0x7000);
+ writel(0x0000000f, dramcont + 0x8000);
+ writel(0x000000c3, dramcont + 0x8004);
+ writel(0x00000071, dramcont + 0x8008);
+ writel(0x0000003b, dramcont + UMC_DICGCTLA);
+ writel(0x020a0808, dramcont + UMC_DICGCTLB);
+ writel(0x00000004, dramcont + UMC_FLOWCTLG);
+ writel(0x80000201, ca_base + 0xc20);
+ writel(0x0801e01e, dramcont + UMC_FLOWCTLA);
+ writel(0x00200000, dramcont + UMC_FLOWCTLB);
+ writel(0x00004444, dramcont + UMC_FLOWCTLC);
+ writel(0x200a0a00, dramcont + UMC_SPCSETB);
+ writel(0x00000000, dramcont + UMC_SPCSETD);
+ writel(0x00000520, dramcont + UMC_DFICUPDCTLA);
+}
+
+static int umc_init_sub(int freq, int size_ch0, int size_ch1)
+{
+ void __iomem *ssif_base = (void __iomem *)UMC_SSIF_BASE;
+ void __iomem *ca_base0 = (void __iomem *)UMC_CA_BASE(0);
+ 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);
+ umc_dram_init_poll(dramcont0);
+ umc_dram_init_poll(dramcont1);
+
+ writel(0x00000101, dramcont0 + UMC_DIOCTLA);
+
+ ph1_ld4_ddrphy_init(phy0_0, freq, size_ch0);
+
+ ddrphy_prepare_training(phy0_0, 0);
+ ddrphy_training(phy0_0);
+
+ writel(0x00000101, dramcont1 + UMC_DIOCTLA);
+
+ ph1_ld4_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);
+
+ umc_start_ssif(ssif_base);
+
+ return 0;
+}
+
+int ph1_ld4_umc_init(const struct uniphier_board_data *bd)
+{
+ if ((bd->dram_ch0_size == SZ_128M || bd->dram_ch0_size == SZ_256M) &&
+ (bd->dram_ch1_size == SZ_128M || bd->dram_ch1_size == SZ_256M) &&
+ (bd->dram_freq == 1333 || bd->dram_freq == 1600) &&
+ bd->dram_ch0_width == 16 && bd->dram_ch1_width == 16) {
+ return umc_init_sub(bd->dram_freq,
+ bd->dram_ch0_size / SZ_128M,
+ bd->dram_ch1_size / SZ_128M);
+ } else {
+ pr_err("Unsupported DDR configuration\n");
+ return -EINVAL;
+ }
+}
diff --git a/arch/arm/mach-uniphier/dram/umc-ph1-pro4.c b/arch/arm/mach-uniphier/dram/umc-ph1-pro4.c
new file mode 100644
index 0000000000..8c9f0579fc
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/umc-ph1-pro4.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <mach/init.h>
+#include <mach/umc-regs.h>
+#include <mach/ddrphy-regs.h>
+
+static void umc_start_ssif(void __iomem *ssif_base)
+{
+ writel(0x00000001, ssif_base + 0x0000b004);
+ writel(0xffffffff, ssif_base + 0x0000c004);
+ writel(0x07ffffff, ssif_base + 0x0000c008);
+ writel(0x00000001, ssif_base + 0x0000b000);
+ writel(0x00000001, ssif_base + 0x0000c000);
+
+ writel(0x03010100, ssif_base + UMC_HDMCHSEL);
+ writel(0x03010101, ssif_base + UMC_MDMCHSEL);
+ writel(0x03010100, ssif_base + UMC_DVCCHSEL);
+ writel(0x03010100, ssif_base + UMC_DMDCHSEL);
+
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_FETCH);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_WC);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_RC);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_DST);
+ writel(0x00000000, ssif_base + 0x0000c044); /* DCGIV_SSIF_REG */
+
+ writel(0x00000001, ssif_base + UMC_CPURST);
+ writel(0x00000001, ssif_base + UMC_IDSRST);
+ writel(0x00000001, ssif_base + UMC_IXMRST);
+ writel(0x00000001, ssif_base + UMC_HDMRST);
+ writel(0x00000001, ssif_base + UMC_MDMRST);
+ writel(0x00000001, ssif_base + UMC_HDDRST);
+ writel(0x00000001, ssif_base + UMC_MDDRST);
+ writel(0x00000001, ssif_base + UMC_SIORST);
+ writel(0x00000001, ssif_base + UMC_GIORST);
+ writel(0x00000001, ssif_base + UMC_HD2RST);
+ writel(0x00000001, ssif_base + UMC_VIORST);
+ writel(0x00000001, ssif_base + UMC_DVCRST);
+ writel(0x00000001, ssif_base + UMC_RGLRST);
+ writel(0x00000001, ssif_base + UMC_VPERST);
+ writel(0x00000001, ssif_base + UMC_AIORST);
+ writel(0x00000001, ssif_base + UMC_DMDRST);
+}
+
+static void umc_dramcont_init(void __iomem *dramcont, void __iomem *ca_base,
+ int size, int freq)
+{
+ writel(0x66bb0f17, dramcont + UMC_CMDCTLA);
+ writel(0x18c6aa44, dramcont + UMC_CMDCTLB);
+ writel(0x5101387f, dramcont + UMC_INITCTLA);
+ writel(0x43030d3f, dramcont + UMC_INITCTLB);
+ writel(0x00ff00ff, dramcont + UMC_INITCTLC);
+ writel(0x00000d71, dramcont + UMC_DRMMR0);
+ writel(0x00000006, dramcont + UMC_DRMMR1);
+ writel(0x00000298, dramcont + UMC_DRMMR2);
+ writel(0x00000000, dramcont + UMC_DRMMR3);
+ writel(0x003f0617, dramcont + UMC_SPCCTLA);
+ writel(0x00ff0008, dramcont + UMC_SPCCTLB);
+ writel(0x000c00ae, dramcont + UMC_RDATACTL_D0);
+ writel(0x000c00ae, dramcont + UMC_RDATACTL_D1);
+ writel(0x04060802, dramcont + UMC_WDATACTL_D0);
+ writel(0x04060802, dramcont + UMC_WDATACTL_D1);
+ writel(0x04a02000, dramcont + UMC_DATASET);
+ writel(0x00000000, ca_base + 0x2300);
+ writel(0x00400020, dramcont + UMC_DCCGCTL);
+ writel(0x0000000f, dramcont + 0x7000);
+ writel(0x0000000f, dramcont + 0x8000);
+ writel(0x000000c3, dramcont + 0x8004);
+ writel(0x00000071, dramcont + 0x8008);
+ writel(0x00000004, dramcont + UMC_FLOWCTLG);
+ writel(0x00000000, dramcont + 0x0060);
+ writel(0x80000201, ca_base + 0xc20);
+ writel(0x0801e01e, dramcont + UMC_FLOWCTLA);
+ writel(0x00200000, dramcont + UMC_FLOWCTLB);
+ writel(0x00004444, dramcont + UMC_FLOWCTLC);
+ writel(0x200a0a00, dramcont + UMC_SPCSETB);
+ writel(0x00010000, dramcont + UMC_SPCSETD);
+ writel(0x80000020, dramcont + UMC_DFICUPDCTLA);
+}
+
+static int umc_init_sub(int freq, int size_ch0, int size_ch1)
+{
+ void __iomem *ssif_base = (void __iomem *)UMC_SSIF_BASE;
+ void __iomem *ca_base0 = (void __iomem *)UMC_CA_BASE(0);
+ 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);
+ umc_dram_init_poll(dramcont0);
+ umc_dram_init_poll(dramcont1);
+
+ writel(0x00000101, dramcont0 + UMC_DIOCTLA);
+
+ ph1_pro4_ddrphy_init(phy0_0, freq, size_ch0);
+
+ ddrphy_prepare_training(phy0_0, 0);
+ ddrphy_training(phy0_0);
+
+ writel(0x00000103, dramcont0 + UMC_DIOCTLA);
+
+ ph1_pro4_ddrphy_init(phy0_1, freq, size_ch0);
+
+ ddrphy_prepare_training(phy0_1, 1);
+ ddrphy_training(phy0_1);
+
+ writel(0x00000101, dramcont1 + UMC_DIOCTLA);
+
+ ph1_pro4_ddrphy_init(phy1_0, freq, size_ch1);
+
+ ddrphy_prepare_training(phy1_0, 0);
+ ddrphy_training(phy1_0);
+
+ writel(0x00000103, dramcont1 + UMC_DIOCTLA);
+
+ ph1_pro4_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);
+
+ umc_start_ssif(ssif_base);
+
+ return 0;
+}
+
+int ph1_pro4_umc_init(const struct uniphier_board_data *bd)
+{
+ if (((bd->dram_ch0_size == SZ_512M && bd->dram_ch0_width == 32) ||
+ (bd->dram_ch0_size == SZ_256M && bd->dram_ch0_width == 16)) &&
+ ((bd->dram_ch1_size == SZ_512M && bd->dram_ch1_width == 32) ||
+ (bd->dram_ch1_size == SZ_256M && bd->dram_ch1_width == 16)) &&
+ bd->dram_freq == 1600) {
+ return umc_init_sub(bd->dram_freq,
+ bd->dram_ch0_size / SZ_128M,
+ bd->dram_ch1_size / SZ_128M);
+ } else {
+ pr_err("Unsupported DDR configuration\n");
+ return -EINVAL;
+ }
+}
diff --git a/arch/arm/mach-uniphier/dram/umc-ph1-sld8.c b/arch/arm/mach-uniphier/dram/umc-ph1-sld8.c
new file mode 100644
index 0000000000..bc60a3472e
--- /dev/null
+++ b/arch/arm/mach-uniphier/dram/umc-ph1-sld8.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <mach/init.h>
+#include <mach/umc-regs.h>
+#include <mach/ddrphy-regs.h>
+
+static void umc_start_ssif(void __iomem *ssif_base)
+{
+ writel(0x00000000, ssif_base + 0x0000b004);
+ writel(0xffffffff, ssif_base + 0x0000c004);
+ writel(0x000fffcf, ssif_base + 0x0000c008);
+ writel(0x00000001, ssif_base + 0x0000b000);
+ writel(0x00000001, ssif_base + 0x0000c000);
+ writel(0x03010101, ssif_base + UMC_MDMCHSEL);
+ writel(0x03010100, ssif_base + UMC_DMDCHSEL);
+
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_FETCH);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC0);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMQUE1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMWC1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_COMRC1);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_WC);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_RC);
+ writel(0x00000000, ssif_base + UMC_CLKEN_SSIF_DST);
+
+ writel(0x00000001, ssif_base + UMC_CPURST);
+ writel(0x00000001, ssif_base + UMC_IDSRST);
+ writel(0x00000001, ssif_base + UMC_IXMRST);
+ writel(0x00000001, ssif_base + UMC_MDMRST);
+ writel(0x00000001, ssif_base + UMC_MDDRST);
+ writel(0x00000001, ssif_base + UMC_SIORST);
+ writel(0x00000001, ssif_base + UMC_VIORST);
+ writel(0x00000001, ssif_base + UMC_FRCRST);
+ writel(0x00000001, ssif_base + UMC_RGLRST);
+ writel(0x00000001, ssif_base + UMC_AIORST);
+ writel(0x00000001, ssif_base + UMC_DMDRST);
+}
+
+static void umc_dramcont_init(void __iomem *dramcont, void __iomem *ca_base,
+ int size, int freq)
+{
+#ifdef CONFIG_DDR_STANDARD
+ writel(0x55990b11, dramcont + UMC_CMDCTLA);
+ writel(0x16958944, dramcont + UMC_CMDCTLB);
+#else
+ writel(0x45990b11, dramcont + UMC_CMDCTLA);
+ writel(0x16958924, dramcont + UMC_CMDCTLB);
+#endif
+
+ writel(0x5101046A, dramcont + UMC_INITCTLA);
+
+ if (size == 1)
+ writel(0x27028B0A, dramcont + UMC_INITCTLB);
+ else if (size == 2)
+ writel(0x38028B0A, dramcont + UMC_INITCTLB);
+
+ writel(0x00FF00FF, dramcont + UMC_INITCTLC);
+ writel(0x00000b51, dramcont + UMC_DRMMR0);
+ writel(0x00000006, dramcont + UMC_DRMMR1);
+ writel(0x00000290, dramcont + UMC_DRMMR2);
+
+#ifdef CONFIG_DDR_STANDARD
+ writel(0x00000000, dramcont + UMC_DRMMR3);
+#else
+ writel(0x00000800, dramcont + UMC_DRMMR3);
+#endif
+
+ if (size == 1)
+ writel(0x00240512, dramcont + UMC_SPCCTLA);
+ else if (size == 2)
+ writel(0x00350512, dramcont + UMC_SPCCTLA);
+
+ writel(0x00ff0006, dramcont + UMC_SPCCTLB);
+ writel(0x000a00ac, dramcont + UMC_RDATACTL_D0);
+ writel(0x04060806, dramcont + UMC_WDATACTL_D0);
+ writel(0x04a02000, dramcont + UMC_DATASET);
+ writel(0x00000000, ca_base + 0x2300);
+ writel(0x00400020, dramcont + UMC_DCCGCTL);
+ writel(0x00000003, dramcont + 0x7000);
+ writel(0x0000004f, dramcont + 0x8000);
+ writel(0x000000c3, dramcont + 0x8004);
+ writel(0x00000077, dramcont + 0x8008);
+ writel(0x0000003b, dramcont + UMC_DICGCTLA);
+ writel(0x020a0808, dramcont + UMC_DICGCTLB);
+ writel(0x00000004, dramcont + UMC_FLOWCTLG);
+ writel(0x80000201, ca_base + 0xc20);
+ writel(0x0801e01e, dramcont + UMC_FLOWCTLA);
+ writel(0x00200000, dramcont + UMC_FLOWCTLB);
+ writel(0x00004444, dramcont + UMC_FLOWCTLC);
+ writel(0x200a0a00, dramcont + UMC_SPCSETB);
+ writel(0x00000000, dramcont + UMC_SPCSETD);
+ writel(0x00000520, dramcont + UMC_DFICUPDCTLA);
+}
+
+static int umc_init_sub(int freq, int size_ch0, int size_ch1)
+{
+ void __iomem *ssif_base = (void __iomem *)UMC_SSIF_BASE;
+ void __iomem *ca_base0 = (void __iomem *)UMC_CA_BASE(0);
+ 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);
+ umc_dram_init_poll(dramcont0);
+ umc_dram_init_poll(dramcont1);
+
+ writel(0x00000101, dramcont0 + UMC_DIOCTLA);
+
+ ph1_sld8_ddrphy_init(phy0_0, freq, size_ch0);
+
+ ddrphy_prepare_training(phy0_0, 0);
+ ddrphy_training(phy0_0);
+
+ writel(0x00000101, dramcont1 + UMC_DIOCTLA);
+
+ ph1_sld8_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);
+
+ umc_start_ssif(ssif_base);
+
+ return 0;
+}
+
+int ph1_sld8_umc_init(const struct uniphier_board_data *bd)
+{
+ if ((bd->dram_ch0_size == SZ_128M || bd->dram_ch0_size == SZ_256M) &&
+ (bd->dram_ch1_size == SZ_128M || bd->dram_ch1_size == SZ_256M) &&
+ bd->dram_freq == 1333 &&
+ bd->dram_ch0_width == 16 && bd->dram_ch1_width == 16) {
+ return umc_init_sub(bd->dram_freq,
+ bd->dram_ch0_size / SZ_128M,
+ bd->dram_ch1_size / SZ_128M);
+ } else {
+ pr_err("Unsupported DDR configuration\n");
+ return -EINVAL;
+ }
+}
OpenPOWER on IntegriCloud