aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorLudovic Barre <ludovic.barre@stericsson.com>2011-03-25 09:26:57 +0100
committerSebastian RASMUSSEN <sebastian.rasmussen@stericsson.com>2011-04-07 16:05:16 +0200
commit0c6eefa863a9415fbb3b96c5c533926d2708118e (patch)
tree21583b17dd203e2a912b68da2e13fff384a35ffb /drivers/mmc
parenta0e9b86d3bb29f82972731f816cd81770e1c5ffa (diff)
mmci: reorganize send request to split in
- PIO/DMA commun data setup - specific prepare data for PIO or DMA mode - start data (register writing), So in write request (irq context) the configuration is alwready do, just write the registers ST-Ericsson Linux next: N/A ST-Ericsson ID: - ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I39178321e8a22e405c091029971bab6323c1ee1b Signed-off-by: Ludovic Barre <ludovic.barre@stericsson.com> Change-Id: I39178321e8a22e405c091029971bab6323c1ee1b Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/17175 Reviewed-by: Sebastian RASMUSSEN <sebastian.rasmussen@stericsson.com> Tested-by: Sebastian RASMUSSEN <sebastian.rasmussen@stericsson.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/mmci.c481
-rw-r--r--drivers/mmc/host/mmci.h65
2 files changed, 309 insertions, 237 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 023ecb29f5e..b0c53445c84 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -58,8 +58,6 @@ static unsigned int dataread_delay_clks = 7500000;
* @txsize_threshold: Sets DMA burst size to minimal if transfer size is
* less or equal to this threshold. This shall be specified in
* number of bytes. Set 0 for no burst compensation
- * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware
- * and will not work at all.
* @sdio: variant supports SDIO
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @pwrreg_powerup: power up value for MMCIPOWER register
@@ -76,7 +74,6 @@ struct variant_data {
unsigned int fifosize;
unsigned int fifohalfsize;
unsigned int txsize_threshold;
- bool broken_blockend;
bool sdio;
bool st_clkdiv;
unsigned int pwrreg_powerup;
@@ -109,7 +106,6 @@ static struct variant_data variant_ux500 = {
.clkreg_enable = 1 << 14, /* HWFCEN */
.dmareg_enable = 1 << 12, /* DMAREQCTRL */
.datalength_bits = 24,
- .broken_blockend = true,
.sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -339,46 +335,6 @@ static void mmci_stop_data(struct mmci_host *host)
host->data = NULL;
}
-static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
-{
- unsigned int flags = SG_MITER_ATOMIC;
-
- if (data->flags & MMC_DATA_READ)
- flags |= SG_MITER_TO_SG;
- else
- flags |= SG_MITER_FROM_SG;
-
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
-}
-
-static void
-mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
-{
- void __iomem *base = host->base;
-
- dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
- cmd->opcode, cmd->arg, cmd->flags);
-
- if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
- writel(0, base + MMCICOMMAND);
- udelay(1);
- }
-
- c |= cmd->opcode | MCI_CPSM_ENABLE;
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136)
- c |= MCI_CPSM_LONGRSP;
- c |= MCI_CPSM_RESPONSE;
- }
- if (/*interrupt*/0)
- c |= MCI_CPSM_INTERRUPT;
-
- host->cmd = cmd;
-
- writel(cmd->arg, base + MMCIARGUMENT);
- writel(c, base + MMCICOMMAND);
-}
-
static void
mmci_complete_data_xfer(struct mmci_host *host)
{
@@ -402,6 +358,15 @@ mmci_complete_data_xfer(struct mmci_host *host)
}
}
+static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
+{
+ unsigned int flags = SG_MITER_ATOMIC;
+
+ flags |= data->flags & MMC_DATA_READ ?
+ SG_MITER_TO_SG : SG_MITER_FROM_SG;
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+}
+
/*
* All the DMA operation mode stuff goes inside this ifdef.
* This assumes that you have a generic DMA device interface,
@@ -646,148 +611,6 @@ static inline int mmci_dma_start_data(struct mmci_host *host,
}
#endif
-static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
-{
- struct variant_data *variant = host->variant;
- unsigned int datactrl, timeout, irqmask0, irqmask1;
- unsigned int clkcycle_ns;
- void __iomem *base;
- int blksz_bits;
- u32 clk;
-
- dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
- data->blksz, data->blocks, data->flags);
-
- host->data = data;
- host->size = data->blksz * data->blocks;
- host->data_xfered = 0;
- host->last_blockend = false;
- host->dataend = false;
- host->cache_len = 0;
- host->cache = 0;
-
- clkcycle_ns = 1000000000 / host->cclk;
- timeout = data->timeout_ns / clkcycle_ns;
- timeout += data->timeout_clks;
-
- if (data->flags & MMC_DATA_READ) {
- /*
- * Since the read command is sent after we have setup
- * the data transfer we must increase the data timeout.
- * Unfortunately this is not enough since some cards
- * does not seem to stick to what is stated in their
- * CSD for TAAC and NSAC.
- */
- timeout += dataread_delay_clks;
- }
-
- base = host->base;
- writel(timeout, base + MMCIDATATIMER);
- writel(host->size, base + MMCIDATALENGTH);
-
- blksz_bits = ffs(data->blksz) - 1;
-
-#ifdef CONFIG_ARCH_U8500
- /* Temporary solution for db8500v2. */
- if (cpu_is_u8500v20_or_later())
- datactrl = MCI_DPSM_ENABLE | (data->blksz << 16);
- else
-#endif
- datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
-
- if (data->flags & MMC_DATA_READ)
- datactrl |= MCI_DPSM_DIRECTION;
-
- if (host->mmc->card && mmc_card_ddr_mode(host->mmc->card)) {
- datactrl |= MCI_ST_DPSM_DDRMODE;
-
- /* Needed for DDR */
- clk = readl(base + MMCICLOCK);
- clk |= MCI_NEG_EDGE;
-
- writel(clk, (base + MMCICLOCK));
- }
-
- if (variant->sdio &&
- host->mmc->card &&
- mmc_card_sdio(host->mmc->card)) {
- /*
- * The ST Micro variants has a special bit
- * to enable SDIO mode. This bit is set the first time
- * a SDIO data transfer is done and must remain set
- * after the data transfer is completed. The reason is
- * because of otherwise no SDIO interrupts can be
- * received.
- */
- datactrl |= MCI_ST_DPSM_SDIOEN;
-
- /*
- * The ST Micro variant for SDIO transfer sizes
- * less than or equal to 8 bytes needs to have clock
- * H/W flow control disabled. Since flow control is
- * not really needed for anything that fits in the
- * FIFO, we can disable it for any write smaller
- * than the FIFO size.
- */
- if ((host->size <= variant->fifosize) &&
- (data->flags & MMC_DATA_WRITE))
- writel(readl(host->base + MMCICLOCK) &
- ~variant->clkreg_enable,
- host->base + MMCICLOCK);
- else
- writel(readl(host->base + MMCICLOCK) |
- variant->clkreg_enable,
- host->base + MMCICLOCK);
- }
-
- if (host->dma_enable) {
- int ret;
-
- /*
- * Attempt to use DMA operation mode, if this
- * should fail, fall back to PIO mode
- */
- ret = mmci_dma_start_data(host, datactrl);
- if (!ret)
- return;
- }
-
- /* IRQ mode, map the SG list for CPU reading/writing */
- mmci_init_sg(host, data);
-
- if (data->flags & MMC_DATA_READ) {
- irqmask1 = MCI_RXFIFOHALFFULLMASK;
-
- /*
- * If we have less than a FIFOSIZE of bytes to
- * transfer, trigger a PIO interrupt as soon as any
- * data is available.
- */
- if (host->size < variant->fifosize)
- irqmask1 |= MCI_RXDATAAVLBLMASK;
- } else {
- /*
- * We don't actually need to include "FIFO empty" here
- * since its implicit in "FIFO half empty".
- */
- irqmask1 = MCI_TXFIFOHALFEMPTYMASK;
- }
-
- /* Setup IRQ */
- irqmask0 = readl(base + MMCIMASK0);
- if (variant->broken_blockend) {
- host->last_blockend = true;
- irqmask0 &= ~MCI_DATABLOCKENDMASK;
- } else {
- irqmask0 |= MCI_DATABLOCKENDMASK;
- }
- writel(irqmask0, base + MMCIMASK0);
- mmci_set_mask1(host, irqmask1);
-
- /* Start the data transfer */
- writel(datactrl, base + MMCIDATACTRL);
-}
-
static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
@@ -1053,6 +876,14 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer,
return ptr - buffer;
}
+static void mmci_start_data(struct mmci_host *host)
+{
+ writel(host->mmci_clockctrl, host->base + MMCICLOCK);
+ writel(host->mmci_datatimer, host->base + MMCIDATATIMER);
+ writel(host->mmci_datalenght, host->base + MMCIDATALENGTH);
+ writel(host->mmci_datactrl, host->base + MMCIDATACTRL);
+}
+
/*
* PIO data transfer IRQ handler.
*/
@@ -1190,16 +1021,225 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
return IRQ_RETVAL(ret);
}
-static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+static int mmci_setup_data(struct mmci_host *host, struct mmc_data *data)
+{
+ unsigned int clkcycle_ns;
+ int blksz_bits;
+
+ dev_dbg(mmc_dev(host->mmc), "[%s] blksz:%d nb_blk:%d sg_len:%d "
+ "ptr_sg:%p flags %08x\n", __func__, data->blksz,
+ data->blocks, data->sg_len, data->sg, data->flags);
+
+ host->size = data->blksz * data->blocks;
+ host->pio_active = XFER_NONE;
+
+ clkcycle_ns = 1000000000 / host->cclk;
+ host->mmci_datatimer = data->timeout_ns / clkcycle_ns;
+ host->mmci_datatimer += data->timeout_clks;
+
+ blksz_bits = ffs(data->blksz) - 1;
+
+ /*FIXME shift must be define */
+#ifdef CONFIG_ARCH_U8500
+ /* Temporary solution for db8500v2. */
+ if (cpu_is_u8500v20_or_later())
+ host->mmci_datactrl = data->blksz << 16;
+ else
+#endif
+ host->mmci_datactrl = blksz_bits << 4;
+
+ if (data->flags & MMC_DATA_READ) {
+ host->mmci_datactrl |= MCI_DPSM_DIRECTION;
+ host->mmci_datatimer += dataread_delay_clks;
+ }
+
+ host->mmci_datactrl |= MCI_DPSM_ENABLE;
+
+ /* Needed for DDR */
+ if (host->mmc->card && mmc_card_ddr_mode(host->mmc->card)) {
+ host->mmci_datactrl |= MCI_ST_DPSM_DDRMODE;
+ host->mmci_clockctrl |= MCI_NEG_EDGE;
+ }
+
+ host->mmci_datalenght = data->blksz * data->blocks;
+
+ /* irq mask */
+ host->mmci_mask0 = MCI_DATACRCFAILMASK | MCI_DATATIMEOUTMASK |
+ MCI_TXUNDERRUNMASK | MCI_RXOVERRUNMASK | MCI_STARTBITERRMASK;
+
+ return 0;
+}
+
+static inline void mmci_prepare_sdio(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct variant_data *variant = host->variant;
+
+ /* The ST Micro variants:
+ * -has a special bit to enable SDIO.
+ * -for SDIO transfer sizes less then 8 bytes
+ * should have clock H/W flow control disabled.
+ */
+ host->mmci_clockctrl |= variant->clkreg_enable;
+ if (variant->sdio && host->mmc->card) {
+ if (mmc_card_sdio(host->mmc->card)) {
+ host->mmci_datactrl |= MCI_ST_DPSM_SDIOEN;
+ if ((host->size <= variant->fifosize) &&
+ (data->flags & MMC_DATA_WRITE))
+ host->mmci_clockctrl &= ~variant->clkreg_enable;
+ else
+ host->mmci_clockctrl |= variant->clkreg_enable;
+ }
+ }
+}
+
+static inline void mmci_prepare_pio(struct mmci_host *host,
+ struct mmc_data *data)
{
- struct mmci_host *host = mmc_priv(mmc);
struct variant_data *variant = host->variant;
+ u32 irqmask1 = 0;
+ int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+ host->cache_len = 0;
+ host->cache = 0;
+
+ host->pio_active = rw ? XFER_WRITE : XFER_READ;
+
+ /* IRQ mode, map the SG list for CPU reading/writing */
+ mmci_init_sg(host, data);
+
+ /* FIXME
+ * if write case, perhaps we can preload the fifo
+ */
+ if (data->flags & MMC_DATA_READ) {
+ irqmask1 |= MCI_RXFIFOHALFFULLMASK;
+ /*
+ * If we have less than a FIFOSIZE of bytes to
+ * transfer, trigger a PIO interrupt as soon as any
+ * data is available.
+ */
+ if (host->size < variant->fifosize)
+ irqmask1 |= MCI_RXDATAAVLBLMASK;
+ } else {
+ /*
+ * We don't actually need to include "FIFO empty" here
+ * since its implicit in "FIFO half empty".
+ */
+ irqmask1 |= MCI_TXFIFOHALFEMPTYMASK;
+ }
+
+ host->mmci_mask0 &= ~MCI_DATAENDMASK;
+ mmci_set_mask1(host, irqmask1);
+}
+
+static void mmci_prepare_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ int res = 0;
+
+ mmci_prepare_sdio(host, data);
+
+ /*
+ * Attempt to use DMA operation mode, if this
+ * should fail, fall back to PIO mode
+ */
+ if (host->dma_enable) {
+ res = mmci_prepare_dma(host, data);
+ if (!res) {
+ host->dma_complete = COMPLETION_DMA_START;
+ return;
+ } else {
+ host->dma_complete = COMPLETION_DMA_NONE;
+ dev_dbg(mmc_dev(host->mmc),
+ "prepare dma error %d.\n", res);
+ host->mmci_datactrl &= ~MCI_DPSM_DMAENABLE;
+ host->mmci_datactrl &= ~host->variant->dmareg_enable;
+ }
+ }
+
+ mmci_prepare_pio(host, data);
+}
+
+static void mmci_prepare_command(struct mmci_host *host,
+ struct mmc_command *cmd)
+{
+ host->mmci_mask0 |= MCI_CMDTIMEOUTMASK | MCI_CMDCRCFAILMASK;
+
+ if (cmd->data)
+ host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
+ else if (cmd->flags & MMC_RSP_PRESENT)
+ host->complete_what = COMPLETION_RSPFIN;
+ else
+ host->complete_what = COMPLETION_CMDSENT;
+
+ host->mmci_argument = cmd->arg;
+ host->mmci_command = cmd->opcode | MCI_CPSM_ENABLE;
+
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ host->mmci_command |= MCI_CPSM_RESPONSE;
+ host->mmci_mask0 |= MCI_CMDRESPENDMASK;
+ if (cmd->flags & MMC_RSP_136)
+ host->mmci_command |= MCI_CPSM_LONGRSP;
+ } else
+ host->mmci_mask0 |= MCI_CMDSENTMASK;
+}
+
+static void mmci_send_command(struct mmci_host *host)
+{
+ writel(host->mmci_argument, host->base + MMCIARGUMENT);
+ writel(host->mmci_command, host->base + MMCICOMMAND);
+}
+
+static void mmci_send_request(struct mmc_host *mmc)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ struct mmc_request *mrq = host->mrq;
+ struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
+ int res;
unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Clear mmci status and mask registers */
+ writel(0x7ff, host->base + MMCICLEAR);
+ clear_imasks(host);
+
+ if (cmd->data) {
+ res = mmci_setup_data(host, cmd->data);
+ if (res) {
+ dev_err(mmc_dev(mmc), "data setup error %d.\n", res);
+ goto err_data;
+ }
+
+ mmci_prepare_data(host, cmd->data);
+
+ if (cmd->data->flags & MMC_DATA_READ)
+ mmci_start_data(host);
+ }
+
+ mmci_prepare_command(host, cmd);
+ enable_imasks(host);
+ mmci_send_command(host);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return;
+
+err_data:
+ cmd->error = res;
+ cmd->data->error = res;
+ mmc_request_done(mmc, mrq);
+ return;
+}
+
+static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ host->cmd_is_stop = 0;
+
WARN_ON(host->mrq != NULL);
if (mrq->data &&
- (!variant->non_power_of_2_blksize ||
+ (!host->variant->non_power_of_2_blksize ||
#ifdef CONFIG_ARCH_U8500
!cpu_is_u8500v20_or_later() ||
#endif
@@ -1212,16 +1252,9 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
return;
}
- spin_lock_irqsave(&host->lock, flags);
-
host->mrq = mrq;
-
- if (mrq->data && mrq->data->flags & MMC_DATA_READ)
- mmci_start_data(host, mrq->data);
-
- mmci_start_command(host, mrq->cmd, 0);
-
- spin_unlock_irqrestore(&host->lock, flags);
+ host->stat.nb_core_req++;
+ mmci_send_request(mmc);
}
static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -1321,6 +1354,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->pwr != pwr) {
host->pwr = pwr;
+ host->mmci_power = pwr;
writel(pwr, host->base + MMCIPOWER);
}
@@ -1397,10 +1431,9 @@ static int mmci_enable(struct mmc_host *mmc)
writel(MCI_ST_DPSM_SDIOEN, host->base + MMCIDATACTRL);
}
- /* Restore registers for POWER, CLOCK and IRQMASK0 */
- writel(host->irqmask0_reg, host->base + MMCIMASK0);
- writel(host->pwr_reg, host->base + MMCIPOWER);
- writel(host->clk_reg, host->base + MMCICLOCK);
+ /* Restore registers for POWER and CLOCK. */
+ writel(host->mmci_power, host->base + MMCIPOWER);
+ writel(host->mmci_clockctrl, host->base + MMCICLOCK);
spin_unlock_irqrestore(&host->lock, flags);
@@ -1421,18 +1454,13 @@ static int mmci_disable(struct mmc_host *mmc, int lazy)
spin_lock_irqsave(&host->lock, flags);
- /* Save registers for POWER, CLOCK and IRQMASK0 */
- host->irqmask0_reg = readl(host->base + MMCIMASK0);
- host->pwr_reg = readl(host->base + MMCIPOWER);
- host->clk_reg = readl(host->base + MMCICLOCK);
-
/*
- * Make sure we do not get any interrupts when we disabled the
- * clock and the regulator. Especially important for SDIO
+ * Make sure we do not get any interrupts when disable is done
+ * of the clock and the regulator. Especially important for SDIO
* interrupts, since they may occur even without any active
* request handling ongoing.
*/
- writel(0, host->base + MMCIMASK0);
+ disable_imasks(host);
spin_unlock_irqrestore(&host->lock, flags);
@@ -1518,10 +1546,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
host->gpio_cd = -ENOSYS;
host->gpio_cd_irq = -1;
- host->irqmask0_reg = 0;
- host->pwr_reg = 0;
- host->clk_reg = 0;
-
host->hw_designer = amba_manf(dev);
host->hw_revision = amba_rev(dev);
dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
@@ -1684,9 +1708,11 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
&& host->gpio_cd_irq < 0)
mmc->caps |= MMC_CAP_NEEDS_POLL;
- mmci_setup_dma(host);
+ ret = mmci_setup_dma(host);
+ if (ret)
+ mmci_disable_dma(host);
- ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED,
+ ret = request_irq(dev->irq[0], mmci_irq, 0,
DRIVER_NAME " (cmd)", host);
if (ret)
goto unmap;
@@ -1694,20 +1720,19 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
if (dev->irq[1] == NO_IRQ)
host->singleirq = true;
else {
- ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
+ ret = request_irq(dev->irq[1], mmci_pio_irq, 0,
DRIVER_NAME " (pio)", host);
if (ret)
goto irq0_free;
}
- /* Prepare IRQMASK0 */
- host->irqmask0_reg = MCI_IRQENABLE;
- if (host->variant->broken_blockend)
- host->irqmask0_reg &= ~MCI_DATABLOCKEND;
-
amba_set_drvdata(dev, mmc);
- mmc_add_host(mmc);
+ ret = mmc_add_host(mmc);
+ if (ret) {
+ dev_err(mmc_dev(host->mmc), "failed to add mmc host.\n");
+ goto irq0_free;
+ }
dev_info(&dev->dev,
"%s: MMCI/PL180 manf %x rev %x cfg %02x at 0x%016llx\n",
@@ -1718,6 +1743,9 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
/* Ugly hack for u8500_sdio_detect_card, to be removed soon. */
sdio_host_ptr = host;
+ tasklet_init(&host->mmci_tasklet,
+ mmci_tasklet, (unsigned long) host);
+
mmci_debugfs_create(host);
return 0;
@@ -1763,8 +1791,7 @@ static int __devexit mmci_remove(struct amba_device *dev)
mmci_debugfs_remove(host);
mmc_remove_host(mmc);
- writel(0, host->base + MMCIMASK0);
- writel(0, host->base + MMCIMASK1);
+ disable_imasks(host);
writel(0, host->base + MMCICOMMAND);
writel(0, host->base + MMCIDATACTRL);
@@ -1831,8 +1858,8 @@ static int mmci_suspend(struct amba_device *dev, pm_message_t state)
mmc_host_enable(mmc);
mmc_power_save_host(mmc);
mmc_host_disable(mmc);
- host->pwr_reg = 0;
- host->clk_reg = 0;
+ host->mmci_power = 0;
+ host->mmci_clockctrl = 0;
}
} else {
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 87d35cc1fea..6216aa34e55 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -78,6 +78,7 @@
#define MCI_CMDRESPEND (1 << 6)
#define MCI_CMDSENT (1 << 7)
#define MCI_DATAEND (1 << 8)
+#define MCI_STARTBITERR (1 << 9)
#define MCI_DATABLOCKEND (1 << 10)
#define MCI_CMDACTIVE (1 << 11)
#define MCI_TXACTIVE (1 << 12)
@@ -103,6 +104,7 @@
#define MCI_CMDRESPENDCLR (1 << 6)
#define MCI_CMDSENTCLR (1 << 7)
#define MCI_DATAENDCLR (1 << 8)
+#define MCI_STARTBITERRCLR (1 << 9)
#define MCI_DATABLOCKENDCLR (1 << 10)
#define MCI_SDIOITC (1 << 22)
#define MCI_CEATAENDC (1 << 23)
@@ -117,6 +119,7 @@
#define MCI_CMDRESPENDMASK (1 << 6)
#define MCI_CMDSENTMASK (1 << 7)
#define MCI_DATAENDMASK (1 << 8)
+#define MCI_STARTBITERRMASK (1 << 9)
#define MCI_DATABLOCKENDMASK (1 << 10)
#define MCI_CMDACTIVEMASK (1 << 11)
#define MCI_TXACTIVEMASK (1 << 12)
@@ -159,12 +162,38 @@ struct variant_data;
struct dma_chan;
struct dma_async_tx_descriptor;
+enum mmci_dma_complete{
+ COMPLETION_DMA_NONE,
+ COMPLETION_DMA_START,
+ COMPLETION_DMA_XFERFINISH,
+};
+
+enum mmci_waitfor {
+ COMPLETION_NONE,
+ COMPLETION_FINALIZE,
+ COMPLETION_REQ,
+ COMPLETION_CMDSENT,
+ COMPLETION_RSPFIN,
+ COMPLETION_XFERFINISH,
+ COMPLETION_XFERFINISH_RSPFIN,
+};
+
+struct mmci_stat{
+ unsigned long nb_core_req;
+ unsigned long nb_cmdcrcfail;
+ unsigned long nb_rxoverrun;
+ unsigned long nb_txunderrun;
+ unsigned long nb_datacrcfail;
+ unsigned long nb_datatimeout;
+ unsigned long nb_startbiterr;
+ unsigned long nb_dma_err;
+};
+
struct mmci_host {
phys_addr_t phybase;
void __iomem *base;
struct mmc_request *mrq;
struct mmc_command *cmd;
- struct mmc_data *data;
struct mmc_host *mmc;
struct clk *clk;
int gpio_cd;
@@ -188,14 +217,6 @@ struct mmci_host {
struct timer_list timer;
unsigned int oldstat;
- bool last_blockend;
- bool dataend;
-
- /* register cache */
- unsigned int irqmask0_reg;
- unsigned int pwr_reg;
- unsigned int clk_reg;
-
/* pio stuff */
struct sg_mapping_iter sg_miter;
unsigned int size;
@@ -214,8 +235,32 @@ struct mmci_host {
struct dma_async_tx_descriptor *dma_desc;
#endif
+ struct tasklet_struct mmci_tasklet;
+ enum mmci_waitfor complete_what;
+ enum mmci_dma_complete dma_complete;
+
+ int cmd_is_stop;
+
+#define XFER_NONE 0
+#define XFER_READ 1
+#define XFER_WRITE 2
+ u32 pio_active;
+
+ /* mmci registers*/
+ u32 mmci_command;
+ u32 mmci_argument;
+
+ u32 mmci_mask0;
+ u32 mmci_mask1;
+
+ u32 mmci_datatimer;
+ u32 mmci_datalenght;
+ u32 mmci_datactrl;
+ u32 mmci_clockctrl;
+ u32 mmci_power;
+
+ struct mmci_stat stat;
#ifdef CONFIG_DEBUG_FS
struct dentry *debug_regs;
#endif
};
-