Re: [v4, 6/6] mmc: esdhc: add eMMC DDR mode support

2015-08-04 Thread Dong Aisheng
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

2015-07-30 Thread Yangbo Lu
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;
+