[U-Boot] [PATCH 05/14] sunxi: dram: Code cleanup for the impedance calibration

Siarhei Siamashka siarhei.siamashka at gmail.com
Fri Jul 18 18:22:56 CEST 2014


Moved the impedance setup code part into a separate function. Added explicit
wait for ZQ calibration completion before proceeding to the next initialization
steps. Removed the CONFIG_SUN7I ifdef guard around the code, which has identical
behaviour on sun4i/sun5i/sun7i. And if 'odt_en' is set in the 'dram_para' struct,
then ODT now actually gets enabled in the DRAM_IOCR register (which the older
code failed to do and was always running without ODT no matter the settings).

Signed-off-by: Siarhei Siamashka <siarhei.siamashka at gmail.com>
---
 arch/arm/cpu/armv7/sunxi/dram.c        | 71 ++++++++++++++++++++++++++++------
 arch/arm/include/asm/arch-sunxi/dram.h |  4 ++
 2 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c
index def4247..afeb2df 100644
--- a/arch/arm/cpu/armv7/sunxi/dram.c
+++ b/arch/arm/cpu/armv7/sunxi/dram.c
@@ -49,6 +49,19 @@ static void await_completion(u32 *reg, u32 mask)
 }
 
 /*
+ * Wait up to 1s for mask to be set in given reg.
+ */
+static void await_bits_set(u32 *reg, u32 mask)
+{
+	unsigned long tmo = timer_get_us() + 1000000;
+
+	while ((readl(reg) & mask) != mask) {
+		if (timer_get_us() > tmo)
+			panic("Timeout initialising DRAM\n");
+	}
+}
+
+/*
  * This performs the external DRAM reset by driving the RESET pin low and
  * then high again. According to the DDR3 spec, the RESET pin needs to be
  * kept low for at least 200 us.
@@ -353,6 +366,51 @@ static void mctl_ddr3_initialize(void)
 	await_completion(&dram->ccr, DRAM_CCR_INIT);
 }
 
+/*
+ * Perform impedance calibration on the DRAM controller side of the wire.
+ */
+static void mctl_set_impedance(u32 zq, u32 odt_en)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	u32 reg_val;
+	u32 zprog = zq & 0xFF, zdata = (zq >> 8) & 0xFFFFF;
+
+#ifndef CONFIG_SUN7I
+	/* wait for the default impedance configuration to settle */
+	await_bits_set(&dram->zqsr, DRAM_ZQSR_ZDONE);
+#endif
+
+	if (!odt_en)
+		return;
+
+#ifdef CONFIG_SUN7I
+	/* some weird magic, but sun7i fails to boot without it */
+	writel((1 << 24) | (1 << 1), &dram->zqcr1);
+#endif
+
+	/* needed at least for sun5i, because it does not self clear there */
+	clrbits_le32(&dram->zqcr0, DRAM_ZQCR0_ZCAL);
+
+	if (zdata) {
+		/* set the user supplied impedance data */
+		reg_val = DRAM_ZQCR0_ZDEN | zdata;
+		writel(reg_val, &dram->zqcr0);
+		/* no need to wait, this takes effect immediately */
+	} else {
+		/* do the calibration using the external resistor */
+		reg_val = DRAM_ZQCR0_ZCAL | DRAM_ZQCR0_IMP_DIV(zprog);
+		writel(reg_val, &dram->zqcr0);
+		/* wait for the new impedance configuration to settle */
+		await_bits_set(&dram->zqsr, DRAM_ZQSR_ZDONE);
+	}
+
+	/* needed at least for sun5i, because it does not self clear there */
+	clrbits_le32(&dram->zqcr0, DRAM_ZQCR0_ZCAL);
+
+	/* set I/O configure register */
+	writel(DRAM_IOCR_ODT_EN(odt_en), &dram->iocr);
+}
+
 unsigned long dramc_init(struct dram_para *para)
 {
 	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
@@ -407,20 +465,9 @@ unsigned long dramc_init(struct dram_para *para)
 	reg_val |= DRAM_DCR_MODE(DRAM_DCR_MODE_INTERLEAVE);
 	writel(reg_val, &dram->dcr);
 
-#ifdef CONFIG_SUN7I
-	setbits_le32(&dram->zqcr1, (0x1 << 24) | (0x1 << 1));
-	if (para->tpr4 & 0x2)
-		clrsetbits_le32(&dram->zqcr1, (0x1 << 24), (0x1 << 1));
 	dramc_clock_output_en(1);
-#endif
 
-#if (defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I))
-	/* set odt impendance divide ratio */
-	reg_val = ((para->zq) >> 8) & 0xfffff;
-	reg_val |= ((para->zq) & 0xff) << 20;
-	reg_val |= (para->zq) & 0xf0000000;
-	writel(reg_val, &dram->zqcr0);
-#endif
+	mctl_set_impedance(para->zq, para->odt_en);
 
 	mctl_set_cke_delay();
 
diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h
index 67fbfad..4433eeb 100644
--- a/arch/arm/include/asm/arch-sunxi/dram.h
+++ b/arch/arm/include/asm/arch-sunxi/dram.h
@@ -159,6 +159,10 @@ struct dram_para {
 
 #define DRAM_ZQCR0_IMP_DIV(n) (((n) & 0xff) << 20)
 #define DRAM_ZQCR0_IMP_DIV_MASK DRAM_ZQCR0_IMP_DIV(0xff)
+#define DRAM_ZQCR0_ZCAL (1 << 31) /* Starts ZQ calibration when set to 1 */
+#define DRAM_ZQCR0_ZDEN (1 << 28) /* Uses ZDATA instead of doing calibration */
+
+#define DRAM_ZQSR_ZDONE (1 << 31) /* ZQ calibration completion flag */
 
 #define DRAM_IOCR_ODT_EN(n) ((((n) & 0x3) << 30) | ((n) & 0x3) << 0)
 #define DRAM_IOCR_ODT_EN_MASK DRAM_IOCR_ODT_EN(0x3)
-- 
1.8.3.2



More information about the U-Boot mailing list