Revert "HACK Revert "mmc: tegra: Set override voltages with dvfs APIs""
Dan Willemsen [Sun, 25 Aug 2013 07:19:10 +0000 (00:19 -0700)]
This reverts commit 75e7891fb7c5c02ac44632675fd13a1700cb189e.

Signed-off-by: Dan Willemsen <dwillemsen@nvidia.com>

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

index 8e6d719..6e49455 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/platform_data/mmc-sdhci-tegra.h>
 #include <mach/pinmux.h>
 #include <mach/pm_domains.h>
+#include <mach/clk.h>
 
 #include "sdhci-pltfm.h"
 
@@ -229,13 +230,13 @@ static struct freq_tuning_params tuning_params[TUNING_FREQ_COUNT] = {
        [TUNING_HIGH_FREQ] = {
                .freq_hz = 136000000,
                .nr_voltages = 2,
-               .voltages = {ULONG_MAX, 1100000},
+               .voltages = {ULONG_MAX, 1100},
        },
 #else
        [TUNING_HIGH_FREQ] = {
                .freq_hz = 156000000,
                .nr_voltages = 2,
-               .voltages = {UINT_MAX, 1100000},
+               .voltages = {ULONG_MAX, 1100},
        },
 #endif
 };
@@ -253,6 +254,9 @@ struct tap_window_data {
 struct tegra_tuning_data {
        unsigned int            best_tap_value;
        bool                    select_partial_win;
+       bool                    nominal_vcore_tun_done;
+       bool                    override_vcore_tun_done;
+       bool                    one_shot_tuning;
        struct tap_window_data  *tap_data[TUNING_VOLTAGES_COUNT];
 };
 
@@ -294,7 +298,8 @@ struct sdhci_tegra {
        struct sdhci_tegra_sd_stats *sd_stat_head;
        struct notifier_block reboot_notify;
        bool is_parent_pllc;
-       unsigned int nominal_vcore_uV;
+       unsigned int nominal_vcore_mv;
+       unsigned int min_vcore_override_mv;
        /* Tuning related structures and variables */
        /* Tuning opcode to be used */
        unsigned int tuning_opcode;
@@ -306,6 +311,7 @@ struct sdhci_tegra {
 #define TUNING_STATUS_RETUNE   2
        /* Freq tuning information for each sampling clock freq */
        struct tegra_tuning_data tuning_data;
+       bool set_tuning_override;
        unsigned int best_tap_values[TUNING_FREQ_COUNT];
        struct tegra_freq_gov_data *gov_data;
 };
@@ -1343,6 +1349,38 @@ static int sdhci_tegra_sd_error_stats(struct sdhci_host *host, u32 int_status)
        return 0;
 }
 
+static void sdhci_tegra_dump_tuning_data(struct sdhci_host *sdhci, u8 freq_band)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+
+       if (tegra_host->tuning_data.tap_data[0]) {
+               dev_info(mmc_dev(sdhci->mmc), "Tuning window data at 1.25V\n");
+               pr_info("Partial window %d\n",
+                       tegra_host->tuning_data.tap_data[0]->partial_win);
+               pr_info("full window start %d\n",
+                       tegra_host->tuning_data.tap_data[0]->full_win_begin);
+               pr_info("full window end %d\n",
+                       tegra_host->tuning_data.tap_data[0]->full_win_end);
+       }
+
+       if ((freq_band == TUNING_HIGH_FREQ) &&
+               (tegra_host->tuning_data.tap_data[1])) {
+               dev_info(mmc_dev(sdhci->mmc), "Tuning window data at 1.1V\n");
+                       pr_info("partial window %d\n",
+               tegra_host->tuning_data.tap_data[1]->partial_win);
+               pr_info("full window being %d\n",
+                       tegra_host->tuning_data.tap_data[1]->full_win_begin);
+               pr_info("full window end %d\n",
+                       tegra_host->tuning_data.tap_data[1]->full_win_end);
+       }
+               pr_info("%s window chosen\n",
+                       tegra_host->tuning_data.select_partial_win ?
+                       "partial" : "full");
+               pr_info("Best tap value %d\n",
+                       tegra_host->tuning_data.best_tap_value);
+}
+
 /*
  * Calculation of best tap value for low frequencies(82MHz).
  * X = Partial win, Y = Full win start, Z = Full win end.
@@ -1454,6 +1492,20 @@ static void calculate_high_freq_tap_value(struct sdhci_host *sdhci)
        vmax_tap_data = tuning_data->tap_data[0];
        vmid_tap_data = tuning_data->tap_data[1];
 
+       /*
+        * If tuning at min override voltage is not done or one shot tuning is
+        * done, set the best tap value as 50% of the full window.
+        */
+       if (!tuning_data->override_vcore_tun_done ||
+               tuning_data->one_shot_tuning) {
+               dev_info(mmc_dev(sdhci->mmc),
+                       "Setting best tap as 50 percent of the full window\n");
+               tuning_data->best_tap_value = (vmax_tap_data->full_win_begin +
+                       ((vmax_tap_data->full_win_end -
+                       vmax_tap_data->full_win_begin) >> 1));
+               return;
+       }
+
        curr_clock = sdhci->max_clk / 1000000;
        max_clock = uhs_max_freq_MHz[sdhci->mmc->ios.timing];
 
