diff mbox

[V7,1/2] mmc: core: HS200 mode support for eMMC 4.5

Message ID 1324440779-27843-2-git-send-email-girish.shivananjappa@linaro.org
State New
Headers show

Commit Message

Girish K S Dec. 21, 2011, 4:12 a.m. UTC
This patch adds the support of the HS200 bus speed for eMMC 4.5 devices.
The eMMC 4.5 devices have support for 200MHz bus speed. The function
prototype of the tuning function is modified to handle the tuning command
number which is different in sd and mmc case.

cc: Chris Ball <cjb@laptop.org>
Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
---
 drivers/mmc/core/bus.c     |    3 +-
 drivers/mmc/core/debugfs.c |    3 +
 drivers/mmc/core/mmc.c     |  142 +++++++++++++++++++++++++++++++++++++++++---
 drivers/mmc/core/sd.c      |    3 +-
 drivers/mmc/core/sdio.c    |    4 +-
 include/linux/mmc/card.h   |    3 +
 include/linux/mmc/mmc.h    |   66 ++++++++++++++++++++-
 7 files changed, 211 insertions(+), 13 deletions(-)

Comments

Philip Rakity Dec. 21, 2011, 4:59 a.m. UTC | #1
On Dec 20, 2011, at 8:12 PM, Girish K S wrote:

> This patch adds the support of the HS200 bus speed for eMMC 4.5 devices.
> The eMMC 4.5 devices have support for 200MHz bus speed. The function
> prototype of the tuning function is modified to handle the tuning command
> number which is different in sd and mmc case.
>
> cc: Chris Ball <cjb@laptop.org>
> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> ---
> drivers/mmc/core/bus.c     |    3 +-
> drivers/mmc/core/debugfs.c |    3 +
> drivers/mmc/core/mmc.c     |  142 +++++++++++++++++++++++++++++++++++++++++---
> drivers/mmc/core/sd.c      |    3 +-
> drivers/mmc/core/sdio.c    |    4 +-
> include/linux/mmc/card.h   |    3 +
> include/linux/mmc/mmc.h    |   66 ++++++++++++++++++++-
> 7 files changed, 211 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index f8a228a..5d011a3 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card)
>                        mmc_card_ddr_mode(card) ? "DDR " : "",
>                        type);
>        } else {
> -               printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
> +               pr_info("%s: new %s%s%s%s card at address %04x\n",
>                        mmc_hostname(card->host),
>                        mmc_card_uhs(card) ? "ultra high speed " :
>                        (mmc_card_highspeed(card) ? "high speed " : ""),
> +                       (mmc_card_hs200(card) ? "HS200 " : ""),
>                        mmc_card_ddr_mode(card) ? "DDR " : "",
>                        type, card->rca);
>        }
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 027615d..9ab5b17 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>        case MMC_TIMING_UHS_DDR50:
>                str = "sd uhs DDR50";
>                break;
> +       case MMC_TIMING_MMC_HS200:
> +               str = "mmc high-speed SDR200";
> +               break;
>        default:
>                str = "invalid";
>                break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f0a9f1f..4de3416 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>        }
>        card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>        switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
> +       case EXT_CSD_CARD_TYPE_SDR_ALL:
> +       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> +       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> +       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> +               card->ext_csd.hs_max_dtr = 200000000;
> +               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
> +               break;
> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> +               card->ext_csd.hs_max_dtr = 200000000;
> +               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
> +               break;
> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> +               card->ext_csd.hs_max_dtr = 200000000;
> +               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
> +               break;
>        case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>             EXT_CSD_CARD_TYPE_26:
>                card->ext_csd.hs_max_dtr = 52000000;
> @@ -700,6 +721,58 @@ static int mmc_select_powerclass(struct mmc_card *card,
> }
>
> /*
> + * Selects the desired buswidth and switch to the HS200 mode
> + * if bus width set without error
> + */
> +static int mmc_select_hs200(struct mmc_card *card)
> +{
> +       int err = 0;
> +       struct mmc_host *host;
> +       u32 bus_width = MMC_BUS_WIDTH_4;
> +
> +       BUG_ON(!card);
> +
> +       host = card->host;
> +
> +       if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
> +               && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
> +               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0);

if 1.2 volt is not supported should one try 1.8v signaling ?

> +
> +       /*
> +        * Host is capable of 8bit transfer, then switch
> +        * the device to work in 8bit transfer mode. If the
> +        * mmc switch command returns error then switch to
> +        * 4bit transfer mode. On success set the corresponding
> +        * bus width on the host.
> +        */
> +       if (!err && host->caps & MMC_CAP_8_BIT_DATA) {
> +               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                                EXT_CSD_BUS_WIDTH,
> +                                EXT_CSD_BUS_WIDTH_8,
> +                                card->ext_csd.generic_cmd6_time);
> +               bus_width = MMC_BUS_WIDTH_8;
> +       }
> +
> +       /* If the 8bit mode fails switch to 4 bit mode */
> +       if (err) {
> +               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                                EXT_CSD_BUS_WIDTH,
> +                                EXT_CSD_BUS_WIDTH_4,
> +                                card->ext_csd.generic_cmd6_time);
> +               bus_width = MMC_BUS_WIDTH_4;
> +       }
> +
> +       /* switch to HS200 mode if bus width set successfully */
> +       if (!err) {
> +               mmc_set_bus_width(card->host, bus_width);
> +               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                                EXT_CSD_HS_TIMING, 2, 0);
> +       }
> +
> +       return err;
> +}


The fact the switch does not report an error does not mean the card supports 8 bit or even 4 bit data.
One needs to either run CMD19 to test the bus width or try to read the
ext_csd data (or its equivalent) to determine the bus width supported works.

The best example of this is mmc card that does NOT bring out all the pins.  Some manufactures have
done this in the past.  This is the reason when the bus test is needed.


