summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-02-26 16:54:27 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2010-02-26 16:54:27 -0800
commit64d497f55379b1e320a08ec2426468d96f5642ec (patch)
tree22b9ab3c5e69c5cc2728cbc2ca7fc7623beef8f1 /drivers/video
parent37d4008484977f60d5d37499a2670c79b214dd46 (diff)
parentb5f5fe80fa98a60daa0fa94512d1599b1e26674c (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6: (187 commits) sh: remove dead LED code for migo-r and ms7724se sh: ecovec build fix for CONFIG_I2C=n sh: ecovec r-standby support sh: ms7724se r-standby support sh: SH-Mobile R-standby register save/restore clocksource: Fix up a registration/IRQ race in the sh drivers. sh: ms7724: modify scan_timing for KEYSC sh: ms7724: Add sh_sir support sh: mach-ecovec24: Add sh_sir support sh: wire up SET/GET_UNALIGN_CTL. sh: allow alignment fault mode to be configured at kernel boot. sh: sh7724: Update FSI/SPU2 clock sh: always enable sh7724 vpu_clk and set to 166MHz on Ecovec sh: add sh7724 kick callback to clk_div4_table sh: introduce struct clk_div4_table sh: clock-cpg div4 set_rate() shift fix sh: Turn on speculative return for SH7785 and SH7786 sh: Merge legacy and dynamic PMB modes. sh: Use uncached I/O helpers in PMB setup. sh: Provide uncached I/O helpers. ...
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/pvr2fb.c2
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c88
2 files changed, 63 insertions, 27 deletions
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 53f8f1100e81..f9975100d56d 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -831,7 +831,7 @@ static int __devinit pvr2fb_common_init(void)
printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node);
pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len,
- fb_info->fix.id, pgprot_val(PAGE_SHARED));
+ fb_info->fix.id, PAGE_SHARED);
printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n",
fb_info->node, pvr2fb_map);
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index a69830d26f7f..8d7653e56df5 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 {
@@ -122,8 +124,8 @@ struct sh_mobile_lcdc_chan {
struct scatterlist *sglist;
unsigned long frame_end;
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,19 +368,8 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
}
/* VSYNC End */
- if (ldintr & LDINTR_VES) {
- unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR);
- /* Set the source address for the next refresh */
- lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle +
- ch->new_pan_offset);
- if (lcdc_chan_is_sublcd(ch))
- lcdc_write(ch->lcdc, _LDRCNTR,
- ldrcntr ^ LDRCNTR_SRS);
- else
- lcdc_write(ch->lcdc, _LDRCNTR,
- ldrcntr ^ LDRCNTR_MRS);
- ch->pan_offset = ch->new_pan_offset;
- }
+ if (ldintr & LDINTR_VES)
+ complete(&ch->vsync_completion);
}
return IRQ_HANDLED;
@@ -767,25 +758,69 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct sh_mobile_lcdc_chan *ch = info->par;
+ struct sh_mobile_lcdc_priv *priv = ch->lcdc;
+ unsigned long ldrcntr;
+ unsigned long new_pan_offset;
+
+ new_pan_offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * (info->var.bits_per_pixel / 8));
- if (info->var.xoffset == var->xoffset &&
- info->var.yoffset == var->yoffset)
+ if (new_pan_offset == ch->pan_offset)
return 0; /* No change, do nothing */
- ch->new_pan_offset = (var->yoffset * info->fix.line_length) +
- (var->xoffset * (info->var.bits_per_pixel / 8));
+ ldrcntr = lcdc_read(priv, _LDRCNTR);
- if (ch->new_pan_offset != ch->pan_offset) {
- unsigned long ldintr;
- ldintr = lcdc_read(ch->lcdc, _LDINTR);
- ldintr |= LDINTR_VEE;
- lcdc_write(ch->lcdc, _LDINTR, ldintr);
- sh_mobile_lcdc_deferred_io_touch(info);
- }
+ /* Set the source address for the next refresh */
+ lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset);
+ if (lcdc_chan_is_sublcd(ch))
+ lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
+ else
+ lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS);
+
+ ch->pan_offset = new_pan_offset;
+
+ sh_mobile_lcdc_deferred_io_touch(info);
+
+ 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 +830,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,8 +998,8 @@ 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;
switch (pdata->ch[i].chan) {
case LCDC_CHAN_MAINLCD: