summaryrefslogtreecommitdiff
path: root/drivers/mmc/mxsmmc.c
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2012-04-16 23:01:12 +0200
committerWolfgang Denk <wd@denx.de>2012-04-16 23:01:12 +0200
commitdb39f24151627733d6166c5e9a875fe8b356fa72 (patch)
treed091e23af47b9ae848c6f69144f941d9f072aae6 /drivers/mmc/mxsmmc.c
parentb64c2420e02a7d068aae6e0d069f270feb3cdc9a (diff)
parent2694bb9bcc8ca9636faf38c866dda7bf0529e35f (diff)
Merge branch 'master' of git://git.denx.de/u-boot-arm
* 'master' of git://git.denx.de/u-boot-arm: ARM926EJS: Fix cache.c to comply with checkpatch.pl ARM926EJS: Make asm routines volatile in cache ops MX35: mx35pdk: wrong board revision ARM1136: MX35: Make asm routines volatile in cache ops ARM: add u-boot.imx as target for i.MX SOCs M28: Pull out CONFIG_APBH_DMA so it's always enabled DMA: Split the APBH DMA init into block and channel init imx: Return gpio_set_value in gpio_direction_output imx: Use GPIO_TO_PORT macro in the gpio driver instead of (gpio >> 5) imx: Add GPIO_TO_PORT macro in the mxc_gpio driver imx: Remove unneeded/repititive definitions from imx headers i.MX28: Allow coexistence of PIO and DMA mode for SD/MMC MX31: mx31pdk: drop enable_caches from board file i.MX28: Fix initial stack pointer position mx35: mx35pdk: fix when cache functions are linked mx35: flea3: fix when cache functions are linked ARM: 926ejs: use debug() for misaligned addresses ARM1136: add cache flush and invalidate operations mx6qsabrelite: Fix the serial console port mx6qsabrelite: Add boot switch setting information into the README i.MX6: mx6qsabrelite: add cache commands if cache is enabled i.MX6: implement enable_caches() i.MX6: define CACHELINE_SIZE MX53: DDR: Fix ZQHWCTRL field TZQ_CS mx28evk: Add a README file mx28: Split the README into a common part and a m28 specific part tricorder: Load kernel from ubifs tricorder: Add UBIFS cm-t35: fix Ethernet reset timing hawkboard: Add CONFIG_SPL_LIBGENERIC_SUPPORT BeagleBoard: Remove userbutton command and use gpio command instead OMAP: Move omap1510inn to Unmaintained / Orphaned
Diffstat (limited to 'drivers/mmc/mxsmmc.c')
-rw-r--r--drivers/mmc/mxsmmc.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c
index e8bad9dc751..35c6bdabb06 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);
@@ -292,6 +338,7 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int))
(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
struct mmc *mmc = NULL;
struct mxsmmc_priv *priv = NULL;
+ int ret;
mmc = malloc(sizeof(struct mmc));
if (!mmc)
@@ -310,6 +357,10 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int))
return -ENOMEM;
}
+ ret = mxs_dma_init_channel(id);
+ if (ret)
+ return ret;
+
priv->mmc_is_wp = wp;
priv->id = id;
switch (id) {