summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Kunapuli <pkunapuli@nvidia.com>2013-07-24 01:12:53 +0530
committerRiham Haidar <rhaidar@nvidia.com>2013-09-16 12:28:30 -0700
commit1b10b307c339d6ca811fee3ec7460577df64ef7a (patch)
treecb099370e90f6b233ed11353e857cc1dc49a913a
parent7101e9fd4e105ac2e26f0652466d19d67e3cd897 (diff)
mmc: tegra: 1.39V Tuning during device enumeration
Tuning at 1.39V to find a valid tap value that works at all core voltages. Boosting emc clock to 900MHz before setting 1.39V and releasing the frequency after 1.39V setting is removed. Bug 1331018 Reviewed-on: http://git-master/r/252471 (cherry picked from commit 25efc183d9f57431c379fecce0e2cc541b0fbc93) Change-Id: Icbf009a90ba9d0bd88a5991aab2fad8f1783b823 Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com> Signed-off-by: Naveen Kumar Arepalli <naveenk@nvidia.com> Change-Id: I512a29e94cb935c12a8e705da1d4478c640c9529 Reviewed-on: http://git-master/r/274994 GVS: Gerrit_Virtual_Submit Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/tegra11_clocks.c1
-rw-r--r--drivers/mmc/host/sdhci-tegra.c123
-rw-r--r--drivers/mmc/host/sdhci.c2
-rw-r--r--drivers/mmc/host/sdhci.h2
4 files changed, 70 insertions, 58 deletions
diff --git a/arch/arm/mach-tegra/tegra11_clocks.c b/arch/arm/mach-tegra/tegra11_clocks.c
index 1e147c3e6665..f8e76d585846 100644
--- a/arch/arm/mach-tegra/tegra11_clocks.c
+++ b/arch/arm/mach-tegra/tegra11_clocks.c
@@ -6781,6 +6781,7 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("2d.emc", "tegra_gr2d", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("msenc.emc", "tegra_msenc", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("tsec.emc", "tegra_tsec", "emc", &tegra_clk_emc, NULL, 0, 0),
+ SHARED_CLK("sdmmc1.emc", "sdhci-tegra.0", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("sdmmc4.emc", "sdhci-tegra.3", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("camera.emc", "vi", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("iso.emc", "iso", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 7c5a94740dd1..e27ac92dc5b5 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -254,6 +254,7 @@ struct sdhci_tegra {
bool card_present;
bool is_rail_enabled;
struct clk *emc_clk;
+ bool emc_clk_enabled;
unsigned int emc_max_clk;
struct sdhci_tegra_sd_stats *sd_stat_head;
unsigned int nominal_vcore_mv;
@@ -732,8 +733,9 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
} else if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) {
/*
* In SDR50 mode, run the sdmmc controller at freq greater than
- * 104MHz to ensure the core voltage is at 1.2V. If the core voltage
- * is below 1.2V, CRC errors would occur during data transfers.
+ * 104MHz to ensure the core voltage is at 1.2V.
+ * If the core voltage is below 1.2V, CRC errors would occur
+ * during data transfers.
*/
clk_rate = clock * 2;
} else {
@@ -1135,6 +1137,8 @@ static void sdhci_tegra_dump_tuning_data(struct sdhci_host *sdhci, u8 freq_band)
tegra_host->tuning_data.select_partial_win ?
"partial" : "full");
pr_info("Best tap value %d\n",
+ tegra_host->tuning_data.best_hv_tap_value);
+ pr_info("Best tap value %d\n",
tegra_host->tuning_data.best_tap_value);
}
@@ -1230,8 +1234,7 @@ calculate_best_tap:
* If there is no margin window for both cases,
* best tap=(Y+Z')/2.
*/
-static void calculate_high_freq_tap_value(struct sdhci_host *sdhci,
- bool hv_tuning_call)
+static unsigned int calculate_high_freq_tap_value(struct sdhci_host *sdhci)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
struct sdhci_tegra *tegra_host = pltfm_host->priv;
@@ -1262,11 +1265,7 @@ static void calculate_high_freq_tap_value(struct sdhci_host *sdhci,
best_tap = (vmax_tap_data->full_win_begin +
(((vmax_tap_data->full_win_end -
vmax_tap_data->full_win_begin) * 5) / 10));
- if (hv_tuning_call)
- tuning_data->best_hv_tap_value = best_tap;
- else
- tuning_data->best_tap_value = best_tap;
- return;
+ return best_tap;
}
curr_clock = sdhci->max_clk / 1000000;
@@ -1326,10 +1325,7 @@ static void calculate_high_freq_tap_value(struct sdhci_host *sdhci,
tuning_data->select_partial_win = true;
}
}
- if (hv_tuning_call)
- tuning_data->best_hv_tap_value = best_tap;
- else
- tuning_data->best_tap_value = best_tap;
+ return best_tap;
}
static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci)
@@ -1535,8 +1531,7 @@ out:
return err;
}
-static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode,
- bool hv_tuning_call)
+static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
struct sdhci_tegra *tegra_host = pltfm_host->priv;
@@ -1546,7 +1541,8 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode,
u16 ctrl_2;
u32 ier;
unsigned int freq_band;
- unsigned int i;
+ unsigned int i = 0;
+ unsigned int j = 0;
unsigned int voltage = 0;
bool vcore_override_failed = false;
static unsigned int vcore_lvl;
@@ -1581,27 +1577,22 @@ 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) {
- if (hv_tuning_call)
- freq_band = TUNING_HIGH_FREQ_HV;
- else
- freq_band = TUNING_HIGH_FREQ;
- } else {
+ 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 (!hv_tuning_call) {
- if (tegra_host->tuning_status == TUNING_STATUS_DONE) {
+ if ((tegra_host->tuning_status == TUNING_STATUS_DONE) &&
+ (tegra_host->instance != 0)) {
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;
- }
}
/* Remove any previously set override voltages */
@@ -1620,6 +1611,11 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode,
* holding a lock. The spinlock needs to be released when calling
* non-atomic context functions like regulator calls etc.
*/
+ for (j = 2 ; j >= 1; j--) {
+ if ((tegra_host->instance == 0) && (freq_band != TUNING_LOW_FREQ))
+ freq_band = j;
+ else
+ j = j-1;
for (i = 0; i < tuning_params[freq_band].nr_voltages; i++) {
spin_unlock(&sdhci->lock);
if (!tuning_data->tap_data[i]) {
@@ -1665,6 +1661,16 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci, u32 opcode,
}
}
if (voltage != vcore_lvl) {
+ /* Boost emc clock to 900MHz before setting 1.39V */
+ if ((voltage == 1390) && tegra_host->emc_clk) {
+ err = clk_prepare_enable(tegra_host->emc_clk);
+ if (err)
+ dev_err(mmc_dev(sdhci->mmc),
+ "1.39V emc freq boost failed %d\n",
+ err);
+ else
+ tegra_host->emc_clk_enabled = true;
+ }
err = tegra_dvfs_override_core_voltage(voltage);
if (err) {
vcore_override_failed = true;
@@ -1708,6 +1714,11 @@ skip_vcore_override:
err);
else
vcore_lvl = 0;
+ if (tegra_host->emc_clk_enabled) {
+ clk_disable_unprepare(tegra_host->emc_clk);
+ tegra_host->emc_clk_enabled = false;
+ }
+
spin_lock(&sdhci->lock);
}
@@ -1720,23 +1731,27 @@ skip_vcore_override:
tegra_host->set_tuning_override = true;
/* Calculate best tap for current freq band */
- if (freq_band == TUNING_LOW_FREQ)
+ if (freq_band == TUNING_LOW_FREQ) {
calculate_low_freq_tap_value(sdhci);
- else
- calculate_high_freq_tap_value(sdhci, hv_tuning_call);
+ } else {
+ if (freq_band == TUNING_HIGH_FREQ) {
+ tegra_host->tuning_data.best_tap_value =
+ calculate_high_freq_tap_value(sdhci);
+ goto set_best_tap;
+ } else {
+ tegra_host->tuning_data.best_hv_tap_value =
+ calculate_high_freq_tap_value(sdhci);
+ goto set_best_tap;
+ }
+ }
set_best_tap:
/* Dump the tap window data */
sdhci_tegra_dump_tuning_data(sdhci, freq_band);
-
- if (hv_tuning_call) {
- sdhci_tegra_set_tap_delay(sdhci,
- tegra_host->tuning_data.best_hv_tap_value);
- } else {
- sdhci_tegra_set_tap_delay(sdhci,
- tegra_host->tuning_data.best_tap_value);
}
+ 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
@@ -1748,10 +1763,6 @@ set_best_tap:
tuning_data->overide_vcore_tuning_done = false;
tegra_host->tuning_status = TUNING_STATUS_RETUNE;
} else {
- if (hv_tuning_call)
- tegra_host->is_hv_tuning_done = true;
- else
- tegra_host->is_hv_tuning_done = false;
if (tuning_data->nominal_vcore_tuning_done &&
tuning_data->overide_vcore_tuning_done)
tegra_host->tuning_status = TUNING_STATUS_DONE;
@@ -2075,27 +2086,26 @@ static ssize_t sdhci_handle_boost_mode_tap(struct device *dev,
tegra_host->tuning_turbo_enable = 1;
dev_err(mmc_dev(sdhci_host_for_sdio->mmc),
"Setting tap value for Voltage turbo mode\n");
- if (tegra_host->is_hv_tuning_done) {
- sdhci_tegra_set_tap_delay(sdhci_host_for_sdio,
- tegra_host->tuning_data.best_hv_tap_value);
- } else {
- disable_irq(sdhci_host_for_sdio->irq);
- spin_lock(&sdhci_host_for_sdio->lock);
- sdhci_tegra_execute_tuning(sdhci_host_for_sdio,
- MMC_SEND_TUNING_BLOCK, true);
- spin_unlock(&sdhci_host_for_sdio->lock);
- enable_irq(sdhci_host_for_sdio->irq);
- }
+ disable_irq(sdhci_host_for_sdio->irq);
+ spin_lock(&sdhci_host_for_sdio->lock);
+ sdhci_tegra_set_tap_delay(sdhci_host_for_sdio,
+ tegra_host->tuning_data.best_hv_tap_value);
+ spin_unlock(&sdhci_host_for_sdio->lock);
+ enable_irq(sdhci_host_for_sdio->irq);
} else if (tap_enable == 0) {
/* set tap value calculated for voltage range 1.1 to 1.25 */
tegra_host->tuning_turbo_enable = 0;
dev_err(mmc_dev(sdhci_host_for_sdio->mmc),
"Setting tap value for voltage non-turbo mode\n");
+ disable_irq(sdhci_host_for_sdio->irq);
+ spin_lock(&sdhci_host_for_sdio->lock);
sdhci_tegra_set_tap_delay(sdhci_host_for_sdio,
tegra_host->tuning_data.best_tap_value);
+ spin_unlock(&sdhci_host_for_sdio->lock);
+ enable_irq(sdhci_host_for_sdio->irq);
} else {
dev_err(mmc_dev(sdhci_host_for_sdio->mmc),
- "Wrong value 1: enable turbo mode 0: disable turbo mode\n");
+ "Wrong value 1: enable turbo mode 0: disable turbo mode\n");
}
return count;
}
@@ -2318,15 +2328,14 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
if (rc != 0)
goto err_clk_put;
- if (!strcmp(dev_name(mmc_dev(host->mmc)), "sdhci-tegra.3")) {
+ if (!strcmp(dev_name(mmc_dev(host->mmc)), "sdhci-tegra.0")) {
tegra_host->emc_clk = clk_get(mmc_dev(host->mmc), "emc");
if (IS_ERR(tegra_host->emc_clk)) {
dev_err(mmc_dev(host->mmc), "clk err\n");
rc = PTR_ERR(tegra_host->emc_clk);
goto err_clk_put;
- }
- tegra_host->emc_max_clk =
- clk_round_rate(tegra_host->emc_clk, ULONG_MAX);
+ } else
+ clk_set_rate(tegra_host->emc_clk, 900000000);
}
pltfm_host->priv = tegra_host;
@@ -2374,6 +2383,8 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
if (plat->min_vcore_override_mv)
tegra_host->min_vcore_override_mv = plat->min_vcore_override_mv;
+ pr_err("nominal vcore %d, override %d\n", tegra_host->nominal_vcore_mv,
+ tegra_host->min_vcore_override_mv);
rc = sdhci_add_host(host);
if (tegra_host->instance == 0) {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7bea3afd7638..f1d88bfc79b3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1746,7 +1746,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
if ((host->quirks & SDHCI_QUIRK_NON_STANDARD_TUNING) &&
host->ops->execute_freq_tuning) {
- err = host->ops->execute_freq_tuning(host, opcode, false);
+ err = host->ops->execute_freq_tuning(host, opcode);
spin_unlock(&host->lock);
enable_irq(host->irq);
sdhci_runtime_pm_put(host);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index dec8533f6122..c75cf6af0756 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -286,7 +286,7 @@ struct sdhci_ops {
int (*suspend)(struct sdhci_host *host);
int (*resume)(struct sdhci_host *host);
int (*execute_freq_tuning)(struct sdhci_host *sdhci,
- u32 opcode, bool hr_tuning_call);
+ u32 opcode);
int (*get_tuning_counter)(struct sdhci_host *sdhci);
int (*sd_error_stats)(struct sdhci_host *host, u32 int_status);
};