@@ -1715,11 +1767,13 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
        u32 ier;
        unsigned int freq_band;
        unsigned int i;
-       unsigned int voltage;
+       unsigned int voltage = 0;
 #ifdef CONFIG_MMC_FREQ_SCALING
        unsigned int dfs_freq = 0;
        bool single_freq_tuning = false;
 #endif
+       bool vcore_override_failed = false;
+       static unsigned int vcore_lvl;
 
        /* Tuning is valid only in SDR104 and SDR50 modes */
        ctrl_2 = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2);
@@ -1736,6 +1790,8 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
        else
                return -EINVAL;
 
+       sdhci->flags &= ~SDHCI_NEEDS_RETUNING;
+
        /* Set the tuning command to be used */
        tegra_host->tuning_opcode = opcode;
 
@@ -1749,12 +1805,23 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
        sdhci_writel(sdhci, SDHCI_INT_DATA_AVAIL |
                SDHCI_INT_DATA_CRC, SDHCI_INT_ENABLE);
 
+       if (sdhci->max_clk > tuning_params[TUNING_LOW_FREQ].freq_hz)
+               freq_band = TUNING_HIGH_FREQ;
+       else
+               freq_band = TUNING_LOW_FREQ;
+       tuning_data = &tegra_host->tuning_data;
+
        /*
         * If tuning is already done and retune request is not set, then skip
         * best tap value calculation and use the old best tap value.
         */
