linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework
@ 2011-03-30 15:19 jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 1/8] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet at newoldbits.com
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

Implement OMAP PM layer omap_pm_set_max_dev_wakeup_lat API by
creating a unified API which calls omap_device_set_dev_constraint
for all classes of constraints (devices wake-up latency, devices
throughput...).
The implementation of the constraints framework is at the omap_device
level: management and storage of the constraints, dispatching of the
constraints to the appropriate low level layers.

NOTE: only works for devices which have been converted to use
     omap_device/omap_hwmod.

Longer term, we could possibly remove this API from the OMAP PM layer,
and instead directly use the device level API.

For the devices wake-up latency constraints, the power domains get
the next power state programmed directly in the registers via
pwrdm_wakeuplat_update_pwrst.

Note about PM QOS: the MPU and CORE power domains get the next power
state via cpuidle, which get the strongest wake-up latency constraint
by querying PM QOS. The usage of PM QOS is temporary, until a generic
solution is in place.

The bus throughput constraints framework is supported by still is a
no-op for the moment.

For the wake-up latency constraints framework to have effect on the
power domains states, CONFIG_CPU_IDLE and CONFIG_OMAP_PM_CONSTRAINTS
must be enabled.

Based on Vibhore's original patch and completely reworked using
omap_device, omap_hwmod, powerdomain and PM QOS frameworks.
Cc: Vibhore Vardhan <vvardhan@ti.com>

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Based on khilman's pm-core branch

v3:
. updated after review comments from Kevin,
. patches re-ordering for git bisect compliance,
. reworked the constraints storage and management:
  - the omap_device layer stores all constraints in per-omap_device
    constraints lists,
  - the powerdomain layer manages the wake-up latency constraints in
    per-pwrdm constraint list and applies the constraint to the
    corresponding power domain.
. add the support for the INACTIVE power state,
. move the power domains state initialization from pwrdms_setup to an early init call,

v2:
. updated after review comments from Kevin and Paul,
. initial patch split according to the layering,
. added support for ascending or descending order of constraints values,
. added throughput constraints to the framework, although the tput implementation
 currently is a no-op,

To Do:
. refine the wake-up latency figures by defining the conditions of measurements and by
 measuring on actual hardware,
. define the effect of power domains states combinations,
. debug: add some control knobs for the wake-up latencies in /sysfs,
. add a user-space API to request and remove constraints.

Jean Pihet (8):
  OMAP PM: create a PM layer plugin for per-device constraints
  OMAP2+: powerdomain: control power domains next state
  OMAP3: powerdomain data: add wake-up latency figures
  OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency
    constraints
  OMAP: PM CONSTRAINTS: add an enum for the classes of constraint
  OMAP2+: omap_device: implement the constraints management code
  OMAP: PM CONSTRAINTS: implement wake-up latency constraints
  OMAP PM: early init of the pwrdms states

 arch/arm/mach-omap2/omap_hwmod.c              |   26 ++-
 arch/arm/mach-omap2/pm34xx.c                  |    2 +-
 arch/arm/mach-omap2/pm44xx.c                  |    2 +-
 arch/arm/mach-omap2/powerdomain.c             |  211 ++++++++++++++
 arch/arm/mach-omap2/powerdomain.h             |   42 +++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c   |   84 ++++++-
 arch/arm/plat-omap/Kconfig                    |    7 +
 arch/arm/plat-omap/Makefile                   |    1 +
 arch/arm/plat-omap/include/plat/omap-pm.h     |    4 +
 arch/arm/plat-omap/include/plat/omap_device.h |   15 +-
 arch/arm/plat-omap/include/plat/omap_hwmod.h  |    2 +
 arch/arm/plat-omap/omap-pm-constraints.c      |  369 +++++++++++++++++++++++++
 arch/arm/plat-omap/omap_device.c              |  189 +++++++++++++
 13 files changed, 946 insertions(+), 8 deletions(-)
 create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c

-- 
1.7.2.5

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

* [PATCH 1/8] OMAP PM: create a PM layer plugin for per-device constraints
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 2/8] OMAP2+: powerdomain: control power domains next state jean.pihet at newoldbits.com
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

Created arch/arm/plat-omap/omap-pm-constraints.c file from
arch/arm/plat-omap/omap-pm-noop.c and the associated Kconfig option
OMAP_PM_CONSTRAINTS.

Based on the original patch from Vishwanath,
cf. https://patchwork.kernel.org/patch/327312/

Cc: Vishwanath BS <vishwanath.bs@ti.com>

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/plat-omap/Kconfig               |    7 +
 arch/arm/plat-omap/Makefile              |    1 +
 arch/arm/plat-omap/omap-pm-constraints.c |  363 ++++++++++++++++++++++++++++++
 3 files changed, 371 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-omap/omap-pm-constraints.c

diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index b6333ae..22199da 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -215,6 +215,13 @@ config OMAP_PM_NONE
 config OMAP_PM_NOOP
 	bool "No-op/debug PM layer"
 
+config OMAP_PM_CONSTRAINTS
+	depends on PM
+	bool "Per device constraints"
+	help
+	  Select this option to enable the PM layer plugin for
+	  the per-device constraints support
+
 endchoice
 
 endmenu
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index a4a1285..a293367 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -32,3 +32,4 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
 obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
 
 obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
