Re: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
From: Jaehoon Chung
Date: Thu May 19 2016 - 23:54:54 EST
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@xxxxxxxxxxxxxx>
>>> ---
>>>
>>> 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.
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@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>