summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2013-10-30 13:38:19 -0700
committerYu-Huan Hsu <yhsu@nvidia.com>2013-11-04 11:44:21 -0800
commit29398abbc8eb7f95bb7d9bb0021f723a6bc9cde4 (patch)
tree3ad0ab485d2bd00e2a6f7fe37eb693eaa844544b /arch/arm
parentc9946a79f856a95fa6c8faf33ca2d97962e4ba56 (diff)
ARM: tegra: dvfs: Add deferred override option
Added an option to defer aggregation of module peak voltage into core override floor after DVFS initialization. This way the peak voltage can be determined based on board specific maximum rate rather than using maximum chip capability. Provided interface to specify deferred maximum rates, and platform specific call-back to adjust DVFS tables (when necessary) after final override floor is resolved. Override floor is reported equal to nominal voltage (i.e., zero override range) until all deferred limits are known. Bug 1372817 Change-Id: Iaee091a3dd95f1cbdb93efae71cbe6fa1048a895 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/323712 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-tegra/dvfs.c70
-rw-r--r--arch/arm/mach-tegra/dvfs.h20
2 files changed, 76 insertions, 14 deletions
diff --git a/arch/arm/mach-tegra/dvfs.c b/arch/arm/mach-tegra/dvfs.c
index 880de4b479d8..cc839935ea2b 100644
--- a/arch/arm/mach-tegra/dvfs.c
+++ b/arch/arm/mach-tegra/dvfs.c
@@ -775,6 +775,12 @@ int tegra_dvfs_get_freqs(struct clk *c, unsigned long **freqs, int *num_freqs)
}
EXPORT_SYMBOL(tegra_dvfs_get_freqs);
+static inline int dvfs_rail_get_override_floor(struct dvfs_rail *rail)
+{
+ return rail->override_unresolved ? rail->nominal_millivolts :
+ rail->min_override_millivolts;
+}
+
#ifdef CONFIG_TEGRA_VDD_CORE_OVERRIDE
static DEFINE_MUTEX(rail_override_lock);
@@ -789,16 +795,17 @@ static int dvfs_override_core_voltage(int override_mv)
if (rail->fixed_millivolts)
return -ENOSYS;
- floor = rail->min_override_millivolts;
+ mutex_lock(&rail_override_lock);
+
+ floor = dvfs_rail_get_override_floor(rail);
ceiling = rail->nominal_millivolts;
if (override_mv && ((override_mv < floor) || (override_mv > ceiling))) {
pr_err("%s: override level %d outside the range [%d...%d]\n",
__func__, override_mv, floor, ceiling);
+ mutex_unlock(&rail_override_lock);
return -EINVAL;
}
- mutex_lock(&rail_override_lock);
-
if (override_mv == rail->override_millivolts) {
ret = 0;
goto out;
@@ -840,6 +847,47 @@ out:
mutex_unlock(&rail_override_lock);
return ret;
}
+
+int tegra_dvfs_resolve_override(struct clk *c, unsigned long max_rate)
+{
+ int mv;
+ struct dvfs *d = c->dvfs;
+ struct dvfs_rail *rail;
+
+ if (!d)
+ return 0;
+ rail = d->dvfs_rail;
+
+ mutex_lock(&rail_override_lock);
+ mutex_lock(&dvfs_lock);
+
+ if (d->defer_override && rail->override_unresolved) {
+ d->defer_override = false;
+
+ mv = tegra_dvfs_predict_peak_millivolts(c, max_rate);
+ if (rail->min_override_millivolts < mv)
+ rail->min_override_millivolts = mv;
+
+ rail->override_unresolved--;
+ if (!rail->override_unresolved && rail->resolve_override)
+ rail->resolve_override(rail->min_override_millivolts);
+ }
+ mutex_unlock(&dvfs_lock);
+ mutex_unlock(&rail_override_lock);
+ return 0;
+}
+
+int tegra_dvfs_rail_get_override_floor(struct dvfs_rail *rail)
+{
+ if (rail) {
+ int mv;
+ mutex_lock(&rail_override_lock);
+ mv = dvfs_rail_get_override_floor(rail);
+ mutex_unlock(&rail_override_lock);
+ return mv;
+ }
+ return -ENOENT;
+}
#else
static int dvfs_override_core_voltage(int override_mv)
{
@@ -898,8 +946,12 @@ int __init tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d)
if (i && c->ops && !c->ops->shared_bus_update &&
!(c->flags & PERIPH_ON_CBUS) && !d->can_override) {
int mv = tegra_dvfs_predict_peak_millivolts(c, d->freqs[i-1]);
- if (d->dvfs_rail->min_override_millivolts < mv)
- d->dvfs_rail->min_override_millivolts = mv;
+ struct dvfs_rail *rail = d->dvfs_rail;
+ if (d->defer_override)
+ rail->override_unresolved++;
+ else if (rail->min_override_millivolts < mv)
+ rail->min_override_millivolts =
+ min(mv, rail->nominal_millivolts);
}
mutex_lock(&dvfs_lock);
@@ -1746,10 +1798,14 @@ static int dvfs_tree_show(struct seq_file *s, void *data)
seq_printf(s, " thermal %-7d mV\n", thermal_mv_floor);
if (rail == tegra_core_rail) {
- seq_printf(s, " override %-7d mV [%-4d...%-4d]\n",
+ seq_printf(s, " override %-7d mV [%-4d...%-4d]",
rail->override_millivolts,
- rail->min_override_millivolts,
+ dvfs_rail_get_override_floor(rail),
rail->nominal_millivolts);
+ if (rail->override_unresolved)
+ seq_printf(s, " unresolved %d",
+ rail->override_unresolved);
+ seq_putc(s, '\n');
}
list_sort(NULL, &rail->dvfs, dvfs_tree_sort_cmp);
diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h
index 6508d9791f63..d203d2807444 100644
--- a/arch/arm/mach-tegra/dvfs.h
+++ b/arch/arm/mach-tegra/dvfs.h
@@ -72,6 +72,8 @@ struct dvfs_rail {
int fixed_millivolts;
int override_millivolts;
int min_override_millivolts;
+ int override_unresolved;
+ int (*resolve_override)(int mv);
const int *therm_mv_floors;
int therm_mv_floors_num;
@@ -149,6 +151,7 @@ struct dvfs {
struct dvfs_rail *dvfs_rail;
bool auto_dvfs;
bool can_override;
+ bool defer_override;
/* Filled in by tegra_dvfs_init */
int max_millivolts;
@@ -270,6 +273,16 @@ int tegra_dvfs_init_thermal_dvfs_voltages(int *millivolts,
int *peak_millivolts, int freqs_num, int ranges_num, struct dvfs *d);
int tegra_dvfs_rail_dfll_mode_set_cold(struct dvfs_rail *rail);
+#ifdef CONFIG_TEGRA_VDD_CORE_OVERRIDE
+int tegra_dvfs_resolve_override(struct clk *c, unsigned long max_rate);
+int tegra_dvfs_rail_get_override_floor(struct dvfs_rail *rail);
+#else
+static inline int tegra_dvfs_resolve_override(struct clk *c, unsigned long rate)
+{ return 0; }
+static inline int tegra_dvfs_rail_get_override_floor(struct dvfs_rail *rail)
+{ return 0; }
+#endif
+
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail);
int tegra_dvfs_rail_post_enable(struct dvfs_rail *rail);
@@ -352,13 +365,6 @@ static inline int tegra_dvfs_rail_get_thermal_floor(struct dvfs_rail *rail)
return 0;
}
-static inline int tegra_dvfs_rail_get_override_floor(struct dvfs_rail *rail)
-{
- if (rail)
- return rail->min_override_millivolts;
- return -ENOENT;
-}
-
static inline bool tegra_dvfs_is_dfll_bypass(void)
{
#ifdef CONFIG_REGULATOR_TEGRA_DFLL_BYPASS