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: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Ludovic Barre <ludovic.barre@st.com>
This commit is contained in:
Ulf Hansson 2019-01-29 15:35:56 +01:00
parent e9d6a371cf
commit e9968c6fa8
2 changed files with 24 additions and 2 deletions

View 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. */

View 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;