diff options
author | Antti Hatala <ahatala@nvidia.com> | 2010-03-16 05:34:18 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-03-16 11:48:18 -0800 |
commit | b11af049255663bfc437e17657192f0127cf0064 (patch) | |
tree | 28e67c1d727e51da408fa7e104f69d7c9f57ccea /arch/arm | |
parent | ede4eb643d23adbb79e9434905a06f88a3b5fe81 (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>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-tegra/nvrm_user.c | 485 |
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) |