aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2017-10-11 03:24:14 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-10-13 18:54:40 -0400
commit009acd196fc860045bf7b2c3f5812f0f5efb2782 (patch)
tree76f26d4863ee59701532f74d80b1807e6b9ebd0f
parent69f658e399f3d9cb9c9680afb714ba23860d7ccb (diff)
PM / OPP: Support updating performance state of device's power domain
The genpd framework now provides an API to request device's power domain to update its performance state. Use that interface from the OPP core for devices whose power domains support performance states. Note that this commit doesn't add any mechanism by which performance states are made available to the OPP core. That would be done by a later commit. Note that the current implementation is restricted to the case where the device doesn't have separate regulators for itself. We shouldn't over engineer the code before we have real use case for them. We can always come back and add more code to support such cases later on. Tested-by: Rajendra Nayak <rnayak@codeaurora.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/opp/core.c57
-rw-r--r--drivers/opp/debugfs.c3
-rw-r--r--drivers/opp/opp.h4
3 files changed, 63 insertions, 1 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 80c21207e48c..0ce8069d6843 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -19,6 +19,7 @@
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/device.h> 20#include <linux/device.h>
21#include <linux/export.h> 21#include <linux/export.h>
22#include <linux/pm_domain.h>
22#include <linux/regulator/consumer.h> 23#include <linux/regulator/consumer.h>
23 24
24#include "opp.h" 25#include "opp.h"
@@ -535,6 +536,44 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk,
535 return ret; 536 return ret;
536} 537}
537 538
539static inline int
540_generic_set_opp_domain(struct device *dev, struct clk *clk,
541 unsigned long old_freq, unsigned long freq,
542 unsigned int old_pstate, unsigned int new_pstate)
543{
544 int ret;
545
546 /* Scaling up? Scale domain performance state before frequency */
547 if (freq > old_freq) {
548 ret = dev_pm_genpd_set_performance_state(dev, new_pstate);
549 if (ret)
550 return ret;
551 }
552
553 ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
554 if (ret)
555 goto restore_domain_state;
556
557 /* Scaling down? Scale domain performance state after frequency */
558 if (freq < old_freq) {
559 ret = dev_pm_genpd_set_performance_state(dev, new_pstate);
560 if (ret)
561 goto restore_freq;
562 }
563
564 return 0;
565
566restore_freq:
567 if (_generic_set_opp_clk_only(dev, clk, freq, old_freq))
568 dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
569 __func__, old_freq);
570restore_domain_state:
571 if (freq > old_freq)
572 dev_pm_genpd_set_performance_state(dev, old_pstate);
573
574 return ret;
575}
576
538static int _generic_set_opp_regulator(const struct opp_table *opp_table, 577static int _generic_set_opp_regulator(const struct opp_table *opp_table,
539 struct device *dev, 578 struct device *dev,
540 unsigned long old_freq, 579 unsigned long old_freq,
@@ -653,7 +692,16 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
653 692
654 /* Only frequency scaling */ 693 /* Only frequency scaling */
655 if (!opp_table->regulators) { 694 if (!opp_table->regulators) {
656 ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); 695 /*
696 * We don't support devices with both regulator and
697 * domain performance-state for now.
698 */
699 if (opp_table->genpd_performance_state)
700 ret = _generic_set_opp_domain(dev, clk, old_freq, freq,
701 IS_ERR(old_opp) ? 0 : old_opp->pstate,
702 opp->pstate);
703 else
704 ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
657 } else if (!opp_table->set_opp) { 705 } else if (!opp_table->set_opp) {
658 ret = _generic_set_opp_regulator(opp_table, dev, old_freq, freq, 706 ret = _generic_set_opp_regulator(opp_table, dev, old_freq, freq,
659 IS_ERR(old_opp) ? NULL : old_opp->supplies, 707 IS_ERR(old_opp) ? NULL : old_opp->supplies,
@@ -1706,6 +1754,13 @@ void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev,
1706 if (remove_all || !opp->dynamic) 1754 if (remove_all || !opp->dynamic)
1707 dev_pm_opp_put(opp); 1755 dev_pm_opp_put(opp);
1708 } 1756 }
1757
1758 /*
1759 * The OPP table is getting removed, drop the performance state
1760 * constraints.
1761 */
1762 if (opp_table->genpd_performance_state)
1763 dev_pm_genpd_set_performance_state(dev, 0);
1709 } else { 1764 } else {
1710 _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table); 1765 _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
1711 } 1766 }
diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c
index 9318848f3c67..b03c03576a62 100644
--- a/drivers/opp/debugfs.c
+++ b/drivers/opp/debugfs.c
@@ -99,6 +99,9 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
99 if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend)) 99 if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend))
100 return -ENOMEM; 100 return -ENOMEM;
101 101
102 if (!debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate))
103 return -ENOMEM;
104
102 if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate)) 105 if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
103 return -ENOMEM; 106 return -ENOMEM;
104 107
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index 166eef990599..e8f767ab5814 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -58,6 +58,7 @@ extern struct list_head opp_tables;
58 * @dynamic: not-created from static DT entries. 58 * @dynamic: not-created from static DT entries.
59 * @turbo: true if turbo (boost) OPP 59 * @turbo: true if turbo (boost) OPP
60 * @suspend: true if suspend OPP 60 * @suspend: true if suspend OPP
61 * @pstate: Device's power domain's performance state.
61 * @rate: Frequency in hertz 62 * @rate: Frequency in hertz
62 * @supplies: Power supplies voltage/current values 63 * @supplies: Power supplies voltage/current values
63 * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's 64 * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
@@ -76,6 +77,7 @@ struct dev_pm_opp {
76 bool dynamic; 77 bool dynamic;
77 bool turbo; 78 bool turbo;
78 bool suspend; 79 bool suspend;
80 unsigned int pstate;
79 unsigned long rate; 81 unsigned long rate;
80 82
81 struct dev_pm_opp_supply *supplies; 83 struct dev_pm_opp_supply *supplies;
@@ -135,6 +137,7 @@ enum opp_table_access {
135 * @clk: Device's clock handle 137 * @clk: Device's clock handle
136 * @regulators: Supply regulators 138 * @regulators: Supply regulators
137 * @regulator_count: Number of power supply regulators 139 * @regulator_count: Number of power supply regulators
140 * @genpd_performance_state: Device's power domain support performance state.
138 * @set_opp: Platform specific set_opp callback 141 * @set_opp: Platform specific set_opp callback
139 * @set_opp_data: Data to be passed to set_opp callback 142 * @set_opp_data: Data to be passed to set_opp callback
140 * @dentry: debugfs dentry pointer of the real device directory (not links). 143 * @dentry: debugfs dentry pointer of the real device directory (not links).
@@ -170,6 +173,7 @@ struct opp_table {
170 struct clk *clk; 173 struct clk *clk;
171 struct regulator **regulators; 174 struct regulator **regulators;
172 unsigned int regulator_count; 175 unsigned int regulator_count;
176 bool genpd_performance_state;
173 177
174 int (*set_opp)(struct dev_pm_set_opp_data *data); 178 int (*set_opp)(struct dev_pm_set_opp_data *data);
175 struct dev_pm_set_opp_data *set_opp_data; 179 struct dev_pm_set_opp_data *set_opp_data;