diff mbox

[01/02] sh: Add wait for vsync

Message ID AB12B32E73474741A2C5361C433A44DE017AD5FD@rte-ben-exch.RTE.ADWIN.RENESAS.COM (mailing list archive)
State Accepted
Headers show

Commit Message

Phil Edworthy Feb. 15, 2010, 1:57 p.m. UTC
None
diff mbox

Patch

diff -ruNp a/drivers/video/sh_mobile_lcdcfb.c
b/drivers/video/sh_mobile_lcdcfb.c
--- a/drivers/video/sh_mobile_lcdcfb.c	2010-01-06 00:02:46.000000000 +0000
+++ b/drivers/video/sh_mobile_lcdcfb.c	2010-02-15 13:10:57.000000000 +0000
@@ -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
 #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(in
 		}
 
 		/* 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(in
 					   ldrcntr ^ LDRCNTR_MRS);
 			ch->pan_offset = ch->new_pan_offset;
 		}
+
+		if (ldintr & LDINTR_VES)
+			complete(&ch->vsync_completion);
 	}
 
 	return IRQ_HANDLED;
@@ -786,6 +793,44 @@  static int sh_mobile_fb_pan_display(stru
 	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 +840,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 +1008,7 @@  static int __init sh_mobile_lcdc_probe(s
 			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;
 
diff -ruNp a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
--- a/include/video/sh_mobile_lcdc.h	2010-01-06 00:02:46.000000000 +0000
+++ b/include/video/sh_mobile_lcdc.h	2010-02-15 13:09:24.000000000 +0000
@@ -34,6 +34,8 @@  enum { LCDC_CLK_BUS, LCDC_CLK_PERIPHERAL
 #define LCDC_FLAGS_HSCNT (1 << 3) /* Disable HSYNC during VBLANK */
 #define LCDC_FLAGS_DWCNT (1 << 4) /* Disable dotclock during blanking */
 
+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
+
 struct sh_mobile_lcdc_sys_bus_cfg {
 	unsigned long ldmt2r;
 	unsigned long ldmt3r;