summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntti Hatala <ahatala@nvidia.com>2010-03-16 05:34:18 -0700
committerGary King <gking@nvidia.com>2010-03-16 11:48:18 -0800
commitb11af049255663bfc437e17657192f0127cf0064 (patch)
tree28e67c1d727e51da408fa7e104f69d7c9f57ccea
parentede4eb643d23adbb79e9434905a06f88a3b5fe81 (diff)
tegra power: implement early_suspend handler for display power
For proper power behavior Android expects the display to be turned off and on in the early_suspend stages instead of as a part of the actual suspend sequence. Add notifications for display on/off in the nvrm power notification interface, and call them at appropriate times. When CONFIG_HAS_EARLYSUSPEND is not defined, continue to notify nvrm_daemon in the power manager suspend/resume calls. Tabify & whitespace cleanup nvrm_user.c. Change-Id: Ie0129e0a5812352e97c95c4f323928d907782dee Reviewed-on: http://git-master/r/866 Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Gary King <gking@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/nvrm_user.c485
1 files changed, 255 insertions, 230 deletions
diff --git a/arch/arm/mach-tegra/nvrm_user.c b/arch/arm/mach-tegra/nvrm_user.c
index d830ac3f139c..6ebee8c58562 100644
--- a/arch/arm/mach-tegra/nvrm_user.c
+++ b/arch/arm/mach-tegra/nvrm_user.c
@@ -31,6 +31,9 @@
#include <linux/freezer.h>
#include <linux/suspend.h>
#include <linux/percpu.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
#include <asm/cpu.h>
#include "nvcommon.h"
#include "nvassert.h"
@@ -291,160 +294,160 @@ long nvrm_unlocked_ioctl(struct file *file,
}
break;
case NvRmIoctls_NvRmGetClientId:
- err = NvOsCopyIn(&p, (void*)arg, sizeof(p));
- if (err != NvSuccess)
- {
- NvOsDebugPrintf("NvRmIoctls_NvRmGetClientId: copy in failed\n");
- goto fail;
- }
-
- NV_ASSERT(p.InBufferSize == 0);
- NV_ASSERT(p.OutBufferSize == sizeof(NvRtClientHandle));
- NV_ASSERT(p.InOutBufferSize == 0);
-
- if (NvOsCopyOut(p.pBuffer,
- &file->private_data,
- sizeof(NvRtClientHandle)) != NvSuccess)
- {
- NvOsDebugPrintf("Failed to copy client id\n");
- goto fail;
- }
- break;
- case NvRmIoctls_NvRmClientAttach:
- {
- NvRtClientHandle Client;
-
- err = NvOsCopyIn(&p, (void*)arg, sizeof(p));
- if (err != NvSuccess)
- {
- NvOsDebugPrintf("NvRmIoctls_NvRmClientAttach: copy in failed\n");
- goto fail;
- }
-
- NV_ASSERT(p.InBufferSize == sizeof(NvRtClientHandle));
- NV_ASSERT(p.OutBufferSize == 0);
- NV_ASSERT(p.InOutBufferSize == 0);
-
- if (NvOsCopyIn((void*)&Client,
- p.pBuffer,
- sizeof(NvRtClientHandle)) != NvSuccess)
- {
- NvOsDebugPrintf("Failed to copy client id\n");
- goto fail;
- }
-
- NV_ASSERT(Client || !"Bad client");
-
- if (Client == (NvRtClientHandle)file->private_data)
- {
- // The daemon is attaching to itself, no need to add refcount
- break;
- }
- if (NvRtAddClientRef(s_RtHandle, Client) != NvSuccess)
- {
- NvOsDebugPrintf("Client ref add unsuccessful\n");
- goto fail;
- }
- break;
- }
- case NvRmIoctls_NvRmClientDetach:
- {
- NvRtClientHandle Client;
-
- err = NvOsCopyIn(&p, (void*)arg, sizeof(p));
- if (err != NvSuccess)
- {
- NvOsDebugPrintf("NvRmIoctls_NvRmClientAttach: copy in failed\n");
- goto fail;
- }
-
- NV_ASSERT(p.InBufferSize == sizeof(NvRtClientHandle));
- NV_ASSERT(p.OutBufferSize == 0);
- NV_ASSERT(p.InOutBufferSize == 0);
-
- if (NvOsCopyIn((void*)&Client,
- p.pBuffer,
- sizeof(NvRtClientHandle)) != NvSuccess)
- {
- NvOsDebugPrintf("Failed to copy client id\n");
- goto fail;
- }
-
- NV_ASSERT(Client || !"Bad client");
-
- if (Client == (NvRtClientHandle)file->private_data)
- {
- // The daemon is detaching from itself, no need to dec refcount
- break;
- }
-
- client_detach(Client);
- break;
- }
- // FIXME: power ioctls?
- default:
- printk( "unknown ioctl code\n" );
- goto fail;
- }
+ err = NvOsCopyIn(&p, (void*)arg, sizeof(p));
+ if (err != NvSuccess)
+ {
+ NvOsDebugPrintf("NvRmIoctls_NvRmGetClientId: copy in failed\n");
+ goto fail;
+ }
+
+ NV_ASSERT(p.InBufferSize == 0);
+ NV_ASSERT(p.OutBufferSize == sizeof(NvRtClientHandle));
+ NV_ASSERT(p.InOutBufferSize == 0);
+
+ if (NvOsCopyOut(p.pBuffer,
+ &file->private_data,
+ sizeof(NvRtClientHandle)) != NvSuccess)
+ {
+ NvOsDebugPrintf("Failed to copy client id\n");
+ goto fail;
+ }
+ break;
+ case NvRmIoctls_NvRmClientAttach:
+ {
+ NvRtClientHandle Client;
+
+ err = NvOsCopyIn(&p, (void*)arg, sizeof(p));
+ if (err != NvSuccess)
+ {
+ NvOsDebugPrintf("NvRmIoctls_NvRmClientAttach: copy in failed\n");
+ goto fail;
+ }
+
+ NV_ASSERT(p.InBufferSize == sizeof(NvRtClientHandle));
+ NV_ASSERT(p.OutBufferSize == 0);
+ NV_ASSERT(p.InOutBufferSize == 0);
+
+ if (NvOsCopyIn((void*)&Client,
+ p.pBuffer,
+ sizeof(NvRtClientHandle)) != NvSuccess)
+ {
+ NvOsDebugPrintf("Failed to copy client id\n");
+ goto fail;
+ }
+
+ NV_ASSERT(Client || !"Bad client");
+
+ if (Client == (NvRtClientHandle)file->private_data)
+ {
+ // The daemon is attaching to itself, no need to add refcount
+ break;
+ }
+ if (NvRtAddClientRef(s_RtHandle, Client) != NvSuccess)
+ {
+ NvOsDebugPrintf("Client ref add unsuccessful\n");
+ goto fail;
+ }
+ break;
+ }
+ case NvRmIoctls_NvRmClientDetach:
+ {
+ NvRtClientHandle Client;
+
+ err = NvOsCopyIn(&p, (void*)arg, sizeof(p));
+ if (err != NvSuccess)
+ {
+ NvOsDebugPrintf("NvRmIoctls_NvRmClientAttach: copy in failed\n");
+ goto fail;
+ }
+
+ NV_ASSERT(p.InBufferSize == sizeof(NvRtClientHandle));
+ NV_ASSERT(p.OutBufferSize == 0);
+ NV_ASSERT(p.InOutBufferSize == 0);
+
+ if (NvOsCopyIn((void*)&Client,
+ p.pBuffer,
+ sizeof(NvRtClientHandle)) != NvSuccess)
+ {
+ NvOsDebugPrintf("Failed to copy client id\n");
+ goto fail;
+ }
+
+ NV_ASSERT(Client || !"Bad client");
+
+ if (Client == (NvRtClientHandle)file->private_data)
+ {
+ // The daemon is detaching from itself, no need to dec refcount
+ break;
+ }
+
+ client_detach(Client);
+ break;
+ }
+ // FIXME: power ioctls?
+ default:
+ printk( "unknown ioctl code\n" );
+ goto fail;
+ }
- e = 0;
- goto clean;
+ e = 0;
+ goto clean;
fail:
- e = -EINVAL;
+ e = -EINVAL;
clean:
- if( bAlloc )
- {
- NvOsFree( ptr );
- }
+ if( bAlloc )
+ {
+ NvOsFree( ptr );
+ }
- return e;
+ return e;
}
int nvrm_mmap(struct file *file, struct vm_area_struct *vma)
{
- return 0;
+ return 0;
}
static int nvrm_probe(struct platform_device *pdev)
{
- int e = 0;
- NvU32 NumTypes = NvRtObjType_NvRm_Num;
+ int e = 0;
+ NvU32 NumTypes = NvRtObjType_NvRm_Num;
- printk("nvrm probe\n");
+ printk("nvrm probe\n");
- NV_ASSERT(s_RtHandle == NULL);
+ NV_ASSERT(s_RtHandle == NULL);
- if (NvRtCreate(1, &NumTypes, &s_RtHandle) != NvSuccess)
- {
- e = -ENOMEM;
- }
+ if (NvRtCreate(1, &NumTypes, &s_RtHandle) != NvSuccess)
+ {
+ e = -ENOMEM;
+ }
- if (e == 0)
- {
- e = misc_register( &nvrm_dev );
- }
+ if (e == 0)
+ {
+ e = misc_register( &nvrm_dev );
+ }
- if( e < 0 )
- {
- if (s_RtHandle)
- {
- NvRtDestroy(s_RtHandle);
- s_RtHandle = NULL;
- }
+ if( e < 0 )
+ {
+ if (s_RtHandle)
+ {
+ NvRtDestroy(s_RtHandle);
+ s_RtHandle = NULL;
+ }
- printk("nvrm probe failed to open\n");
- }
- return e;
+ printk("nvrm probe failed to open\n");
+ }
+ return e;
}
static int nvrm_remove(struct platform_device *pdev)
{
- misc_deregister( &nvrm_dev );
- NvRtDestroy(s_RtHandle);
- s_RtHandle = NULL;
- return 0;
+ misc_deregister( &nvrm_dev );
+ NvRtDestroy(s_RtHandle);
+ s_RtHandle = NULL;
+ return 0;
}
static int nvrm_suspend(struct platform_device *pdev, pm_message_t state)
@@ -468,11 +471,11 @@ static int nvrm_resume(struct platform_device *pdev)
static struct platform_driver nvrm_driver =
{
- .probe = nvrm_probe,
- .remove = nvrm_remove,
- .suspend = nvrm_suspend,
- .resume = nvrm_resume,
- .driver = { .name = "nvrm" }
+ .probe = nvrm_probe,
+ .remove = nvrm_remove,
+ .suspend = nvrm_suspend,
+ .resume = nvrm_resume,
+ .driver = { .name = "nvrm" }
};
#if defined(CONFIG_PM)
@@ -487,140 +490,162 @@ struct kobject *nvrm_kobj;
char* nvrm_notifier;
-#define STRING_PM_NONE "none" // initial state
+#define STRING_PM_NONE "none" // initial state
#define STRING_PM_SUSPEND_PREPARE "PM_SUSPEND_PREPARE" // notify to daemon
-#define STRING_PM_POST_SUSPEND "PM_POST_SUSPEND" // notify to daemon
-#define STRING_PM_CONTINUE "PM_CONTINUE" // reply from daemon
-#define STRING_PM_SIGNAL "PM_SIGNAL" // request signal
+#define STRING_PM_POST_SUSPEND "PM_POST_SUSPEND" // notify to daemon
+#define STRING_PM_DISPLAY_OFF "PM_DISPLAY_OFF" // notify to daemon
+#define STRING_PM_DISPLAY_ON "PM_DISPLAY_ON" // notify to daemon
+#define STRING_PM_CONTINUE "PM_CONTINUE" // reply from daemon
+#define STRING_PM_SIGNAL "PM_SIGNAL" // request signal
ssize_t
nvrm_notifier_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
- return sprintf(buf, "%s\n", nvrm_notifier);
+ return sprintf(buf, "%s\n", nvrm_notifier);
}
ssize_t
nvrm_notifier_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
- printk(KERN_INFO "%s: /sys/power/nvrm/notifier=%s\n", __func__, buf);
+ printk(KERN_INFO "%s: /sys/power/nvrm/notifier=%s\n", __func__, buf);
- if (! strcmp(buf, STRING_PM_CONTINUE))
- {
- nvrm_notifier = STRING_PM_CONTINUE;
-
- // Wake up pm_notifier.
- tegra_pm_notifier_continue_ok = 1;
- wake_up(&tegra_pm_notifier_wait);
- }
- else if (! strncmp(buf, STRING_PM_SIGNAL, strlen(STRING_PM_SIGNAL)))
- {
- s_nvrm_daemon_pid = 0;
- s_nvrm_daemon_sig = 0;
- sscanf(buf, STRING_PM_SIGNAL " %d %d",
- &s_nvrm_daemon_pid, &s_nvrm_daemon_sig);
- printk(KERN_INFO "%s: nvrm_daemon=%d signal=%d\n",
- __func__, s_nvrm_daemon_pid, s_nvrm_daemon_sig);
- }
- else
- {
- printk(KERN_ERR "%s: Wrong value '%s'.\n", __func__, buf);
- }
+ if (!strcmp(buf, STRING_PM_CONTINUE)) {
+ // Wake up pm_notifier.
+ tegra_pm_notifier_continue_ok = 1;
+ wake_up(&tegra_pm_notifier_wait);
+ }
+ else if (!strncmp(buf, STRING_PM_SIGNAL, strlen(STRING_PM_SIGNAL))) {
+ s_nvrm_daemon_pid = 0;
+ s_nvrm_daemon_sig = 0;
+ sscanf(buf, STRING_PM_SIGNAL " %d %d",
+ &s_nvrm_daemon_pid, &s_nvrm_daemon_sig);
+ printk(KERN_INFO "%s: nvrm_daemon=%d signal=%d\n",
+ __func__, s_nvrm_daemon_pid, s_nvrm_daemon_sig);
+ }
+ else {
+ printk(KERN_ERR "%s: Wrong value '%s'.\n", __func__, buf);
+ }
- return count;
+ return count;
}
static struct kobj_attribute nvrm_notifier_attribute =
- __ATTR(notifier, 0666, nvrm_notifier_show, nvrm_notifier_store);
+ __ATTR(notifier, 0666, nvrm_notifier_show, nvrm_notifier_store);
//
// PM notifier
//
-int tegra_pm_notifier(struct notifier_block *nb,
- unsigned long event, void *nouse)
+static void notify_daemon(char* notice)
{
- int err;
- long timeout = HZ * 30;
+ long timeout = HZ * 30;
+ int err;
- printk(KERN_INFO "%s: event=%lx\n", __func__, event);
+ // In case daemon's pid is not reported, do not signal or wait.
+ if (!s_nvrm_daemon_pid) {
+ printk(KERN_ERR "%s: Don't know nvrm_daemon's PID.\n", __func__);
+ return;
+ }
- // Notify the event to nvrm_daemon.
- if (event == PM_SUSPEND_PREPARE)
- {
- tegra_pm_notifier_continue_ok = 0; // Clear before kicking nvrm_daemon.
- nvrm_notifier = STRING_PM_SUSPEND_PREPARE;
- }
- else if (event == PM_POST_SUSPEND)
- {
- tegra_pm_notifier_continue_ok = 0; // Clear before kicking nvrm_daemon.
- nvrm_notifier = STRING_PM_POST_SUSPEND;
- }
- else
- {
- printk(KERN_ERR "%s: Unknown event %ld.\n", __func__, event);
- return NOTIFY_DONE;
- }
+ // Clear before kicking nvrm_daemon.
+ tegra_pm_notifier_continue_ok = 0;
+ nvrm_notifier = notice;
- // In case if daemon's pid is not reported, do not signal or wait.
- if (! s_nvrm_daemon_pid)
- {
- printk(KERN_ERR "%s: Don't know nvrm_daemon's PID.\n", __func__);
- return NOTIFY_DONE;
- }
+ // Send signal to nvrm_daemon.
+ printk(KERN_INFO "%s: Sending signal=%d to pid=%d.\n",
+ __func__, s_nvrm_daemon_sig, s_nvrm_daemon_pid);
- // Send signal to nvrm_daemon.
- printk(KERN_INFO "%s: Sending signal=%d to pid=%d.\n",
- __func__, s_nvrm_daemon_sig, s_nvrm_daemon_pid);
- err = kill_pid(find_get_pid(s_nvrm_daemon_pid), s_nvrm_daemon_sig, 0);
- if (err)
- {
- printk(KERN_ERR "%s: Cannot send signal to nvrm_daemon (PID=%d).\n",
- __func__, s_nvrm_daemon_pid);
- return NOTIFY_DONE;
- }
+ err = kill_pid(find_get_pid(s_nvrm_daemon_pid), s_nvrm_daemon_sig, 0);
+ if (err) {
+ printk(KERN_ERR "%s: Cannot send signal to nvrm_daemon (PID=%d).\n",
+ __func__, s_nvrm_daemon_pid);
+ }
+ else {
+ // Wait for the reply from nvrm_daemon.
+ printk(KERN_INFO "%s: Wait for nvrm_daemon.\n", __func__);
+ if (wait_event_timeout(tegra_pm_notifier_wait,
+ tegra_pm_notifier_continue_ok, timeout) == 0) {
+ printk(KERN_ERR "%s: Timed out. nvrm_daemon did not reply.\n", __func__);
+ }
+ }
- // Wait for the reply from nvrm_daemon.
- printk(KERN_INFO "%s: Wait for nvrm_daemon.\n", __func__);
- timeout = wait_event_timeout(tegra_pm_notifier_wait,
- tegra_pm_notifier_continue_ok, timeout);
+ // Go back to the initial state.
+ nvrm_notifier = STRING_PM_NONE;
+}
- // Go back to the initial state.
- nvrm_notifier = STRING_PM_NONE;
+int tegra_pm_notifier(struct notifier_block *nb,
+ unsigned long event, void *nouse)
+{
+ printk(KERN_INFO "%s: event=%lx\n", __func__, event);
- // In case of timeout.
- if (timeout == 0)
- {
- printk(KERN_ERR "%s: Timed out. nvrm_daemon did not reply.\n", __func__);
- return NOTIFY_DONE;
- }
+ // Notify the event to nvrm_daemon.
+ if (event == PM_SUSPEND_PREPARE) {
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ notify_daemon(STRING_PM_DISPLAY_OFF);
+#endif
+ notify_daemon(STRING_PM_SUSPEND_PREPARE);
+ }
+ else if (event == PM_POST_SUSPEND) {
+ notify_daemon(STRING_PM_POST_SUSPEND);
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ notify_daemon(STRING_PM_DISPLAY_ON);
+#endif
+ }
+ else {
+ printk(KERN_ERR "%s: Unknown event %ld.\n", __func__, event);
+ return NOTIFY_DONE;
+ }
+
+ printk(KERN_INFO "%s: Woken up.\n", __func__);
+ return NOTIFY_OK;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void tegra_display_off(struct early_suspend *h)
+{
+ notify_daemon(STRING_PM_DISPLAY_OFF);
+}
- printk(KERN_INFO "%s: Woken up.\n", __func__);
- return NOTIFY_OK;
+void tegra_display_on(struct early_suspend *h)
+{
+ notify_daemon(STRING_PM_DISPLAY_ON);
}
+
+static struct early_suspend tegra_display_power =
+{
+ .suspend = tegra_display_off,
+ .resume = tegra_display_on,
+ .level = EARLY_SUSPEND_LEVEL_DISABLE_FB
+};
+#endif
#endif
static int __init nvrm_init(void)
{
- int ret = 0;
- printk(KERN_INFO "%s called\n", __func__);
+ int ret = 0;
+ printk(KERN_INFO "%s called\n", __func__);
+
+ #if defined(CONFIG_PM)
+ // Register PM notifier.
+ pm_notifier(tegra_pm_notifier, 0);
+ init_waitqueue_head(&tegra_pm_notifier_wait);
- #if defined(CONFIG_PM)
- // Register PM notifier.
- pm_notifier(tegra_pm_notifier, 0);
- init_waitqueue_head(&tegra_pm_notifier_wait);
+ #if defined(CONFIG_HAS_EARLYSUSPEND)
+ register_early_suspend(&tegra_display_power);
+ #endif
- // Create /sys/power/nvrm/notifier.
- nvrm_kobj = kobject_create_and_add("nvrm", power_kobj);
- sysfs_create_file(nvrm_kobj, &nvrm_notifier_attribute.attr);
- nvrm_notifier = STRING_PM_NONE;
- #endif
+ // Create /sys/power/nvrm/notifier.
+ nvrm_kobj = kobject_create_and_add("nvrm", power_kobj);
+ sysfs_create_file(nvrm_kobj, &nvrm_notifier_attribute.attr);
+ nvrm_notifier = STRING_PM_NONE;
+ #endif
- // Register NvRm platform driver.
- ret= platform_driver_register(&nvrm_driver);
+ // Register NvRm platform driver.
+ ret = platform_driver_register(&nvrm_driver);
- return ret;
+ return ret;
}
static void __exit nvrm_deinit(void)