[PATCH v1] mmc: am654_sdhci: Add the quirk to set TESTCD bit

Emanuele Ghidoli ghidoliemanuele at gmail.com
Tue Jul 2 21:54:29 CEST 2024


From: Emanuele Ghidoli <emanuele.ghidoli at toradex.com>

The ARASAN MMC controller on Keystone 3 class of devices need the SDCD
line to be connected for proper functioning.

In cases where this can't be connected, add a quirk to force the
controller into test mode and set the TESTCD bit. Use the flag
"ti,fails-without-test-cd", to implement this above quirk when required.

Additionally, this quirk also avoids waiting for the controller debounce
time.

This commit is similar to linux kernel commit c7666240ec76
("drivers: mmc: sdhci_am654: Add the quirk to set TESTCD bit").

Signed-off-by: Emanuele Ghidoli <emanuele.ghidoli at toradex.com>
---
 drivers/mmc/am654_sdhci.c | 38 +++++++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
index fadab7d40bb7..43f890d269e9 100644
--- a/drivers/mmc/am654_sdhci.c
+++ b/drivers/mmc/am654_sdhci.c
@@ -106,6 +106,8 @@ struct am654_sdhci_plat {
 #define FREQSEL_2_BIT	BIT(2)
 #define STRBSEL_4_BIT	BIT(3)
 #define DLL_CALIB	BIT(4)
+	u32 quirks;
+#define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0)
 };
 
 struct timing_data {
@@ -351,10 +353,8 @@ int am654_sdhci_init(struct am654_sdhci_plat *plat)
 }
 
 #define MAX_SDCD_DEBOUNCE_TIME 2000
-static int am654_sdhci_deferred_probe(struct sdhci_host *host)
+static int am654_sdhci_cd_poll(struct mmc *mmc)
 {
-	struct udevice *dev = host->mmc->dev;
-	struct am654_sdhci_plat *plat = dev_get_plat(dev);
 	unsigned long start;
 	int val;
 
@@ -369,12 +369,35 @@ static int am654_sdhci_deferred_probe(struct sdhci_host *host)
 		if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME)
 			return -ENOMEDIUM;
 
-		val = mmc_getcd(host->mmc);
+		val = mmc_getcd(mmc);
 	} while (!val);
 
+	return 0;
+}
+
+static int am654_sdhci_deferred_probe(struct sdhci_host *host)
+{
+	struct udevice *dev = host->mmc->dev;
+	struct am654_sdhci_plat *plat = dev_get_plat(dev);
+	int ret;
+
+	if (!(plat->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST)) {
+		if (am654_sdhci_cd_poll(host->mmc))
+			return -ENOMEDIUM;
+	}
+
 	am654_sdhci_init(plat);
 
-	return sdhci_probe(dev);
+	ret = sdhci_probe(dev);
+
+	if (plat->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST) {
+		u8 hostctrlreg = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+		hostctrlreg |= SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST;
+		sdhci_writeb(host, hostctrlreg, SDHCI_HOST_CONTROL);
+	}
+
+	return ret;
 }
 
 static void am654_sdhci_write_b(struct sdhci_host *host, u8 val, int reg)
@@ -680,6 +703,9 @@ static int am654_sdhci_probe(struct udevice *dev)
 
 	regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
 
+	if (plat->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST)
+		am654_sdhci_deferred_probe(host);
+
 	return 0;
 }
 
@@ -729,6 +755,8 @@ static int am654_sdhci_of_to_plat(struct udevice *dev)
 
 	dev_read_u32(dev, "ti,strobe-sel", &plat->strb_sel);
 	dev_read_u32(dev, "ti,clkbuf-sel", &plat->clkbuf_sel);
+	if (dev_read_bool(dev, "ti,fails-without-test-cd"))
+		plat->quirks |= SDHCI_AM654_QUIRK_FORCE_CDTEST;
 
 	ret = mmc_of_parse(dev, cfg);
 	if (ret)
-- 
2.34.1



More information about the U-Boot mailing list