aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVibhore Vardhan <vvardhan@ti.com>2011-05-30 21:05:41 -0500
committerNishanth Menon <nm@ti.com>2011-06-13 16:37:43 -0500
commit4accc4deb59cc91934888f9a36f6f8b1f94ec5da (patch)
treeff1db3c0fabf1402074459c6e0d27a9c8f9f2672
parent6a63f50d02ec2d97b70f7af360d63f8b7efdcde7 (diff)
downloadkernel_samsung_tuna-4accc4deb59cc91934888f9a36f6f8b1f94ec5da.zip
kernel_samsung_tuna-4accc4deb59cc91934888f9a36f6f8b1f94ec5da.tar.gz
kernel_samsung_tuna-4accc4deb59cc91934888f9a36f6f8b1f94ec5da.tar.bz2
OMAP PM: Device wakeup latency constraint framework
This patch implements device wakeup latency constraint framework. Using omap_pm_set_max_dev_wakeup_lat(), drivers can specify the maximum amount of time for a device to become accessible after its clocks are enabled. This is done by restricting the power states that the parent powerdomain of a device can be put into. Only power states with profiled wakeup latency value less than the requested constraint get selected while the constraint is active. Ported from 2.6.35 by Axel Haslam <axelhaslam@ti.com> Signed-off-by: Vibhore Vardhan <vvardhan@ti.com> Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>
-rw-r--r--arch/arm/mach-omap2/powerdomain.c172
-rw-r--r--arch/arm/mach-omap2/powerdomain.h34
-rw-r--r--arch/arm/mach-omap2/powerdomains3xxx_data.c60
-rw-r--r--arch/arm/mach-omap2/powerdomains44xx_data.c78
-rw-r--r--arch/arm/plat-omap/omap-pm.c47
5 files changed, 383 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af0847..cd541d3 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -19,6 +19,8 @@
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/slab.h>
+
#include <trace/events/power.h>
#include "cm2xxx_3xxx.h"
@@ -108,6 +110,13 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
pwrdm->state = pwrdm_read_pwrst(pwrdm);
pwrdm->state_counter[pwrdm->state] = 1;
+ /* Initialize priority ordered list for wakeup latency constraint */
+ spin_lock_init(&pwrdm->wakeuplat_lock);
+ plist_head_init(&pwrdm->wakeuplat_dev_list, &pwrdm->wakeuplat_lock);
+
+ /* res_mutex protects res_list add and del ops */
+ mutex_init(&pwrdm->wakeuplat_mutex);
+
pr_debug("powerdomain: registered %s\n", pwrdm->name);
return 0;
@@ -208,6 +217,7 @@ void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs)
{
struct powerdomain **p = NULL;
+
if (!custom_funcs)
WARN(1, "powerdomain: No custom pwrdm functions registered\n");
else
@@ -999,3 +1009,165 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
return 0;
}
+
+
+/**
+ * pwrdm_wakeuplat_set_constraint - Set powerdomain wakeup latency constraint
+ * @pwrdm: struct powerdomain * to which requesting device belongs to
+ * @dev: struct device * of requesting device
+ * @t: wakeup latency constraint in microseconds
+ *
+ * Adds new entry to powerdomain's wakeup latency constraint list.
+ * If the requesting device already exists in the list, old value is
+ * overwritten. Checks whether current power state is still adequate.
+ * Returns -EINVAL if the powerdomain or device pointer is NULL,
+ * or -ENOMEM if kmalloc fails, or -ERANGE if constraint can't be met,
+ * or returns 0 upon success.
+ */
+int pwrdm_wakeuplat_set_constraint (struct powerdomain *pwrdm,
+ struct device *dev, unsigned long t)
+{
+ struct wakeuplat_dev_list *user;
+ int found = 0, ret = 0;
+
+ if (!pwrdm || !dev) {
+ WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pwrdm->wakeuplat_mutex);
+
+ plist_for_each_entry(user, &pwrdm->wakeuplat_dev_list, node) {
+ if (user->dev == dev) {
+ found = 1;
+ break;
+ }
+ }
+
+ /* Add new entry to the list or update existing request */
+ if (found && user->constraint_us == t) {
+ goto exit_set;
+ } else if (!found) {
+ user = kzalloc(sizeof(struct wakeuplat_dev_list), GFP_KERNEL);
+ if (!user) {
+ pr_err("OMAP PM: FATAL ERROR: kzalloc failed\n");
+ ret = -ENOMEM;
+ goto exit_set;
+ }
+ user->dev = dev;
+ } else {
+ plist_del(&user->node, &pwrdm->wakeuplat_dev_list);
+ }
+
+ plist_node_init(&user->node, t);
+ plist_add(&user->node, &pwrdm->wakeuplat_dev_list);
+ user->node.prio = user->constraint_us = t;
+
+ ret = pwrdm_wakeuplat_update_pwrst(pwrdm);
+
+exit_set:
+ mutex_unlock(&pwrdm->wakeuplat_mutex);
+
+ return ret;
+}
+
+/**
+ * pwrdm_wakeuplat_release_constraint - Release powerdomain wkuplat constraint
+ * @pwrdm: struct powerdomain * to which requesting device belongs to
+ * @dev: struct device * of requesting device
+ *
+ * Removes device's entry from powerdomain's wakeup latency constraint list.
+ * Checks whether current power state is still adequate.
+ * Returns -EINVAL if the powerdomain or device pointer is NULL or
+ * no such entry exists in the list, or returns 0 upon success.
+ */
+int pwrdm_wakeuplat_release_constraint (struct powerdomain *pwrdm,
+ struct device *dev)
+{
+ struct wakeuplat_dev_list *user;
+ int found = 0, ret = 0;
+
+ if (!pwrdm || !dev) {
+ WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pwrdm->wakeuplat_mutex);
+
+ plist_for_each_entry(user, &pwrdm->wakeuplat_dev_list, node) {
+ if (user->dev == dev) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("OMAP PM: Error: no prior constraint to release\n");
+ ret = -EINVAL;
+ goto exit_rls;
+ }
+
+ plist_del(&user->node, &pwrdm->wakeuplat_dev_list);
+ kfree(user);
+
+ ret = pwrdm_wakeuplat_update_pwrst(pwrdm);
+
+exit_rls:
+ mutex_unlock(&pwrdm->wakeuplat_mutex);
+
+ return ret;
+}
+
+/**
+ * pwrdm_wakeuplat_update_pwrst - Update power domain power state if needed
+ * @pwrdm: struct powerdomain * to which requesting device belongs to
+ *
+ * Finds minimum latency value from all entries in the list and
+ * the power domain power state neeting the constraint. Programs
+ * new state if it is different from current power state.
+ * Returns -EINVAL if the powerdomain or device pointer is NULL or
+ * no such entry exists in the list, or -ERANGE if constraint can't be met,
+ * or returns 0 upon success.
+ */
+int pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm)
+{
+ struct plist_node *node;
+ int ret = 0, new_state;
+ unsigned long min_latency = -1;
+
+ if (!plist_head_empty(&pwrdm->wakeuplat_dev_list)) {
+ node = plist_last(&pwrdm->wakeuplat_dev_list);
+ min_latency = node->prio;
+ }
+
+ /* Find power state with wakeup latency < minimum constraint. */
+ for (new_state = 0x0; new_state < PWRDM_MAX_PWRSTS; new_state++) {
+ if (min_latency == -1 ||
+ pwrdm->wakeup_lat[new_state] < min_latency)
+ break;
+ }
+
+ /* No power state wkuplat met constraint. Keep power domain ON. */
+ if (new_state == PWRDM_MAX_PWRSTS) {
+ new_state = PWRDM_FUNC_PWRST_ON;
+ ret = -ERANGE;
+ }
+
+ /* OSWR is not supported, set CSWR instead. TODO: add OSWR support */
+ if (new_state == PWRDM_FUNC_PWRST_OSWR)
+ new_state = PWRDM_FUNC_PWRST_CSWR;
+
+ if (pwrdm->state != new_state) {
+ if (cpu_is_omap44xx())
+ omap4_set_pwrdm_state(pwrdm, new_state);
+ else if (cpu_is_omap34xx())
+ set_pwrdm_state(pwrdm, new_state);
+ }
+
+ pr_debug("OMAP PM: %s pwrst: curr= %d, prev= %d next= %d "
+ "wkuplat_min= %lu, 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;
+}
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 32a92e5..cf04390 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -19,6 +19,9 @@
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/plist.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/atomic.h>
@@ -84,6 +87,16 @@
/* XXX A completely arbitrary number. What is reasonable here? */
#define PWRDM_TRANSITION_BAILOUT 100000
+/* 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_ON 0x3
+
+#define PWRDM_MAX_FUNC_PWRSTS 4
+
+#define UNSUP_STATE -1
+
struct clockdomain;
struct powerdomain;
@@ -105,8 +118,10 @@ struct powerdomain;
* @state_counter:
* @timer:
* @state_timer:
- *
- * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
+ * @wakeup_lat: Wakeup latencies for possible powerdomain power states
+ * @wakeuplat_lock: spinlock for plist
+ * @wakeuplat_dev_list: plist_head linking all devices placing constraint
+ * @wa * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
*/
struct powerdomain {
const char *name;
@@ -130,6 +145,16 @@ struct powerdomain {
s64 timer;
s64 state_timer[PWRDM_MAX_PWRSTS];
#endif
+ const u32 wakeup_lat[PWRDM_MAX_FUNC_PWRSTS];
+ spinlock_t wakeuplat_lock;
+ struct plist_head wakeuplat_dev_list;
+ struct mutex wakeuplat_mutex;
+};
+
+struct wakeuplat_dev_list {
+ struct device *dev;
+ unsigned long constraint_us;
+ struct plist_node node;
};
/**
@@ -238,5 +263,10 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank);
extern struct powerdomain wkup_omap2_pwrdm;
extern struct powerdomain gfx_omap2_pwrdm;
+int pwrdm_wakeuplat_set_constraint(struct powerdomain *pwrdm,
+ struct device *dev, unsigned long t);
+int pwrdm_wakeuplat_release_constraint(struct powerdomain *pwrdm,
+ struct device *dev);
+int pwrdm_wakeuplat_update_pwrst(struct powerdomain *pwrdm);
#endif
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index 469a920..278caff 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -52,6 +52,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain mpu_3xxx_pwrdm = {
@@ -68,6 +74,12 @@ 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_ON] = 0,
+ },
};
/*
@@ -98,6 +110,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -121,6 +139,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain dss_pwrdm = {
@@ -136,6 +160,12 @@ 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_ON] = 0,
+ },
};
/*
@@ -157,6 +187,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain cam_pwrdm = {
@@ -172,6 +208,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain per_pwrdm = {
@@ -187,6 +229,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain emu_pwrdm = {
@@ -201,6 +249,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain usbhost_pwrdm = {
@@ -223,6 +277,12 @@ 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_ON] = 0,
+ },
};
static struct powerdomain dpll1_pwrdm = {
diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index e970d18..288b310 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -54,6 +54,12 @@ static struct powerdomain core_44xx_pwrdm = {
[4] = PWRSTS_ON, /* ducati_unicache */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* gfx_44xx_pwrdm: 3D accelerator power domain */
@@ -71,6 +77,12 @@ static struct powerdomain gfx_44xx_pwrdm = {
[0] = PWRSTS_ON, /* gfx_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* abe_44xx_pwrdm: Audio back end power domain */
@@ -91,6 +103,12 @@ static struct powerdomain abe_44xx_pwrdm = {
[1] = PWRSTS_ON, /* periphmem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* dss_44xx_pwrdm: Display subsystem power domain */
@@ -109,6 +127,12 @@ static struct powerdomain dss_44xx_pwrdm = {
[0] = PWRSTS_ON, /* dss_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* tesla_44xx_pwrdm: Tesla processor power domain */
@@ -131,6 +155,12 @@ static struct powerdomain tesla_44xx_pwrdm = {
[2] = PWRSTS_ON, /* tesla_l2 */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* wkup_44xx_pwrdm: Wake-up power domain */
@@ -164,6 +194,12 @@ static struct powerdomain cpu0_44xx_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* cpu0_l1 */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */
@@ -181,6 +217,12 @@ static struct powerdomain cpu1_44xx_pwrdm = {
.pwrsts_mem_on = {
[0] = PWRSTS_ON, /* cpu1_l1 */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* emu_44xx_pwrdm: Emulation power domain */
@@ -218,6 +260,12 @@ static struct powerdomain mpu_443x_pwrdm = {
[1] = PWRSTS_ON, /* mpu_l2 */
[2] = PWRSTS_ON, /* mpu_ram */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
static struct powerdomain mpu_446x_pwrdm = {
@@ -236,6 +284,12 @@ static struct powerdomain mpu_446x_pwrdm = {
[0] = PWRSTS_ON, /* mpu_l2 */
[1] = PWRSTS_ON, /* mpu_ram */
},
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* ivahd_44xx_pwrdm: IVA-HD power domain */
@@ -260,6 +314,12 @@ static struct powerdomain ivahd_44xx_pwrdm = {
[3] = PWRSTS_ON, /* tcm2_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* cam_44xx_pwrdm: Camera subsystem power domain */
@@ -277,6 +337,12 @@ static struct powerdomain cam_44xx_pwrdm = {
[0] = PWRSTS_ON, /* cam_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_CSWR] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* l3init_44xx_pwrdm: L3 initators pheripherals power domain */
@@ -295,6 +361,12 @@ static struct powerdomain l3init_44xx_pwrdm = {
[0] = PWRSTS_ON, /* l3init_bank1 */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = 1000,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/* l4per_44xx_pwrdm: Target peripherals power domain */
@@ -315,6 +387,12 @@ static struct powerdomain l4per_44xx_pwrdm = {
[1] = PWRSTS_ON, /* retained_bank */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
+ .wakeup_lat = {
+ [PWRDM_FUNC_PWRST_OFF] = UNSUP_STATE,
+ [PWRDM_FUNC_PWRST_OSWR] = 600,
+ [PWRDM_FUNC_PWRST_CSWR] = 300,
+ [PWRDM_FUNC_PWRST_ON] = 0,
+ },
};
/*
diff --git a/arch/arm/plat-omap/omap-pm.c b/arch/arm/plat-omap/omap-pm.c
index bc8b39a..6292a6c 100644
--- a/arch/arm/plat-omap/omap-pm.c
+++ b/arch/arm/plat-omap/omap-pm.c
@@ -20,7 +20,7 @@
/* Interface documentation is in mach/omap-pm.h */
#include <plat/omap-pm.h>
-
+#include <plat/omap_device.h>
#include <plat/powerdomain.h>
struct omap_opp *dsp_opps;
@@ -81,17 +81,52 @@ int omap_pm_set_min_bus_tput(struct device *dev, u8 agent_id, unsigned long r)
int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
long t)
{
+ struct omap_device *odev;
+ struct powerdomain *pwrdm_dev;
+ struct platform_device *pdev;
+ int ret = 0;
+
if (!req_dev || !dev || t < -1) {
WARN(1, "OMAP PM: %s: invalid parameter(s)", __func__);
return -EINVAL;
};
- if (t == -1)
+ /* Look for the devices Power Domain */
+ pdev = container_of(dev, struct platform_device, dev);
+
+ /* Try to catch non platform devices. */
+ if (pdev->name == NULL) {
+ pr_err("OMAP-PM: Error: platform device not valid\n");
+ return -EINVAL;
+ }
+
+ odev = to_omap_device(pdev);
+ if (odev) {
+ pwrdm_dev = omap_device_get_pwrdm(odev);
+ } else {
+ pr_err("OMAP-PM: Error: Could not find omap_device "
+ "for %s\n", pdev->name);
+ return -EINVAL;
+ }
+
+ /* Catch devices with undefined powerdomains. */
+ if (!pwrdm_dev) {
+ pr_err("OMAP-PM: Error: could not find parent "
+ "powerdomain for %s\n", pdev->name);
+ return -EINVAL;
+ }
+
+ if (t == -1) {
pr_debug("OMAP PM: remove max device latency constraint: "
- "dev %s\n", dev_name(dev));
- else
+ "dev %s, pwrdm %s, req by %s\n", dev_name(dev),
+ pwrdm_dev->name, dev_name(req_dev));
+ ret = pwrdm_wakeuplat_release_constraint(pwrdm_dev, req_dev);
+ } else {
pr_debug("OMAP PM: add max device latency constraint: "
- "dev %s, t = %ld usec\n", dev_name(dev), t);
+ "dev %s, t = %ld usec, pwrdm %s, req by %s\n",
+ dev_name(dev), t, pwrdm_dev->name, dev_name(req_dev));
+ ret = pwrdm_wakeuplat_set_constraint(pwrdm_dev, req_dev, t);
+ }
/*
* For current Linux, this needs to map the device to a
@@ -106,7 +141,7 @@ int omap_pm_set_max_dev_wakeup_lat(struct device *req_dev, struct device *dev,
* TI CDP code can call constraint_set here.
*/
- return 0;
+ return ret;
}
int omap_pm_set_max_sdma_lat(struct pm_qos_request_list **qos_request,