mmc: renesas_sdhi: Add manual correction
authorTakeshi Saito <takeshi.saito.xv@renesas.com>
Tue, 17 Dec 2019 11:40:31 +0000 (12:40 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 24 Mar 2020 13:35:38 +0000 (14:35 +0100)
This patch adds a manual correction mechanism for SDHI. Currently, SDHI
uses automatic TAP position correction. However, TAP position can also
be corrected manually via correction error status flags.

Signed-off-by: Takeshi Saito <takeshi.saito.xv@renesas.com>
Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://lore.kernel.org/r/20191217114034.13290-3-wsa+renesas@sang-engineering.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/renesas_sdhi.h
drivers/mmc/host/renesas_sdhi_core.c

index f524251..11a0b2b 100644 (file)
@@ -57,6 +57,7 @@ struct renesas_sdhi {
        void __iomem *scc_ctl;
        u32 scc_tappos;
        u32 scc_tappos_hs400;
+       bool doing_tune;
 };
 
 #define host_to_priv(host) \
index 519d91a..6cedc0a 100644 (file)
@@ -263,6 +263,8 @@ static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
 #define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN       BIT(0)
 /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */
 #define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR       BIT(2)
+#define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP     BIT(1)
+#define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN   BIT(0)
 /* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT2 register */
 #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL  BIT(4)
 #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN    BIT(31)
@@ -321,6 +323,8 @@ static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host,
 {
        struct renesas_sdhi *priv = host_to_priv(host);
 
+       priv->doing_tune = true;
+
        /* Set sampling clock position */
        sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap);
 }
@@ -426,6 +430,8 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
        unsigned long ntap;     /* temporary counter of tuning success */
        unsigned long i;
 
+       priv->doing_tune = false;
+
        /* Clear SCC_RVSREQ */
        sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
 
@@ -485,6 +491,47 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
        return 0;
 }
 
+static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap)
+{
+       struct renesas_sdhi *priv = host_to_priv(host);
+       u32 val;
+
+       val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ);
+       if (!val)
+               return false;
+
+       sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+
+       /* Change TAP position according to correction status */
+       if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR)
+               return true;    /* Need re-tune */
+       else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP)
+               host->tap_set = (host->tap_set + 1) % host->tap_num;
+       else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN)
+               host->tap_set = (host->tap_set - 1) % host->tap_num;
+       else
+               return false;
+
+       sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET,
+                      host->tap_set / (use_4tap ? 2 : 1));
+
+       return false;
+}
+
+static bool renesas_sdhi_auto_correction(struct tmio_mmc_host *host)
+{
+       struct renesas_sdhi *priv = host_to_priv(host);
+
+       /* Check SCC error */
+       if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) &
+           SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
+               sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+               return true;
+       }
+
+       return false;
+}
+
 static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
 {
        struct renesas_sdhi *priv = host_to_priv(host);
@@ -499,20 +546,14 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
            !(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap))
                return false;
 
-       if (mmc_doing_retune(host->mmc))
+       if (mmc_doing_retune(host->mmc) || priv->doing_tune)
                return false;
 
-       /* Check SCC error */
        if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
-           SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &&
-           sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) &
-           SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
-               /* Clear SCC error */
-               sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
-               return true;
-       }
+           SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN)
+               return renesas_sdhi_auto_correction(host);
 
-       return false;
+       return renesas_sdhi_manual_correction(host, use_4tap);
 }
 
 static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)