sunxi: H6: move LPDDR3 timing definition into separate file

Currently the H6 DRAM driver only supports one kind of LPDDR3 DRAM.
Split the timing parameters for this LPDDR3 configuration  into a
separate file, to allow selecting an alternative later at compile time
(as the sunxi-dw driver does).

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Tested-by: Jernej Skrabec <jernej.skrabec@siol.net>
Reviewed-by: Jernej Skrabec <jernej.skrabec@siol.net>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
index eeb4da5..54c4755 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
@@ -287,6 +287,31 @@
 #define DCR_DDR4	(4 << 0)
 #define DCR_DDR8BANK	BIT(3)
 
+/*
+ * The delay parameters allow to allegedly specify delay times of some
+ * unknown unit for each individual bit trace in each of the four data bytes
+ * the 32-bit wide access consists of. Also three control signals can be
+ * adjusted individually.
+ */
+#define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
+/* The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable and DQSN */
+#define WR_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 4)
+/*
+ * The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable, DQSN,
+ * Termination and Power down
+ */
+#define RD_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 6)
+struct dram_para {
+	u32 clk;
+	enum sunxi_dram_type type;
+	u8 cols;
+	u8 rows;
+	u8 ranks;
+	const u8 dx_read_delays[NR_OF_BYTE_LANES][RD_LINES_PER_BYTE_LANE];
+	const u8 dx_write_delays[NR_OF_BYTE_LANES][WR_LINES_PER_BYTE_LANE];
+};
+
+
 static inline int ns_to_t(int nanoseconds)
 {
 	const unsigned int ctrl_freq = CONFIG_DRAM_CLK / 2;
@@ -294,4 +319,6 @@
 	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
 }
 
+void mctl_set_timing_params(struct dram_para *para);
+
 #endif /* _SUNXI_DRAM_SUN50I_H6_H */
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 1669e62..d588936 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -340,7 +340,7 @@
 	This allows both the SPL and the U-Boot proper to be entered in
 	either mode and switch to AArch64 if needed.
 
-if SUNXI_DRAM_DW
+if SUNXI_DRAM_DW || DRAM_SUN50I_H6
 config SUNXI_DRAM_DDR3
 	bool
 
@@ -370,6 +370,14 @@
 	This option is the LPDDR3 timing used by the stock boot0 by
 	Allwinner.
 
+config SUNXI_DRAM_H6_LPDDR3
+	bool "LPDDR3 DRAM chips on the H6 DRAM controller"
+	select SUNXI_DRAM_LPDDR3
+	depends on DRAM_SUN50I_H6
+	---help---
+	This option is the LPDDR3 timing used by the stock boot0 by
+	Allwinner.
+
 config SUNXI_DRAM_DDR2_V3S
 	bool "DDR2 found in V3s chip"
 	select SUNXI_DRAM_DDR2
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 43a93e3..d129f33 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -39,4 +39,5 @@
 obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_sunxi_dw.o
 obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_timings/
 obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_sun50i_h6.o
+obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_timings/
 endif
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c
index 7a8b724..697b8af 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
@@ -32,33 +32,8 @@
  * similar PHY is ZynqMP.
  */
 
-/*
- * The delay parameters below allow to allegedly specify delay times of some
- * unknown unit for each individual bit trace in each of the four data bytes
- * the 32-bit wide access consists of. Also three control signals can be
- * adjusted individually.
- */
-#define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
-/* The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable and DQSN */
-#define WR_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 4)
-/*
- * The eight data lines (DQn) plus DM, DQS, DQS/DM/DQ Output Enable, DQSN,
- * Termination and Power down
- */
-#define RD_LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 6)
-struct dram_para {
-	u32 clk;
-	enum sunxi_dram_type type;
-	u8 cols;
-	u8 rows;
-	u8 ranks;
-	const u8 dx_read_delays[NR_OF_BYTE_LANES][RD_LINES_PER_BYTE_LANE];
-	const u8 dx_write_delays[NR_OF_BYTE_LANES][WR_LINES_PER_BYTE_LANE];
-};
-
 static void mctl_sys_init(struct dram_para *para);
 static void mctl_com_init(struct dram_para *para);
-static void mctl_set_timing_lpddr3(struct dram_para *para);
 static void mctl_channel_init(struct dram_para *para);
 
 static void mctl_core_init(struct dram_para *para)
