[PATCH v3 3/5] mmc: core: implement enhanced strobe support

Shawn Lin shawn.lin at rock-chips.com
Thu May 19 21:15:46 PDT 2016


Hi

在 2016-5-20 11:54, Jaehoon Chung 写道:
> On 05/20/2016 12:15 PM, Shawn Lin wrote:
>> Hi
>>
>> 在 2016-5-20 10:45, Jaehoon Chung 写道:
>>> On 05/10/2016 06:09 PM, Shawn Lin wrote:
>>>> Controllers use data strobe line to latch data from devices
>>>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>>>> introduces enhanced strobe mode for latching cmd response from
>>>> emmc devices to host controllers. This new feature is optional,
>>>> so it depends both on device's cap and host's cap to decide
>>>> whether to use it or not.
>>>>
>>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>>> ---
>>>>
>>>> Changes in v3: None
>>>> Changes in v2: None
>>>>
>>>>    drivers/mmc/core/bus.c   |  3 +-
>>>>    drivers/mmc/core/core.c  |  8 +++++
>>>>    drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
>>>>    include/linux/mmc/card.h |  1 +
>>>>    include/linux/mmc/host.h | 11 +++++++
>>>>    include/linux/mmc/mmc.h  |  3 ++
>>>>    6 files changed, 102 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>>>> index 4bc48f1..7e94b9d 100644
>>>> --- a/drivers/mmc/core/bus.c
>>>> +++ b/drivers/mmc/core/bus.c
>>>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>>>                mmc_card_ddr52(card) ? "DDR " : "",
>>>>                type);
>>>>        } else {
>>>> -        pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>>>> +        pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>>>                mmc_hostname(card->host),
>>>>                mmc_card_uhs(card) ? "ultra high speed " :
>>>>                (mmc_card_hs(card) ? "high speed " : ""),
>>>>                mmc_card_hs400(card) ? "HS400 " :
>>>>                (mmc_card_hs200(card) ? "HS200 " : ""),
>>>> +            mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>>>>                mmc_card_ddr52(card) ? "DDR " : "",
>>>>                uhs_bus_speed_mode, type, card->rca);
>>>>        }
>>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>>> index 99275e4..a559501 100644
>>>> --- a/drivers/mmc/core/core.c
>>>> +++ b/drivers/mmc/core/core.c
>>>> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>>>>        host->ios.bus_width = MMC_BUS_WIDTH_1;
>>>>        host->ios.timing = MMC_TIMING_LEGACY;
>>>>        host->ios.drv_type = 0;
>>>> +    host->ios.enhanced_strobe = false;
>>>> +
>>>> +    /*
>>>> +     * Make sure we are in non-enhanced strobe mode before we
>>>> +     * actually enable it in ext_csd.
>>>> +     */
>>>> +    if (host->ops->hs400_enhanced_strobe)
>>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>>>
>>>>        mmc_set_ios(host);
>>>>    }
>>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>>> index f99c47e..c2d1981 100644
>>>> --- a/drivers/mmc/core/mmc.c
>>>> +++ b/drivers/mmc/core/mmc.c
>>>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>>>            avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>>>        }
>>>>
>>>> +    if ((caps2 & MMC_CAP2_HS400_ES) &&
>>>> +        card->ext_csd.strobe_support &&
>>>> +        (card_type & EXT_CSD_CARD_TYPE_HS400))
>>>> +        avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>>>
>>> Does it need to check whether support HS400_1.8V/1.2V or not?
>>> It should be more stable than now.
>>>
>>
>> Ahh, right.
>> I need to add "avail_type & EXT_CSD_CARD_TYPE_HS400" instead of
>> "card_type & EXT_CSD_CARD_TYPE_HS400"... because if "avail_type &
>> EXT_CSD_CARD_TYPE_HS400" is true, it implies that "card_type & EXT_CSD_CARD_TYPE_HS400" must be true.
>
> Otherwise, you can check or add the capabilities in the parse_of_mmc().
> It can choose according to your preference. :)
>
> Anyway, i have tested your patches..If you send the patch V4, i will also test.

Thanks for testing. I will cc you when pushing V4.

>
> Best Regards,
> Jaehoon Chung
>
>>
>>
>> Thansk for catching this!
>>
>>
>>> if (avail_type & (EXT_CSD_CARD_TYPE_HS400_1.8V | EXT_CSD_CARD_TYPE_HS400_1.2V)) {
>>>      if ((cap2 & MMC_CAP2_HS400_ES) && ...
>>> }
>>>
>>> how about this?
>>>
>>> Best Regards,
>>> Jaehoon Chung
>>>
>>>> +
>>>>        card->ext_csd.hs_max_dtr = hs_max_dtr;
>>>>        card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>>>        card->mmc_avail_type = avail_type;
>>>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>>>                mmc_card_set_blockaddr(card);
>>>>        }
>>>>
>>>> +    card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>>>        card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>>>        mmc_select_card_type(card);
>>>>
>>>> @@ -1216,6 +1222,73 @@ out_err:
>>>>        return err;
>>>>    }
>>>>
>>>> +static int mmc_select_hs400es(struct mmc_card *card)
>>>> +{
>>>> +    struct mmc_host *host = card->host;
>>>> +    int err = 0;
>>>> +    u8 val;
>>>> +
>>>> +    err = mmc_select_bus_width(card);
>>>> +    if (IS_ERR_VALUE(err))
>>>> +        goto out_err;
>>>> +
>>>> +    /* Switch card to HS mode */
>>>> +    err = mmc_select_hs(card);
>>>> +    if (err) {
>>>> +        pr_err("%s: switch to high-speed failed, err:%d\n",
>>>> +            mmc_hostname(host), err);
>>>> +        goto out_err;
>>>> +    }
>>>> +
>>>> +    err = mmc_switch_status(card);
>>>> +    if (err)
>>>> +        goto out_err;
>>>> +
>>>> +    /* Switch card to DDR with strobe bit */
>>>> +    val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>>>> +    err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>> +             EXT_CSD_BUS_WIDTH,
>>>> +             val,
>>>> +             card->ext_csd.generic_cmd6_time);
>>>> +    if (err) {
>>>> +        pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>>>> +            mmc_hostname(host), err);
>>>> +        goto out_err;
>>>> +    }
>>>> +
>>>> +    /* Switch card to HS400 */
>>>> +    val = EXT_CSD_TIMING_HS400 |
>>>> +          card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>>>> +    err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>> +               EXT_CSD_HS_TIMING, val,
>>>> +               card->ext_csd.generic_cmd6_time,
>>>> +               true, false, true);
>>>> +    if (err) {
>>>> +        pr_err("%s: switch to hs400es failed, err:%d\n",
>>>> +            mmc_hostname(host), err);
>>>> +        goto out_err;
>>>> +    }
>>>> +
>>>> +    /* Set host controller to HS400 timing and frequency */
>>>> +    mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>>>> +
>>>> +    /* Controller enable enhanced strobe function */
>>>> +    host->ios.enhanced_strobe = true;
>>>> +    if (host->ops->hs400_enhanced_strobe)
>>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>>> +
>>>> +    err = mmc_switch_status(card);
>>>> +    if (err)
>>>> +        goto out_err;
>>>> +
>>>> +    return 0;
>>>> +
>>>> +out_err:
>>>> +    pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>>>> +           __func__, err);
>>>> +    return err;
>>>> +}
>>>> +
>>>>    static void mmc_select_driver_type(struct mmc_card *card)
>>>>    {
>>>>        int card_drv_type, drive_strength, drv_type;
>>>> @@ -1297,7 +1370,7 @@ err:
>>>>    }
>>>>
>>>>    /*
>>>> - * Activate High Speed or HS200 mode if supported.
>>>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>>>     */
>>>>    static int mmc_select_timing(struct mmc_card *card)
>>>>    {
>>>> @@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>>>        if (!mmc_can_ext_csd(card))
>>>>            goto bus_speed;
>>>>
>>>> -    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>> +    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>>>> +        err = mmc_select_hs400es(card);
>>>> +    else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>>            err = mmc_select_hs200(card);
>>>>        else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>>>            err = mmc_select_hs(card);
>>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>>> index eb0151b..22defc2 100644
>>>> --- a/include/linux/mmc/card.h
>>>> +++ b/include/linux/mmc/card.h
>>>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>>>        u8            raw_partition_support;    /* 160 */
>>>>        u8            raw_rpmb_size_mult;    /* 168 */
>>>>        u8            raw_erased_mem_count;    /* 181 */
>>>> +    u8            strobe_support;        /* 184 */
>>>>        u8            raw_ext_csd_structure;    /* 194 */
>>>>        u8            raw_card_type;        /* 196 */
>>>>        u8            raw_driver_strength;    /* 197 */
>>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>>> index 2a06fb0..f98bd0e 100644
>>>> --- a/include/linux/mmc/host.h
>>>> +++ b/include/linux/mmc/host.h
>>>> @@ -19,6 +19,7 @@
>>>>
>>>>    #include <linux/mmc/core.h>
>>>>    #include <linux/mmc/card.h>
>>>> +#include <linux/mmc/mmc.h>
>>>>    #include <linux/mmc/pm.h>
>>>>
>>>>    struct mmc_ios {
>>>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>>>    #define MMC_SET_DRIVER_TYPE_A    1
>>>>    #define MMC_SET_DRIVER_TYPE_C    2
>>>>    #define MMC_SET_DRIVER_TYPE_D    3
>>>> +
>>>> +    bool enhanced_strobe;            /* hs400es selection */
>>>>    };
>>>>
>>>>    struct mmc_host_ops {
>>>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>>>
>>>>        /* Prepare HS400 target operating frequency depending host driver */
>>>>        int    (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>>>> +    /* Prepare enhanced strobe depending host driver */
>>>> +    void    (*hs400_enhanced_strobe)(struct mmc_host *host,
>>>> +                     struct mmc_ios *ios);
>>>>        int    (*select_drive_strength)(struct mmc_card *card,
>>>>                         unsigned int max_dtr, int host_drv,
>>>>                         int card_drv, int *drv_type);
>>>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>>>        return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>>>    }
>>>>
>>>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>>>> +{
>>>> +    return card->host->ios.enhanced_strobe == true;
>>>> +}
>>>> +
>>>>    void mmc_retune_timer_stop(struct mmc_host *host);
>>>>
>>>>    static inline void mmc_retune_needed(struct mmc_host *host)
>>>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>>>> index 15f2c4a..c376209 100644
>>>> --- a/include/linux/mmc/mmc.h
>>>> +++ b/include/linux/mmc/mmc.h
>>>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>>>    #define EXT_CSD_PART_CONFIG        179    /* R/W */
>>>>    #define EXT_CSD_ERASED_MEM_CONT        181    /* RO */
>>>>    #define EXT_CSD_BUS_WIDTH        183    /* R/W */
>>>> +#define EXT_CSD_STROBE_SUPPORT        184    /* RO */
>>>>    #define EXT_CSD_HS_TIMING        185    /* R/W */
>>>>    #define EXT_CSD_POWER_CLASS        187    /* R/W */
>>>>    #define EXT_CSD_REV            192    /* RO */
>>>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>>>    #define EXT_CSD_CARD_TYPE_HS400_1_2V    (1<<7)    /* Card can run at 200MHz DDR, 1.2V */
>>>>    #define EXT_CSD_CARD_TYPE_HS400        (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>>>                         EXT_CSD_CARD_TYPE_HS400_1_2V)
>>>> +#define EXT_CSD_CARD_TYPE_HS400ES    (1<<8)    /* Card can run at HS400ES */
>>>>
>>>>    #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 */
>>>>    #define EXT_CSD_BUS_WIDTH_8    2    /* Card is in 8 bit mode */
>>>>    #define EXT_CSD_DDR_BUS_WIDTH_4    5    /* Card is in 4 bit DDR mode */
>>>>    #define EXT_CSD_DDR_BUS_WIDTH_8    6    /* Card is in 8 bit DDR mode */
>>>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)    /* Enhanced strobe mode */
>>>>
>>>>    #define EXT_CSD_TIMING_BC    0    /* Backwards compatility */
>>>>    #define EXT_CSD_TIMING_HS    1    /* High speed */
>>>>
>>>
>>>
>>>
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>>
>
>
>
>




More information about the Linux-rockchip mailing list