diff options
author | Pavan Kunapuli <pkunapuli@nvidia.com> | 2014-02-03 13:08:56 +0530 |
---|---|---|
committer | Harry Hong <hhong@nvidia.com> | 2014-05-27 22:51:14 -0700 |
commit | 5bf181dba1391eef6321bf8aaa4d066c85d0d6b7 (patch) | |
tree | e691304f2eac3e8ef0ce7f444662745371e98f6a /drivers | |
parent | babc63b6fe2be8a0d84b612ff85680af6dd6ac9c (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.c | 178 |
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"); |