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.palt...@synopsys.com>
---
 drivers/spi/designware_spi.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index c501aeea16..71d8839d55 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -338,6 +338,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int 
bitlen,
 {
        struct udevice *bus = dev->parent;
        struct dw_spi_priv *priv = dev_get_priv(bus);
+       unsigned long start;
        const u8 *tx = dout;
        u8 *rx = din;
        int ret = 0;
@@ -394,6 +395,22 @@ 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.
+        */
+       start = get_timer(0);
+       while (!(dw_readl(priv, DW_SPI_SR) & SR_TF_EMPT) ||
+               (dw_readl(priv, DW_SPI_SR) & SR_BUSY)) {
+               if (get_timer(start) > RX_TIMEOUT) {
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+       }
+
        return ret;
 }
 
-- 
2.14.3

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to