[U-Boot] [PATCH v4 16/26] sunxi: H3: add DRAM controller single bit delay support

Andre Przywara andre.przywara at arm.com
Mon Jan 2 12:48:40 CET 2017


From: Jens Kuske <jenskuske at gmail.com>

So far the DRAM driver for the H3 SoC (and apparently boot0/libdram as
well) only applied coarse delay line settings, with one delay value for
all the data lines in each byte lane and one value for the control lines.

Instead of setting the delays for whole bytes only allow setting it for
each individual bit. Also add support for address/command lane delays.

For the purpose of this patch the rules for the existing coarse settings
were just applied to the new scheme, so the actual register writes don't
change for the H3. Other SoCs will utilize this feature later properly.

With a stock GCC 5.3.0 this increases the dram_sun8i_h3.o code size from
2296 to 2344 Bytes.

[Andre: move delay parameters into macros to ease later sharing, use
	defines for numbers of delay registers, extend commit message]

Signed-off-by: Jens Kuske <jenskuske at gmail.com>
Signed-off-by: Andre Przywara <andre.przywara at arm.com>
---
 arch/arm/mach-sunxi/dram_sun8i_h3.c | 77 ++++++++++++++++++++++++-------------
 1 file changed, 50 insertions(+), 27 deletions(-)

diff --git a/arch/arm/mach-sunxi/dram_sun8i_h3.c b/arch/arm/mach-sunxi/dram_sun8i_h3.c
index 539268f..4396754 100644
--- a/arch/arm/mach-sunxi/dram_sun8i_h3.c
+++ b/arch/arm/mach-sunxi/dram_sun8i_h3.c
@@ -15,13 +15,24 @@
 #include <asm/arch/dram.h>
 #include <linux/kconfig.h>
 
+/*
+ * 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 BITS_PER_BYTE		8
+#define NR_OF_BYTE_LANES	(32 / BITS_PER_BYTE)
+/* The eight data lines (DQn) plus DM, DQS and DQSN */
+#define LINES_PER_BYTE_LANE	(BITS_PER_BYTE + 3)
 struct dram_para {
-	u32 read_delays;
-	u32 write_delays;
 	u16 page_size;
 	u8 bus_width;
 	u8 dual_rank;
 	u8 row_bits;
+	const u8 dx_read_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
+	const u8 dx_write_delays[NR_OF_BYTE_LANES][LINES_PER_BYTE_LANE];
+	const u8 ac_delays[31];
 };
 
 static inline int ns_to_t(int nanoseconds)
@@ -64,34 +75,25 @@ static void mctl_phy_init(u32 val)
 	mctl_await_completion(&mctl_ctl->pgsr[0], PGSR_INIT_DONE, 0x1);
 }
 
-static void mctl_dq_delay(u32 read, u32 write)
+static void mctl_set_bit_delays(struct dram_para *para)
 {
 	struct sunxi_mctl_ctl_reg * const mctl_ctl =
 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
 	int i, j;
-	u32 val;
-
-	for (i = 0; i < 4; i++) {
-		val = DXBDLR_WRITE_DELAY((write >> (i * 4)) & 0xf) |
-		      DXBDLR_READ_DELAY(((read >> (i * 4)) & 0xf) * 2);
-
-		for (j = DXBDLR_DQ(0); j <= DXBDLR_DM; j++)
-			writel(val, &mctl_ctl->dx[i].bdlr[j]);
-	}
 
 	clrbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
 
-	for (i = 0; i < 4; i++) {
-		val = DXBDLR_WRITE_DELAY((write >> (16 + i * 4)) & 0xf) |
-		      DXBDLR_READ_DELAY((read >> (16 + i * 4)) & 0xf);
+	for (i = 0; i < NR_OF_BYTE_LANES; i++)
+		for (j = 0; j < LINES_PER_BYTE_LANE; j++)
+			writel(DXBDLR_WRITE_DELAY(para->dx_write_delays[i][j]) |
+			       DXBDLR_READ_DELAY(para->dx_read_delays[i][j]),
+			       &mctl_ctl->dx[i].bdlr[j]);
 
-		writel(val, &mctl_ctl->dx[i].bdlr[DXBDLR_DQS]);
-		writel(val, &mctl_ctl->dx[i].bdlr[DXBDLR_DQSN]);
-	}
+	for (i = 0; i < 31; i++)
+		writel(ACBDLR_WRITE_DELAY(para->ac_delays[i]),
+		       &mctl_ctl->acbdlr[i]);
 
 	setbits_le32(&mctl_ctl->pgcr[0], 1 << 26);
-
-	udelay(1);
 }
 
 enum {
@@ -412,11 +414,8 @@ static int mctl_channel_init(struct dram_para *para)
 	clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24,
 			(para->dual_rank ? 0x3 : 0x1) << 24);
 
-
-	if (para->read_delays || para->write_delays) {
-		mctl_dq_delay(para->read_delays, para->write_delays);
-		udelay(50);
-	}
+	mctl_set_bit_delays(para);
+	udelay(50);
 
 	mctl_zq_calibration(para);
 
@@ -490,6 +489,29 @@ static void mctl_auto_detect_dram_size(struct dram_para *para)
 			break;
 }
 
+/*
+ * The actual values used here are taken from Allwinner provided boot0
+ * binaries, though they are probably board specific, so would likely benefit
+ * from invidual tuning for each board. Apparently a lot of boards copy from
+ * some Allwinner reference design, so we go with those generic values for now
+ * in the hope that they are reasonable for most (all?) boards.
+ */
+#define SUN8I_H3_DX_READ_DELAYS					\
+	{{ 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
+	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 },	\
+	 { 18, 18, 18, 18, 18, 18, 18, 18, 18,  0,  0 },	\
+	 { 14, 14, 14, 14, 14, 14, 14, 14, 14,  0,  0 }}
+#define SUN8I_H3_DX_WRITE_DELAYS				\
+	{{  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
+	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
+	 {  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 10 },	\
+	 {  0,  0,  0,  0,  0,  0,  0,  0,  0,  6,  6 }}
+#define SUN8I_H3_AC_DELAYS					\
+	{  0,  0,  0,  0,  0,  0,  0,  0,			\
+	   0,  0,  0,  0,  0,  0,  0,  0,			\
+	   0,  0,  0,  0,  0,  0,  0,  0,			\
+	   0,  0,  0,  0,  0,  0,  0      }
+
 unsigned long sunxi_dram_init(void)
 {
 	struct sunxi_mctl_com_reg * const mctl_com =
@@ -498,12 +520,13 @@ unsigned long sunxi_dram_init(void)
 			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
 
 	struct dram_para para = {
-		.read_delays = 0x00007979,	/* dram_tpr12 */
-		.write_delays = 0x6aaa0000,	/* dram_tpr11 */
 		.dual_rank = 0,
 		.bus_width = 32,
 		.row_bits = 15,
 		.page_size = 4096,
+		.dx_read_delays  = SUN8I_H3_DX_READ_DELAYS,
+		.dx_write_delays = SUN8I_H3_DX_WRITE_DELAYS,
+		.ac_delays	 = SUN8I_H3_AC_DELAYS,
 	};
 
 	mctl_sys_init(&para);
-- 
2.8.2



More information about the U-Boot mailing list