
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.
- Add data reset for data error and command with busy error.
- Add timeout value detecting during waiting transfer complete.
- Ignore Command inhibit (DAT) state when excuting CMD12.
- Add command CRC error detecting.
- Enlarged the timeout value used for busy state release.
- In case eSDHC host version 2.3, host will signal transfer complete
interrupt once busy state was release.
Signed-off-by: Haijun Zhang Haijun.Zhang@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