> +
> +/*
>  * Handle the detection and initialisation of a card.
>  *
>  * In the case of a resume, "oldcard" will contain the card
> @@ -905,11 +978,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>        /*
>         * Activate high speed (if supported)
>         */
> -       if ((card->ext_csd.hs_max_dtr != 0) &&
> -               (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> -               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -                                EXT_CSD_HS_TIMING, 1,
> -                                card->ext_csd.generic_cmd6_time);
> +       if (card->ext_csd.hs_max_dtr != 0) {
> +               err = 0;
> +               if ((card->ext_csd.hs_max_dtr > 52000000) &&
> +                   (host->caps2 & MMC_CAP2_HS200))
> +                       err = mmc_select_hs200(card);
> +               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
> +                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                                        EXT_CSD_HS_TIMING, 1, 0);
> +
>                if (err && err != -EBADMSG)
>                        goto free_card;
>
> @@ -918,8 +995,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>                               mmc_hostname(card->host));
>                        err = 0;
>                } else {
> -                       mmc_card_set_highspeed(card);
> -                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +                       if ((card->ext_csd.hs_max_dtr > 52000000) &&
> +                           (host->caps2 & MMC_CAP2_HS200)) {
> +                               mmc_card_set_hs200(card);
> +                               mmc_set_timing(card->host,
> +                                              MMC_TIMING_MMC_HS200);
> +                       } else {
> +                               mmc_card_set_highspeed(card);
> +                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +                       }
>                }
>        }
>
> @@ -944,7 +1028,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         */
>        max_dtr = (unsigned int)-1;
>
> -       if (mmc_card_highspeed(card)) {
> +       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>                if (max_dtr > card->ext_csd.hs_max_dtr)
>                        max_dtr = card->ext_csd.hs_max_dtr;
>        } else if (max_dtr > card->csd.max_dtr) {
> @@ -970,9 +1054,49 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>        }
>
>        /*
> +        * Indicate HS200 SDR mode (if supported).
> +        */
> +       if (mmc_card_hs200(card)) {
> +               u32 ext_csd_bits;
> +               u32 bus_width = card->host->ios.bus_width;
> +
> +               /*
> +                * For devices supporting HS200 mode, the bus width has
> +                * to be set before executing the tuning function. If
> +                * set before tuning, then device will respond with CRC
> +                * errors for responses on CMD line. So for HS200 the
> +                * sequence will be
> +                * 1. set bus width 4bit / 8 bit (1 bit not supported)
> +                * 2. switch to HS200 mode
> +                * 3. set the clock to > 52Mhz <=200MHz and
> +                * 4. execute tuning for HS200
> +                */
> +               if ((host->caps2 & MMC_CAP2_HS200) &&
> +                   card->host->ops->execute_tuning)
> +                       err = card->host->ops->execute_tuning(card->host,
> +                                       MMC_SEND_TUNING_BLOCK_HS200);
> +               if (err) {
> +                       pr_warning("tuning execution failed\n");
> +                       goto err;
> +               }
> +
> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +                                       EXT_CSD_BUS_WIDTH_8 :
> +                                       EXT_CSD_BUS_WIDTH_4;
> +               err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
> +               if (err) {
> +                       pr_err("%s: power class selection to bus width"
> +                              "%d failed\n", mmc_hostname(card->host),
> +                              1 << bus_width);
> +                       goto err;
> +               }
> +       }
> +
> +       /*
>         * Activate wide bus and DDR (if supported).
>         */
> -       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> +       if (!mmc_card_hs200(card) &&
> +           (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
>            (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
>                static unsigned ext_csd_bits[][2] = {
>                        { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 6f27d35..a775131 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
>
>        /* SPI mode doesn't define CMD19 */
>        if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
> -               err = card->host->ops->execute_tuning(card->host);
> +               err = card->host->ops->execute_tuning(card->host,       \
> +                                                     MMC_SEND_TUNING_BLOCK);
>
> out:
>        kfree(status);
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index b77f770..bd7bacc 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -14,6 +14,7 @@
>
> #include <linux/mmc/host.h>
> #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
> #include <linux/mmc/sdio.h>
> #include <linux/mmc/sdio_func.h>
> #include <linux/mmc/sdio_ids.h>
> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
>
>        /* Initialize and start re-tuning timer */
>        if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
> -               err = card->host->ops->execute_tuning(card->host);
> +               err = card->host->ops->execute_tuning(card->host,
> +                                                     MMC_SEND_TUNING_BLOCK);
>
> out:
>
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 9478a6b..9f22ba5 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -216,6 +216,7 @@ struct mmc_card {
> #define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
> #define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
> #define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
> +#define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
>        unsigned int            quirks;         /* card quirks */
> #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
> #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> @@ -374,6 +375,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
> #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
> #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
> #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
> +#define mmc_card_hs200(c)      ((c)->state & MMC_STATE_HIGHSPEED_200)
> #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
> #define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
> #define mmc_card_uhs(c)                ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
> @@ -384,6 +386,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
> #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
> #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> +#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
> #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
> #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
> #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 665548e..2c8cc69 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -51,6 +51,7 @@
> #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
> #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
> #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
> +#define MMC_SEND_TUNING_BLOCK_HS200    21      /* adtc R1  */
>
>   /* class 3 */
> #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
> @@ -339,13 +340,76 @@ struct _mmc_csd {
>
> #define EXT_CSD_CARD_TYPE_26   (1<<0)  /* Card can run at 26MHz */
> #define EXT_CSD_CARD_TYPE_52   (1<<1)  /* Card can run at 52MHz */
> -#define EXT_CSD_CARD_TYPE_MASK 0xF     /* Mask out reserved bits */
> +#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
> #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>                                             /* DDR mode @1.8V or 3V I/O */
> #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>                                             /* DDR mode @1.2V I/O */
> #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>                                        | EXT_CSD_CARD_TYPE_DDR_1_2V)
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
> +                                               /* SDR mode @1.2V I/O */
> +
> +#define EXT_CSD_CARD_TYPE_SDR_200      (EXT_CSD_CARD_TYPE_SDR_1_8V     \
> +                                       | EXT_CSD_CARD_TYPE_SDR_1_2V)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL      (EXT_CSD_CARD_TYPE_SDR_200      \
> +                                       | EXT_CSD_CARD_TYPE_52          \
> +                                       | EXT_CSD_CARD_TYPE_26)
> +
> +#define        EXT_CSD_CARD_TYPE_SDR_1_2V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_2V     \
> +                                       | EXT_CSD_CARD_TYPE_52          \
> +                                       | EXT_CSD_CARD_TYPE_26)
> +
> +#define        EXT_CSD_CARD_TYPE_SDR_1_8V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_8V     \
> +                                       | EXT_CSD_CARD_TYPE_52          \
> +                                       | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +                                               | EXT_CSD_CARD_TYPE_DDR_1_8V \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +                                               | EXT_CSD_CARD_TYPE_DDR_1_8V \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +                                               | EXT_CSD_CARD_TYPE_DDR_1_2V \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +                                               | EXT_CSD_CARD_TYPE_DDR_1_2V \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +                                               | EXT_CSD_CARD_TYPE_DDR_52   \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +                                               | EXT_CSD_CARD_TYPE_DDR_52   \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V     (EXT_CSD_CARD_TYPE_SDR_200   \
> +                                               | EXT_CSD_CARD_TYPE_DDR_1_8V \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V     (EXT_CSD_CARD_TYPE_SDR_200   \
> +                                               | EXT_CSD_CARD_TYPE_DDR_1_2V \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52       (EXT_CSD_CARD_TYPE_SDR_200   \
> +                                               | EXT_CSD_CARD_TYPE_DDR_52   \
> +                                               | EXT_CSD_CARD_TYPE_52       \
> +                                               | EXT_CSD_CARD_TYPE_26)
>
> #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
> #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
> --
> 1.7.1
>
> --
> 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
Subhash Jadavani Dec. 21, 2011, 6:34 a.m. UTC | #2
> -----Original Message-----
> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
> owner@vger.kernel.org] On Behalf Of Girish K S
> Sent: Wednesday, December 21, 2011 9:43 AM
> To: linux-mmc@vger.kernel.org
> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org; Girish K S;
> Chris Ball
> Subject: [PATCH V7 1/2] mmc: core: HS200 mode support for eMMC 4.5
> 
> This patch adds the support of the HS200 bus speed for eMMC 4.5
> devices.
> The eMMC 4.5 devices have support for 200MHz bus speed. The function
> prototype of the tuning function is modified to handle the tuning
> command
> number which is different in sd and mmc case.
> 
> cc: Chris Ball <cjb@laptop.org>
> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> ---
>  drivers/mmc/core/bus.c     |    3 +-
>  drivers/mmc/core/debugfs.c |    3 +
>  drivers/mmc/core/mmc.c     |  142
> +++++++++++++++++++++++++++++++++++++++++---
>  drivers/mmc/core/sd.c      |    3 +-
>  drivers/mmc/core/sdio.c    |    4 +-
>  include/linux/mmc/card.h   |    3 +
>  include/linux/mmc/mmc.h    |   66 ++++++++++++++++++++-

Looks like you have missed to add change in "include/linux/mmc/host.h" in
this patch.



>  7 files changed, 211 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index f8a228a..5d011a3 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr_mode(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_highspeed(card) ? "high speed " : ""),
> +			(mmc_card_hs200(card) ? "HS200 " : ""),
>  			mmc_card_ddr_mode(card) ? "DDR " : "",
>  			type, card->rca);
>  	}
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 027615d..9ab5b17 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void
> *data)
>  	case MMC_TIMING_UHS_DDR50:
>  		str = "sd uhs DDR50";
>  		break;
> +	case MMC_TIMING_MMC_HS200:
> +		str = "mmc high-speed SDR200";
> +		break;
>  	default:
>  		str = "invalid";
>  		break;
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f0a9f1f..4de3416 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card,
> u8 *ext_csd)
>  	}
>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>  	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
> +	case EXT_CSD_CARD_TYPE_SDR_ALL:
> +	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
> +	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
> +	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
> +		card->ext_csd.hs_max_dtr = 200000000;
> +		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
> +		break;
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
> +		card->ext_csd.hs_max_dtr = 200000000;
> +		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
> +		break;
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
> +	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
> +		card->ext_csd.hs_max_dtr = 200000000;
> +		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
> +		break;
>  	case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>  	     EXT_CSD_CARD_TYPE_26:
>  		card->ext_csd.hs_max_dtr = 52000000;
> @@ -700,6 +721,58 @@ static int mmc_select_powerclass(struct mmc_card
> *card,
>  }
> 
>  /*
> + * Selects the desired buswidth and switch to the HS200 mode
> + * if bus width set without error
> + */
> +static int mmc_select_hs200(struct mmc_card *card)
> +{
> +	int err = 0;
> +	struct mmc_host *host;
> +	u32 bus_width = MMC_BUS_WIDTH_4;
> +
> +	BUG_ON(!card);
> +
> +	host = card->host;
> +
> +	if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
> +		&& (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
> +		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120,
> 0);
> +
> +	/*
> +	 * Host is capable of 8bit transfer, then switch
> +	 * the device to work in 8bit transfer mode. If the
> +	 * mmc switch command returns error then switch to
> +	 * 4bit transfer mode. On success set the corresponding
> +	 * bus width on the host.
> +	 */
> +	if (!err && host->caps & MMC_CAP_8_BIT_DATA) {
> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +				 EXT_CSD_BUS_WIDTH,
> +				 EXT_CSD_BUS_WIDTH_8,
> +				 card->ext_csd.generic_cmd6_time);
> +		bus_width = MMC_BUS_WIDTH_8;
> +	}
> +
> +	/* If the 8bit mode fails switch to 4 bit mode */
> +	if (err) {
> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +				 EXT_CSD_BUS_WIDTH,
> +				 EXT_CSD_BUS_WIDTH_4,
> +				 card->ext_csd.generic_cmd6_time);
> +		bus_width = MMC_BUS_WIDTH_4;
> +	}
> +
> +	/* switch to HS200 mode if bus width set successfully */
> +	if (!err) {
> +		mmc_set_bus_width(card->host, bus_width);
> +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +				 EXT_CSD_HS_TIMING, 2, 0);
> +	}
> +
> +	return err;
> +}
> +
> +/*
>   * Handle the detection and initialisation of a card.
>   *
>   * In the case of a resume, "oldcard" will contain the card
> @@ -905,11 +978,15 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  	/*
>  	 * Activate high speed (if supported)
>  	 */
> -	if ((card->ext_csd.hs_max_dtr != 0) &&
> -		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
> -		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> -				 EXT_CSD_HS_TIMING, 1,
> -				 card->ext_csd.generic_cmd6_time);
> +	if (card->ext_csd.hs_max_dtr != 0) {
> +		err = 0;
> +		if ((card->ext_csd.hs_max_dtr > 52000000) &&
> +		    (host->caps2 & MMC_CAP2_HS200))
> +			err = mmc_select_hs200(card);
> +		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
> +			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +					 EXT_CSD_HS_TIMING, 1, 0);
> +
>  		if (err && err != -EBADMSG)
>  			goto free_card;
> 
> @@ -918,8 +995,15 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  			       mmc_hostname(card->host));
>  			err = 0;
>  		} else {
> -			mmc_card_set_highspeed(card);
> -			mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
> +			if ((card->ext_csd.hs_max_dtr > 52000000) &&
> +			    (host->caps2 & MMC_CAP2_HS200)) {
> +				mmc_card_set_hs200(card);
> +				mmc_set_timing(card->host,
> +					       MMC_TIMING_MMC_HS200);
> +			} else {
> +				mmc_card_set_highspeed(card);
> +				mmc_set_timing(card->host,
MMC_TIMING_MMC_HS);
> +			}
>  		}
>  	}
> 
> @@ -944,7 +1028,7 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  	 */
>  	max_dtr = (unsigned int)-1;
> 
> -	if (mmc_card_highspeed(card)) {
> +	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>  		if (max_dtr > card->ext_csd.hs_max_dtr)
>  			max_dtr = card->ext_csd.hs_max_dtr;
>  	} else if (max_dtr > card->csd.max_dtr) {
> @@ -970,9 +1054,49 @@ static int mmc_init_card(struct mmc_host *host,
> u32 ocr,
>  	}
> 
>  	/*
> +	 * Indicate HS200 SDR mode (if supported).
> +	 */
> +	if (mmc_card_hs200(card)) {
> +		u32 ext_csd_bits;
> +		u32 bus_width = card->host->ios.bus_width;
> +
> +		/*
> +		 * For devices supporting HS200 mode, the bus width has
> +		 * to be set before executing the tuning function. If
> +		 * set before tuning, then device will respond with CRC
> +		 * errors for responses on CMD line. So for HS200 the
> +		 * sequence will be
> +		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
> +		 * 2. switch to HS200 mode
> +		 * 3. set the clock to > 52Mhz <=200MHz and
> +		 * 4. execute tuning for HS200
> +		 */
> +		if ((host->caps2 & MMC_CAP2_HS200) &&
> +		    card->host->ops->execute_tuning)
> +			err = card->host->ops->execute_tuning(card->host,
> +					MMC_SEND_TUNING_BLOCK_HS200);
> +		if (err) {
> +			pr_warning("tuning execution failed\n");
> +			goto err;
> +		}
> +
> +		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
> +					EXT_CSD_BUS_WIDTH_8 :
> +					EXT_CSD_BUS_WIDTH_4;
> +		err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
> +		if (err) {
> +			pr_err("%s: power class selection to bus width"
> +			       "%d failed\n", mmc_hostname(card->host),
> +			       1 << bus_width);
> +			goto err;
> +		}
> +	}
> +
> +	/*
>  	 * Activate wide bus and DDR (if supported).
>  	 */
> -	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
> +	if (!mmc_card_hs200(card) &&
> +	    (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
>  	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
>  		static unsigned ext_csd_bits[][2] = {
>  			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 6f27d35..a775131 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card
> *card)
> 
>  	/* SPI mode doesn't define CMD19 */
>  	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning)
> -		err = card->host->ops->execute_tuning(card->host);
> +		err = card->host->ops->execute_tuning(card->host,	\
> +
MMC_SEND_TUNING_BLOCK);
> 
>  out:
>  	kfree(status);
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index b77f770..bd7bacc 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -14,6 +14,7 @@
> 
>  #include <linux/mmc/host.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/sdio.h>
>  #include <linux/mmc/sdio_func.h>
>  #include <linux/mmc/sdio_ids.h>
> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card
> *card)
> 
>  	/* Initialize and start re-tuning timer */
>  	if (!mmc_host_is_spi(card->host) && card->host->ops-
> >execute_tuning)
> -		err = card->host->ops->execute_tuning(card->host);
> +		err = card->host->ops->execute_tuning(card->host,
> +
MMC_SEND_TUNING_BLOCK);
> 
>  out:
> 
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 9478a6b..9f22ba5 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -216,6 +216,7 @@ struct mmc_card {
>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra
> high speed mode */
>  #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
>  #define MMC_CARD_REMOVED	(1<<7)		/* card has been
> removed */
> +#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in
> HS200 mode */
>  	unsigned int		quirks; 	/* card quirks */
>  #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0
> writes outside of the VS CCCR range */
>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func-
> >cur_blksize */
> @@ -374,6 +375,7 @@ static inline void __maybe_unused
> remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
>  #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
>  #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
> +#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
>  #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
>  #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
>  #define mmc_card_uhs(c)		((c)->state &
> MMC_STATE_ULTRAHIGHSPEED)
> @@ -384,6 +386,7 @@ static inline void __maybe_unused
> remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>  #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
> +#define mmc_card_set_hs200(c)	((c)->state |=
> MMC_STATE_HIGHSPEED_200)
>  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
> MMC_STATE_HIGHSPEED_DDR)
>  #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 665548e..2c8cc69 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -51,6 +51,7 @@
>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1
> */
>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1
> */
>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1
> */
> +#define MMC_SEND_TUNING_BLOCK_HS200	21	/* adtc R1  */
> 
>    /* class 3 */
>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1
> */
> @@ -339,13 +340,76 @@ struct _mmc_csd {
> 
>  #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
>  #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
> -#define EXT_CSD_CARD_TYPE_MASK	0xF	/* Mask out reserved bits */
> +#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz
> */
>  					     /* DDR mode @1.8V or 3V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz
> */
>  					     /* DDR mode @1.2V I/O */
>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>  					| EXT_CSD_CARD_TYPE_DDR_1_2V)
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at
> 200MHz */
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at
> 200MHz */
> +						/* SDR mode @1.2V I/O */
> +
> +#define EXT_CSD_CARD_TYPE_SDR_200	(EXT_CSD_CARD_TYPE_SDR_1_8V	\
> +					| EXT_CSD_CARD_TYPE_SDR_1_2V)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL	(EXT_CSD_CARD_TYPE_SDR_200	\
> +					| EXT_CSD_CARD_TYPE_52		\
> +					| EXT_CSD_CARD_TYPE_26)
> +
> +#define	EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V	\
> +					| EXT_CSD_CARD_TYPE_52		\
> +					| EXT_CSD_CARD_TYPE_26)
> +
> +#define	EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V	\
> +					| EXT_CSD_CARD_TYPE_52		\
> +					| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_8V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_8V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_2V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +						| EXT_CSD_CARD_TYPE_DDR_1_2V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
> 	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
> +						| EXT_CSD_CARD_TYPE_DDR_52
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
> 	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
> +						| EXT_CSD_CARD_TYPE_DDR_52
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
> 	(EXT_CSD_CARD_TYPE_SDR_200   \
> +						| EXT_CSD_CARD_TYPE_DDR_1_8V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
> 	(EXT_CSD_CARD_TYPE_SDR_200   \
> +						| EXT_CSD_CARD_TYPE_DDR_1_2V
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> +
> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52	(EXT_CSD_CARD_TYPE_SDR_200
> \
> +						| EXT_CSD_CARD_TYPE_DDR_52
\
> +						| EXT_CSD_CARD_TYPE_52
\
> +						| EXT_CSD_CARD_TYPE_26)
> 
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
> --
> 1.7.1
> 
> --
> 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
Girish K S Dec. 21, 2011, 8:58 a.m. UTC | #3
On 21 December 2011 10:29, Philip Rakity <prakity@marvell.com> wrote:
>
> On Dec 20, 2011, at 8:12 PM, Girish K S wrote:
>
>> This patch adds the support of the HS200 bus speed for eMMC 4.5 devices.
>> The eMMC 4.5 devices have support for 200MHz bus speed. The function
>> prototype of the tuning function is modified to handle the tuning command
>> number which is different in sd and mmc case.
>>
>> cc: Chris Ball <cjb@laptop.org>
>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>> drivers/mmc/core/bus.c     |    3 +-
>> drivers/mmc/core/debugfs.c |    3 +
>> drivers/mmc/core/mmc.c     |  142 +++++++++++++++++++++++++++++++++++++++++---
>> drivers/mmc/core/sd.c      |    3 +-
>> drivers/mmc/core/sdio.c    |    4 +-
>> include/linux/mmc/card.h   |    3 +
>> include/linux/mmc/mmc.h    |   66 ++++++++++++++++++++-
>> 7 files changed, 211 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index f8a228a..5d011a3 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card)
>>                        mmc_card_ddr_mode(card) ? "DDR " : "",
>>                        type);
>>        } else {
>> -               printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
>> +               pr_info("%s: new %s%s%s%s card at address %04x\n",
>>                        mmc_hostname(card->host),
>>                        mmc_card_uhs(card) ? "ultra high speed " :
>>                        (mmc_card_highspeed(card) ? "high speed " : ""),
>> +                       (mmc_card_hs200(card) ? "HS200 " : ""),
>>                        mmc_card_ddr_mode(card) ? "DDR " : "",
>>                        type, card->rca);
>>        }
>> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> index 027615d..9ab5b17 100644
>> --- a/drivers/mmc/core/debugfs.c
>> +++ b/drivers/mmc/core/debugfs.c
>> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>>        case MMC_TIMING_UHS_DDR50:
>>                str = "sd uhs DDR50";
>>                break;
>> +       case MMC_TIMING_MMC_HS200:
>> +               str = "mmc high-speed SDR200";
>> +               break;
>>        default:
>>                str = "invalid";
>>                break;
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index f0a9f1f..4de3416 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>        }
>>        card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>        switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
>> +       case EXT_CSD_CARD_TYPE_SDR_ALL:
>> +       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>> +       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>> +       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>> +               card->ext_csd.hs_max_dtr = 200000000;
>> +               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
>> +               break;
>> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>> +       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>> +               card->ext_csd.hs_max_dtr = 200000000;
>> +               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
>> +               break;
>> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>> +       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>> +               card->ext_csd.hs_max_dtr = 200000000;
>> +               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
>> +               break;
>>        case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>>             EXT_CSD_CARD_TYPE_26:
>>                card->ext_csd.hs_max_dtr = 52000000;
>> @@ -700,6 +721,58 @@ static int mmc_select_powerclass(struct mmc_card *card,
>> }
>>
>> /*
>> + * Selects the desired buswidth and switch to the HS200 mode
>> + * if bus width set without error
>> + */
>> +static int mmc_select_hs200(struct mmc_card *card)
>> +{
>> +       int err = 0;
>> +       struct mmc_host *host;
>> +       u32 bus_width = MMC_BUS_WIDTH_4;
>> +
>> +       BUG_ON(!card);
>> +
>> +       host = card->host;
>> +
>> +       if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
>> +               && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
>> +               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0);
>
> if 1.2 volt is not supported should one try 1.8v signaling ?
>
>> +
>> +       /*
>> +        * Host is capable of 8bit transfer, then switch
>> +        * the device to work in 8bit transfer mode. If the
>> +        * mmc switch command returns error then switch to
>> +        * 4bit transfer mode. On success set the corresponding
>> +        * bus width on the host.
>> +        */
>> +       if (!err && host->caps & MMC_CAP_8_BIT_DATA) {
>> +               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                EXT_CSD_BUS_WIDTH,
>> +                                EXT_CSD_BUS_WIDTH_8,
>> +                                card->ext_csd.generic_cmd6_time);
>> +               bus_width = MMC_BUS_WIDTH_8;
>> +       }
>> +
>> +       /* If the 8bit mode fails switch to 4 bit mode */
>> +       if (err) {
>> +               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                EXT_CSD_BUS_WIDTH,
>> +                                EXT_CSD_BUS_WIDTH_4,
>> +                                card->ext_csd.generic_cmd6_time);
>> +               bus_width = MMC_BUS_WIDTH_4;
>> +       }
>> +
>> +       /* switch to HS200 mode if bus width set successfully */
>> +       if (!err) {
>> +               mmc_set_bus_width(card->host, bus_width);
>> +               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                EXT_CSD_HS_TIMING, 2, 0);
>> +       }
>> +
>> +       return err;
>> +}
>
>
> The fact the switch does not report an error does not mean the card supports 8 bit or even 4 bit data.
> One needs to either run CMD19 to test the bus width or try to read the
> ext_csd data (or its equivalent) to determine the bus width supported works.
>
After setting the bus width, CMD21(MMC) equivalent to CMD19(SD) is
executed.  Are you mentioning CMD19 of MMC

