aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorManjunathappa, Prakash <prakash.pm@ti.com>2012-07-18 11:31:56 -0400
committerFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2012-07-28 21:09:27 -0400
commitdeb95c6c958f5ba97b6b89ab18917bf79cb8ce7b (patch)
treebfaa9d4baaee6cf4232be798bfe88095c74acc50 /drivers/video
parent8a81dccd391a3e78f502da137de8fb62020c5809 (diff)
video: da8xx-fb: fix flicker due to 1 frame delay in updated frame
Flicker/tearing effect is observed with current FB driver. Issue is because of 2 active DMA channels ping ponging among them along with usage of 2 DDR ping pong buffers in driver. Application unaware of active DMA channel keeps updating frame being displayed, this leads to tearing effect. Below steps describes the issue: 1)Initially assume both buffers FB0 and FB1 are programmed for buffer-0. 2)On EOF0: Program FB0 for buffer-1, indicate(wake up) application to fill up buffer-0. As FB1 is active and continues to DMA buffer-0 (which is being filled), leading to tearing/flickering issue. 3)On EOF1: Program FB1 for buffer-0, indicate(wake up) application to fill up buffer-1. As FB0 is active and continues to DMA buffer-1(which is being filled), leading to tearing/flickering issue. 4)On EOF0: Program FB0 for buffer-1, indicate(wake up) application to fill up buffer-0. As FB1 is active and continues to DMA buffer-0(which is being filled), leading to tearing/flickering issue. ... Above steps depict that issue is because of 1 frame delay in frame panned by application. Patch fixes the issue by keeping track free DMA channel and configures it in drivers PAN callback so that panned frame from application gets displayed in next frame period. Wiki below describes the issue in detail and it also has link to application with which issue can be reproduced. http://processors.wiki.ti.com/index.php/DA8xx_LCDC_Linux_FB_FAQs Signed-off-by: Nellutla, Aditya <aditya.n@ti.com> Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com> Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/da8xx-fb.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 7264aa3b20ff..6b7f2da6f907 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -30,6 +30,7 @@
30#include <linux/clk.h> 30#include <linux/clk.h>
31#include <linux/cpufreq.h> 31#include <linux/cpufreq.h>
32#include <linux/console.h> 32#include <linux/console.h>
33#include <linux/spinlock.h>
33#include <linux/slab.h> 34#include <linux/slab.h>
34#include <linux/lcm.h> 35#include <linux/lcm.h>
35#include <video/da8xx-fb.h> 36#include <video/da8xx-fb.h>
@@ -161,6 +162,13 @@ struct da8xx_fb_par {
161 wait_queue_head_t vsync_wait; 162 wait_queue_head_t vsync_wait;
162 int vsync_flag; 163 int vsync_flag;
163 int vsync_timeout; 164 int vsync_timeout;
165 spinlock_t lock_for_chan_update;
166
167 /*
168 * LCDC has 2 ping pong DMA channels, channel 0
169 * and channel 1.
170 */
171 unsigned int which_dma_channel_done;
164#ifdef CONFIG_CPU_FREQ 172#ifdef CONFIG_CPU_FREQ
165 struct notifier_block freq_transition; 173 struct notifier_block freq_transition;
166 unsigned int lcd_fck_rate; 174 unsigned int lcd_fck_rate;
@@ -741,6 +749,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
741 lcdc_write(stat, LCD_MASKED_STAT_REG); 749 lcdc_write(stat, LCD_MASKED_STAT_REG);
742 750
743 if (stat & LCD_END_OF_FRAME0) { 751 if (stat & LCD_END_OF_FRAME0) {
752 par->which_dma_channel_done = 0;
744 lcdc_write(par->dma_start, 753 lcdc_write(par->dma_start,
745 LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); 754 LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
746 lcdc_write(par->dma_end, 755 lcdc_write(par->dma_end,
@@ -750,6 +759,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
750 } 759 }
751 760
752 if (stat & LCD_END_OF_FRAME1) { 761 if (stat & LCD_END_OF_FRAME1) {
762 par->which_dma_channel_done = 1;
753 lcdc_write(par->dma_start, 763 lcdc_write(par->dma_start,
754 LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); 764 LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
755 lcdc_write(par->dma_end, 765 lcdc_write(par->dma_end,
@@ -796,6 +806,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
796 lcdc_write(stat, LCD_STAT_REG); 806 lcdc_write(stat, LCD_STAT_REG);
797 807
798 if (stat & LCD_END_OF_FRAME0) { 808 if (stat & LCD_END_OF_FRAME0) {
809 par->which_dma_channel_done = 0;
799 lcdc_write(par->dma_start, 810 lcdc_write(par->dma_start,
800 LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); 811 LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
801 lcdc_write(par->dma_end, 812 lcdc_write(par->dma_end,
@@ -805,6 +816,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
805 } 816 }
806 817
807 if (stat & LCD_END_OF_FRAME1) { 818 if (stat & LCD_END_OF_FRAME1) {
819 par->which_dma_channel_done = 1;
808 lcdc_write(par->dma_start, 820 lcdc_write(par->dma_start,
809 LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); 821 LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
810 lcdc_write(par->dma_end, 822 lcdc_write(par->dma_end,
@@ -1053,6 +1065,7 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
1053 struct fb_fix_screeninfo *fix = &fbi->fix; 1065 struct fb_fix_screeninfo *fix = &fbi->fix;
1054 unsigned int end; 1066 unsigned int end;
1055 unsigned int start; 1067 unsigned int start;
1068 unsigned long irq_flags;
1056 1069
1057 if (var->xoffset != fbi->var.xoffset || 1070 if (var->xoffset != fbi->var.xoffset ||
1058 var->yoffset != fbi->var.yoffset) { 1071 var->yoffset != fbi->var.yoffset) {
@@ -1070,6 +1083,21 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
1070 end = start + fbi->var.yres * fix->line_length - 1; 1083 end = start + fbi->var.yres * fix->line_length - 1;
1071 par->dma_start = start; 1084 par->dma_start = start;
1072 par->dma_end = end; 1085 par->dma_end = end;
1086 spin_lock_irqsave(&par->lock_for_chan_update,
1087 irq_flags);
1088 if (par->which_dma_channel_done == 0) {
1089 lcdc_write(par->dma_start,
1090 LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
1091 lcdc_write(par->dma_end,
1092 LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
1093 } else if (par->which_dma_channel_done == 1) {
1094 lcdc_write(par->dma_start,
1095 LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
1096 lcdc_write(par->dma_end,
1097 LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
1098 }
1099 spin_unlock_irqrestore(&par->lock_for_chan_update,
1100 irq_flags);
1073 } 1101 }
1074 } 1102 }
1075 1103
@@ -1299,6 +1327,8 @@ static int __devinit fb_probe(struct platform_device *device)
1299 /* initialize the vsync wait queue */ 1327 /* initialize the vsync wait queue */
1300 init_waitqueue_head(&par->vsync_wait); 1328 init_waitqueue_head(&par->vsync_wait);
1301 par->vsync_timeout = HZ / 5; 1329 par->vsync_timeout = HZ / 5;
1330 par->which_dma_channel_done = -1;
1331 spin_lock_init(&par->lock_for_chan_update);
1302 1332
1303 /* Register the Frame Buffer */ 1333 /* Register the Frame Buffer */
1304 if (register_framebuffer(da8xx_fb_info) < 0) { 1334 if (register_framebuffer(da8xx_fb_info) < 0) {