mmc: dwmmc: Poll for iDMAC TX/RX interrupt
authorLey Foon Tan <ley.foon.tan@intel.com>
Thu, 20 Dec 2018 09:55:41 +0000 (17:55 +0800)
committerMarek Vasut <marex@denx.de>
Mon, 18 Feb 2019 12:00:54 +0000 (13:00 +0100)
Poll for iDMAC TX/RX interrupt before disable DMA.
This to prevent disable DMA before data is transfer
completed.

Signed-off-by: Ley Foon Tan <ley.foon.tan@intel.com>
drivers/mmc/dw_mmc.c
include/dwmmc.h

index 7544b84ab614cbd525ad5a9dc1100e4967886455..93a836eac3629bde23f89e62747e17c41eea3ab0 100644 (file)
@@ -12,6 +12,7 @@
 #include <memalign.h>
 #include <mmc.h>
 #include <dwmmc.h>
+#include <wait_bit.h>
 
 #define PAGE_SIZE 4096
 
@@ -55,6 +56,9 @@ static void dwmci_prepare_data(struct dwmci_host *host,
 
        dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
 
+       /* Clear IDMAC interrupt */
+       dwmci_writel(host, DWMCI_IDSTS, 0xFFFFFFFF);
+
        data_start = (ulong)cur_idmac;
        dwmci_writel(host, DWMCI_DBADDR, (ulong)cur_idmac);
 
@@ -340,6 +344,18 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 
                /* only dma mode need it */
                if (!host->fifo_mode) {
+                       if (data->flags == MMC_DATA_READ)
+                               mask = DWMCI_IDINTEN_RI;
+                       else
+                               mask = DWMCI_IDINTEN_TI;
+                       ret = wait_for_bit_le32(host->ioaddr + DWMCI_IDSTS,
+                                               mask, true, 1000, false);
+                       if (ret)
+                               debug("%s: DWMCI_IDINTEN mask 0x%x timeout.\n",
+                                     __func__, mask);
+                       /* clear interrupts */
+                       dwmci_writel(host, DWMCI_IDSTS, DWMCI_IDINTEN_MASK);
+
                        ctrl = dwmci_readl(host, DWMCI_CTRL);
                        ctrl &= ~(DWMCI_DMA_EN);
                        dwmci_writel(host, DWMCI_CTRL, ctrl);
@@ -494,6 +510,9 @@ static int dwmci_init(struct mmc *mmc)
        dwmci_writel(host, DWMCI_CLKENA, 0);
        dwmci_writel(host, DWMCI_CLKSRC, 0);
 
+       if (!host->fifo_mode)
+               dwmci_writel(host, DWMCI_IDINTEN, DWMCI_IDINTEN_MASK);
+
        return 0;
 }
 
index 4ceda5e43c5ed5190f5650a3a5897db65399e024..f06720dc0d98eecc1f343b0362141899ebb1cf6c 100644 (file)
 /* UHS register */
 #define DWMCI_DDR_MODE (1 << 16)
 
+/* Internal IDMAC interrupt defines */
+#define DWMCI_IDINTEN_RI               BIT(1)
+#define DWMCI_IDINTEN_TI               BIT(0)
+
+#define DWMCI_IDINTEN_MASK     (DWMCI_IDINTEN_TI | \
+                                DWMCI_IDINTEN_RI)
+
 /* quirks */
 #define DWMCI_QUIRK_DISABLE_SMU                (1 << 0)