diff options
author | Ludovic Barre <ludovic.barre@stericsson.com> | 2011-03-25 09:26:57 +0100 |
---|---|---|
committer | Sebastian RASMUSSEN <sebastian.rasmussen@stericsson.com> | 2011-04-07 16:05:16 +0200 |
commit | 0c6eefa863a9415fbb3b96c5c533926d2708118e (patch) | |
tree | 21583b17dd203e2a912b68da2e13fff384a35ffb /drivers/mmc | |
parent | a0e9b86d3bb29f82972731f816cd81770e1c5ffa (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.c | 481 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 65 |
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 }; - |