All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 0/8] PM / OPP: Multiple regulator support
@ 2016-10-20  8:44 Viresh Kumar
  2016-10-20  8:44 ` [PATCH V2 1/8] PM / OPP: Reword binding supporting multiple regulators per device Viresh Kumar
                   ` (8 more replies)
  0 siblings, 9 replies; 35+ messages in thread
From: Viresh Kumar @ 2016-10-20  8:44 UTC (permalink / raw)
  To: Rafael Wysocki, nm, sboyd
  Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
	d-gerlach, broonie, Viresh Kumar

Hi,

Some platforms (like TI) have complex DVFS configuration for CPU
devices, where multiple regulators are required to be configured to
change DVFS state of the device. This was explained well by Nishanth
earlier [1].

Some thoughts went into it few months back but then it all got lost. I
am trying to get that back on track with this thread.

One of the major complaints around multiple regulators case was that the
DT isn't responsible in any way to represent the ordering in which
multiple supplies need to be programmed, before or after frequency
change. It was considered in this patch and such information is left to
the platform specific OPP driver now, which can register its own
opp_set_rate() callback with the OPP core and the OPP core will then
call it during DVFS.

The patches are tested on Exynos5250 (Dual A15). I have hacked around DT
and code to pass values for multiple regulators and verified that they
are all properly read by the kernel (using debugfs interface).

Though more testing on real (TI) platforms would be useful.

This is rebased over: linux-next branch in the PM tree.

V1->V2:
- Ack from Rob for 1st patch
- Moved the supplies structure to pm_opp.h (Dave)
- Fixed an compilation warning.

--
viresh

[1] https://marc.info/?l=linux-pm&m=145684495832764&w=2

Viresh Kumar (8):
  PM / OPP: Reword binding supporting multiple regulators per device
  PM / OPP: Don't use OPP structure outside of rcu protected section
  PM / OPP: Manage supply's voltage/current in a separate structure
  PM / OPP: Pass struct dev_pm_opp_supply to _set_opp_voltage()
  PM / OPP: Add infrastructure to manage multiple regulators
  PM / OPP: Separate out _generic_opp_set_rate()
  PM / OPP: Allow platform specific custom opp_set_rate() callbacks
  PM / OPP: Don't WARN on multiple calls to dev_pm_opp_set_regulators()

 Documentation/devicetree/bindings/opp/opp.txt |  25 +-
 drivers/base/power/opp/core.c                 | 501 ++++++++++++++++++++------
 drivers/base/power/opp/debugfs.c              |  48 ++-
 drivers/base/power/opp/of.c                   | 104 ++++--
 drivers/base/power/opp/opp.h                  |  20 +-
 drivers/cpufreq/cpufreq-dt.c                  |   9 +-
 include/linux/pm_opp.h                        |  49 ++-
 7 files changed, 574 insertions(+), 182 deletions(-)

-- 
2.7.1.410.g6faf27b

