mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-17 22:49:02 +00:00
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: Jean-Jacques Hiblot <jjhiblot@ti.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
04a2ea248f
commit
01298da31d
2 changed files with 55 additions and 18 deletions
|
@ -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 int mmc_power_cycle(struct mmc *mmc);
|
static int mmc_power_cycle(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;
|
||||||
|
@ -792,10 +793,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 forbidden = 0;
|
||||||
|
bool change = false;
|
||||||
|
|
||||||
|
if (part_num & PART_ACCESS_MASK)
|
||||||
|
forbidden = MMC_CAP(MMC_HS_200);
|
||||||
|
|
||||||
|
if (MMC_CAP(mmc->selected_mode) & forbidden) {
|
||||||
|
debug("selected mode (%s) is forbidden 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 & ~forbidden);
|
||||||
|
|
||||||
|
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[] = {
|
||||||
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)
|
||||||
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->host_caps | MMC_MODE_1BIT);
|
caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT);
|
||||||
|
|
||||||
if (!uhs_en)
|
if (!uhs_en)
|
||||||
caps &= ~UHS_CAPS;
|
caps &= ~UHS_CAPS;
|
||||||
|
@ -1588,18 +1614,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->host_caps | MMC_MODE_1BIT);
|
card_caps &= (mmc->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)
|
||||||
|
@ -1610,8 +1632,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),
|
||||||
|
@ -2006,14 +2030,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) {
|
||||||
|
|
|
@ -585,7 +585,12 @@ struct mmc {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
u8 *ext_csd;
|
u8 *ext_csd;
|
||||||
enum bus_mode selected_mode;
|
enum bus_mode selected_mode; /* mode currently used */
|
||||||
|
enum bus_mode best_mode; /* best mode is the supported mode with the
|
||||||
|
* highest bandwidth. It may not always be the
|
||||||
|
* operating mode due to limitations when
|
||||||
|
* accessing the boot partitions
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mmc_hwpart_conf {
|
struct mmc_hwpart_conf {
|
||||||
|
|
Loading…
Add table
Reference in a new issue