Skip to content

Commit

Permalink
mmc: mmc: Fix HS setting in mmc_select_hs400()
Browse files Browse the repository at this point in the history
mmc_select_hs400() begins with the card and host in HS200 mode.
Therefore, any commands sent to the card should use HS200 timing.
It is incorrect to set the host to High Speed (HS) timing before
sending the switch command.  Doing so is unreliable because
the timing parameters for HS mode are tighter than the timing
parameters for HS200 mode.  Thus the HS timings should be set
only after the card has switched mode.

However, it is not unreasonable first to reduce the frequency to
the HS mode frequency, which should make the switch command and
subsequent CMD13 commands more reliable.

This patch does that.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: <stable@vger.kernel.org> # 4.2+
Tested-by: Alim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
  • Loading branch information
Adrian Hunter authored and Ulf Hansson committed Nov 9, 2015
1 parent 1815e61 commit 51b12f7
Showing 1 changed file with 8 additions and 6 deletions.
14 changes: 8 additions & 6 deletions drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
static int mmc_select_hs400(struct mmc_card *card)
{
struct mmc_host *host = card->host;
unsigned int max_dtr;
int err = 0;
u8 val;

Expand All @@ -1053,13 +1054,11 @@ static int mmc_select_hs400(struct mmc_card *card)
host->ios.bus_width == MMC_BUS_WIDTH_8))
return 0;

/*
* Before switching to dual data rate operation for HS400,
* it is required to convert from HS200 mode to HS mode.
*/
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
mmc_set_bus_speed(card);
/* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);

/* Switch card to HS mode */
val = EXT_CSD_TIMING_HS |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
Expand All @@ -1072,6 +1071,9 @@ static int mmc_select_hs400(struct mmc_card *card)
return err;
}

/* Set host controller to HS timing */
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);

err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_DDR_BUS_WIDTH_8,
Expand Down

0 comments on commit 51b12f7

Please sign in to comment.