> The best example of this is mmc card that does NOT bring out all the pins.  Some manufactures have
> done this in the past.  This is the reason when the bus test is needed.
>
>
>> +
>> +/*
>>  * Handle the detection and initialisation of a card.
>>  *
>>  * In the case of a resume, "oldcard" will contain the card
>> @@ -905,11 +978,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>        /*
>>         * Activate high speed (if supported)
>>         */
>> -       if ((card->ext_csd.hs_max_dtr != 0) &&
>> -               (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>> -               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> -                                EXT_CSD_HS_TIMING, 1,
>> -                                card->ext_csd.generic_cmd6_time);
>> +       if (card->ext_csd.hs_max_dtr != 0) {
>> +               err = 0;
>> +               if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> +                   (host->caps2 & MMC_CAP2_HS200))
>> +                       err = mmc_select_hs200(card);
>> +               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> +                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                        EXT_CSD_HS_TIMING, 1, 0);
>> +
>>                if (err && err != -EBADMSG)
>>                        goto free_card;
>>
>> @@ -918,8 +995,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>                               mmc_hostname(card->host));
>>                        err = 0;
>>                } else {
>> -                       mmc_card_set_highspeed(card);
>> -                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> +                       if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> +                           (host->caps2 & MMC_CAP2_HS200)) {
>> +                               mmc_card_set_hs200(card);
>> +                               mmc_set_timing(card->host,
>> +                                              MMC_TIMING_MMC_HS200);
>> +                       } else {
>> +                               mmc_card_set_highspeed(card);
>> +                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> +                       }
>>                }
>>        }
>>
>> @@ -944,7 +1028,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>         */
>>        max_dtr = (unsigned int)-1;
>>
>> -       if (mmc_card_highspeed(card)) {
>> +       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>>                if (max_dtr > card->ext_csd.hs_max_dtr)
>>                        max_dtr = card->ext_csd.hs_max_dtr;
>>        } else if (max_dtr > card->csd.max_dtr) {
>> @@ -970,9 +1054,49 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>        }
>>
>>        /*
>> +        * Indicate HS200 SDR mode (if supported).
>> +        */
>> +       if (mmc_card_hs200(card)) {
>> +               u32 ext_csd_bits;
>> +               u32 bus_width = card->host->ios.bus_width;
>> +
>> +               /*
>> +                * For devices supporting HS200 mode, the bus width has
>> +                * to be set before executing the tuning function. If
>> +                * set before tuning, then device will respond with CRC
>> +                * errors for responses on CMD line. So for HS200 the
>> +                * sequence will be
>> +                * 1. set bus width 4bit / 8 bit (1 bit not supported)
>> +                * 2. switch to HS200 mode
>> +                * 3. set the clock to > 52Mhz <=200MHz and
>> +                * 4. execute tuning for HS200
>> +                */
>> +               if ((host->caps2 & MMC_CAP2_HS200) &&
>> +                   card->host->ops->execute_tuning)
>> +                       err = card->host->ops->execute_tuning(card->host,
>> +                                       MMC_SEND_TUNING_BLOCK_HS200);
>> +               if (err) {
>> +                       pr_warning("tuning execution failed\n");
>> +                       goto err;
>> +               }
>> +
>> +               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> +                                       EXT_CSD_BUS_WIDTH_8 :
>> +                                       EXT_CSD_BUS_WIDTH_4;
>> +               err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
>> +               if (err) {
>> +                       pr_err("%s: power class selection to bus width"
>> +                              "%d failed\n", mmc_hostname(card->host),
>> +                              1 << bus_width);
>> +                       goto err;
>> +               }
>> +       }
>> +
>> +       /*
>>         * Activate wide bus and DDR (if supported).
>>         */
>> -       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> +       if (!mmc_card_hs200(card) &&
>> +           (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
>>            (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
>>                static unsigned ext_csd_bits[][2] = {
>>                        { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> index 6f27d35..a775131 100644
>> --- a/drivers/mmc/core/sd.c
>> +++ b/drivers/mmc/core/sd.c
>> @@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
>>
>>        /* SPI mode doesn't define CMD19 */
>>        if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
>> -               err = card->host->ops->execute_tuning(card->host);
>> +               err = card->host->ops->execute_tuning(card->host,       \
>> +                                                     MMC_SEND_TUNING_BLOCK);
>>
>> out:
>>        kfree(status);
>> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> index b77f770..bd7bacc 100644
>> --- a/drivers/mmc/core/sdio.c
>> +++ b/drivers/mmc/core/sdio.c
>> @@ -14,6 +14,7 @@
>>
>> #include <linux/mmc/host.h>
>> #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>> #include <linux/mmc/sdio.h>
>> #include <linux/mmc/sdio_func.h>
>> #include <linux/mmc/sdio_ids.h>
>> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
>>
>>        /* Initialize and start re-tuning timer */
>>        if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
>> -               err = card->host->ops->execute_tuning(card->host);
>> +               err = card->host->ops->execute_tuning(card->host,
>> +                                                     MMC_SEND_TUNING_BLOCK);
>>
>> out:
>>
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index 9478a6b..9f22ba5 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -216,6 +216,7 @@ struct mmc_card {
>> #define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
>> #define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
>> #define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
>> +#define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
>>        unsigned int            quirks;         /* card quirks */
>> #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
>> #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
>> @@ -374,6 +375,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>> #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
>> #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
>> #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
>> +#define mmc_card_hs200(c)      ((c)->state & MMC_STATE_HIGHSPEED_200)
>> #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
>> #define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
>> #define mmc_card_uhs(c)                ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
>> @@ -384,6 +386,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>> #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
>> #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>> #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
>> +#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
>> #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
>> #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
>> #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 665548e..2c8cc69 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -51,6 +51,7 @@
>> #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
>> #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
>> #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
>> +#define MMC_SEND_TUNING_BLOCK_HS200    21      /* adtc R1  */
>>
>>   /* class 3 */
>> #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
>> @@ -339,13 +340,76 @@ struct _mmc_csd {
>>
>> #define EXT_CSD_CARD_TYPE_26   (1<<0)  /* Card can run at 26MHz */
>> #define EXT_CSD_CARD_TYPE_52   (1<<1)  /* Card can run at 52MHz */
>> -#define EXT_CSD_CARD_TYPE_MASK 0xF     /* Mask out reserved bits */
>> +#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
>> #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
>>                                             /* DDR mode @1.8V or 3V I/O */
>> #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
>>                                             /* DDR mode @1.2V I/O */
>> #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>>                                        | EXT_CSD_CARD_TYPE_DDR_1_2V)
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
>> +                                               /* SDR mode @1.2V I/O */
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_200      (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> +                                       | EXT_CSD_CARD_TYPE_SDR_1_2V)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL      (EXT_CSD_CARD_TYPE_SDR_200      \
>> +                                       | EXT_CSD_CARD_TYPE_52          \
>> +                                       | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define        EXT_CSD_CARD_TYPE_SDR_1_2V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>> +                                       | EXT_CSD_CARD_TYPE_52          \
>> +                                       | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define        EXT_CSD_CARD_TYPE_SDR_1_8V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> +                                       | EXT_CSD_CARD_TYPE_52          \
>> +                                       | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_1_8V \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_1_8V \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_1_2V \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_1_2V \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_52   \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_52   \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V     (EXT_CSD_CARD_TYPE_SDR_200   \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_1_8V \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V     (EXT_CSD_CARD_TYPE_SDR_200   \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_1_2V \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52       (EXT_CSD_CARD_TYPE_SDR_200   \
>> +                                               | EXT_CSD_CARD_TYPE_DDR_52   \
>> +                                               | EXT_CSD_CARD_TYPE_52       \
>> +                                               | EXT_CSD_CARD_TYPE_26)
>>
>> #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>> #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>> --
>> 1.7.1
>>
>> --
>> 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
>
Girish K S Dec. 21, 2011, 8:59 a.m. UTC | #4
On 21 December 2011 12:04, Subhash Jadavani <subhashj@codeaurora.org> wrote:
>
>
>> -----Original Message-----
>> From: linux-mmc-owner@vger.kernel.org [mailto:linux-mmc-
>> owner@vger.kernel.org] On Behalf Of Girish K S
>> Sent: Wednesday, December 21, 2011 9:43 AM
>> To: linux-mmc@vger.kernel.org
>> Cc: patches@linaro.org; linux-samsung-soc@vger.kernel.org; Girish K S;
>> Chris Ball
>> Subject: [PATCH V7 1/2] mmc: core: HS200 mode support for eMMC 4.5
>>
>> This patch adds the support of the HS200 bus speed for eMMC 4.5
>> devices.
>> The eMMC 4.5 devices have support for 200MHz bus speed. The function
>> prototype of the tuning function is modified to handle the tuning
>> command
>> number which is different in sd and mmc case.
>>
>> cc: Chris Ball <cjb@laptop.org>
>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>>  drivers/mmc/core/bus.c     |    3 +-
>>  drivers/mmc/core/debugfs.c |    3 +
>>  drivers/mmc/core/mmc.c     |  142
>> +++++++++++++++++++++++++++++++++++++++++---
>>  drivers/mmc/core/sd.c      |    3 +-
>>  drivers/mmc/core/sdio.c    |    4 +-
>>  include/linux/mmc/card.h   |    3 +
>>  include/linux/mmc/mmc.h    |   66 ++++++++++++++++++++-
>
> Looks like you have missed to add change in "include/linux/mmc/host.h" in
> this patch.
yes
>
>
>
>>  7 files changed, 211 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index f8a228a..5d011a3 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card)
>>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>>                       type);
>>       } else {
>> -             printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
>> +             pr_info("%s: new %s%s%s%s card at address %04x\n",
>>                       mmc_hostname(card->host),
>>                       mmc_card_uhs(card) ? "ultra high speed " :
>>                       (mmc_card_highspeed(card) ? "high speed " : ""),
>> +                     (mmc_card_hs200(card) ? "HS200 " : ""),
>>                       mmc_card_ddr_mode(card) ? "DDR " : "",
>>                       type, card->rca);
>>       }
>> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> index 027615d..9ab5b17 100644
>> --- a/drivers/mmc/core/debugfs.c
>> +++ b/drivers/mmc/core/debugfs.c
>> @@ -135,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void
>> *data)
>>       case MMC_TIMING_UHS_DDR50:
>>               str = "sd uhs DDR50";
>>               break;
>> +     case MMC_TIMING_MMC_HS200:
>> +             str = "mmc high-speed SDR200";
>> +             break;
>>       default:
>>               str = "invalid";
>>               break;
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index f0a9f1f..4de3416 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card,
>> u8 *ext_csd)
>>       }
>>       card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>       switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL:
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
>> +     case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
>> +             card->ext_csd.hs_max_dtr = 200000000;
>> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
>> +             break;
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
>> +             card->ext_csd.hs_max_dtr = 200000000;
>> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
>> +             break;
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
>> +     case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
>> +             card->ext_csd.hs_max_dtr = 200000000;
>> +             card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
>> +             break;
>>       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
>>            EXT_CSD_CARD_TYPE_26:
>>               card->ext_csd.hs_max_dtr = 52000000;
>> @@ -700,6 +721,58 @@ static int mmc_select_powerclass(struct mmc_card
>> *card,
>>  }
>>
>>  /*
>> + * Selects the desired buswidth and switch to the HS200 mode
>> + * if bus width set without error
>> + */
>> +static int mmc_select_hs200(struct mmc_card *card)
>> +{
>> +     int err = 0;
>> +     struct mmc_host *host;
>> +     u32 bus_width = MMC_BUS_WIDTH_4;
>> +
>> +     BUG_ON(!card);
>> +
>> +     host = card->host;
>> +
>> +     if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
>> +             && (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
>> +             err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120,
>> 0);
>> +
>> +     /*
>> +      * Host is capable of 8bit transfer, then switch
>> +      * the device to work in 8bit transfer mode. If the
>> +      * mmc switch command returns error then switch to
>> +      * 4bit transfer mode. On success set the corresponding
>> +      * bus width on the host.
>> +      */
>> +     if (!err && host->caps & MMC_CAP_8_BIT_DATA) {
>> +             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                              EXT_CSD_BUS_WIDTH,
>> +                              EXT_CSD_BUS_WIDTH_8,
>> +                              card->ext_csd.generic_cmd6_time);
>> +             bus_width = MMC_BUS_WIDTH_8;
>> +     }
>> +
>> +     /* If the 8bit mode fails switch to 4 bit mode */
>> +     if (err) {
>> +             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                              EXT_CSD_BUS_WIDTH,
>> +                              EXT_CSD_BUS_WIDTH_4,
>> +                              card->ext_csd.generic_cmd6_time);
>> +             bus_width = MMC_BUS_WIDTH_4;
>> +     }
>> +
>> +     /* switch to HS200 mode if bus width set successfully */
>> +     if (!err) {
>> +             mmc_set_bus_width(card->host, bus_width);
>> +             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                              EXT_CSD_HS_TIMING, 2, 0);
>> +     }
>> +
>> +     return err;
>> +}
>> +
>> +/*
>>   * Handle the detection and initialisation of a card.
>>   *
>>   * In the case of a resume, "oldcard" will contain the card
>> @@ -905,11 +978,15 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>       /*
>>        * Activate high speed (if supported)
>>        */
>> -     if ((card->ext_csd.hs_max_dtr != 0) &&
>> -             (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
>> -             err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> -                              EXT_CSD_HS_TIMING, 1,
>> -                              card->ext_csd.generic_cmd6_time);
>> +     if (card->ext_csd.hs_max_dtr != 0) {
>> +             err = 0;
>> +             if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> +                 (host->caps2 & MMC_CAP2_HS200))
>> +                     err = mmc_select_hs200(card);
>> +             else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
>> +                     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                      EXT_CSD_HS_TIMING, 1, 0);
>> +
>>               if (err && err != -EBADMSG)
>>                       goto free_card;
>>
>> @@ -918,8 +995,15 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>                              mmc_hostname(card->host));
>>                       err = 0;
>>               } else {
>> -                     mmc_card_set_highspeed(card);
>> -                     mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>> +                     if ((card->ext_csd.hs_max_dtr > 52000000) &&
>> +                         (host->caps2 & MMC_CAP2_HS200)) {
>> +                             mmc_card_set_hs200(card);
>> +                             mmc_set_timing(card->host,
>> +                                            MMC_TIMING_MMC_HS200);
>> +                     } else {
>> +                             mmc_card_set_highspeed(card);
>> +                             mmc_set_timing(card->host,
> MMC_TIMING_MMC_HS);
>> +                     }
>>               }
>>       }
>>
>> @@ -944,7 +1028,7 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>        */
>>       max_dtr = (unsigned int)-1;
>>
>> -     if (mmc_card_highspeed(card)) {
>> +     if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
>>               if (max_dtr > card->ext_csd.hs_max_dtr)
>>                       max_dtr = card->ext_csd.hs_max_dtr;
>>       } else if (max_dtr > card->csd.max_dtr) {
>> @@ -970,9 +1054,49 @@ static int mmc_init_card(struct mmc_host *host,
>> u32 ocr,
>>       }
>>
>>       /*
>> +      * Indicate HS200 SDR mode (if supported).
>> +      */
>> +     if (mmc_card_hs200(card)) {
>> +             u32 ext_csd_bits;
>> +             u32 bus_width = card->host->ios.bus_width;
>> +
>> +             /*
>> +              * For devices supporting HS200 mode, the bus width has
>> +              * to be set before executing the tuning function. If
>> +              * set before tuning, then device will respond with CRC
>> +              * errors for responses on CMD line. So for HS200 the
>> +              * sequence will be
>> +              * 1. set bus width 4bit / 8 bit (1 bit not supported)
>> +              * 2. switch to HS200 mode
>> +              * 3. set the clock to > 52Mhz <=200MHz and
>> +              * 4. execute tuning for HS200
>> +              */
>> +             if ((host->caps2 & MMC_CAP2_HS200) &&
>> +                 card->host->ops->execute_tuning)
>> +                     err = card->host->ops->execute_tuning(card->host,
>> +                                     MMC_SEND_TUNING_BLOCK_HS200);
>> +             if (err) {
>> +                     pr_warning("tuning execution failed\n");
>> +                     goto err;
>> +             }
>> +
>> +             ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
>> +                                     EXT_CSD_BUS_WIDTH_8 :
>> +                                     EXT_CSD_BUS_WIDTH_4;
>> +             err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
>> +             if (err) {
>> +                     pr_err("%s: power class selection to bus width"
>> +                            "%d failed\n", mmc_hostname(card->host),
>> +                            1 << bus_width);
>> +                     goto err;
>> +             }
>> +     }
>> +
>> +     /*
>>        * Activate wide bus and DDR (if supported).
>>        */
>> -     if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
>> +     if (!mmc_card_hs200(card) &&
>> +         (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
>>           (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
>>               static unsigned ext_csd_bits[][2] = {
>>                       { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
>> index 6f27d35..a775131 100644
>> --- a/drivers/mmc/core/sd.c
>> +++ b/drivers/mmc/core/sd.c
>> @@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card
>> *card)
>>
>>       /* SPI mode doesn't define CMD19 */
>>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >execute_tuning)
>> -             err = card->host->ops->execute_tuning(card->host);
>> +             err = card->host->ops->execute_tuning(card->host,       \
>> +
> MMC_SEND_TUNING_BLOCK);
>>
>>  out:
>>       kfree(status);
>> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
>> index b77f770..bd7bacc 100644
>> --- a/drivers/mmc/core/sdio.c
>> +++ b/drivers/mmc/core/sdio.c
>> @@ -14,6 +14,7 @@
>>
>>  #include <linux/mmc/host.h>
>>  #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>  #include <linux/mmc/sdio.h>
>>  #include <linux/mmc/sdio_func.h>
>>  #include <linux/mmc/sdio_ids.h>
>> @@ -556,7 +557,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card
>> *card)
>>
>>       /* Initialize and start re-tuning timer */
>>       if (!mmc_host_is_spi(card->host) && card->host->ops-
>> >execute_tuning)
>> -             err = card->host->ops->execute_tuning(card->host);
>> +             err = card->host->ops->execute_tuning(card->host,
>> +
> MMC_SEND_TUNING_BLOCK);
>>
>>  out:
>>
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index 9478a6b..9f22ba5 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -216,6 +216,7 @@ struct mmc_card {
>>  #define MMC_STATE_ULTRAHIGHSPEED (1<<5)              /* card is in ultra
>> high speed mode */
>>  #define MMC_CARD_SDXC                (1<<6)          /* card is SDXC */
>>  #define MMC_CARD_REMOVED     (1<<7)          /* card has been
>> removed */
>> +#define MMC_STATE_HIGHSPEED_200      (1<<8)          /* card is in
>> HS200 mode */
>>       unsigned int            quirks;         /* card quirks */
>>  #define MMC_QUIRK_LENIENT_FN0        (1<<0)          /* allow SDIO FN0
>> writes outside of the VS CCCR range */
>>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func-
>> >cur_blksize */
>> @@ -374,6 +375,7 @@ static inline void __maybe_unused
>> remove_quirk(struct mmc_card *card, int data)
>>  #define mmc_card_present(c)  ((c)->state & MMC_STATE_PRESENT)
>>  #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
>>  #define mmc_card_highspeed(c)        ((c)->state & MMC_STATE_HIGHSPEED)
>> +#define mmc_card_hs200(c)    ((c)->state & MMC_STATE_HIGHSPEED_200)
>>  #define mmc_card_blockaddr(c)        ((c)->state & MMC_STATE_BLOCKADDR)
>>  #define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
>>  #define mmc_card_uhs(c)              ((c)->state &
>> MMC_STATE_ULTRAHIGHSPEED)
>> @@ -384,6 +386,7 @@ static inline void __maybe_unused
>> remove_quirk(struct mmc_card *card, int data)
>>  #define mmc_card_set_present(c)      ((c)->state |= MMC_STATE_PRESENT)
>>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
>>  #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
>> +#define mmc_card_set_hs200(c)        ((c)->state |=
>> MMC_STATE_HIGHSPEED_200)
>>  #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
>>  #define mmc_card_set_ddr_mode(c) ((c)->state |=
>> MMC_STATE_HIGHSPEED_DDR)
>>  #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 665548e..2c8cc69 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -51,6 +51,7 @@
>>  #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1
>> */
>>  #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1
>> */
>>  #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1
>> */
>> +#define MMC_SEND_TUNING_BLOCK_HS200  21      /* adtc R1  */
>>
>>    /* class 3 */
>>  #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1
>> */
>> @@ -339,13 +340,76 @@ struct _mmc_csd {
>>
>>  #define EXT_CSD_CARD_TYPE_26 (1<<0)  /* Card can run at 26MHz */
>>  #define EXT_CSD_CARD_TYPE_52 (1<<1)  /* Card can run at 52MHz */
>> -#define EXT_CSD_CARD_TYPE_MASK       0xF     /* Mask out reserved bits */
>> +#define EXT_CSD_CARD_TYPE_MASK       0x3F    /* Mask out reserved bits */
>>  #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz
>> */
>>                                            /* DDR mode @1.8V or 3V I/O */
>>  #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz
>> */
>>                                            /* DDR mode @1.2V I/O */
>>  #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
>>                                       | EXT_CSD_CARD_TYPE_DDR_1_2V)
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V   (1<<4)  /* Card can run at
>> 200MHz */
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V   (1<<5)  /* Card can run at
>> 200MHz */
>> +                                             /* SDR mode @1.2V I/O */
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_200    (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> +                                     | EXT_CSD_CARD_TYPE_SDR_1_2V)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL    (EXT_CSD_CARD_TYPE_SDR_200      \
>> +                                     | EXT_CSD_CARD_TYPE_52          \
>> +                                     | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define      EXT_CSD_CARD_TYPE_SDR_1_2V_ALL
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V     \
>> +                                     | EXT_CSD_CARD_TYPE_52          \
>> +                                     | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define      EXT_CSD_CARD_TYPE_SDR_1_8V_ALL
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V     \
>> +                                     | EXT_CSD_CARD_TYPE_52          \
>> +                                     | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_8V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_8V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_2V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_2V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52
>>       (EXT_CSD_CARD_TYPE_SDR_1_2V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52
>>       (EXT_CSD_CARD_TYPE_SDR_1_8V  \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V
>>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_8V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V
>>       (EXT_CSD_CARD_TYPE_SDR_200   \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_1_2V
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>> +
>> +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52     (EXT_CSD_CARD_TYPE_SDR_200
>> \
>> +                                             | EXT_CSD_CARD_TYPE_DDR_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_52
> \
>> +                                             | EXT_CSD_CARD_TYPE_26)
>>
>>  #define EXT_CSD_BUS_WIDTH_1  0       /* Card is in 1 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_4  1       /* Card is in 4 bit mode */
>> --
>> 1.7.1
>>
>> --
>> 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
>
> --
> 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 mbox

Patch

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index f8a228a..5d011a3 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -303,10 +303,11 @@  int mmc_add_card(struct mmc_card *card)
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type);
 	} else {
-		printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_highspeed(card) ? "high speed " : ""),
+			(mmc_card_hs200(card) ? "HS200 " : ""),
 			mmc_card_ddr_mode(card) ? "DDR " : "",
 			type, card->rca);
 	}
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 027615d..9ab5b17 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -135,6 +135,9 @@  static int mmc_ios_show(struct seq_file *s, void *data)
 	case MMC_TIMING_UHS_DDR50:
 		str = "sd uhs DDR50";
 		break;
+	case MMC_TIMING_MMC_HS200:
+		str = "mmc high-speed SDR200";
+		break;
 	default:
 		str = "invalid";
 		break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f0a9f1f..4de3416 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -286,6 +286,27 @@  static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 	}
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
 	switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+	case EXT_CSD_CARD_TYPE_SDR_ALL:
+	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
+	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
+	case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
+		card->ext_csd.hs_max_dtr = 200000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
+		break;
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
+	case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
+		card->ext_csd.hs_max_dtr = 200000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
+		break;
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
+	case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
+		card->ext_csd.hs_max_dtr = 200000000;
+		card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
+		break;
 	case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
 	     EXT_CSD_CARD_TYPE_26:
 		card->ext_csd.hs_max_dtr = 52000000;
@@ -700,6 +721,58 @@  static int mmc_select_powerclass(struct mmc_card *card,
 }
 
 /*
+ * Selects the desired buswidth and switch to the HS200 mode
+ * if bus width set without error
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+	int err = 0;
+	struct mmc_host *host;
+	u32 bus_width = MMC_BUS_WIDTH_4;
+
+	BUG_ON(!card);
+
+	host = card->host;
+
+	if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)
+		&& (host->caps2 & MMC_CAP2_HS200_1_2V_SDR))
+		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0);
+
+	/*
+	 * Host is capable of 8bit transfer, then switch
+	 * the device to work in 8bit transfer mode. If the
+	 * mmc switch command returns error then switch to
+	 * 4bit transfer mode. On success set the corresponding
+	 * bus width on the host.
+	 */
+	if (!err && host->caps & MMC_CAP_8_BIT_DATA) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH,
+				 EXT_CSD_BUS_WIDTH_8,
+				 card->ext_csd.generic_cmd6_time);
+		bus_width = MMC_BUS_WIDTH_8;
+	}
+
+	/* If the 8bit mode fails switch to 4 bit mode */
+	if (err) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH,
+				 EXT_CSD_BUS_WIDTH_4,
+				 card->ext_csd.generic_cmd6_time);
+		bus_width = MMC_BUS_WIDTH_4;
+	}
+
+	/* switch to HS200 mode if bus width set successfully */
+	if (!err) {
+		mmc_set_bus_width(card->host, bus_width);
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_HS_TIMING, 2, 0);
+	}
+
+	return err;
+}
+
+/*
  * Handle the detection and initialisation of a card.
  *
  * In the case of a resume, "oldcard" will contain the card
@@ -905,11 +978,15 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	/*
 	 * Activate high speed (if supported)
 	 */
