Clear all controller interrupt status bits and enable the DMA DONE
interrupt in the DMA DST interrupt enable register before starting
the DMA read. Also poll the BUSY bit in the DMA status register until it
becomes zero, which implies that the DMA is done with the transfer and
may accept a new command. Return -ETIMEDOUT if the BUSY bit does not
clear.

Signed-off-by: Venkatesh Yadav Abbarapu <[email protected]>
Signed-off-by: Padmarao Begari <[email protected]>
---
 drivers/spi/cadence_ospi_versal.c | 20 ++++++++++++++++++++
 drivers/spi/cadence_qspi.h        |  1 +
 2 files changed, 21 insertions(+)

diff --git a/drivers/spi/cadence_ospi_versal.c 
b/drivers/spi/cadence_ospi_versal.c
index f97bf744122..0133c92b60c 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -50,6 +50,12 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
 
                writel(CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE,
                       priv->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE);
+               /* Clear all interrupts. */
+               writel(CQSPI_IRQ_STATUS_MASK,
+                      priv->regbase + CQSPI_REG_IRQSTATUS);
+               /* Enable DMA done interrupt */
+               writel(CQSPI_DMA_DST_I_STS_DONE,
+                      priv->regbase + CQSPI_DMA_DST_I_ENBL_REG);
                writel(CQSPI_DFLT_DMA_PERIPH_CFG,
                       priv->regbase + CQSPI_REG_DMA_PERIPH_CFG);
                writel(lower_32_bits((unsigned long)rxbuf), priv->regbase +
@@ -73,6 +79,8 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
                if (ret)
                        return ret;
 
+               /* Disable DMA interrupt */
+               writel(0x0, priv->regbase + CQSPI_DMA_DST_I_DISBL_REG);
                /* Clear indirect completion status */
                writel(CQSPI_REG_INDIRECTRD_DONE, priv->regbase +
                       CQSPI_REG_INDIRECTRD);
@@ -152,6 +160,18 @@ int cadence_qspi_apb_wait_for_dma_cmplt(struct 
cadence_spi_priv *priv)
 
        writel(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG),
               priv->regbase + CQSPI_DMA_DST_I_STS_REG);
+
+       /* Wait until the DMA is ready to accept a new command */
+       timeout = CQSPI_DMA_TIMEOUT;
+       while ((readl(priv->regbase + CQSPI_DMA_DST_STS_REG) &
+               CQSPI_DMA_DST_STS_BUSY) && --timeout)
+               udelay(1);
+
+       if (!timeout) {
+               printf("DMA busy timeout\n");
+               return -ETIMEDOUT;
+       }
+
        return 0;
 }
 
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 86f2fd639c5..7efe0454936 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -192,6 +192,7 @@
 #define CQSPI_DFLT_DMA_PERIPH_CFG               0x602
 #define CQSPI_DFLT_DST_CTRL_REG_VAL             0xF43FFA00
 
+#define CQSPI_DMA_DST_STS_BUSY                  BIT(0)
 #define CQSPI_DMA_DST_I_STS_DONE                BIT(1)
 #define CQSPI_DMA_TIMEOUT                       10000000
 
-- 
2.34.1

Reply via email to