diff options
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 87 | ||||
-rw-r--r-- | include/fsl_esdhc.h | 2 |
2 files changed, 87 insertions, 2 deletions
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 0f6f8b1..a9b07a9 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -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(®s->irqstat); + while (!(esdhc_read32(®s->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(®s->irqstat); + databuf = in_le32(®s->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(®s->irqstat); + while (!(esdhc_read32(®s->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(®s->irqstat); + out_le32(®s->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(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + printf("\nThe SD card is locked. " + "Can not write to a locked card.\n\n"); + return TIMEOUT; + } + esdhc_write32(®s->dsaddr, (u32)data->src); + } else + esdhc_write32(®s->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(®s->dsaddr, (u32)data->src); } +#endif esdhc_write32(®s->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(®s->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(®s->prsstat) & PRSSTAT_DLA)); +#endif } esdhc_write32(®s->irqstat, -1); diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index f9ae15a..477bbd7 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -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) @@ -121,6 +122,7 @@ #define XFERTYP_DMAEN 0x00000001 #define CINS_TIMEOUT 1000 +#define PIO_TIMEOUT 100000 #define DSADDR 0x2e004 |