Hi Haijun, On Nov 5, 2013, at 8:23 AM, Haijun Zhang wrote:
> The max timeout value esdhc host can accept was about 2.69 sec > At 50 Mhz SD_CLK period, the max busy timeout > value = 2^27 * SD_CLK period ~= 2.69 sec. > > In case erase command CMD38 timeout is caculate by ^ calculated? > mult * 300ms * num(unit by erase group), so the time one erase > group need should be more than 300ms, 500ms should be enough. > > 1. Add data reset for data error and command with busy error. > 2. Add timeout value detecting during waiting transfer complete. > 3. Ignore Command inhibit (DAT) state when excuting CMD12. > 4. Add command CRC error detecting. > 5. Enlarged the timeout value used for busy state release. > 6. In case eSDHC host version 2.3, host will signal transfer complete > interrupt once busy state was release. > > Signed-off-by: Haijun Zhang <haijun.zh...@freescale.com> > --- > drivers/mmc/fsl_esdhc.c | 165 +++++++++++++++++++++++++++++++----------------- > 1 file changed, 108 insertions(+), 57 deletions(-) > > diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c > index 9f4d3a2..a8503fb 100644 > --- a/drivers/mmc/fsl_esdhc.c > +++ b/drivers/mmc/fsl_esdhc.c > @@ -266,26 +266,36 @@ static int > esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) > { > uint xfertyp; > - uint irqstat; > + uint irqstat, mask; > struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; > volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; > + int ret = 0, timeout; > + > + esdhc_write32(®s->irqstat, -1); ^ Please don't -1 for unsigned quantities. Use 0xffffffffU if need be. I know it used to be -1, but since we're making the changes here, lets fix it in every case. > + > + sync(); > + > + mask = PRSSTAT_CICHB | PRSSTAT_CIDHB; > > #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111 > if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) > return 0; > +#else > + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) > + mask &= ~PRSSTAT_CIDHB; > #endif > > - esdhc_write32(®s->irqstat, -1); > - > - sync(); > - > /* Wait for the bus to be idle */ > - while ((esdhc_read32(®s->prsstat) & PRSSTAT_CICHB) || > - (esdhc_read32(®s->prsstat) & PRSSTAT_CIDHB)) > - ; > - > - while (esdhc_read32(®s->prsstat) & PRSSTAT_DLA) > - ; > + timeout = 1000; > + while (esdhc_read32(®s->prsstat) & mask) { > + if (timeout == 0) { > + printf("\nController never released inhibit bit(s).\n"); > + ret = COMM_ERR; > + goto reset; > + } > + timeout--; > + mdelay(1); > + } > > /* Wait at least 8 SD clock cycles before the next command */ > /* > @@ -296,11 +306,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, > struct mmc_data *data) > > /* Set up for a data transfer if we have one */ > if (data) { > - int err; > - > - err = esdhc_setup_data(mmc, data); > - if(err) > - return err; > + ret = esdhc_setup_data(mmc, data); > + if (ret) > + goto reset; > } > > /* Figure out the transfer arguments */ > @@ -325,43 +333,14 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, > struct mmc_data *data) > > irqstat = esdhc_read32(®s->irqstat); > > - /* Reset CMD and DATA portions on error */ > - if (irqstat & CMD_ERR) { > - esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | > - SYSCTL_RSTC); > - while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) > - ; > - > - if (data) { > - esdhc_write32(®s->sysctl, > - esdhc_read32(®s->sysctl) | > - SYSCTL_RSTD); > - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD)) > - ; > - } > + if (irqstat & IRQSTAT_CTOE) { > + ret = TIMEOUT; > + goto reset; > } > > - if (irqstat & IRQSTAT_CTOE) > - return TIMEOUT; > - > - if (irqstat & CMD_ERR) > - return COMM_ERR; > - > - /* Workaround for ESDHC errata ENGcm03648 */ > - if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { > - int timeout = 2500; > - > - /* Poll on DATA0 line for cmd with busy signal for 250 ms */ > - while (timeout > 0 && !(esdhc_read32(®s->prsstat) & > - PRSSTAT_DAT0)) { > - udelay(100); > - timeout--; > - } > - > - if (timeout <= 0) { > - printf("Timeout waiting for DAT0 to go high!\n"); > - return TIMEOUT; > - } > + if (irqstat & CMD_ERR) { > + ret = COMM_ERR; > + goto reset; > } > > /* Copy the response to the response buffer */ > @@ -379,28 +358,100 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, > struct mmc_data *data) > } else > cmd->response[0] = esdhc_read32(®s->cmdrsp0); > > - /* Wait until all of the blocks are transferred */ > + /* > + * At 50 Mhz SD_CLK period, the max busy timeout > + * value or data transfer time need was about > + * = 2^27 * SD_CLK period ~= 2.69 sec. > + * So wait max 10 sec for data transfer complete or busy > + * state release. > + */ > + timeout = 10000; > + > + /* > + * eSDHC host V2.3 has response busy interrupt, so > + * we should wait for busy state to be released and data > + * was out of programing state before next command send. > + */ > +#ifdef CONFIG_FSL_SDHC_V2_3 > + if (data || (cmd->resp_type & MMC_RSP_BUSY)) { > +#else > if (data) { > +#endif > #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO > esdhc_pio_read_write(mmc, data); > #else > do { > irqstat = esdhc_read32(®s->irqstat); > > - if (irqstat & IRQSTAT_DTOE) > - return TIMEOUT; > + if (irqstat & IRQSTAT_DTOE) { > + ret = TIMEOUT; > + break; > + } > > - if (irqstat & DATA_ERR) > - return COMM_ERR; > - } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE); > + if (irqstat & DATA_ERR) { > + ret = COMM_ERR; > + break; > + } > + > + if (timeout <= 0) { > + ret = TIMEOUT; > + break; > + } > + mdelay(1); > + timeout--; > + } while (((irqstat & DATA_COMPLETE) != DATA_COMPLETE) && > + (esdhc_read32(®s->prsstat) & PRSSTAT_DLA)); > #endif > if (data->flags & MMC_DATA_READ) > check_and_invalidate_dcache_range(cmd, data); > } > > + /* Workaround for ESDHC errata ENGcm03648 */ > + if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { > + int timeout = 5000; > + > + /* Poll on DATA0 line for cmd with busy signal for 500 ms */ > + while (timeout > 0 && !(esdhc_read32(®s->prsstat) & > + PRSSTAT_DAT0)) { > + udelay(100); > + timeout--; > + } > + > + if (timeout <= 0) { > + printf("\nTimeout waiting for DAT0 to go high!\n"); > + ret = TIMEOUT; > + goto reset; > + } > + } > + > + if (ret) > + goto reset; > + > esdhc_write32(®s->irqstat, -1); > > return 0; > + > +reset: > + > + /* Reset CMD and DATA portions on error */ > + if (irqstat & (CMD_ERR | DATA_ERR)) { > + esdhc_write32(®s->sysctl, esdhc_read32(®s->sysctl) | > + SYSCTL_RSTC); > + while (esdhc_read32(®s->sysctl) & SYSCTL_RSTC) > + ; > + > + if (data || (cmd->resp_type & MMC_RSP_BUSY)) { > + esdhc_write32(®s->sysctl, > + esdhc_read32(®s->sysctl) | > + SYSCTL_RSTA); > + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) > + ; > + } In general I do not like loops without a timeout terminating condition. I'll let it pass for now, but please follow up with a patch for the whole driver turning those into timeout condition terminated loops. > + } > + > + esdhc_write32(®s->irqstat, -1); > + > + return ret; > } > > static void set_sysctl(struct mmc *mmc, uint clock) > -- > 1.8.4 > > Regards -- Pantelis _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot