]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
mmc: Change mode when switching to a boot partition
authorJean-Jacques Hiblot <jjhiblot@ti.com>
Thu, 21 Sep 2017 14:30:09 +0000 (16:30 +0200)
committerJaehoon Chung <jh80.chung@samsung.com>
Fri, 12 Jan 2018 09:11:04 +0000 (18:11 +0900)
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>
drivers/mmc/mmc.c
include/mmc.h

index dbd95946ea3fcae72a791784f4e3910a70236e24..6278d1fa0c6c1d5ab488025462858727b127a9ff 100644 (file)
@@ -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_power_cycle(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;
@@ -792,10 +793,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 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 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->host_caps | MMC_MODE_1BIT);
+       caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT);
 
        if (!uhs_en)
                caps &= ~UHS_CAPS;
@@ -1588,18 +1614,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->host_caps | MMC_MODE_1BIT);
+       card_caps &= (mmc->host_caps | MMC_MODE_1BIT);
 
        /* Only version 4 of MMC supports wider bus widths */
        if (mmc->version < MMC_VERSION_4)
@@ -1610,8 +1632,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),
@@ -2006,14 +2030,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) {
index 59ea363ea2714aa93be639579680edcd401a6111..a8901bffc7b6f852d0942018d7f9e1997d370c46 100644 (file)
@@ -585,7 +585,12 @@ struct mmc {
 #endif
 #endif
        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 {