diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/pvr2fb.c | 2 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 88 |
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) | |||
831 | printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node); | 831 | printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node); |
832 | 832 | ||
833 | pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len, | 833 | pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len, |
834 | fb_info->fix.id, pgprot_val(PAGE_SHARED)); | 834 | fb_info->fix.id, PAGE_SHARED); |
835 | 835 | ||
836 | printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n", | 836 | printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n", |
837 | fb_info->node, pvr2fb_map); | 837 | 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 @@ | |||
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 { |
@@ -122,8 +124,8 @@ struct sh_mobile_lcdc_chan { | |||
122 | struct scatterlist *sglist; | 124 | struct scatterlist *sglist; |
123 | unsigned long frame_end; | 125 | unsigned long frame_end; |
124 | unsigned long pan_offset; | 126 | unsigned long pan_offset; |
125 | unsigned long new_pan_offset; | ||
126 | wait_queue_head_t frame_end_wait; | 127 | wait_queue_head_t frame_end_wait; |
128 | struct completion vsync_completion; | ||
127 | }; | 129 | }; |
128 | 130 | ||
129 | struct sh_mobile_lcdc_priv { | 131 | struct sh_mobile_lcdc_priv { |
@@ -366,19 +368,8 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data) | |||
366 | } | 368 | } |
367 | 369 | ||
368 | /* VSYNC End */ | 370 | /* VSYNC End */ |
369 | if (ldintr & LDINTR_VES) { | 371 | if (ldintr & LDINTR_VES) |
370 | unsigned long ldrcntr = lcdc_read(priv, _LDRCNTR); | 372 | complete(&ch->vsync_completion); |
371 | /* Set the source address for the next refresh */ | ||
372 | lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + | ||
373 | ch->new_pan_offset); | ||
374 | if (lcdc_chan_is_sublcd(ch)) | ||
375 | lcdc_write(ch->lcdc, _LDRCNTR, | ||
376 | ldrcntr ^ LDRCNTR_SRS); | ||
377 | else | ||
378 | lcdc_write(ch->lcdc, _LDRCNTR, | ||
379 | ldrcntr ^ LDRCNTR_MRS); | ||
380 | ch->pan_offset = ch->new_pan_offset; | ||
381 | } | ||
382 | } | 373 | } |
383 | 374 | ||
384 | return IRQ_HANDLED; | 375 | return IRQ_HANDLED; |
@@ -767,25 +758,69 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
767 | struct fb_info *info) | 758 | struct fb_info *info) |
768 | { | 759 | { |
769 | 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)); | ||
770 | 767 | ||
771 | if (info->var.xoffset == var->xoffset && | 768 | if (new_pan_offset == ch->pan_offset) |
772 | info->var.yoffset == var->yoffset) | ||
773 | return 0; /* No change, do nothing */ | 769 | return 0; /* No change, do nothing */ |
774 | 770 | ||
775 | ch->new_pan_offset = (var->yoffset * info->fix.line_length) + | 771 | ldrcntr = lcdc_read(priv, _LDRCNTR); |
776 | (var->xoffset * (info->var.bits_per_pixel / 8)); | ||
777 | 772 | ||
778 | if (ch->new_pan_offset != ch->pan_offset) { | 773 | /* Set the source address for the next refresh */ |
779 | unsigned long ldintr; | 774 | lcdc_write_chan_mirror(ch, LDSA1R, ch->dma_handle + new_pan_offset); |
780 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | 775 | if (lcdc_chan_is_sublcd(ch)) |
781 | ldintr |= LDINTR_VEE; | 776 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); |
782 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | 777 | else |
783 | sh_mobile_lcdc_deferred_io_touch(info); | 778 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_MRS); |
784 | } | 779 | |
780 | ch->pan_offset = new_pan_offset; | ||
781 | |||
782 | sh_mobile_lcdc_deferred_io_touch(info); | ||
783 | |||
784 | return 0; | ||
785 | } | ||
786 | |||
787 | static int sh_mobile_wait_for_vsync(struct fb_info *info) | ||
788 | { | ||
789 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
790 | unsigned long ldintr; | ||
791 | int ret; | ||
792 | |||
793 | /* Enable VSync End interrupt */ | ||
794 | ldintr = lcdc_read(ch->lcdc, _LDINTR); | ||
795 | ldintr |= LDINTR_VEE; | ||
796 | lcdc_write(ch->lcdc, _LDINTR, ldintr); | ||
797 | |||
798 | ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion, | ||
799 | msecs_to_jiffies(100)); | ||
800 | if (!ret) | ||
801 | return -ETIMEDOUT; | ||
785 | 802 | ||
786 | return 0; | 803 | return 0; |
787 | } | 804 | } |
788 | 805 | ||
806 | static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, | ||
807 | unsigned long arg) | ||
808 | { | ||
809 | int retval; | ||
810 | |||
811 | switch (cmd) { | ||
812 | case FBIO_WAITFORVSYNC: | ||
813 | retval = sh_mobile_wait_for_vsync(info); | ||
814 | break; | ||
815 | |||
816 | default: | ||
817 | retval = -ENOIOCTLCMD; | ||
818 | break; | ||
819 | } | ||
820 | return retval; | ||
821 | } | ||
822 | |||
823 | |||
789 | static struct fb_ops sh_mobile_lcdc_ops = { | 824 | static struct fb_ops sh_mobile_lcdc_ops = { |
790 | .owner = THIS_MODULE, | 825 | .owner = THIS_MODULE, |
791 | .fb_setcolreg = sh_mobile_lcdc_setcolreg, | 826 | .fb_setcolreg = sh_mobile_lcdc_setcolreg, |
@@ -795,6 +830,7 @@ static struct fb_ops sh_mobile_lcdc_ops = { | |||
795 | .fb_copyarea = sh_mobile_lcdc_copyarea, | 830 | .fb_copyarea = sh_mobile_lcdc_copyarea, |
796 | .fb_imageblit = sh_mobile_lcdc_imageblit, | 831 | .fb_imageblit = sh_mobile_lcdc_imageblit, |
797 | .fb_pan_display = sh_mobile_fb_pan_display, | 832 | .fb_pan_display = sh_mobile_fb_pan_display, |
833 | .fb_ioctl = sh_mobile_ioctl, | ||
798 | }; | 834 | }; |
799 | 835 | ||
800 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) | 836 | 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) | |||
962 | goto err1; | 998 | goto err1; |
963 | } | 999 | } |
964 | init_waitqueue_head(&priv->ch[i].frame_end_wait); | 1000 | init_waitqueue_head(&priv->ch[i].frame_end_wait); |
1001 | init_completion(&priv->ch[i].vsync_completion); | ||
965 | priv->ch[j].pan_offset = 0; | 1002 | priv->ch[j].pan_offset = 0; |
966 | priv->ch[j].new_pan_offset = 0; | ||
967 | 1003 | ||
968 | switch (pdata->ch[i].chan) { | 1004 | switch (pdata->ch[i].chan) { |
969 | case LCDC_CHAN_MAINLCD: | 1005 | case LCDC_CHAN_MAINLCD: |