summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPavan Kunapuli <pkunapuli@nvidia.com>2014-02-03 13:08:56 +0530
committerHarry Hong <hhong@nvidia.com>2014-05-27 22:51:14 -0700
commit5bf181dba1391eef6321bf8aaa4d066c85d0d6b7 (patch)
treee691304f2eac3e8ef0ce7f444662745371e98f6a /drivers
parentbabc63b6fe2be8a0d84b612ff85680af6dd6ac9c (diff)
mmc: tegra: Use first valid full win for negative margins
For negative margin calculations, use the first valid full window in the first valid UI if Avg UI is found. If Avg UI is not found, use first and second full windows to determine the negative margin. During negative margin calculation, marking each step as boundary. Bug 1423423 Change-Id: I5c79a890799c442b1e6be5243db362a03efc58bc Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com> Reviewed-on: http://git-master/r/362768 (cherry picked from commit 976bfae7bf33dd5fe2bc653627df44d8f2688a21) Reviewed-on: http://git-master/r/415581 Reviewed-by: Harry Hong <hhong@nvidia.com> Tested-by: Harry Hong <hhong@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/host/sdhci-tegra.c178
1 files changed, 159 insertions, 19 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 363b50b0dac1..8f79b2873c79 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -175,7 +175,7 @@
#define TUNING_VOLTAGES_COUNT 3
#define TUNING_RETRIES 1
#define DFS_FREQ_COUNT 2
-
+#define NEG_MAR_CHK_WIN_COUNT 2
/* Tuning core voltage requirements */
#define NOMINAL_VCORE_TUN BIT(0)
#define BOOT_VCORE_TUN BIT(1)
@@ -2118,16 +2118,33 @@ static int adjust_holes_in_tap_windows(struct sdhci_host *sdhci,
tap_data = &tuning_data->tap_data[i];
final_tap_data = &tuning_data->final_tap_data[j];
- if (tap_hole < tap_data->win_start) {
+ if (tap_hole <= tap_data->win_start) {
+ if (tap_hole == tap_data->win_start) {
+ memcpy(final_tap_data, tap_data,
+ sizeof(struct tap_window_data));
+ final_tap_data->win_start++;
+ final_tap_data->win_start_attr =
+ WIN_EDGE_HOLE;
+ j++;
+ i++;
+ num_of_wins--;
+ }
get_next_hole = true;
continue;
- } else if (tap_hole > tap_data->win_end) {
+ } else if (tap_hole >= tap_data->win_end) {
memcpy(final_tap_data, tap_data,
sizeof(struct tap_window_data));
+ if (tap_hole == tap_data->win_end) {
+ final_tap_data->win_end--;
+ final_tap_data->win_end_attr =
+ WIN_EDGE_HOLE;
+ get_next_hole = true;
+ } else
+ get_next_hole = false;
+
i++;
j++;
num_of_wins--;
- get_next_hole = false;
continue;
} else if ((tap_hole >= tap_data->win_start) &&
(tap_hole <= tap_data->win_end)) {
@@ -2169,6 +2186,108 @@ static int adjust_holes_in_tap_windows(struct sdhci_host *sdhci,
}
/*
+ * Insert the boundaries from negative margin calculations into the windows
+ * from auto tuning.
+ */
+static int insert_boundaries_in_tap_windows(struct sdhci_host *sdhci,
+ struct tegra_tuning_data *tuning_data, u8 boun_end)
+{
+ struct tap_window_data *tap_data;
+ struct tap_window_data *new_tap_data;
+ struct tap_window_data *temp_tap_data;
+ struct tuning_values *calc_values = &tuning_data->calc_values;
+ int curr_boun;
+ u8 i = 0, j = 0, num_of_wins;
+ bool get_next_boun = false;
+
+ temp_tap_data = devm_kzalloc(mmc_dev(sdhci->mmc),
+ sizeof(struct tap_window_data) * 42, GFP_KERNEL);
+ if (IS_ERR_OR_NULL(temp_tap_data)) {
+ dev_err(mmc_dev(sdhci->mmc), "No mem for final tap wins\n");
+ return -ENOMEM;
+ }
+
+ num_of_wins = tuning_data->num_of_valid_tap_wins;
+ curr_boun = boun_end;
+ do {
+ curr_boun -= calc_values->ui;
+ } while (curr_boun > 0);
+ curr_boun += calc_values->ui;
+
+ do {
+ if (get_next_boun) {
+ curr_boun += calc_values->ui;
+ /*
+ * If the boun_end exceeds the intial boundary end,
+ * just copy remaining windows and return.
+ */
+ if (curr_boun >= boun_end)
+ curr_boun += MAX_TAP_VALUES;
+ }
+
+ tap_data = &tuning_data->tap_data[i];
+ new_tap_data = &temp_tap_data[j];
+ if (curr_boun <= tap_data->win_start) {
+ get_next_boun = true;
+ continue;
+ } else if (curr_boun >= tap_data->win_end) {
+ memcpy(new_tap_data, tap_data,
+ sizeof(struct tap_window_data));
+ i++;
+ j++;
+ num_of_wins--;
+ get_next_boun = false;
+ continue;
+ } else if ((curr_boun >= tap_data->win_start) &&
+ (curr_boun <= tap_data->win_end)) {
+ new_tap_data->win_start = tap_data->win_start;
+ new_tap_data->win_start_attr =
+ tap_data->win_start_attr;
+ new_tap_data->win_end = curr_boun - 1;
+ new_tap_data->win_end_attr =
+ tap_data->win_end_attr;
+ j++;
+ new_tap_data = &temp_tap_data[j];
+ new_tap_data->win_start = curr_boun;
+ new_tap_data->win_end = curr_boun;
+ new_tap_data->win_start_attr =
+ WIN_EDGE_BOUN_START;
+ new_tap_data->win_end_attr =
+ WIN_EDGE_BOUN_END;
+ j++;
+ new_tap_data = &temp_tap_data[j];
+ new_tap_data->win_start = curr_boun + 1;
+ new_tap_data->win_start_attr = WIN_EDGE_BOUN_START;
+ new_tap_data->win_end = tap_data->win_end;
+ new_tap_data->win_end_attr =
+ tap_data->win_end_attr;
+ i++;
+ j++;
+ num_of_wins--;
+ get_next_boun = true;
+ }
+ } while (num_of_wins > 0);
+
+ /* Update the num of valid wins count after tap holes insertion */
+ tuning_data->num_of_valid_tap_wins = j;
+
+ memcpy(tuning_data->tap_data, temp_tap_data,
+ j * sizeof(struct tap_window_data));
+ SDHCI_TEGRA_DBG("***tuning windows after inserting boundaries***\n");
+ SDHCI_TEGRA_DBG("WIN_ATTR legend: 0-BOUN_ST, 1-BOUN_END, 2-HOLE\n");
+ for (i = 0; i < tuning_data->num_of_valid_tap_wins; i++) {
+ new_tap_data = &tuning_data->tap_data[i];
+ SDHCI_TEGRA_DBG("win[%d]:%d(%d) - %d(%d)\n", i,
+ new_tap_data->win_start,
+ new_tap_data->win_start_attr,
+ new_tap_data->win_end, new_tap_data->win_end_attr);
+ }
+ SDHCI_TEGRA_DBG("***********************************************\n");
+
+ return 0;
+}
+
+/*
* Scan for all tap values and get all passing tap windows.
*/
static int sdhci_tegra_get_tap_window_data(struct sdhci_host *sdhci,
@@ -2178,11 +2297,12 @@ static int sdhci_tegra_get_tap_window_data(struct sdhci_host *sdhci,
struct sdhci_tegra *tegra_host = pltfm_host->priv;
struct tap_window_data *tap_data;
struct tuning_ui tuning_ui[10];
- int err = 0, partial_win_start = 0;
+ int err = 0, partial_win_start = 0, temp_margin = 0;
unsigned int tap_value, calc_ui = 0;
u8 prev_boundary_end = 0, num_of_wins = 0;
u8 num_of_uis = 0, valid_num_uis = 0;
- u8 ref_ui;
+ u8 ref_ui, first_valid_full_win = 0;
+ u8 boun_end = 0, next_boun_end = 0;
u8 j = 0;
bool valid_ui_found = false;
@@ -2278,10 +2398,14 @@ static int sdhci_tegra_get_tap_window_data(struct sdhci_host *sdhci,
if (tuning_ui[j - 1].ui > tuning_ui[j + 1].ui) {
tuning_ui[j + 1].is_valid_ui = false;
j++;
+ valid_num_uis--;
} else {
- tuning_ui[j - 1].is_valid_ui = false;
+ if (tuning_ui[j - 1].is_valid_ui) {
+ valid_num_uis--;
+ tuning_ui[j - 1].is_valid_ui =
+ false;
+ }
}
- valid_num_uis--;
}
}
}
@@ -2289,8 +2413,11 @@ static int sdhci_tegra_get_tap_window_data(struct sdhci_host *sdhci,
/* Calculate the cumulative UI if there are valid UIs left */
if (valid_num_uis) {
for (j = 0; j < num_of_uis; j++)
- if (tuning_ui[j].is_valid_ui)
+ if (tuning_ui[j].is_valid_ui) {
calc_ui += tuning_ui[j].ui;
+ if (!first_valid_full_win)
+ first_valid_full_win = j + 1;
+ }
}
if (calc_ui) {
@@ -2315,27 +2442,40 @@ static int sdhci_tegra_get_tap_window_data(struct sdhci_host *sdhci,
*/
if (tuning_data->is_partial_win_valid && (num_of_wins > 1)) {
if (valid_ui_found) {
- partial_win_start = tuning_data->tap_data[1].win_start;
+ partial_win_start =
+ tuning_data->tap_data[first_valid_full_win].win_start;
+ boun_end = partial_win_start;
do {
partial_win_start -=
tuning_data->calc_values.ui;
} while (partial_win_start > 0);
} else {
- for (j = 1; j < num_of_wins; j++) {
- tap_data = &tuning_data->tap_data[j];
- if ((tap_data->win_start -
- tuning_data->calc_values.ui) <= 0) {
- partial_win_start =
- (tap_data->win_start -
- tuning_data->calc_values.ui);
- } else
- break;
+ for (j = 0; j < NEG_MAR_CHK_WIN_COUNT; j++) {
+ temp_margin =
+ tuning_data->tap_data[j + 1].win_start;
+ if (!boun_end)
+ boun_end = temp_margin;
+ else if (!next_boun_end)
+ next_boun_end = temp_margin;
+ do {
+ temp_margin -=
+ tuning_data->calc_values.ui;
+ } while (temp_margin > 0);
+
+ if (!partial_win_start ||
+ (temp_margin > partial_win_start))
+ partial_win_start = temp_margin;
}
}
if (partial_win_start <= 0)
tuning_data->tap_data[0].win_start = partial_win_start;
}
+ if (boun_end)
+ insert_boundaries_in_tap_windows(sdhci, tuning_data, boun_end);
+ if (next_boun_end)
+ insert_boundaries_in_tap_windows(sdhci, tuning_data, next_boun_end);
+
/* Print info of all tap windows */
SDHCI_TEGRA_DBG("**********Auto tuning windows*************\n");
SDHCI_TEGRA_DBG("WIN_ATTR legend: 0-BOUN_ST, 1-BOUN_END, 2-HOLE\n");