From 29c9acd4383978dd6069fa590a6eddb416bddaff Mon Sep 17 00:00:00 2001 From: yxj Date: Thu, 24 Jan 2013 11:05:08 +0800 Subject: [PATCH] rk3188 lcdc:add vsync support --- drivers/video/rockchip/lcdc/rk3188_lcdc.c | 73 +++++++++++++++++++++++ drivers/video/rockchip/lcdc/rk3188_lcdc.h | 2 + 2 files changed, 75 insertions(+) diff --git a/drivers/video/rockchip/lcdc/rk3188_lcdc.c b/drivers/video/rockchip/lcdc/rk3188_lcdc.c index c02ebf1c97ac..6bc01db5f7d0 100644 --- a/drivers/video/rockchip/lcdc/rk3188_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3188_lcdc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -678,6 +679,30 @@ static int rk3188_lcdc_blank(struct rk_lcdc_device_driver *dev_drv, static int rk3188_lcdc_ioctl(struct rk_lcdc_device_driver *dev_drv, unsigned int cmd,unsigned long arg,int layer_id) { + struct rk3188_lcdc_device *lcdc_dev = + container_of(dev_drv,struct rk3188_lcdc_device,driver); + u32 panel_size[2]; + void __user *argp = (void __user *)arg; + int enable; + switch(cmd) + { + case FBIOGET_PANEL_SIZE: //get panel size + panel_size[0] = lcdc_dev->screen->x_res; + panel_size[1] = lcdc_dev->screen->y_res; + if(copy_to_user(argp, panel_size, 8)) + return -EFAULT; + break; + case RK_FBIOSET_CONFIG_DONE: + lcdc_cfg_done(lcdc_dev); + break; + case RK_FBIOSET_VSYNC_ENABLE: + if (copy_from_user(&enable, argp, sizeof(enable))) + return -EFAULT; + lcdc_dev->vsync_info.active = enable; + break; + default: + break; + } return 0; } @@ -992,6 +1017,35 @@ static int rk3188_set_dsp_lut(struct rk_lcdc_device_driver *dev_drv,int *lut) return ret; } + +static int lcdc_wait_for_vsync_thread(void *data) +{ + struct rk3188_lcdc_device *lcdc_dev = data; + + while (!kthread_should_stop()) { + ktime_t timestamp = lcdc_dev->vsync_info.timestamp; + int ret = wait_event_interruptible(lcdc_dev->vsync_info.wait, + !ktime_equal(timestamp, lcdc_dev->vsync_info.timestamp) && + lcdc_dev->vsync_info.active); + + if (!ret) { + sysfs_notify(&lcdc_dev->driver.dev->kobj, NULL, "vsync"); + } + } + + return 0; +} + +static ssize_t rk3188_lcdc_vsync_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rk3188_lcdc_device *lcdc_dev = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%llu\n", + ktime_to_ns(lcdc_dev->vsync_info.timestamp)); +} + +static DEVICE_ATTR(vsync, S_IRUGO, rk3188_lcdc_vsync_show, NULL); + static struct layer_par lcdc_layer[] = { [0] = { .name = "win0", @@ -1031,6 +1085,7 @@ static irqreturn_t rk3188_lcdc_isr(int irq, void *dev_id) { struct rk3188_lcdc_device *lcdc_dev = (struct rk3188_lcdc_device *)dev_id; + ktime_t timestamp = ktime_get(); lcdc_msk_reg(lcdc_dev, INT_STATUS, m_FS_INT_CLEAR, v_FS_INT_CLEAR(1)); @@ -1042,6 +1097,9 @@ static irqreturn_t rk3188_lcdc_isr(int irq, void *dev_id) spin_unlock(&(lcdc_dev->driver.cpl_lock)); } #endif + lcdc_dev->vsync_info.timestamp = timestamp; + wake_up_interruptible_all(&lcdc_dev->vsync_info.wait); + return IRQ_HANDLED; } @@ -1166,6 +1224,21 @@ static int __devinit rk3188_lcdc_probe(struct platform_device *pdev) ret = -ENODEV; goto err4; } + + init_waitqueue_head(&lcdc_dev->vsync_info.wait); + ret = device_create_file(&pdev->dev, &dev_attr_vsync); + if (ret) { + dev_err(&pdev->dev, "failed to create vsync file\n"); + } + lcdc_dev->vsync_info.thread = kthread_run(lcdc_wait_for_vsync_thread, + lcdc_dev, "lcdc-vsync"); + + + if (lcdc_dev->vsync_info.thread == ERR_PTR(-ENOMEM)) { + dev_err(&pdev->dev, "failed to run vsync thread\n"); + lcdc_dev->vsync_info.thread = NULL; + } + lcdc_dev->vsync_info.active = 1; ret = rk_fb_register(&(lcdc_dev->driver),&lcdc_driver,lcdc_dev->id); if(ret < 0) diff --git a/drivers/video/rockchip/lcdc/rk3188_lcdc.h b/drivers/video/rockchip/lcdc/rk3188_lcdc.h index 2426cc341db7..ac19a3623895 100644 --- a/drivers/video/rockchip/lcdc/rk3188_lcdc.h +++ b/drivers/video/rockchip/lcdc/rk3188_lcdc.h @@ -305,6 +305,8 @@ struct rk3188_lcdc_device{ bool clk_on; //if aclk or hclk is closed ,acess to register is not allowed u8 atv_layer_cnt; //active layer counter,when atv_layer_cnt = 0,disable lcdc + + struct rk_fb_vsync vsync_info; unsigned int irq; -- 2.34.1