Message ID | 1482745590-29718-2-git-send-email-yangbo.lu@nxp.com (mailing list archive) |
---|---|
State | Accepted, archived |
Headers | show |
On 26/12/16 11:46, Yangbo Lu wrote: > The eSDHC_PRSSTAT[SDSTB] bit indicates whether the internal card clock is > stable. This bit is for the host driver to poll clock status when changing > the clock frequency. It is recommended to clear eSDHC_SYSCTL[SDCLKEN] > to remove glitch on the card clock when the frequency is changing. This > patch is to disable SDCLKEN bit before changing frequency and enable it > after SDSTB bit is set. > > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> > --- > Changes for v2: > - added Adrian into to list > --- > drivers/mmc/host/sdhci-esdhc.h | 5 +++++ > drivers/mmc/host/sdhci-of-esdhc.c | 21 ++++++++++++++++++--- > 2 files changed, 23 insertions(+), 3 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h > index 8cd8449..ece8b37 100644 > --- a/drivers/mmc/host/sdhci-esdhc.h > +++ b/drivers/mmc/host/sdhci-esdhc.h > @@ -31,6 +31,10 @@ > * eSDHC register definition > */ > > +/* Present State Register */ > +#define ESDHC_PRSSTAT 0x24 > +#define ESDHC_CLOCK_STABLE 0x00000008 > + > /* Protocol Control Register */ > #define ESDHC_PROCTL 0x28 > #define ESDHC_CTRL_4BITBUS (0x1 << 1) > @@ -43,6 +47,7 @@ > #define ESDHC_CLOCK_MASK 0x0000fff0 > #define ESDHC_PREDIV_SHIFT 8 > #define ESDHC_DIVIDER_SHIFT 4 > +#define ESDHC_CLOCK_SDCLKEN 0x00000008 > #define ESDHC_CLOCK_PEREN 0x00000004 > #define ESDHC_CLOCK_HCKEN 0x00000002 > #define ESDHC_CLOCK_IPGEN 0x00000001 > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c > index 9a6eb44..0849885 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > int pre_div = 1; > int div = 1; > + u32 timeout; > u32 temp; > > host->mmc->actual_clock = 0; > @@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > } > > temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); > - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN > - | ESDHC_CLOCK_MASK); > + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | > + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > > while (host->max_clk / pre_div / 16 > clock && pre_div < 256) > @@ -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > | (div << ESDHC_DIVIDER_SHIFT) > | (pre_div << ESDHC_PREDIV_SHIFT)); > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > - mdelay(1); > + > + /* Wait max 20 ms */ > + timeout = 20; > + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { > + if (timeout == 0) { > + pr_err("%s: Internal clock never stabilised.\n", > + mmc_hostname(host->mmc)); > + return; > + } > + timeout--; > + mdelay(1); > + } Please try to do this with readx_poll_timeout_atomic(). However we are not racing with anything (and one of the things that needs doing in SDHCI is to reduce the use of the spin lock) so you could drop the spin lock while using readx_poll_timeout() instead. > + > + temp |= ESDHC_CLOCK_SDCLKEN; > + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > } > > static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Adrian, Thanks a lot for reviewing my patches. Please see my comments inline. Best regards, Yangbo Lu > -----Original Message----- > From: Adrian Hunter [mailto:adrian.hunter@intel.com] > Sent: Thursday, January 12, 2017 3:09 PM > To: Y.B. Lu; linux-mmc@vger.kernel.org; ulf.hansson@linaro.org > Subject: Re: [v2, 2/2] mmc: sdhci-of-esdhc: avoid clock glitch when > frequency is changing > > On 26/12/16 11:46, Yangbo Lu wrote: > > The eSDHC_PRSSTAT[SDSTB] bit indicates whether the internal card clock > > is stable. This bit is for the host driver to poll clock status when > > changing the clock frequency. It is recommended to clear > > eSDHC_SYSCTL[SDCLKEN] to remove glitch on the card clock when the > > frequency is changing. This patch is to disable SDCLKEN bit before > > changing frequency and enable it after SDSTB bit is set. > > > > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> > > --- > > Changes for v2: > > - added Adrian into to list > > --- > > drivers/mmc/host/sdhci-esdhc.h | 5 +++++ > > drivers/mmc/host/sdhci-of-esdhc.c | 21 ++++++++++++++++++--- > > 2 files changed, 23 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/mmc/host/sdhci-esdhc.h > > b/drivers/mmc/host/sdhci-esdhc.h index 8cd8449..ece8b37 100644 > > --- a/drivers/mmc/host/sdhci-esdhc.h > > +++ b/drivers/mmc/host/sdhci-esdhc.h > > @@ -31,6 +31,10 @@ > > * eSDHC register definition > > */ > > > > +/* Present State Register */ > > +#define ESDHC_PRSSTAT 0x24 > > +#define ESDHC_CLOCK_STABLE 0x00000008 > > + > > /* Protocol Control Register */ > > #define ESDHC_PROCTL 0x28 > > #define ESDHC_CTRL_4BITBUS (0x1 << 1) > > @@ -43,6 +47,7 @@ > > #define ESDHC_CLOCK_MASK 0x0000fff0 > > #define ESDHC_PREDIV_SHIFT 8 > > #define ESDHC_DIVIDER_SHIFT 4 > > +#define ESDHC_CLOCK_SDCLKEN 0x00000008 > > #define ESDHC_CLOCK_PEREN 0x00000004 > > #define ESDHC_CLOCK_HCKEN 0x00000002 > > #define ESDHC_CLOCK_IPGEN 0x00000001 > > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c > > b/drivers/mmc/host/sdhci-of-esdhc.c > > index 9a6eb44..0849885 100644 > > --- a/drivers/mmc/host/sdhci-of-esdhc.c > > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > > @@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host > *host, unsigned int clock) > > struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > > int pre_div = 1; > > int div = 1; > > + u32 timeout; > > u32 temp; > > > > host->mmc->actual_clock = 0; > > @@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host > *host, unsigned int clock) > > } > > > > temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); > > - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN > > - | ESDHC_CLOCK_MASK); > > + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | > ESDHC_CLOCK_HCKEN | > > + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); > > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > > > > while (host->max_clk / pre_div / 16 > clock && pre_div < 256) @@ > > -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host > *host, unsigned int clock) > > | (div << ESDHC_DIVIDER_SHIFT) > > | (pre_div << ESDHC_PREDIV_SHIFT)); > > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > > - mdelay(1); > > + > > + /* Wait max 20 ms */ > > + timeout = 20; > > + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { > > + if (timeout == 0) { > > + pr_err("%s: Internal clock never stabilised.\n", > > + mmc_hostname(host->mmc)); > > + return; > > + } > > + timeout--; > > + mdelay(1); > > + } > > Please try to do this with readx_poll_timeout_atomic(). However we are > not racing with anything (and one of the things that needs doing in SDHCI > is to reduce the use of the spin lock) so you could drop the spin lock > while using > readx_poll_timeout() instead. > [Lu Yangbo-B47093] The function readx_poll_timeout_atomic() periodically polls an address, but the addr must be the only argument for op. Our sdhci_readl has two arguments. Any suggestion for this? readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) Thanks :) > > + > > + temp |= ESDHC_CLOCK_SDCLKEN; > > + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > > } > > > > static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int > > width) > > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 26/12/16 11:46, Yangbo Lu wrote: > The eSDHC_PRSSTAT[SDSTB] bit indicates whether the internal card clock is > stable. This bit is for the host driver to poll clock status when changing > the clock frequency. It is recommended to clear eSDHC_SYSCTL[SDCLKEN] > to remove glitch on the card clock when the frequency is changing. This > patch is to disable SDCLKEN bit before changing frequency and enable it > after SDSTB bit is set. > > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> > --- > Changes for v2: > - added Adrian into to list > --- > drivers/mmc/host/sdhci-esdhc.h | 5 +++++ > drivers/mmc/host/sdhci-of-esdhc.c | 21 ++++++++++++++++++--- > 2 files changed, 23 insertions(+), 3 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h > index 8cd8449..ece8b37 100644 > --- a/drivers/mmc/host/sdhci-esdhc.h > +++ b/drivers/mmc/host/sdhci-esdhc.h > @@ -31,6 +31,10 @@ > * eSDHC register definition > */ > > +/* Present State Register */ > +#define ESDHC_PRSSTAT 0x24 > +#define ESDHC_CLOCK_STABLE 0x00000008 > + > /* Protocol Control Register */ > #define ESDHC_PROCTL 0x28 > #define ESDHC_CTRL_4BITBUS (0x1 << 1) > @@ -43,6 +47,7 @@ > #define ESDHC_CLOCK_MASK 0x0000fff0 > #define ESDHC_PREDIV_SHIFT 8 > #define ESDHC_DIVIDER_SHIFT 4 > +#define ESDHC_CLOCK_SDCLKEN 0x00000008 > #define ESDHC_CLOCK_PEREN 0x00000004 > #define ESDHC_CLOCK_HCKEN 0x00000002 > #define ESDHC_CLOCK_IPGEN 0x00000001 > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c > index 9a6eb44..0849885 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > int pre_div = 1; > int div = 1; > + u32 timeout; > u32 temp; > > host->mmc->actual_clock = 0; > @@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > } > > temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); > - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN > - | ESDHC_CLOCK_MASK); > + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | > + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > > while (host->max_clk / pre_div / 16 > clock && pre_div < 256) > @@ -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > | (div << ESDHC_DIVIDER_SHIFT) > | (pre_div << ESDHC_PREDIV_SHIFT)); > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > - mdelay(1); > + > + /* Wait max 20 ms */ > + timeout = 20; > + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { > + if (timeout == 0) { > + pr_err("%s: Internal clock never stabilised.\n", > + mmc_hostname(host->mmc)); > + return; > + } > + timeout--; > + mdelay(1); > + } > + > + temp |= ESDHC_CLOCK_SDCLKEN; > + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > } > > static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 13/01/17 04:12, Y.B. Lu wrote: > Hi Adrian, > > Thanks a lot for reviewing my patches. > Please see my comments inline. > > Best regards, > Yangbo Lu > >> -----Original Message----- >> From: Adrian Hunter [mailto:adrian.hunter@intel.com] >> Sent: Thursday, January 12, 2017 3:09 PM >> To: Y.B. Lu; linux-mmc@vger.kernel.org; ulf.hansson@linaro.org >> Subject: Re: [v2, 2/2] mmc: sdhci-of-esdhc: avoid clock glitch when >> frequency is changing >> >> On 26/12/16 11:46, Yangbo Lu wrote: >>> The eSDHC_PRSSTAT[SDSTB] bit indicates whether the internal card clock >>> is stable. This bit is for the host driver to poll clock status when >>> changing the clock frequency. It is recommended to clear >>> eSDHC_SYSCTL[SDCLKEN] to remove glitch on the card clock when the >>> frequency is changing. This patch is to disable SDCLKEN bit before >>> changing frequency and enable it after SDSTB bit is set. >>> >>> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> >>> --- >>> Changes for v2: >>> - added Adrian into to list >>> --- >>> drivers/mmc/host/sdhci-esdhc.h | 5 +++++ >>> drivers/mmc/host/sdhci-of-esdhc.c | 21 ++++++++++++++++++--- >>> 2 files changed, 23 insertions(+), 3 deletions(-) >>> >>> diff --git a/drivers/mmc/host/sdhci-esdhc.h >>> b/drivers/mmc/host/sdhci-esdhc.h index 8cd8449..ece8b37 100644 >>> --- a/drivers/mmc/host/sdhci-esdhc.h >>> +++ b/drivers/mmc/host/sdhci-esdhc.h >>> @@ -31,6 +31,10 @@ >>> * eSDHC register definition >>> */ >>> >>> +/* Present State Register */ >>> +#define ESDHC_PRSSTAT 0x24 >>> +#define ESDHC_CLOCK_STABLE 0x00000008 >>> + >>> /* Protocol Control Register */ >>> #define ESDHC_PROCTL 0x28 >>> #define ESDHC_CTRL_4BITBUS (0x1 << 1) >>> @@ -43,6 +47,7 @@ >>> #define ESDHC_CLOCK_MASK 0x0000fff0 >>> #define ESDHC_PREDIV_SHIFT 8 >>> #define ESDHC_DIVIDER_SHIFT 4 >>> +#define ESDHC_CLOCK_SDCLKEN 0x00000008 >>> #define ESDHC_CLOCK_PEREN 0x00000004 >>> #define ESDHC_CLOCK_HCKEN 0x00000002 >>> #define ESDHC_CLOCK_IPGEN 0x00000001 >>> diff --git a/drivers/mmc/host/sdhci-of-esdhc.c >>> b/drivers/mmc/host/sdhci-of-esdhc.c >>> index 9a6eb44..0849885 100644 >>> --- a/drivers/mmc/host/sdhci-of-esdhc.c >>> +++ b/drivers/mmc/host/sdhci-of-esdhc.c >>> @@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host >> *host, unsigned int clock) >>> struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); >>> int pre_div = 1; >>> int div = 1; >>> + u32 timeout; >>> u32 temp; >>> >>> host->mmc->actual_clock = 0; >>> @@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host >> *host, unsigned int clock) >>> } >>> >>> temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); >>> - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN >>> - | ESDHC_CLOCK_MASK); >>> + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | >> ESDHC_CLOCK_HCKEN | >>> + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); >>> sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); >>> >>> while (host->max_clk / pre_div / 16 > clock && pre_div < 256) @@ >>> -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host >> *host, unsigned int clock) >>> | (div << ESDHC_DIVIDER_SHIFT) >>> | (pre_div << ESDHC_PREDIV_SHIFT)); >>> sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); >>> - mdelay(1); >>> + >>> + /* Wait max 20 ms */ >>> + timeout = 20; >>> + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { >>> + if (timeout == 0) { >>> + pr_err("%s: Internal clock never stabilised.\n", >>> + mmc_hostname(host->mmc)); >>> + return; >>> + } >>> + timeout--; >>> + mdelay(1); >>> + } >> >> Please try to do this with readx_poll_timeout_atomic(). However we are >> not racing with anything (and one of the things that needs doing in SDHCI >> is to reduce the use of the spin lock) so you could drop the spin lock >> while using >> readx_poll_timeout() instead. >> > > [Lu Yangbo-B47093] The function readx_poll_timeout_atomic() periodically polls an address, but the addr must be > the only argument for op. Our sdhci_readl has two arguments. Any suggestion for this? > > readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) Yeah, I forgot about that, sorry. -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 26 December 2016 at 10:46, Yangbo Lu <yangbo.lu@nxp.com> wrote: > The eSDHC_PRSSTAT[SDSTB] bit indicates whether the internal card clock is > stable. This bit is for the host driver to poll clock status when changing > the clock frequency. It is recommended to clear eSDHC_SYSCTL[SDCLKEN] > to remove glitch on the card clock when the frequency is changing. This > patch is to disable SDCLKEN bit before changing frequency and enable it > after SDSTB bit is set. > > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Thanks, applied for next! Kind regards Uffe > --- > Changes for v2: > - added Adrian into to list > --- > drivers/mmc/host/sdhci-esdhc.h | 5 +++++ > drivers/mmc/host/sdhci-of-esdhc.c | 21 ++++++++++++++++++--- > 2 files changed, 23 insertions(+), 3 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h > index 8cd8449..ece8b37 100644 > --- a/drivers/mmc/host/sdhci-esdhc.h > +++ b/drivers/mmc/host/sdhci-esdhc.h > @@ -31,6 +31,10 @@ > * eSDHC register definition > */ > > +/* Present State Register */ > +#define ESDHC_PRSSTAT 0x24 > +#define ESDHC_CLOCK_STABLE 0x00000008 > + > /* Protocol Control Register */ > #define ESDHC_PROCTL 0x28 > #define ESDHC_CTRL_4BITBUS (0x1 << 1) > @@ -43,6 +47,7 @@ > #define ESDHC_CLOCK_MASK 0x0000fff0 > #define ESDHC_PREDIV_SHIFT 8 > #define ESDHC_DIVIDER_SHIFT 4 > +#define ESDHC_CLOCK_SDCLKEN 0x00000008 > #define ESDHC_CLOCK_PEREN 0x00000004 > #define ESDHC_CLOCK_HCKEN 0x00000002 > #define ESDHC_CLOCK_IPGEN 0x00000001 > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c > index 9a6eb44..0849885 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > int pre_div = 1; > int div = 1; > + u32 timeout; > u32 temp; > > host->mmc->actual_clock = 0; > @@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > } > > temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); > - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN > - | ESDHC_CLOCK_MASK); > + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | > + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > > while (host->max_clk / pre_div / 16 > clock && pre_div < 256) > @@ -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) > | (div << ESDHC_DIVIDER_SHIFT) > | (pre_div << ESDHC_PREDIV_SHIFT)); > sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > - mdelay(1); > + > + /* Wait max 20 ms */ > + timeout = 20; > + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { > + if (timeout == 0) { > + pr_err("%s: Internal clock never stabilised.\n", > + mmc_hostname(host->mmc)); > + return; > + } > + timeout--; > + mdelay(1); > + } > + > + temp |= ESDHC_CLOCK_SDCLKEN; > + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); > } > > static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) > -- > 2.1.0.27.g96db324 > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index 8cd8449..ece8b37 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -31,6 +31,10 @@ * eSDHC register definition */ +/* Present State Register */ +#define ESDHC_PRSSTAT 0x24 +#define ESDHC_CLOCK_STABLE 0x00000008 + /* Protocol Control Register */ #define ESDHC_PROCTL 0x28 #define ESDHC_CTRL_4BITBUS (0x1 << 1) @@ -43,6 +47,7 @@ #define ESDHC_CLOCK_MASK 0x0000fff0 #define ESDHC_PREDIV_SHIFT 8 #define ESDHC_DIVIDER_SHIFT 4 +#define ESDHC_CLOCK_SDCLKEN 0x00000008 #define ESDHC_CLOCK_PEREN 0x00000004 #define ESDHC_CLOCK_HCKEN 0x00000002 #define ESDHC_CLOCK_IPGEN 0x00000001 diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 9a6eb44..0849885 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); int pre_div = 1; int div = 1; + u32 timeout; u32 temp; host->mmc->actual_clock = 0; @@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) } temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN - | ESDHC_CLOCK_MASK); + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); while (host->max_clk / pre_div / 16 > clock && pre_div < 256) @@ -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) | (div << ESDHC_DIVIDER_SHIFT) | (pre_div << ESDHC_PREDIV_SHIFT)); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - mdelay(1); + + /* Wait max 20 ms */ + timeout = 20; + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { + if (timeout == 0) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + return; + } + timeout--; + mdelay(1); + } + + temp |= ESDHC_CLOCK_SDCLKEN; + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); } static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
The eSDHC_PRSSTAT[SDSTB] bit indicates whether the internal card clock is stable. This bit is for the host driver to poll clock status when changing the clock frequency. It is recommended to clear eSDHC_SYSCTL[SDCLKEN] to remove glitch on the card clock when the frequency is changing. This patch is to disable SDCLKEN bit before changing frequency and enable it after SDSTB bit is set. Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> --- Changes for v2: - added Adrian into to list --- drivers/mmc/host/sdhci-esdhc.h | 5 +++++ drivers/mmc/host/sdhci-of-esdhc.c | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-)