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

Andy Fleming afleming at gmail.com
Sat Apr 18 00:35:31 CEST 2009


On Fri, Apr 3, 2009 at 11:28 AM, Dipen Dudhat
<dipen.dudhat at 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 at 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(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
> +                       printf("\nThe SD card is locked. "
> +                                       "Can not write to a locked card.\n\n");
> +                       return TIMEOUT;
> +               }
> +               out_be32(&regs->dsaddr, (u32)data->src);
> +       } else
> +               out_be32(&regs->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(&regs->irqstat);
> +                       while(!(in_be32(&regs->prsstat) & PRSSTAT_BREN));
> +                       while(size && (!(irqstat & IRQSTAT_TC))) {
> +                               if(chunk_remain == 0) {
> +                                       udelay(1000);
> +                                       irqstat = in_be32(&regs->irqstat);
> +                                       databuf = in_be32(&regs->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(&regs->irqstat);
> +                       while(!(in_be32(&regs->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(&regs->irqstat);
> +                                       out_be32(&regs->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(&regs->irqstat);
> +
> +               if (irqstat & DATA_ERR)
> +                       return COMM_ERR;
> +
> +               if (irqstat & IRQSTAT_DTOE)
> +                       return TIMEOUT;
> +       } while (!(irqstat & IRQSTAT_TC) &&
> +                       (in_be32(&regs->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(&regs->irqstat);
> -
> -                       if (irqstat & DATA_ERR)
> -                               return COMM_ERR;
> -
> -                       if (irqstat & IRQSTAT_DTOE)
> -                               return TIMEOUT;
> -               } while (!(irqstat & IRQSTAT_TC) &&
> -                               (in_be32(&regs->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


More information about the U-Boot mailing list