+obj-$(CONFIG_OMAP_PM_CONSTRAINTS) += omap-pm-constraints.o
diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
new file mode 100644
index 0000000..c8b4e4c
--- /dev/null
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -0,0 +1,363 @@
+/*
+ * omap-pm.c - OMAP power management interface
+ *
+ * This code implements the OMAP power management interface to
+ * drivers, CPUIdle, CPUFreq, and DSP Bridge.
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ * Paul Walmsley
+ *
+ * Interface developed by (in alphabetical order):
+ * Karthik Dasu, Tony Lindgren, Jean Pihet, Rajendra Nayak, Sakari Poussa,
+ * Veeramanikandan Raju, Anand Sawant, Igor Stoppa, Paul Walmsley,
+ * Richard Woodruff
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+/* Interface documentation is in mach/omap-pm.h */
+#include <plat/omap-pm.h>
+#include <plat/omap_device.h>
+
+static bool off_mode_enabled;
+static u32 dummy_context_loss_counter;
+
+/*
+ * Device-driver-originated constraints (via board-*.c files)
+ */
+
+int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+{
+	if (!dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux, this needs to map the MPU to a
+	 * powerdomain, then go through the list of current max lat
+	 * constraints on the MPU and find the smallest.  If
+	 * the latency constraint has changed, the code should
+	 * recompute the state to enter for the next powerdomain
+	 * state.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
+{
+	if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
+	    agent_id != OCP_TARGET_AGENT)) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (r == 0)
+		pr_debug("OMAP PM: remove min bus tput constraint: "
+			 "dev %s for agent_id %d\n", dev_name(dev), agent_id);
+	else
+		pr_debug("OMAP PM: add min bus tput constraint: "
+			 "dev %s for agent_id %d: rate %ld KiB\n",
+			 dev_name(dev), agent_id, r);
+
+	/*
+	 * This code should model the interconnect and compute the
+	 * required clock frequency, convert that to a VDD2 OPP ID, then
+	 * set the VDD2 OPP appropriately.
+	 *
+	 * TI CDP code can call constraint_set here on the VDD2 OPP.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
+				   long t)
+{
+	if (!req_dev || !dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max device latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max device latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux, this needs to map the device to a
+	 * powerdomain, then go through the list of current max lat
+	 * constraints on that powerdomain and find the smallest.  If
+	 * the latency constraint has changed, the code should
+	 * recompute the state to enter for the next powerdomain
+	 * state.  Conceivably, this code should also determine
+	 * whether to actually disable the device clocks or not,
+	 * depending on how long it takes to re-enable the clocks.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_max_sdma_lat(struct device *dev, long t)
+{
+	if (!dev || t < -1) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	};
+
+	if (t == -1)
+		pr_debug("OMAP PM: remove max DMA latency constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add max DMA latency constraint: "
+			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+
+	/*
+	 * For current Linux PM QOS params, this code should scan the
+	 * list of maximum CPU and DMA latencies and select the
+	 * smallest, then set cpu_dma_latency pm_qos_param
+	 * accordingly.
+	 *
+	 * For future Linux PM QOS params, with separate CPU and DMA
+	 * latency params, this code should just set the dma_latency param.
+	 *
+	 * TI CDP code can call constraint_set here.
+	 */
+
+	return 0;
+}
+
+int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
+{
+	if (!dev || !c || r < 0) {
+		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	}
+
+	if (r == 0)
+		pr_debug("OMAP PM: remove min clk rate constraint: "
+			 "dev %s\n", dev_name(dev));
+	else
+		pr_debug("OMAP PM: add min clk rate constraint: "
+			 "dev %s, rate = %ld Hz\n", dev_name(dev), r);
+
+	/*
+	 * Code in a real implementation should keep track of these
+	 * constraints on the clock, and determine the highest minimum
+	 * clock rate.  It should iterate over each OPP and determine
+	 * whether the OPP will result in a clock rate that would
+	 * satisfy this constraint (and any other PM constraint in effect
+	 *@that time).  Once it finds the lowest-voltage OPP that
+	 * meets those conditions, it should switch to it, or return
+	 * an error if the code is not capable of doing so.
+	 */
+
+	return 0;
+}
+
+/*
+ * DSP Bridge-specific constraints
+ */
+
+const struct omap_opp *omap_pm_dsp_get_opp_table(void)
+{
+	pr_debug("OMAP PM: DSP request for OPP table\n");
+
+	/*
+	 * Return DSP frequency table here:  The final item in the
+	 * array should have .rate = .opp_id = 0.
+	 */
+
+	return NULL;
+}
+
+void omap_pm_dsp_set_min_opp(u8 opp_id)
+{
+	if (opp_id == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	pr_debug("OMAP PM: DSP requests minimum VDD1 OPP to be %d\n", opp_id);
+
+	/*
+	 *
+	 * For l-o dev tree, our VDD1 clk is keyed on OPP ID, so we
+	 * can just test to see which is higher, the CPU's desired OPP
+	 * ID or the DSP's desired OPP ID, and use whichever is
+	 * highest.
+	 *
+	 * In CDP12.14+, the VDD1 OPP custom clock that controls the DSP
+	 * rate is keyed on MPU speed, not the OPP ID.  So we need to
+	 * map the OPP ID to the MPU speed for use with clk_set_rate()
+	 * if it is higher than the current OPP clock rate.
+	 *
+	 */
+}
+
+
+u8 omap_pm_dsp_get_opp(void)
+{
+	pr_debug("OMAP PM: DSP requests current DSP OPP ID\n");
+
+	/*
+	 * For l-o dev tree, call clk_get_rate() on VDD1 OPP clock
+	 *
+	 * CDP12.14+:
+	 * Call clk_get_rate() on the OPP custom clock, map that to an
+	 * OPP ID using the tables defined in board-*.c/chip-*.c files.
+	 */
+
+	return 0;
+}
+
+/*
+ * CPUFreq-originated constraint
+ *
+ * In the future, this should be handled by custom OPP clocktype
+ * functions.
+ */
+
+struct cpufreq_frequency_table **omap_pm_cpu_get_freq_table(void)
+{
+	pr_debug("OMAP PM: CPUFreq request for frequency table\n");
+
+	/*
+	 * Return CPUFreq frequency table here: loop over
+	 * all VDD1 clkrates, pull out the mpu_ck frequencies, build
+	 * table
+	 */
+
+	return NULL;
+}
+
+void omap_pm_cpu_set_freq(unsigned long f)
+{
+	if (f == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
+		 f);
+
+	/*
+	 * For l-o dev tree, determine whether MPU freq or DSP OPP id
+	 * freq is higher.  Find the OPP ID corresponding to the
+	 * higher frequency.  Call clk_round_rate() and clk_set_rate()
+	 * on the OPP custom clock.
+	 *
+	 * CDP should just be able to set the VDD1 OPP clock rate here.
+	 */
+}
+
+unsigned long omap_pm_cpu_get_freq(void)
+{
+	pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
+
+	/*
+	 * Call clk_get_rate() on the mpu_ck.
+	 */
+
+	return 0;
+}
+
+/**
+ * omap_pm_enable_off_mode - notify OMAP PM that off-mode is enabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been enabled.
+ */
+void omap_pm_enable_off_mode(void)
+{
+	off_mode_enabled = true;
+}
+
+/**
+ * omap_pm_disable_off_mode - notify OMAP PM that off-mode is disabled
+ *
+ * Intended for use only by OMAP PM core code to notify this layer
+ * that off mode has been disabled.
+ */
+void omap_pm_disable_off_mode(void)
+{
+	off_mode_enabled = false;
+}
+
+/*
+ * Device context loss tracking
+ */
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	u32 count;
+
+	if (WARN_ON(!dev))
+		return 0;
+
+	if (dev->parent == &omap_device_parent) {
+		count = omap_device_get_context_loss_count(pdev);
+	} else {
+		WARN_ONCE(off_mode_enabled, "omap_pm: using dummy context "
+			  "loss counter; device %s should be converted to "
+			  "omap_device", dev_name(dev));
+		if (off_mode_enabled)
+			dummy_context_loss_counter++;
+		count = dummy_context_loss_counter;
+	}
+
+	pr_debug("OMAP PM: context loss count for dev %s = %d\n",
+		 dev_name(dev), count);
+
+	return count;
+}
+
+#else
+
+u32 omap_pm_get_dev_context_loss_count(struct device *dev)
+{
+	return dummy_context_loss_counter;
+}
+
+#endif
+
+/* Should be called before clk framework init */
+int __init omap_pm_if_early_init(void)
+{
+	return 0;
+}
+
+/* Must be called after clock framework is initialized */
+int __init omap_pm_if_init(void)
+{
+	return 0;
+}
+
+void omap_pm_if_exit(void)
+{
+	/* Deallocate CPUFreq frequency table here */
+}
+
-- 
1.7.2.5

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

* [PATCH 2/8] OMAP2+: powerdomain: control power domains next state
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 1/8] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 3/8] OMAP3: powerdomain data: add wake-up latency figures jean.pihet at newoldbits.com
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

When a wake-up latency constraint is requested or removed the omap device
layer dispatches the updated strongest constraint value to the
corresponding power domain.
The power domains get the next power state programmed directly in the
registers via pwrdm_wakeuplat_update_pwrst.

Note about PM QOS: the MPU and CORE power domains get the next power
state via cpuidle, which get the strongest wake-up latency constraint
by querying PM QOS. The usage of PM QOS is temporary, until a generic
solution is in place.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/powerdomain.c |  206 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |   42 +++++++-
 2 files changed, 246 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 49c6513..b8d3860 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <trace/events/power.h>
@@ -104,6 +105,12 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	for (i = 0; i < pwrdm->banks; i++)
 		pwrdm->ret_mem_off_counter[i] = 0;
 
+	/* Initialize the per-od wake-up constraints list and spinlock */
+	spin_lock_init(&pwrdm->wkup_lat_plist_lock);
+	plist_head_init(&pwrdm->wkup_lat_plist_head,
+			&pwrdm->wkup_lat_plist_lock);
+
+	/* Initialize the pwrdm state */
 	pwrdm_wait_transition(pwrdm);
 	pwrdm->state = pwrdm_read_pwrst(pwrdm);
 	pwrdm->state_counter[pwrdm->state] = 1;
