diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 9b7d731fa9e6..4ab614ef1bc0 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -886,10 +886,10 @@ static void dfll_load_i2c_lut(struct tegra_dfll *td) u32 val; for (i = 0; i < MAX_DFLL_VOLTAGES; i++) { - if (i < td->lut_min) - lut_index = td->lut_min; - else if (i > td->lut_max) - lut_index = td->lut_max; + if (i < td->lut_bottom) + lut_index = td->lut_bottom; + else if (i > td->lut_size - 1) + lut_index = td->lut_size - 1; else lut_index = i; @@ -1020,6 +1020,28 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate) return -ENOENT; } +/** + * find_mv_out_cap - find the out_map index with voltage >= @mv + * @td: DFLL instance + * @mv: millivolts + * + * Find the lut index with voltage greater than or equal to @mv, + * and return it. If all of the voltages in out_map are less than + * @mv, then return the lut index * corresponding to the highest + * possible voltage, even though it's less than @mv. + */ +static u8 find_mv_out_cap(struct tegra_dfll *td, int mv) +{ + u8 i; + + for (i = td->lut_bottom; i < td->lut_size; i++) { + if (td->lut_uv[i] >= mv * 1000) + return i; + } + + return i - 1; /* maximum possible output */ +} + /** * dfll_calculate_rate_request - calculate DFLL parameters for a given rate * @td: DFLL instance @@ -1704,7 +1726,17 @@ static void dfll_init_tuning_thresholds(struct tegra_dfll *td) if ((out_min + 2) > max_voltage_index) return; - out_start = out_min + DFLL_TUNE_HIGH_MARGIN_STEPS; + if (td->soc->cvb->cpu_dfll_data.tune_high_margin_millivolts) { + unsigned int mv; + + mv = td->soc->tune_high_min_millivolts + + td->soc->cvb->cpu_dfll_data.tune_high_margin_millivolts; + if (mv * 1000 > td->lut_uv[max_voltage_index]) + return; + out_start = max((u8)(out_min + 1), find_mv_out_cap(td, mv)); + } else { + out_start = out_min + DFLL_TUNE_HIGH_MARGIN_STEPS; + } if (out_start > max_voltage_index) return; diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index fb209eb5f365..f05d14cd6d44 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -31,6 +31,8 @@ struct tegra_dfll_soc_data { unsigned long max_freq; const struct cvb_table *cvb; struct rail_alignment alignment; + unsigned int min_millivolts; + unsigned int tune_high_min_millivolts; void (*init_clock_trimmers)(void); void (*set_clock_trimmers_high)(void); diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index a507b1622995..d801589b35cb 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -685,6 +685,7 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = { .tune1_low = 0x012207ff, .tune1_high = 0x03FFF7FF, .tune_high_min_millivolts = 850, + .tune_high_margin_millivolts = 38, } }, { @@ -697,6 +698,7 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = { .tune0_high = 0x0000ffff, .tune1_low = 0x021107ff, .tune_high_min_millivolts = 850, + .tune_high_margin_millivolts = 38, } }, { @@ -709,6 +711,7 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = { .tune0_high = 0x0000ffff, .tune1_low = 0x021107ff, .tune_high_min_millivolts = 850, + .tune_high_margin_millivolts = 38, } }, { @@ -720,6 +723,7 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = { .tune0_low = 0x0000ffcf, .tune1_low = 0x012207ff, .tune_high_min_millivolts = 850, + .tune_high_margin_millivolts = 38, } }, }; diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h index 95694e4199f6..244b771061db 100644 --- a/drivers/clk/tegra/cvb.h +++ b/drivers/clk/tegra/cvb.h @@ -34,6 +34,7 @@ struct cvb_cpu_dfll_data { u32 tune1_low; u32 tune1_high; unsigned int tune_high_min_millivolts; + unsigned int tune_high_margin_millivolts; }; struct cvb_table {