|
@@ -43,6 +43,13 @@
|
|
#include <asm/arch/sys_proto.h>
|
|
#include <asm/arch/sys_proto.h>
|
|
#include <asm/arch/dma.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 {
|
|
struct mxsmmc_priv {
|
|
int id;
|
|
int id;
|
|
struct mx28_ssp_regs *regs;
|
|
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;
|
|
struct mx28_ssp_regs *ssp_regs = priv->regs;
|
|
uint32_t reg;
|
|
uint32_t reg;
|
|
int timeout;
|
|
int timeout;
|
|
- uint32_t data_count, cache_data_count;
|
|
|
|
|
|
+ uint32_t data_count;
|
|
uint32_t ctrl0;
|
|
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);
|
|
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;
|
|
return 0;
|
|
|
|
|
|
data_count = data->blocksize * data->blocks;
|
|
data_count = data->blocksize * data->blocks;
|
|
|
|
+ timeout = MXSMMC_MAX_TIMEOUT;
|
|
|
|
|
|
|
|
+#ifdef CONFIG_MXS_MMC_DMA
|
|
if (data_count % ARCH_DMA_MINALIGN)
|
|
if (data_count % ARCH_DMA_MINALIGN)
|
|
cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN);
|
|
cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN);
|
|
else
|
|
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,
|
|
invalidate_dcache_range((uint32_t)priv->desc->cmd.address,
|
|
(uint32_t)(priv->desc->cmd.address + cache_data_count));
|
|
(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 */
|
|
/* Check data errors */
|
|
reg = readl(&ssp_regs->hw_ssp_status);
|
|
reg = readl(&ssp_regs->hw_ssp_status);
|