[U-Boot] [PATCH 21/22] mmc: Change mode when switching to a boot partition

Jean-Jacques Hiblot jjhiblot at ti.com
Fri May 12 18:16:39 UTC 2017


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 at ti.com>
---
 drivers/mmc/mmc.c | 66 +++++++++++++++++++++++++++++++++++++++++--------------
 include/mmc.h     |  1 +
 2 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 074d286..c7dda64 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -32,6 +32,7 @@ static const unsigned int sd_au_size[] = {
 static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
 static void mmc_power_cycle(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)
 static struct mmc mmc_static;
@@ -788,10 +789,38 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
 	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 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,
 			 (mmc->part_config & ~PART_ACCESS_MASK)
 			 | (part_num & PART_ACCESS_MASK));
@@ -1438,7 +1467,7 @@ static const struct mode_width_tuning sd_modes_by_pref[] = {
 	     mwt++) \
 		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;
 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
@@ -1447,11 +1476,8 @@ static int sd_select_mode_and_width(struct mmc *mmc)
 	uint caps;
 
 
-	err = sd_get_capabilities(mmc);
-	if (err)
-		return err;
 	/* 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)
 		caps &= ~UHS_CAPS;
@@ -1582,18 +1608,14 @@ static const struct ext_csd_bus_width {
 	    ecbv++) \
 		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;
 	const struct mode_width_tuning *mwt;
 	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 */
-	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 */
 	if (mmc->version < MMC_VERSION_4)
@@ -1605,8 +1627,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc)
 		return -ENOTSUPP;
 	}
 
-	for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
-		for_each_supported_width(mmc->card_caps & mwt->widths,
+	mmc_set_clock(mmc, mmc->legacy_speed, false);
+
+	for_each_mmc_mode_by_pref(card_caps, mwt) {
+		for_each_supported_width(card_caps & mwt->widths,
 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
 			debug("trying mode %s width %d (at %d MHz)\n",
 			      mmc_mode_name(mwt->mode),
@@ -1999,14 +2023,22 @@ static int mmc_startup(struct mmc *mmc)
 	if (err)
 		return err;
 
-	if (IS_SD(mmc))
-		err = sd_select_mode_and_width(mmc);
-	else
-		err = mmc_select_mode_and_width(mmc);
+	if (IS_SD(mmc)) {
+		err = sd_get_capabilities(mmc);
+		if (err)
+			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)
 		return err;
 
+	mmc->best_mode = mmc->selected_mode;
 
 	/* Fix the block length for DDR mode */
 	if (mmc->ddr_mode) {
diff --git a/include/mmc.h b/include/mmc.h
index 775c47e..921a7ff 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -573,6 +573,7 @@ struct mmc {
 #endif
 	u8 *ext_csd;
 	enum bus_mode selected_mode;
+	enum bus_mode best_mode;
 };
 
 struct mmc_hwpart_conf {
-- 
1.9.1



More information about the U-Boot mailing list