mmc: core: Add hs400 enhanced strobe mode support

This adds hs400 enhanced strobe mode support
in mmc core layer which is emmc 5.1 feature.

Change-Id: Ifa80d8ed1544212629193f58f05db4bd0e163adc
Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
This commit is contained in:
Sahitya Tummala 2015-10-08 15:34:49 +05:30
parent 84a71d3cfe
commit 36354b8cb4
5 changed files with 114 additions and 3 deletions

View File

@ -398,11 +398,12 @@ int mmc_add_card(struct mmc_card *card)
mmc_card_ddr_mode(card) ? "DDR " : "",
type);
} else {
pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
pr_info("%s: new %s%s%s%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_hs400(card) ? "HS400 " : ""),
(mmc_card_hs400_strobe(card) ? "enhanced strobe " : ""),
(mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_ddr_mode(card) ? "DDR " : "",
uhs_bus_speed_mode, type, card->rca);

View File

@ -313,6 +313,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
}
card->ext_csd.raw_strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
/*
* The EXT_CSD format is meant to be forward compatible. As long
* as CSD_STRUCTURE does not change, all values for EXT_CSD_REV
@ -1117,6 +1118,98 @@ out:
return err;
}
static int mmc_select_hs400_strobe(struct mmc_card *card, u8 *ext_csd)
{
int err = 0, ret = 0;
struct mmc_host *host = card->host;
if (!(host->caps2 & MMC_CAP2_HS400) || !host->ops->enhanced_strobe ||
!(card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400) ||
!mmc_card_strobe(card)) {
err = -EOPNOTSUPP;
goto err;
}
if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
&& (host->caps2 & MMC_CAP2_HS400_1_2V))
if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
err = __mmc_set_signal_voltage(host,
MMC_SIGNAL_VOLTAGE_180);
/* If fails try again during next card power cycle */
if (err) {
pr_err("%s: err in __mmc_set_signal_voltage failed\n",
mmc_hostname(host));
goto err;
}
/*
* For HS400 enhanced strobe mode following sequence is being followed:
* - switch to HS mode.
* - select DDR bus width along with enhanced strobe mode enabled.
* - switch to HS400 mode and set clock to max.
* - call for host specific ops to enable enhanced strobe at host side.
*/
err = mmc_select_hs(card, ext_csd);
if (err) {
pr_warn("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(host), err);
goto err;
}
mmc_card_clr_highspeed(card);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
0x86,
card->ext_csd.generic_cmd6_time);
if (err) {
pr_warn("%s: switch to DDR bus width with enhanced strobe for hs400 failed, err:%d\n",
mmc_hostname(host), err);
goto err;
}
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING,
0x3,
card->ext_csd.generic_cmd6_time);
if (err) {
pr_warn("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
goto err;
}
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_clock(host, MMC_HS400_MAX_DTR);
mmc_card_set_hs400(card);
mmc_host_clk_hold(host);
err = host->ops->enhanced_strobe(host);
mmc_host_clk_release(host);
/*
* Fall back to HS mode if hs400 enhanced
* strobe is unsuccessful.
* Lower the clock and adjust the timing
* to be able to switch to HighSpeed mode
*/
if (err) {
pr_debug("%s: strobe execution failed %d\n",
mmc_hostname(host), err);
mmc_card_clr_hs400(card);
mmc_set_timing(host, MMC_TIMING_LEGACY);
mmc_set_clock(host, MMC_HIGH_26_MAX_DTR);
ret = mmc_select_hs(card, ext_csd);
if (ret)
pr_warn("%s: select highspeed mode failed %d\n",
__func__, ret);
goto err;
}
mmc_card_set_hs400_strobe(card);
err:
return err;
}
static int mmc_select_hs400(struct mmc_card *card, u8 *ext_csd)
{
int err = 0;
@ -1236,7 +1329,11 @@ int mmc_set_clock_bus_speed(struct mmc_card *card, unsigned long freq)
mmc_set_timing(card->host, MMC_TIMING_LEGACY);
mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
}
err = mmc_select_hs400(card, card->cached_ext_csd);
if (mmc_card_hs400_strobe(card))
err = mmc_select_hs400_strobe(card,
card->cached_ext_csd);
else
err = mmc_select_hs400(card, card->cached_ext_csd);
}
return err;
@ -1335,7 +1432,8 @@ static int mmc_select_bus_speed(struct mmc_card *card, u8 *ext_csd)
int err = 0;
BUG_ON(!card);
if (!mmc_select_hs400_strobe(card, ext_csd))
goto out;
if (!mmc_select_hs400(card, ext_csd))
goto out;
if (!mmc_select_hs200(card, ext_csd))

View File

@ -95,6 +95,8 @@ struct mmc_ext_csd {
u8 raw_partition_support; /* 160 */
u8 raw_rpmb_size_mult; /* 168 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_strobe_support; /* 184 */
#define MMC_STROBE_SUPPORT (1 << 0)
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
u8 raw_drive_strength; /* 197 */
@ -351,6 +353,7 @@ struct mmc_card {
#define MMC_STATE_NEED_BKOPS (1<<11) /* card needs to do BKOPS */
#define MMC_STATE_CMDQ (1<<12) /* card is in cmd queue mode */
#define MMC_STATE_SUSPENDED (1<<13) /* card is suspended */
#define MMC_STATE_HS400_STROBE (1<<14) /* card is in strobe 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 */
@ -546,6 +549,9 @@ struct mmc_fixup {
card->cid.year, \
card->cid.month)
#define mmc_card_strobe(c) (((c)->ext_csd).raw_strobe_support & \
MMC_STROBE_SUPPORT)
/*
* Unconditionally quirk add/remove.
*/
@ -569,6 +575,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
#define mmc_card_hs200(c) ((c)->state & MMC_STATE_HIGHSPEED_200)
#define mmc_card_hs400(c) ((c)->state & MMC_STATE_HIGHSPEED_400)
#define mmc_card_hs400_strobe(c) ((c)->state & MMC_STATE_HS400_STROBE)
#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)
@ -588,6 +595,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_clr_hs200(c) ((c)->state &= ~MMC_STATE_HIGHSPEED_200)
#define mmc_card_set_hs400(c) ((c)->state |= MMC_STATE_HIGHSPEED_400)
#define mmc_card_clr_hs400(c) ((c)->state &= ~MMC_STATE_HIGHSPEED_400)
#define mmc_card_set_hs400_strobe(c) ((c)->state |= MMC_STATE_HS400_STROBE)
#define mmc_card_clr_hs400_strobe(c) ((c)->state &= ~MMC_STATE_HS400_STROBE)
#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_clr_ddr_mode(c) ((c)->state &= ~MMC_STATE_HIGHSPEED_DDR)

View File

@ -165,6 +165,7 @@ struct mmc_host_ops {
/* The tuning command opcode value is different for SD and eMMC cards */
int (*execute_tuning)(struct mmc_host *host, u32 opcode);
int (*enhanced_strobe)(struct mmc_host *host);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host);

View File

@ -244,6 +244,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 */
@ -334,6 +335,7 @@ struct _mmc_csd {
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V \
| EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_ENHANCED_STROBE (1 << 0)
#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 */