ppc/85xx: PIO Support for FSL eSDHC Controller Driver
authorDipen Dudhat <dipen.dudhat@freescale.com>
Mon, 5 Oct 2009 10:11:58 +0000 (15:41 +0530)
committerAndy Fleming <afleming@freescale.com>
Sat, 24 Apr 2010 02:02:30 +0000 (21:02 -0500)
On some Freescale SoC Internal DMA of eSDHC controller has bug.
So PIO Mode has been introduced to do data transfer using CPU.

Signed-off-by: Dipen Dudhat <dipen.dudhat@freescale.com>
drivers/mmc/fsl_esdhc.c
include/fsl_esdhc.h

index 0f6f8b161c91a645746756cb50989e11aeea7561..a9b07a97c7d3356022cb5564c9b1fd58461dd2b8 100644 (file)
@@ -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,6 +99,71 @@ 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 int
+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 timeout;
+                       }
+                       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 = 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 timeout;
+                       }
+                       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;
@@ -104,6 +171,17 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
        struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
        struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
 
+#ifdef 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);
+#else
        wml_value = data->blocksize/4;
 
        if (data->flags & MMC_DATA_READ) {
@@ -124,6 +202,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
                                        wml_value << 16);
                esdhc_write32(&regs->dsaddr, (u32)data->src);
        }
+#endif
 
        esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
 
@@ -220,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);
 
@@ -230,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);
index f9ae15ad42a91158034726b64539e826eca0e1e4..477bbd792e81f4066c4f6d0b4239d798f82afc28 100644 (file)
@@ -90,6 +90,7 @@
 #define PRSSTAT_CDPL           (0x00040000)
 #define PRSSTAT_CINS           (0x00010000)
 #define PRSSTAT_BREN           (0x00000800)
+#define PRSSTAT_BWEN           (0x00000400)
 #define PRSSTAT_DLA            (0x00000004)
 #define PRSSTAT_CICHB          (0x00000002)
 #define PRSSTAT_CIDHB          (0x00000001)
 #define XFERTYP_DMAEN          0x00000001
 
 #define CINS_TIMEOUT           1000
+#define PIO_TIMEOUT            100000
 
 #define DSADDR         0x2e004