summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-12-14 13:25:50 -0800
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-01-19 10:29:17 -0800
commit732dd0ebfa107da83c18bedc42f1d606271bb89c (patch)
tree0b164bddbf8089e31cadfe46fc219dfe97dcde60
parent8501e757c02e6d30d775e1d4fb4da3ae1bee74bc (diff)
ARM: tegra: dvfs: Add alternative dvfs frequency limits
Added an option to specify alternative dvfs frequency limits for each tegra clock domain. These alternative limits can be applied in some particularly extreme (e.g., slow) corner of process-temperature space with no effect on regular limits for the rest of the space. Bug 913884 Change-Id: I05e319b60f6dc6f4e7f15c7e677e5a3bce77f201 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/70188 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com> Tested-by: Diwakar Tundlam <dtundlam@nvidia.com> Reviewed-by: Krishna Reddy <vdumpa@nvidia.com> Reviewed-on: http://git-master/r/75614 Reviewed-by: Varun Wadekar <vwadekar@nvidia.com> Tested-by: Varun Wadekar <vwadekar@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/dvfs.c46
-rw-r--r--arch/arm/mach-tegra/dvfs.h11
2 files changed, 54 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/dvfs.c b/arch/arm/mach-tegra/dvfs.c
index 22c666081c90..8723e6fa60df 100644
--- a/arch/arm/mach-tegra/dvfs.c
+++ b/arch/arm/mach-tegra/dvfs.c
@@ -320,16 +320,23 @@ static int dvfs_rail_connect_to_regulator(struct dvfs_rail *rail)
return 0;
}
+static inline unsigned long *dvfs_get_freqs(struct dvfs *d)
+{
+ return (d->alt_freqs_state == ALT_FREQS_ENABLED) ?
+ &d->alt_freqs[0] : &d->freqs[0];
+}
+
static int
__tegra_dvfs_set_rate(struct dvfs *d, unsigned long rate)
{
int i = 0;
int ret;
+ unsigned long *freqs = dvfs_get_freqs(d);
- if (d->freqs == NULL || d->millivolts == NULL)
+ if (freqs == NULL || d->millivolts == NULL)
return -ENODEV;
- if (rate > d->freqs[d->num_freqs - 1]) {
+ if (rate > freqs[d->num_freqs - 1]) {
pr_warn("tegra_dvfs: rate %lu too high for dvfs on %s\n", rate,
d->clk_name);
return -EINVAL;
@@ -338,7 +345,7 @@ __tegra_dvfs_set_rate(struct dvfs *d, unsigned long rate)
if (rate == 0) {
d->cur_millivolts = 0;
} else {
- while (i < d->num_freqs && rate > d->freqs[i])
+ while (i < d->num_freqs && rate > freqs[i])
i++;
if ((d->max_millivolts) &&
@@ -360,6 +367,31 @@ __tegra_dvfs_set_rate(struct dvfs *d, unsigned long rate)
return ret;
}
+static inline int dvfs_alt_freqs_set(struct dvfs *d, bool enable)
+{
+ if (d->alt_freqs_state == ALT_FREQS_NOT_SUPPORTED)
+ return -ENOSYS;
+
+ d->alt_freqs_state = enable ? ALT_FREQS_ENABLED : ALT_FREQS_DISABLED;
+ return 0;
+}
+
+int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable)
+{
+ int ret;
+ enum dvfs_alt_freqs old_state;
+
+ mutex_lock(&dvfs_lock);
+
+ old_state = d->alt_freqs_state;
+ ret = dvfs_alt_freqs_set(d, enable);
+ if (!ret && (old_state != d->alt_freqs_state))
+ ret = __tegra_dvfs_set_rate(d, d->cur_rate);
+
+ mutex_unlock(&dvfs_lock);
+ return ret;
+}
+
int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate)
{
int i;
@@ -370,6 +402,14 @@ int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate)
if (!c->dvfs->millivolts)
return -ENODEV;
+ /*
+ * Predicted voltage can not be used across the switch to alternative
+ * frequency limits. For now, just fail the call for clock that has
+ * alternative limits initialized.
+ */
+ if (c->dvfs->alt_freqs_state != ALT_FREQS_NOT_SUPPORTED)
+ return -ENOSYS;
+
for (i = 0; i < c->dvfs->num_freqs; i++) {
if (rate <= c->dvfs->freqs[i])
break;
diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h
index 462eef645a4f..f7e863f14f39 100644
--- a/arch/arm/mach-tegra/dvfs.h
+++ b/arch/arm/mach-tegra/dvfs.h
@@ -73,6 +73,12 @@ struct dvfs_rail {
struct rail_stats stats;
};
+enum dvfs_alt_freqs {
+ ALT_FREQS_NOT_SUPPORTED = 0,
+ ALT_FREQS_DISABLED,
+ ALT_FREQS_ENABLED,
+};
+
struct dvfs {
/* Used only by tegra2_clock.c */
const char *clk_name;
@@ -82,9 +88,11 @@ struct dvfs {
/* Must be initialized before tegra_dvfs_init */
int freqs_mult;
unsigned long freqs[MAX_DVFS_FREQS];
+ unsigned long alt_freqs[MAX_DVFS_FREQS];
const int *millivolts;
struct dvfs_rail *dvfs_rail;
bool auto_dvfs;
+ enum dvfs_alt_freqs alt_freqs_state;
/* Filled in by tegra_dvfs_init */
int max_millivolts;
@@ -116,6 +124,7 @@ struct dvfs_rail *tegra_dvfs_get_rail_by_name(const char *reg_id);
int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate);
void tegra_dvfs_core_cap_enable(bool enable);
void tegra_dvfs_core_cap_level_set(int level);
+int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable);
#else
static inline void tegra_soc_init_dvfs(void)
{}
@@ -150,6 +159,8 @@ static inline void tegra_dvfs_core_cap_enable(bool enable)
{}
static inline void tegra_dvfs_core_cap_level_set(int level)
{}
+static inline int tegra_dvfs_alt_freqs_set(struct dvfs *d, bool enable)
+{ return 0; }
#endif
#ifndef CONFIG_ARCH_TEGRA_2x_SOC