[U-Boot] [PATCH 7/7 V5] powerpc/esdhc: Update esdhc command execution process
Zhang Haijun
b42677 at freescale.com
Fri Jan 10 04:54:21 CET 2014
Hi, Pantelis
This patch is based on patch http://patchwork.ozlabs.org/patch/283002/
I'm afraid it was delegated to York by mistake.
Best regards,
Haijun
于 2014/1/9 19:08, Pantelis Antoniou 写道:
> Hi Haijun,
>
> Patch does not apply.
>
> On Dec 30, 2013, at 10:20 AM, Haijun Zhang wrote:
>
>> The max timeout value esdhc host can accept is 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 caculated by
>> mult * 300ms * num(unit by erase group), so the time one erase
>> group need should be more than 300ms, 5000ms should be enough.
>>
>> 1. Add data reset procedure for data error and command with busy error.
>> 2. Add timeout value detecting during waiting for 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.
>>
>> Signed-off-by: Haijun Zhang <Haijun.Zhang at freescale.com>
>> ---
>> changes for V5:
>> - no changes
>>
>> drivers/mmc/fsl_esdhc.c | 164 +++++++++++++++++++++++++++++++-----------------
>> 1 file changed, 106 insertions(+), 58 deletions(-)
>>
>> diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
>> index 9f4d3a2..134a02d 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 = 0, 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, 0xffffffffU);
>> +
>> + 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,7 +358,20 @@ 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.
>> + */
>> if (data) {
>> #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
>> esdhc_pio_read_write(mmc, data);
>> @@ -387,20 +379,76 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
>> 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);
>> }
>>
>> - esdhc_write32(®s->irqstat, -1);
>> + /* 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 5 sec */
>> + while (timeout > 0 && !(esdhc_read32(®s->prsstat) &
>> + PRSSTAT_DAT0)) {
>> + mdelay(1);
>> + timeout--;
>> + }
>> +
>> + if (timeout <= 0) {
>> + printf("\nTimeout waiting for DAT0 to go high!\n");
>> + ret = TIMEOUT;
>> + goto reset;
>> + }
>> + }
>> +
>> + if (esdhc_read32(®s->irqstat) & (DATA_ERR | CMD_ERR))
>> + ret = COMM_ERR;
>> +
>> + if (ret)
>> + goto reset;
>> +
>> + esdhc_write32(®s->irqstat, 0xffffffffU);
>>
>> return 0;
>> +
>> +reset:
>> +
>> + /* Reset CMD and DATA portions on error */
>> + 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_RSTD);
>> + while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTD))
>> + ;
>> + }
>> +
>> + esdhc_write32(®s->irqstat, 0xffffffffU);
>> +
>> + return ret;
>> }
>>
>> static void set_sysctl(struct mmc *mmc, uint clock)
>> --
>> 1.8.4.1
>>
>>
> Regards
>
> -- Pantelis
>
>
>
More information about the U-Boot
mailing list