On 16/10/20 7:25 am, Yangbo Lu wrote: > For eMMC HS400 mode initialization, the DLL reset is a required step > if DLL is enabled to use previously, like in bootloader. > This step has not been documented in reference manual, but the RM will > be fixed sooner or later. > > This patch is to add the step of DLL reset, and make sure delay chain > locked for HS400. > > Signed-off-by: Yangbo Lu <yangbo.lu@xxxxxxx> > --- > drivers/mmc/host/sdhci-esdhc.h | 2 ++ > drivers/mmc/host/sdhci-of-esdhc.c | 24 ++++++++++++++++++++++++ > 2 files changed, 26 insertions(+) > > diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h > index a30796e..6de02f0 100644 > --- a/drivers/mmc/host/sdhci-esdhc.h > +++ b/drivers/mmc/host/sdhci-esdhc.h > @@ -5,6 +5,7 @@ > * Copyright (c) 2007 Freescale Semiconductor, Inc. > * Copyright (c) 2009 MontaVista Software, Inc. > * Copyright (c) 2010 Pengutronix e.K. > + * Copyright 2020 NXP > * Author: Wolfram Sang <kernel@xxxxxxxxxxxxxx> > */ > > @@ -88,6 +89,7 @@ > /* DLL Config 0 Register */ > #define ESDHC_DLLCFG0 0x160 > #define ESDHC_DLL_ENABLE 0x80000000 > +#define ESDHC_DLL_RESET 0x40000000 > #define ESDHC_DLL_FREQ_SEL 0x08000000 > > /* DLL Config 1 Register */ > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c > index 0b45eff..a39ff86 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -4,6 +4,7 @@ > * > * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc. > * Copyright (c) 2009 MontaVista Software, Inc. > + * Copyright 2020 NXP > * > * Authors: Xiaobo Xie <X.Xie@xxxxxxxxxxxxx> > * Anton Vorontsov <avorontsov@xxxxxxxxxxxxx> > @@ -743,6 +744,29 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > if (host->mmc->actual_clock == MMC_HS200_MAX_DTR) > temp |= ESDHC_DLL_FREQ_SEL; > sdhci_writel(host, temp, ESDHC_DLLCFG0); > + > + temp |= ESDHC_DLL_RESET; > + sdhci_writel(host, temp, ESDHC_DLLCFG0); > + udelay(1); > + temp &= ~ESDHC_DLL_RESET; > + sdhci_writel(host, temp, ESDHC_DLLCFG0); > + > + /* Wait max 20 ms */ > + timeout = ktime_add_ms(ktime_get(), 20); > + while (1) { > + bool timedout = ktime_after(ktime_get(), timeout); > + > + if (sdhci_readl(host, ESDHC_DLLSTAT0) & > + ESDHC_DLL_STS_SLV_LOCK) > + break; > + if (timedout) { > + pr_err("%s: timeout for delay chain lock.\n", > + mmc_hostname(host->mmc)); > + break; > + } > + usleep_range(10, 20); > + } It is possible now to do these loops using read_poll_timeout e.g. something like this: if (read_poll_timeout(sdhci_readl, temp, temp & ESDHC_DLL_STS_SLV_LOCK, 10, 20000, false, host, ESDHC_DLLSTAT0)) pr_err("%s: timeout for delay chain lock.\n", mmc_hostname(host->mmc)); > + > temp = sdhci_readl(host, ESDHC_TBCTL); > sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL); > >