Commit b9a2a0e2e9c024009010a9755d5377795f660b1a
Committed by
Tom Rini
1 parent
9a878e8f17
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
mmc: Add support for downgrading HS200/HS400 to HS mode
The mmc_select_mode_and_width() function can be called while the card is in HS200/HS400 mode and can be used to downgrade the card to lower mode, e.g. HS. This is used for example by mmc_boot_part_access_chk() which cannot access the card in HS200/HS400 mode and which is in turn called by saveenv if env is in the MMC. In such case, forcing the card clock to legacy frequency cannot work. Instead, the card must be switched to HS mode first, from which it can then be reprogrammed as needed. However, this procedure needs additional code changes, since the current implementation checks whether the card correctly switched to HS mode in mmc_set_card_speed(). The check only expects that the card will be going to HS mode from lower modes, not from higher modes, hence add a parameter which indicates that the HS200/HS400 to HS downgrade is happening. This makes the code send the switch command first, reconfigure the controller next and finally perform the EXT_CSD readback check. The last two steps cannot be done in reverse order as the card is already in HS mode when the clock are being switched on the controller side. Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com> Cc: Jaehoon Chung <jh80.chung@samsung.com>
Showing 1 changed file with 33 additions and 6 deletions Side-by-side Diff
drivers/mmc/mmc.c
... | ... | @@ -754,7 +754,8 @@ |
754 | 754 | } |
755 | 755 | |
756 | 756 | #if !CONFIG_IS_ENABLED(MMC_TINY) |
757 | -static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) | |
757 | +static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, | |
758 | + bool hsdowngrade) | |
758 | 759 | { |
759 | 760 | int err; |
760 | 761 | int speed_bits; |
... | ... | @@ -788,6 +789,20 @@ |
788 | 789 | if (err) |
789 | 790 | return err; |
790 | 791 | |
792 | +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ | |
793 | + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) | |
794 | + /* | |
795 | + * In case the eMMC is in HS200/HS400 mode and we are downgrading | |
796 | + * to HS mode, the card clock are still running much faster than | |
797 | + * the supported HS mode clock, so we can not reliably read out | |
798 | + * Extended CSD. Reconfigure the controller to run at HS mode. | |
799 | + */ | |
800 | + if (hsdowngrade) { | |
801 | + mmc_select_mode(mmc, MMC_HS); | |
802 | + mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false); | |
803 | + } | |
804 | +#endif | |
805 | + | |
791 | 806 | if ((mode == MMC_HS) || (mode == MMC_HS_52)) { |
792 | 807 | /* Now check to see that it worked */ |
793 | 808 | err = mmc_send_ext_csd(mmc, test_csd); |
... | ... | @@ -1849,7 +1864,7 @@ |
1849 | 1864 | int err; |
1850 | 1865 | |
1851 | 1866 | /* Set timing to HS200 for tuning */ |
1852 | - err = mmc_set_card_speed(mmc, MMC_HS_200); | |
1867 | + err = mmc_set_card_speed(mmc, MMC_HS_200, false); | |
1853 | 1868 | if (err) |
1854 | 1869 | return err; |
1855 | 1870 | |
... | ... | @@ -1865,7 +1880,7 @@ |
1865 | 1880 | } |
1866 | 1881 | |
1867 | 1882 | /* Set back to HS */ |
1868 | - mmc_set_card_speed(mmc, MMC_HS); | |
1883 | + mmc_set_card_speed(mmc, MMC_HS, false); | |
1869 | 1884 | mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false); |
1870 | 1885 | |
1871 | 1886 | err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, |
... | ... | @@ -1873,7 +1888,7 @@ |
1873 | 1888 | if (err) |
1874 | 1889 | return err; |
1875 | 1890 | |
1876 | - err = mmc_set_card_speed(mmc, MMC_HS_400); | |
1891 | + err = mmc_set_card_speed(mmc, MMC_HS_400, false); | |
1877 | 1892 | if (err) |
1878 | 1893 | return err; |
1879 | 1894 | |
... | ... | @@ -1920,7 +1935,19 @@ |
1920 | 1935 | return -ENOTSUPP; |
1921 | 1936 | } |
1922 | 1937 | |
1923 | - mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE); | |
1938 | +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ | |
1939 | + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) | |
1940 | + /* | |
1941 | + * In case the eMMC is in HS200/HS400 mode, downgrade to HS mode | |
1942 | + * before doing anything else, since a transition from either of | |
1943 | + * the HS200/HS400 mode directly to legacy mode is not supported. | |
1944 | + */ | |
1945 | + if (mmc->selected_mode == MMC_HS_200 || | |
1946 | + mmc->selected_mode == MMC_HS_400) | |
1947 | + mmc_set_card_speed(mmc, MMC_HS, true); | |
1948 | + else | |
1949 | +#endif | |
1950 | + mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE); | |
1924 | 1951 | |
1925 | 1952 | for_each_mmc_mode_by_pref(card_caps, mwt) { |
1926 | 1953 | for_each_supported_width(card_caps & mwt->widths, |
... | ... | @@ -1952,7 +1979,7 @@ |
1952 | 1979 | } |
1953 | 1980 | } else { |
1954 | 1981 | /* configure the bus speed (card) */ |
1955 | - err = mmc_set_card_speed(mmc, mwt->mode); | |
1982 | + err = mmc_set_card_speed(mmc, mwt->mode, false); | |
1956 | 1983 | if (err) |
1957 | 1984 | goto error; |
1958 | 1985 |
-
mentioned in commit 5cf120
-
mentioned in commit 5d275b
-
mentioned in commit 891589
-
mentioned in commit 5cf120
-
mentioned in commit 5d275b
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120
-
mentioned in commit 5cf120