[PATCH sunxi/next] spi: sunxi: use XCH status to detect in-progress transfer
Icenowy Zheng
uwu at icenowy.me
Mon Jul 11 16:44:52 CEST 2022
在 2022-07-11星期一的 00:03 +0100,Andre Przywara写道:
> On Tue, 28 Jun 2022 14:49:24 +0800
> Icenowy Zheng <uwu at icenowy.me> wrote:
>
> Hi Icenowy,
>
> > The current detection of RX FIFO depth seems to be not reliable,
> > and
> > XCH will self-clear when a transfer is done.
>
> many thanks for sending this, indeed what I put in -next is broken,
> probably for everything except the F1C100 ;-)
>
> Digging a bit deeper this gets more interesting, though:
> I chased the issue down to my very first commit, that is (now
> properly!)
> setting the SPI bus frequency in the SPI controller's CCR register.
> It
> turns out that there are more issues in this driver, which lead to an
> actual frequency limit of 1 MHz[1]. So my commit now actually
> programs
> this value, and apparently it's too slow(?) for the code? Raising the
> default 1 to 4 MHz makes it work again (even without your patch). The
> previous timeout is generous, though, but by looking at the FIFO
> status
> register it just seemed to be stuck after clocking out one byte only,
> with the RX buf staying at 0. Reading FSR after your new loop reveals
> that the condition holds (RX FIFO level == nbytes), so there is
> something quite weird going on. Without your patch, but with some
> udelay(1000) after(!) the loop it also works, interestingly.
>
> As for the actual code change: looking at the XCH bit is probably
> indeed the most robust and clever method of checking for the end of a
> transfer, so I am tempted to take this change. However there are more
> things broken, apparently, and I would like to get to the bottom of
> those issues, before trying to paper over them.
>
> Cheers,
> Andre
>
> [1] The driver (as most U-Boot SPI drivers, actually) tries to read
> spi-max-frequency from the SPI's *controller* DT node, although this
> is
> a SPI *slave* property. It (correctly) doesn't find anything in
> there,
> so falls back to some (assumed) safe value of 1 MHz.
Ooops... It sounds like the SPI framework is broken?
>
> > Check XCH bit when polling for transfer finish.
>
>
> >
> > Signed-off-by: Icenowy Zheng <uwu at icenowy.me>
> > ---
> > drivers/spi/spi-sunxi.c | 14 +++++---------
> > 1 file changed, 5 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
> > index 2f33337725..a424c6a98e 100644
> > --- a/drivers/spi/spi-sunxi.c
> > +++ b/drivers/spi/spi-sunxi.c
> > @@ -83,7 +83,7 @@ DECLARE_GLOBAL_DATA_PTR;
> > #endif
> > #define SUN4I_SPI_MIN_RATE 3000
> > #define SUN4I_SPI_DEFAULT_RATE 1000000
> > -#define SUN4I_SPI_TIMEOUT_US 1000000
> > +#define SUN4I_SPI_TIMEOUT_MS 1000
> >
> > #define SPI_REG(priv, reg) ((priv)->base + \
> > (priv)->variant->regs[reg])
> > @@ -326,7 +326,6 @@ static int sun4i_spi_xfer(struct udevice *dev,
> > unsigned int bitlen,
> > struct dm_spi_slave_plat *slave_plat =
> > dev_get_parent_plat(dev);
> >
> > u32 len = bitlen / 8;
> > - u32 rx_fifocnt;
> > u8 nbytes;
> > int ret;
> >
> > @@ -364,13 +363,10 @@ static int sun4i_spi_xfer(struct udevice
> > *dev, unsigned int bitlen,
> > setbits_le32(SPI_REG(priv, SPI_TCR),
> > SPI_BIT(priv, SPI_TCR_XCH));
> >
> > - /* Wait till RX FIFO to be empty */
> > - ret = readl_poll_timeout(SPI_REG(priv, SPI_FSR),
> > - rx_fifocnt,
> > - (((rx_fifocnt &
> > - SPI_BIT(priv,
> > SPI_FSR_RF_CNT_MASK)) >>
> > -
> > SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes),
> > - SUN4I_SPI_TIMEOUT_US);
> > + /* Wait for the transfer to be done */
> > + ret = wait_for_bit_le32((const void *)SPI_REG(priv,
> > SPI_TCR),
> > + SPI_BIT(priv, SPI_TCR_XCH),
> > + false,
> > SUN4I_SPI_TIMEOUT_MS, false);
> > if (ret < 0) {
> > printf("ERROR: sun4i_spi: Timeout
> > transferring data\n");
> > sun4i_spi_set_cs(bus, slave_plat->cs,
> > false);
>
More information about the U-Boot
mailing list