[PATCH 2/2] sunxi: enable dual rank memory on R40

Ivan Uvarov i.uvarov at cognitivepilot.com
Fri Feb 26 15:04:54 CET 2021


I have tested this patchset on both OKA40i-C and our custom carrier
board which uses the same SoM (Forlinx FETA40i-C), and can confirm that:
1) It does enable functioning of U-Boot on the FETA40i SoM, and
2) I have not experienced any immediately apparent problems with DRAM in
either U-Boot itself or the loaded OS during my testing.


Tested-by: Ivan Uvarov <i.uvarov at cognitivepilot.com>


On 2/25/21 7:13 PM, Icenowy Zheng wrote:
> Previously we do not have proper dual rank memory detection on R40
> (because we omitted PIR_QSGATE, which does not work on R40 with our
> configuration), and dual rank memory is just simply disabled as early
> R40 boards available (Banana Pi M2 Ultra and Berry) have single rank
> memory.
> 
> As a board with dual rank memory (Forlinx OKA40i-C) is now known to us,
> we need to have a way to do memory rank detection to support that board.
> 
> Add some routine to detect memory rank by trying to access the memory
> in rank 1 and check for error status of the memory controller, and then
> enable dual rank memory on R40.
> 
> Similar routine can be used to detect half DQ width (which is also
> detected by PIR_QSGATE on other SoCs), but it's left unimplemented
> because there's no known R40 board with half DQ width now.
> 
> Signed-off-by: Icenowy Zheng <icenowy at aosc.io>
> ---
>  arch/arm/mach-sunxi/dram_sunxi_dw.c | 55 +++++++++++++++++++++++++----
>  1 file changed, 49 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/mach-sunxi/dram_sunxi_dw.c b/arch/arm/mach-sunxi/dram_sunxi_dw.c
> index 2b9d631d49..b86ae7cdf3 100644
> --- a/arch/arm/mach-sunxi/dram_sunxi_dw.c
> +++ b/arch/arm/mach-sunxi/dram_sunxi_dw.c
> @@ -414,11 +414,9 @@ static void mctl_set_cr(uint16_t socid, struct dram_para *para)
>  	}
>  
>  	if (socid == SOCID_R40) {
> -		if (para->dual_rank)
> -			panic("Dual rank memory not supported\n");
> -
>  		/* Mux pin to A15 address line for single rank memory. */
> -		setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
> +		if (!para->dual_rank)
> +			setbits_le32(&mctl_com->cr_r1, MCTL_CR_R1_MUX_A15);
>  	}
>  }
>  
> @@ -702,8 +700,55 @@ static unsigned long mctl_calc_rank_size(struct rank_para *rank)
>  	return (1UL << (rank->row_bits + rank->bank_bits)) * rank->page_size;
>  }
>  
> +/*
> + * Because we cannot do mctl_phy_init(PIR_QSGATE) on R40 now (which leads
> + * to failure), it's needed to detect the rank count of R40 in another way.
> + *
> + * The code here is modelled after time_out_detect() in BSP, which tries to
> + * access the memory and check for error code.
> + *
> + * TODO: auto detect half DQ width here
> + */
> +static void mctl_r40_detect_rank_count(struct dram_para *para)
> +{
> +	ulong rank1_base = (ulong) CONFIG_SYS_SDRAM_BASE +
> +			   mctl_calc_rank_size(&para->ranks[0]);
> +	struct sunxi_mctl_ctl_reg * const mctl_ctl =
> +			(struct sunxi_mctl_ctl_reg *)SUNXI_DRAM_CTL0_BASE;
> +
> +	/* Enable read time out */
> +	setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
> +
> +	(void) readl((void *) rank1_base);
> +	udelay(10);
> +
> +	if (readl(&mctl_ctl->pgsr[0]) & (0x1 << 13)) {
> +		clrsetbits_le32(&mctl_ctl->dtcr, 0xf << 24, 0x1 << 24);
> +		para->dual_rank = 0;
> +	}
> +
> +	/* Reset PHY FIFO to clear it */
> +	clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
> +	udelay(100);
> +	setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 26);
> +
> +	/* Clear error status */
> +	setbits_le32(&mctl_ctl->pgcr[0], 0x1 << 24);
> +
> +	/* Clear time out flag */
> +	clrbits_le32(&mctl_ctl->pgsr[0], 0x1 << 13);
> +
> +	/* Disable read time out */
> +	clrbits_le32(&mctl_ctl->pgcr[0], 0x1 << 25);
> +}
> +
>  static void mctl_auto_detect_dram_size(uint16_t socid, struct dram_para *para)
>  {
> +	if (socid == SOCID_R40) {
> +		mctl_r40_detect_rank_count(para);
> +		mctl_set_cr(socid, para);
> +	}
> +
>  	mctl_auto_detect_dram_size_rank(socid, para, (ulong)CONFIG_SYS_SDRAM_BASE, &para->ranks[0]);
>  
>  	if ((socid == SOCID_A64 || socid == SOCID_R40) && para->dual_rank) {
> @@ -854,8 +899,6 @@ unsigned long sunxi_dram_init(void)
>  	uint16_t socid = SOCID_H3;
>  #elif defined(CONFIG_MACH_SUN8I_R40)
>  	uint16_t socid = SOCID_R40;
> -	/* Currently we cannot support R40 with dual rank memory */
> -	para.dual_rank = 0;
>  #elif defined(CONFIG_MACH_SUN8I_V3S)
>  	uint16_t socid = SOCID_V3S;
>  #elif defined(CONFIG_MACH_SUN50I)
> 


More information about the U-Boot mailing list