^ permalink raw reply	[flat|nested] 35+ messages in thread
* [PATCH 7/8] PM / OPP: Allow platform specific custom opp_set_rate() callbacks
@ 2016-10-04 11:56 Viresh Kumar
  2016-10-12  2:10 ` [PATCH V2 " Viresh Kumar
  0 siblings, 1 reply; 35+ messages in thread
From: Viresh Kumar @ 2016-10-04 11:56 UTC (permalink / raw)
  To: Rafael Wysocki, nm, sboyd, Viresh Kumar
  Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
	d-gerlach, broonie, Viresh Kumar

The generic opp_set_rate() handler isn't sufficient for platforms with
complex DVFS.  For example, some TI platforms have multiple regulators
for a CPU device. The order in which various supplies need to be
programmed is only known to the platform code and its best to leave it
to it.

This patch implements APIs to register platform specific opp_set_rate()
callback.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/base/power/opp/core.c | 114 +++++++++++++++++++++++++++++++++++++++++-
 drivers/base/power/opp/opp.h  |   1 +
 include/linux/pm_opp.h        |  10 ++++
 3 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 96f04392daef..f7c4ef194aac 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -677,6 +677,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 {
 	struct opp_table *opp_table;
 	unsigned long freq, old_freq;
+	int (*set_rate)(struct device *dev, struct dev_pm_set_rate_data *data);
 	struct dev_pm_opp *old_opp, *opp;
 	struct regulator **regulators;
 	struct dev_pm_set_rate_data *data;
@@ -738,6 +739,11 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 		return _generic_opp_set_rate_clk_only(dev, clk, old_freq, freq);
 	}
 
+	if (opp_table->set_rate)
+		set_rate = opp_table->set_rate;
+	else
+		set_rate = _generic_opp_set_rate;
+
 	data = opp_table->set_rate_data;
 	data->regulators = regulators;
 	data->regulator_count = opp_table->regulator_count;
@@ -755,7 +761,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 
 	rcu_read_unlock();
 
-	return _generic_opp_set_rate(dev, data);
+	return set_rate(dev, data);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
 
@@ -889,6 +895,9 @@ static void _remove_opp_table(struct opp_table *opp_table)
 	if (opp_table->regulators)
 		return;
 
+	if (opp_table->set_rate)
+		return;
+
 	/* Release clk */
 	if (!IS_ERR(opp_table->clk))
 		clk_put(opp_table->clk);
@@ -1562,6 +1571,109 @@ void dev_pm_opp_put_regulators(struct device *dev)
 EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
 
 /**
+ * dev_pm_opp_register_set_rate_helper() - Register custom OPP set rate helper
+ * @dev: Device for which the helper is getting registered.
+ * @set_rate: Custom OPP set rate helper.
+ *
+ * This is useful to support complex platforms (like platforms with multiple
+ * regulators per device), instead of the generic OPP set rate helper.
+ *
+ * This must be called before any OPPs are initialized for the device.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int dev_pm_opp_register_set_rate_helper(struct device *dev,
+	int (*set_rate)(struct device *dev, struct dev_pm_set_rate_data *data))
+{
+	struct opp_table *opp_table;
+	int ret;
+
+	if (!set_rate)
+		return -EINVAL;
+
+	mutex_lock(&opp_table_lock);
+
+	opp_table = _add_opp_table(dev);
+	if (!opp_table) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	/* This should be called before OPPs are initialized */
+	if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+		ret = -EBUSY;
+		goto err;
+	}
+
+	/* Already have custom set_rate helper */
+	if (WARN_ON(opp_table->set_rate)) {
+		ret = -EBUSY;
+		goto err;
+	}
+
+	opp_table->set_rate = set_rate;
+
+	mutex_unlock(&opp_table_lock);
+	return 0;
+
+err:
+	_remove_opp_table(opp_table);
+unlock:
+	mutex_unlock(&opp_table_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_rate_helper);
+
+/**
+ * dev_pm_opp_register_put_rate_helper() - Releases resources blocked for
+ *					   set_rate helper
+ * @dev: Device for which custom set_rate helper has to be cleared.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+void dev_pm_opp_register_put_rate_helper(struct device *dev)
+{
+	struct opp_table *opp_table;
+
+	mutex_lock(&opp_table_lock);
+
+	/* Check for existing table for 'dev' first */
+	opp_table = _find_opp_table(dev);
+	if (IS_ERR(opp_table)) {
+		dev_err(dev, "Failed to find opp_table: %ld\n",
+			PTR_ERR(opp_table));
+		goto unlock;
+	}
+
+	if (!opp_table->set_rate) {
+		dev_err(dev, "%s: Doesn't have custom set_rate helper set\n",
+			__func__);
+		goto unlock;
+	}
+
+	/* Make sure there are no concurrent readers while updating opp_table */
+	WARN_ON(!list_empty(&opp_table->opp_list));
+
+	opp_table->set_rate = NULL;
+
+	/* Try freeing opp_table if this was the last blocking resource */
+	_remove_opp_table(opp_table);
+
+unlock:
+	mutex_unlock(&opp_table_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_rate_helper);
+
+/**
  * dev_pm_opp_add()  - Add an OPP table from a table definitions
  * @dev:	device for which we do this operation
  * @freq:	Frequency in Hz for this OPP
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 28011d6da345..38d97a59d762 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -194,6 +194,7 @@ struct opp_table {
 	struct regulator **regulators;
 	unsigned int regulator_count;
 
+	int (*set_rate)(struct device *dev, struct dev_pm_set_rate_data *data);
 	struct dev_pm_set_rate_data *set_rate_data;
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 630f0fd6065c..ef882ed24b0e 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -79,6 +79,8 @@ int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
 void dev_pm_opp_put_prop_name(struct device *dev);
 int dev_pm_opp_set_regulators(struct device *dev, const char *names[], unsigned int count);
 void dev_pm_opp_put_regulators(struct device *dev);
+int dev_pm_opp_register_set_rate_helper(struct device *dev, int (*set_rate)(struct device *dev, struct dev_pm_set_rate_data *data));
+void dev_pm_opp_register_put_rate_helper(struct device *dev);
 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
 int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
 int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
@@ -178,6 +180,14 @@ static inline int dev_pm_opp_set_supported_hw(struct device *dev,
 
 static inline void dev_pm_opp_put_supported_hw(struct device *dev) {}
 
+int dev_pm_opp_register_set_rate_helper(struct device *dev,
+	int (*set_rate)(struct device *dev, struct dev_pm_set_rate_data *data))
+{
+	return -ENOTSUPP;
+}
+
+static inline void dev_pm_opp_register_put_rate_helper(struct device *dev) {}
+
 static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
 {
 	return -ENOTSUPP;
-- 
2.7.1.410.g6faf27b

^ permalink raw reply related	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2016-11-10  1:37 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-20  8:44 [PATCH V2 0/8] PM / OPP: Multiple regulator support Viresh Kumar
2016-10-20  8:44 ` [PATCH V2 1/8] PM / OPP: Reword binding supporting multiple regulators per device Viresh Kumar
2016-10-24 22:48   ` Stephen Boyd
2016-10-24 22:48     ` Stephen Boyd
2016-10-20  8:44 ` [PATCH V2 2/8] PM / OPP: Don't use OPP structure outside of rcu protected section Viresh Kumar
2016-10-24 22:52   ` Stephen Boyd
2016-10-25  3:37     ` Viresh Kumar
2016-10-20  8:44 ` [PATCH V2 3/8] PM / OPP: Manage supply's voltage/current in a separate structure Viresh Kumar
2016-10-20  8:44 ` [PATCH V2 4/8] PM / OPP: Pass struct dev_pm_opp_supply to _set_opp_voltage() Viresh Kumar
2016-10-24 23:14   ` Stephen Boyd
2016-10-25  3:45     ` Viresh Kumar
2016-10-25 20:26       ` Stephen Boyd
2016-10-26  3:34         ` Viresh Kumar
2016-10-20  8:44 ` [PATCH V2 5/8] PM / OPP: Add infrastructure to manage multiple regulators Viresh Kumar
2016-10-21 22:32   ` Dave Gerlach
2016-10-21 22:32     ` Dave Gerlach
2016-10-24  3:35     ` Viresh Kumar
2016-10-25 16:49   ` Stephen Boyd
2016-10-26  6:05     ` Viresh Kumar
2016-11-10  1:37       ` Stephen Boyd
2016-10-20  8:45 ` [PATCH V2 6/8] PM / OPP: Separate out _generic_opp_set_rate() Viresh Kumar
2016-10-25 18:59   ` Stephen Boyd
2016-10-26  6:07     ` Viresh Kumar
2016-10-20  8:45 ` [PATCH V2 7/8] PM / OPP: Allow platform specific custom opp_set_rate() callbacks Viresh Kumar
2016-10-25 19:01   ` Stephen Boyd
2016-10-26  6:07     ` Viresh Kumar
2016-10-20  8:45 ` [PATCH V2 8/8] PM / OPP: Don't WARN on multiple calls to dev_pm_opp_set_regulators() Viresh Kumar
2016-10-25 19:01   ` Stephen Boyd
2016-10-21 13:39 ` [PATCH V2 0/8] PM / OPP: Multiple regulator support Rafael J. Wysocki
2016-10-21 15:40   ` Viresh Kumar
2016-10-24  1:08     ` Dave Gerlach
2016-10-24  4:26       ` Viresh Kumar
2016-10-25 21:13         ` Dave Gerlach
2016-10-26  3:21           ` Viresh Kumar
  -- strict thread matches above, loose matches on Subject: below --
2016-10-04 11:56 [PATCH 7/8] PM / OPP: Allow platform specific custom opp_set_rate() callbacks Viresh Kumar
2016-10-12  2:10 ` [PATCH V2 " Viresh Kumar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.