-       if (tegra_host->tuning_status == TUNING_STATUS_DONE)
+       if (tegra_host->tuning_status == TUNING_STATUS_DONE) {
+               dev_info(mmc_dev(sdhci->mmc),
+                       "Tuning already done. Setting tuned tap value %d\n",
+                       tegra_host->tuning_data.best_tap_value);
                goto set_best_tap;
+       }
+
 #ifdef CONFIG_MMC_FREQ_SCALING
        for (dfs_freq = 0; dfs_freq < TUNING_FREQ_COUNT; dfs_freq++) {
                if (sdhci->mmc->caps2 & MMC_CAP2_FREQ_SCALING)
@@ -1767,6 +1834,14 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
                        freq_band = TUNING_HIGH_FREQ;
                else
                        freq_band = TUNING_LOW_FREQ;
+               /* Remove any previously set override voltages */
+               if (tegra_host->set_tuning_override) {
+                       spin_unlock(&sdhci->lock);
+                       tegra_dvfs_override_core_voltage(0);
+                       spin_lock(&sdhci->lock);
+                       vcore_lvl = 0;
+                       tegra_host->set_tuning_override = false;
+               }
 
                /*
                 * Run tuning and get the passing tap window info for all
@@ -1781,8 +1856,9 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
                        spin_unlock(&sdhci->lock);
                        if (!tuning_data->tap_data[i]) {
                                tuning_data->tap_data[i] = devm_kzalloc(
-                               mmc_dev(sdhci->mmc),
-                               sizeof(struct tap_window_data), GFP_KERNEL);
+                                       mmc_dev(sdhci->mmc),
+                                       sizeof(struct tap_window_data),
+                                       GFP_KERNEL);
                                if (!tuning_data->tap_data[i]) {
                                        err = -ENOMEM;
                                        dev_err(mmc_dev(sdhci->mmc),
@@ -1793,40 +1869,110 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
                        }
                        tap_data = tuning_data->tap_data[i];
 
-                       if (tegra_host->nominal_vcore_uV) {
-                               if (!tegra_host->vcore_reg)
-                                       tegra_host->vcore_reg = regulator_get(
-                                       mmc_dev(sdhci->mmc), "vdd_core");
-                               if (IS_ERR_OR_NULL(tegra_host->vcore_reg)) {
-                                       dev_info(mmc_dev(sdhci->mmc),
-                                       "No vdd_core %ld. Tuning might fail.\n",
-                                       PTR_ERR(tegra_host->vcore_reg));
-                                       tegra_host->vcore_reg = NULL;
+                       /*
+                        * If nominal vcore is not specified, run tuning once
+                        * and set the tap value. Tuning might fail but this is
+                        * a better option than not trying tuning at all.
+                        */
+                       if (!tegra_host->nominal_vcore_mv) {
+                               dev_err(mmc_dev(sdhci->mmc),
+                               "Missing nominal vcore. Tuning might fail\n");
+                               tuning_data->one_shot_tuning = true;
+                               goto skip_vcore_override;
+                       }
+
+                       voltage = tuning_params[freq_band].voltages[i];
+                       if (voltage > tegra_host->nominal_vcore_mv) {
+                               voltage = tegra_host->nominal_vcore_mv;
+                               if (tuning_data->nominal_vcore_tun_done) {
+                                       spin_lock(&sdhci->lock);
+                                       continue;
+                               }
+                       }
+                       if (voltage < tegra_host->min_vcore_override_mv) {
+                               voltage = tegra_host->min_vcore_override_mv;
+                               /*
+                                * If nominal and min override voltages are
+                                * equal, set one shot tuning and mark min
+                                * override tuning as done.
+                                */
+                               if (voltage == tegra_host->nominal_vcore_mv) {
+                                       tuning_data->one_shot_tuning = true;
+                                       tuning_data->override_vcore_tun_done =
+                                               true;
+                               }
+
+                               if (tuning_data->override_vcore_tun_done) {
+                                       spin_lock(&sdhci->lock);
+                                       continue;
+                               }
+                       }
+
+                       if (voltage != vcore_lvl) {
+                               err = tegra_dvfs_override_core_voltage(voltage);
+                               if (err) {
+                                       vcore_override_failed = true;
+                                       dev_err(mmc_dev(sdhci->mmc),
+                                       "Setting tuning override_mv %d failed %d\n",
+                                       voltage, err);
                                } else {
-                                       voltage =
-                                       tuning_params[freq_band].voltages[i];
-                                       if (voltage >
-                                               tegra_host->nominal_vcore_uV)
-                                               voltage =
-                                               tegra_host->nominal_vcore_uV;
-                                       err = regulator_set_voltage(
-                                               tegra_host->vcore_reg, voltage,
-                                               voltage);
-                                       if (err)
-                                               dev_err(mmc_dev(sdhci->mmc),
-                                               "Setting nominal core voltage failed\n");
+                                       vcore_lvl = voltage;
                                }
                        }
                        spin_lock(&sdhci->lock);
 
+skip_vcore_override:
                        /* Get the tuning window info */
                        err = sdhci_tegra_get_tap_window_data(sdhci, tap_data);
                        if (err) {
-                               dev_err(mmc_dev(sdhci->mmc), "Failed to tuning window info\n");
+                               dev_err(mmc_dev(sdhci->mmc), "No tuning window\n");
                                goto out;
                        }
+
+                       /*
+                        * Nominal and min override core voltages are missing.
+                        * Set tuning as done for one shot tuning.
+                        */
+                       if (tuning_data->one_shot_tuning) {
+                               spin_lock(&sdhci->lock);
+                               tuning_data->nominal_vcore_tun_done = true;
+                               tuning_data->override_vcore_tun_done = true;
+                               break;
+                       } else if (voltage >=
+                               tegra_host->min_vcore_override_mv) {
+                               tuning_data->override_vcore_tun_done =
+                                       true;
+                       }
                }
 
+               /* Release the override voltage setting */
+               spin_unlock(&sdhci->lock);
+               err = tegra_dvfs_override_core_voltage(0);
+               if (err)
+                       dev_err(mmc_dev(sdhci->mmc),
+                       "Clearing tuning override voltage failed %d\n",
+                               err);
+               else
+                       vcore_lvl = 0;
+               spin_lock(&sdhci->lock);
+
+
+               if (!vcore_override_failed) {
+                       if (voltage == tegra_host->nominal_vcore_mv)
+                               tuning_data->nominal_vcore_tun_done = true;
+                       else if (voltage >= tegra_host->min_vcore_override_mv)
+                               tuning_data->override_vcore_tun_done = true;
+               }
+
+               /*
+                * If setting min override voltage failed for the first time,
+                * set nominal core voltage as override until retuning is done.
+                */
+               if ((tegra_host->tuning_status != TUNING_STATUS_RETUNE) &&
+                       tuning_data->nominal_vcore_tun_done &&
+                       !tuning_data->override_vcore_tun_done)
+                       tegra_host->set_tuning_override = true;
+
                /* Calculate best tap for current freq band */
                if (freq_band == TUNING_LOW_FREQ)
                        calculate_low_freq_tap_value(sdhci);
