[U-Boot] [PATCH 04/14] sunxi: dram: Code cleanup and comments for the CKE delay handling

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


Before driving the CKE pin (Clock Enable) high, the DDR3 spec requires
to wait for additional 500 us after the RESET pin is de-asserted.

The DRAM controller takes care of this delay by itself, using a
configurable counter in the SDR_IDCR register. This works in the same
way on sun4i/sun5i/sun7i hardware (even the default register value
0x00c80064 is identical). Except that the counter is ticking a bit
slower on sun7i (3 DRAM clock cycles instead of 2), resulting in
longer actual delays for the same settings.

This patch keeps the old code and only removes the CONFIG_SUN7I ifdef.
But maybe we should drop all of this and just add 'udelay(500)' after
the DDR3 reset without bothering to play with these undocumented
registers.

Another interesting observation is that the u-boot-sunxi code (derived
from the Allwinner boot0) did not configure the SDR_IDCR register
for sun4i/sun5i, but performed the DDR3 reset very early. Possibly
resulting in a sufficient time gap between the DDR3 reset and the DDR3
initialization steps.

Signed-off-by: Siarhei Siamashka <siarhei.siamashka at gmail.com>
---
 arch/arm/cpu/armv7/sunxi/dram.c | 45 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c
index 01c492f..def4247 100644
--- a/arch/arm/cpu/armv7/sunxi/dram.c
+++ b/arch/arm/cpu/armv7/sunxi/dram.c
@@ -318,6 +318,41 @@ static void mctl_disable_power_save(void)
 	writel(0x16510000, &dram->ppwrsctl);
 }
 
+/*
+ * After the DRAM is powered up or reset, the DDR3 spec requires to wait at
+ * least 500 us before driving the CKE pin (Clock Enable) high. The dram->idct
+ * (SDR_IDCR) register appears to configure this delay, which gets applied
+ * right at the time when the DRAM initialization is activated in the
+ * 'mctl_ddr3_initialize' function.
+ */
+static void mctl_set_cke_delay(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+
+	/* The CKE delay is represented in dram clock cycles, multiplied by N
+	 * (where N=2 for sun4i/sun5i and N=3 for sun7i). We are being lazy
+	 * to do proper calculations and just set it to the maximum possible
+	 * value 0x1ffff. This is enough to provide the needed 500 us delay
+	 * at the DRAM clock freqencies up to ~524MHz on sun4i/sun5i hardware.
+	 * The sun7i hardware has even more headroom due to a larger multiplier.
+	 */
+	setbits_le32(&dram->idcr, 0x1ffff);
+}
+
+/*
+ * This triggers the DRAM initialization. It performs sending the mode registers
+ * to the DRAM among other things. Very likely the ZQCL command is also getting
+ * executed (to do the initial impedance calibration on the DRAM side of the
+ * wire). The memory controller and the PHY must be already configured before
+ * calling this function.
+ */
+static void mctl_ddr3_initialize(void)
+{
+	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
+	setbits_le32(&dram->ccr, DRAM_CCR_INIT);
+	await_completion(&dram->ccr, DRAM_CCR_INIT);
+}
+
 unsigned long dramc_init(struct dram_para *para)
 {
 	struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE;
@@ -387,10 +422,7 @@ unsigned long dramc_init(struct dram_para *para)
 	writel(reg_val, &dram->zqcr0);
 #endif
 
-#ifdef CONFIG_SUN7I
-	/* Set CKE Delay to about 1ms */
-	setbits_le32(&dram->idcr, 0x1ffff);
-#endif
+	mctl_set_cke_delay();
 
 	mctl_ddr3_reset();
 
@@ -434,9 +466,8 @@ unsigned long dramc_init(struct dram_para *para)
 	if (para->tpr4 & 0x1)
 		setbits_le32(&dram->ccr, DRAM_CCR_COMMAND_RATE_1T);
 #endif
-	/* reset external DRAM */
-	setbits_le32(&dram->ccr, DRAM_CCR_INIT);
-	await_completion(&dram->ccr, DRAM_CCR_INIT);
+	/* initialize external DRAM */
+	mctl_ddr3_initialize();
 
 	/* scan read pipe value */
 	mctl_itm_enable();
-- 
1.8.3.2



More information about the U-Boot mailing list