Commit 72be45ef authored by Jean-Jacques Hiblot's avatar Jean-Jacques Hiblot Committed by Jason Liu

mmc: Change mode when switching to a boot partition

Boot partitions do not support HS200. Changing to a lower performance mode
is required to access them.
mmc_select_mode_and_width() and sd_select_mode_and_width() are modified to
make it easier to call them outside of the initialization context.
Signed-off-by: default avatarJean-Jacques Hiblot <jjhiblot@ti.com>
Reviewed-by: default avatarSimon Glass <sjg@chromium.org>
parent 6f7c7483
...@@ -32,6 +32,7 @@ static const unsigned int sd_au_size[] = { ...@@ -32,6 +32,7 @@ static const unsigned int sd_au_size[] = {
static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
static void mmc_power_cycle(struct mmc *mmc); static void mmc_power_cycle(struct mmc *mmc);
static int mmc_card_busy(struct mmc *mmc); static int mmc_card_busy(struct mmc *mmc);
static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
#if CONFIG_IS_ENABLED(MMC_TINY) #if CONFIG_IS_ENABLED(MMC_TINY)
static struct mmc mmc_static; static struct mmc mmc_static;
...@@ -788,10 +789,38 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num) ...@@ -788,10 +789,38 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
return 0; return 0;
} }
static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
{
int forbiden = 0;
bool change = false;
if (part_num & PART_ACCESS_MASK)
forbiden = MMC_CAP(MMC_HS_200);
if (MMC_CAP(mmc->selected_mode) & forbiden) {
debug("selected mode (%s) is forbiden for part %d\n",
mmc_mode_name(mmc->selected_mode), part_num);
change = true;
} else if (mmc->selected_mode != mmc->best_mode) {
debug("selected mode is not optimal\n");
change = true;
}
if (change)
return mmc_select_mode_and_width(mmc,
mmc->card_caps & ~forbiden);
return 0;
}
int mmc_switch_part(struct mmc *mmc, unsigned int part_num) int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
{ {
int ret; int ret;
ret = mmc_boot_part_access_chk(mmc, part_num);
if (ret)
return ret;
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
(mmc->part_config & ~PART_ACCESS_MASK) (mmc->part_config & ~PART_ACCESS_MASK)
| (part_num & PART_ACCESS_MASK)); | (part_num & PART_ACCESS_MASK));
...@@ -1438,7 +1467,7 @@ static const struct mode_width_tuning sd_modes_by_pref[] = { ...@@ -1438,7 +1467,7 @@ static const struct mode_width_tuning sd_modes_by_pref[] = {
mwt++) \ mwt++) \
if (caps & MMC_CAP(mwt->mode)) if (caps & MMC_CAP(mwt->mode))
static int sd_select_mode_and_width(struct mmc *mmc) static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
{ {
int err; int err;
uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
...@@ -1447,11 +1476,8 @@ static int sd_select_mode_and_width(struct mmc *mmc) ...@@ -1447,11 +1476,8 @@ static int sd_select_mode_and_width(struct mmc *mmc)
uint caps; uint caps;
err = sd_get_capabilities(mmc);
if (err)
return err;
/* Restrict card's capabilities by what the host can do */ /* Restrict card's capabilities by what the host can do */
caps = mmc->card_caps & (mmc->cfg->host_caps | MMC_MODE_1BIT); caps = card_caps & (mmc->cfg->host_caps | MMC_MODE_1BIT);
if (!uhs_en) if (!uhs_en)
caps &= ~UHS_CAPS; caps &= ~UHS_CAPS;
...@@ -1582,18 +1608,14 @@ static const struct ext_csd_bus_width { ...@@ -1582,18 +1608,14 @@ static const struct ext_csd_bus_width {
ecbv++) \ ecbv++) \
if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
static int mmc_select_mode_and_width(struct mmc *mmc) static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
{ {
int err; int err;
const struct mode_width_tuning *mwt; const struct mode_width_tuning *mwt;
const struct ext_csd_bus_width *ecbw; const struct ext_csd_bus_width *ecbw;
err = mmc_get_capabilities(mmc);
if (err)
return err;
/* Restrict card's capabilities by what the host can do */ /* Restrict card's capabilities by what the host can do */
mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
/* Only version 4 of MMC supports wider bus widths */ /* Only version 4 of MMC supports wider bus widths */
if (mmc->version < MMC_VERSION_4) if (mmc->version < MMC_VERSION_4)
...@@ -1605,8 +1627,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc) ...@@ -1605,8 +1627,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc)
return -ENOTSUPP; return -ENOTSUPP;
} }
for_each_mmc_mode_by_pref(mmc->card_caps, mwt) { mmc_set_clock(mmc, mmc->legacy_speed, false);
for_each_supported_width(mmc->card_caps & mwt->widths,
for_each_mmc_mode_by_pref(card_caps, mwt) {
for_each_supported_width(card_caps & mwt->widths,
mmc_is_mode_ddr(mwt->mode), ecbw) { mmc_is_mode_ddr(mwt->mode), ecbw) {
debug("trying mode %s width %d (at %d MHz)\n", debug("trying mode %s width %d (at %d MHz)\n",
mmc_mode_name(mwt->mode), mmc_mode_name(mwt->mode),
...@@ -1999,14 +2023,22 @@ static int mmc_startup(struct mmc *mmc) ...@@ -1999,14 +2023,22 @@ static int mmc_startup(struct mmc *mmc)
if (err) if (err)
return err; return err;
if (IS_SD(mmc)) if (IS_SD(mmc)) {
err = sd_select_mode_and_width(mmc); err = sd_get_capabilities(mmc);
else if (err)
err = mmc_select_mode_and_width(mmc); return err;
err = sd_select_mode_and_width(mmc, mmc->card_caps);
} else {
err = mmc_get_capabilities(mmc);
if (err)
return err;
mmc_select_mode_and_width(mmc, mmc->card_caps);
}
if (err) if (err)
return err; return err;
mmc->best_mode = mmc->selected_mode;
/* Fix the block length for DDR mode */ /* Fix the block length for DDR mode */
if (mmc->ddr_mode) { if (mmc->ddr_mode) {
......
...@@ -573,6 +573,7 @@ struct mmc { ...@@ -573,6 +573,7 @@ struct mmc {
#endif #endif
u8 *ext_csd; u8 *ext_csd;
enum bus_mode selected_mode; enum bus_mode selected_mode;
enum bus_mode best_mode;
}; };
struct mmc_hwpart_conf { struct mmc_hwpart_conf {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment