diff mbox

[RFC,1/6] PM / Voltagedomain: Add generic clk notifier handler for regulator based dynamic voltage scaling

Message ID 1392755543-28335-2-git-send-email-nm@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nishanth Menon Feb. 18, 2014, 8:32 p.m. UTC
From: Mike Turquette <mturquette@linaro.org>

This patch provides helper functions for drivers that wish to scale
voltage through the clock rate-change notifiers. The approach taken
is that the user-driver(cpufreq/devfreq) do not care about the
details of the OPP table, nor does it care about handling the voltage
regulator directly.

By using the clk notifier flags, we are able to sequence the operations
in the right order. The current logic is heavily influenced by
implementation done in cpufreq-cpu0.

[nm@ti.com: Fixes in logic, and broken out from clk to allow building
a generic voltagedomain solution independent of cpufreq]
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
---
 drivers/power/Kconfig             |    1 +
 drivers/power/Makefile            |    1 +
 drivers/power/voltdm/Kconfig      |    7 ++
 drivers/power/voltdm/Makefile     |    2 +
 drivers/power/voltdm/core.c       |  195 +++++++++++++++++++++++++++++++++++++
 include/linux/pm_voltage_domain.h |   47 +++++++++
 6 files changed, 253 insertions(+)
 create mode 100644 drivers/power/voltdm/Kconfig
 create mode 100644 drivers/power/voltdm/Makefile
 create mode 100644 drivers/power/voltdm/core.c
 create mode 100644 include/linux/pm_voltage_domain.h

Comments

Mike Turquette Feb. 25, 2014, 5:51 a.m. UTC | #1
Quoting Nishanth Menon (2014-02-18 12:32:18)
> From: Mike Turquette <mturquette@linaro.org>
> 
> This patch provides helper functions for drivers that wish to scale
> voltage through the clock rate-change notifiers. The approach taken
> is that the user-driver(cpufreq/devfreq) do not care about the
> details of the OPP table, nor does it care about handling the voltage
> regulator directly.
> 
> By using the clk notifier flags, we are able to sequence the operations
> in the right order. The current logic is heavily influenced by
> implementation done in cpufreq-cpu0.
> 
> [nm@ti.com: Fixes in logic, and broken out from clk to allow building
> a generic voltagedomain solution independent of cpufreq]
> Signed-off-by: Nishanth Menon <nm@ti.com>
> Signed-off-by: Mike Turquette <mturquette@linaro.org>

Not-signed-off-by: Mike Turquette <mturquette@linaro.org>

I haven't reviewed this series and it is a pretty big deviation from my
original RFC. You can have authorship of the patches if you want.

I'm not sure about trying to capture the "voltdm" as a core concept. It
feels a bit unwieldy to me. I have wondered about making an abstract
"performance domain" which is the dvfs analogue to generic power
domains. This a reasonable split since gpd are good for idle power
savings (e.g. clock gate, power gate, sleep state, etc) and "perf
domains" would be good for active power savings (dvfs).

Having a generic container for performance domains might make a good
place to stuff all of this glue logic that we keep running into (e.g.
CPU and GPU max frequencies that are related), and it might make another
nice knob for the thermal folks to use.

For the case of the OMAP voltage domains, it would be a place to stuff
all of the VC/VP -> ABB -> Smart Reflex AVS stuff.

Anyways, I don't have a real proposal. I just don't want my name on
these patches since they are really yours now. I might resurrect them
some day in a different context.