-	if ((card->ext_csd.hs_max_dtr != 0) &&
-		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
-		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-				 EXT_CSD_HS_TIMING, 1,
-				 card->ext_csd.generic_cmd6_time);
+	if (card->ext_csd.hs_max_dtr != 0) {
+		err = 0;
+		if ((card->ext_csd.hs_max_dtr > 52000000) &&
+		    (host->caps2 & MMC_CAP2_HS200))
+			err = mmc_select_hs200(card);
+		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					 EXT_CSD_HS_TIMING, 1, 0);
+
 		if (err && err != -EBADMSG)
 			goto free_card;
 
@@ -918,8 +995,15 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			       mmc_hostname(card->host));
 			err = 0;
 		} else {
-			mmc_card_set_highspeed(card);
-			mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+			if ((card->ext_csd.hs_max_dtr > 52000000) &&
+			    (host->caps2 & MMC_CAP2_HS200)) {
+				mmc_card_set_hs200(card);
+				mmc_set_timing(card->host,
+					       MMC_TIMING_MMC_HS200);
+			} else {
+				mmc_card_set_highspeed(card);
+				mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+			}
 		}
 	}
 
@@ -944,7 +1028,7 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 */
 	max_dtr = (unsigned int)-1;
 
-	if (mmc_card_highspeed(card)) {
+	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
 		if (max_dtr > card->ext_csd.hs_max_dtr)
 			max_dtr = card->ext_csd.hs_max_dtr;
 	} else if (max_dtr > card->csd.max_dtr) {
@@ -970,9 +1054,49 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	}
 
 	/*
+	 * Indicate HS200 SDR mode (if supported).
+	 */
+	if (mmc_card_hs200(card)) {
+		u32 ext_csd_bits;
+		u32 bus_width = card->host->ios.bus_width;
+
+		/*
+		 * For devices supporting HS200 mode, the bus width has
+		 * to be set before executing the tuning function. If
+		 * set before tuning, then device will respond with CRC
+		 * errors for responses on CMD line. So for HS200 the
+		 * sequence will be
+		 * 1. set bus width 4bit / 8 bit (1 bit not supported)
+		 * 2. switch to HS200 mode
+		 * 3. set the clock to > 52Mhz <=200MHz and
+		 * 4. execute tuning for HS200
+		 */
+		if ((host->caps2 & MMC_CAP2_HS200) &&
+		    card->host->ops->execute_tuning)
+			err = card->host->ops->execute_tuning(card->host,
+					MMC_SEND_TUNING_BLOCK_HS200);
+		if (err) {
+			pr_warning("tuning execution failed\n");
+			goto err;
+		}
+
+		ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+					EXT_CSD_BUS_WIDTH_8 :
+					EXT_CSD_BUS_WIDTH_4;
+		err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+		if (err) {
+			pr_err("%s: power class selection to bus width"
+			       "%d failed\n", mmc_hostname(card->host),
+			       1 << bus_width);
+			goto err;
+		}
+	}
+
+	/*
 	 * Activate wide bus and DDR (if supported).
 	 */
