]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/commitdiff
mmc: sdhci: Skip tuning if it is already done.
authorNaveen Kumar Arepalli <naveenk@nvidia.com>
Thu, 23 Apr 2015 09:35:46 +0000 (15:05 +0530)
committerPavan Kunapuli <pkunapuli@nvidia.com>
Thu, 14 May 2015 11:45:39 +0000 (04:45 -0700)
-Skip tuning if it is already done.
-Restore the best tap value if tuning is already done.

Bug 200098030

Signed-off-by: Naveen Kumar Arepalli <naveenk@nvidia.com>
Reviewed-on: http://git-master/r/734836
(cherry picked from commit aa406ea7610c7cb61c2e52a3f96fac44a9226bfa)
Reviewed-on: http://git-master/r/738344
Change-Id: Ic67350a4607979259fb75882660fcbc36af97000
Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com>
Reviewed-on: http://git-master/r/742721

drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
include/linux/mmc/sdhci.h

index e8742592e04cbb0d2c742d94bc38df59d0ac9168..c1ccd58299527092d7eda6ff737234571b6d2156 100644 (file)
@@ -320,6 +320,9 @@ struct sdhci_tegra {
        int drive_group_sel;
        bool en_strobe;
        unsigned int tuned_tap_delay;
+       unsigned int tuning_status;
+#define TUNING_STATUS_DONE     1
+#define TUNING_STATUS_RETUNE   2
        struct padctrl *sdmmc_padctrl;
        ktime_t timestamp;
        struct regulator *vdd_io_reg;
@@ -381,6 +384,21 @@ static void tegra_sdhci_dumpregs(struct sdhci_host *sdhci)
                                SDMMC_VENDOR_ERR_INTR_STATUS_0));
 }
 
+static bool tegra_sdhci_is_tuning_done(struct sdhci_host *sdhci)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+
+       if (tegra_host->tuning_status == TUNING_STATUS_DONE) {
+               dev_info(mmc_dev(sdhci->mmc),
+                       "Tuning already done, restoring the best tap value : %u\n",
+                               tegra_host->tuned_tap_delay);
+               sdhci_tegra_set_tap_delay(sdhci, tegra_host->tuned_tap_delay);
+               return true;
+       }
+       return false;
+}
+
 static int sdhci_tegra_get_max_tuning_loop_counter(struct sdhci_host *sdhci)
 {
        u16 hw_tuning_iterations;
@@ -715,6 +733,9 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
 
        if (plat->uhs_mask & MMC_MASK_HS400)
                host->mmc->caps2 &= ~MMC_CAP2_HS400;
+
+       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+               tegra_host->tuning_status = TUNING_STATUS_RETUNE;
 }
 
 static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
@@ -1951,6 +1972,7 @@ static void tegra_sdhci_config_tap(struct sdhci_host *sdhci, u8 option)
                tap_delay >>= SDHCI_VNDR_CLK_CTRL_TAP_VALUE_SHIFT;
                tap_delay &= SDHCI_VNDR_CLK_CTRL_TAP_VALUE_MASK;
                tegra_host->tuned_tap_delay = tap_delay;
+               tegra_host->tuning_status = TUNING_STATUS_DONE;
                break;
        case SET_DEFAULT_TAP:
                sdhci_tegra_set_tap_delay(sdhci, tegra_host->plat->tap_delay);
@@ -2196,6 +2218,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
        .config_tap_delay       = tegra_sdhci_config_tap,
        .validate_sd2_0         = tegra_sdhci_validate_sd2_0,
        .get_max_pio_transfer_limits = tegra_sdhci_set_max_pio_transfer_limits,
+       .is_tuning_done         = tegra_sdhci_is_tuning_done,
 };
 
 static const struct sdhci_pltfm_data sdhci_tegra124_pdata = {
@@ -2219,6 +2242,7 @@ static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
        .quirks2 = TEGRA_SDHCI_QUIRKS2 |
                SDHCI_QUIRK2_NON_STD_TUN_CARD_CLOCK |
                SDHCI_QUIRK2_NON_STD_TUNING_LOOP_CNTR |
+               SDHCI_QUIRK2_SKIP_TUNING |
                SDHCI_QUIRK2_PERIODIC_CALIBRATION,
        .ops  = &tegra_sdhci_ops,
 };
@@ -2248,6 +2272,7 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
        .quirks2 = TEGRA_SDHCI_QUIRKS2 |
                SDHCI_QUIRK2_NON_STD_TUN_CARD_CLOCK |
                SDHCI_QUIRK2_NON_STD_TUNING_LOOP_CNTR |
+               SDHCI_QUIRK2_SKIP_TUNING |
                SDHCI_QUIRK2_PERIODIC_CALIBRATION,
        .ops  = &tegra_sdhci_ops,
 };
index b7c64b0f92132c7d2a334ed34bc9336d48836beb..8e4eaa3c7d13ee69e620582c1ff7ec942bf5f0a7 100644 (file)
@@ -2453,6 +2453,15 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        sdhci_runtime_pm_get(host);
        spin_lock_irqsave(&host->lock, flags);
 
+       if ((host->quirks2 & SDHCI_QUIRK2_SKIP_TUNING) &&
+               host->ops->is_tuning_done) {
+               if(host->ops->is_tuning_done(host)) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       sdhci_runtime_pm_put(host);
+                       return 0;
+               }
+       }
+
        if ((host->quirks2 & SDHCI_QUIRK2_NON_STD_TUNING_LOOP_CNTR) &&
                (host->ops->get_max_tuning_loop_counter))
                tuning_loop_counter =
index b8eba6fe799e9179ab43fb07803060c7cb799601..a2203c8ceabffe87bd8d3172fa90ac3574419bd1 100644 (file)
@@ -325,6 +325,7 @@ struct sdhci_ops {
        void    (*dump_host_cust_regs)(struct sdhci_host *host);
        int     (*get_max_tuning_loop_counter)(struct sdhci_host *sdhci);
        void    (*config_tap_delay)(struct sdhci_host *host, u8 option);
+       bool    (*is_tuning_done)(struct sdhci_host *sdhci);
        int     (*validate_sd2_0)(struct sdhci_host *sdhci);
        void    (*get_max_pio_transfer_limits)(struct sdhci_host *sdhci);
 };
index cd2d740af10bb527eaddf7930c0c5b882a497aa5..195947d3ff4cfb99fc848cf9a74ad208b272432c 100644 (file)
@@ -150,6 +150,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_NON_STD_TUNING_LOOP_CNTR          (1<<14)
 #define SDHCI_QUIRK2_PERIODIC_CALIBRATION              (1<<15)
 #define SDHCI_QUIRK2_DISABLE_CARD_CLOCK_FIRST          (1<<16)
+/*Controller skips tuning if it is already done*/
+#define SDHCI_QUIRK2_SKIP_TUNING                       (1<<17)
 
        unsigned int  acmd12_ctrl;
        unsigned int  command;