[U-Boot] [PATCH] PIO Mode Read/Write support for FSL eSDHC

PIO mode support for freescale eSDHC Driver. PIO has added to enable data transfer without use of eSDHC DMA Engine.
Signed-off-by: Dipen Dudhat dipen.dudhat@freescale.com --- drivers/mmc/fsl_esdhc.c | 136 +++++++++++++++++++++++++++++++++++++++++++---- include/fsl_esdhc.h | 1 + 2 files changed, 127 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 0ba45cd..c96011f 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -71,8 +71,12 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) uint xfertyp = 0;
if (data) { +#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO + xfertyp |= XFERTYP_DPSEL; +#else xfertyp |= XFERTYP_DPSEL | XFERTYP_DMAEN;
+#endif if (data->blocks > 1) { xfertyp |= XFERTYP_MSBSEL; xfertyp |= XFERTYP_BCEN; @@ -96,6 +100,102 @@ uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) return XFERTYP_CMD(cmd->cmdidx) | xfertyp; }
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO +static int esdhc_setup_pio_data(struct mmc *mmc, struct mmc_data *data) +{ + int timeout; + struct fsl_esdhc *regs = mmc->priv; + + if (!(data->flags & MMC_DATA_READ)) { + if ((in_be32(®s->prsstat) & PRSSTAT_WPSPL) == 0) { + printf("\nThe SD card is locked. " + "Can not write to a locked card.\n\n"); + return TIMEOUT; + } + out_be32(®s->dsaddr, (u32)data->src); + } else + out_be32(®s->dsaddr, (u32)data->dest); + + out_be32(®s->blkattr, data->blocks << 16 | data->blocksize); + + /* Calculate the timeout period for data transactions */ + timeout = __ilog2(mmc->tran_speed/10); + timeout -= 13; + + if (timeout > 14) + timeout = 14; + + if (timeout < 0) + timeout = 0; + + clrsetbits_be32(®s->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16); + + return 0; +} + +/* + * 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) +{ + volatile struct fsl_esdhc *regs = mmc->priv; + uint blocks; + uchar* buffer; + uint chunk_remain; + uint databuf; + uint size,irqstat; + + if (data->flags & MMC_DATA_READ) { + blocks = data->blocks; + buffer = (uchar*) data->dest; + chunk_remain = 0; + while(blocks) { + size = data->blocksize; + irqstat = in_be32(®s->irqstat); + while(!(in_be32(®s->prsstat) & PRSSTAT_BREN)); + while(size && (!(irqstat & IRQSTAT_TC))) { + if(chunk_remain == 0) { + udelay(1000); + irqstat = in_be32(®s->irqstat); + databuf = in_be32(®s->datport); + chunk_remain =4; + } + *buffer = databuf & 0xFF; + buffer++; + databuf >>= 8; + size--; + chunk_remain--; + } + blocks--; + } + } else { + blocks = data->blocks; + buffer = (uchar*) data->src; + chunk_remain = 4; + while(blocks) { + size = data->blocksize; + irqstat = in_be32(®s->irqstat); + while(!(in_be32(®s->prsstat) & PRSSTAT_BWEN)); + while(size && (!(irqstat & IRQSTAT_TC))) { + databuf >>=8; + databuf |= (u32)*buffer<<24; + buffer++; + size--; + chunk_remain--; + if(chunk_remain == 0) { + irqstat = in_be32(®s->irqstat); + out_be32(®s->datport,databuf); + chunk_remain =4; + } + } + blocks--; + } + } +} +#endif + static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { uint wml_value; @@ -141,6 +241,23 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) return 0; }
+static void +esdhc_dma_read_write(struct mmc *mmc) +{ + volatile struct fsl_esdhc *regs = mmc->priv; + uint irqstat; + + do { + irqstat = in_be32(®s->irqstat); + + if (irqstat & DATA_ERR) + return COMM_ERR; + + if (irqstat & IRQSTAT_DTOE) + return TIMEOUT; + } while (!(irqstat & IRQSTAT_TC) && + (in_be32(®s->prsstat) & PRSSTAT_DLA)); +}
/* * Sends a command out on the bus. Takes the mmc pointer, @@ -174,7 +291,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (data) { int err;
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO + err = esdhc_setup_pio_data(mmc, data); +#else err = esdhc_setup_data(mmc, data); +#endif if(err) return err; } @@ -215,16 +336,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Wait until all of the blocks are transferred */ if (data) { - do { - irqstat = in_be32(®s->irqstat); - - if (irqstat & DATA_ERR) - return COMM_ERR; - - if (irqstat & IRQSTAT_DTOE) - return TIMEOUT; - } while (!(irqstat & IRQSTAT_TC) && - (in_be32(®s->prsstat) & PRSSTAT_DLA)); +#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO + esdhc_pio_read_write(mmc,data); +#else + esdhc_dma_read_write(mmc); +#endif }
out_be32(®s->irqstat, -1); diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index 0a5c5d6..c6504c4 100644 --- a/include/fsl_esdhc.h +++ b/include/fsl_esdhc.h @@ -84,6 +84,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)

On Fri, Apr 3, 2009 at 11:28 AM, Dipen Dudhat dipen.dudhat@freescale.com wrote:
PIO mode support for freescale eSDHC Driver. PIO has added to enable data transfer without use of eSDHC DMA Engine.
Signed-off-by: Dipen Dudhat dipen.dudhat@freescale.com
drivers/mmc/fsl_esdhc.c | 136 +++++++++++++++++++++++++++++++++++++++++++---- include/fsl_esdhc.h | 1 + 2 files changed, 127 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 0ba45cd..c96011f 100644
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO +static int esdhc_setup_pio_data(struct mmc *mmc, struct mmc_data *data) +{
- int timeout;
- struct fsl_esdhc *regs = mmc->priv;
- if (!(data->flags & MMC_DATA_READ)) {
- if ((in_be32(®s->prsstat) & PRSSTAT_WPSPL) == 0) {
- printf("\nThe SD card is locked. "
- "Can not write to a locked card.\n\n");
- return TIMEOUT;
- }
- out_be32(®s->dsaddr, (u32)data->src);
- } else
- out_be32(®s->dsaddr, (u32)data->dest);
Rather than create two different versions of the setup function, which are about 50% the same, make functions for the stuff above this point in each of the existing functions, and then do the #ifdef for picking which to call inside this function.
+/*
- 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) +{
- volatile struct fsl_esdhc *regs = mmc->priv;
- uint blocks;
- uchar* buffer;
- uint chunk_remain;
- uint databuf;
- uint size,irqstat;
- if (data->flags & MMC_DATA_READ) {
- blocks = data->blocks;
- buffer = (uchar*) data->dest;
- chunk_remain = 0;
- while(blocks) {
- size = data->blocksize;
- irqstat = in_be32(®s->irqstat);
- while(!(in_be32(®s->prsstat) & PRSSTAT_BREN));
- while(size && (!(irqstat & IRQSTAT_TC))) {
- if(chunk_remain == 0) {
- udelay(1000);
- irqstat = in_be32(®s->irqstat);
- databuf = in_be32(®s->datport);
- chunk_remain =4;
- }
- *buffer = databuf & 0xFF;
- buffer++;
- databuf >>= 8;
- size--;
- chunk_remain--;
- }
- blocks--;
- }
- } else {
- blocks = data->blocks;
- buffer = (uchar*) data->src;
- chunk_remain = 4;
- while(blocks) {
- size = data->blocksize;
- irqstat = in_be32(®s->irqstat);
- while(!(in_be32(®s->prsstat) & PRSSTAT_BWEN));
- while(size && (!(irqstat & IRQSTAT_TC))) {
- databuf >>=8;
- databuf |= (u32)*buffer<<24;
- buffer++;
- size--;
- chunk_remain--;
- if(chunk_remain == 0) {
- irqstat = in_be32(®s->irqstat);
- out_be32(®s->datport,databuf);
- chunk_remain =4;
- }
- }
- blocks--;
- }
- }
+} +#endif
Split this into a read function and a write function, and move the if() statement into the caller.
static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) { uint wml_value; @@ -141,6 +241,23 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) return 0; }
+static void +esdhc_dma_read_write(struct mmc *mmc)
Call this esdhc_wait_dma()
+{
- volatile struct fsl_esdhc *regs = mmc->priv;
- uint irqstat;
- do {
- irqstat = in_be32(®s->irqstat);
- if (irqstat & DATA_ERR)
- return COMM_ERR;
- if (irqstat & IRQSTAT_DTOE)
- return TIMEOUT;
- } while (!(irqstat & IRQSTAT_TC) &&
- (in_be32(®s->prsstat) & PRSSTAT_DLA));
+}
/* * Sends a command out on the bus. Takes the mmc pointer, @@ -174,7 +291,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (data) { int err;
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
- err = esdhc_setup_pio_data(mmc, data);
+#else err = esdhc_setup_data(mmc, data); +#endif
Using my suggestion above, this would stay the same as it was.
if(err) return err; } @@ -215,16 +336,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Wait until all of the blocks are transferred */ if (data) {
- do {
- irqstat = in_be32(®s->irqstat);
- if (irqstat & DATA_ERR)
- return COMM_ERR;
- if (irqstat & IRQSTAT_DTOE)
- return TIMEOUT;
- } while (!(irqstat & IRQSTAT_TC) &&
- (in_be32(®s->prsstat) & PRSSTAT_DLA));
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
- esdhc_pio_read_write(mmc,data);
My suggestion is to put the if-else from read_write here, and call the read and write functions separately.
Andy
participants (2)
-
Andy Fleming
-
Dipen Dudhat