Hi Adrian, > -----Original Message----- > From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc- > owner@xxxxxxxxxxxxxxx] On Behalf Of Adrian Hunter > Sent: Thursday, April 20, 2017 3:33 PM > To: Y.B. Lu; linux-mmc@xxxxxxxxxxxxxxx; ulf.hansson@xxxxxxxxxx > Cc: Xiaobo Xie > Subject: Re: [v4, 1/5] mmc: sdhci-of-esdhc: add peripheral clock support > > On 11/04/17 08:10, Yangbo Lu wrote: > > eSDHC could select peripheral clock or platform clock as clock source > > by the PCS bit of eSDHC Control Register, and this bit couldn't be > > reset by software reset for all. In default, the platform clock is > > used. But we have to use peripheral clock since it has a higher > > frequency to support eMMC > > HS200 mode and SD UHS-I mode. This patch is to add peripheral clock > > support and use it instead of platform clock if it's declared in eSDHC > dts node. > > > > Signed-off-by: Yangbo Lu <yangbo.lu@xxxxxxx> > > --- > > Changes for v2: > > - None > > Changes for v3: > > - None > > Changes for v4: > > - Added clk_put() > > - Used udelay() to poll ESDHC_CLOCK_STABLE > > Should probably include <linux/ktime.h> otherwise: > [Lu Yangbo-B47093] I didn't find any warning in compiling. But probably you're right to see ktime.h here. I will add that. Thank you very much :) > Acked-by: Adrian Hunter <adrian.hunter@xxxxxxxxx> > > > --- > > drivers/mmc/host/sdhci-esdhc.h | 1 + > > drivers/mmc/host/sdhci-of-esdhc.c | 72 > > +++++++++++++++++++++++++++++++++++++-- > > 2 files changed, 71 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/mmc/host/sdhci-esdhc.h > > b/drivers/mmc/host/sdhci-esdhc.h index ece8b37..5343fc0 100644 > > --- a/drivers/mmc/host/sdhci-esdhc.h > > +++ b/drivers/mmc/host/sdhci-esdhc.h > > @@ -54,6 +54,7 @@ > > > > /* Control Register for DMA transfer */ > > #define ESDHC_DMA_SYSCTL 0x40c > > +#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000 > > #define ESDHC_DMA_SNOOP 0x00000040 > > > > #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */ diff --git > > a/drivers/mmc/host/sdhci-of-esdhc.c > > b/drivers/mmc/host/sdhci-of-esdhc.c > > index ff37e74..6d024b6 100644 > > --- a/drivers/mmc/host/sdhci-of-esdhc.c > > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > > @@ -19,6 +19,7 @@ > > #include <linux/delay.h> > > #include <linux/module.h> > > #include <linux/sys_soc.h> > > +#include <linux/clk.h> > > #include <linux/mmc/host.h> > > #include "sdhci-pltfm.h" > > #include "sdhci-esdhc.h" > > @@ -30,6 +31,7 @@ struct sdhci_esdhc { > > u8 vendor_ver; > > u8 spec_ver; > > bool quirk_incorrect_hostver; > > + unsigned int peripheral_clock; > > }; > > > > /** > > @@ -414,15 +416,25 @@ static int esdhc_of_enable_dma(struct sdhci_host > > *host) static unsigned int esdhc_of_get_max_clock(struct sdhci_host > > *host) { > > struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > > + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > > > > - return pltfm_host->clock; > > + if (esdhc->peripheral_clock) > > + return esdhc->peripheral_clock; > > + else > > + return pltfm_host->clock; > > } > > > > static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) > > { > > struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > > + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); > > + unsigned int clock; > > > > - return pltfm_host->clock / 256 / 16; > > + if (esdhc->peripheral_clock) > > + clock = esdhc->peripheral_clock; > > + else > > + clock = pltfm_host->clock; > > + return clock / 256 / 16; > > } > > > > static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int > > clock) @@ -512,6 +524,33 @@ static void > esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) > > sdhci_writel(host, ctrl, ESDHC_PROCTL); } > > > > +static void esdhc_clock_enable(struct sdhci_host *host, bool enable) > > +{ > > + u32 val; > > + ktime_t timeout; > > + > > + val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); > > + > > + if (enable) > > + val |= ESDHC_CLOCK_SDCLKEN; > > + else > > + val &= ~ESDHC_CLOCK_SDCLKEN; > > + > > + sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL); > > + > > + /* Wait max 20 ms */ > > + timeout = ktime_add_ms(ktime_get(), 20); > > + val = ESDHC_CLOCK_STABLE; > > + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) { > > + if (ktime_after(ktime_get(), timeout)) { > > + pr_err("%s: Internal clock never stabilised.\n", > > + mmc_hostname(host->mmc)); > > + break; > > + } > > + udelay(10); > > + } > > +} > > + > > static void esdhc_reset(struct sdhci_host *host, u8 mask) { > > sdhci_reset(host, mask); > > @@ -613,6 +652,9 @@ static void esdhc_init(struct platform_device > > *pdev, struct sdhci_host *host) { > > struct sdhci_pltfm_host *pltfm_host; > > struct sdhci_esdhc *esdhc; > > + struct device_node *np; > > + struct clk *clk; > > + u32 val; > > u16 host_ver; > > > > pltfm_host = sdhci_priv(host); > > @@ -626,6 +668,32 @@ static void esdhc_init(struct platform_device > *pdev, struct sdhci_host *host) > > esdhc->quirk_incorrect_hostver = true; > > else > > esdhc->quirk_incorrect_hostver = false; > > + > > + np = pdev->dev.of_node; > > + clk = of_clk_get(np, 0); > > + if (!IS_ERR(clk)) { > > + /* > > + * esdhc->peripheral_clock would be assigned with a value > > + * which is eSDHC base clock when use periperal clock. > > + * For ls1046a, the clock value got by common clk API is > > + * peripheral clock while the eSDHC base clock is 1/2 > > + * peripheral clock. > > + */ > > + if (of_device_is_compatible(np, "fsl,ls1046a-esdhc")) > > + esdhc->peripheral_clock = clk_get_rate(clk) / 2; > > + else > > + esdhc->peripheral_clock = clk_get_rate(clk); > > + > > + clk_put(clk); > > + } > > + > > + if (esdhc->peripheral_clock) { > > + esdhc_clock_enable(host, false); > > + val = sdhci_readl(host, ESDHC_DMA_SYSCTL); > > + val |= ESDHC_PERIPHERAL_CLK_SEL; > > + sdhci_writel(host, val, ESDHC_DMA_SYSCTL); > > + esdhc_clock_enable(host, true); > > + } > > } > > > > static int sdhci_esdhc_probe(struct platform_device *pdev) > > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at > http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html