Re: [patch]: sdhci support emmc ddr50 mode [v5]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jan 10, 2011 at 9:56 PM, zhangfei gao <zhangfei.gao@xxxxxxxxx> wrote:
> Update typo
>
> From 93873d40ea72b1ccd97c3629ffe555080ac4d0e4 Mon Sep 17 00:00:00 2001
> From: Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx>
> Date: Sun, 9 Jan 2011 18:09:12 -0500
> Subject: [PATCH] mmc: sdhci support emmc ddr50 mode
>
>        1. Spec sdhc 3.0 does not claim support 1.2v ddr mode, so sdhci.c
> return error and SDR mode is been reused.
>        2. Call back function set_uhs is added, since some controller count
> on external pmic to provide io voltage
>        3. mmc_set_uhs is added to make host switch io voltage according to uhs_mode
>        4. Verified on mmp2 and toshiba emmc
>
> Signed-off-by: Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx>
> ---
>  drivers/mmc/core/core.c  |   18 +++++++++++++
>  drivers/mmc/core/core.h  |    1 +
>  drivers/mmc/core/mmc.c   |    9 ++++++
>  drivers/mmc/host/sdhci.c |   64 +++++++++++++++++++++++++++++++++++++++++++---
>  drivers/mmc/host/sdhci.h |   16 ++++++++++-
>  include/linux/mmc/host.h |    2 +
>  6 files changed, 104 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index a8e89f3..1f1f185 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -623,6 +623,24 @@ static inline void mmc_set_ios(struct mmc_host *host)
>        host->ops->set_ios(host, ios);
>  }
>
> +int mmc_set_uhs(struct mmc_host *host, unsigned int uhs_mode)
> +{
> +       int ret = -EINVAL;
> +
> +       if (host->ops->set_uhs) {
> +               ret = host->ops->set_uhs(host, uhs_mode);
> +
> +               /*
> +                * According to sdhc standard spec v3.0
> +                * 1.8v regulator should be stable withing 5ms
> +                */
> +               if (!ret)
> +                       mmc_delay(5);
> +       }
> +
> +       return ret;
> +}
> +
>  /*
>  * Control chip select pin on a host.
>  */
> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
> index 026c975..4b1ea7e 100644
> --- a/drivers/mmc/core/core.h
> +++ b/drivers/mmc/core/core.h
> @@ -41,6 +41,7 @@ void mmc_set_bus_width(struct mmc_host *host,
> unsigned int width);
>  void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
>                           unsigned int ddr);
>  u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
> +int mmc_set_uhs(struct mmc_host *host, unsigned int uhs_mode);
>  void mmc_set_timing(struct mmc_host *host, unsigned int timing);
>
>  static inline void mmc_delay(unsigned int ms)
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 86cac0d..657c5ef 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -529,6 +529,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                                ddr = MMC_1_2V_DDR_MODE;
>        }
>
> +       if (ddr) {
> +               if (mmc_set_uhs(host, ddr)) {
> +                       printk(KERN_WARNING "%s: DDR mode not accepted by host "
> +                               "and reuse MMC_SDR_MODE.\n",
> +                               mmc_hostname(host));
> +                       ddr = MMC_SDR_MODE;
> +               }
> +       }
> +
>        /*
>         * Activate wide bus and DDR (if supported).
>         */
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index d5febe5..decc50f 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -80,7 +80,7 @@ static void sdhci_dumpregs(struct sdhci_host *host)
>                sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
>        printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
>                sdhci_readl(host, SDHCI_CAPABILITIES),
> -               sdhci_readl(host, SDHCI_CAPABILITIES_1));
> +               sdhci_readl(host, SDHCI_CAPABILITIES_H));
>        printk(KERN_DEBUG DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
>                sdhci_readw(host, SDHCI_COMMAND),
>                sdhci_readl(host, SDHCI_MAX_CURRENT));
> @@ -986,6 +986,22 @@ static void sdhci_finish_command(struct sdhci_host *host)
>        host->cmd = NULL;
>  }
>
> +static void sdhci_set_ddr(struct sdhci_host *host, unsigned int ddr)
> +{
> +       u16 con;
> +
> +       if (ddr == MMC_SDR_MODE)
> +               return;
> +
> +       con = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +       if (con & SDHCI_CTRL2_1_8V) {
> +               con &= ~SDHCI_CTRL2_UHS_MASK;
> +               if (ddr & MMC_1_8V_DDR_MODE)
> +                       con |= SDHCI_CTRL2_DDR50;
> +               sdhci_writew(host, con, SDHCI_HOST_CONTROL2);
> +       }
> +}
> +
>  static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
>  {
>        int div;
> @@ -1180,6 +1196,7 @@ static void sdhci_set_ios(struct mmc_host *mmc,
> struct mmc_ios *ios)
>        }
>
>        sdhci_set_clock(host, ios->clock);
> +       sdhci_set_ddr(host, ios->ddr);
>
>        if (ios->power_mode == MMC_POWER_OFF)
>                sdhci_set_power(host, -1);
> @@ -1237,6 +1254,35 @@ out:
>        spin_unlock_irqrestore(&host->lock, flags);
>  }
>
> +static int sdhci_set_uhs(struct mmc_host *mmc, unsigned int uhs_mode)
> +{
> +       struct sdhci_host *host;
> +       unsigned long flags;
> +       int ret = 0;
> +
> +       host = mmc_priv(mmc);
> +
> +       spin_lock_irqsave(&host->lock, flags);
> +       if (uhs_mode & MMC_1_8V_DDR_MODE) {
> +               u16 con;
> +
> +               con = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +               con |= SDHCI_CTRL2_1_8V;
> +               sdhci_writew(host, con, SDHCI_HOST_CONTROL2);
> +       } else
> +               goto err;
> +
> +       spin_unlock_irqrestore(&host->lock, flags);
> +
> +       if (host->ops->set_uhs)
> +               ret = host->ops->set_uhs(host, uhs_mode);
> +
> +       return ret;
> +err:
> +       spin_unlock_irqrestore(&host->lock, flags);
> +       return  -EINVAL;
> +}
> +
>  static int sdhci_get_ro(struct mmc_host *mmc)
>  {
>        struct sdhci_host *host;
> @@ -1287,6 +1333,7 @@ out:
>  static const struct mmc_host_ops sdhci_ops = {
>        .request        = sdhci_request,
>        .set_ios        = sdhci_set_ios,
> +       .set_uhs        = sdhci_set_uhs,
>        .get_ro         = sdhci_get_ro,
>        .enable_sdio_irq = sdhci_enable_sdio_irq,
>  };
> @@ -1744,7 +1791,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
>  int sdhci_add_host(struct sdhci_host *host)
>  {
>        struct mmc_host *mmc;
> -       unsigned int caps, ocr_avail;
> +       unsigned int caps, caps_h = 0, ocr_avail;
>        int ret;
>
>        WARN_ON(host == NULL);
> @@ -1767,8 +1814,17 @@ int sdhci_add_host(struct sdhci_host *host)
>                        host->version);
>        }
>
> -       caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
> -               sdhci_readl(host, SDHCI_CAPABILITIES);
> +       if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
> +               caps = host->caps;
> +       else {
> +               caps = sdhci_readl(host, SDHCI_CAPABILITIES);
> +               caps_h = sdhci_readl(host, SDHCI_CAPABILITIES_H);
> +       }
> +
> +       if (caps & SDHCI_CAN_VDD_180) {
> +               if (caps_h & SDHCI_CAN_DDR50)
> +                       mmc->caps |= (MMC_CAP_1_8V_DDR);
> +       }
>
>        if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
>                host->flags |= SDHCI_USE_SDMA;
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 6e0969e..6be28a9 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -145,7 +145,14 @@
>
>  #define SDHCI_ACMD12_ERR       0x3C
>
> -/* 3E-3F reserved */
> +#define SDHCI_HOST_CONTROL2    0x3E
> +#define  SDHCI_CTRL2_UHS_MASK  0x0007
> +#define   SDHCI_CTRL2_SDR12    0x0000
> +#define   SDHCI_CTRL2_SDR25    0x0001
> +#define   SDHCI_CTRL2_SDR50    0x0002
> +#define   SDHCI_CTRL2_SDR104   0x0003
> +#define   SDHCI_CTRL2_DDR50    0x0004
> +#define  SDHCI_CTRL2_1_8V      0x0008
>
>  #define SDHCI_CAPABILITIES     0x40
>  #define  SDHCI_TIMEOUT_CLK_MASK        0x0000003F
> @@ -166,7 +173,10 @@
>  #define  SDHCI_CAN_VDD_180     0x04000000
>  #define  SDHCI_CAN_64BIT       0x10000000
>
> -#define SDHCI_CAPABILITIES_1   0x44
> +#define SDHCI_CAPABILITIES_H   0x44
> +#define  SDHCI_CAN_SDR50       0x00000001
> +#define  SDHCI_CAN_SDR104      0x00000002
> +#define  SDHCI_CAN_DDR50       0x00000004
>
>  #define SDHCI_MAX_CURRENT      0x48
>
> @@ -222,6 +232,8 @@ struct sdhci_ops {
>        void (*platform_send_init_74_clocks)(struct sdhci_host *host,
>                                             u8 power_mode);
>        unsigned int    (*get_ro)(struct sdhci_host *host);
> +       int             (*set_uhs)(struct sdhci_host *host,
> +                               unsigned int uhs_mode);
>  };
>
>  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index bcb793e..07131b0 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -117,6 +117,8 @@ struct mmc_host_ops {
>
>        /* optional callback for HC quirks */
>        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
> +
> +       int     (*set_uhs)(struct mmc_host *host, unsigned int uhs_mode);
>  };
>
>  struct mmc_card;
> --
> 1.7.0.4
>

Hi, Chris

What's your suggestion about this patch, thanks in advance.
--
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


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux