lkml.org 
[lkml]   [2016]   [May]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [PATCH v6 3/5] mmc: core: implement enhanced strobe support
    From
    Date
    On 26/05/16 04:56, 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@rock-chips.com>

    I have a couple of comments below, but they don't necessarily require any
    action, so:

    Acked-by: Adrian Hunter <adrian.hunter@intel.com>

    >
    > Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
    > Tested-by: Douglas Anderson <dianders@chromium.org>
    > Tested-by: Jaehoon Chung <jh80.chung@samsung.com>
    > ---
    >
    > Changes in v6:
    > - add Doug's test-tag and Jaehoon's review-test-tag
    >
    > Changes in v5: None
    > Changes in v4: None
    > Changes in v3: None
    > Changes in v2: None
    >
    > drivers/mmc/core/bus.c | 3 +-
    > drivers/mmc/core/core.c | 9 ++++++
    > drivers/mmc/core/mmc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
    > include/linux/mmc/card.h | 1 +
    > include/linux/mmc/host.h | 11 +++++++
    > include/linux/mmc/mmc.h | 3 ++
    > 6 files changed, 108 insertions(+), 3 deletions(-)
    >
    > diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
    > index 4bc48f1..c64266f 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..b0c1f07 100644
    > --- a/drivers/mmc/core/core.c
    > +++ b/drivers/mmc/core/core.c
    > @@ -1127,6 +1127,15 @@ 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->caps2 & MMC_CAP2_HS400_ES) &&
    > + 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..9dc91ba 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 &&
    > + (avail_type & EXT_CSD_CARD_TYPE_HS400))
    > + avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
    > +
    > 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,78 @@ out_err:
    > return err;
    > }
    >
    > +static int mmc_select_hs400es(struct mmc_card *card)
    > +{
    > + struct mmc_host *host = card->host;
    > + int err = 0;
    > + u8 val;
    > +
    > + if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
    > + err = -ENOTSUPP;
    > + goto out_err;
    > + }
    > +
    > + 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;

    The spec. says "switch to High Speed mode and then set the clock frequency
    to a value not greater than 52 MHz" which would tend to imply changing to
    the High Speed frequency here. It shouldn't make any difference, so I don't
    know if it is worth doing.

    > +
    > + /* 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);
    > +

    And again here, if we followed the spec. exactly we would change to the
    HS400 frequency here rather than after sending CMD13. Again, it shouldn't
    make any difference, so I don't if it is worth doing.

    > + 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 +1375,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 +1384,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..0eabb72 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;
    > +}
    > +
    > 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 */
    >

    \
     
     \ /
      Last update: 2016-05-26 13:21    [W:2.761 / U:0.280 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site