]> www.infradead.org Git - users/hch/block.git/commitdiff
mmc: mmci: Send a CMD12 to clear the DPSM at errors
authorUlf Hansson <ulf.hansson@linaro.org>
Tue, 29 Jan 2019 14:35:56 +0000 (15:35 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 25 Feb 2019 07:40:58 +0000 (08:40 +0100)
The current approach with sending a CMD12 (STOP_TRANSMISSION) to complete a
data transfer request, either because of using the open-ended transmission
type or because of receiving an error during a pre-defined data transfer,
isn't sufficient for the STM32 sdmmc variant. More precisely, this variant
needs to clear the DPSM ("Data Path State Machine") by sending a CMD12, for
all failing ADTC commands.

Support this, by adding a struct mmc_command inside the struct mmci_host
and initialize it to a CMD12 during ->probe(). Let's also add checks for
the new conditions, to enable mmci_data_irq() and mmci_cmd_irq() to
postpone the calls to mmci_request_end(), but instead send the CMD12.

Cc: Ludovic Barre <ludovic.barre@st.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Ludovic Barre <ludovic.barre@st.com>
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h

index 7dd3ccf5baf00a2af54a2a99009c3c4f462062ee..387ff14587b873cd327e75286235dbbd86069c31 100644 (file)
@@ -1127,6 +1127,12 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
        writel(c, base + MMCICOMMAND);
 }
 
+static void mmci_stop_command(struct mmci_host *host)
+{
+       host->stop_abort.error = 0;
+       mmci_start_command(host, &host->stop_abort, 0);
+}
+
 static void
 mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
              unsigned int status)
@@ -1196,10 +1202,16 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                        /* The error clause is handled above, success! */
                        data->bytes_xfered = data->blksz * data->blocks;
 
-               if (!data->stop || (host->mrq->sbc && !data->error))
+               if (!data->stop) {
+                       if (host->variant->cmdreg_stop && data->error)
+                               mmci_stop_command(host);
+                       else
+                               mmci_request_end(host, data->mrq);
+               } else if (host->mrq->sbc && !data->error) {
                        mmci_request_end(host, data->mrq);
-               else
+               } else {
                        mmci_start_command(host, data->stop, 0);
+               }
        }
 }
 
@@ -1298,6 +1310,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
                        mmci_dma_error(host);
 
                        mmci_stop_data(host);
+                       if (host->variant->cmdreg_stop && cmd->error) {
+                               mmci_stop_command(host);
+                               return;
+                       }
                }
                mmci_request_end(host, host->mrq);
        } else if (sbc) {
@@ -1956,6 +1972,11 @@ static int mmci_probe(struct amba_device *dev,
                mmc->max_busy_timeout = 0;
        }
 
+       /* Prepare a CMD12 - needed to clear the DPSM on some variants. */
+       host->stop_abort.opcode = MMC_STOP_TRANSMISSION;
+       host->stop_abort.arg = 0;
+       host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
        mmc->ops = &mmci_ops;
 
        /* We support these PM capabilities. */
index 24229097d05c2c0fee4b083faeb1a37189c2f7fd..14df8105443844f6ac986c04806fdb0350f87b67 100644 (file)
@@ -377,6 +377,7 @@ struct mmci_host {
        void __iomem            *base;
        struct mmc_request      *mrq;
        struct mmc_command      *cmd;
+       struct mmc_command      stop_abort;
        struct mmc_data         *data;
        struct mmc_host         *mmc;
        struct clk              *clk;