]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Thu, 2 Jan 2020 02:23:50 +0000 (21:23 -0500)
committerSasha Levin <sashal@kernel.org>
Thu, 2 Jan 2020 02:23:50 +0000 (21:23 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.4/mmc-sdhci-of-esdhc-fix-up-erratum-a-008171-workaroun.patch [new file with mode: 0644]
queue-5.4/mmc-sdhci-of-esdhc-re-implement-erratum-a-009204-wor.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/mmc-sdhci-of-esdhc-fix-up-erratum-a-008171-workaroun.patch b/queue-5.4/mmc-sdhci-of-esdhc-fix-up-erratum-a-008171-workaroun.patch
new file mode 100644 (file)
index 0000000..3cb3b51
--- /dev/null
@@ -0,0 +1,429 @@
+From d3c9c525c244659838b5c7a10208bb395559733d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 9 Oct 2019 15:41:40 +0800
+Subject: mmc: sdhci-of-esdhc: fix up erratum A-008171 workaround
+
+From: Yangbo Lu <yangbo.lu@nxp.com>
+
+[ Upstream commit 22dc132d5448db1b1c021de0c34aa8033ca7d98f ]
+
+A previous patch implemented an incomplete workaround of erratum
+A-008171. The complete workaround is as below. This patch is to
+implement the complete workaround which uses SW tuning if HW tuning
+fails, and retries both HW/SW tuning once with reduced clock if
+workaround fails. This is suggested by hardware team, and the patch
+had been verified on LS1046A eSDHC + Phison 32G eMMC which could
+trigger the erratum.
+
+Workaround:
+/* For T1040, T2080, LS1021A, T1023 Rev 1: */
+1. Program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO.
+2. Program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO.
+3. Program the software tuning mode by setting TBCTL[TB_MODE] = 2'h3.
+4. Set SYSCTL2[EXTN] and SYSCTL2[SAMPCLKSEL].
+5. Issue SEND_TUNING_BLK Command (CMD19 for SD, CMD21 for MMC).
+6. Wait for IRQSTAT[BRR], buffer read ready, to be set.
+7. Clear IRQSTAT[BRR].
+8. Check SYSCTL2[EXTN] to be cleared.
+9. Check SYSCTL2[SAMPCLKSEL], Sampling Clock Select. It's set value
+   indicate tuning procedure success, and clear indicate failure.
+   In case of tuning failure, fixed sampling scheme could be used by
+   clearing TBCTL[TB_EN].
+/* For LS1080A Rev 1, LS2088A Rev 1.0, LA1575A Rev 1.0: */
+1. Read the TBCTL[31:0] register. Write TBCTL[11:8]=4'h8 and wait for
+   1ms.
+2. Read the TBCTL[31:0] register and rewrite again. Wait for 1ms second.
+3. Read the TBSTAT[31:0] register twice.
+3.1 Reset data lines by setting ESDHCCTL[RSTD] bit.
+3.2 Check ESDHCCTL[RSTD] bit.
+3.3 If ESDHCCTL[RSTD] is 0, go to step 3.4 else go to step 3.2.
+3.4 Write 32'hFFFF_FFFF to IRQSTAT register.
+4. if TBSTAT[15:8]-TBSTAT[7:0] > 4*DIV_RATIO or TBSTAT[7:0]-TBSTAT[15:8]
+   > 4*DIV_RATIO , then program TBPTR[TB_WNDW_END_PTR] = 4*DIV_RATIO and
+   program TBPTR[TB_WNDW_START_PTR] = 8*DIV_RATIO.
+/* For LS1012A Rev1, LS1043A Rev 1.x, LS1046A 1.0: */
+1. Read the TBCTL[0:31] register. Write TBCTL[20:23]=4'h8 and wait for
+   1ms.
+2. Read the TBCTL[0:31] register and rewrite again. Wait for 1ms second.
+3. Read the TBSTAT[0:31] register twice.
+3.1 Reset data lines by setting ESDHCCTL[RSTD] bit.
+3.2 Check ESDHCCTL[RSTD] bit.
+3.3 If ESDHCCTL[RSTD] is 0, go to step 3.4 else go to step 3.2.
+3.4 Write 32'hFFFF_FFFF to IRQSTAT register.
+4. if TBSTAT[16:23]-TBSTAT[24:31] > 4*DIV_RATIO or TBSTAT[24:31]-
+   TBSTAT[16:23] > 4* DIV_RATIO , then program TBPTR[TB_WNDW_END_PTR] =
+   4*DIV_RATIO and program TBPTR[TB_WNDW_START_PTR] = 8*DIV_RATIO.
+/* For LS1080A Rev 1, LS2088A Rev 1.0, LA1575A Rev 1.0 LS1012A Rev1,
+ * LS1043A Rev 1.x, LS1046A 1.0:
+ */
+5. else program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and program
+   TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO.
+6. Program the software tuning mode by setting TBCTL[TB_MODE] = 2'h3.
+7. Set SYSCTL2[EXTN], wait 1us and SYSCTL2[SAMPCLKSEL].
+8. Issue SEND_TUNING_BLK Command (CMD19 for SD, CMD21 for MMC).
+9. Wait for IRQSTAT[BRR], buffer read ready, to be set.
+10. Clear IRQSTAT[BRR].
+11. Check SYSCTL2[EXTN] to be cleared.
+12. Check SYSCTL2[SAMPCLKSEL], Sampling Clock Select. It's set value
+    indicate tuning procedure success, and clear indicate failure.
+    In case of tuning failure, fixed sampling scheme could be used by
+    clearing TBCTL[TB_EN].
+
+Fixes: b1f378ab5334 ("mmc: sdhci-of-esdhc: add erratum A008171 support")
+Signed-off-by: Yinbo Zhu <yinbo.zhu@nxp.com>
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/sdhci-esdhc.h    |  14 ++
+ drivers/mmc/host/sdhci-of-esdhc.c | 222 +++++++++++++++++++++++++-----
+ 2 files changed, 203 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
+index 57b582bf73d9..9289bb4d633e 100644
+--- a/drivers/mmc/host/sdhci-esdhc.h
++++ b/drivers/mmc/host/sdhci-esdhc.h
+@@ -51,6 +51,11 @@
+ #define ESDHC_CLOCK_HCKEN             0x00000002
+ #define ESDHC_CLOCK_IPGEN             0x00000001
++/* System Control 2 Register */
++#define ESDHC_SYSTEM_CONTROL_2                0x3c
++#define ESDHC_SMPCLKSEL                       0x00800000
++#define ESDHC_EXTN                    0x00400000
++
+ /* Host Controller Capabilities Register 2 */
+ #define ESDHC_CAPABILITIES_1          0x114
+@@ -59,7 +64,16 @@
+ #define ESDHC_HS400_WNDW_ADJUST               0x00000040
+ #define ESDHC_HS400_MODE              0x00000010
+ #define ESDHC_TB_EN                   0x00000004
++#define ESDHC_TB_MODE_MASK            0x00000003
++#define ESDHC_TB_MODE_SW              0x00000003
++#define ESDHC_TB_MODE_3                       0x00000002
++
++#define ESDHC_TBSTAT                  0x124
++
+ #define ESDHC_TBPTR                   0x128
++#define ESDHC_WNDW_STRT_PTR_SHIFT     8
++#define ESDHC_WNDW_STRT_PTR_MASK      (0x7f << 8)
++#define ESDHC_WNDW_END_PTR_MASK               0x7f
+ /* SD Clock Control Register */
+ #define ESDHC_SDCLKCTL                        0x144
+diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
+index 889ed98ec0e7..14f0cb7fa374 100644
+--- a/drivers/mmc/host/sdhci-of-esdhc.c
++++ b/drivers/mmc/host/sdhci-of-esdhc.c
+@@ -77,8 +77,10 @@ struct sdhci_esdhc {
+       bool quirk_incorrect_hostver;
+       bool quirk_limited_clk_division;
+       bool quirk_unreliable_pulse_detection;
+-      bool quirk_fixup_tuning;
++      bool quirk_tuning_erratum_type1;
++      bool quirk_tuning_erratum_type2;
+       bool quirk_ignore_data_inhibit;
++      bool in_sw_tuning;
+       unsigned int peripheral_clock;
+       const struct esdhc_clk_fixup *clk_fixup;
+       u32 div_ratio;
+@@ -408,6 +410,8 @@ static void esdhc_le_writel(struct sdhci_host *host, u32 val, int reg)
+ static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)
+ {
++      struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++      struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+       int base = reg & ~0x3;
+       u32 value;
+       u32 ret;
+@@ -416,10 +420,24 @@ static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)
+       ret = esdhc_writew_fixup(host, reg, val, value);
+       if (reg != SDHCI_TRANSFER_MODE)
+               iowrite32be(ret, host->ioaddr + base);
++
++      /* Starting SW tuning requires ESDHC_SMPCLKSEL to be set
++       * 1us later after ESDHC_EXTN is set.
++       */
++      if (base == ESDHC_SYSTEM_CONTROL_2) {
++              if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
++                  esdhc->in_sw_tuning) {
++                      udelay(1);
++                      ret |= ESDHC_SMPCLKSEL;
++                      iowrite32be(ret, host->ioaddr + base);
++              }
++      }
+ }
+ static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)
+ {
++      struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++      struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+       int base = reg & ~0x3;
+       u32 value;
+       u32 ret;
+@@ -428,6 +446,18 @@ static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)
+       ret = esdhc_writew_fixup(host, reg, val, value);
+       if (reg != SDHCI_TRANSFER_MODE)
+               iowrite32(ret, host->ioaddr + base);
++
++      /* Starting SW tuning requires ESDHC_SMPCLKSEL to be set
++       * 1us later after ESDHC_EXTN is set.
++       */
++      if (base == ESDHC_SYSTEM_CONTROL_2) {
++              if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
++                  esdhc->in_sw_tuning) {
++                      udelay(1);
++                      ret |= ESDHC_SMPCLKSEL;
++                      iowrite32(ret, host->ioaddr + base);
++              }
++      }
+ }
+ static void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg)
+@@ -793,16 +823,21 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
+       }
+ }
+-static struct soc_device_attribute soc_fixup_tuning[] = {
++static struct soc_device_attribute soc_tuning_erratum_type1[] = {
++      { .family = "QorIQ T1023", .revision = "1.0", },
+       { .family = "QorIQ T1040", .revision = "1.0", },
+       { .family = "QorIQ T2080", .revision = "1.0", },
+-      { .family = "QorIQ T1023", .revision = "1.0", },
+       { .family = "QorIQ LS1021A", .revision = "1.0", },
+-      { .family = "QorIQ LS1080A", .revision = "1.0", },
+-      { .family = "QorIQ LS2080A", .revision = "1.0", },
++      { },
++};
++
++static struct soc_device_attribute soc_tuning_erratum_type2[] = {
+       { .family = "QorIQ LS1012A", .revision = "1.0", },
+       { .family = "QorIQ LS1043A", .revision = "1.*", },
+       { .family = "QorIQ LS1046A", .revision = "1.0", },
++      { .family = "QorIQ LS1080A", .revision = "1.0", },
++      { .family = "QorIQ LS2080A", .revision = "1.0", },
++      { .family = "QorIQ LA1575A", .revision = "1.0", },
+       { },
+ };
+@@ -826,15 +861,97 @@ static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable)
+       esdhc_clock_enable(host, true);
+ }
++static void esdhc_prepare_sw_tuning(struct sdhci_host *host, u8 *window_start,
++                                  u8 *window_end)
++{
++      struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++      struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
++      u8 tbstat_15_8, tbstat_7_0;
++      u32 val;
++
++      if (esdhc->quirk_tuning_erratum_type1) {
++              *window_start = 5 * esdhc->div_ratio;
++              *window_end = 3 * esdhc->div_ratio;
++              return;
++      }
++
++      /* Write TBCTL[11:8]=4'h8 */
++      val = sdhci_readl(host, ESDHC_TBCTL);
++      val &= ~(0xf << 8);
++      val |= 8 << 8;
++      sdhci_writel(host, val, ESDHC_TBCTL);
++
++      mdelay(1);
++
++      /* Read TBCTL[31:0] register and rewrite again */
++      val = sdhci_readl(host, ESDHC_TBCTL);
++      sdhci_writel(host, val, ESDHC_TBCTL);
++
++      mdelay(1);
++
++      /* Read the TBSTAT[31:0] register twice */
++      val = sdhci_readl(host, ESDHC_TBSTAT);
++      val = sdhci_readl(host, ESDHC_TBSTAT);
++
++      /* Reset data lines by setting ESDHCCTL[RSTD] */
++      sdhci_reset(host, SDHCI_RESET_DATA);
++      /* Write 32'hFFFF_FFFF to IRQSTAT register */
++      sdhci_writel(host, 0xFFFFFFFF, SDHCI_INT_STATUS);
++
++      /* If TBSTAT[15:8]-TBSTAT[7:0] > 4 * div_ratio
++       * or TBSTAT[7:0]-TBSTAT[15:8] > 4 * div_ratio,
++       * then program TBPTR[TB_WNDW_END_PTR] = 4 * div_ratio
++       * and program TBPTR[TB_WNDW_START_PTR] = 8 * div_ratio.
++       */
++      tbstat_7_0 = val & 0xff;
++      tbstat_15_8 = (val >> 8) & 0xff;
++
++      if (abs(tbstat_15_8 - tbstat_7_0) > (4 * esdhc->div_ratio)) {
++              *window_start = 8 * esdhc->div_ratio;
++              *window_end = 4 * esdhc->div_ratio;
++      } else {
++              *window_start = 5 * esdhc->div_ratio;
++              *window_end = 3 * esdhc->div_ratio;
++      }
++}
++
++static int esdhc_execute_sw_tuning(struct mmc_host *mmc, u32 opcode,
++                                 u8 window_start, u8 window_end)
++{
++      struct sdhci_host *host = mmc_priv(mmc);
++      struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
++      struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
++      u32 val;
++      int ret;
++
++      /* Program TBPTR[TB_WNDW_END_PTR] and TBPTR[TB_WNDW_START_PTR] */
++      val = ((u32)window_start << ESDHC_WNDW_STRT_PTR_SHIFT) &
++            ESDHC_WNDW_STRT_PTR_MASK;
++      val |= window_end & ESDHC_WNDW_END_PTR_MASK;
++      sdhci_writel(host, val, ESDHC_TBPTR);
++
++      /* Program the software tuning mode by setting TBCTL[TB_MODE]=2'h3 */
++      val = sdhci_readl(host, ESDHC_TBCTL);
++      val &= ~ESDHC_TB_MODE_MASK;
++      val |= ESDHC_TB_MODE_SW;
++      sdhci_writel(host, val, ESDHC_TBCTL);
++
++      esdhc->in_sw_tuning = true;
++      ret = sdhci_execute_tuning(mmc, opcode);
++      esdhc->in_sw_tuning = false;
++      return ret;
++}
++
+ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ {
+       struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
++      u8 window_start, window_end;
++      int ret, retries = 1;
+       bool hs400_tuning;
+       unsigned int clk;
+       u32 val;
+-      int ret;
+       /* For tuning mode, the sd clock divisor value
+        * must be larger than 3 according to reference manual.
+@@ -843,39 +960,73 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+       if (host->clock > clk)
+               esdhc_of_set_clock(host, clk);
+-      if (esdhc->quirk_limited_clk_division &&
+-          host->flags & SDHCI_HS400_TUNING)
+-              esdhc_of_set_clock(host, host->clock);
+-
+       esdhc_tuning_block_enable(host, true);
+       hs400_tuning = host->flags & SDHCI_HS400_TUNING;
+-      ret = sdhci_execute_tuning(mmc, opcode);
+-      if (hs400_tuning) {
+-              val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
+-              val |= ESDHC_FLW_CTL_BG;
+-              sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
+-      }
++      do {
++              if (esdhc->quirk_limited_clk_division &&
++                  hs400_tuning)
++                      esdhc_of_set_clock(host, host->clock);
+-      if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) {
++              /* Do HW tuning */
++              val = sdhci_readl(host, ESDHC_TBCTL);
++              val &= ~ESDHC_TB_MODE_MASK;
++              val |= ESDHC_TB_MODE_3;
++              sdhci_writel(host, val, ESDHC_TBCTL);
+-              /* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and
+-               * program TBPTR[TB_WNDW_START_PTR] = 5*DIV_RATIO
+-               */
+-              val = sdhci_readl(host, ESDHC_TBPTR);
+-              val = (val & ~((0x7f << 8) | 0x7f)) |
+-              (3 * esdhc->div_ratio) | ((5 * esdhc->div_ratio) << 8);
+-              sdhci_writel(host, val, ESDHC_TBPTR);
++              ret = sdhci_execute_tuning(mmc, opcode);
++              if (ret)
++                      break;
+-              /* program the software tuning mode by setting
+-               * TBCTL[TB_MODE]=2'h3
++              /* If HW tuning fails and triggers erratum,
++               * try workaround.
+                */
+-              val = sdhci_readl(host, ESDHC_TBCTL);
+-              val |= 0x3;
+-              sdhci_writel(host, val, ESDHC_TBCTL);
+-              sdhci_execute_tuning(mmc, opcode);
++              ret = host->tuning_err;
++              if (ret == -EAGAIN &&
++                  (esdhc->quirk_tuning_erratum_type1 ||
++                   esdhc->quirk_tuning_erratum_type2)) {
++                      /* Recover HS400 tuning flag */
++                      if (hs400_tuning)
++                              host->flags |= SDHCI_HS400_TUNING;
++                      pr_info("%s: Hold on to use fixed sampling clock. Try SW tuning!\n",
++                              mmc_hostname(mmc));
++                      /* Do SW tuning */
++                      esdhc_prepare_sw_tuning(host, &window_start,
++                                              &window_end);
++                      ret = esdhc_execute_sw_tuning(mmc, opcode,
++                                                    window_start,
++                                                    window_end);
++                      if (ret)
++                              break;
++
++                      /* Retry both HW/SW tuning with reduced clock. */
++                      ret = host->tuning_err;
++                      if (ret == -EAGAIN && retries) {
++                              /* Recover HS400 tuning flag */
++                              if (hs400_tuning)
++                                      host->flags |= SDHCI_HS400_TUNING;
++
++                              clk = host->max_clk / (esdhc->div_ratio + 1);
++                              esdhc_of_set_clock(host, clk);
++                              pr_info("%s: Hold on to use fixed sampling clock. Try tuning with reduced clock!\n",
++                                      mmc_hostname(mmc));
++                      } else {
++                              break;
++                      }
++              } else {
++                      break;
++              }
++      } while (retries--);
++
++      if (ret) {
++              esdhc_tuning_block_enable(host, false);
++      } else if (hs400_tuning) {
++              val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
++              val |= ESDHC_FLW_CTL_BG;
++              sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
+       }
++
+       return ret;
+ }
+@@ -1111,10 +1262,15 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
+       pltfm_host = sdhci_priv(host);
+       esdhc = sdhci_pltfm_priv(pltfm_host);
+-      if (soc_device_match(soc_fixup_tuning))
+-              esdhc->quirk_fixup_tuning = true;
++      if (soc_device_match(soc_tuning_erratum_type1))
++              esdhc->quirk_tuning_erratum_type1 = true;
++      else
++              esdhc->quirk_tuning_erratum_type1 = false;
++
++      if (soc_device_match(soc_tuning_erratum_type2))
++              esdhc->quirk_tuning_erratum_type2 = true;
+       else
+-              esdhc->quirk_fixup_tuning = false;
++              esdhc->quirk_tuning_erratum_type2 = false;
+       if (esdhc->vendor_ver == VENDOR_V_22)
+               host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+-- 
+2.20.1
+
diff --git a/queue-5.4/mmc-sdhci-of-esdhc-re-implement-erratum-a-009204-wor.patch b/queue-5.4/mmc-sdhci-of-esdhc-re-implement-erratum-a-009204-wor.patch
new file mode 100644 (file)
index 0000000..eb98107
--- /dev/null
@@ -0,0 +1,67 @@
+From a56e79c4998756a605197de9a3a1817e4b55004a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Dec 2019 11:23:35 +0800
+Subject: mmc: sdhci-of-esdhc: re-implement erratum A-009204 workaround
+
+From: Yangbo Lu <yangbo.lu@nxp.com>
+
+[ Upstream commit f667216c5c7c967c3e568cdddefb51fe606bfe26 ]
+
+The erratum A-009204 workaround patch was reverted because of
+incorrect implementation.
+
+8b6dc6b mmc: sdhci-of-esdhc: Revert "mmc: sdhci-of-esdhc: add
+        erratum A-009204 support"
+
+This patch is to re-implement the workaround (add a 5 ms delay
+before setting SYSCTL[RSTD] to make sure all the DMA transfers
+are finished).
+
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+Link: https://lore.kernel.org/r/20191219032335.26528-1-yangbo.lu@nxp.com
+Fixes: 5dd195522562 ("mmc: sdhci-of-esdhc: add erratum A-009204 support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/host/sdhci-of-esdhc.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
+index 14f0cb7fa374..fcfb50f84c8b 100644
+--- a/drivers/mmc/host/sdhci-of-esdhc.c
++++ b/drivers/mmc/host/sdhci-of-esdhc.c
+@@ -80,6 +80,7 @@ struct sdhci_esdhc {
+       bool quirk_tuning_erratum_type1;
+       bool quirk_tuning_erratum_type2;
+       bool quirk_ignore_data_inhibit;
++      bool quirk_delay_before_data_reset;
+       bool in_sw_tuning;
+       unsigned int peripheral_clock;
+       const struct esdhc_clk_fixup *clk_fixup;
+@@ -735,6 +736,11 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
+       struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+       u32 val;
++      if (esdhc->quirk_delay_before_data_reset &&
++          (mask & SDHCI_RESET_DATA) &&
++          (host->flags & SDHCI_REQ_USE_DMA))
++              mdelay(5);
++
+       sdhci_reset(host, mask);
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+@@ -1197,6 +1203,10 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
+       if (match)
+               esdhc->clk_fixup = match->data;
+       np = pdev->dev.of_node;
++
++      if (of_device_is_compatible(np, "fsl,p2020-esdhc"))
++              esdhc->quirk_delay_before_data_reset = true;
++
+       clk = of_clk_get(np, 0);
+       if (!IS_ERR(clk)) {
+               /*
+-- 
+2.20.1
+
index fedb3132dad965a9aada180ad35ffe72bde1b62a..162eec318298133d831790371f7a84676d55478e 100644 (file)
@@ -188,3 +188,5 @@ ipv6-addrconf-only-check-invalid-header-values-when-netlink_f_strict_chk-is-set.
 net-phylink-fix-interface-passed-to-mac_link_up.patch
 net-ena-fix-napi-handler-misbehavior-when-the-napi-budget-is-zero.patch
 vhost-vsock-accept-only-packets-with-the-right-dst_cid.patch
+mmc-sdhci-of-esdhc-fix-up-erratum-a-008171-workaroun.patch
+mmc-sdhci-of-esdhc-re-implement-erratum-a-009204-wor.patch