]> git.sur5r.net Git - u-boot/blobdiff - drivers/mmc/fsl_esdhc.c
Merge branch 'sf' of git://git.denx.de/u-boot-blackfin
[u-boot] / drivers / mmc / fsl_esdhc.c
index e665b5ebd8a7f10d62877c5e97482ceabc07e095..a368fe60db4a285bb5b43a8ec16069ab8e436d24 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007, Freescale Semiconductor, Inc
+ * Copyright 2007,2010 Freescale Semiconductor, Inc
  * Andy Fleming
  *
  * Based vaguely on the pxa mmc code:
@@ -72,8 +72,10 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
        uint xfertyp = 0;
 
        if (data) {
-               xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN;
-
+               xfertyp |= XFERTYP_DPSEL;
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+               xfertyp |= XFERTYP_DMAEN;
+#endif
                if (data->blocks > 1) {
                        xfertyp |= XFERTYP_MSBSEL;
                        xfertyp |= XFERTYP_BCEN;
@@ -97,12 +99,78 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
        return XFERTYP_CMD(cmd->cmdidx) | xfertyp;
 }
 
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
+/*
+ * PIO Read/Write Mode reduce the performace as DMA is not used in this mode.
+ */
+static void
+esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data)
+{
+       struct fsl_esdhc *regs = mmc->priv;
+       uint blocks;
+       char *buffer;
+       uint databuf;
+       uint size;
+       uint irqstat;
+       uint timeout;
+
+       if (data->flags & MMC_DATA_READ) {
+               blocks = data->blocks;
+               buffer = data->dest;
+               while (blocks) {
+                       timeout = PIO_TIMEOUT;
+                       size = data->blocksize;
+                       irqstat = esdhc_read32(&regs->irqstat);
+                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
+                               && --timeout);
+                       if (timeout <= 0) {
+                               printf("\nData Read Failed in PIO Mode.");
+                               return;
+                       }
+                       while (size && (!(irqstat & IRQSTAT_TC))) {
+                               udelay(100); /* Wait before last byte transfer complete */
+                               irqstat = esdhc_read32(&regs->irqstat);
+                               databuf = in_le32(&regs->datport);
+                               *((uint *)buffer) = databuf;
+                               buffer += 4;
+                               size -= 4;
+                       }
+                       blocks--;
+               }
+       } else {
+               blocks = data->blocks;
+               buffer = (char *)data->src;
+               while (blocks) {
+                       timeout = PIO_TIMEOUT;
+                       size = data->blocksize;
+                       irqstat = esdhc_read32(&regs->irqstat);
+                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BWEN)
+                               && --timeout);
+                       if (timeout <= 0) {
+                               printf("\nData Write Failed in PIO Mode.");
+                               return;
+                       }
+                       while (size && (!(irqstat & IRQSTAT_TC))) {
+                               udelay(100); /* Wait before last byte transfer complete */
+                               databuf = *((uint *)buffer);
+                               buffer += 4;
+                               size -= 4;
+                               irqstat = esdhc_read32(&regs->irqstat);
+                               out_le32(&regs->datport, databuf);
+                       }
+                       blocks--;
+               }
+       }
+}
+#endif
+
 static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
 {
-       uint wml_value;
        int timeout;
        struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
        struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+       uint wml_value;
 
        wml_value = data->blocksize/4;
 
@@ -110,8 +178,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
                if (wml_value > 0x10)
                        wml_value = 0x10;
 
-               wml_value = 0x100000 | wml_value;
-
+               esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
                esdhc_write32(&regs->dsaddr, (u32)data->dest);
        } else {
                if (wml_value > 0x80)
@@ -120,11 +187,22 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
                        printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
                        return TIMEOUT;
                }
-               wml_value = wml_value << 16 | 0x10;
+
+               esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
+                                       wml_value << 16);
                esdhc_write32(&regs->dsaddr, (u32)data->src);
        }
-
-       esdhc_write32(&regs->wml, wml_value);
+#else  /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
+       if (!(data->flags & MMC_DATA_READ)) {
+               if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
+                       printf("\nThe SD card is locked. "
+                               "Can not write to a locked card.\n\n");
+                       return TIMEOUT;
+               }
+               esdhc_write32(&regs->dsaddr, (u32)data->src);
+       } else
+               esdhc_write32(&regs->dsaddr, (u32)data->dest);
+#endif /* CONFIG_SYS_FSL_ESDHC_USE_PIO */
 
        esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
 
@@ -221,6 +299,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 
        /* Wait until all of the blocks are transferred */
        if (data) {
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
+               esdhc_pio_read_write(mmc, data);
+#else
                do {
                        irqstat = esdhc_read32(&regs->irqstat);
 
@@ -231,6 +312,7 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
                                return TIMEOUT;
                } while (!(irqstat & IRQSTAT_TC) &&
                                (esdhc_read32(&regs->prsstat) & PRSSTAT_DLA));
+#endif
        }
 
        esdhc_write32(&regs->irqstat, -1);
@@ -265,18 +347,13 @@ void set_sysctl(struct mmc *mmc, uint clock)
 
        clk = (pre_div << 8) | (div << 4);
 
-       /* On imx the clock must be stopped before changing frequency */
-       if (cfg->clk_enable)
-               esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
+       esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
 
        esdhc_clrsetbits32(&regs->sysctl, SYSCTL_CLOCK_MASK, clk);
 
        udelay(10000);
 
-       clk = SYSCTL_PEREN;
-       /* On imx systems the clock must be explicitely enabled */
-       if (cfg->clk_enable)
-               clk |= SYSCTL_CKEN;
+       clk = SYSCTL_PEREN | SYSCTL_CKEN;
 
        esdhc_setbits32(&regs->sysctl, clk);
 }
@@ -349,6 +426,20 @@ static int esdhc_init(struct mmc *mmc)
        return ret;
 }
 
+static void esdhc_reset(struct fsl_esdhc *regs)
+{
+       unsigned long timeout = 100; /* wait max 100 ms */
+
+       /* reset the controller */
+       esdhc_write32(&regs->sysctl, SYSCTL_RSTA);
+
+       /* hardware clears the bit when it is done */
+       while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
+               udelay(1000);
+       if (!timeout)
+               printf("MMC/SD: Reset never completed.\n");
+}
+
 int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
 {
        struct fsl_esdhc *regs;
@@ -363,6 +454,9 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
        sprintf(mmc->name, "FSL_ESDHC");
        regs = (struct fsl_esdhc *)cfg->esdhc_base;
 
+       /* First reset the eSDHC controller */
+       esdhc_reset(regs);
+
        mmc->priv = cfg;
        mmc->send_cmd = esdhc_send_cmd;
        mmc->set_ios = esdhc_set_ios;