summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaras Kondratiuk <taras@ti.com>2012-08-01 20:51:33 +0800
committerAndy Green <andy.green@linaro.org>2012-08-01 20:51:33 +0800
commit0b8ff05e6f463c728cdd91fed0a15d4344a6ecb3 (patch)
treeb40528cb569ddf7d0ad3eb76156cf6ad8febf8b7
parent7c3f9ba7e014b5020af21f96cebbb15f0c78f56b (diff)
OMAP3+: PM: DVFS: Scale dependent domains to existing OPP
Currently dependent domain is scaled to: - dependent voltage that is got from voltage dependency table. - frequency that is got from OPP found for dependent voltage. OPP for dependent voltage is found by _volt_to_opp() function which looks for OPP with equal or _greater_ voltage. So if there is no OPP with exact voltage (or this OPP is disabled), then frequency from OPP with higher voltage will be used. As a result device will run at not supported combination of frequency and voltage. This may lead to instabilities. This patch scales dependent domain to a correct voltage-frequency tuple, by using both frequency and voltage from the matched OPP. Change-Id: Ieb14be32ce2f6f2971ca0530dd077bb445a7e2f7 Signed-off-by: Taras Kondratiuk <taras@ti.com>
-rw-r--r--arch/arm/mach-omap2/dvfs.c53
1 files changed, 34 insertions, 19 deletions
diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c
index 44642507eb4..63cb025a441 100644
--- a/arch/arm/mach-omap2/dvfs.c
+++ b/arch/arm/mach-omap2/dvfs.c
@@ -528,7 +528,7 @@ static int _remove_freq_request(struct omap_vdd_dvfs_info *dvfs_info,
*
* This runs down the table provided to find the match for main_volt
* provided and sets up a scale request for the dependent domain
- * for the dependent voltage.
+ * for the dependent OPP.
*
* Returns 0 if all went well.
*/
@@ -540,7 +540,7 @@ static int _dep_scan_table(struct device *dev,
struct omap_vdd_dvfs_info *tdvfs_info;
struct opp *opp;
int i, ret;
- unsigned long dep_volt = 0, new_freq = 0;
+ unsigned long dep_volt = 0, new_dep_volt = 0, new_freq = 0;
if (!dep_table) {
dev_err(dev, "%s: deptable not present for vdd%s\n",
@@ -571,14 +571,6 @@ static int _dep_scan_table(struct device *dev,
}
}
- /* See if dep_volt is possible for the vdd*/
- ret = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm),
- dev, dep_volt);
- if (ret)
- dev_err(dev, "%s: Failed to add dep to domain %s volt=%ld\n",
- __func__, dep_info->name, dep_volt);
-
- /* And also add corresponding freq request */
tdvfs_info = _voltdm_to_dvfs_info(dep_info->_dep_voltdm);
if (!tdvfs_info) {
dev_warn(dev, "%s: no dvfs_info\n",
@@ -594,18 +586,41 @@ static int _dep_scan_table(struct device *dev,
rcu_read_lock();
opp = _volt_to_opp(target_dev, dep_volt);
- if (!IS_ERR(opp))
+ if (!IS_ERR(opp)) {
+ new_dep_volt = opp_get_voltage(opp);
new_freq = opp_get_freq(opp);
+ }
rcu_read_unlock();
- if (new_freq) {
- ret = _add_freq_request(tdvfs_info, dev, target_dev, new_freq);
- if (ret) {
- dev_err(target_dev, "%s: freqadd(%s) failed %d[f=%ld,"
- "v=%ld]\n", __func__, dev_name(dev),
- i, new_freq, dep_volt);
- return ret;
- }
+ if (!new_dep_volt || !new_freq) {
+ dev_err(target_dev, "%s: no valid OPP for voltage %lu\n",
+ __func__, dep_volt);
+ return -ENODATA;
+ }
+
+ /* TODO: In case of _add_vdd_user() failure
+ * _dep_scan_table() will end up with previous voltage request,
+ * but without a frequency request.
+ * System should be left in previous state in case of failure.
+ * Same issue is present in omap_device_scale() function.
+ */
+ ret = _add_freq_request(tdvfs_info, dev, target_dev, new_freq);
+ if (ret) {
+ dev_err(target_dev, "%s: freqadd(%s) failed %d"
+ "[f=%ld, v=%ld(%ld)]\n",
+ __func__, dev_name(dev), ret, new_freq,
+ new_dep_volt, dep_volt);
+ return ret;
+ }
+
+ ret = _add_vdd_user(tdvfs_info, dev, new_dep_volt);
+ if (ret) {
+ dev_err(target_dev, "%s: vddadd(%s) failed %d"
+ "[f=%ld, v=%ld(%ld)]\n",
+ __func__, dev_name(dev), ret, new_freq,
+ new_dep_volt, dep_volt);
+ _remove_freq_request(tdvfs_info, dev, target_dev);
+ return ret;
}
return ret;