mmc: sdhci-of-esdhc: fix esdhc_reset() for different controller versions
authorYangbo Lu <yangbo.lu@nxp.com>
Wed, 8 Jan 2020 04:07:12 +0000 (12:07 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 17 Apr 2020 08:50:16 +0000 (10:50 +0200)
commit 2aa3d826adb578b26629a79b775a552cfe3fedf7 upstream.

This patch is to fix operating in esdhc_reset() for different
controller versions, and to add bus-width restoring after data
reset for eSDHC (verdor version <= 2.2).

Also add annotation for understanding.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20200108040713.38888-1-yangbo.lu@nxp.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mmc/host/sdhci-of-esdhc.c

index fcfb50f..fd1251e 100644 (file)
@@ -734,23 +734,58 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
-       u32 val;
+       u32 val, bus_width = 0;
 
+       /*
+        * Add delay to make sure all the DMA transfers are finished
+        * for quirk.
+        */
        if (esdhc->quirk_delay_before_data_reset &&
            (mask & SDHCI_RESET_DATA) &&
            (host->flags & SDHCI_REQ_USE_DMA))
                mdelay(5);
 
+       /*
+        * Save bus-width for eSDHC whose vendor version is 2.2
+        * or lower for data reset.
+        */
+       if ((mask & SDHCI_RESET_DATA) &&
+           (esdhc->vendor_ver <= VENDOR_V_22)) {
+               val = sdhci_readl(host, ESDHC_PROCTL);
+               bus_width = val & ESDHC_CTRL_BUSWIDTH_MASK;
+       }
+
        sdhci_reset(host, mask);
 
-       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
-       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+       /*
+        * Restore bus-width setting and interrupt registers for eSDHC
+        * whose vendor version is 2.2 or lower for data reset.
+        */
+       if ((mask & SDHCI_RESET_DATA) &&
+           (esdhc->vendor_ver <= VENDOR_V_22)) {
+               val = sdhci_readl(host, ESDHC_PROCTL);
+               val &= ~ESDHC_CTRL_BUSWIDTH_MASK;
+               val |= bus_width;
+               sdhci_writel(host, val, ESDHC_PROCTL);
+
+               sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+               sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+       }
 
-       if (mask & SDHCI_RESET_ALL) {
+       /*
+        * Some bits have to be cleaned manually for eSDHC whose spec
+        * version is higher than 3.0 for all reset.
+        */
+       if ((mask & SDHCI_RESET_ALL) &&
+           (esdhc->spec_ver >= SDHCI_SPEC_300)) {
                val = sdhci_readl(host, ESDHC_TBCTL);
                val &= ~ESDHC_TB_EN;
                sdhci_writel(host, val, ESDHC_TBCTL);
 
+               /*
+                * Initialize eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] to
+                * 0 for quirk.
+                */
                if (esdhc->quirk_unreliable_pulse_detection) {
                        val = sdhci_readl(host, ESDHC_DLLCFG1);
                        val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;