|
@@ -30,6 +30,7 @@
|
|
|
#include <linux/clk.h>
|
|
|
#include <linux/cpufreq.h>
|
|
|
#include <linux/console.h>
|
|
|
+#include <linux/spinlock.h>
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/lcm.h>
|
|
|
#include <video/da8xx-fb.h>
|
|
@@ -161,6 +162,13 @@ struct da8xx_fb_par {
|
|
|
wait_queue_head_t vsync_wait;
|
|
|
int vsync_flag;
|
|
|
int vsync_timeout;
|
|
|
+ spinlock_t lock_for_chan_update;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * LCDC has 2 ping pong DMA channels, channel 0
|
|
|
+ * and channel 1.
|
|
|
+ */
|
|
|
+ unsigned int which_dma_channel_done;
|
|
|
#ifdef CONFIG_CPU_FREQ
|
|
|
struct notifier_block freq_transition;
|
|
|
unsigned int lcd_fck_rate;
|
|
@@ -741,6 +749,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
|
|
|
lcdc_write(stat, LCD_MASKED_STAT_REG);
|
|
|
|
|
|
if (stat & LCD_END_OF_FRAME0) {
|
|
|
+ par->which_dma_channel_done = 0;
|
|
|
lcdc_write(par->dma_start,
|
|
|
LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
|
|
|
lcdc_write(par->dma_end,
|
|
@@ -750,6 +759,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
|
|
|
}
|
|
|
|
|
|
if (stat & LCD_END_OF_FRAME1) {
|
|
|
+ par->which_dma_channel_done = 1;
|
|
|
lcdc_write(par->dma_start,
|
|
|
LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
|
|
|
lcdc_write(par->dma_end,
|
|
@@ -796,6 +806,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
|
|
|
lcdc_write(stat, LCD_STAT_REG);
|
|
|
|
|
|
if (stat & LCD_END_OF_FRAME0) {
|
|
|
+ par->which_dma_channel_done = 0;
|
|
|
lcdc_write(par->dma_start,
|
|
|
LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
|
|
|
lcdc_write(par->dma_end,
|
|
@@ -805,6 +816,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
|
|
|
}
|
|
|
|
|
|
if (stat & LCD_END_OF_FRAME1) {
|
|
|
+ par->which_dma_channel_done = 1;
|
|
|
lcdc_write(par->dma_start,
|
|
|
LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
|
|
|
lcdc_write(par->dma_end,
|
|
@@ -1053,6 +1065,7 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
|
|
|
struct fb_fix_screeninfo *fix = &fbi->fix;
|
|
|
unsigned int end;
|
|
|
unsigned int start;
|
|
|
+ unsigned long irq_flags;
|
|
|
|
|
|
if (var->xoffset != fbi->var.xoffset ||
|
|
|
var->yoffset != fbi->var.yoffset) {
|
|
@@ -1070,6 +1083,21 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var,
|
|
|
end = start + fbi->var.yres * fix->line_length - 1;
|
|
|
par->dma_start = start;
|
|
|
par->dma_end = end;
|
|
|
+ spin_lock_irqsave(&par->lock_for_chan_update,
|
|
|
+ irq_flags);
|
|
|
+ if (par->which_dma_channel_done == 0) {
|
|
|
+ lcdc_write(par->dma_start,
|
|
|
+ LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
|
|
|
+ lcdc_write(par->dma_end,
|
|
|
+ LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
|
|
|
+ } else if (par->which_dma_channel_done == 1) {
|
|
|
+ lcdc_write(par->dma_start,
|
|
|
+ LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
|
|
|
+ lcdc_write(par->dma_end,
|
|
|
+ LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&par->lock_for_chan_update,
|
|
|
+ irq_flags);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1299,6 +1327,8 @@ static int __devinit fb_probe(struct platform_device *device)
|
|
|
/* initialize the vsync wait queue */
|
|
|
init_waitqueue_head(&par->vsync_wait);
|
|
|
par->vsync_timeout = HZ / 5;
|
|
|
+ par->which_dma_channel_done = -1;
|
|
|
+ spin_lock_init(&par->lock_for_chan_update);
|
|
|
|
|
|
/* Register the Frame Buffer */
|
|
|
if (register_framebuffer(da8xx_fb_info) < 0) {
|