Message ID | 1573816712-26841-2-git-send-email-haibo.chen@nxp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | None | expand |
On 15/11/19 1:18 PM, haibo.chen@nxp.com wrote: > From: Haibo Chen <haibo.chen@nxp.com> > > When force clock off, check the SDOFF of register PRSSTAT to make sure > the clock is gate off. Before force clock on, check the SDSTB of register > PRSSTAT to make sure the clock is stable, this will eliminate the clock > glitch. > > Signed-off-by: Haibo Chen <haibo.chen@nxp.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> > --- > drivers/mmc/host/sdhci-esdhc-imx.c | 24 +++++++++++++++++++++++- > drivers/mmc/host/sdhci-esdhc.h | 1 + > 2 files changed, 24 insertions(+), 1 deletion(-) > > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c > index 2ed945f5c259..0667b6903708 100644 > --- a/drivers/mmc/host/sdhci-esdhc-imx.c > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c > @@ -9,6 +9,7 @@ > */ > > #include <linux/io.h> > +#include <linux/iopoll.h> > #include <linux/delay.h> > #include <linux/err.h> > #include <linux/clk.h> > @@ -313,6 +314,17 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i > writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); > } > > +static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host) > +{ > + u32 present_state; > + int ret; > + > + ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state, > + (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100); > + if (ret == -ETIMEDOUT) > + dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__); > +} > + > static u32 esdhc_readl_le(struct sdhci_host *host, int reg) > { > struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > @@ -526,6 +538,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) > else > new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; > writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); > + if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON)) > + esdhc_wait_for_card_clock_gate_off(host); > return; > case SDHCI_HOST_CONTROL2: > new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); > @@ -754,12 +768,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, > int ddr_pre_div = imx_data->is_ddr ? 2 : 1; > int pre_div = 1; > int div = 1; > + int ret; > u32 temp, val; > > if (esdhc_is_usdhc(imx_data)) { > val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); > writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, > host->ioaddr + ESDHC_VENDOR_SPEC); > + esdhc_wait_for_card_clock_gate_off(host); > } > > if (clock == 0) { > @@ -814,13 +830,18 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, > | (pre_div << ESDHC_PREDIV_SHIFT)); > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > > + /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */ > + ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp, > + (temp & ESDHC_CLOCK_STABLE), 2, 100); > + if (ret == -ETIMEDOUT) > + dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n"); > + > if (esdhc_is_usdhc(imx_data)) { > val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); > writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, > host->ioaddr + ESDHC_VENDOR_SPEC); > } > > - mdelay(1); > } > > static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) > @@ -1005,6 +1026,7 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host) > writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & > ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, > host->ioaddr + ESDHC_VENDOR_SPEC); > + esdhc_wait_for_card_clock_gate_off(host); > > /* force a reset on strobe dll */ > writel(ESDHC_STROBE_DLL_CTRL_RESET, > diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h > index 9289bb4d633e..947212f16bc6 100644 > --- a/drivers/mmc/host/sdhci-esdhc.h > +++ b/drivers/mmc/host/sdhci-esdhc.h > @@ -31,6 +31,7 @@ > > /* Present State Register */ > #define ESDHC_PRSSTAT 0x24 > +#define ESDHC_CLOCK_GATE_OFF 0x00000080 > #define ESDHC_CLOCK_STABLE 0x00000008 > > /* Protocol Control Register */ >
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 2ed945f5c259..0667b6903708 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -9,6 +9,7 @@ */ #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/clk.h> @@ -313,6 +314,17 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); } +static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host) +{ + u32 present_state; + int ret; + + ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state, + (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100); + if (ret == -ETIMEDOUT) + dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__); +} + static u32 esdhc_readl_le(struct sdhci_host *host, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -526,6 +538,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) else new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); + if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON)) + esdhc_wait_for_card_clock_gate_off(host); return; case SDHCI_HOST_CONTROL2: new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); @@ -754,12 +768,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, int ddr_pre_div = imx_data->is_ddr ? 2 : 1; int pre_div = 1; int div = 1; + int ret; u32 temp, val; if (esdhc_is_usdhc(imx_data)) { val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, host->ioaddr + ESDHC_VENDOR_SPEC); + esdhc_wait_for_card_clock_gate_off(host); } if (clock == 0) { @@ -814,13 +830,18 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, | (pre_div << ESDHC_PREDIV_SHIFT)); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); + /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */ + ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp, + (temp & ESDHC_CLOCK_STABLE), 2, 100); + if (ret == -ETIMEDOUT) + dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n"); + if (esdhc_is_usdhc(imx_data)) { val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, host->ioaddr + ESDHC_VENDOR_SPEC); } - mdelay(1); } static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) @@ -1005,6 +1026,7 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host) writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, host->ioaddr + ESDHC_VENDOR_SPEC); + esdhc_wait_for_card_clock_gate_off(host); /* force a reset on strobe dll */ writel(ESDHC_STROBE_DLL_CTRL_RESET, diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index 9289bb4d633e..947212f16bc6 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -31,6 +31,7 @@ /* Present State Register */ #define ESDHC_PRSSTAT 0x24 +#define ESDHC_CLOCK_GATE_OFF 0x00000080 #define ESDHC_CLOCK_STABLE 0x00000008 /* Protocol Control Register */