summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-11-30 00:37:39 -0800
committerSimone Willett <swillett@nvidia.com>2012-12-03 16:22:46 -0800
commitfc8acc6918e52ec8028b3892b91f850fe544cd67 (patch)
tree700f0f8272074357ccbfca8ffcb8a8649cacc244
parentf50ccca936905da72b003e2517bc536e9d3a63be (diff)
ARM: tegra11: dvfs: Update CPU dvfs table format
To support CPU process binning on top of continues virtual binning: - added process id to CPU cvb dvfs table, and implemented table selection based on both speedo and process ids (only speedo id was used before) - integrated dfll tuning data into CPU cvb dvfs table, so that it can be specified differently for each process bin. Bug 1161126 Bug 1170986 Change-Id: Ie8e898170540bab59470a9f55a40fb6213f2686b Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/167918 Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/dvfs.h4
-rw-r--r--arch/arm/mach-tegra/tegra11_dvfs.c78
2 files changed, 46 insertions, 36 deletions
diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h
index 2a7802debf1a..a6241d7fde6c 100644
--- a/arch/arm/mach-tegra/dvfs.h
+++ b/arch/arm/mach-tegra/dvfs.h
@@ -140,8 +140,10 @@ struct cpu_cvb_dvfs_table {
struct cpu_cvb_dvfs {
int speedo_id;
+ int process_id;
+
+ struct dvfs_dfll_data dfll_tune_data;
int max_mv;
- int min_dfll_mv;
int freqs_mult;
int speedo_scale;
int voltage_scale;
diff --git a/arch/arm/mach-tegra/tegra11_dvfs.c b/arch/arm/mach-tegra/tegra11_dvfs.c
index e1301333e41c..f38fa655d098 100644
--- a/arch/arm/mach-tegra/tegra11_dvfs.c
+++ b/arch/arm/mach-tegra/tegra11_dvfs.c
@@ -64,12 +64,18 @@ int __attribute__((weak)) tegra_get_cvb_alignment_uV(void)
}
/* CPU DVFS tables */
-/* FIXME: real data */
static struct cpu_cvb_dvfs cpu_cvb_dvfs_table[] = {
{
.speedo_id = 0,
+ .process_id = -1,
+ .dfll_tune_data = {
+ .tune0 = 0x00b0019d,
+ .tune0_high_mv = 0x00b0019d,
+ .tune1 = 0x0000001f,
+ .droop_rate_min = 1000000,
+ .min_millivolts = 1000,
+ },
.max_mv = 1250,
- .min_dfll_mv = 1000,
.freqs_mult = MHZ,
.speedo_scale = 100,
.voltage_scale = 100,
@@ -103,16 +109,10 @@ static int cpu_dfll_millivolts[MAX_DVFS_FREQS];
static struct dvfs cpu_dvfs = {
.clk_name = "cpu_g",
- .process_id = -1,
.millivolts = cpu_millivolts,
.dfll_millivolts = cpu_dfll_millivolts,
.auto_dvfs = true,
.dvfs_rail = &tegra11_dvfs_rail_vdd_cpu,
- .dfll_data = {
- .tune0 = 0x00b0019d,
- .tune1 = 0x0000001f,
- .droop_rate_min = 1000000,
- },
};
/* Core DVFS tables */
@@ -357,6 +357,17 @@ static bool __init match_dvfs_one(struct dvfs *d, int speedo_id, int process_id)
return true;
}
+static bool __init match_cpu_cvb_one(struct cpu_cvb_dvfs *d,
+ int speedo_id, int process_id)
+{
+ if ((d->process_id != -1 && d->process_id != process_id) ||
+ (d->speedo_id != -1 && d->speedo_id != speedo_id)) {
+ pr_debug("tegra11_dvfs: rejected cpu cvb speedo %d,"
+ " process %d\n", d->speedo_id, d->process_id);
+ return false;
+ }
+ return true;
+}
/* cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) / v_scale */
static inline int get_cvb_voltage(int speedo, int s_scale,
@@ -378,30 +389,18 @@ static inline int round_cvb_voltage(int mv, int v_scale)
cvb_align_step_uv / 1000;
}
-static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
- int *max_freq_index)
+static int __init set_cpu_dvfs_data(
+ struct cpu_cvb_dvfs *d, struct dvfs *cpu_dvfs, int *max_freq_index)
{
- int i, j, mv, dfll_mv;
+ int i, j, mv, dfll_mv, min_dfll_mv;
unsigned long fmax_at_vmin = 0;
unsigned long fmax_pll_mode = 0;
unsigned long fmin_use_dfll = 0;
- struct cpu_cvb_dvfs *d = NULL;
struct cpu_cvb_dvfs_table *table = NULL;
int speedo = tegra_cpu_speedo_value();
- /* Find matching cvb dvfs entry */
- for (i = 0; i < ARRAY_SIZE(cpu_cvb_dvfs_table); i++) {
- d = &cpu_cvb_dvfs_table[i];
- if (speedo_id == d->speedo_id)
- break;
- }
-
- if (!d) {
- pr_err("tegra11_dvfs: no cpu dvfs table for speedo_id %d\n",
- speedo_id);
- return -ENOENT;
- }
- BUG_ON(d->min_dfll_mv < tegra11_dvfs_rail_vdd_cpu.min_millivolts);
+ min_dfll_mv = d->dfll_tune_data.min_millivolts;
+ BUG_ON(min_dfll_mv < tegra11_dvfs_rail_vdd_cpu.min_millivolts);
/*
* Use CVB table to fill in CPU dvfs frequencies and voltages. Each
@@ -428,8 +427,8 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
mv = round_cvb_voltage(mv, d->voltage_scale);
/* Check maximum frequency at minimum voltage for dfll source */
- dfll_mv = max(dfll_mv, d->min_dfll_mv);
- if (dfll_mv > d->min_dfll_mv) {
+ dfll_mv = max(dfll_mv, min_dfll_mv);
+ if (dfll_mv > min_dfll_mv) {
if (!j)
break; /* 1st entry already above Vmin */
if (!fmax_at_vmin)
@@ -445,7 +444,7 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
}
/* Minimum rate with pll source voltage above dfll Vmin */
- if ((mv >= d->min_dfll_mv) && (!fmin_use_dfll))
+ if ((mv >= min_dfll_mv) && (!fmin_use_dfll))
fmin_use_dfll = table->freq;
/* fill in dvfs tables */
@@ -466,8 +465,7 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
/* Table must not be empty and must have and at least one entry below,
and one entry above Vmin */
if (!i || !j || !fmax_at_vmin) {
- pr_err("tegra11_dvfs: invalid cpu dvfs table for speedo_id %d\n",
- speedo_id);
+ pr_err("tegra11_dvfs: invalid cpu dvfs table\n");
return -ENOENT;
}
@@ -478,17 +476,19 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
}
/* dvfs tables are successfully populated - fill in the rest */
- cpu_dvfs->speedo_id = speedo_id;
+ cpu_dvfs->speedo_id = d->speedo_id;
+ cpu_dvfs->process_id = d->process_id;
cpu_dvfs->freqs_mult = d->freqs_mult;
cpu_dvfs->dvfs_rail->nominal_millivolts = min(d->max_mv,
max(cpu_millivolts[j - 1], cpu_dfll_millivolts[j - 1]));
*max_freq_index = j - 1;
+ cpu_dvfs->dfll_data = d->dfll_tune_data;
cpu_dvfs->dfll_data.max_rate_boost = fmax_pll_mode ?
(cpu_dvfs->freqs[j - 1] - fmax_pll_mode) * d->freqs_mult : 0;
cpu_dvfs->dfll_data.out_rate_min = fmax_at_vmin * d->freqs_mult;
cpu_dvfs->dfll_data.use_dfll_rate_min = fmin_use_dfll * d->freqs_mult;
- cpu_dvfs->dfll_data.min_millivolts = d->min_dfll_mv;
+ cpu_dvfs->dfll_data.min_millivolts = min_dfll_mv;
return 0;
}
@@ -532,10 +532,11 @@ int tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
void __init tegra11x_init_dvfs(void)
{
int cpu_speedo_id = tegra_cpu_speedo_id();
+ int cpu_process_id = tegra_cpu_process_id();
int soc_speedo_id = tegra_soc_speedo_id();
int core_process_id = tegra_core_process_id();
- int i;
+ int i, ret;
int core_nominal_mv_index;
int cpu_max_freq_index;
@@ -575,8 +576,15 @@ void __init tegra11x_init_dvfs(void)
* voltage limit is not violated). Error when cpu dvfs table can not
* be constructed must never happen.
*/
- if (set_cpu_dvfs_data(cpu_speedo_id, &cpu_dvfs, &cpu_max_freq_index))
- BUG();
+ for (ret = 0, i = 0; i < ARRAY_SIZE(cpu_cvb_dvfs_table); i++) {
+ struct cpu_cvb_dvfs *d = &cpu_cvb_dvfs_table[i];
+ if (match_cpu_cvb_one(d, cpu_speedo_id, cpu_process_id)) {
+ ret = set_cpu_dvfs_data(
+ d, &cpu_dvfs, &cpu_max_freq_index);
+ break;
+ }
+ }
+ BUG_ON((i == ARRAY_SIZE(cpu_cvb_dvfs_table)) || ret);
/* Init rail structures and dependencies */
tegra_dvfs_init_rails(tegra11_dvfs_rails,