diff mbox series

[U-Boot,2/2] mmc: tmio: renesas: Downgrade SD/MMC from UHS/HS200/HS400 modes before boot

Message ID 20190206131052.24334-2-marek.vasut+renesas@gmail.com
State Deferred
Delegated to: Peng Fan
Headers show
Series [U-Boot,1/2] mmc: Export {sd,mmc}_select_mode_and_width() | expand

Commit Message

Marek Vasut Feb. 6, 2019, 1:10 p.m. UTC
Older kernel versions cannot handle situation where either the eMMC
is left in HS200/HS400 mode or SD in UHS modes by the bootloader and
can misbehave. Downgrade the eMMC to HS/HS52 mode and/or SD to non-UHS
mode before boot to allow such older kernels to work with modern U-Boot.

Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
---
 drivers/mmc/renesas-sdhi.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
diff mbox series

Patch

diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index a556acd5cb..d78f91f937 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -15,6 +15,7 @@ 
 #include <power/regulator.h>
 #include <asm/unaligned.h>
 
+#include "mmc_private.h"
 #include "tmio-common.h"
 
 #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
@@ -530,13 +531,38 @@  static int renesas_sdhi_probe(struct udevice *dev)
 	return ret;
 }
 
+int renesas_sdhi_remove(struct udevice *dev)
+{
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+	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);
+	}
+}
+
 U_BOOT_DRIVER(renesas_sdhi) = {
 	.name = "renesas-sdhi",
 	.id = UCLASS_MMC,
 	.of_match = renesas_sdhi_match,
 	.bind = tmio_sd_bind,
 	.probe = renesas_sdhi_probe,
+	.remove = renesas_sdhi_remove,
 	.priv_auto_alloc_size = sizeof(struct tmio_sd_priv),
 	.platdata_auto_alloc_size = sizeof(struct tmio_sd_plat),
 	.ops = &renesas_sdhi_ops,
+	.flags = DM_FLAG_OS_PREPARE,
 };