[U-Boot] QSPI support on i.MX7D Sabre Eval Board

Thomas Schaefer Thomas.Schaefer at kontron.com
Mon Jun 24 15:47:03 UTC 2019


Hi all,


> Hi Fabio,
> 
> > Hi Thomas,
> > 
> > On Wed, Jun 19, 2019 at 10:04 AM Thomas Schaefer <Thomas.Schaefer at kontron.com> wrote:
> > >
> > > Hi all,
> > >
> > > I've built current u-boot (v2019.07-rc4) with QSPI support for our i.MX7D Sabre eval system. I am using mx7dsabresd_qspi_defconfig.
> > >
> > > The resulting u-boot fails to read from QSPI, i.e. the data read is not the same than that written before with a previous (v2018) version.
> > >
> > > After some investigation I found that the 'is_controller_busy' function comes back with -ETIMEDOUT during read operation, because the retry count >of 5 is too low.
> > >
> > > To figure out how many retries are needed, I added some debug code as part of a while(1) loop to the is_controller_busy function:
> > >
> > > diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index
> > > 1598c4f698..fa5b7a29f2 100644
> > > --- a/drivers/spi/fsl_qspi.c
> > > +++ b/drivers/spi/fsl_qspi.c
> > > @@ -152,16 +152,20 @@ static inline int is_controller_busy(const struct fsl_qspi_priv *priv)
> > >         u32 val;
> > >         const u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
> > >                          QSPI_SR_IP_ACC_MASK;
> > > -       unsigned int retry = 5;
> > > +       unsigned int retry = 0;
> > >
> > >         do {
> > >                 val = qspi_read32(priv->flags, &priv->regs->sr);
> > >
> > > -               if ((~val & mask) == mask)
> > > +               if ((~val & mask) == mask) {
> > > +                       if (retry > 5)
> > > +                               printf("%s: timeout! retry = %d\n", 
> > > + __func__, retry);
> > >                         return 0;
> > > +               }
> > >
> > >                 udelay(1);
> > > -       } while (--retry);
> > > +               retry++;
> > > +       } while (1);
> > >
> > >         return -ETIMEDOUT;
> > >  }
> > >
> > > On my MX7 eval system I found that a retry count between 73 and 147 is necessary to make sure that the controller will be ready before the next operation.
> > >
> > > So from my point of view we have 2 options to fix this issue:
> > >
> > > - increase retry from 5 to 200
> > > - wait in an endless loop (while (1) ) and return only when the controller is ready (which means that the board will hang if the controller doesn't come back for some other reason.
> > >
> > > What do you think?
> >
> > I think that readl_poll_timeout() could be used here as it will timeout if the QSPI controller is not ready.
> >
> > Also, could you check how this is handled in the fsl qspi driver in the kernel?
> 
> There is a similar readl_plll_tout call in 5.1.12 linux kernel driver (spi-fsl-qspi.c) with 1000us timeout:
> 
> /* wait for the controller being ready */ fsl_qspi_readl_poll_tout(q, base + QUADSPI_SR, (QUADSPI_SR_IP_ACC_MASK |
> 				 QUADSPI_SR_AHB_ACC_MASK), 10, 1000);
> 
> The fsl additions take concern about endianess before calling the general 'readl_poll_timeout' function.
> 
> Thomas
>

Following Fabio's suggestion I have prepared the following patch that fixes the QSPI read support issue of the fsl_qspi driver on my i.MX7D Sabre eval system. Could you please review/check this patch and introduce it into upcoming v2019.07 version?

Thanks, Thomas


From: Thomas Schaefer <thomas.schaefer at kontron.com>
Date: Mon, 24 Jun 2019 17:15:57 +0200
Subject: [PATCH] driver/spi: fsl_qspi: fix is_controller_busy check

Use readl_poll_timeout function to check for busy controller with
a timeout of 1000 us instead of 5 fixed test loops.

Signed-off-by: Thomas Schaefer <thomas.schaefer at kontron.com>
---
 drivers/spi/fsl_qspi.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 1598c4f698..41abe1996f 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -10,6 +10,7 @@
 #include <spi.h>
 #include <asm/io.h>
 #include <linux/sizes.h>
+#include <linux/iopoll.h>
 #include <dm.h>
 #include <errno.h>
 #include <watchdog.h>
@@ -150,20 +151,13 @@ static void qspi_write32(u32 flags, u32 *addr, u32 val)
 static inline int is_controller_busy(const struct fsl_qspi_priv *priv)
 {
        u32 val;
-       const u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
-                        QSPI_SR_IP_ACC_MASK;
-       unsigned int retry = 5;
+       u32 mask = QSPI_SR_BUSY_MASK | QSPI_SR_AHB_ACC_MASK |
+                  QSPI_SR_IP_ACC_MASK;

-       do {
-               val = qspi_read32(priv->flags, &priv->regs->sr);
+       if (priv->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG)
+               mask = (u32)cpu_to_be32(mask);

-               if ((~val & mask) == mask)
-                       return 0;
-
-               udelay(1);
-       } while (--retry);
-
-       return -ETIMEDOUT;
+       return readl_poll_timeout(&priv->regs->sr, val, !(val & mask), 1000);
 }

 /* QSPI support swapping the flash read/write data
--
2.11.0



More information about the U-Boot mailing list