diff options
| author | Phil Edworthy <Phil.Edworthy@renesas.com> | 2010-02-15 08:57:49 -0500 |
|---|---|---|
| committer | Paul Mundt <lethal@linux-sh.org> | 2010-02-15 23:30:27 -0500 |
| commit | 40331b21f5fdb746e80fc609ef60ef71b5cd47d9 (patch) | |
| tree | 66467a8eff27a8f379d433c717bd91bc84c7b6bf | |
| parent | 04c869735541c27dd137c55f35f8a18bb372bbe1 (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>
| -rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 48 | ||||
| -rw-r--r-- | include/video/sh_mobile_lcdc.h | 2 |
2 files changed, 49 insertions, 1 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index a69830d26f7f..37aeced2dc18 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
| 20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
| 21 | #include <linux/vmalloc.h> | 21 | #include <linux/vmalloc.h> |
| 22 | #include <linux/ioctl.h> | ||
| 22 | #include <video/sh_mobile_lcdc.h> | 23 | #include <video/sh_mobile_lcdc.h> |
| 23 | #include <asm/atomic.h> | 24 | #include <asm/atomic.h> |
| 24 | 25 | ||
| @@ -106,6 +107,7 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { | |||
| 106 | #define LDRCNTR_SRC 0x00010000 | 107 | #define LDRCNTR_SRC 0x00010000 |
| 107 | #define LDRCNTR_MRS 0x00000002 | 108 | #define LDRCNTR_MRS 0x00000002 |
| 108 | #define LDRCNTR_MRC 0x00000001 | 109 | #define LDRCNTR_MRC 0x00000001 |
| 110 | #define LDSR_MRS 0x00000100 | ||
| 109 | 111 | ||
| 110 | struct sh_mobile_lcdc_priv; | 112 | struct sh_mobile_lcdc_priv; |
| 111 | struct sh_mobile_lcdc_chan { | 113 | struct sh_mobile_lcdc_chan { |
| @@ -124,6 +126,7 @@ struct sh_mobile_lcdc_chan { | |||
| 124 | unsigned long pan_offset; | 126 | unsigned long pan_offset; |
| 125 | unsigned long new_pan_offset; | 127 | unsigned long new_pan_offset; |
| 126 | wait_queue_head_t frame_end_wait; | 128 | wait_queue_head_t frame_end_wait; |
| 129 | struct completion vsync_completion; | ||
| 127 | }; | 130 | }; |
| 128 | 131 | ||
| 129 | struct sh_mobile_lcdc_priv { | 132 | struct sh_mobile_lcdc_priv { |
| @@ -366,7 +369,8 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
| 366 | } | 369 | } |
| 367 | 370 | ||
| 368 | /* VSYNC End */ | 371 | /* VSYNC End */ |
| 369 | if (ldintr & LDINTR_VES) { | 372 | if ((ldintr & LDINTR_VES) && |
| 373 | (ch->pan_offset != ch->new_pan_offset)) { | ||
| 370 | unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); | 374 | unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); |
| 371 | /* Set the source address for the next refresh */ | 375 | /* Set the source address for the next refresh */ |
| 372 | lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + | 376 | lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + |
| @@ -379,6 +383,9 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
| 379 | ldrcntr ^ LDRCNTR_MRS); | 383 | ldrcntr ^ LDRCNTR_MRS); |
| 380 | ch->pan_offset = ch->new_pan_offset; | 384 | ch->pan_offset = ch->new_pan_offset; |
| 381 | } | 385 | } |
| 386 | |||
| 387 | if (ldintr & LDINTR_VES) | ||
| 388 | complete(&ch->vsync_completion); | ||
| 382 | } | 389 | } |
| 383 | 390 | ||
| 384 | return IRQ_HANDLED; | 391 | return IRQ_HANDLED; |
| @@ -786,6 +793,43 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
| 786 | return 0; | 793 | return 0; |
| 787 | } | 794 | } |
| 788 | 795 | ||
| 796 | static int sh_mobile_wait_for_vsync(struct fb_info *info) | ||
| 797 | { | ||
| 798 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 799 | unsigned long ldintr; | ||
| 800 | int ret; | ||
| 801 | |||
| 802 | /* Enable VSync End interrupt */ | ||
| 803 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | ||
| 804 | ldintr |= LDINTR_VEE; | ||
| 805 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | ||
| 806 | |||
| 807 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, | ||
| 808 | msecs_to_jiffies(100)); | ||
| 809 | if (!ret) | ||
| 810 | return -ETIMEDOUT; | ||
| 811 | |||
| 812 | return 0; | ||
| 813 | } | ||
| 814 | |||
| 815 | static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, | ||
| 816 | unsigned long arg) | ||
| 817 | { | ||
| 818 | int retval; | ||
| 819 | |||
| 820 | switch (cmd) { | ||
| 821 | case FBIO_WAITFORVSYNC: | ||
| 822 | retval = sh_mobile_wait_for_vsync(info); | ||
| 823 | break; | ||
| 824 | |||
| 825 | default: | ||
| 826 | retval = -ENOIOCTLCMD; | ||
| 827 | break; | ||
| 828 | } | ||
| 829 | return retval; | ||
| 830 | } | ||
| 831 | |||
| 832 | |||
| 789 | static struct fb_ops sh_mobile_lcdc_ops = { | 833 | static struct fb_ops sh_mobile_lcdc_ops = { |
| 790 | .owner = THIS_MODULE, | 834 | .owner = THIS_MODULE, |
| 791 | .fb_setcolreg = sh_mobile_lcdc_setcolreg, | 835 | .fb_setcolreg = sh_mobile_lcdc_setcolreg, |
| @@ -795,6 +839,7 @@ static struct fb_ops sh_mobile_lcdc_ops = { | |||
| 795 | .fb_copyarea = sh_mobile_lcdc_copyarea, | 839 | .fb_copyarea = sh_mobile_lcdc_copyarea, |
| 796 | .fb_imageblit = sh_mobile_lcdc_imageblit, | 840 | .fb_imageblit = sh_mobile_lcdc_imageblit, |
| 797 | .fb_pan_display = sh_mobile_fb_pan_display, | 841 | .fb_pan_display = sh_mobile_fb_pan_display, |
| 842 | .fb_ioctl = sh_mobile_ioctl, | ||
| 798 | }; | 843 | }; |
| 799 | 844 | ||
| 800 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) | 845 | 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) | |||
| 962 | goto err1; | 1007 | goto err1; |
| 963 | } | 1008 | } |
| 964 | init_waitqueue_head(&priv->ch[i].frame_end_wait); | 1009 | init_waitqueue_head(&priv->ch[i].frame_end_wait); |
| 1010 | init_completion(&priv->ch[i].vsync_completion); | ||
| 965 | priv->ch[j].pan_offset = 0; | 1011 | priv->ch[j].pan_offset = 0; |
| 966 | priv->ch[j].new_pan_offset = 0; | 1012 | priv->ch[j].new_pan_offset = 0; |
| 967 | 1013 | ||
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 288205457713..2cc893fc1f85 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h | |||
| @@ -34,6 +34,8 @@ enum { LCDC_CLK_BUS, LCDC_CLK_PERIPHERAL, LCDC_CLK_EXTERNAL }; | |||
| 34 | #define LCDC_FLAGS_HSCNT (1 << 3) /* Disable HSYNC during VBLANK */ | 34 | #define LCDC_FLAGS_HSCNT (1 << 3) /* Disable HSYNC during VBLANK */ |
| 35 | #define LCDC_FLAGS_DWCNT (1 << 4) /* Disable dotclock during blanking */ | 35 | #define LCDC_FLAGS_DWCNT (1 << 4) /* Disable dotclock during blanking */ |
| 36 | 36 | ||
| 37 | #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) | ||
| 38 | |||
| 37 | struct sh_mobile_lcdc_sys_bus_cfg { | 39 | struct sh_mobile_lcdc_sys_bus_cfg { |
| 38 | unsigned long ldmt2r; | 40 | unsigned long ldmt2r; |
| 39 | unsigned long ldmt3r; | 41 | unsigned long ldmt3r; |
