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:
parent
84a71d3cfe
commit
36354b8cb4
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue