From patchwork Tue May 19 03:37:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peng Fan X-Patchwork-Id: 245966 List-Id: U-Boot discussion From: peng.fan at nxp.com (Peng Fan) Date: Tue, 19 May 2020 03:37:53 +0000 Subject: [PATCH] mmc: retry CMD1 in mmc_send_op_cond() until the eMMC is ready In-Reply-To: <1589526845-14680-1-git-send-email-haibo.chen@nxp.com> References: <1589526845-14680-1-git-send-email-haibo.chen@nxp.com> Message-ID: > Subject: [PATCH] mmc: retry CMD1 in mmc_send_op_cond() until the eMMC > is ready > > From: Haibo Chen > > According to eMMC specification v5.1 section 6.4.3, we should issue > CMD1 repeatedly in the idle state until the eMMC is ready even if > mmc_send_op_cond() send CMD1 with argument = 0. Otherwise some > eMMC devices seems to enter the inactive mode after > mmc_complete_op_cond() issued CMD0 when the eMMC device is busy. This > patch also align with Linux 5.7. > > Signed-off-by: Haibo Chen > --- > drivers/mmc/mmc.c | 41 +++++++++++++++++++++++++++++++++-------- > 1 file changed, 33 insertions(+), 8 deletions(-) > > diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index > 523c055967..509549756b 100644 > --- a/drivers/mmc/mmc.c > +++ b/drivers/mmc/mmc.c > @@ -664,21 +664,46 @@ static int mmc_send_op_cond_iter(struct mmc > *mmc, int use_arg) > > static int mmc_send_op_cond(struct mmc *mmc) { > + struct mmc_cmd cmd; > int err, i; > + int timeout = 1000; > + ulong start; > > /* Some cards seem to need this */ > mmc_go_idle(mmc); > > - /* Asking to the card its capabilities */ > - for (i = 0; i < 2; i++) { > - err = mmc_send_op_cond_iter(mmc, i != 0); > + cmd.cmdidx = MMC_CMD_SEND_OP_COND; > + cmd.resp_type = MMC_RSP_R3; > + cmd.cmdarg = 0; > + > + start = get_timer(0); > + /* > + * According to eMMC specification v5.1 section 6.4.3, we > + * should issue CMD1 repeatedly in the idle state until > + * the eMMC is ready. Otherwise some eMMC devices seem to enter > + * the inactive mode after mmc_complete_op_cond() issued CMD0 > when > + * the eMMC device is busy. > + */ Could we just extend the previous for loop to fix the issue? Your piece code duplicate much of the code and changed the original behavior. > + while (1) { > + err = mmc_send_cmd(mmc, &cmd, NULL); > if (err) > return err; > - > - /* exit if not busy (flag seems to be inverted) */ > - if (mmc->ocr & OCR_BUSY) > - break; > + if (mmc_host_is_spi(mmc)) { > + if (!(cmd.response[0] & (1 << 0))) > + break; > + } else { > + mmc->ocr = cmd.response[0]; > + /* exit if not busy (flag seems to be inverted) */ > + if (mmc->ocr & OCR_BUSY) > + break; > + } > + if (get_timer(start) > timeout) > + return -EOPNOTSUPP; TIMEOUT, please. > + udelay(100); This will change the original behavior by adding a delay. > + if (!mmc_host_is_spi(mmc)) > + cmd.cmdarg = cmd.response[0] | (1 << 30); Do we need "1 << 30" ? > } > + > mmc->op_cond_pending = 1; > return 0; > } > @@ -691,7 +716,7 @@ static int mmc_complete_op_cond(struct mmc > *mmc) > int err; > > mmc->op_cond_pending = 0; > - if (!(mmc->ocr & OCR_BUSY)) { > + if (mmc->ocr & OCR_BUSY) { When card not go out busy, it means card not finish power up seq. Why drop !? > /* Some cards seem to need this */ > mmc_go_idle(mmc); > > -- Would the following patch help? Thanks, Peng. > 2.17.1 diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 523c055967..d3a0538cdb 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -665,12 +665,15 @@ static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) static int mmc_send_op_cond(struct mmc *mmc) { int err, i; + int timeout = 1000; + ulong start; /* Some cards seem to need this */ mmc_go_idle(mmc); + start = get_timer(0); /* Asking to the card its capabilities */ - for (i = 0; i < 2; i++) { + for (i = 0; ; i++) { err = mmc_send_op_cond_iter(mmc, i != 0); if (err) return err; @@ -678,6 +681,9 @@ static int mmc_send_op_cond(struct mmc *mmc) /* exit if not busy (flag seems to be inverted) */ if (mmc->ocr & OCR_BUSY) break; + + if (get_timer(start) > timeout) + return -ETIMEDOUT; } mmc->op_cond_pending = 1; return 0;