@@ -67,7 +42,7 @@
 	mctl_com_init(para);
 	switch (para->type) {
 	case SUNXI_DRAM_TYPE_LPDDR3:
-		mctl_set_timing_lpddr3(para);
+		mctl_set_timing_params(para);
 		break;
 	default:
 		panic("Unsupported DRAM type!");
@@ -171,127 +146,6 @@
 	MBUS_CONF(HDCP2,  true,    HIGH, 2,  100,   64,   32);
 }
 
-static u32 mr_lpddr3[12] = {
-	0x00000000, 0x00000043, 0x0000001a, 0x00000001,
-	0x00000000, 0x00000000, 0x00000048, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000003,
-};
-
-/* TODO: flexible timing */
-static void mctl_set_timing_lpddr3(struct dram_para *para)
-{
-	struct sunxi_mctl_ctl_reg * const mctl_ctl =
-			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
-	struct sunxi_mctl_phy_reg * const mctl_phy =
-			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
-	int i;
-
-	u8 tccd		= 2;
-	u8 tfaw		= max(ns_to_t(50), 4);
-	u8 trrd		= max(ns_to_t(10), 2);
-	u8 trcd		= max(ns_to_t(24), 2);
-	u8 trc		= ns_to_t(70);
-	u8 txp		= max(ns_to_t(8), 2);
-	u8 twtr		= max(ns_to_t(8), 2);
-	u8 trtp		= max(ns_to_t(8), 2);
-	u8 twr		= max(ns_to_t(15), 2);
-	u8 trp		= ns_to_t(18);
-	u8 tras		= ns_to_t(42);
-	u8 twtr_sa	= ns_to_t(5);
-	u8 tcksrea	= ns_to_t(11);
-	u16 trefi	= ns_to_t(3900) / 32;
-	u16 trfc	= ns_to_t(210);
-	u16 txsr	= ns_to_t(220);
-
-	if (CONFIG_DRAM_CLK % 400 == 0) {
-		/* Round up these parameters */
-		twtr_sa++;
-		tcksrea++;
-	}
-
-	u8 tmrw		= 5;
-	u8 tmrd		= 5;
-	u8 tmod		= 12;
-	u8 tcke		= 3;
-	u8 tcksrx	= 5;
-	u8 tcksre	= 5;
-	u8 tckesr	= 5;
-	u8 trasmax	= CONFIG_DRAM_CLK / 60;
-	u8 txs		= 4;
-	u8 txsdll	= 4;
-	u8 txsabort	= 4;
-	u8 txsfast	= 4;
-
-	u8 tcl		= 5; /* CL 10 */
-	u8 tcwl		= 3; /* CWL 6 */
-	u8 t_rdata_en	= twtr_sa + 8;
-
-	u32 tdinit0	= (200 * CONFIG_DRAM_CLK) + 1;		/* 200us */
-	u32 tdinit1	= (100 * CONFIG_DRAM_CLK) / 1000 + 1;	/* 100ns */
-	u32 tdinit2	= (11 * CONFIG_DRAM_CLK) + 1;		/* 11us */
-	u32 tdinit3	= (1 * CONFIG_DRAM_CLK) + 1;		/* 1us */
-
-	u8 twtp		= tcwl + 4 + twr + 1;
-	/*
-	 * The code below for twr2rd and trd2wr follows the IP core's
-	 * document from ZynqMP and i.MX7. The BSP has both number
-	 * substracted by 2.
-	 */
-	u8 twr2rd	= tcwl + 4 + 1 + twtr;
-	u8 trd2wr	= tcl + 4 + (tcksrea >> 1) - tcwl + 1;
-
-	/* set mode registers */
-	for (i = 0; i < ARRAY_SIZE(mr_lpddr3); i++)
-		writel(mr_lpddr3[i], &mctl_phy->mr[i]);
-
-	/* set DRAM timing */
-	writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras,
-	       &mctl_ctl->dramtmg[0]);
-	writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]);
-	writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd,
-	       &mctl_ctl->dramtmg[2]);
-	writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]);
-	writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp,
-	       &mctl_ctl->dramtmg[4]);
-	writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke,
-	       &mctl_ctl->dramtmg[5]);
-	/* Value suggested by ZynqMP manual and used by libdram */
-	writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]);
-	writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs,
-	       &mctl_ctl->dramtmg[8]);
-	writel(txsr, &mctl_ctl->dramtmg[14]);
-
-	clrsetbits_le32(&mctl_ctl->init[0], (3 << 30), (1 << 30));
-	writel(0, &mctl_ctl->dfimisc);
-	clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
-
-	/*
-	 * Set timing registers of the PHY.
-	 * Note: the PHY is clocked 2x from the DRAM frequency.
-	 */
-	writel((trrd << 25) | (tras << 17) | (trp << 9) | (trtp << 1),
-	       &mctl_phy->dtpr[0]);
-	writel((tfaw << 17) | 0x28000400 | (tmrd << 1), &mctl_phy->dtpr[1]);
-	writel(((txs << 6) - 1) | (tcke << 17), &mctl_phy->dtpr[2]);
-	writel(((txsdll << 22) - (0x1 << 16)) | twtr_sa | (tcksrea << 8),
-	       &mctl_phy->dtpr[3]);
-	writel((txp << 1) | (trfc << 17) | 0x800, &mctl_phy->dtpr[4]);
-	writel((trc << 17) | (trcd << 9) | (twtr << 1), &mctl_phy->dtpr[5]);
-	writel(0x0505, &mctl_phy->dtpr[6]);
-
-	/* Configure DFI timing */
-	writel(tcl | 0x2000200 | (t_rdata_en << 16) | 0x808000,
-	       &mctl_ctl->dfitmg0);
-	writel(0x040201, &mctl_ctl->dfitmg1);
-
-	/* Configure PHY timing */
-	writel(tdinit0 | (tdinit1 << 20), &mctl_phy->ptr[3]);
-	writel(tdinit2 | (tdinit3 << 18), &mctl_phy->ptr[4]);
-
-	/* set refresh timing */
-	writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
-}
-
 static void mctl_sys_init(struct dram_para *para)
 {
 	struct sunxi_ccm_reg * const ccm =
@@ -735,12 +589,14 @@
 			(struct sunxi_mctl_com_reg *)SUNXI_DRAM_COM_BASE;
 	struct dram_para para = {
 		.clk = CONFIG_DRAM_CLK,
+#ifdef CONFIG_SUNXI_DRAM_H6_LPDDR3
 		.type = SUNXI_DRAM_TYPE_LPDDR3,
 		.ranks = 2,
 		.cols = 11,
 		.rows = 14,
 		.dx_read_delays  = SUN50I_H6_DX_READ_DELAYS,
 		.dx_write_delays = SUN50I_H6_DX_WRITE_DELAYS,
+#endif
 	};
 
 	unsigned long size;
diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile
index 278a8a1..0886a95 100644
--- a/arch/arm/mach-sunxi/dram_timings/Makefile
+++ b/arch/arm/mach-sunxi/dram_timings/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_SUNXI_DRAM_DDR3_1333)	+= ddr3_1333.o
 obj-$(CONFIG_SUNXI_DRAM_LPDDR3_STOCK)	+= lpddr3_stock.o
 obj-$(CONFIG_SUNXI_DRAM_DDR2_V3S)	+= ddr2_v3s.o
