ARM: uniphier: allow to enable multiple SoCs

Before this commit, the Kconfig menu in mach-uniphier only allowed us
to choose one SoC to be compiled.  Each SoC has its own defconfig file
for the build-test coverage.  Consequently, some defconfig files are
duplicated with only the difference in CONFIG_DEFAULT_DEVICE_TREE and
CONFIG_{SOC_NAME}=y.

Now, most of board-specific parameters have been moved to device trees,
so it makes sense to include init code of multiple SoCs into a single
image as long as the SoCs have similar architecture.  In fact, some
SoCs of UniPhier family are very similar:
 - PH1-LD4 and PH1-sLD8
 - PH1-LD6b and ProXstream2 (will be added in the upcoming commit)

This commit will be helpful to merge some defconfig files for better
maintainability.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
diff --git a/arch/arm/mach-uniphier/ddrphy/Makefile b/arch/arm/mach-uniphier/ddrphy/Makefile
new file mode 100644
index 0000000..e2d109d
--- /dev/null
+++ b/arch/arm/mach-uniphier/ddrphy/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ARCH_UNIPHIER_PH1_LD4)	+= ddrphy-training.o ddrphy-ph1-ld4.o
+obj-$(CONFIG_ARCH_UNIPHIER_PH1_PRO4)	+= ddrphy-training.o ddrphy-ph1-pro4.o
+obj-$(CONFIG_ARCH_UNIPHIER_PH1_SLD8)	+= ddrphy-training.o ddrphy-ph1-sld8.o
diff --git a/arch/arm/mach-uniphier/ddrphy/ddrphy-ph1-ld4.c b/arch/arm/mach-uniphier/ddrphy/ddrphy-ph1-ld4.c
new file mode 100644
index 0000000..991d929
--- /dev/null
+++ b/arch/arm/mach-uniphier/ddrphy/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/ddrphy/ddrphy-ph1-pro4.c b/arch/arm/mach-uniphier/ddrphy/ddrphy-ph1-pro4.c
new file mode 100644
index 0000000..bc47ba3
--- /dev/null
+++ b/arch/arm/mach-uniphier/ddrphy/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/ddrphy/ddrphy-ph1-sld8.c b/arch/arm/mach-uniphier/ddrphy/ddrphy-ph1-sld8.c
new file mode 100644
index 0000000..39024a0
--- /dev/null
+++ b/arch/arm/mach-uniphier/ddrphy/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/ddrphy/ddrphy-training.c b/arch/arm/mach-uniphier/ddrphy/ddrphy-training.c
new file mode 100644
index 0000000..a98b814
--- /dev/null
+++ b/arch/arm/mach-uniphier/ddrphy/ddrphy-training.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.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_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) {
+			printf("%s: error: timeout during DDR training\n",
+								__func__);
+			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) {
+			printf("%s: error: %s failed\n", __func__,
+						init_sequence[i].description);
+			return -1;
+		}
+	}
+
+#ifdef DISPLAY_ELAPSED_TIME
+	printf("%s: info: elapsed time %ld msec\n", get_timer(start));
+#endif
+
+	return 0;
+}