DW SPI: fix tx data loss on FIFO flush
authorEugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Thu, 22 Mar 2018 10:50:43 +0000 (13:50 +0300)
committerJagan Teki <jagan@amarulasolutions.com>
Thu, 22 Mar 2018 17:31:35 +0000 (23:01 +0530)
In current implementation if some data still exists in Tx FIFO it
can be silently flushed, i.e. dropped on disabling of the controller,
which happens when writing 0 to DW_SPI_SSIENR (it happens in the
beginning of new transfer)

So add wait for current transmit operation to complete to be sure
that current transmit operation is finished before new one.

Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Reviewed-by: Jagan Teki <jagan@openedev.com>
drivers/spi/designware_spi.c

index c501aeea166e2cae4fdb13f7a1f9d569ebcda20e..5e196b21c9c25a28b651eb57bf38000b1cf93a4a 100644 (file)
@@ -18,6 +18,7 @@
 #include <spi.h>
 #include <fdtdec.h>
 #include <linux/compat.h>
+#include <linux/iopoll.h>
 #include <asm/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -342,6 +343,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
        u8 *rx = din;
        int ret = 0;
        u32 cr0 = 0;
+       u32 val;
        u32 cs;
 
        /* spi core configured to do 8 bit transfers */
@@ -394,6 +396,19 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
        /* Start transfer in a polling loop */
        ret = poll_transfer(priv);
 
+       /*
+        * Wait for current transmit operation to complete.
+        * Otherwise if some data still exists in Tx FIFO it can be
+        * silently flushed, i.e. dropped on disabling of the controller,
+        * which happens when writing 0 to DW_SPI_SSIENR which happens
+        * in the beginning of new transfer.
+        */
+       if (readl_poll_timeout(priv->regs + DW_SPI_SR, val,
+                              !(val & SR_TF_EMPT) || (val & SR_BUSY),
+                              RX_TIMEOUT * 1000)) {
+               ret = -ETIMEDOUT;
+       }
+
        return ret;
 }