Regards,
Mike
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nishanth Menon Feb. 25, 2014, 8:56 p.m. UTC | #2
Hi Mike,
On 02/24/2014 11:51 PM, Mike Turquette wrote:
> Quoting Nishanth Menon (2014-02-18 12:32:18)
>> From: Mike Turquette <mturquette@linaro.org>
>>
>> This patch provides helper functions for drivers that wish to scale
>> voltage through the clock rate-change notifiers. The approach taken
>> is that the user-driver(cpufreq/devfreq) do not care about the
>> details of the OPP table, nor does it care about handling the voltage
>> regulator directly.
>>
>> By using the clk notifier flags, we are able to sequence the operations
>> in the right order. The current logic is heavily influenced by
>> implementation done in cpufreq-cpu0.
>>
>> [nm@ti.com: Fixes in logic, and broken out from clk to allow building
>> a generic voltagedomain solution independent of cpufreq]
>> Signed-off-by: Nishanth Menon <nm@ti.com>
>> Signed-off-by: Mike Turquette <mturquette@linaro.org>
> 
> Not-signed-off-by: Mike Turquette <mturquette@linaro.org>
> 
> I haven't reviewed this series and it is a pretty big deviation from my
> original RFC. You can have authorship of the patches if you want.

Sure, I had send a private note requesting clarification about the
authorship, but I guess I can take this as the response :).

> 
> I'm not sure about trying to capture the "voltdm" as a core concept. It
> feels a bit unwieldy to me.

Considering it is a simple collation of regulators and SoC specific
"magic" which have to be operated in tandem to clock operation, Why
does it seem unwieldy? Usage of multiple voltage planes in a single
voltage domain concept does not seem unique to TI processors either:
For example, imx6q-cpufreq.c uses 3 regulators (arm, pu, soc),
s5pv210-cpufreq.c uses two regulators (vddarm, vddint), ideally OMAP
implementation would use two (vdd_mpu, vbb_mpu).

> I have wondered about making an abstract
> "performance domain" which is the dvfs analogue to generic power
> domains. This a reasonable split since gpd are good for idle power
> savings (e.g. clock gate, power gate, sleep state, etc) and "perf
> domains" would be good for active power savings (dvfs).
> 
> Having a generic container for performance domains might make a good
> place to stuff all of this glue logic that we keep running into (e.g.
> CPU and GPU max frequencies that are related), and it might make another
> nice knob for the thermal folks to use.

This sounds like one level higher abstraction that we are speaking of
here? I was'nt intending to solve the bigger picture problem here -
just an abstraction level that might allow reusablity for multiple
SoCs. In fact, having an abstraction away for voltage domain(which may
consist of multiple regulators and any SoC specific magic) purely
allows us to move towards a direction you mention here.

> 
> For the case of the OMAP voltage domains, it would be a place to stuff
> all of the VC/VP -> ABB -> Smart Reflex AVS stuff.
> 

Unfortunately, I dont completely comprehend objection we have to this
approach (other than an higher level abstraction is needed) and if we
do have an objection, what is the alternate approach should be for
representing hardware which this series attempts to present.
diff mbox

Patch

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index ba69751..5c4fe16 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -394,3 +394,4 @@  source "drivers/power/reset/Kconfig"
 endif # POWER_SUPPLY
 
 source "drivers/power/avs/Kconfig"
