msm: msm_sdcc: use AUTO_PROG_DONE bit for CMD53 write
SDCCv4 supports AUTO_PROG_DONE bit for CMD53 write.
Without this bit, driver had to send the dummy CMD52
to know whether card is busy programming or not.
As AUTO_PROG_DONE bit is available, driver no longer
sends dummy CMD52 rather it sets this AUTO_PROG_DONE
bit in MCI_DATA_CTL register and then waits for
PROG_DONE interrupt status bit to be set.
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index d6a343a..9d21c71 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -297,6 +297,8 @@
{
host->curr.data = NULL;
host->curr.got_dataend = 0;
+ host->curr.wait_for_auto_prog_done = 0;
+ host->curr.got_auto_prog_done = 0;
writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
(~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
msmsdcc_delay(host); /* Allow the DPSM to be reset */
@@ -414,8 +416,9 @@
host->dma.sg = NULL;
host->dma.busy = 0;
- if (host->curr.got_dataend || mrq->data->error) {
-
+ if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
+ (host->curr.wait_for_auto_prog_done &&
+ host->curr.got_auto_prog_done))) || mrq->data->error) {
/*
* If we've already gotten our DATAEND / DATABLKEND
* for this request, then complete it through here.
@@ -566,7 +569,9 @@
host->sps.sg = NULL;
host->sps.busy = 0;
- if (host->curr.got_dataend || mrq->data->error) {
+ if ((host->curr.got_dataend && (!host->curr.wait_for_auto_prog_done ||
+ (host->curr.wait_for_auto_prog_done &&
+ host->curr.got_auto_prog_done))) || mrq->data->error) {
/*
* If we've already gotten our DATAEND / DATABLKEND
* for this request, then complete it through here.
@@ -928,11 +933,15 @@
host->curr.xfer_remain = host->curr.xfer_size;
host->curr.data_xfered = 0;
host->curr.got_dataend = 0;
+ host->curr.got_auto_prog_done = 0;
memset(&host->pio, 0, sizeof(host->pio));
datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
+ if (host->curr.wait_for_auto_prog_done)
+ datactrl |= MCI_AUTO_PROG_DONE;
+
if (!msmsdcc_check_dma_op_req(data)) {
if (host->is_dma_mode && !msmsdcc_config_dma(host, data)) {
datactrl |= MCI_DPSM_DMAENABLE;
@@ -1436,11 +1445,19 @@
}
}
+ /* Check for prog done */
+ if (host->curr.wait_for_auto_prog_done &&
+ (status & MCI_PROGDONE))
+ host->curr.got_auto_prog_done = 1;
+
/* Check for data done */
if (!host->curr.got_dataend && (status & MCI_DATAEND))
host->curr.got_dataend = 1;
- if (host->curr.got_dataend) {
+ if (host->curr.got_dataend &&
+ (!host->curr.wait_for_auto_prog_done ||
+ (host->curr.wait_for_auto_prog_done &&
+ host->curr.got_auto_prog_done))) {
/*
* If DMA is still in progress, we complete
* via the completion handler
@@ -1541,14 +1558,23 @@
host->curr.mrq = mrq;
- if (!host->plat->sdcc_v4_sup) {
- if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
- if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
- mrq->cmd->opcode == 54) {
+ if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
+ if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
+ mrq->cmd->opcode == 54) {
+ if (!host->plat->sdcc_v4_sup)
host->dummy_52_needed = 1;
- }
+ else
+ /*
+ * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
+ * write operations using CMD53 and CMD54.
+ * Setting this bit with CMD53 would
+ * automatically triggers PROG_DONE interrupt
+ * without the need of sending dummy CMD52.
+ */
+ host->curr.wait_for_auto_prog_done = 1;
}
}
+
msmsdcc_request_start(host, mrq);
spin_unlock_irqrestore(&host->lock, flags);
}
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index f6f76ff..b4d2d58 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -77,6 +77,7 @@
#define MCI_DPSM_DIRECTION (1 << 1)
#define MCI_DPSM_MODE (1 << 2)
#define MCI_DPSM_DMAENABLE (1 << 3)
+#define MCI_AUTO_PROG_DONE (1 << 19)
#define MCI_RX_DATA_PEND (1 << 20)
#define MMCIDATACNT 0x030
@@ -256,6 +257,8 @@
unsigned int xfer_remain; /* Bytes remaining to send */
unsigned int data_xfered; /* Bytes acked by BLKEND irq */
int got_dataend;
+ int wait_for_auto_prog_done;
+ int got_auto_prog_done;
int user_pages;
};