mmc: Downgrade SD/MMC from UHS/HS200/HS400 modes before boot

Older kernel versions or systems which do not connect eMMC reset line
properly may not be able to handle situations where either the eMMC
is left in HS200/HS400 mode or SD card in UHS modes by the bootloader
and may misbehave. Downgrade the eMMC to HS/HS52 mode and/or SD card
to non-UHS mode before booting the kernel to allow such older kernels
to work with modern U-Boot.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Tom Rini <trini@konsulko.com>
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index b04345a..1c1527c 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -2781,6 +2781,32 @@
 	return err;
 }
 
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
+    CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
+    CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+int mmc_deinit(struct mmc *mmc)
+{
+	u32 caps_filtered;
+
+	if (!mmc->has_init)
+		return 0;
+
+	if (IS_SD(mmc)) {
+		caps_filtered = mmc->card_caps &
+			~(MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25) |
+			  MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_DDR50) |
+			  MMC_CAP(UHS_SDR104));
+
+		return sd_select_mode_and_width(mmc, caps_filtered);
+	} else {
+		caps_filtered = mmc->card_caps &
+			~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400));
+
+		return mmc_select_mode_and_width(mmc, caps_filtered);
+	}
+}
+#endif
+
 int mmc_set_dsr(struct mmc *mmc, u16 val)
 {
 	mmc->dsr = val;