diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index d13b3b355d8f..66820e4b6391 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -1309,27 +1309,32 @@ error: } #endif -static void send_vsync_work(struct work_struct *work) -{ - char buf[64]; - char *envp[2]; - - snprintf(buf, sizeof(buf), "VSYNC=%llu", - ktime_to_ns(vsync_cntrl.vsync_time)); - envp[0] = buf; - envp[1] = NULL; - kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp); -} - #ifdef CONFIG_FB_MSM_MDP303 /* vsync_isr_handler: Called from isr context*/ static void vsync_isr_handler(void) { vsync_cntrl.vsync_time = ktime_get(); - schedule_work(&(vsync_cntrl.vsync_work)); } #endif +static ssize_t vsync_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + if (atomic_read(&vsync_cntrl.suspend) > 0 || + atomic_read(&vsync_cntrl.vsync_resume) == 0) + return 0; + + INIT_COMPLETION(vsync_cntrl.vsync_wait); + + wait_for_completion(&vsync_cntrl.vsync_wait); + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", + ktime_to_ns(vsync_cntrl.vsync_time)); + buf[strlen(buf) + 1] = '\0'; + return ret; +} + /* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */ int mdp_ppp_pipe_wait(void) { @@ -1814,6 +1819,8 @@ irqreturn_t mdp_isr(int irq, void *ptr) if (!vsync_isr) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + + complete_all(&vsync_cntrl.vsync_wait); } /* DMA3 TV-Out Start */ @@ -1882,6 +1889,8 @@ irqreturn_t mdp_isr(int irq, void *ptr) if (!vsync_isr) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + + complete_all(&vsync_cntrl.vsync_wait); } /* DMA2 LCD-Out Complete */ @@ -2011,8 +2020,9 @@ static void mdp_drv_init(void) for (i = 0; i < MDP_MAX_BLOCK; i++) { atomic_set(&mdp_block_power_cnt[i], 0); } - INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work); vsync_cntrl.disabled_clocks = 1; + init_completion(&vsync_cntrl.vsync_wait); + atomic_set(&vsync_cntrl.vsync_resume, 1); #ifdef MSM_FB_ENABLE_DBGFS { struct dentry *root; @@ -2098,7 +2108,9 @@ static int mdp_off(struct platform_device *pdev) pr_debug("%s:+\n", __func__); mdp_histogram_ctrl_all(FALSE); - + atomic_set(&vsync_cntrl.suspend, 1); + atomic_set(&vsync_cntrl.vsync_resume, 0); + complete_all(&vsync_cntrl.vsync_wait); mdp_clk_ctrl(1); if (mfd->panel.type == MIPI_CMD_PANEL) mdp4_dsi_cmd_off(pdev); @@ -2129,7 +2141,16 @@ void mdp4_hw_init(void) { /* empty */ } + #endif +static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); +static struct attribute *vsync_fs_attrs[] = { + &dev_attr_vsync_event.attr, + NULL, +}; +static struct attribute_group vsync_fs_attr_group = { + .attrs = vsync_fs_attrs, +}; static int mdp_on(struct platform_device *pdev) { @@ -2159,10 +2180,26 @@ static int mdp_on(struct platform_device *pdev) mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); } - if ((mdp_rev == MDP_REV_303) && - (mfd->panel.type == MIPI_CMD_PANEL)) + if (mdp_rev == MDP_REV_303 && mfd->panel.type == MIPI_CMD_PANEL) { + vsync_cntrl.dev = mfd->fbi->dev; + if (!vsync_cntrl.sysfs_created) { + ret = sysfs_create_group(&vsync_cntrl.dev->kobj, + &vsync_fs_attr_group); + if (ret) { + pr_err("%s: sysfs creation failed, ret=%d\n", + __func__, ret); + return ret; + } + + kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD); + pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); + vsync_cntrl.sysfs_created = 1; + } + atomic_set(&vsync_cntrl.suspend, 0); + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); ret = panel_next_on(pdev); diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h index 21195b132992..77e16867bf78 100644 --- a/drivers/video/msm/mdp.h +++ b/drivers/video/msm/mdp.h @@ -97,6 +97,10 @@ struct vsync { struct work_struct vsync_work; int vsync_irq_enabled; int disabled_clocks; + struct completion vsync_wait; + atomic_t suspend; + atomic_t vsync_resume; + int sysfs_created; }; extern struct vsync vsync_cntrl; diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c index 68c45d46feed..cee40c29f93c 100644 --- a/drivers/video/msm/mdp_dma.c +++ b/drivers/video/msm/mdp_dma.c @@ -520,6 +520,9 @@ void mdp_dma_vsync_ctrl(int enable) return; spin_lock_irqsave(&mdp_spin_lock, flag); + if (!enable) + INIT_COMPLETION(vsync_cntrl.vsync_wait); + vsync_cntrl.vsync_irq_enabled = enable; if (!enable) vsync_cntrl.disabled_clocks = 0; @@ -536,6 +539,9 @@ void mdp_dma_vsync_ctrl(int enable) mdp_enable_irq(MDP_VSYNC_TERM); spin_unlock_irqrestore(&mdp_spin_lock, flag); } + if (vsync_cntrl.vsync_irq_enabled && + atomic_read(&vsync_cntrl.suspend) == 0) + atomic_set(&vsync_cntrl.vsync_resume, 1); } void mdp_lcd_update_workqueue_handler(struct work_struct *work) diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c index ed224c28e7e8..e2fb8ba8d42b 100644 --- a/drivers/video/msm/mdp_dma_dsi_video.c +++ b/drivers/video/msm/mdp_dma_dsi_video.c @@ -34,6 +34,33 @@ static int first_pixel_start_x; static int first_pixel_start_y; +static ssize_t vsync_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + INIT_COMPLETION(vsync_cntrl.vsync_wait); + + if (atomic_read(&vsync_cntrl.suspend) > 0 || + atomic_read(&vsync_cntrl.vsync_resume) == 0) + return 0; + + wait_for_completion(&vsync_cntrl.vsync_wait); + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", + ktime_to_ns(vsync_cntrl.vsync_time)); + buf[strlen(buf) + 1] = '\0'; + return ret; +} + +static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); +static struct attribute *vsync_fs_attrs[] = { + &dev_attr_vsync_event.attr, + NULL, +}; +static struct attribute_group vsync_fs_attr_group = { + .attrs = vsync_fs_attrs, +}; + int mdp_dsi_video_on(struct platform_device *pdev) { int dsi_width; @@ -88,6 +115,7 @@ int mdp_dsi_video_on(struct platform_device *pdev) var = &fbi->var; vsync_cntrl.dev = mfd->fbi->dev; + atomic_set(&vsync_cntrl.suspend, 0); bpp = fbi->var.bits_per_pixel / 8; buf = (uint8 *) fbi->fix.smem_start; @@ -226,6 +254,20 @@ int mdp_dsi_video_on(struct platform_device *pdev) /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + if (!vsync_cntrl.sysfs_created) { + ret = sysfs_create_group(&vsync_cntrl.dev->kobj, + &vsync_fs_attr_group); + if (ret) { + pr_err("%s: sysfs creation failed, ret=%d\n", + __func__, ret); + return ret; + } + + kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD); + pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); + vsync_cntrl.sysfs_created = 1; + } + return ret; } @@ -241,6 +283,10 @@ int mdp_dsi_video_off(struct platform_device *pdev) mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); ret = panel_next_off(pdev); + + atomic_set(&vsync_cntrl.suspend, 1); + atomic_set(&vsync_cntrl.vsync_resume, 0); + complete_all(&vsync_cntrl.vsync_wait); /* delay to make sure the last frame finishes */ msleep(20); @@ -255,6 +301,9 @@ void mdp_dma_video_vsync_ctrl(int enable) return; spin_lock_irqsave(&mdp_spin_lock, flag); + if (!enable) + INIT_COMPLETION(vsync_cntrl.vsync_wait); + vsync_cntrl.vsync_irq_enabled = enable; if (!enable) vsync_cntrl.disabled_clocks = 0; @@ -270,6 +319,9 @@ void mdp_dma_video_vsync_ctrl(int enable) mdp_enable_irq(MDP_VSYNC_TERM); spin_unlock_irqrestore(&mdp_spin_lock, flag); } + if (vsync_cntrl.vsync_irq_enabled && + atomic_read(&vsync_cntrl.suspend) == 0) + atomic_set(&vsync_cntrl.vsync_resume, 1); } void mdp_dsi_video_update(struct msm_fb_data_type *mfd) diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c index 6146b45ebd70..fbfe35f3bd65 100644 --- a/drivers/video/msm/mdp_dma_lcdc.c +++ b/drivers/video/msm/mdp_dma_lcdc.c @@ -51,6 +51,33 @@ extern uint32 mdp_intr_mask; int first_pixel_start_x; int first_pixel_start_y; +static ssize_t vsync_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + if (atomic_read(&vsync_cntrl.suspend) > 0 || + atomic_read(&vsync_cntrl.vsync_resume) == 0) + return 0; + + INIT_COMPLETION(vsync_cntrl.vsync_wait); + + wait_for_completion(&vsync_cntrl.vsync_wait); + ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", + ktime_to_ns(vsync_cntrl.vsync_time)); + buf[strlen(buf) + 1] = '\0'; + return ret; +} + +static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL); +static struct attribute *vsync_fs_attrs[] = { + &dev_attr_vsync_event.attr, + NULL, +}; +static struct attribute_group vsync_fs_attr_group = { + .attrs = vsync_fs_attrs, +}; + int mdp_lcdc_on(struct platform_device *pdev) { int lcdc_width; @@ -106,6 +133,7 @@ int mdp_lcdc_on(struct platform_device *pdev) fbi = mfd->fbi; var = &fbi->var; vsync_cntrl.dev = mfd->fbi->dev; + atomic_set(&vsync_cntrl.suspend, 0); /* MDP cmd block enable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); @@ -292,6 +320,20 @@ int mdp_lcdc_on(struct platform_device *pdev) /* MDP cmd block disable */ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + if (!vsync_cntrl.sysfs_created) { + ret = sysfs_create_group(&vsync_cntrl.dev->kobj, + &vsync_fs_attr_group); + if (ret) { + pr_err("%s: sysfs creation failed, ret=%d\n", + __func__, ret); + return ret; + } + + kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD); + pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__); + vsync_cntrl.sysfs_created = 1; + } + return ret; } @@ -321,6 +363,9 @@ int mdp_lcdc_off(struct platform_device *pdev) ret = panel_next_off(pdev); up(&mfd->dma->mutex); + atomic_set(&vsync_cntrl.suspend, 1); + atomic_set(&vsync_cntrl.vsync_resume, 0); + complete_all(&vsync_cntrl.vsync_wait); /* delay to make sure the last frame finishes */ msleep(16); @@ -336,6 +381,9 @@ void mdp_dma_lcdc_vsync_ctrl(int enable) return; spin_lock_irqsave(&mdp_spin_lock, flag); + if (!enable) + INIT_COMPLETION(vsync_cntrl.vsync_wait); + vsync_cntrl.vsync_irq_enabled = enable; if (!enable) vsync_cntrl.disabled_clocks = 0; @@ -351,6 +399,10 @@ void mdp_dma_lcdc_vsync_ctrl(int enable) mdp_enable_irq(MDP_VSYNC_TERM); spin_unlock_irqrestore(&mdp_spin_lock, flag); } + + if (vsync_cntrl.vsync_irq_enabled && + atomic_read(&vsync_cntrl.suspend) == 0) + atomic_set(&vsync_cntrl.vsync_resume, 1); } void mdp_lcdc_update(struct msm_fb_data_type *mfd)