diff options
Diffstat (limited to 'drivers/mmc/mxsmmc.c')
-rw-r--r-- | drivers/mmc/mxsmmc.c | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index e8bad9d..dfceaef 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -43,6 +43,13 @@ #include <asm/arch/sys_proto.h> #include <asm/arch/dma.h> +/* + * CONFIG_MXS_MMC_DMA: This feature is highly experimental and has no + * performance benefit unless you operate the platform with + * data cache enabled. This is disabled by default, enable + * only if you know what you're doing. + */ + struct mxsmmc_priv { int id; struct mx28_ssp_regs *regs; @@ -66,8 +73,13 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) struct mx28_ssp_regs *ssp_regs = priv->regs; uint32_t reg; int timeout; - uint32_t data_count, cache_data_count; + uint32_t data_count; uint32_t ctrl0; +#ifndef CONFIG_MXS_MMC_DMA + uint32_t *data_ptr; +#else + uint32_t cache_data_count; +#endif debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx); @@ -185,7 +197,9 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) return 0; data_count = data->blocksize * data->blocks; + timeout = MXSMMC_MAX_TIMEOUT; +#ifdef CONFIG_MXS_MMC_DMA if (data_count % ARCH_DMA_MINALIGN) cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); else @@ -218,6 +232,38 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) invalidate_dcache_range((uint32_t)priv->desc->cmd.address, (uint32_t)(priv->desc->cmd.address + cache_data_count)); } +#else + if (data->flags & MMC_DATA_READ) { + data_ptr = (uint32_t *)data->dest; + while (data_count && --timeout) { + reg = readl(&ssp_regs->hw_ssp_status); + if (!(reg & SSP_STATUS_FIFO_EMPTY)) { + *data_ptr++ = readl(&ssp_regs->hw_ssp_data); + data_count -= 4; + timeout = MXSMMC_MAX_TIMEOUT; + } else + udelay(1000); + } + } else { + data_ptr = (uint32_t *)data->src; + timeout *= 100; + while (data_count && --timeout) { + reg = readl(&ssp_regs->hw_ssp_status); + if (!(reg & SSP_STATUS_FIFO_FULL)) { + writel(*data_ptr++, &ssp_regs->hw_ssp_data); + data_count -= 4; + timeout = MXSMMC_MAX_TIMEOUT; + } else + udelay(1000); + } + } + + if (!timeout) { + printf("MMC%d: Data timeout with command %d (status 0x%08x)!\n", + mmc->block_dev.dev, cmd->cmdidx, reg); + return COMM_ERR; + } +#endif /* Check data errors */ reg = readl(&ssp_regs->hw_ssp_status); |