Commit 4a694dc9 authored by Adrian Hunter's avatar Adrian Hunter Committed by Pierre Ossman

omap_hsmmc: Fix response type for busy after response

Some MMC commands result in the card becoming busy after
the response is received.  This needs to be specified
for the omap_hsmmc host controller, which is what this
patch does.  However, the effect is that some commands
with no data will cause a Transfer Complete (TC) interrupt
in addition to the Command Complete (CC) interrupt.
In order to deal with that, the irq handler has needed
a few changes also.

The benefit of this change is that the omap_hsmmc host
controller driver now waits for the TC interrupt while
the card is busy, so the mmc_block driver needs to poll
the card status just once instead of repeatedly.
i.e. the net result is more sleep and less cpu.

The command sequence for open-ended multi-block write
with DMA is now:

	Issue write command CMD25
	Receive CC interrupt
	Data is sent
	Receive TC interrupt (DMA is done)
	Issue stop command CMD12
	Receive CC interrupt
	Card is busy
	Receive TC interrupt
	Card is now ready for next transfer
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 82788ff5
...@@ -150,6 +150,7 @@ struct mmc_omap_host { ...@@ -150,6 +150,7 @@ struct mmc_omap_host {
int initstr; int initstr;
int slot_id; int slot_id;
int dbclk_enabled; int dbclk_enabled;
int response_busy;
struct omap_mmc_platform_data *pdata; struct omap_mmc_platform_data *pdata;
}; };
...@@ -244,10 +245,14 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd, ...@@ -244,10 +245,14 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
host->response_busy = 0;
if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) if (cmd->flags & MMC_RSP_136)
resptype = 1; resptype = 1;
else else if (cmd->flags & MMC_RSP_BUSY) {
resptype = 3;
host->response_busy = 1;
} else
resptype = 2; resptype = 2;
} }
...@@ -282,6 +287,15 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd, ...@@ -282,6 +287,15 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
static void static void
mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
{ {
if (!data) {
struct mmc_request *mrq = host->mrq;
host->mrq = NULL;
mmc_omap_fclk_lazy_disable(host);
mmc_request_done(host->mmc, mrq);
return;
}
host->data = NULL; host->data = NULL;
if (host->use_dma && host->dma_ch != -1) if (host->use_dma && host->dma_ch != -1)
...@@ -323,7 +337,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) ...@@ -323,7 +337,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10); cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
} }
} }
if (host->data == NULL || cmd->error) { if ((host->data == NULL && !host->response_busy) || cmd->error) {
host->mrq = NULL; host->mrq = NULL;
mmc_request_done(host->mmc, cmd->mrq); mmc_request_done(host->mmc, cmd->mrq);
} }
...@@ -413,7 +427,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -413,7 +427,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
struct mmc_data *data; struct mmc_data *data;
int end_cmd = 0, end_trans = 0, status; int end_cmd = 0, end_trans = 0, status;
if (host->cmd == NULL && host->data == NULL) { if (host->mrq == NULL) {
OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_WRITE(host->base, STAT,
OMAP_HSMMC_READ(host->base, STAT)); OMAP_HSMMC_READ(host->base, STAT));
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -438,18 +452,24 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) ...@@ -438,18 +452,24 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
} }
end_cmd = 1; end_cmd = 1;
} }
if (host->data) { if (host->data || host->response_busy) {
mmc_dma_cleanup(host, -ETIMEDOUT); if (host->data)
mmc_dma_cleanup(host, -ETIMEDOUT);
host->response_busy = 0;
mmc_omap_reset_controller_fsm(host, SRD); mmc_omap_reset_controller_fsm(host, SRD);
} }
} }
if ((status & DATA_TIMEOUT) || if ((status & DATA_TIMEOUT) ||
(status & DATA_CRC)) { (status & DATA_CRC)) {
if (host->data) { if (host->data || host->response_busy) {
if (status & DATA_TIMEOUT) int err = (status & DATA_TIMEOUT) ?
mmc_dma_cleanup(host, -ETIMEDOUT); -ETIMEDOUT : -EILSEQ;
if (host->data)
mmc_dma_cleanup(host, err);
else else
mmc_dma_cleanup(host, -EILSEQ); host->mrq->cmd->error = err;
host->response_busy = 0;
mmc_omap_reset_controller_fsm(host, SRD); mmc_omap_reset_controller_fsm(host, SRD);
end_trans = 1; end_trans = 1;
} }
......
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