@@ -191,6 +198,103 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 	return 0;
 }
 
+/**
+ * pwrdm_wakeuplat_update_pwrst - Update power domain power state if needed
+ * @pwrdm: struct powerdomain * to which requesting device belongs to.
+ * @min_latency: the allowed wake-up latency for the given power domain. A
+ *  value of 0 means 'no constraint' on the pwrdm.
+ *
+ * Finds the power domain next power state that fulfills the constraint.
+ * Programs a new target state if it is different from current power state.
+ *
+ * Note about PM QOS: the MPU and CORE power domains get the next power
+ * state via cpuidle, which get the strongest wake-up latency constraint
+ * by querying PM QOS. The usage of PM QOS is temporary, until a generic
+ * solution is in place.
+ * The power domains other then MPU and CORE get the next power state
+ * programmed directly in the registers.
+ *
+ * Returns 0 upon success.
+ */
+static int pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm,
+					long min_latency)
+{
+	int ret = 0, new_state = 0;
+
+	if (!pwrdm) {
+		WARN(1, "powerdomain: %s: invalid parameter(s)", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * Apply constraints to MPU and CORE via the PM QOS API.
+	 * Every power domain struct has a pm_qos_request_list field
+	 */
+	if (pwrdm->flags & PWRDM_USES_PM_QOS_CONSTRAINTS) {
+		if (pm_qos_request_active(&pwrdm->pm_qos_request))
+			pm_qos_remove_request(&pwrdm->pm_qos_request);
+
+		if (min_latency > 0) {
+			pm_qos_add_request(&pwrdm->pm_qos_request,
+					   PM_QOS_CPU_DMA_LATENCY,
+					   min_latency);
+			pr_debug("powerdomain: %s: pwrdm %s: "
+				 "adding a PM_QOS_CPU_DMA_LATENCY request, "
+				 "min_latency=%ld\n", __func__, pwrdm->name,
+				 min_latency);
+		}
+
+		return 0;
+	}
+
+	/*
+	 * Apply constraints to pwrdm other than MPU and CORE by programming
+	 * the pwrdm next power state.
+	 */
+
+	/* Find power state with wakeup latency < minimum constraint */
+	for (new_state = 0x0; new_state < PWRDM_MAX_PWRSTS; new_state++) {
+		if (min_latency == 0 ||
+		    pwrdm->wakeup_lat[new_state] <= min_latency)
+			break;
+	}
+
+	switch (new_state) {
+	case PWRDM_FUNC_PWRST_OFF:
+		new_state = PWRDM_POWER_OFF;
+		break;
+	case PWRDM_FUNC_PWRST_OSWR:
+		pwrdm_set_logic_retst(pwrdm, PWRDM_POWER_OFF);
+		new_state = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_CSWR:
+		pwrdm_set_logic_retst(pwrdm, PWRDM_POWER_RET);
+		new_state = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_INACTIVE:
+		new_state = PWRDM_POWER_INACTIVE;
+		break;
+	case PWRDM_FUNC_PWRST_ON:
+		new_state = PWRDM_POWER_ON;
+		break;
+	default:
+		pr_warn("powerdomain: requested latency constraint not "
+			"supported %s set to ON state\n", pwrdm->name);
+		new_state = PWRDM_POWER_ON;
+		break;
+	}
+
+	if (pwrdm_read_pwrst(pwrdm) != new_state)
+		ret = omap_set_pwrdm_state(pwrdm, new_state);
+
+	pr_debug("powerdomain: %s pwrst: curr=%d, prev=%d next=%d "
+		 "min_latency=%ld, set_state=%d\n", pwrdm->name,
+		 pwrdm_read_pwrst(pwrdm), pwrdm_read_prev_pwrst(pwrdm),
+		 pwrdm_read_next_pwrst(pwrdm), min_latency, new_state);
+
+	return ret;
+}
+
 /* Public functions */
 
 /**
@@ -930,6 +1034,108 @@ int pwrdm_post_transition(void)
 	return 0;
 }
 
+/*
+ * pwrdm_set_wkup_lat_constraint - Set/update/remove a powerdomain wakeup
+ *  latency constraint and apply it
+ * @pwrdm: struct powerdomain * which the constraint applies to
+ * @cookie: constraint identifier, used for tracking.
+ * @min_latency: minimum wakeup latency constraint (in microseconds) for
+ *  the given pwrdm. The value of 0 removes the constraint.
+ *
+ * Tracks the constraints by @cookie.
+ * Constraint set/update: Adds a new entry to powerdomain's wake-up latency
+ * constraint list.
+ * If the constraint identifier already exists in the list, the old value is
+ * overwritten.
+ * Constraint removal: Removes the identifier's entry from powerdomain's
+ * wakeup latency constraint list.
+ *
+ * Applies the strongest constraint value for the given pwrdm by calling
+ * pwrdm_wakeuplat_update_pwrst.
+ *
+ * Returns 0 upon success or a negative value in case of error.
+ *
+ * The caller must check the validity of the parameters.
+ */
+int pwrdm_set_wkup_lat_constraint(struct powerdomain *pwrdm, void *cookie,
+				  long min_latency)
+{
+	struct pwrdm_wkup_constraints_entry *user = NULL, *tmp_user;
+	int ret = 0;
+	long value = 0;
+	unsigned long flags;
+
+	pr_debug("powerdomain: %s: pwrdm %s, cookie=0x%p, min_latency=%ld\n",
+		 __func__, pwrdm->name, cookie, min_latency);
+
+	/* Check if there already is a constraint for cookie */
+	spin_lock_irqsave(&pwrdm->wkup_lat_plist_lock, flags);
+	plist_for_each_entry(tmp_user, &pwrdm->wkup_lat_plist_head, node) {
+		if (tmp_user->cookie == cookie) {
+			user = tmp_user;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+
+	if (min_latency > 0) {
+		/* Nothing to update, job done */
+		if (user && (user->node.prio == min_latency))
+			goto exit_ok;
+
+		/* Add new entry to the list or update existing request */
+		if (!user) {
+			user = kzalloc(
+				sizeof(struct pwrdm_wkup_constraints_entry),
+				GFP_KERNEL);
+			if (!user) {
+				pr_err("%s: FATAL ERROR: kzalloc failed\n",
+				       __func__);
+				ret = -ENOMEM;
+				goto exit_error;
+			}
+			user->cookie = cookie;
+		} else {
+			spin_lock_irqsave(&pwrdm->wkup_lat_plist_lock, flags);
+			plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+			spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock,
+					       flags);
+		}
+
+		spin_lock_irqsave(&pwrdm->wkup_lat_plist_lock, flags);
+		plist_node_init(&user->node, min_latency);
+		plist_add(&user->node, &pwrdm->wkup_lat_plist_head);
+		spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+	} else {
+		/* Remove the constraint from the list */
+		if (!user) {
+			pr_err("%s: Error: no prior constraint to release\n",
+			       __func__);
+			ret = -EINVAL;
+			goto exit_error;
+		}
+
+		spin_lock_irqsave(&pwrdm->wkup_lat_plist_lock, flags);
+		plist_del(&user->node, &pwrdm->wkup_lat_plist_head);
+		spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+		kfree(user);
+	}
+
+exit_ok:
+	/* Find the strongest constraint from the list */
+	spin_lock_irqsave(&pwrdm->wkup_lat_plist_lock, flags);
+	value = plist_first(&pwrdm->wkup_lat_plist_head)->prio;
+	spin_unlock_irqrestore(&pwrdm->wkup_lat_plist_lock, flags);
+
+	/* Apply the constraint to the pwrdm */
+	pr_debug("powerdomain: %s: pwrdm %s, value=%ld\n",
+		 __func__, pwrdm->name, value);
+	pwrdm_wakeuplat_update_pwrst(pwrdm, value);
+
+exit_error:
+	return ret;
+}
+
 /**
  * pwrdm_get_context_loss_count - get powerdomain's context loss count
  * @pwrdm: struct powerdomain * to wait for
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 027f40b..523ba9e 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -19,7 +19,10 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
-
+#include <linux/plist.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/pm_qos_params.h>
 #include <linux/atomic.h>
 
 #include <plat/cpu.h>
@@ -43,6 +46,16 @@
 #define PWRSTS_RET_ON		(PWRSTS_RET | PWRSTS_ON)
 #define PWRSTS_OFF_RET_ON	(PWRSTS_OFF_RET | PWRSTS_ON)
 
+/* Powerdomain functional power states */
+#define PWRDM_FUNC_PWRST_OFF		0x0
+#define PWRDM_FUNC_PWRST_OSWR		0x1
+#define PWRDM_FUNC_PWRST_CSWR		0x2
+#define PWRDM_FUNC_PWRST_INACTIVE	0x3
+#define PWRDM_FUNC_PWRST_ON		0x4
+
+#define PWRDM_MAX_FUNC_PWRSTS	5
+
+#define UNSUP_STATE		-1
 
 /* Powerdomain flags */
 #define PWRDM_HAS_HDWR_SAR	(1 << 0) /* hardware save-and-restore support */
@@ -56,6 +69,12 @@
 						  * state without waking up the
 						  * powerdomain
 						  */
+#define PWRDM_USES_PM_QOS_CONSTRAINTS	(1 << 3) /* Uses the PM QOS framework
+						  * for wake-up latency
+						  * constraints.
+						  * Note: temporary until the
+						  * generic OMAP PM is in place
+						  */
 
 /*
  * Number of memory banks that are power-controllable.	On OMAP4430, the
@@ -93,7 +112,13 @@ struct powerdomain;
  * @state_counter:
  * @timer:
  * @state_timer:
- *
+ * @wakeup_lat: wakeup latencies (in us) for possible powerdomain power states
+ * Note about the wakeup latencies ordering: the values must be sorted
+ *  in decremental order
+ * @wkup_lat_plist_head: pwrdm wake-up latency constraints list
+ * @wkup_lat_plist_lock: spinlock that protects the constraints lists
+ * @pm_qos_request: PM QOS handle, only used to control the MPU and CORE power
+ *  domains states; to be removed when a generic solution is in place.
  * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
  */
 struct powerdomain {
@@ -118,6 +143,16 @@ struct powerdomain {
 	s64 timer;
 	s64 state_timer[PWRDM_MAX_PWRSTS];
 #endif
+	const u32 wakeup_lat[PWRDM_MAX_FUNC_PWRSTS];
+	struct plist_head wkup_lat_plist_head;
+	spinlock_t wkup_lat_plist_lock;
+	struct pm_qos_request_list pm_qos_request;
+};
+
+/* Linked list for the wake-up latency constraints */
+struct pwrdm_wkup_constraints_entry {
+	void			*cookie;
+	struct plist_node	node;
 };
 
 /**
@@ -207,6 +242,9 @@ int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
 int pwrdm_pre_transition(void);
 int pwrdm_post_transition(void);
 int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
+
+int pwrdm_set_wkup_lat_constraint(struct powerdomain *pwrdm, void *cookie,
+				  long min_latency);
 u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
 bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
 
-- 
1.7.2.5

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

* [PATCH 3/8] OMAP3: powerdomain data: add wake-up latency figures
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 1/8] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 2/8] OMAP2+: powerdomain: control power domains next state jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints jean.pihet at newoldbits.com
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

Figures are added to the power domains structs.

Note: the figures are preliminary figures. More accurate measurements
are needed. Also the conditions of measurements shall be investigated
and described.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/powerdomains3xxx_data.c |   84 ++++++++++++++++++++++++++-
 1 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 9c9c113..11dc57e 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -31,6 +31,13 @@
 
 /*
  * Powerdomains
+ *
+ * The wakeup_lat values are derived from measurements on
+ * the actual target.
+ *
+ * Note: the latency figures are preliminary and only used
+ * for the constraints framework validation.
+ * Actual figures and measurements conditions shall be added.
  */
 
 static struct powerdomain iva2_pwrdm = {
@@ -52,6 +59,13 @@ static struct powerdomain iva2_pwrdm = {
 		[2] = PWRSTS_OFF_ON,
 		[3] = PWRSTS_ON,
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1100,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 350,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain mpu_3xxx_pwrdm = {
@@ -60,7 +74,8 @@ static struct powerdomain mpu_3xxx_pwrdm = {
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 	.pwrsts		  = PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
-	.flags		  = PWRDM_HAS_MPU_QUIRK,
+	.flags		  = PWRDM_HAS_MPU_QUIRK |
+			    PWRDM_USES_PM_QOS_CONSTRAINTS,
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_OFF_RET,
@@ -68,6 +83,13 @@ static struct powerdomain mpu_3xxx_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_OFF_ON,
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 95,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 45,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /*
@@ -90,6 +112,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = {
 	.pwrsts		  = PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 2,
+	.flags		  = PWRDM_USES_PM_QOS_CONSTRAINTS,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_OFF_RET,	 /* MEM1RETSTATE */
 		[1] = PWRSTS_OFF_RET,	 /* MEM2RETSTATE */
@@ -98,6 +121,13 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = {
 		[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
 		[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 100,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 60,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -111,7 +141,8 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {
 	 * Setting the SAR flag for errata ID i478 which applies
 	 *  to 3430 <= ES3.1
 	 */
-	.flags		  = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */
+	.flags		  = PWRDM_HAS_HDWR_SAR /* for USBTLL only */ |
+			    PWRDM_USES_PM_QOS_CONSTRAINTS,
 	.banks		  = 2,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_OFF_RET,	 /* MEM1RETSTATE */
@@ -121,6 +152,13 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {
 		[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
 		[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 100,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 60,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain dss_pwrdm = {
@@ -136,6 +174,13 @@ static struct powerdomain dss_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_ON,  /* MEMONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 70,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 20,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 /*
@@ -157,6 +202,13 @@ static struct powerdomain sgx_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_ON,  /* MEMONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 1000,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain cam_pwrdm = {
@@ -172,6 +224,13 @@ static struct powerdomain cam_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_ON,  /* MEMONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 850,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 35,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain per_pwrdm = {
@@ -187,6 +246,13 @@ static struct powerdomain per_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_ON,  /* MEMONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 200,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 110,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain emu_pwrdm = {
@@ -201,6 +267,13 @@ static struct powerdomain neon_pwrdm = {
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 	.pwrsts		  = PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_RET,
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 200,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 35,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain usbhost_pwrdm = {
@@ -223,6 +296,13 @@ static struct powerdomain usbhost_pwrdm = {
 	.pwrsts_mem_on	  = {
 		[0] = PWRSTS_ON,  /* MEMONSTATE */
 	},
+	.wakeup_lat = {
+		[PWRDM_FUNC_PWRST_OFF] = 800,
+		[PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_CSWR] = 150,
+		[PWRDM_FUNC_PWRST_INACTIVE] = UNSUP_STATE,
+		[PWRDM_FUNC_PWRST_ON] = 0,
+	},
 };
 
 static struct powerdomain dpll1_pwrdm = {
-- 
1.7.2.5

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

* [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
                   ` (2 preceding siblings ...)
  2011-03-30 15:19 ` [PATCH 3/8] OMAP3: powerdomain data: add wake-up latency figures jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  2011-03-31 11:20   ` Sergei Shtylyov
  2011-03-31 11:29   ` Russell King - ARM Linux
  2011-03-30 15:19 ` [PATCH 5/8] OMAP: PM CONSTRAINTS: add an enum for the classes of constraint jean.pihet at newoldbits.com
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

Hwmod is queried from the omap device layer to manage the power domains
wake-up latency constraints. Hwmod retrieves the correct power domain
and if it exists it calls the corresponding power domain function.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod.c             |   26 +++++++++++++++++++++++++-
 arch/arm/plat-omap/include/plat/omap_hwmod.h |    2 ++
 2 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e034294..62de888 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -142,6 +142,7 @@
 #include "powerdomain.h"
 #include <plat/clock.h>
 #include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 #include <plat/prcm.h>
 
 #include "cm2xxx_3xxx.h"
@@ -2322,11 +2323,34 @@ ohsps_unlock:
 	return ret;
 }
 
+/*
+ * omap_hwmod_set_wkup_constraint- set/release a wake-up latency constraint
+ *
+ * @oh: struct omap_hwmod* to which the target device belongs to.
+ * @cookie: identifier of the constraints list for @oh.
+ * @min_latency: the minimum allowed wake-up latency for @oh.
+ *
+ * Returns 0 upon success.
+ */
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh,
+				       void *cookie, long min_latency)
+{
+	struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
+
+	if (!PTR_ERR(pwrdm)) {
+		pr_err("%s: Error: could not find powerdomain "
+		       "for %s\n", __func__, oh->name);
+		return -EINVAL;
+	}
+
+	return pwrdm_set_wkup_lat_constraint(pwrdm, cookie, min_latency);
+}
+
 /**
  * omap_hwmod_get_context_loss_count - get lost context count
  * @oh: struct omap_hwmod *
  *
- * Query the powerdomain of of @oh to get the context loss
+ * Query the powerdomain of @oh to get the context loss
  * count for this device.
  *
  * Returns the context loss count of the powerdomain assocated with @oh
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 1adea9c..bf9e81d 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -598,6 +598,8 @@ int omap_hwmod_for_each_by_class(const char *classname,
 				 void *user);
 
 int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
+int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh, void *cookie,
+				       long min_latency);
 u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
 
 int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
-- 
1.7.2.5

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

* [PATCH 5/8] OMAP: PM CONSTRAINTS: add an enum for the classes of constraint
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
                   ` (3 preceding siblings ...)
  2011-03-30 15:19 ` [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 6/8] OMAP2+: omap_device: implement the constraints management code jean.pihet at newoldbits.com
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

Defined values in the enum:
- OMAP_PM_CONSTRAINT_WKUP_LAT
- OMAP_PM_CONSTRAINT_THROUGHPUT

More classes can be added later if needed.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/plat-omap/include/plat/omap-pm.h |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h
index c0a7520..5f19cb2 100644
--- a/arch/arm/plat-omap/include/plat/omap-pm.h
+++ b/arch/arm/plat-omap/include/plat/omap-pm.h
@@ -70,6 +70,10 @@ void omap_pm_if_exit(void);
  * Device-driver-originated constraints (via board-*.c files, platform_data)
  */
 
+enum omap_pm_constraint_class {
+	OMAP_PM_CONSTRAINT_WKUP_LAT,
+	OMAP_PM_CONSTRAINT_THROUGHPUT
+};
 
 /**
  * omap_pm_set_max_mpu_wakeup_lat - set the maximum MPU wakeup latency
-- 
1.7.2.5

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

* [PATCH 6/8] OMAP2+: omap_device: implement the constraints management code
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
                   ` (4 preceding siblings ...)
  2011-03-30 15:19 ` [PATCH 5/8] OMAP: PM CONSTRAINTS: add an enum for the classes of constraint jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 7/8] OMAP: PM CONSTRAINTS: implement wake-up latency constraints jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 8/8] OMAP PM: early init of the pwrdms states jean.pihet at newoldbits.com
  7 siblings, 0 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

The code at omap device level manages the constraints: storage,
tracking of requesters and dispatching to the low level
code (e.g. powerdomain for the wake-up latency constraints).

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/plat-omap/include/plat/omap_device.h |   15 ++-
 arch/arm/plat-omap/omap_device.c              |  189 +++++++++++++++++++++++++
 2 files changed, 203 insertions(+), 1 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
index e4c349f..9a47b47 100644
--- a/arch/arm/plat-omap/include/plat/omap_device.h
+++ b/arch/arm/plat-omap/include/plat/omap_device.h
@@ -32,9 +32,11 @@
 #define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_DEVICE_H
 
 #include <linux/kernel.h>
+#include <linux/plist.h>
 #include <linux/platform_device.h>
 
 #include <plat/omap_hwmod.h>
+#include <plat/omap-pm.h>
 
 extern struct device omap_device_parent;
 
@@ -54,8 +56,8 @@ extern struct device omap_device_parent;
  * @pm_lat_level: array index of the last odpl entry executed - -1 if never
  * @dev_wakeup_lat: dev wakeup latency in nanoseconds
  * @_dev_wakeup_lat_limit: dev wakeup latency limit in nsec - set by OMAP PM
+ * @wkup_lat_plist_head: devices wake-up latency constraints list
  * @_state: one of OMAP_DEVICE_STATE_* (see above)
- * @flags: device flags
  *
  * Integrates omap_hwmod data into Linux platform_device.
  *
@@ -67,6 +69,7 @@ struct omap_device {
 	struct platform_device		pdev;
 	struct omap_hwmod		**hwmods;
 	struct omap_device_pm_latency	*pm_lats;
+	struct plist_head		wkup_lat_plist_head;
 	u32				dev_wakeup_lat;
 	u32				_dev_wakeup_lat_limit;
 	u8				pm_lats_cnt;
@@ -75,6 +78,13 @@ struct omap_device {
 	u8				_state;
 };
 
+/* Linked list for the devices constraints entries */
+struct omap_device_constraints_entry {
+	struct device			*dev;
+	struct device			*req_dev;
+	struct plist_node		node;
+};
+
 /* Device driver interface (call via platform_data fn ptrs) */
 
 int omap_device_enable(struct platform_device *pdev);
@@ -107,6 +117,9 @@ void __iomem *omap_device_get_rt_va(struct omap_device *od);
 int omap_device_align_pm_lat(struct platform_device *pdev,
 			     u32 new_wakeup_lat_limit);
 struct powerdomain *omap_device_get_pwrdm(struct omap_device *od);
+int omap_device_set_dev_constraint(enum omap_pm_constraint_class class,
+				   struct device *req_dev,
+				   struct device *dev, long t);
 u32 omap_device_get_context_loss_count(struct platform_device *pdev);
 
 /* Other */
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 9bbda9a..eff577f 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -292,10 +292,194 @@ static void _add_optional_clock_clkdev(struct omap_device *od,
 	}
 }
 
+/* Spinlock that protects the constraints lists */
+static spinlock_t _constraints_lock;
+
+/*
+ * _store_constraint: add/update/remove a constraint from a plist. There is
+ *  one plist per omap_device.
+ *
+ * @constraints_list: plist to use
+ * @req_dev: constraint requester, used to track the requests
+ * @dev: device constraint target, used to track the requests
+ * @value: constraint value. The plist is sorted by the value. -1 remove the
+ *  constraint from the list
+ * @ascending: return the lowest constraint value if set to 1, return the
+ *  highest value if not.
+ *
+ * Tracks the constraints by req_dev and dev.
+ * Returns the strongest constraint value for the given device, 0 in the
+ * case there is no constraint or a negative value in case of error.
+ *
+ * The caller must check the validity of the parameters.
+ */
+static long _store_constraint(struct plist_head *constraints_list,
+			      struct device *req_dev, struct device *dev,
+			      long value, int ascending)
+{
+	struct omap_device_constraints_entry *user = NULL, *tmp_user;
+	int ret = 0;
+	unsigned long flags;
+
+	/* Check if there already is a constraint for dev and req_dev */
+	spin_lock_irqsave(&_constraints_lock, flags);
+	plist_for_each_entry(tmp_user, constraints_list, node) {
+		if ((tmp_user->req_dev == req_dev) && (tmp_user->dev == dev)) {
+			user = tmp_user;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&_constraints_lock, flags);
+
+	if (value >= 0) {
+		/* Nothing to update, job done */
+		if (user && (user->node.prio == value))
+			goto exit_ok;
+
+		/* Add new entry to the list or update existing request */
+		if (!user) {
+			user = kzalloc(
+				sizeof(struct omap_device_constraints_entry),
+				GFP_KERNEL);
+			if (!user) {
+				pr_err("%s: FATAL ERROR: kzalloc failed\n",
+				       __func__);
+				ret = -ENOMEM;
+				goto exit_error;
+			}
+			user->req_dev = req_dev;
+			user->dev = dev;
+		} else {
+			spin_lock_irqsave(&_constraints_lock, flags);
+			plist_del(&user->node, constraints_list);
+			spin_unlock_irqrestore(&_constraints_lock, flags);
+		}
+
+		spin_lock_irqsave(&_constraints_lock, flags);
+		plist_node_init(&user->node, value);
+		plist_add(&user->node, constraints_list);
+		spin_unlock_irqrestore(&_constraints_lock, flags);
+	} else {
+		/* Remove the constraint from the list */
+		if (!user) {
+			pr_err("%s: Error: no prior constraint to release\n",
+			       __func__);
+			ret = -EINVAL;
+			goto exit_error;
+		}
+
+		spin_lock_irqsave(&_constraints_lock, flags);
+		plist_del(&user->node, constraints_list);
+		spin_unlock_irqrestore(&_constraints_lock, flags);
+		kfree(user);
+	}
+
+exit_ok:
+	/* Find the strongest constraint for the given device */
+	spin_lock_irqsave(&_constraints_lock, flags);
+	if (ascending) {
+		/* Find the lowest (i.e. first) value */
+		ret = plist_first(constraints_list)->prio;
+	} else {
+		/* Find the highest (i.e. last) value */
+		ret = plist_last(constraints_list)->prio;
+	}
+	spin_unlock_irqrestore(&_constraints_lock, flags);
+
+exit_error:
+	return ret;
+}
 
 /* Public functions for use by core code */
 
 /**
+ * omap_device_set_dev_constraint - set/release a device constraint
+ * @class: constraint class
+ * @req_dev: constraint requester, used for tracking the constraints
+ * @dev: device to apply the constraint to. Must have an associated omap_device
+ * @t: constraint value. A value of -1 removes the constraint.
+ *
+ * Using the primary hwmod, set/release a device constraint for the dev
+ * device, requested by the req_dev device. Depending of the constraint class
+ * this code calls the appropriate low level code, e.g. power domain for
+ * the wake-up latency constraints.
+ *
+ * If any hwmods exist for the omap_device assoiated with @dev,
+ * set/release the constraint for the corresponding hwmods, otherwise return
+ * -EINVAL.
+ */
+int omap_device_set_dev_constraint(enum omap_pm_constraint_class class,
+				   struct device *req_dev,
+				   struct device *dev, long t)
+{
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
+	void *cookie = NULL;
+	u32 ret = -EINVAL;
+
+	/* Only valid for omap_devices */
+	if (dev->parent != &omap_device_parent) {
+		pr_err("%s: Error: not an omap_device %s\n",
+		       __func__, dev_name(dev));
+		return -EINVAL;
+	}
+
+	/* Look for the platform device for dev */
+	pdev = to_platform_device(dev);
+
+	/* Try to catch non platform devices. */
+	if (pdev->name == NULL) {
+		pr_err("%s: Error: platform device for device %s not valid\n",
+		       __func__, dev_name(dev));
+		return -EINVAL;
+	}
+
+	/* Find the associated omap_device for dev */
+	od = _find_by_pdev(pdev);
+	if (!od || (od->hwmods_cnt != 1)) {
+		pr_err("%s: Error: No unique hwmod for device %s\n",
+		       __func__, dev_name(dev));
+		return -EINVAL;
+	}
+
+	/* Find the primary omap_hwmod for dev */
+	oh = od->hwmods[0];
+
+	switch (class) {
+	case OMAP_PM_CONSTRAINT_WKUP_LAT:
+		/*
+		 * Store the constraint in the appropriate list and find the
+		 * strongest constraint
+		 */
+		ret = _store_constraint(&od->wkup_lat_plist_head,
+					req_dev, dev, t, 1);
+
+		/* Apply the constraint by calling the low level code */
+		cookie = (void *) &od->wkup_lat_plist_head;
+		if (ret >= 0) {
+			ret = omap_hwmod_set_wkup_lat_constraint(oh, cookie,
+								 ret);
+		} else {
+			pr_err("%s: Error storing the constraint for device "
+			       "%s\n", __func__, dev_name(dev));
+		}
+
+		break;
+	case OMAP_PM_CONSTRAINT_THROUGHPUT:
+		WARN(1, "OMAP PM: %s: Bus throughput constraint class \
+		     not implemented\n", __func__);
+		ret = -EINVAL;
+		break;
+	default:
+		WARN(1, "OMAP PM: %s: invalid constraint class %d",
+		     __func__, class);
+	}
+
+	return ret;
+}
+
+/**
  * omap_device_get_context_loss_count - get lost context count
  * @od: struct omap_device *
  *
@@ -489,6 +673,8 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
 	od->pm_lats = pm_lats;
 	od->pm_lats_cnt = pm_lats_cnt;
 
+	plist_head_init(&od->wkup_lat_plist_head, &_constraints_lock);
+
 	if (is_early_device)
 		ret = omap_early_device_register(od);
 	else
@@ -824,6 +1010,9 @@ struct device omap_device_parent = {
 
 static int __init omap_device_init(void)
 {
+	/* Initialize priority ordered list for wakeup latency constraint */
+	spin_lock_init(&_constraints_lock);
+
 	return device_register(&omap_device_parent);
 }
 core_initcall(omap_device_init);
-- 
1.7.2.5

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

* [PATCH 7/8] OMAP: PM CONSTRAINTS: implement wake-up latency constraints
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
                   ` (5 preceding siblings ...)
  2011-03-30 15:19 ` [PATCH 6/8] OMAP2+: omap_device: implement the constraints management code jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  2011-03-30 15:19 ` [PATCH 8/8] OMAP PM: early init of the pwrdms states jean.pihet at newoldbits.com
  7 siblings, 0 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

Implement the wake-up latency constraints using an internal
unified function _set_dev_constraint at OMAP PM level,
which calls the corresponding function at omap device level.

The actual constraints management code is at the omap device level.

Note: the bus throughput function is implemented but currently is
a no-op.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/plat-omap/omap-pm-constraints.c |  172 +++++++++++++++--------------
 1 files changed, 89 insertions(+), 83 deletions(-)

diff --git a/arch/arm/plat-omap/omap-pm-constraints.c b/arch/arm/plat-omap/omap-pm-constraints.c
index c8b4e4c..805dba3 100644
--- a/arch/arm/plat-omap/omap-pm-constraints.c
+++ b/arch/arm/plat-omap/omap-pm-constraints.c
@@ -24,6 +24,7 @@
 /* Interface documentation is in mach/omap-pm.h */
 #include <plat/omap-pm.h>
 #include <plat/omap_device.h>
+#include <plat/common.h>
 
 static bool off_mode_enabled;
 static u32 dummy_context_loss_counter;
@@ -32,119 +33,124 @@ static u32 dummy_context_loss_counter;
  * Device-driver-originated constraints (via board-*.c files)
  */
 
-int omap_pm_set_max_mpu_wakeup_lat(struct device *dev, long t)
+/*
+ * Generic function to omap_device layer for the constraints API.
+ */
+static int _set_dev_constraint(enum omap_pm_constraint_class class,
+			       struct device *req_dev, struct device *dev,
+			       long t)
 {
-	if (!dev || t < -1) {
+	int ret = 0;
+
+	if (!req_dev || !dev || t < -1) {
 		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
 		return -EINVAL;
-	};
-
-	if (t == -1)
-		pr_debug("OMAP PM: remove max MPU wakeup latency constraint: "
-			 "dev %s\n", dev_name(dev));
-	else
-		pr_debug("OMAP PM: add max MPU wakeup latency constraint: "
-			 "dev %s, t = %ld usec\n", dev_name(dev), t);
+	}
 
-	/*
-	 * For current Linux, this needs to map the MPU to a
-	 * powerdomain, then go through the list of current max lat
-	 * constraints on the MPU and find the smallest.  If
-	 * the latency constraint has changed, the code should
-	 * recompute the state to enter for the next powerdomain
-	 * state.
-	 *
-	 * TI CDP code can call constraint_set here.
-	 */
+	/* Only valid for omap_devices */
+	if (dev->parent == &omap_device_parent) {
+		if (t == -1)
+			pr_debug("OMAP PM: remove constraint of class %d "
+				 "from req_dev %s on dev %s\n",
+				 class, dev_name(req_dev), dev_name(dev));
+		else
+			pr_debug("OMAP PM: add constraint of class %d "
+				 "from req_dev %s on dev %s, t = %ld\n",
+				 class, dev_name(req_dev), dev_name(dev), t);
+
+		ret = omap_device_set_dev_constraint(class, req_dev, dev, t);
+	} else {
+		pr_err("OMAP-PM: %s: Error: not an omap_device\n", __func__);
+		return -EINVAL;
+	}
 
-	return 0;
+	return ret;
 }
 
+/*
+ * omap_pm_set_min_bus_tput - set/release bus throughput constraints
+ */
 int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
 {
+	long t;
+	struct device *req_dev = NULL;
+
 	if (!dev || (agent_id != OCP_INITIATOR_AGENT &&
 	    agent_id != OCP_TARGET_AGENT)) {
 		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
 		return -EINVAL;
 	};
 
+	/*
+	 * This code calls the generic omap_device API function
+	 * _set_dev_constraint with the class OMAP_PM_CONSTRAINT_THROUGHPUT.
+	 * _set_dev_constraint should manage the constraints lists and call
+	 * the appropriate low level code that models the interconnect,
+	 * computes the required clock frequency, converts that to a VDD2
+	 * OPP ID and sets the VDD2 OPP appropriately.
+	 */
+
+	/*
+	 * A value of r == 0 removes the constraint. Convert it to the
+	 * generic _set_dev_constraint convention (-1 for constraint removal)
+	 */
 	if (r == 0)
-		pr_debug("OMAP PM: remove min bus tput constraint: "
-			 "dev %s for agent_id %d\n", dev_name(dev), agent_id);
+		t = -1;
 	else
-		pr_debug("OMAP PM: add min bus tput constraint: "
-			 "dev %s for agent_id %d: rate %ld KiB\n",
-			 dev_name(dev), agent_id, r);
+		t = r;
 
 	/*
-	 * This code should model the interconnect and compute the
-	 * required clock frequency, convert that to a VDD2 OPP ID, then
-	 * set the VDD2 OPP appropriately.
-	 *
-	 * TI CDP code can call constraint_set here on the VDD2 OPP.
+	 * Assign the device for L3 or L4 interconnect to req_dev,
+	 * based on the value of agent_id
 	 */
+	switch (agent_id) {
+	case OCP_INITIATOR_AGENT:
+		req_dev = omap2_get_l3_device();
+		break;
+	case OCP_TARGET_AGENT:
+		/* Fixme: need the device for L4 interconnect */
+		break;
+	}
 
-	return 0;
+	return _set_dev_constraint(OMAP_PM_CONSTRAINT_THROUGHPUT,
+				   req_dev, dev, t);
 }
 
+/*
+ * omap_pm_set_max_dev_wakeup_lat - set/release devices wake-up latency
+ * constraints
+ */
 int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
 				   long t)
 {
-	if (!req_dev || !dev || t < -1) {
-		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
-		return -EINVAL;
-	};
-
-	if (t == -1)
-		pr_debug("OMAP PM: remove max device latency constraint: "
-			 "dev %s\n", dev_name(dev));
-	else
-		pr_debug("OMAP PM: add max device latency constraint: "
-			 "dev %s, t = %ld usec\n", dev_name(dev), t);
-
-	/*
-	 * For current Linux, this needs to map the device to a
-	 * powerdomain, then go through the list of current max lat
-	 * constraints on that powerdomain and find the smallest.  If
-	 * the latency constraint has changed, the code should
-	 * recompute the state to enter for the next powerdomain
-	 * state.  Conceivably, this code should also determine
-	 * whether to actually disable the device clocks or not,
-	 * depending on how long it takes to re-enable the clocks.
-	 *
-	 * TI CDP code can call constraint_set here.
-	 */
-
-	return 0;
+	return _set_dev_constraint(OMAP_PM_CONSTRAINT_WKUP_LAT, req_dev,
+				   dev, t);
 }
 
-int omap_pm_set_max_sdma_lat(struct device *dev, long t)
+/*
+ * omap_pm_set_max_mpu_wakeup_lat - set/release MPU wake-up latency
+ * constraints
+ *
+ * Maps to _set_dev_constraint with OMAP_PM_CONSTRAINT_WKUP_LAT
+ * as constraint class and the MPU device as constraints target.
+ */
+int omap_pm_set_max_mpu_wakeup_lat(struct device *req_dev, long t)
 {
-	if (!dev || t < -1) {
-		WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
-		return -EINVAL;
-	};
-
-	if (t == -1)
-		pr_debug("OMAP PM: remove max DMA latency constraint: "
-			 "dev %s\n", dev_name(dev));
-	else
-		pr_debug("OMAP PM: add max DMA latency constraint: "
-			 "dev %s, t = %ld usec\n", dev_name(dev), t);
-
-	/*
-	 * For current Linux PM QOS params, this code should scan the
-	 * list of maximum CPU and DMA latencies and select the
-	 * smallest, then set cpu_dma_latency pm_qos_param
-	 * accordingly.
-	 *
-	 * For future Linux PM QOS params, with separate CPU and DMA
-	 * latency params, this code should just set the dma_latency param.
-	 *
-	 * TI CDP code can call constraint_set here.
-	 */
+	return _set_dev_constraint(OMAP_PM_CONSTRAINT_WKUP_LAT, req_dev,
+				   omap2_get_mpuss_device(), t);
+}
 
-	return 0;
+/*
+ * omap_pm_set_max_sdma_lat - set/release SDMA start latency
+ * constraints
+ *
+ * Currently maps to _set_dev_constraint with OMAP_PM_CONSTRAINT_WKUP_LAT
+ * as constraint class and the L3 device as constraints target.
+ */
+int omap_pm_set_max_sdma_lat(struct device *req_dev, long t)
+{
+	return _set_dev_constraint(OMAP_PM_CONSTRAINT_WKUP_LAT, req_dev,
+				   omap2_get_l3_device(), t);
 }
 
 int omap_pm_set_min_clk_rate(struct device *dev, struct clk *c, long r)
-- 
1.7.2.5

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

* [PATCH 8/8] OMAP PM: early init of the pwrdms states
  2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
                   ` (6 preceding siblings ...)
  2011-03-30 15:19 ` [PATCH 7/8] OMAP: PM CONSTRAINTS: implement wake-up latency constraints jean.pihet at newoldbits.com
@ 2011-03-30 15:19 ` jean.pihet at newoldbits.com
  7 siblings, 0 replies; 11+ messages in thread
From: jean.pihet at newoldbits.com @ 2011-03-30 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jean Pihet <j-pihet@ti.com>

The powerdomains next states are initialized in pwrdms_setup as a
late_initcall. Because the wake-up constraint can be requested
early in the boot sequence, the power domains next states can be
overwritten by pwrdms_setup.

This patch fixes it by initializing the power domains next states
early at boot, so that the constraints can be applied.
Later in the pwrdms_setup function the currently programmed
next states are re-used as next state values.

Applies to OMAP3 and OMAP4.

Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
on MPU, CORE and PER.

Signed-off-by: Jean Pihet <j-pihet@ti.com>
---
 arch/arm/mach-omap2/pm34xx.c      |    2 +-
 arch/arm/mach-omap2/pm44xx.c      |    2 +-
 arch/arm/mach-omap2/powerdomain.c |    5 +++++
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 0c5e3a4..8d202a7 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -840,7 +840,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_RET;
+	pwrst->next_state = pwrdm_read_next_pwrst(pwrdm);
 	list_add(&pwrst->node, &pwrst_list);
 
 	if (pwrdm_has_hdwr_sar(pwrdm))
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 76cfff2..ed35482 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -84,7 +84,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_ON;
+	pwrdm->state = pwrdm_read_pwrst(pwrdm);
 	list_add(&pwrst->node, &pwrst_list);
 
 	return pwrdm_set_next_pwrst(pwrst->pwrdm, pwrst->next_state);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index b8d3860..ac8a2d7 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -78,6 +78,7 @@ static struct powerdomain *_pwrdm_lookup(const char *name)
 static int _pwrdm_register(struct powerdomain *pwrdm)
 {
 	int i;
+	int next_state = PWRDM_POWER_RET;
 
 	if (!pwrdm || !pwrdm->name)
 		return -EINVAL;
@@ -114,6 +115,10 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	pwrdm_wait_transition(pwrdm);
 	pwrdm->state = pwrdm_read_pwrst(pwrdm);
 	pwrdm->state_counter[pwrdm->state] = 1;
+	/* Early init of the next power state */
+	if (cpu_is_omap44xx())
+		next_state = PWRDM_POWER_ON;
+	pwrdm_set_next_pwrst(pwrdm, next_state);
 
 	pr_debug("powerdomain: registered %s\n", pwrdm->name);
 
-- 
1.7.2.5

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

* [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints
  2011-03-30 15:19 ` [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints jean.pihet at newoldbits.com
@ 2011-03-31 11:20   ` Sergei Shtylyov
  2011-03-31 11:29   ` Russell King - ARM Linux
  1 sibling, 0 replies; 11+ messages in thread
From: Sergei Shtylyov @ 2011-03-31 11:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hello.

On 30-03-2011 19:19, jean.pihet at newoldbits.com wrote:

> From: Jean Pihet<j-pihet@ti.com>

> Hwmod is queried from the omap device layer to manage the power domains
> wake-up latency constraints. Hwmod retrieves the correct power domain
> and if it exists it calls the corresponding power domain function.

> Tested on OMAP3 Beagleboard in RET/OFF using wake-up latency constraints
> on MPU, CORE and PER.

> Signed-off-by: Jean Pihet<j-pihet@ti.com>
[...]

> diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
> index e034294..62de888 100644
> --- a/arch/arm/mach-omap2/omap_hwmod.c
> +++ b/arch/arm/mach-omap2/omap_hwmod.c
[...]
> @@ -2322,11 +2323,34 @@ ohsps_unlock:
>   	return ret;
>   }
>
> +/*
> + * omap_hwmod_set_wkup_constraint- set/release a wake-up latency constraint
> + *
> + * @oh: struct omap_hwmod* to which the target device belongs to.
> + * @cookie: identifier of the constraints list for @oh.
> + * @min_latency: the minimum allowed wake-up latency for @oh.
> + *
> + * Returns 0 upon success.
> + */
> +int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh,
> +				       void *cookie, long min_latency)
> +{
> +	struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
> +
> +	if (!PTR_ERR(pwrdm)) {

    What's the point of calling PTR_ERR() at all, if just '!pwrdm' will give 
the same result?

WBR, Sergei

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

* [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints
  2011-03-30 15:19 ` [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints jean.pihet at newoldbits.com
  2011-03-31 11:20   ` Sergei Shtylyov
@ 2011-03-31 11:29   ` Russell King - ARM Linux
  1 sibling, 0 replies; 11+ messages in thread
From: Russell King - ARM Linux @ 2011-03-31 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 30, 2011 at 05:19:20PM +0200, jean.pihet at newoldbits.com wrote:
> +/*
> + * omap_hwmod_set_wkup_constraint- set/release a wake-up latency constraint
> + *
> + * @oh: struct omap_hwmod* to which the target device belongs to.
> + * @cookie: identifier of the constraints list for @oh.
> + * @min_latency: the minimum allowed wake-up latency for @oh.
> + *
> + * Returns 0 upon success.
> + */
> +int omap_hwmod_set_wkup_lat_constraint(struct omap_hwmod *oh,
> +				       void *cookie, long min_latency)
> +{
> +	struct powerdomain *pwrdm = omap_hwmod_get_pwrdm(oh);
> +
> +	if (!PTR_ERR(pwrdm)) {
> +		pr_err("%s: Error: could not find powerdomain "
> +		       "for %s\n", __func__, oh->name);
> +		return -EINVAL;
> +	}

If omap_hwmod_get_pwrdm() returns errors encoded into pointers, then:

	if (IS_ERR(pwrdm)) {
		...
		return PTR_ERR(pwrdm);
	}

If it doesn't, then:

	if (!pwrdm) {
		...
		return -EINVAL;
	}

Note that PTR_ERR returns true for both valid error codes and valid
pointers.  Use the interface correctly and don't take shortcuts.  They
don't work.

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

end of thread, other threads:[~2011-03-31 11:29 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-30 15:19 [PATCH v3 0/8] OMAP: add PM CONSTRAINTS framework jean.pihet at newoldbits.com
2011-03-30 15:19 ` [PATCH 1/8] OMAP PM: create a PM layer plugin for per-device constraints jean.pihet at newoldbits.com
2011-03-30 15:19 ` [PATCH 2/8] OMAP2+: powerdomain: control power domains next state jean.pihet at newoldbits.com
2011-03-30 15:19 ` [PATCH 3/8] OMAP3: powerdomain data: add wake-up latency figures jean.pihet at newoldbits.com
2011-03-30 15:19 ` [PATCH 4/8] OMAP2+: omap_hwmod: manage the omap_devices the wake-up latency constraints jean.pihet at newoldbits.com
2011-03-31 11:20   ` Sergei Shtylyov
2011-03-31 11:29   ` Russell King - ARM Linux
2011-03-30 15:19 ` [PATCH 5/8] OMAP: PM CONSTRAINTS: add an enum for the classes of constraint jean.pihet at newoldbits.com
2011-03-30 15:19 ` [PATCH 6/8] OMAP2+: omap_device: implement the constraints management code jean.pihet at newoldbits.com
2011-03-30 15:19 ` [PATCH 7/8] OMAP: PM CONSTRAINTS: implement wake-up latency constraints jean.pihet at newoldbits.com
2011-03-30 15:19 ` [PATCH 8/8] OMAP PM: early init of the pwrdms states jean.pihet at newoldbits.com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).