summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNishanth Menon <nm@ti.com>2012-08-01 20:53:32 +0800
committerAndy Green <andy.green@linaro.org>2012-08-01 20:53:32 +0800
commitcd5d320333bbe7742e2196df5b896ec9931b031f (patch)
tree574de3a87c604b4fcea9c90702b7e66905c06d43
parent54c74ae99930268f90d8e4b20147133337229741 (diff)
OMAP3+: PM: DVFS: decide to scale dependent domains based on nominal voltage
Current DVFS scale decision assumes voltage dependency - hence the scale decision is implemented based on voltage transition decision. This is wrong as the dependency between domains is at OPP tuple level, so no matter what the voltage level is, if we transition from a lower frequency to a higher frequency, we should scale dependent domain ahead of transitioning voltage/frequency for the current domain, and viceversa when switching to lower OPP. With Smartreflex AVS Class3 or Smartreflex AVS Class1.5, consider the following Scenario: The current OPP might be in Vnom (Vn) - if SR is disabled OR if SR has not yet made the first adjustment Vcurrent(Vc) - which can either be: Vsr_intermdiate(Vi) - if SR was interrupted in the middle of convergence Vsr(Vs) - if SR has completed adjustment. For all purposes Current OPP's Vn > Vc. However, when we consider the new OPP we are entering (assume for SR1.5, new OPP is not a calibrated opp in this discussion): Going down, we have the following cases: Case a) current_Vn > current_Vc > new_Vn Case b) current_Vn > new_Vn > current_Vc Going up, we could have: Case c) new_Vn > current_Vn > current_Vc OR we might even have a scenario case d) current_Vn > (current_Vc == new_Vn) Today's code compares current_Vc against new_Vn, and makes a decision when to scale dependent domain. This will work find in case (a) and case (c). However, in case (b), we scale dependent domain at the wrong time, in case of case (d), we dont even attempt to scale dependent domains!! This is wrong. since the comparable factor which closely represents the order of OPP is Vnom, the right thing to check for scaling dependent domains is Vnom. Hence use it instead. Change-Id: I93868743301e115fab8e33ff14317b07b81ef5d8 Signed-off-by: Nishanth Menon <nm@ti.com>
-rw-r--r--arch/arm/mach-omap2/dvfs.c19
-rw-r--r--arch/arm/mach-omap2/voltage.h7
2 files changed, 21 insertions, 5 deletions
diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c
index 5e9bd7bcf21..8dab888ff1b 100644
--- a/arch/arm/mach-omap2/dvfs.c
+++ b/arch/arm/mach-omap2/dvfs.c
@@ -783,10 +783,9 @@ static int _dvfs_scale(struct device *req_dev, struct device *target_dev,
if (!curr_volt)
curr_volt = omap_get_operation_voltage(curr_vdata);
- if (curr_volt == new_volt) {
- volt_scale_dir = DVFS_VOLT_SCALE_NONE;
- } else if (curr_volt < new_volt) {
-
+ /* Make a decision to scale dependent domain based on nominal voltage */
+ if (omap_get_nominal_voltage(new_vdata) >
+ omap_get_nominal_voltage(curr_vdata)) {
ret = _dep_scale_domains(target_dev, vdd);
if (ret) {
dev_err(target_dev,
@@ -794,7 +793,13 @@ static int _dvfs_scale(struct device *req_dev, struct device *target_dev,
__func__, ret, new_volt);
goto fail;
}
+ }
+ /* Now decide on switching OPP */
+
+ if (curr_volt == new_volt) {
+ volt_scale_dir = DVFS_VOLT_SCALE_NONE;
+ } else if (curr_volt < new_volt) {
ret = voltdm_scale(voltdm, new_vdata);
if (ret) {
dev_err(target_dev,
@@ -851,8 +856,12 @@ static int _dvfs_scale(struct device *req_dev, struct device *target_dev,
if (ret)
goto fail;
- if (DVFS_VOLT_SCALE_DOWN == volt_scale_dir) {
+ if (DVFS_VOLT_SCALE_DOWN == volt_scale_dir)
voltdm_scale(voltdm, new_vdata);
+
+ /* Make a decision to scale dependent domain based on nominal voltage */
+ if (omap_get_nominal_voltage(new_vdata) <
+ omap_get_nominal_voltage(curr_vdata)) {
_dep_scale_domains(target_dev, vdd);
}
diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h
index dc87b6de2e4..a93636420e4 100644
--- a/arch/arm/mach-omap2/voltage.h
+++ b/arch/arm/mach-omap2/voltage.h
@@ -331,6 +331,13 @@ static inline unsigned long omap_get_dyn_nominal(struct omap_volt_data *vdata)
}
return vdata->volt_nominal;
}
+static inline unsigned long omap_get_nominal_voltage(
+ struct omap_volt_data *vdata)
+{
+ if (IS_ERR_OR_NULL(vdata))
+ return 0;
+ return vdata->volt_nominal;
+}
static inline int voltdm_register_notifier(struct voltagedomain *voltdm,
struct notifier_block *nb)