diff options
author | Phil Edworthy <Phil.Edworthy@renesas.com> | 2010-02-11 05:24:25 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-02-15 23:30:29 -0500 |
commit | 92e1f9a7ed613b36f3aaf8b04a79e2fd4fa37ec1 (patch) | |
tree | 3e1ac9265c8b7044b99d8473deb25dff577994ec /drivers/video/sh_mobile_lcdcfb.c | |
parent | 40331b21f5fdb746e80fc609ef60ef71b5cd47d9 (diff) |
video: sh_mobile_lcdcfb: Fix panning.
Fixed SH-Mobile panning. Previously the address of the frame to be displayed
was updated in the VSync end interrupt. This meant there was a minimum of 1
frame bewteen calling FBIOPAN_DISPLAY ioctl and the pan occuring. This meant
that apps were not able to use the FBIO_WAITFORVSYNC ioctl to wait for the
pan to complete. This patch moves the write to LDSA1R mirror reg into the
pan ioctl. Tested on MS7724 board 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/sh_mobile_lcdcfb.c')
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 46 |
1 files changed, 18 insertions, 28 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 37aeced2dc18..8d7653e56df5 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -124,7 +124,6 @@ struct sh_mobile_lcdc_chan { | |||
124 | struct scatterlist *sglist; | 124 | struct scatterlist *sglist; |
125 | unsigned long frame_end; | 125 | unsigned long frame_end; |
126 | unsigned long pan_offset; | 126 | unsigned long pan_offset; |
127 | unsigned long new_pan_offset; | ||
128 | wait_queue_head_t frame_end_wait; | 127 | wait_queue_head_t frame_end_wait; |
129 | struct completion vsync_completion; | 128 | struct completion vsync_completion; |
130 | }; | 129 | }; |
@@ -369,21 +368,6 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
369 | } | 368 | } |
370 | 369 | ||
371 | /* VSYNC End */ | 370 | /* VSYNC End */ |
372 | if ((ldintr & LDINTR_VES) && | ||
373 | (ch->pan_offset != ch->new_pan_offset)) { | ||
374 | unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); | ||
375 | /* Set the source address for the next refresh */ | ||
376 | lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + | ||
377 | ch->new_pan_offset); | ||
378 | if (lcdc_chan_is_sublcd(ch)) | ||
379 | lcdc_write(ch->lcdc, _LDRCNTR, | ||
380 | ldrcntr ^ LDRCNTR_SRS); | ||
381 | else | ||
382 | lcdc_write(ch->lcdc, _LDRCNTR, | ||
383 | ldrcntr ^ LDRCNTR_MRS); | ||
384 | ch->pan_offset = ch->new_pan_offset; | ||
385 | } | ||
386 | |||
387 | if (ldintr & LDINTR_VES) | 371 | if (ldintr & LDINTR_VES) |
388 | complete(&ch->vsync_completion); | 372 | complete(&ch->vsync_completion); |
389 | } | 373 | } |
@@ -774,21 +758,28 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
774 | struct fb_info *info) | 758 | struct fb_info *info) |
775 | { | 759 | { |
776 | struct sh_mobile_lcdc_chan *ch = info->par; | 760 | struct sh_mobile_lcdc_chan *ch = info->par; |
761 | struct sh_mobile_lcdc_priv *priv = ch->lcdc; | ||
762 | unsigned long ldrcntr; | ||
763 | unsigned long new_pan_offset; | ||
764 | |||
765 | new_pan_offset = (var->yoffset * info->fix.line_length) + | ||
766 | (var->xoffset * (info->var.bits_per_pixel / 8)); | ||
777 | 767 | ||
778 | if (info->var.xoffset == var->xoffset && | 768 | if (new_pan_offset == ch->pan_offset) |
779 | info->var.yoffset == var->yoffset) | ||
780 | return 0; /* No change, do nothing */ | 769 | return 0; /* No change, do nothing */ |
781 | 770 | ||
782 | ch->new_pan_offset = (var->yoffset * info->fix.line_length) + | 771 | ldrcntr = lcdc_read(priv, _LDRCNTR); |
783 | (var->xoffset * (info->var.bits_per_pixel / 8)); | ||
784 | 772 | ||
785 | if (ch->new_pan_offset != ch->pan_offset) { | 773 | /* Set the source address for the next refresh */ |
786 | unsigned long ldintr; | 774 | lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset); |
787 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | 775 | if (lcdc_chan_is_sublcd(ch)) |
788 | ldintr |= LDINTR_VEE; | 776 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); |
789 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | 777 | else |
790 | sh_mobile_lcdc_deferred_io_touch(info); | 778 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); |
791 | } | 779 | |
780 | ch->pan_offset = new_pan_offset; | ||
781 | |||
782 | sh_mobile_lcdc_deferred_io_touch(info); | ||
792 | 783 | ||
793 | return 0; | 784 | return 0; |
794 | } | 785 | } |
@@ -1009,7 +1000,6 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1009 | init_waitqueue_head(&priv->ch[i].frame_end_wait); | 1000 | init_waitqueue_head(&priv->ch[i].frame_end_wait); |
1010 | init_completion(&priv->ch[i].vsync_completion); | 1001 | init_completion(&priv->ch[i].vsync_completion); |
1011 | priv->ch[j].pan_offset = 0; | 1002 | priv->ch[j].pan_offset = 0; |
1012 | priv->ch[j].new_pan_offset = 0; | ||
1013 | 1003 | ||
1014 | switch (pdata->ch[i].chan) { | 1004 | switch (pdata->ch[i].chan) { |
1015 | case LCDC_CHAN_MAINLCD: | 1005 | case LCDC_CHAN_MAINLCD: |