+obj-$(CONFIG_SUNXI_DRAM_H6_LPDDR3)	+= h6_lpddr3.o
diff --git a/arch/arm/mach-sunxi/dram_timings/h6_lpddr3.c b/arch/arm/mach-sunxi/dram_timings/h6_lpddr3.c
new file mode 100644
index 0000000..1000860
--- /dev/null
+++ b/arch/arm/mach-sunxi/dram_timings/h6_lpddr3.c
@@ -0,0 +1,132 @@
+/*
+ * sun50i H6 LPDDR3 timings
+ *
+ * (C) Copyright 2017      Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/dram.h>
+#include <asm/arch/cpu.h>
+
+static u32 mr_lpddr3[12] = {
+	0x00000000, 0x00000043, 0x0000001a, 0x00000001,
+	0x00000000, 0x00000000, 0x00000048, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000003,
+};
+
+/* TODO: flexible timing */
+void mctl_set_timing_params(struct dram_para *para)
+{
+	struct sunxi_mctl_ctl_reg * const mctl_ctl =
+			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
+	struct sunxi_mctl_phy_reg * const mctl_phy =
+			(struct sunxi_mctl_phy_reg *)SUNXI_DRAM_PHY0_BASE;
+	int i;
+
+	u8 tccd		= 2;
+	u8 tfaw		= max(ns_to_t(50), 4);
+	u8 trrd		= max(ns_to_t(10), 2);
+	u8 trcd		= max(ns_to_t(24), 2);
+	u8 trc		= ns_to_t(70);
+	u8 txp		= max(ns_to_t(8), 2);
+	u8 twtr		= max(ns_to_t(8), 2);
+	u8 trtp		= max(ns_to_t(8), 2);
+	u8 twr		= max(ns_to_t(15), 2);
+	u8 trp		= ns_to_t(18);
+	u8 tras		= ns_to_t(42);
+	u8 twtr_sa	= ns_to_t(5);
+	u8 tcksrea	= ns_to_t(11);
+	u16 trefi	= ns_to_t(3900) / 32;
+	u16 trfc	= ns_to_t(210);
+	u16 txsr	= ns_to_t(220);
+
+	if (CONFIG_DRAM_CLK % 400 == 0) {
+		/* Round up these parameters */
+		twtr_sa++;
+		tcksrea++;
+	}
+
+	u8 tmrw		= 5;
+	u8 tmrd		= 5;
+	u8 tmod		= 12;
+	u8 tcke		= 3;
+	u8 tcksrx	= 5;
+	u8 tcksre	= 5;
+	u8 tckesr	= 5;
+	u8 trasmax	= CONFIG_DRAM_CLK / 60;
+	u8 txs		= 4;
+	u8 txsdll	= 4;
+	u8 txsabort	= 4;
+	u8 txsfast	= 4;
+
+	u8 tcl		= 5; /* CL 10 */
+	u8 tcwl		= 3; /* CWL 6 */
+	u8 t_rdata_en	= twtr_sa + 8;
+
+	u32 tdinit0	= (200 * CONFIG_DRAM_CLK) + 1;		/* 200us */
+	u32 tdinit1	= (100 * CONFIG_DRAM_CLK) / 1000 + 1;	/* 100ns */
+	u32 tdinit2	= (11 * CONFIG_DRAM_CLK) + 1;		/* 11us */
+	u32 tdinit3	= (1 * CONFIG_DRAM_CLK) + 1;		/* 1us */
+
+	u8 twtp		= tcwl + 4 + twr + 1;
+	/*
+	 * The code below for twr2rd and trd2wr follows the IP core's
+	 * document from ZynqMP and i.MX7. The BSP has both number
+	 * substracted by 2.
+	 */
+	u8 twr2rd	= tcwl + 4 + 1 + twtr;
+	u8 trd2wr	= tcl + 4 + (tcksrea >> 1) - tcwl + 1;
+
+	/* set mode registers */
+	for (i = 0; i < ARRAY_SIZE(mr_lpddr3); i++)
+		writel(mr_lpddr3[i], &mctl_phy->mr[i]);
+
+	/* set DRAM timing */
+	writel((twtp << 24) | (tfaw << 16) | (trasmax << 8) | tras,
+	       &mctl_ctl->dramtmg[0]);
+	writel((txp << 16) | (trtp << 8) | trc, &mctl_ctl->dramtmg[1]);
+	writel((tcwl << 24) | (tcl << 16) | (trd2wr << 8) | twr2rd,
+	       &mctl_ctl->dramtmg[2]);
+	writel((tmrw << 20) | (tmrd << 12) | tmod, &mctl_ctl->dramtmg[3]);
+	writel((trcd << 24) | (tccd << 16) | (trrd << 8) | trp,
+	       &mctl_ctl->dramtmg[4]);
+	writel((tcksrx << 24) | (tcksre << 16) | (tckesr << 8) | tcke,
+	       &mctl_ctl->dramtmg[5]);
+	/* Value suggested by ZynqMP manual and used by libdram */
+	writel((txp + 2) | 0x02020000, &mctl_ctl->dramtmg[6]);
+	writel((txsfast << 24) | (txsabort << 16) | (txsdll << 8) | txs,
+	       &mctl_ctl->dramtmg[8]);
+	writel(txsr, &mctl_ctl->dramtmg[14]);
+
+	clrsetbits_le32(&mctl_ctl->init[0], (3 << 30), (1 << 30));
+	writel(0, &mctl_ctl->dfimisc);
+	clrsetbits_le32(&mctl_ctl->rankctl, 0xff0, 0x660);
+
+	/*
+	 * Set timing registers of the PHY.
+	 * Note: the PHY is clocked 2x from the DRAM frequency.
+	 */
+	writel((trrd << 25) | (tras << 17) | (trp << 9) | (trtp << 1),
+	       &mctl_phy->dtpr[0]);
+	writel((tfaw << 17) | 0x28000400 | (tmrd << 1), &mctl_phy->dtpr[1]);
+	writel(((txs << 6) - 1) | (tcke << 17), &mctl_phy->dtpr[2]);
+	writel(((txsdll << 22) - (0x1 << 16)) | twtr_sa | (tcksrea << 8),
+	       &mctl_phy->dtpr[3]);
+	writel((txp << 1) | (trfc << 17) | 0x800, &mctl_phy->dtpr[4]);
+	writel((trc << 17) | (trcd << 9) | (twtr << 1), &mctl_phy->dtpr[5]);
+	writel(0x0505, &mctl_phy->dtpr[6]);
+
+	/* Configure DFI timing */
+	writel(tcl | 0x2000200 | (t_rdata_en << 16) | 0x808000,
+	       &mctl_ctl->dfitmg0);
+	writel(0x040201, &mctl_ctl->dfitmg1);
+
+	/* Configure PHY timing */
+	writel(tdinit0 | (tdinit1 << 20), &mctl_phy->ptr[3]);
+	writel(tdinit2 | (tdinit3 << 18), &mctl_phy->ptr[4]);
+
+	/* set refresh timing */
+	writel((trefi << 16) | trfc, &mctl_ctl->rfshtmg);
+}
diff --git a/configs/beelink_gs1_defconfig b/configs/beelink_gs1_defconfig
index f5de850..eec4edd 100644
--- a/configs/beelink_gs1_defconfig
+++ b/configs/beelink_gs1_defconfig
@@ -3,6 +3,7 @@
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SPL=y
 CONFIG_MACH_SUN50I_H6=y
