diff options
author | Daniel Hillenbrand <daniel.hillenbrand@codeworkx.de> | 2012-07-27 02:03:16 +0200 |
---|---|---|
committer | Daniel Hillenbrand <daniel.hillenbrand@codeworkx.de> | 2012-07-27 02:20:26 +0200 |
commit | e4ab2a76603300c573de592a00aed5096533b032 (patch) | |
tree | ebd839e7eb8d046f31af4ba2e1e48eb164ac1963 /drivers/video | |
parent | 5eb00c0353bc1987b1e40759c172dd2a839a4707 (diff) | |
download | kernel_samsung_smdk4412-e4ab2a76603300c573de592a00aed5096533b032.zip kernel_samsung_smdk4412-e4ab2a76603300c573de592a00aed5096533b032.tar.gz kernel_samsung_smdk4412-e4ab2a76603300c573de592a00aed5096533b032.tar.bz2 |
s3cfb: asynchronous vsync notification
Change-Id: Id3642cd25475b3c872b1ae7d4b69d53f122dffa8
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/samsung/s3cfb.h | 4 | ||||
-rw-r--r-- | drivers/video/samsung/s3cfb_main.c | 41 | ||||
-rw-r--r-- | drivers/video/samsung/s3cfb_ops.c | 21 |
3 files changed, 63 insertions, 3 deletions
diff --git a/drivers/video/samsung/s3cfb.h b/drivers/video/samsung/s3cfb.h index 6adb765..b278184 100644 --- a/drivers/video/samsung/s3cfb.h +++ b/drivers/video/samsung/s3cfb.h @@ -178,6 +178,10 @@ struct s3cfb_global { unsigned int wq_count; struct fb_info **fb; + ktime_t vsync_timestamp; + int vsync_state; + struct task_struct *vsync_thread; + atomic_t enabled_win; enum s3cfb_output_t output; enum s3cfb_rgb_mode_t rgb_mode; diff --git a/drivers/video/samsung/s3cfb_main.c b/drivers/video/samsung/s3cfb_main.c index a6e4564..2cb7c86 100644 --- a/drivers/video/samsung/s3cfb_main.c +++ b/drivers/video/samsung/s3cfb_main.c @@ -29,6 +29,7 @@ #include <linux/memory.h> #include <linux/pm_runtime.h> #include <linux/delay.h> +#include <linux/kthread.h> #include <plat/clock.h> #include <plat/media.h> #include <mach/media.h> @@ -57,6 +58,8 @@ #include <mach/regs-pmu.h> #include <plat/regs-fb-s5p.h> +extern int s3cfb_vsync_timestamp_changed(struct s3cfb_global *fbdev, ktime_t prev_timestamp); + struct s3cfb_fimd_desc *fbfimd; inline struct s3cfb_global *get_fimd_global(int id) @@ -91,7 +94,8 @@ static irqreturn_t s3cfb_irq_frame(int irq, void *dev_id) s3cfb_clear_interrupt(fbdev[0]); fbdev[0]->wq_count++; - wake_up(&fbdev[0]->wq); + fbdev[0]->vsync_timestamp = ktime_get(); + wake_up_interruptible(&fbdev[0]->wq); return IRQ_HANDLED; } @@ -318,6 +322,32 @@ void s3cfb_trigger(void) EXPORT_SYMBOL(s3cfb_trigger); #endif +static int s3cfb_wait_for_vsync_thread(void *data) +{ + struct s3cfb_global *fbdev = data; + + while (!kthread_should_stop()) { + ktime_t prev_timestamp = fbdev->vsync_timestamp; + + int ret = wait_event_interruptible_timeout(fbdev->wq, + s3cfb_vsync_timestamp_changed(fbdev, prev_timestamp), + msecs_to_jiffies(100)); + + if (ret > 0) { + char *envp[2]; + char buf[64]; + + snprintf(buf, sizeof(buf), "VSYNC=%llu", + ktime_to_ns(fbdev->vsync_timestamp)); + envp[0] = buf; + envp[1] = NULL; + kobject_uevent_env(&fbdev->dev->kobj, KOBJ_CHANGE, envp); + } + } + + return 0; +} + static int s3cfb_probe(struct platform_device *pdev) { struct s3c_platform_fb *pdata = NULL; @@ -494,6 +524,12 @@ static int s3cfb_probe(struct platform_device *pdev) pdata->lcd_on(pdev); #endif + fbdev[0]->vsync_thread = kthread_run(s3cfb_wait_for_vsync_thread, fbdev[0], "s3cfb-vsync"); + if (fbdev[0]->vsync_thread == ERR_PTR(-ENOMEM)) { + dev_err(fbdev[0]->dev, "failed to run vsync thread\n"); + fbdev[0]->vsync_thread = NULL; + } + ret = device_create_file(&(pdev->dev), &dev_attr_win_power); if (ret < 0) dev_err(fbdev[0]->dev, "failed to add sysfs entries\n"); @@ -565,6 +601,9 @@ static int s3cfb_remove(struct platform_device *pdev) } } + if (fbdev[i]->vsync_thread) + kthread_stop(fbdev[i]->vsync_thread); + kfree(fbdev[i]->fb); kfree(fbdev[i]); } diff --git a/drivers/video/samsung/s3cfb_ops.c b/drivers/video/samsung/s3cfb_ops.c index 3ff2f05..82ece16 100644 --- a/drivers/video/samsung/s3cfb_ops.c +++ b/drivers/video/samsung/s3cfb_ops.c @@ -1082,15 +1082,32 @@ int s3cfb_cursor(struct fb_info *fb, struct fb_cursor *cursor) return 0; } +int s3cfb_vsync_timestamp_changed(struct s3cfb_global *fbdev, ktime_t prev_timestamp) +{ + return !ktime_equal(prev_timestamp, fbdev->vsync_timestamp); +} + int s3cfb_wait_for_vsync(struct s3cfb_global *fbdev) { + ktime_t prev_timestamp; + int ret; + dev_dbg(fbdev->dev, "waiting for VSYNC interrupt\n"); - sleep_on_timeout(&fbdev->wq, HZ / 10); + prev_timestamp = fbdev->vsync_timestamp; + + ret = wait_event_interruptible_timeout(fbdev->wq, + s3cfb_vsync_timestamp_changed(fbdev, prev_timestamp), + msecs_to_jiffies(100)); + + if (ret == 0) + return -ETIMEDOUT; + if (ret < 0) + return ret; dev_dbg(fbdev->dev, "got a VSYNC interrupt\n"); - return 0; + return ret; } int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg) |