diff options
author | Girish S Ghongdemath <girishsg@ti.com> | 2012-08-01 20:51:04 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-08-01 20:51:04 +0800 |
commit | 7c3f9ba7e014b5020af21f96cebbb15f0c78f56b (patch) | |
tree | e47b61933a2120dd785d72df1dba670c1864d48c | |
parent | def45c57a611be107610a9f6d6d436b4414b6c9b (diff) |
OMAP4: DVFS: Scale freq when dependent volt is scaled
Add support to scale frequency when _dependent_ voltage is scaled for
that particular OPP.
If there is a volt domain dependency between two device then device scale should
take care of scaling voltage and its freq together. For example, MPU has
dependency on CORE. Which implies, if MPU runs above OPP50 than CORE should be
at OPP100. This dependency was only restricted to voltage in the current framework.
However, we need to consider its corresponding frequency as well. Because, the
dependency is just not on the voltage but its on the device _OPP_. Which is a tuple
of Volt and Freq.
This patch also takes care of scaling vdd frequency appropriatley when devices within
that vdd domain request for that particular OPP. For example, if SGX does a device
scale for OPP100 then CORE vdd's voltage and frequency is scaled to OPP100 as well.
Below short log on how dvfs/core/info looks like when system is loaded:
|- voltage requests
| |
| |-962000: aess:aess
| |-1127000: platform:mpu.0
| |-1250000: pvrsrvkm:pvrsrvkm.0
| X
|
|- frequency requests
| |
| |- platform:l3_main_1.0
| | |-100000000: aess:aess
| | |-200000000: platform:mpu.0
| | |-200000000: pvrsrvkm:pvrsrvkm.0
| | X
| |- pvrsrvkm:pvrsrvkm.0
| | |-384000000: pvrsrvkm:pvrsrvkm.0
| | X
Below log on dvfs/core/info when system is unloaded idle usecase:
|- voltage requests
| |
| |-962000: platform:mpu.0
| |-962000: pvrsrvkm:pvrsrvkm.0
| |-962000: aess:aess
| X
|
|- frequency requests
| |
| |- platform:l3_main_1.0
| | |-100000000: platform:mpu.0
| | |-100000000: pvrsrvkm:pvrsrvkm.0
| | |-100000000: aess:aess
| | X
| |- pvrsrvkm:pvrsrvkm.0
| | |-153600000: pvrsrvkm:pvrsrvkm.0
| X
Change-Id: I7bb8396f4b353b41260ffe1ea63268c10d9bd123
Signed-off-by: Girish S G <girishsg@ti.com>
Conflicts:
arch/arm/mach-omap2/dvfs.c
Signed-off-by: Sebastien Jan <s-jan@ti.com>
-rw-r--r-- | arch/arm/mach-omap2/dvfs.c | 81 |
1 files changed, 72 insertions, 9 deletions
diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c index d5d3e2a8fa3..44642507eb4 100644 --- a/arch/arm/mach-omap2/dvfs.c +++ b/arch/arm/mach-omap2/dvfs.c @@ -66,15 +66,17 @@ * needs to be scaled to. This API then internally finds out the voltage * domain to which the device belongs to and the voltage to which the voltage * domain needs to be put to for the device to be scaled to the new frequency - * from he device opp table. Then this API will add requested frequency into + * from the device opp table. Then this API will add requested frequency into * the corresponding target device frequency list and add voltage request to * the corresponding vdd. Subsequently it calls voltage scale function which * will find out the highest requested voltage for the given vdd and scales - * the voltage to the required one. It also runs through the list of all + * the voltage to the required one and also adds corresponding frequency + * request for that voltage. It also runs through the list of all * scalable devices belonging to this voltage domain and scale them to the * appropriate frequencies using the set_rate pointer in the device opp * tables. - * 6. Handle inter VDD dependecies. + * 6. Handle inter VDD dependecies. This will take care of scaling domain's voltage + * and frequency together. * * * DOC: The Core DVFS data structure: @@ -534,8 +536,11 @@ static int _dep_scan_table(struct device *dev, struct omap_vdd_dep_info *dep_info, unsigned long main_volt) { struct omap_vdd_dep_volt *dep_table = dep_info->dep_table; - int i; - unsigned long dep_volt = 0; + struct device *target_dev; + struct omap_vdd_dvfs_info *tdvfs_info; + struct opp *opp; + int i, ret; + unsigned long dep_volt = 0, new_freq = 0; if (!dep_table) { dev_err(dev, "%s: deptable not present for vdd%s\n", @@ -567,12 +572,43 @@ static int _dep_scan_table(struct device *dev, } /* See if dep_volt is possible for the vdd*/ - i = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm), + ret = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm), dev, dep_volt); - if (i) + if (ret) dev_err(dev, "%s: Failed to add dep to domain %s volt=%ld\n", __func__, dep_info->name, dep_volt); - return i; + + /* 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", + __func__); + return -ENODEV; + } + target_dev = _dvfs_info_to_dev(tdvfs_info); + if (!target_dev) { + dev_warn(dev, "%s: no target_dev\n", + __func__); + return -ENODEV; + } + + rcu_read_lock(); + opp = _volt_to_opp(target_dev, dep_volt); + if (!IS_ERR(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; + } + } + + return ret; } /** @@ -832,10 +868,11 @@ int omap_device_scale(struct device *req_dev, struct device *target_dev, unsigned long rate) { struct opp *opp; - unsigned long volt, freq = rate; + unsigned long volt, freq = rate, new_freq = 0; struct omap_vdd_dvfs_info *tdvfs_info; struct platform_device *p_dev; struct omap_device *od; + struct device *dev; int ret = 0; p_dev = container_of(target_dev, struct platform_device, dev); @@ -906,6 +943,32 @@ int omap_device_scale(struct device *req_dev, struct device *target_dev, goto out; } + dev = _dvfs_info_to_dev(tdvfs_info); + if (!dev) { + dev_warn(dev, "%s: no target_dev\n", + __func__); + ret = -ENODEV; + goto out; + } + + if (dev != target_dev) { + rcu_read_lock(); + opp = _volt_to_opp(dev, volt); + if (!IS_ERR(opp)) + new_freq = opp_get_freq(opp); + rcu_read_unlock(); + if (new_freq) { + ret = _add_freq_request(tdvfs_info, req_dev, dev, + new_freq); + if (ret) { + dev_err(target_dev, "%s: freqadd(%s) failed %d" + "[f=%ld, v=%ld]\n", __func__, + dev_name(req_dev), ret, freq, volt); + goto out; + } + } + } + /* Do the actual scaling */ ret = _dvfs_scale(req_dev, target_dev, tdvfs_info); if (ret) { |