diff options
Diffstat (limited to 'arch/arm/cpu/armv7')
-rw-r--r-- | arch/arm/cpu/armv7/sunxi/dram.c | 57 |
1 files changed, 50 insertions, 7 deletions
diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index a632926fa7..6849952adb 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -78,6 +78,19 @@ static void mctl_ddr3_reset(void) udelay(200); setbits_le32(&dram->mcr, DRAM_MCR_RESET); } + /* After the RESET pin is de-asserted, the DDR3 spec requires to wait + * for additional 500 us before driving the CKE pin (Clock Enable) + * high. The duration of this delay can be configured in the SDR_IDCR + * (Initialization Delay Configuration Register) and applied + * automatically by the DRAM controller during the DDR3 initialization + * step. But SDR_IDCR has limited range on sun4i/sun5i hardware and + * can't provide sufficient delay at DRAM clock frequencies higher than + * 524 MHz (while Allwinner A13 supports DRAM clock frequency up to + * 533 MHz according to the datasheet). Additionally, there is no + * official documentation for the SDR_IDCR register anywhere, and + * there is always a chance that we are interpreting it wrong. + * Better be safe than sorry, so add an explicit delay here. */ + udelay(500); } static void mctl_set_drive(void) @@ -382,6 +395,40 @@ 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). Here it is set to + * the maximum possible value 0x1ffff, just like in the Allwinner's + * boot0 bootloader. The resulting delay value is somewhere between + * ~0.4 ms (sun5i with 648 MHz DRAM clock speed) and ~1.1 ms (sun7i + * with 360 MHz DRAM clock speed). */ + 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; @@ -459,10 +506,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(); #ifdef CONFIG_SUN7I mctl_ddr3_reset(); @@ -527,9 +571,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(); |