[U-Boot] [PATCH V2] spi: tegra: clear RDY bit prior to every transfer

Jagan Teki jagannadh.teki at gmail.com
Wed Dec 18 19:34:57 CET 2013


On Wed, Dec 18, 2013 at 11:48 PM, Stephen Warren <swarren at wwwdotorg.org> wrote:
> From: Yen Lin <yelin at nvidia.com>
>
> The RDY bit indicates that a transfer is complete. This needs to be
> cleared by SW before every single HW transaction, rather than only
> at the start of each SW transaction (those being made up of n HW
> transactions).
>
> It seems that earlier HW may have cleared this bit autonomously when
> starting a new transfer, and hence this code was not needed in practice.
> However, this is generally a good idea in all cases. In Tegra124, the
> HW behaviour appears to have changed, and SW must explicitly clear this
> bit. Otherwise, SW will believe that transfers have completed when they
> have not, and may e.g. read stale data from the RX FIFO.
>
> Signed-off-by: Yen Lin <yelin at nvidia.com>
> [swarren, rewrote commit description, unified duplicate RDY clearing code
> and moved it right before the start of the HW transaction, unconditionally
> exit loop after reading RX data, rather than checking if TX FIFO is empty,
> since it is guaranteed to be]
> Signed-off-by: Stephen Warren <swarren at nvidia.com>
> ---
> V2: Rebased on u-boot/master rather than a local branch with some Tegra124
>     changes applied first.
>
>  drivers/spi/tegra114_spi.c | 21 ++++++++-------------
>  1 file changed, 8 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c
> index 4d2af483d77f..810fa4718ce1 100644
> --- a/drivers/spi/tegra114_spi.c
> +++ b/drivers/spi/tegra114_spi.c
> @@ -289,9 +289,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>         reg = readl(&regs->fifo_status);
>         writel(reg, &regs->fifo_status);
>
> -       /* clear ready bit */
> -       setbits_le32(&regs->xfer_status, SPI_XFER_STS_RDY);
> -
>         clrsetbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL,
>                         SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE |
>                         (slave->cs << SPI_CMD1_CS_SEL_SHIFT));
> @@ -305,7 +302,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>         /* handle data in 32-bit chunks */
>         while (num_bytes > 0) {
>                 int bytes;
> -               int is_read = 0;
>                 int tm, i;
>
>                 tmpdout = 0;
> @@ -319,6 +315,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>
>                 num_bytes -= bytes;
>
> +               /* clear ready bit */
> +               setbits_le32(&regs->xfer_status, SPI_XFER_STS_RDY);
> +
>                 clrsetbits_le32(&regs->command1,
>                                 SPI_CMD1_BIT_LEN_MASK << SPI_CMD1_BIT_LEN_SHIFT,
>                                 (bytes * 8 - 1) << SPI_CMD1_BIT_LEN_SHIFT);
> @@ -329,20 +328,14 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>                  * Wait for SPI transmit FIFO to empty, or to time out.
>                  * The RX FIFO status will be read and cleared last
>                  */
> -               for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) {
> +               for (tm = 0; tm < SPI_TIMEOUT; ++tm) {
>                         u32 fifo_status, xfer_status;
>
> -                       fifo_status = readl(&regs->fifo_status);
> -
> -                       /* We can exit when we've had both RX and TX activity */
> -                       if (is_read &&
> -                           (fifo_status & SPI_FIFO_STS_TX_FIFO_EMPTY))
> -                               break;
> -
>                         xfer_status = readl(&regs->xfer_status);
>                         if (!(xfer_status & SPI_XFER_STS_RDY))
>                                 continue;
>
> +                       fifo_status = readl(&regs->fifo_status);
>                         if (fifo_status & SPI_FIFO_STS_ERR) {
>                                 debug("%s: got a fifo error: ", __func__);
>                                 if (fifo_status & SPI_FIFO_STS_TX_FIFO_OVF)
> @@ -367,7 +360,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>
>                         if (!(fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)) {
>                                 tmpdin = readl(&regs->rx_fifo);
> -                               is_read = 1;
>
>                                 /* swap bytes read in */
>                                 if (din != NULL) {
> @@ -377,6 +369,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>                                         }
>                                         din += bytes;
>                                 }
> +
> +                               /* We can exit when we've had both RX and TX */
> +                               break;
>                         }
>                 }
>
> --
> 1.8.1.5
>

Applied to u-boot-spi/master

-- 
Thanks,
Jagan.
--------
Jagannadha Sutradharudu Teki,
E: jagannadh.teki at gmail.com, P: +91-9676773388
Engineer - System Software Hacker
U-boot - SPI Custodian and Zynq APSOC
Ln: http://www.linkedin.com/in/jaganteki


More information about the U-Boot mailing list