Commit e9968c6f authored by Ulf Hansson's avatar Ulf Hansson

mmc: mmci: Send a CMD12 to clear the DPSM at errors

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: default avatarUlf Hansson <ulf.hansson@linaro.org>
Tested-by: default avatarLudovic Barre <ludovic.barre@st.com>
parent e9d6a371
...@@ -1127,6 +1127,12 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) ...@@ -1127,6 +1127,12 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
writel(c, base + MMCICOMMAND); 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 static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data, mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status) unsigned int status)
...@@ -1196,11 +1202,17 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, ...@@ -1196,11 +1202,17 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
/* The error clause is handled above, success! */ /* The error clause is handled above, success! */
data->bytes_xfered = data->blksz * data->blocks; data->bytes_xfered = data->blksz * data->blocks;
if (!data->stop || (host->mrq->sbc && !data->error)) if (!data->stop) {
mmci_request_end(host, data->mrq); if (host->variant->cmdreg_stop && data->error)
mmci_stop_command(host);
else else
mmci_request_end(host, data->mrq);
} else if (host->mrq->sbc && !data->error) {
mmci_request_end(host, data->mrq);
} else {
mmci_start_command(host, data->stop, 0); mmci_start_command(host, data->stop, 0);
} }
}
} }
static void static void
...@@ -1298,6 +1310,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ...@@ -1298,6 +1310,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
mmci_dma_error(host); mmci_dma_error(host);
mmci_stop_data(host); mmci_stop_data(host);
if (host->variant->cmdreg_stop && cmd->error) {
mmci_stop_command(host);
return;
}
} }
mmci_request_end(host, host->mrq); mmci_request_end(host, host->mrq);
} else if (sbc) { } else if (sbc) {
...@@ -1956,6 +1972,11 @@ static int mmci_probe(struct amba_device *dev, ...@@ -1956,6 +1972,11 @@ static int mmci_probe(struct amba_device *dev,
mmc->max_busy_timeout = 0; 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; mmc->ops = &mmci_ops;
/* We support these PM capabilities. */ /* We support these PM capabilities. */
......
...@@ -377,6 +377,7 @@ struct mmci_host { ...@@ -377,6 +377,7 @@ struct mmci_host {
void __iomem *base; void __iomem *base;
struct mmc_request *mrq; struct mmc_request *mrq;
struct mmc_command *cmd; struct mmc_command *cmd;
struct mmc_command stop_abort;
struct mmc_data *data; struct mmc_data *data;
struct mmc_host *mmc; struct mmc_host *mmc;
struct clk *clk; struct clk *clk;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment