mmc: tegra: Enable external loopback for SDMMC3
R Raj Kumar [Mon, 20 Jan 2014 15:27:15 +0000 (20:27 +0530)]
Enabled external loopback for SDMMC3 for non-tunable modes.

Bug 1426947

Change-Id: I2c14bfc7d9cb21a44208cda88188836a3de61e77
Signed-off-by: R Raj Kumar <rrajk@nvidia.com>
Reviewed-on: http://git-master/r/360197
(cherry picked from commit 383d882f4e5e4799fc0ba65f9e2a428d9cc77bfd)
Reviewed-on: http://git-master/r/410186
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Shreshtha Sahu <ssahu@nvidia.com>
Tested-by: Shreshtha Sahu <ssahu@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>

drivers/mmc/host/sdhci-tegra.c

index fdda83a..19bc4a5 100644 (file)
@@ -1016,8 +1016,17 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
 
        /* External loopback is valid for sdmmc3 only */
        if ((soc_data->nvquirks & NVQUIRK_DISABLE_EXTERNAL_LOOPBACK) &&
-               (tegra_host->instance == 2))
-               misc_ctrl &= ~(1 << SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT);
+               (tegra_host->instance == 2)) {
+               if ((tegra_host->tuning_status == TUNING_STATUS_DONE)
+                       && (host->mmc->pm_flags &
+                       MMC_PM_KEEP_POWER)) {
+                       misc_ctrl &= ~(1 <<
+                       SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT);
+               } else {
+                       misc_ctrl |= (1 <<
+                       SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT);
+               }
+       }
        sdhci_writel(host, misc_ctrl, SDHCI_VNDR_MISC_CTRL);
 
        if (soc_data->nvquirks & NVQUIRK_DISABLE_AUTO_CMD23)
@@ -2361,12 +2370,15 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
        struct sdhci_tegra *tegra_host = pltfm_host->priv;
        struct tegra_tuning_data *tuning_data;
        unsigned int freq_band;
+       const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
        int err;
        u16 ctrl_2;
+       u32 misc_ctrl;
        u32 ier;
        u8 i, set_retuning = 0;
        bool is_retuning_req = false;
        bool force_retuning = false;
+       bool enable_lb_clk;
 
        /* Tuning is valid only in SDR104 and SDR50 modes */
        ctrl_2 = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2);
@@ -2384,6 +2396,15 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
                return -EINVAL;
 
        SDHCI_TEGRA_DBG("%s: Starting freq tuning\n", mmc_hostname(sdhci->mmc));
+       enable_lb_clk = (soc_data->nvquirks &
+                       NVQUIRK_DISABLE_EXTERNAL_LOOPBACK) &&
+                       (tegra_host->instance == 2);
+       if (enable_lb_clk) {
+               misc_ctrl = sdhci_readl(sdhci, SDHCI_VNDR_MISC_CTRL);
+               misc_ctrl &= ~(1 <<
+                       SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT);
+               sdhci_writel(sdhci, misc_ctrl, SDHCI_VNDR_MISC_CTRL);
+       }
        mutex_lock(&tuning_mutex);
        if (sdhci->flags & SDHCI_NEEDS_RETUNING)
                is_retuning_req = true;
@@ -2487,6 +2508,21 @@ out:
        mutex_unlock(&tuning_mutex);
 
        SDHCI_TEGRA_DBG("%s: Freq tuning done\n", mmc_hostname(sdhci->mmc));
+       if (enable_lb_clk) {
+               misc_ctrl = sdhci_readl(sdhci, SDHCI_VNDR_MISC_CTRL);
+               if (err) {
+                       /* Tuning is failed and card will try to enumerate in
+                        * Legacy High Speed mode. So, Enable External Loopback
+                        * for SDMMC3.
+                        */
+                       misc_ctrl |= (1 <<
+                               SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT);
+               } else {
+                       misc_ctrl &= ~(1 <<
+                               SDHCI_VNDR_MISC_CTRL_EN_EXT_LOOPBACK_SHIFT);
+               }
+               sdhci_writel(sdhci, misc_ctrl, SDHCI_VNDR_MISC_CTRL);
+       }
        return err;
 }