-	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+	if (!mmc_card_hs200(card) &&
+	    (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
 	    (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
 		static unsigned ext_csd_bits[][2] = {
 			{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6f27d35..a775131 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -661,7 +661,8 @@  static int mmc_sd_init_uhs_card(struct mmc_card *card)
 
 	/* SPI mode doesn't define CMD19 */
 	if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
-		err = card->host->ops->execute_tuning(card->host);
+		err = card->host->ops->execute_tuning(card->host,	\
+						      MMC_SEND_TUNING_BLOCK);
 
 out:
 	kfree(status);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index b77f770..bd7bacc 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -14,6 +14,7 @@ 
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
@@ -556,7 +557,8 @@  static int mmc_sdio_init_uhs_card(struct mmc_card *card)
 
 	/* Initialize and start re-tuning timer */
 	if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
-		err = card->host->ops->execute_tuning(card->host);
+		err = card->host->ops->execute_tuning(card->host,
+						      MMC_SEND_TUNING_BLOCK);
 
 out:
 
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9478a6b..9f22ba5 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -216,6 +216,7 @@  struct mmc_card {
 #define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
 #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
 #define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
+#define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -374,6 +375,7 @@  static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_hs200(c)	((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
 #define mmc_card_uhs(c)		((c)->state & MMC_STATE_ULTRAHIGHSPEED)
@@ -384,6 +386,7 @@  static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_hs200(c)	((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 665548e..2c8cc69 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -51,6 +51,7 @@ 
 #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
 #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
+#define MMC_SEND_TUNING_BLOCK_HS200	21	/* adtc R1  */
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
@@ -339,13 +340,76 @@  struct _mmc_csd {
 
 #define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK	0xF	/* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK	0x3F	/* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
 					     /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
 					     /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
 					| EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_SDR_1_8V	(1<<4)	/* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_SDR_1_2V	(1<<5)	/* Card can run at 200MHz */
+						/* SDR mode @1.2V I/O */
+
+#define EXT_CSD_CARD_TYPE_SDR_200	(EXT_CSD_CARD_TYPE_SDR_1_8V	\
+					| EXT_CSD_CARD_TYPE_SDR_1_2V)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL	(EXT_CSD_CARD_TYPE_SDR_200	\
+					| EXT_CSD_CARD_TYPE_52		\
+					| EXT_CSD_CARD_TYPE_26)
+
+#define	EXT_CSD_CARD_TYPE_SDR_1_2V_ALL	(EXT_CSD_CARD_TYPE_SDR_1_2V	\
+					| EXT_CSD_CARD_TYPE_52		\
+					| EXT_CSD_CARD_TYPE_26)
+
+#define	EXT_CSD_CARD_TYPE_SDR_1_8V_ALL	(EXT_CSD_CARD_TYPE_SDR_1_8V	\
+					| EXT_CSD_CARD_TYPE_52		\
+					| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
+						| EXT_CSD_CARD_TYPE_DDR_1_8V \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
+						| EXT_CSD_CARD_TYPE_DDR_1_8V \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
+						| EXT_CSD_CARD_TYPE_DDR_1_2V \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
+						| EXT_CSD_CARD_TYPE_DDR_1_2V \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52	(EXT_CSD_CARD_TYPE_SDR_1_2V  \
+						| EXT_CSD_CARD_TYPE_DDR_52   \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52	(EXT_CSD_CARD_TYPE_SDR_1_8V  \
+						| EXT_CSD_CARD_TYPE_DDR_52   \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V	(EXT_CSD_CARD_TYPE_SDR_200   \
+						| EXT_CSD_CARD_TYPE_DDR_1_8V \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V	(EXT_CSD_CARD_TYPE_SDR_200   \
+						| EXT_CSD_CARD_TYPE_DDR_1_2V \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52	(EXT_CSD_CARD_TYPE_SDR_200   \
+						| EXT_CSD_CARD_TYPE_DDR_52   \
+						| EXT_CSD_CARD_TYPE_52	     \
+						| EXT_CSD_CARD_TYPE_26)
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */