summaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorPhil Edworthy <Phil.Edworthy@renesas.com>2010-02-15 13:57:49 +0000
committerPaul Mundt <lethal@linux-sh.org>2010-02-16 13:30:27 +0900
commit40331b21f5fdb746e80fc609ef60ef71b5cd47d9 (patch)
tree66467a8eff27a8f379d433c717bd91bc84c7b6bf /drivers/video
parent04c869735541c27dd137c55f35f8a18bb372bbe1 (diff)
video: sh_mobile_lcdcfb: Add wait for vsync.
Added FBIO_WAITFORVSYNC ioctl for SH-Mobile devices. Tested on MS7724 and MigoR boards against 2.6.33-rc7. Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index a69830d26f7..37aeced2dc1 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -19,6 +19,7 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
+#include <linux/ioctl.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/atomic.h>
@@ -106,6 +107,7 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
#define LDRCNTR_SRC 0x00010000
#define LDRCNTR_MRS 0x00000002
#define LDRCNTR_MRC 0x00000001
+#define LDSR_MRS 0x00000100
struct sh_mobile_lcdc_priv;
struct sh_mobile_lcdc_chan {
@@ -124,6 +126,7 @@ struct sh_mobile_lcdc_chan {
unsigned long pan_offset;
unsigned long new_pan_offset;
wait_queue_head_t frame_end_wait;
+ struct completion vsync_completion;
};
struct sh_mobile_lcdc_priv {
@@ -366,7 +369,8 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
}
/* VSYNC End */
- if (ldintr & LDINTR_VES) {
+ if ((ldintr & LDINTR_VES) &&
+ (ch->pan_offset != ch->new_pan_offset)) {
unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR);
/* Set the source address for the next refresh */
lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle +
@@ -379,6 +383,9 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
ldrcntr ^ LDRCNTR_MRS);
ch->pan_offset = ch->new_pan_offset;
}
+
+ if (ldintr & LDINTR_VES)
+ complete(&ch->vsync_completion);
}
return IRQ_HANDLED;
@@ -786,6 +793,43 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
return 0;
}
+static int sh_mobile_wait_for_vsync(struct fb_info *info)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+ unsigned long ldintr;
+ int ret;
+
+ /* Enable VSync End interrupt */
+ ldintr = lcdc_read(ch->lcdc, _LDINTR);
+ ldintr |= LDINTR_VEE;
+ lcdc_write(ch->lcdc, _LDINTR, ldintr);
+
+ ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
+ msecs_to_jiffies(100));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ int retval;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ retval = sh_mobile_wait_for_vsync(info);
+ break;
+
+ default:
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+ return retval;
+}
+
+
static struct fb_ops sh_mobile_lcdc_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = sh_mobile_lcdc_setcolreg,
@@ -795,6 +839,7 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_copyarea = sh_mobile_lcdc_copyarea,
.fb_imageblit = sh_mobile_lcdc_imageblit,
.fb_pan_display = sh_mobile_fb_pan_display,
+ .fb_ioctl = sh_mobile_ioctl,
};
static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp)
@@ -962,6 +1007,7 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
init_waitqueue_head(&priv->ch[i].frame_end_wait);
+ init_completion(&priv->ch[i].vsync_completion);
priv->ch[j].pan_offset = 0;
priv->ch[j].new_pan_offset = 0;