@@ -1834,32 +1980,58 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
                        calculate_high_freq_tap_value(sdhci);
 
 set_best_tap:
+               /* Dump the tap window data */
+               sdhci_tegra_dump_tuning_data(sdhci, freq_band);
+
                sdhci_tegra_set_tap_delay(sdhci,
                        tegra_host->tuning_data.best_tap_value);
-       /*
-        * Run tuning with the best tap value. If tuning fails, set the status
-        * for retuning next time enumeration is done.
-        */
-       err = sdhci_tegra_run_frequency_tuning(sdhci);
-       if (err)
-               tegra_host->tuning_status = TUNING_STATUS_RETUNE;
-       else
-               tegra_host->tuning_status = TUNING_STATUS_DONE;
+               /*
+                * Run tuning with the best tap value. If tuning fails, set the
+                * status for retuning next time enumeration is done.
+                */
+               err = sdhci_tegra_run_frequency_tuning(sdhci);
+               if (err) {
+                       tuning_data->nominal_vcore_tun_done = false;
+                       tuning_data->override_vcore_tun_done = false;
+                       tegra_host->tuning_status = TUNING_STATUS_RETUNE;
+               } else {
+                       if (tuning_data->nominal_vcore_tun_done &&
+                               tuning_data->override_vcore_tun_done)
+                               tegra_host->tuning_status = TUNING_STATUS_DONE;
+                       else
+                               tegra_host->tuning_status =
+                                       TUNING_STATUS_RETUNE;
+               }
 #ifdef CONFIG_MMC_FREQ_SCALING
-               tegra_host->best_tap_values[dfs_freq] =
-                       tegra_host->tuning_data.best_tap_value;
-               if (single_freq_tuning)
-                       break;
-}
+                       tegra_host->best_tap_values[dfs_freq] =
+                               tegra_host->tuning_data.best_tap_value;
+                       if (single_freq_tuning)
+                               break;
+               }
 #endif
-
 out:
-       /* Enable the full range for core voltage if vcore_reg exists */
-       if (tegra_host->vcore_reg) {
+       /*
+        * Lock down the core voltage if tuning at override voltage failed
+        * for the first time. The override setting will be removed once
+        * retuning is called.
+        */
+       if (tegra_host->set_tuning_override) {
+               dev_info(mmc_dev(sdhci->mmc),
+                       "Nominal core voltage being set until retuning\n");
                spin_unlock(&sdhci->lock);
-               regulator_put(tegra_host->vcore_reg);
-               tegra_host->vcore_reg = NULL;
+               err = tegra_dvfs_override_core_voltage(
+                               tegra_host->nominal_vcore_mv);
+               if (err)
+                       dev_err(mmc_dev(sdhci->mmc),
+                               "Setting tuning override voltage failed %d\n",
+                                       err);
+               else
+                       vcore_lvl = tegra_host->nominal_vcore_mv;
                spin_lock(&sdhci->lock);
+
+               /* Schedule for the retuning */
+               mod_timer(&sdhci->tuning_timer, jiffies +
+                       10 * HZ);
        }
 
        /* Enable interrupts. Enable full range for core voltage */
@@ -2501,10 +2673,13 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
                host->mmc->caps2 |= MMC_CAP2_FREQ_SCALING;
 #endif
 
-       if (plat->nominal_vcore_uV)
-               tegra_host->nominal_vcore_uV = plat->nominal_vcore_uV;
 
-       host->edp_support = plat->edp_support;
+       if (plat->nominal_vcore_mv)
+               tegra_host->nominal_vcore_mv = plat->nominal_vcore_mv;
+       if (plat->min_vcore_override_mv)
+               tegra_host->min_vcore_override_mv = plat->min_vcore_override_mv;
+
+       host->edp_support = plat->edp_support ? true : false;
        if (host->edp_support)
                for (rc = 0; rc < SD_EDP_NUM_STATES; rc++)
                        host->edp_states[rc] = plat->edp_states[rc];
index 707ce3f..005a45d 100644 (file)
@@ -45,7 +45,8 @@ struct tegra_sdhci_platform_data {
        int is_8bit;
        int pm_flags;
        int pm_caps;
-       int nominal_vcore_uV;
+       int nominal_vcore_mv;
+       int min_vcore_override_mv;
        unsigned int max_clk_limit;
        unsigned int ddr_clk_limit;
        unsigned int tap_delay;