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.uva...@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 <icen...@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(¶->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, ¶->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) >