+source "drivers/power/voltdm/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index ee54a3e..3d47072 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -58,3 +58,4 @@  obj-$(CONFIG_POWER_AVS)		+= avs/
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_POWER_RESET)	+= reset/
+obj-$(CONFIG_VOLTAGE_DOMAIN)	+= voltdm/
diff --git a/drivers/power/voltdm/Kconfig b/drivers/power/voltdm/Kconfig
new file mode 100644
index 0000000..c5353bd
--- /dev/null
+++ b/drivers/power/voltdm/Kconfig
@@ -0,0 +1,7 @@ 
+config VOLTAGE_DOMAIN
+	bool
+	depends on COMMON_CLK && OF && PM_OPP
+	default y if COMMON_CLK
+	---help---
+	  Core voltage domain framework using common clock framework's
+	  notifier mechanism.
diff --git a/drivers/power/voltdm/Makefile b/drivers/power/voltdm/Makefile
new file mode 100644
index 0000000..3fa4408
--- /dev/null
+++ b/drivers/power/voltdm/Makefile
@@ -0,0 +1,2 @@ 
+# Generic voltage domain
+obj-$(CONFIG_VOLTAGE_DOMAIN)	+= core.o
diff --git a/drivers/power/voltdm/core.c b/drivers/power/voltdm/core.c
new file mode 100644
index 0000000..d0ed27e
--- /dev/null
+++ b/drivers/power/voltdm/core.c
@@ -0,0 +1,195 @@ 
+/*
+ * Copyright (C) 2013 Linaro Ltd <mturquette@linaro.org>
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Helper functions for registering clock rate-change notifier handlers
+ * that scale voltage when a clock changes its output frequency.
+ */
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_voltage_domain.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+/**
+ * struct volt_scale_data - Internal structure to maintain notifier information
+ * @dev:	device on behalf of which we register the notifier
+ * @clk:	clk on which we registered the notifier
+ * @reg:	regulator if any which is used for scaling voltage
+ * @tol:	voltage tolerance in %
+ * @nb:		notifier block pointer
+ */
+struct volt_scale_data {
+	struct device *dev;
+	struct clk *clk;
+	struct regulator *reg;
+	int tol;
+	struct notifier_block nb;
+};
+
+#define to_volt_scale_data(_nb) container_of(_nb, \
+		struct volt_scale_data, nb)
+
+static int clk_volt_notifier_handler(struct notifier_block *nb,
+				     unsigned long flags, void *data)
+{
+	struct clk_notifier_data *cnd = data;
+	struct volt_scale_data *vsd = to_volt_scale_data(nb);
+	int ret, volt, tol;
+	struct dev_pm_opp *opp;
+	unsigned long old_rate = cnd->old_rate;
+	unsigned long new_rate = cnd->new_rate;
+
+	if ((new_rate < old_rate && flags == PRE_RATE_CHANGE) ||
+	    (new_rate > old_rate && flags == POST_RATE_CHANGE))
+		return NOTIFY_OK;
+
+	rcu_read_lock();
+	if (flags != ABORT_RATE_CHANGE)
+		opp = dev_pm_opp_find_freq_ceil(vsd->dev, &new_rate);
+	else
+		opp = dev_pm_opp_find_freq_ceil(vsd->dev, &old_rate);
+	if (IS_ERR(opp)) {
+		rcu_read_unlock();
+		dev_err(vsd->dev, "%s: Failed to find OPP for %lu\n",
+			__func__, new_rate);
+		return notifier_from_errno(PTR_ERR(opp));
+	}
+
+	volt = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	tol = volt * vsd->tol / 100;
+
+	dev_dbg(vsd->dev, "%s: %lu -> %lu, V=%d, tol=%d, clk_flag=%lu\n",
+		__func__, old_rate, new_rate, volt, tol, flags);
+
+	ret = regulator_set_voltage_tol(vsd->reg, volt, tol);
+	if (ret) {
+		dev_err(vsd->dev,
+			"%s: Failed to scale voltage(%u): %d\n", __func__,
+			volt, ret);
+		return notifier_from_errno(ret);
+	}
+
+	return NOTIFY_OK;
+}
+
+/**
+ * of_pm_voltdm_notifier_register() - register voltage domain notifier
+ * @dev:	device for which to register notifier for
+ * @np:		node pointer of the device for which we register
+ * @clk:	clk pointer around which the notifier is expected to trigger
+ * @supply:	default regulator supply name(regulator id string)
+ * @voltage_latency:	returns the latency for the voltage domain
+ *
+ * Return: notifier block which is registered with the common clock framework's
+ * notifier for the clk node requested.
+ */
+struct notifier_block *of_pm_voltdm_notifier_register(struct device *dev,
+						      struct device_node *np,
+						      struct clk *clk,
+						      const char *supply,
+						      int *voltage_latency)
+{
+	struct volt_scale_data *vsd;
+	struct dev_pm_opp *opp;
+	unsigned long min, max, freq;
+	int ret;
+
+	vsd = kzalloc(sizeof(*vsd), GFP_KERNEL);
+	if (!vsd)
+		return ERR_PTR(-ENOMEM);
+
+	vsd->dev = dev;
+	vsd->clk = clk;
+	vsd->nb.notifier_call = clk_volt_notifier_handler;
+	vsd->reg = regulator_get_optional(dev, supply);
+	ret = 0;
+	if (IS_ERR(vsd->reg))
+		ret = PTR_ERR(vsd->reg);
+	/* regulator is not mandatory */
+	if (ret != -EPROBE_DEFER) {
+		dev_warn(dev, "%s: Failed to get %s regulator:%d\n",
+			 __func__, supply, ret);
+		ret = 0;
+		goto err_free_vsd;
+	}
+	/* For devices that are not ready.... */
+	if (ret)
+		goto err_free_vsd;
+
+	rcu_read_lock();
+	freq = 0;
+	opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+	if (IS_ERR(opp))
+		goto err_bad_opp;
+	min = dev_pm_opp_get_voltage(opp);
+
+	freq = ULONG_MAX;
+	opp = dev_pm_opp_find_freq_floor(dev, &freq);
+	if (IS_ERR(opp))
+		goto err_bad_opp;
+	max = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	*voltage_latency = regulator_set_voltage_time(vsd->reg, min, max);
+	if (*voltage_latency < 0) {
+		dev_warn(dev,
+			 "%s: Fail calculating voltage latency[%ld<->%ld]:%d\n",
+			 __func__, min, max, *voltage_latency);
+	}
+
+	of_property_read_u32(np, "voltage-tolerance", &vsd->tol);
+
+	ret = clk_notifier_register(clk, &vsd->nb);
+
+	if (ret) {
+		dev_err(dev, "%s: Failed to Register Notifier, %d\n", __func__,
+			ret);
+		goto err_free_reg;
+	}
+
+	return &vsd->nb;
+
+err_bad_opp:
+	rcu_read_unlock();
+	ret = PTR_ERR(opp);
+	dev_err(dev, "%s: failed to get OPP, %d\n", __func__, ret);
+
+err_free_reg:
+	regulator_put(vsd->reg);
+
+err_free_vsd:
+	kfree(vsd);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(of_pm_voltdm_notifier_register);
+
+/**
+ * of_pm_voltdm_notifier_unregister() - unregister notifier for volt domain
+ * @nb:	notifier block returned by of_pm_voltdm_notifier_register
+ */
+void of_pm_voltdm_notifier_unregister(struct notifier_block *nb)
+{
+	struct volt_scale_data *vsd;
+	struct clk *clk;
+
+	/* if caller send us back error value */
+	if (IS_ERR(nb))
+		return;
+
+	vsd = to_volt_scale_data(nb);
+	clk = vsd->clk;
+	clk_notifier_unregister(clk, nb);
+	if (!IS_ERR(vsd->reg))
+		regulator_put(vsd->reg);
+
+	kfree(vsd);
+}
+EXPORT_SYMBOL_GPL(of_pm_voltdm_notifier_unregister);
diff --git a/include/linux/pm_voltage_domain.h b/include/linux/pm_voltage_domain.h
new file mode 100644
index 0000000..1ee7343
--- /dev/null
+++ b/include/linux/pm_voltage_domain.h
@@ -0,0 +1,47 @@ 
+/*
+ * Voltage Domain header for users of voltage domain interface
+ *
+ * Copyright (C) 2013 Linaro Ltd <mturquette@linaro.org>
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __PM_VOLTAGE_DOMAIN__
+#define __PM_VOLTAGE_DOMAIN__
+
+#include <linux/clk.h>
+
+#if defined(CONFIG_VOLTAGE_DOMAIN)
+struct notifier_block *of_pm_voltdm_notifier_register(struct device *dev,
+						      struct device_node *np,
+						      struct clk *clk,
+						      const char *supply,
+						      int *voltage_latency);
+void of_pm_voltdm_notifier_unregister(struct notifier_block *nb);
+
+#else
+static inline struct notifier_block *of_pm_voltdm_notifier_register(
+						      struct device *dev,
+						      struct device_node *np,
+						      struct clk *clk,
+						      const char *supply,
+						      int *voltage_latency);
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void of_pm_voltdm_notifier_unregister(struct notifier_block *nb)
+{
+}
+
+#endif				/* VOLTAGE_DOMAIN */
+
+#endif				/* __PM_VOLTAGE_DOMAIN__ */