Skip to content
Snippets Groups Projects
Commit 60acde43 authored by Yen Lin's avatar Yen Lin Committed by Jagannadha Sutradharudu Teki
Browse files

spi: tegra: clear RDY bit prior to every transfer


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: default avatarYen Lin <yelin@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: default avatarStephen Warren <swarren@nvidia.com>
Reviewed-by: default avatarJagannadha Sutradharudu Teki <jaganna@xilinx.com>
parent 16f47c9c
No related branches found
No related tags found
No related merge requests found
...@@ -289,9 +289,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, ...@@ -289,9 +289,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
reg = readl(&regs->fifo_status); reg = readl(&regs->fifo_status);
writel(reg, &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, clrsetbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL,
SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE | SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE |
(slave->cs << SPI_CMD1_CS_SEL_SHIFT)); (slave->cs << SPI_CMD1_CS_SEL_SHIFT));
...@@ -305,7 +302,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, ...@@ -305,7 +302,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
/* handle data in 32-bit chunks */ /* handle data in 32-bit chunks */
while (num_bytes > 0) { while (num_bytes > 0) {
int bytes; int bytes;
int is_read = 0;
int tm, i; int tm, i;
tmpdout = 0; tmpdout = 0;
...@@ -319,6 +315,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, ...@@ -319,6 +315,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
num_bytes -= bytes; num_bytes -= bytes;
/* clear ready bit */
setbits_le32(&regs->xfer_status, SPI_XFER_STS_RDY);
clrsetbits_le32(&regs->command1, clrsetbits_le32(&regs->command1,
SPI_CMD1_BIT_LEN_MASK << SPI_CMD1_BIT_LEN_SHIFT, SPI_CMD1_BIT_LEN_MASK << SPI_CMD1_BIT_LEN_SHIFT,
(bytes * 8 - 1) << 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, ...@@ -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. * Wait for SPI transmit FIFO to empty, or to time out.
* The RX FIFO status will be read and cleared last * 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; 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); xfer_status = readl(&regs->xfer_status);
if (!(xfer_status & SPI_XFER_STS_RDY)) if (!(xfer_status & SPI_XFER_STS_RDY))
continue; continue;
fifo_status = readl(&regs->fifo_status);
if (fifo_status & SPI_FIFO_STS_ERR) { if (fifo_status & SPI_FIFO_STS_ERR) {
debug("%s: got a fifo error: ", __func__); debug("%s: got a fifo error: ", __func__);
if (fifo_status & SPI_FIFO_STS_TX_FIFO_OVF) if (fifo_status & SPI_FIFO_STS_TX_FIFO_OVF)
...@@ -367,7 +360,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, ...@@ -367,7 +360,6 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (!(fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)) { if (!(fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)) {
tmpdin = readl(&regs->rx_fifo); tmpdin = readl(&regs->rx_fifo);
is_read = 1;
/* swap bytes read in */ /* swap bytes read in */
if (din != NULL) { if (din != NULL) {
...@@ -377,6 +369,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, ...@@ -377,6 +369,9 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
} }
din += bytes; din += bytes;
} }
/* We can exit when we've had both RX and TX */
break;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment