Re: [v4, 6/6] mmc: esdhc: add eMMC DDR mode support
On Fri, Jul 31, 2015 at 11:55 AM, Yangbo Lu wrote: > Add eMMC DDR mode support for Freescale SDHC adapter card. > The u-boot should provide device tree properties 'adapter-type' > and 'periperal-frequency' for this feature, if not, the card > would not use DDR mode. > > Signed-off-by: Yangbo Lu > --- > drivers/mmc/host/sdhci-esdhc.h| 24 +++ > drivers/mmc/host/sdhci-of-esdhc.c | 132 > -- > 2 files changed, 152 insertions(+), 4 deletions(-) > > diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h > index 163ac99..015ec01 100644 > --- a/drivers/mmc/host/sdhci-esdhc.h > +++ b/drivers/mmc/host/sdhci-esdhc.h > @@ -28,10 +28,32 @@ > #define ESDHC_CLOCK_MASK 0xfff0 > #define ESDHC_PREDIV_SHIFT 8 > #define ESDHC_DIVIDER_SHIFT4 > +#define ESDHC_CLOCK_CRDEN 0x0008 > #define ESDHC_CLOCK_PEREN 0x0004 > #define ESDHC_CLOCK_HCKEN 0x0002 > #define ESDHC_CLOCK_IPGEN 0x0001 > > +#define ESDHCI_PRESENT_STATE 0x24 > +#define ESDHC_CLK_STABLE 0x0008 > + > +#define ESDHC_CAPABILITIES_1 0x114 > +#define ESDHC_MODE_MASK0x0007 > +#define ESDHC_MODE_DDR50_SEL 0xfffc > +#define ESDHC_MODE_DDR50 0x0004 > + > +#define ESDHC_CLOCK_CONTROL0x144 > +#define ESDHC_CLKLPBK_EXTPIN 0x8000 > +#define ESDHC_CMDCLK_SHIFTED 0x8000 > + > +/* SDHC Adapter Card Type */ > +#define ESDHC_ADAPTER_TYPE_EMMC45 0x1/* eMMC Card Rev4.5 */ > +#define ESDHC_ADAPTER_TYPE_SDMMC_LEGACY 0x2/* SD/MMC Legacy Card */ > +#define ESDHC_ADAPTER_TYPE_EMMC44 0x3/* eMMC Card Rev4.4 */ > +#define ESDHC_ADAPTER_TYPE_RSV 0x4/* Reserved */ > +#define ESDHC_ADAPTER_TYPE_MMC 0x5/* MMC Card */ > +#define ESDHC_ADAPTER_TYPE_SD 0x6/* SD Card Rev2.0 Rev3.0 */ > +#define ESDHC_NO_ADAPTER0x7/* No Card is Present*/ > + Hi Yangbo, You could put those of_esdhc specific defines in of_esdhc driver since sdhci-esdhc.h is shared by both sdhci-imx-esdhc and sdhci-of-esdhc driver. Or it may be time to remove such dependency that each driver uses its own head file separately since there's already a lot difference between them and no reason to share the headfile anymore. The later one might be a more reasonable way to me. Regards Dong Aisheng > /* pltfm-specific */ > #define ESDHC_HOST_CONTROL_LE 0x20 > > @@ -45,6 +67,8 @@ > /* OF-specific */ > #define ESDHC_DMA_SYSCTL 0x40c > #define ESDHC_DMA_SNOOP0x0040 > +#define ESDHC_FLUSH_ASYNC_FIFO 0x0004 > +#define ESDHC_USE_PERIPHERAL_CLK0x0008 > > #define ESDHC_HOST_CONTROL_RES 0x01 > > diff --git a/drivers/mmc/host/sdhci-of-esdhc.c > b/drivers/mmc/host/sdhci-of-esdhc.c > index f1021d8..6d7e3f9 100644 > --- a/drivers/mmc/host/sdhci-of-esdhc.c > +++ b/drivers/mmc/host/sdhci-of-esdhc.c > @@ -24,11 +24,30 @@ > > #define VENDOR_V_220x12 > #define VENDOR_V_230x13 > + > +static u32 adapter_type; > +static bool peripheral_clk_available; > + > static u32 esdhc_readl(struct sdhci_host *host, int reg) > { > u32 ret; > > - ret = sdhci_32bs_readl(host, reg); > + if (reg == SDHCI_CAPABILITIES_1) { > + ret = sdhci_32bs_readl(host, ESDHC_CAPABILITIES_1); > + switch (adapter_type) { > + case ESDHC_ADAPTER_TYPE_EMMC44: > + if (ret & ESDHC_MODE_DDR50) { > + ret &= ESDHC_MODE_DDR50_SEL; > + /* enable 1/8V DDR capable */ > + host->mmc->caps |= MMC_CAP_1_8V_DDR; > + } else > + ret &= ~ESDHC_MODE_MASK; > + break; > + default: > + ret &= ~ESDHC_MODE_MASK; > + } > + } else > + ret = sdhci_32bs_readl(host, reg); > /* > * The bit of ADMA flag in eSDHC is not compatible with standard > * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is > @@ -159,8 +178,11 @@ static void esdhc_writeb(struct sdhci_host *host, u8 > val, int reg) > } > > /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ > - if (reg == SDHCI_HOST_CONTROL) > + if (reg == SDHCI_HOST_CONTROL) { > val &= ~ESDHC_HOST_CONTROL_RES; > + val &= ~SDHCI_CTRL_HISPD; > + val |= (sdhci_32bs_readl(host, reg) & SDHCI_CTRL_HISPD); > + } > sdhci_clrsetbits(host, 0xff, val, reg); > } > > @@ -307,6 +329,84 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) > sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); > } > > +static void esdhc_clock_control(struct sdhci_host *host, bool enable) > +{ > + u32 value; > + u32 time_out; > + > + value = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); > + > +
[v4, 6/6] mmc: esdhc: add eMMC DDR mode support
Add eMMC DDR mode support for Freescale SDHC adapter card. The u-boot should provide device tree properties 'adapter-type' and 'periperal-frequency' for this feature, if not, the card would not use DDR mode. Signed-off-by: Yangbo Lu --- drivers/mmc/host/sdhci-esdhc.h| 24 +++ drivers/mmc/host/sdhci-of-esdhc.c | 132 -- 2 files changed, 152 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index 163ac99..015ec01 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -28,10 +28,32 @@ #define ESDHC_CLOCK_MASK 0xfff0 #define ESDHC_PREDIV_SHIFT 8 #define ESDHC_DIVIDER_SHIFT4 +#define ESDHC_CLOCK_CRDEN 0x0008 #define ESDHC_CLOCK_PEREN 0x0004 #define ESDHC_CLOCK_HCKEN 0x0002 #define ESDHC_CLOCK_IPGEN 0x0001 +#define ESDHCI_PRESENT_STATE 0x24 +#define ESDHC_CLK_STABLE 0x0008 + +#define ESDHC_CAPABILITIES_1 0x114 +#define ESDHC_MODE_MASK0x0007 +#define ESDHC_MODE_DDR50_SEL 0xfffc +#define ESDHC_MODE_DDR50 0x0004 + +#define ESDHC_CLOCK_CONTROL0x144 +#define ESDHC_CLKLPBK_EXTPIN 0x8000 +#define ESDHC_CMDCLK_SHIFTED 0x8000 + +/* SDHC Adapter Card Type */ +#define ESDHC_ADAPTER_TYPE_EMMC45 0x1/* eMMC Card Rev4.5 */ +#define ESDHC_ADAPTER_TYPE_SDMMC_LEGACY 0x2/* SD/MMC Legacy Card */ +#define ESDHC_ADAPTER_TYPE_EMMC44 0x3/* eMMC Card Rev4.4 */ +#define ESDHC_ADAPTER_TYPE_RSV 0x4/* Reserved */ +#define ESDHC_ADAPTER_TYPE_MMC 0x5/* MMC Card */ +#define ESDHC_ADAPTER_TYPE_SD 0x6/* SD Card Rev2.0 Rev3.0 */ +#define ESDHC_NO_ADAPTER0x7/* No Card is Present*/ + /* pltfm-specific */ #define ESDHC_HOST_CONTROL_LE 0x20 @@ -45,6 +67,8 @@ /* OF-specific */ #define ESDHC_DMA_SYSCTL 0x40c #define ESDHC_DMA_SNOOP0x0040 +#define ESDHC_FLUSH_ASYNC_FIFO 0x0004 +#define ESDHC_USE_PERIPHERAL_CLK0x0008 #define ESDHC_HOST_CONTROL_RES 0x01 diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index f1021d8..6d7e3f9 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -24,11 +24,30 @@ #define VENDOR_V_220x12 #define VENDOR_V_230x13 + +static u32 adapter_type; +static bool peripheral_clk_available; + static u32 esdhc_readl(struct sdhci_host *host, int reg) { u32 ret; - ret = sdhci_32bs_readl(host, reg); + if (reg == SDHCI_CAPABILITIES_1) { + ret = sdhci_32bs_readl(host, ESDHC_CAPABILITIES_1); + switch (adapter_type) { + case ESDHC_ADAPTER_TYPE_EMMC44: + if (ret & ESDHC_MODE_DDR50) { + ret &= ESDHC_MODE_DDR50_SEL; + /* enable 1/8V DDR capable */ + host->mmc->caps |= MMC_CAP_1_8V_DDR; + } else + ret &= ~ESDHC_MODE_MASK; + break; + default: + ret &= ~ESDHC_MODE_MASK; + } + } else + ret = sdhci_32bs_readl(host, reg); /* * The bit of ADMA flag in eSDHC is not compatible with standard * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is @@ -159,8 +178,11 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) } /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */ - if (reg == SDHCI_HOST_CONTROL) + if (reg == SDHCI_HOST_CONTROL) { val &= ~ESDHC_HOST_CONTROL_RES; + val &= ~SDHCI_CTRL_HISPD; + val |= (sdhci_32bs_readl(host, reg) & SDHCI_CTRL_HISPD); + } sdhci_clrsetbits(host, 0xff, val, reg); } @@ -307,6 +329,84 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } +static void esdhc_clock_control(struct sdhci_host *host, bool enable) +{ + u32 value; + u32 time_out; + + value = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); + + if (enable) + value |= ESDHC_CLOCK_CRDEN; + else + value &= ~ESDHC_CLOCK_CRDEN; + + sdhci_writel(host, value, ESDHC_SYSTEM_CONTROL); + + time_out = 20; + value = ESDHC_CLK_STABLE; + while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & value)) { + if (time_out == 0) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + break; + } + time_out--; + mdelay(1); + } +} + +static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) +{ + u16 ctrl_2; +