From patchwork Tue Jan 21 09:42:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 239856 List-Id: U-Boot discussion From: yamada.masahiro at socionext.com (Masahiro Yamada) Date: Tue, 21 Jan 2020 18:42:05 +0900 Subject: [PATCH] mmc: sdhci-cadence: send tune request twice to work around errata Message-ID: <20200121094205.6796-1-yamada.masahiro@socionext.com> Cadence sent out an errata report to their customers of this IP. This errata is not so severe, but the tune request should be sent twice to avoid the potential issue. Quote from the report: Problem Summary --------------- The IP6116 SD/eMMC PHY design has a timing issue on receive data path. This issue may lead to an incorrect values of read/write pointers of the synchronization FIFO. Such a situation can happen at the SDR104 and HS200 tuning procedure when the PHY is requested to change a phase of sampling clock when moving to the next tuning iteration. Workarounds ----------- The following are valid workarounds to resolve the issue: 1. In eMMC mode, software sends tune request twice instead of once at each iteration. This means that the clock phase is not changed on the second request so there is no potential for clock instability. 2. In SD mode, software must not use the hardware tuning and instead perform an almost identical procedure to eMMC, using the HRS34 Tune Force register. Signed-off-by: Masahiro Yamada --- drivers/mmc/sdhci-cadence.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index 4736263bf2a6..eb53653435df 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -170,6 +170,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, { void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS06; u32 tmp; + int i, ret; if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val))) return -EINVAL; @@ -177,11 +178,23 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, tmp = readl(reg); tmp &= ~SDHCI_CDNS_HRS06_TUNE; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val); - tmp |= SDHCI_CDNS_HRS06_TUNE_UP; - writel(tmp, reg); - return readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), - 1); + /* + * Workaround for IP errata: + * The IP6116 SD/eMMC PHY design has a timing issue on receive data + * path. Send tune request twice. + */ + for (i = 0; i < 2; i++) { + tmp |= SDHCI_CDNS_HRS06_TUNE_UP; + writel(tmp, reg); + + ret = readl_poll_timeout(reg, tmp, + !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), 1); + if (ret) + return ret; + } + + return 0; } static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev,