From patchwork Fri Nov 8 02:06:57 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Haijun.Zhang" X-Patchwork-Id: 289667 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id CCD1C2C00A9 for ; Fri, 8 Nov 2013 13:53:33 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 089C84A3D8; Fri, 8 Nov 2013 03:53:25 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HKPBqQtujoND; Fri, 8 Nov 2013 03:53:24 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1BF634A3E6; Fri, 8 Nov 2013 03:53:08 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 485F24A3BB for ; Fri, 8 Nov 2013 03:51:25 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qhtPUq2WgUxj for ; Fri, 8 Nov 2013 03:51:20 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 BL_NJABL=ERR(-1.5) (only DNSBL check requested) Received: from tx2outboundpool.messaging.microsoft.com (tx2ehsobe004.messaging.microsoft.com [65.55.88.14]) by theia.denx.de (Postfix) with ESMTPS id 2EF9C4A3BF for ; Fri, 8 Nov 2013 03:51:13 +0100 (CET) Received: from mail209-tx2-R.bigfish.com (10.9.14.239) by TX2EHSOBE002.bigfish.com (10.9.40.22) with Microsoft SMTP Server id 14.1.225.22; Fri, 8 Nov 2013 02:51:10 +0000 Received: from mail209-tx2 (localhost [127.0.0.1]) by mail209-tx2-R.bigfish.com (Postfix) with ESMTP id 592C96802CB; Fri, 8 Nov 2013 02:51:10 +0000 (UTC) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-SpamScore: 0 X-BigFish: VS0(zzzz1f42h2148h208ch1ee6h1de0h1fdah2073h2146h1202h1e76h1d1ah1d2ah1fc6hzz1de098h8275bh1de097hz2dh2a8h839he5bhf0ah1288h12a5h12a9h12bdh12e5h137ah139eh13b6h1441h1504h1537h162dh1631h1758h1898h18e1h1946h19b5h1ad9h1b0ah1b2fh2222h224fh1fb3h1d0ch1d2eh1d3fh1dfeh1dffh1e23h1fe8h1ff5h2218h2216h1155h) Received: from mail209-tx2 (localhost.localdomain [127.0.0.1]) by mail209-tx2 (MessageSwitch) id 1383879068155439_19490; Fri, 8 Nov 2013 02:51:08 +0000 (UTC) Received: from TX2EHSMHS024.bigfish.com (unknown [10.9.14.229]) by mail209-tx2.bigfish.com (Postfix) with ESMTP id 2165562004C; Fri, 8 Nov 2013 02:51:08 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by TX2EHSMHS024.bigfish.com (10.9.99.124) with Microsoft SMTP Server (TLS) id 14.16.227.3; Fri, 8 Nov 2013 02:51:07 +0000 Received: from az84smr01.freescale.net (10.64.34.197) by 039-SN1MMR1-004.039d.mgd.msft.net (10.84.1.14) with Microsoft SMTP Server (TLS) id 14.3.158.2; Fri, 8 Nov 2013 02:51:07 +0000 Received: from rock.am.freescale.net (rock.ap.freescale.net [10.193.20.106]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id rA82osJs031858; Thu, 7 Nov 2013 19:51:04 -0700 From: Haijun Zhang To: , , Date: Fri, 8 Nov 2013 10:06:57 +0800 Message-ID: <1383876423-2265-2-git-send-email-Haijun.Zhang@freescale.com> X-Mailer: git-send-email 1.8.4 In-Reply-To: <1383876423-2265-1-git-send-email-Haijun.Zhang@freescale.com> References: <1383876423-2265-1-git-send-email-Haijun.Zhang@freescale.com> MIME-Version: 1.0 X-OriginatorOrg: freescale.com X-FOPE-CONNECTOR: Id%0$Dn%*$RO%0$TLS%0$FQDN%$TlsDn% X-Mailman-Approved-At: Fri, 08 Nov 2013 03:53:06 +0100 Cc: Haijun Zhang , trini@ti.com, X.Xie@freescale.com, scottwood@freescale.com Subject: [U-Boot] [PATCH] powerpc/esdhc: Update esdhc command execution process X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 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 --- 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..10b1fcf 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, -1); + + 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)) + ; + } + } + + esdhc_write32(®s->irqstat, -1); + + return ret; } static void set_sysctl(struct mmc *mmc, uint clock)