Merge branch '2020-06-15-misc-bugfixes'
[oweals/u-boot.git] / drivers / mmc / sdhci-cadence.c
index 4736263bf2a690c285bad5c33d32e133d31fb68d..7b5010b6558953a3a785011ef25430eb94020efd 100644 (file)
@@ -6,7 +6,10 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/device_compat.h>
 #include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/sizes.h>
@@ -170,6 +173,7 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat,
 {
        void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS06;
        u32 tmp;
+       int i, ret;
 
        if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
                return -EINVAL;
@@ -177,11 +181,23 @@ static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat,
        tmp = readl(reg);
        tmp &= ~SDHCI_CDNS_HRS06_TUNE;
        tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
-       tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
-       writel(tmp, reg);
 
-       return readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
-                                 1);
+       /*
+        * Workaround for IP errata:
+        * The IP6116 SD/eMMC PHY design has a timing issue on receive data
+        * path. Send tune request twice.
+        */
+       for (i = 0; i < 2; i++) {
+               tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
+               writel(tmp, reg);
+
+               ret = readl_poll_timeout(reg, tmp,
+                                        !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), 1);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev,