mmc: sdhci: Implement MMC_CAP_CMD23 for SDHCI.
Implements support for multiblock transfers bounded by SET_BLOCK_COUNT (CMD23). Signed-off-by: Andrei Warkentin <andreiw@motorola.com> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
parent
d0c97cfb81
commit
e89d456fcd
|
@ -838,9 +838,10 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdhci_set_transfer_mode(struct sdhci_host *host,
|
static void sdhci_set_transfer_mode(struct sdhci_host *host,
|
||||||
struct mmc_data *data)
|
struct mmc_command *cmd)
|
||||||
{
|
{
|
||||||
u16 mode;
|
u16 mode;
|
||||||
|
struct mmc_data *data = cmd->data;
|
||||||
|
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -848,11 +849,14 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
|
||||||
WARN_ON(!host->data);
|
WARN_ON(!host->data);
|
||||||
|
|
||||||
mode = SDHCI_TRNS_BLK_CNT_EN;
|
mode = SDHCI_TRNS_BLK_CNT_EN;
|
||||||
if (data->blocks > 1) {
|
if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
|
||||||
if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
|
|
||||||
mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12;
|
|
||||||
else
|
|
||||||
mode |= SDHCI_TRNS_MULTI;
|
mode |= SDHCI_TRNS_MULTI;
|
||||||
|
/*
|
||||||
|
* If we are sending CMD23, CMD12 never gets sent
|
||||||
|
* on successful completion (so no Auto-CMD12).
|
||||||
|
*/
|
||||||
|
if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
|
||||||
|
mode |= SDHCI_TRNS_AUTO_CMD12;
|
||||||
}
|
}
|
||||||
if (data->flags & MMC_DATA_READ)
|
if (data->flags & MMC_DATA_READ)
|
||||||
mode |= SDHCI_TRNS_READ;
|
mode |= SDHCI_TRNS_READ;
|
||||||
|
@ -893,7 +897,15 @@ static void sdhci_finish_data(struct sdhci_host *host)
|
||||||
else
|
else
|
||||||
data->bytes_xfered = data->blksz * data->blocks;
|
data->bytes_xfered = data->blksz * data->blocks;
|
||||||
|
|
||||||
if (data->stop) {
|
/*
|
||||||
|
* Need to send CMD12 if -
|
||||||
|
* a) open-ended multiblock transfer (no CMD23)
|
||||||
|
* b) error in multiblock transfer
|
||||||
|
*/
|
||||||
|
if (data->stop &&
|
||||||
|
(data->error ||
|
||||||
|
!host->mrq->sbc)) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The controller needs a reset of internal state machines
|
* The controller needs a reset of internal state machines
|
||||||
* upon error conditions.
|
* upon error conditions.
|
||||||
|
@ -949,7 +961,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
|
||||||
|
|
||||||
sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
|
sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
|
||||||
|
|
||||||
sdhci_set_transfer_mode(host, cmd->data);
|
sdhci_set_transfer_mode(host, cmd);
|
||||||
|
|
||||||
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
|
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
|
||||||
printk(KERN_ERR "%s: Unsupported response type!\n",
|
printk(KERN_ERR "%s: Unsupported response type!\n",
|
||||||
|
@ -1004,6 +1016,13 @@ static void sdhci_finish_command(struct sdhci_host *host)
|
||||||
|
|
||||||
host->cmd->error = 0;
|
host->cmd->error = 0;
|
||||||
|
|
||||||
|
/* Finished CMD23, now send actual command. */
|
||||||
|
if (host->cmd == host->mrq->sbc) {
|
||||||
|
host->cmd = NULL;
|
||||||
|
sdhci_send_command(host, host->mrq->cmd);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Processed actual command. */
|
||||||
if (host->data && host->data_early)
|
if (host->data && host->data_early)
|
||||||
sdhci_finish_data(host);
|
sdhci_finish_data(host);
|
||||||
|
|
||||||
|
@ -1011,6 +1030,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
|
||||||
tasklet_schedule(&host->finish_tasklet);
|
tasklet_schedule(&host->finish_tasklet);
|
||||||
|
|
||||||
host->cmd = NULL;
|
host->cmd = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||||
|
@ -1189,7 +1209,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||||
#ifndef SDHCI_USE_LEDS_CLASS
|
#ifndef SDHCI_USE_LEDS_CLASS
|
||||||
sdhci_activate_led(host);
|
sdhci_activate_led(host);
|
||||||
#endif
|
#endif
|
||||||
if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) {
|
|
||||||
|
/*
|
||||||
|
* Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
|
||||||
|
* requests if Auto-CMD12 is enabled.
|
||||||
|
*/
|
||||||
|
if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
|
||||||
if (mrq->stop) {
|
if (mrq->stop) {
|
||||||
mrq->data->stop = NULL;
|
mrq->data->stop = NULL;
|
||||||
mrq->stop = NULL;
|
mrq->stop = NULL;
|
||||||
|
@ -1227,6 +1252,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||||
host->mrq = mrq;
|
host->mrq = mrq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mrq->sbc)
|
||||||
|
sdhci_send_command(host, mrq->sbc);
|
||||||
|
else
|
||||||
sdhci_send_command(host, mrq->cmd);
|
sdhci_send_command(host, mrq->cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2455,7 +2483,10 @@ int sdhci_add_host(struct sdhci_host *host)
|
||||||
} else
|
} else
|
||||||
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
|
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
|
||||||
|
|
||||||
mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE;
|
mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
|
||||||
|
|
||||||
|
if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
|
||||||
|
host->flags |= SDHCI_AUTO_CMD12;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A controller may support 8-bit width, but the board itself
|
* A controller may support 8-bit width, but the board itself
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
#define SDHCI_TRANSFER_MODE 0x0C
|
#define SDHCI_TRANSFER_MODE 0x0C
|
||||||
#define SDHCI_TRNS_DMA 0x01
|
#define SDHCI_TRNS_DMA 0x01
|
||||||
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
||||||
#define SDHCI_TRNS_ACMD12 0x04
|
#define SDHCI_TRNS_AUTO_CMD12 0x04
|
||||||
#define SDHCI_TRNS_READ 0x10
|
#define SDHCI_TRNS_READ 0x10
|
||||||
#define SDHCI_TRNS_MULTI 0x20
|
#define SDHCI_TRNS_MULTI 0x20
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,7 @@ struct sdhci_host {
|
||||||
#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
|
#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
|
||||||
#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */
|
#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */
|
||||||
#define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */
|
#define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */
|
||||||
|
#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
|
||||||
|
|
||||||
unsigned int version; /* SDHCI spec. version */
|
unsigned int version; /* SDHCI spec. version */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue