]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
mmc: am654_sdhci: Add the quirk to set TESTCD bit
authorEmanuele Ghidoli <emanuele.ghidoli@toradex.com>
Tue, 2 Jul 2024 19:54:29 +0000 (21:54 +0200)
committerTom Rini <trini@konsulko.com>
Thu, 11 Jul 2024 19:15:37 +0000 (13:15 -0600)
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@toradex.com>
drivers/mmc/am654_sdhci.c

index 48fac7a11b483aa61736b4db4f52cba63b31b54d..b4c60a48d2e532181b68a921eaad4185a323a4b7 100644 (file)
@@ -105,6 +105,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 {
@@ -350,10 +352,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;
 
@@ -368,12 +368,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)
@@ -679,6 +702,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;
 }
 
@@ -728,6 +754,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)