diff options
author | Taras Kondratiuk <taras@ti.com> | 2012-08-01 20:51:33 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-08-01 20:51:33 +0800 |
commit | 0b8ff05e6f463c728cdd91fed0a15d4344a6ecb3 (patch) | |
tree | b40528cb569ddf7d0ad3eb76156cf6ad8febf8b7 | |
parent | 7c3f9ba7e014b5020af21f96cebbb15f0c78f56b (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.c | 53 |
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; |