summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGirish S Ghongdemath <girishsg@ti.com>2012-08-01 20:51:04 +0800
committerAndy Green <andy.green@linaro.org>2012-08-01 20:51:04 +0800
commit7c3f9ba7e014b5020af21f96cebbb15f0c78f56b (patch)
treee47b61933a2120dd785d72df1dba670c1864d48c
parentdef45c57a611be107610a9f6d6d436b4414b6c9b (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.c81
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) {