]> git.baikalelectronics.ru Git - kernel.git/commitdiff
mmc: sdhci-esdhc-imx: optimize the clock setting
authorHaibo Chen <haibo.chen@nxp.com>
Wed, 19 Feb 2020 08:25:50 +0000 (16:25 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 24 Mar 2020 13:35:41 +0000 (14:35 +0100)
When force clock off, check the SDOFF of register PRSSTAT to make sure
the clock is gate off. Before force clock on, check the SDSTB of register
PRSSTAT to make sure the clock is stable, this will eliminate the clock
glitch.

Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/1582100757-20683-2-git-send-email-haibo.chen@nxp.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h

index 3359153304a369564de697e9afaa9790dfffcad6..6ca01b766604bcd8c66725626b1bbb9485345f2e 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -312,6 +313,17 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
        writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
 }
 
+static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
+{
+       u32 present_state;
+       int ret;
+
+       ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state,
+                               (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100);
+       if (ret == -ETIMEDOUT)
+               dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__);
+}
+
 static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -525,6 +537,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                else
                        new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
                writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
+               if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON))
+                       esdhc_wait_for_card_clock_gate_off(host);
                return;
        case SDHCI_HOST_CONTROL2:
                new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -753,12 +767,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
        int ddr_pre_div = imx_data->is_ddr ? 2 : 1;
        int pre_div = 1;
        int div = 1;
+       int ret;
        u32 temp, val;
 
        if (esdhc_is_usdhc(imx_data)) {
                val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
                writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
                        host->ioaddr + ESDHC_VENDOR_SPEC);
+               esdhc_wait_for_card_clock_gate_off(host);
        }
 
        if (clock == 0) {
@@ -813,13 +829,18 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
                | (pre_div << ESDHC_PREDIV_SHIFT));
        sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
+       /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */
+       ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp,
+                               (temp & ESDHC_CLOCK_STABLE), 2, 100);
+       if (ret == -ETIMEDOUT)
+               dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n");
+
        if (esdhc_is_usdhc(imx_data)) {
                val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
                writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
                        host->ioaddr + ESDHC_VENDOR_SPEC);
        }
 
-       mdelay(1);
 }
 
 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
@@ -1003,6 +1024,7 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
        writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
                ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
                host->ioaddr + ESDHC_VENDOR_SPEC);
+       esdhc_wait_for_card_clock_gate_off(host);
 
        /* force a reset on strobe dll */
        writel(ESDHC_STROBE_DLL_CTRL_RESET,
index 9289bb4d633e447cdfcc638dda502c82bd31d81b..947212f16bc6f8ade79cd8ca506611005966ba86 100644 (file)
@@ -31,6 +31,7 @@
 
 /* Present State Register */
 #define ESDHC_PRSSTAT                  0x24
+#define ESDHC_CLOCK_GATE_OFF           0x00000080
 #define ESDHC_CLOCK_STABLE             0x00000008
 
 /* Protocol Control Register */