Dne petek, 08. januar 2021 ob 03:01:42 CET je André Przywara napisal(a):
> On 03/12/2020 17:46, Jernej Skrabec wrote:
> > It turns out that in rare cases, current analytical approach to detect
> > correct DRAM bus width and rank on H6 doesn't work. On some TV boxes
> > with DDR3, incorrect DRAM configuration triggers write leveling error
> > which immediately stops initialization process. Exact reason why this
> > error appears isn't known. However, if correct configuration is used,
> > initalization works without problem.
> > 
> > In order to fix this issue, simply try another configuration when any
> > kind of error appears during initialization, not just those related to
> > rank and bus width.
> 
> It's a bummer that this auto detection doesn't work, it looked to be the
> right thing.
> But I prefer functionality over pipe dreams ;-)
> 
> > 
> > Tested-by: Thomas Graichen <thomas.graic...@googlemail.com>
> > Signed-off-by: Jernej Skrabec <jernej.skra...@siol.net>
> > ---
> >  arch/arm/mach-sunxi/dram_sun50i_h6.c | 95 +++++++++++++++-------------
> >  1 file changed, 51 insertions(+), 44 deletions(-)
> > 
> > diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/
dram_sun50i_h6.c
> > index 9e34da474798..1cde6132be2c 100644
> > --- a/arch/arm/mach-sunxi/dram_sun50i_h6.c
> > +++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
> > @@ -37,9 +37,9 @@
> >  
> >  static void mctl_sys_init(struct dram_para *para);
> >  static void mctl_com_init(struct dram_para *para);
> > -static void mctl_channel_init(struct dram_para *para);
> > +static bool mctl_channel_init(struct dram_para *para);
> >  
> > -static void mctl_core_init(struct dram_para *para)
> > +static bool mctl_core_init(struct dram_para *para)
> >  {
> >     mctl_sys_init(para);
> >     mctl_com_init(para);
> > @@ -51,7 +51,7 @@ static void mctl_core_init(struct dram_para *para)
> >     default:
> >             panic("Unsupported DRAM type!");
> >     };
> > -   mctl_channel_init(para);
> > +   return mctl_channel_init(para);
> >  }
> >  
> >  /* PHY initialisation */
> > @@ -411,7 +411,7 @@ static void mctl_bit_delay_set(struct dram_para *para)
> >     }
> >  }
> >  
> > -static void mctl_channel_init(struct dram_para *para)
> > +static bool mctl_channel_init(struct dram_para *para)
> >  {
> >     struct sunxi_mctl_com_reg * const mctl_com =
> >                     (struct sunxi_mctl_com_reg 
*)SUNXI_DRAM_COM_BASE;
> > @@ -528,46 +528,15 @@ static void mctl_channel_init(struct dram_para 
*para)
> >             clrbits_le32(&mctl_phy->dx[i].gcr[3], ~0x3ffff);
> >     udelay(10);
> >  
> > -   if (readl(&mctl_phy->pgsr[0]) & 0x400000)
> > -   {
> > -           /* Check for single rank and optionally half DQ. */
> > -           if ((readl(&mctl_phy->dx[0].rsr[0]) & 0x3) == 2 &&
> > -               (readl(&mctl_phy->dx[1].rsr[0]) & 0x3) == 2) {
> > -                   para->ranks = 1;
> > -
> > -                   if ((readl(&mctl_phy->dx[2].rsr[0]) & 0x3) !
= 2 ||
> > -                       (readl(&mctl_phy->dx[3].rsr[0]) & 0x3) !
= 2)
> > -                           para->bus_full_width = 0;
> > -
> > -                   /* Restart DRAM initialization from scratch. 
*/
> > -                   mctl_core_init(para);
> > -                   return;
> > -           }
> > -
> > -           /*
> > -            * Check for dual rank and half DQ. NOTE: This 
combination
> > -            * is highly unlikely and was not tested. Condition is 
the
> > -            * same as in libdram, though.
> > -            */
> > -           if ((readl(&mctl_phy->dx[0].rsr[0]) & 0x3) == 0 &&
> > -               (readl(&mctl_phy->dx[1].rsr[0]) & 0x3) == 0) {
> > -                   para->bus_full_width = 0;
> > -
> > -                   /* Restart DRAM initialization from scratch. 
*/
> > -                   mctl_core_init(para);
> > -                   return;
> > -           }
> > -
> > -           panic("This DRAM setup is currently not supported.\n");
> > -   }
> > -
> >     if (readl(&mctl_phy->pgsr[0]) & 0xff00000) {
> >             /* Oops! There's something wrong! */
> >             debug("PLL = %x\n", readl(0x3001010));
> >             debug("DRAM PHY PGSR0 = %x\n", readl(&mctl_phy-
>pgsr[0]));
> >             for (i = 0; i < 4; i++)
> >                     debug("DRAM PHY DX%dRSR0 = %x\n", i, 
readl(&mctl_phy->dx[i].rsr[0]));
> > -           panic("Error while initializing DRAM PHY!\n");
> > +           debug("Error while initializing DRAM PHY!\n");
> > +
> > +           return false;
> >     }
> >  
> >     if (sunxi_dram_is_lpddr(para->type))
> > @@ -582,13 +551,54 @@ static void mctl_channel_init(struct dram_para 
*para)
> >     writel(0xffffffff, &mctl_com->maer0);
> >     writel(0x7ff, &mctl_com->maer1);
> >     writel(0xffff, &mctl_com->maer2);
> > +
> > +   return true;
> > +}
> > +
> > +static void mctl_auto_detect_rank_width(struct dram_para *para)
> > +{
> > +   /* this is minimum size that it's supported */
> > +   para->cols = 8;
> > +   para->rows = 13;
> > +
> > +   /*
> 
> Can you add here that former versions of this code tried to autodetect
> rank and width, but this didn't work reliably? This would give people
> some breadcrumbs to follow with git log/git annotate.
> 
> Otherwise this is fine:
> 
> Reviewed-by: Andre Przywara <andre.przyw...@arm.com>
> Tested-by: Andre Przywara <andre.przyw...@arm.com> (on Pine H64)
> 
> I can extend the commit while committing, if you like.

Please do. Thanks!

Best regards,
Jernej

> 
> Cheers,
> Andre.
> 
> 
> > +    * Strategy here is to test most demanding combination first and 
least
> > +    * demanding last, otherwise HW might not be fully utilized. For
> > +    * example, half bus width and rank = 1 combination would also 
work
> > +    * on HW with full bus width and rank = 2, but only 1/4 RAM would 
be
> > +    * visible.
> > +    */
> > +
> > +   debug("testing 32-bit width, rank = 2\n");
> > +   para->bus_full_width = 1;
> > +   para->ranks = 2;
> > +   if (mctl_core_init(para))
> > +           return;
> > +
> > +   debug("testing 32-bit width, rank = 1\n");
> > +   para->bus_full_width = 1;
> > +   para->ranks = 1;
> > +   if (mctl_core_init(para))
> > +           return;
> > +
> > +   debug("testing 16-bit width, rank = 2\n");
> > +   para->bus_full_width = 0;
> > +   para->ranks = 2;
> > +   if (mctl_core_init(para))
> > +           return;
> > +
> > +   debug("testing 16-bit width, rank = 1\n");
> > +   para->bus_full_width = 0;
> > +   para->ranks = 1;
> > +   if (mctl_core_init(para))
> > +           return;
> > +
> > +   panic("This DRAM setup is currently not supported.\n");
> >  }
> >  
> >  static void mctl_auto_detect_dram_size(struct dram_para *para)
> >  {
> >     /* TODO: non-(LP)DDR3 */
> > -   /* Detect rank number and half DQ by the code in 
mctl_channel_init. */
> > -   mctl_core_init(para);
> >  
> >     /* detect row address bits */
> >     para->cols = 8;
> > @@ -652,10 +662,6 @@ unsigned long sunxi_dram_init(void)
> >                     (struct sunxi_mctl_com_reg 
*)SUNXI_DRAM_COM_BASE;
> >     struct dram_para para = {
> >             .clk = CONFIG_DRAM_CLK,
> > -           .ranks = 2,
> > -           .cols = 11,
> > -           .rows = 14,
> > -           .bus_full_width = 1,
> >  #ifdef CONFIG_SUNXI_DRAM_H6_LPDDR3
> >             .type = SUNXI_DRAM_TYPE_LPDDR3,
> >             .dx_read_delays  = SUN50I_H6_LPDDR3_DX_READ_DELAYS,
> > @@ -673,6 +679,7 @@ unsigned long sunxi_dram_init(void)
> >     setbits_le32(0x7010310, BIT(8));
> >     clrbits_le32(0x7010318, 0x3f);
> >  
> > +   mctl_auto_detect_rank_width(&para);
> >     mctl_auto_detect_dram_size(&para);
> >  
> >     mctl_core_init(&para);
> > 
> 
> 


Reply via email to