[U-Boot] [PATCH 4/7] sunxi: H6: Add DDR3 support to DRAM controller driver

Andre Przywara andre.przywara at arm.com
Wed Jun 19 01:11:06 UTC 2019


At the moment the H6 DRAM driver only supports LPDDR3 DRAM.

Extend the driver to cover DDR3 DRAM as well.

The changes are partly motivated by looking at the ZynqMP register
documentation, partly by looking at register dumps after boot0/libdram
has initialised the controller.

Many thanks to Jernej for contributing some fixes!

Signed-off-by: Andre Przywara <andre.przywara at arm.com>
---
 arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h |  7 +++
 arch/arm/mach-sunxi/dram_sun50i_h6.c             | 71 +++++++++++++++++-------
 2 files changed, 57 insertions(+), 21 deletions(-)

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 b28ae583c9..8b8085611f 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h6.h
@@ -9,6 +9,8 @@
 #ifndef _SUNXI_DRAM_SUN50I_H6_H
 #define _SUNXI_DRAM_SUN50I_H6_H
 
+#include <stdbool.h>
+
 enum sunxi_dram_type {
 	SUNXI_DRAM_TYPE_DDR3 = 3,
 	SUNXI_DRAM_TYPE_DDR4,
@@ -16,6 +18,11 @@ enum sunxi_dram_type {
 	SUNXI_DRAM_TYPE_LPDDR3,
 };
 
+static inline bool sunxi_dram_is_lpddr(int type)
+{
+	return type >= SUNXI_DRAM_TYPE_LPDDR2;
+}
+
 /*
  * The following information is mainly retrieved by disassembly and some FPGA
  * test code of sun50iw3 platform.
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c
index 697b8af4ce..0436265bdb 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
@@ -42,6 +42,7 @@ static void mctl_core_init(struct dram_para *para)
 	mctl_com_init(para);
 	switch (para->type) {
 	case SUNXI_DRAM_TYPE_LPDDR3:
+	case SUNXI_DRAM_TYPE_DDR3:
 		mctl_set_timing_params(para);
 		break;
 	default:
@@ -302,22 +303,37 @@ static void mctl_com_init(struct dram_para *para)
 		reg_val = 0x3f00;
 	clrsetbits_le32(&mctl_com->unk_0x008, 0x3f00, reg_val);
 
-	/* TODO: half DQ, non-LPDDR3 types */
-	writel(MSTR_DEVICETYPE_LPDDR3 | MSTR_BUSWIDTH_FULL |
-	       MSTR_BURST_LENGTH(8) | MSTR_ACTIVE_RANKS(para->ranks) |
-	       0x80000000, &mctl_ctl->mstr);
-	writel(DCR_LPDDR3 | DCR_DDR8BANK | 0x400, &mctl_phy->dcr);
+	/* TODO: half DQ, DDR4 */
+	reg_val = MSTR_BUSWIDTH_FULL | MSTR_BURST_LENGTH(8) |
+		  MSTR_ACTIVE_RANKS(para->ranks);
+	if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
+		reg_val |= MSTR_DEVICETYPE_LPDDR3;
+	if (para->type == SUNXI_DRAM_TYPE_DDR3)
+		reg_val |= MSTR_DEVICETYPE_DDR3 | MSTR_2TMODE;
+	writel(reg_val | BIT(31), &mctl_ctl->mstr);
+
+	if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
+		reg_val = DCR_LPDDR3 | DCR_DDR8BANK;
+	if (para->type == SUNXI_DRAM_TYPE_DDR3)
+		reg_val = DCR_DDR3 | DCR_DDR8BANK | BIT(28); /* 2T mode */
+	writel(reg_val | 0x400, &mctl_phy->dcr);
 
 	if (para->ranks == 2)
 		writel(0x0303, &mctl_ctl->odtmap);
 	else
 		writel(0x0201, &mctl_ctl->odtmap);
 
-	/* TODO: non-LPDDR3 types */
-	tmp = para->clk * 7 / 2000;
-	reg_val = 0x0400;
-	reg_val |= (tmp + 7) << 24;
-	reg_val |= (((para->clk < 400) ? 3 : 4) - tmp) << 16;
+	/* TODO: DDR4 */
+	if (para->type == SUNXI_DRAM_TYPE_LPDDR3) {
+		tmp = para->clk * 7 / 2000;
+		reg_val = 0x0400;
+		reg_val |= (tmp + 7) << 24;
+		reg_val |= (((para->clk < 400) ? 3 : 4) - tmp) << 16;
+	} else if (para->type == SUNXI_DRAM_TYPE_DDR3) {
+		reg_val = 0x06000400;	/* TODO?: Use CL - CWL value in [7:0] */
+	} else if (para->type == SUNXI_DRAM_TYPE_DDR4) {
+		panic("DDR4 not yet supported\n");
+	}
 	writel(reg_val, &mctl_ctl->odtcfg);
 
 	/* TODO: half DQ */
@@ -372,6 +388,9 @@ static void mctl_bit_delay_set(struct dram_para *para)
 	setbits_le32(&mctl_phy->pgcr[0], BIT(26));
 	udelay(1);
 
+	if (para->type != SUNXI_DRAM_TYPE_LPDDR3)
+		return;
+
 	for (i = 1; i < 14; i++) {
 		val = readl(&mctl_phy->acbdlr[i]);
 		val += 0x0a0a0a0a;
@@ -419,7 +438,8 @@ static void mctl_channel_init(struct dram_para *para)
 	else
 		clrsetbits_le32(&mctl_phy->dtcr[1], 0x30000, 0x10000);
 
-	clrbits_le32(&mctl_phy->dtcr[1], BIT(1));
+	if (sunxi_dram_is_lpddr(para->type))
+		clrbits_le32(&mctl_phy->dtcr[1], BIT(1));
 	if (para->ranks == 2) {
 		writel(0x00010001, &mctl_phy->rankidr);
 		writel(0x20000, &mctl_phy->odtcr);
@@ -428,8 +448,11 @@ static void mctl_channel_init(struct dram_para *para)
 		writel(0x10000, &mctl_phy->odtcr);
 	}
 
-	/* TODO: non-LPDDR3 types */
-	clrsetbits_le32(&mctl_phy->dtcr[0], 0xF0000000, 0x10000040);
+	/* set bits [3:0] to 1? 0 not valid in ZynqMP d/s */
+	if (para->type == SUNXI_DRAM_TYPE_LPDDR3)
+		clrsetbits_le32(&mctl_phy->dtcr[0], 0xF0000000, 0x10000040);
+	else
+		clrsetbits_le32(&mctl_phy->dtcr[0], 0xF0000000, 0x10000000);
 	if (para->clk <= 792) {
 		if (para->clk <= 672) {
 			if (para->clk <= 600)
@@ -459,12 +482,13 @@ static void mctl_channel_init(struct dram_para *para)
 			writel(0x06060606, &mctl_phy->acbdlr[i]);
 	}
 
-	/* TODO: non-LPDDR3 types */
-	mctl_phy_pir_init(PIR_ZCAL | PIR_DCAL | PIR_PHYRST | PIR_DRAMINIT |
-			  PIR_QSGATE | PIR_RDDSKW | PIR_WRDSKW | PIR_RDEYE |
-			  PIR_WREYE);
+	val = PIR_ZCAL | PIR_DCAL | PIR_PHYRST | PIR_DRAMINIT | PIR_QSGATE |
+	      PIR_RDDSKW | PIR_WRDSKW | PIR_RDEYE | PIR_WREYE;
+	if (para->type == SUNXI_DRAM_TYPE_DDR3)
+		val |= PIR_DRAMRST | PIR_WL;
+	mctl_phy_pir_init(val);
 
-	/* TODO: non-LPDDR3 types */
+	/* TODO: DDR4 types ? */
 	for (i = 0; i < 4; i++)
 		writel(0x00000909, &mctl_phy->dx[i].gcr[5]);
 
@@ -520,7 +544,8 @@ static void mctl_channel_init(struct dram_para *para)
 		panic("Error while initializing DRAM PHY!\n");
 	}
 
-	clrsetbits_le32(&mctl_phy->dsgcr, 0xc0, 0x40);
+	if (sunxi_dram_is_lpddr(para->type))
+		clrsetbits_le32(&mctl_phy->dsgcr, 0xc0, 0x40);
 	clrbits_le32(&mctl_phy->pgcr[1], 0x40);
 	clrbits_le32(&mctl_ctl->dfimisc, BIT(0));
 	writel(1, &mctl_ctl->swctl);
@@ -589,11 +614,15 @@ unsigned long sunxi_dram_init(void)
 			(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,
+#ifdef CONFIG_SUNXI_DRAM_H6_LPDDR3
+		.type = SUNXI_DRAM_TYPE_LPDDR3,
+		.dx_read_delays  = SUN50I_H6_DX_READ_DELAYS,
+		.dx_write_delays = SUN50I_H6_DX_WRITE_DELAYS,
+#elif defined(CONFIG_SUNXI_DRAM_H6_DDR3_1333)
+		.type = SUNXI_DRAM_TYPE_DDR3,
 		.dx_read_delays  = SUN50I_H6_DX_READ_DELAYS,
 		.dx_write_delays = SUN50I_H6_DX_WRITE_DELAYS,
 #endif
-- 
2.14.5



More information about the U-Boot mailing list