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

Jernej Škrabec jernej.skrabec at siol.net
Wed Jun 19 15:54:15 UTC 2019


Hi!

Dne sreda, 19. junij 2019 ob 03:11:06 CEST je Andre Przywara napisal(a):
> 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 
*/

You should make a define for BIT(28).

> +	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");

If we go this route, you should also add LPDDR2 or just generalize this 
message and remove "if".

Best regards,
Jernej

> +	}
>  	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






More information about the U-Boot mailing list