+CONFIG_SUNXI_DRAM_H6_LPDDR3=y
 CONFIG_MMC0_CD_PIN="PF6"
 CONFIG_MMC_SUNXI_SLOT_EXTRA=2
 # CONFIG_PSCI_RESET is not set
diff --git a/configs/orangepi_lite2_defconfig b/configs/orangepi_lite2_defconfig
index f6d023e..2d74fc4 100644
--- a/configs/orangepi_lite2_defconfig
+++ b/configs/orangepi_lite2_defconfig
@@ -3,6 +3,7 @@
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SPL=y
 CONFIG_MACH_SUN50I_H6=y
+CONFIG_SUNXI_DRAM_H6_LPDDR3=y
 CONFIG_MMC0_CD_PIN="PF6"
 # CONFIG_PSCI_RESET is not set
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
diff --git a/configs/orangepi_one_plus_defconfig b/configs/orangepi_one_plus_defconfig
index a9d560a..3737ecd 100644
--- a/configs/orangepi_one_plus_defconfig
+++ b/configs/orangepi_one_plus_defconfig
@@ -3,6 +3,7 @@
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SPL=y
 CONFIG_MACH_SUN50I_H6=y
+CONFIG_SUNXI_DRAM_H6_LPDDR3=y
 CONFIG_MMC0_CD_PIN="PF6"
 # CONFIG_PSCI_RESET is not set
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
diff --git a/configs/pine_h64_defconfig b/configs/pine_h64_defconfig
index 5fa279f..a49bd66 100644
--- a/configs/pine_h64_defconfig
+++ b/configs/pine_h64_defconfig
@@ -3,6 +3,7 @@
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SPL=y
 CONFIG_MACH_SUN50I_H6=y
+CONFIG_SUNXI_DRAM_H6_LPDDR3=y
 CONFIG_MMC0_CD_PIN="PF6"
 CONFIG_MMC_SUNXI_SLOT_EXTRA=2
 # CONFIG_PSCI_RESET is not set