--- /dev/null
+From a89e7bcb18081c611eb6cf50edd440fa4983a71a Mon Sep 17 00:00:00 2001
+From: Loic Poulain <loic.poulain@linaro.org>
+Date: Tue, 4 Dec 2018 13:25:32 +0100
+Subject: mmc: sdhci-msm: Disable CDR function on TX
+
+From: Loic Poulain <loic.poulain@linaro.org>
+
+commit a89e7bcb18081c611eb6cf50edd440fa4983a71a upstream.
+
+The Clock Data Recovery (CDR) circuit allows to automatically adjust
+the RX sampling-point/phase for high frequency cards (SDR104, HS200...).
+CDR is automatically enabled during DLL configuration.
+However, according to the APQ8016 reference manual, this function
+must be disabled during TX and tuning phase in order to prevent any
+interferences during tuning challenges and unexpected phase alteration
+during TX transfers.
+
+This patch enables/disables CDR according to the current transfer mode.
+
+This fixes sporadic write transfer issues observed with some SDR104 and
+HS200 cards.
+
+Inspired by sdhci-msm downstream patch:
+https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/432516/
+
+Reported-by: Leonid Segal <leonid.s@variscite.com>
+Reported-by: Manabu Igusa <migusa@arrowjapan.com>
+Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+Acked-by: Georgi Djakov <georgi.djakov@linaro.org>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+[georgi: backport to v4.19+]
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mmc/host/sdhci-msm.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 42 insertions(+), 1 deletion(-)
+
+--- a/drivers/mmc/host/sdhci-msm.c
++++ b/drivers/mmc/host/sdhci-msm.c
+@@ -258,6 +258,8 @@ struct sdhci_msm_host {
+ bool mci_removed;
+ const struct sdhci_msm_variant_ops *var_ops;
+ const struct sdhci_msm_offset *offset;
++ bool use_cdr;
++ u32 transfer_mode;
+ };
+
+ static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
+@@ -1025,6 +1027,26 @@ out:
+ return ret;
+ }
+
++static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable)
++{
++ const struct sdhci_msm_offset *msm_offset = sdhci_priv_msm_offset(host);
++ u32 config, oldconfig = readl_relaxed(host->ioaddr +
++ msm_offset->core_dll_config);
++
++ config = oldconfig;
++ if (enable) {
++ config |= CORE_CDR_EN;
++ config &= ~CORE_CDR_EXT_EN;
++ } else {
++ config &= ~CORE_CDR_EN;
++ config |= CORE_CDR_EXT_EN;
++ }
++
++ if (config != oldconfig)
++ writel_relaxed(config, host->ioaddr +
++ msm_offset->core_dll_config);
++}
++
+ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ {
+ struct sdhci_host *host = mmc_priv(mmc);
+@@ -1042,8 +1064,14 @@ static int sdhci_msm_execute_tuning(stru
+ if (host->clock <= CORE_FREQ_100MHZ ||
+ !(ios.timing == MMC_TIMING_MMC_HS400 ||
+ ios.timing == MMC_TIMING_MMC_HS200 ||
+- ios.timing == MMC_TIMING_UHS_SDR104))
++ ios.timing == MMC_TIMING_UHS_SDR104)) {
++ msm_host->use_cdr = false;
++ sdhci_msm_set_cdr(host, false);
+ return 0;
++ }
++
++ /* Clock-Data-Recovery used to dynamically adjust RX sampling point */
++ msm_host->use_cdr = true;
+
+ /*
+ * For HS400 tuning in HS200 timing requires:
+@@ -1525,6 +1553,19 @@ static int __sdhci_msm_check_write(struc
+ case SDHCI_POWER_CONTROL:
+ req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
+ break;
++ case SDHCI_TRANSFER_MODE:
++ msm_host->transfer_mode = val;
++ break;
++ case SDHCI_COMMAND:
++ if (!msm_host->use_cdr)
++ break;
++ if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
++ SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 &&
++ SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK)
++ sdhci_msm_set_cdr(host, true);
++ else
++ sdhci_msm_set_cdr(host, false);
++ break;
+ }
+
+ if (req_type) {