AnsweredAssumed Answered

imx8mq sd3.0 fails after tuning

Question asked by Miles Wang on Aug 15, 2018
Latest reply on Aug 15, 2018 by igorpadykov

Dear Sir,

 

I want to support imx8mq-evk SD3.0 on VxWork.  I follow the tuning procedure in "sdhci-esdhc-imx.c" as below. But if the tuning is done by calling  esdhc_executing_tuning(), then there is not command response any more. If the tuning is not done, SDR50 works, but SDR104 fails because data CRC error. So I doubt that tuning procedure is not enough. Can you tell me what is missing? Do you have application note to show how to do tuning?  Thanks.

 

static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
{
u32 reg;

/* FIXME: delay a bit for card to be ready for next tuning due to errors */
mdelay(1);

reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
ESDHC_MIX_CTRL_FBCLK_SEL;
writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
dev_dbg(mmc_dev(host->mmc),
"tunning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n",
val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
}

static void esdhc_post_tuning(struct sdhci_host *host)
{
u32 reg;

reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
}

static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
{
int min, max, avg, ret;

/* find the mininum delay first which can pass tuning */
min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min);
if (!mmc_send_tuning(host->mmc, opcode, NULL))
break;
min += ESDHC_TUNE_CTRL_STEP;
}

/* find the maxinum delay which can not pass tuning */
max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max);
if (mmc_send_tuning(host->mmc, opcode, NULL)) {
max -= ESDHC_TUNE_CTRL_STEP;
break;
}
max += ESDHC_TUNE_CTRL_STEP;
}

/* use average delay to get the best timing */
avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg);
ret = mmc_send_tuning(host->mmc, opcode, NULL);
esdhc_post_tuning(host);

dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
ret ? "failed" : "passed", avg, ret);

return ret;
}

Outcomes