aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/s3c-fb.c
diff options
context:
space:
mode:
authorPawel Osciak <p.osciak@samsung.com>2010-08-10 21:02:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-11 11:59:10 -0400
commitefdc846d2f7190c8f3092c09975c0ebba30a95ba (patch)
tree23834f2ab4523b86c53f2a4f3b56834e8155dfb2 /drivers/video/s3c-fb.c
parent067b226b9e8e20463e0937344c93101ac8d8d2b1 (diff)
s3c-fb: add wait for VSYNC ioctl
Add VSYNC interrupt support and an ioctl that allows waiting for it. Interrupts are turned on only when needed. Signed-off-by: Pawel Osciak <p.osciak@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Cc: InKi Dae <inki.dae@samsung.com> Cc: Ben Dooks <ben-linux@fluff.org> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/s3c-fb.c')
-rw-r--r--drivers/video/s3c-fb.c166
1 files changed, 165 insertions, 1 deletions
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index de427d928f48..2e82adf9ab6d 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -21,6 +21,8 @@
21#include <linux/clk.h> 21#include <linux/clk.h>
22#include <linux/fb.h> 22#include <linux/fb.h>
23#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/uaccess.h>
25#include <linux/interrupt.h>
24 26
25#include <mach/map.h> 27#include <mach/map.h>
26#include <plat/regs-fb-v4.h> 28#include <plat/regs-fb-v4.h>
@@ -48,6 +50,11 @@
48 __raw_writel(v, r); } while(0) 50 __raw_writel(v, r); } while(0)
49#endif /* FB_S3C_DEBUG_REGWRITE */ 51#endif /* FB_S3C_DEBUG_REGWRITE */
50 52
53/* irq_flags bits */
54#define S3C_FB_VSYNC_IRQ_EN 0
55
56#define VSYNC_TIMEOUT_MSEC 50
57
51struct s3c_fb; 58struct s3c_fb;
52 59
53#define VALID_BPP(x) (1 << ((x) - 1)) 60#define VALID_BPP(x) (1 << ((x) - 1))
@@ -156,6 +163,16 @@ struct s3c_fb_win {
156}; 163};
157 164
158/** 165/**
166 * struct s3c_fb_vsync - vsync information
167 * @wait: a queue for processes waiting for vsync
168 * @count: vsync interrupt count
169 */
170struct s3c_fb_vsync {
171 wait_queue_head_t wait;
172 unsigned int count;
173};
174
175/**
159 * struct s3c_fb - overall hardware state of the hardware 176 * struct s3c_fb - overall hardware state of the hardware
160 * @dev: The device that we bound to, for printing, etc. 177 * @dev: The device that we bound to, for printing, etc.
161 * @regs_res: The resource we claimed for the IO registers. 178 * @regs_res: The resource we claimed for the IO registers.
@@ -165,6 +182,9 @@ struct s3c_fb_win {
165 * @enabled: A bitmask of enabled hardware windows. 182 * @enabled: A bitmask of enabled hardware windows.
166 * @pdata: The platform configuration data passed with the device. 183 * @pdata: The platform configuration data passed with the device.
167 * @windows: The hardware windows that have been claimed. 184 * @windows: The hardware windows that have been claimed.
185 * @irq_no: IRQ line number
186 * @irq_flags: irq flags
187 * @vsync_info: VSYNC-related information (count, queues...)
168 */ 188 */
169struct s3c_fb { 189struct s3c_fb {
170 struct device *dev; 190 struct device *dev;
@@ -177,6 +197,10 @@ struct s3c_fb {
177 197
178 struct s3c_fb_platdata *pdata; 198 struct s3c_fb_platdata *pdata;
179 struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; 199 struct s3c_fb_win *windows[S3C_FB_MAX_WIN];
200
201 int irq_no;
202 unsigned long irq_flags;
203 struct s3c_fb_vsync vsync_info;
180}; 204};
181 205
182/** 206/**
@@ -798,6 +822,124 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
798 return 0; 822 return 0;
799} 823}
800 824
825/**
826 * s3c_fb_enable_irq() - enable framebuffer interrupts
827 * @sfb: main hardware state
828 */
829static void s3c_fb_enable_irq(struct s3c_fb *sfb)
830{
831 void __iomem *regs = sfb->regs;
832 u32 irq_ctrl_reg;
833
834 if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
835 /* IRQ disabled, enable it */
836 irq_ctrl_reg = readl(regs + VIDINTCON0);
837
838 irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
839 irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
840
841 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
842 irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
843 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
844 irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
845
846 writel(irq_ctrl_reg, regs + VIDINTCON0);
847 }
848}
849
850/**
851 * s3c_fb_disable_irq() - disable framebuffer interrupts
852 * @sfb: main hardware state
853 */
854static void s3c_fb_disable_irq(struct s3c_fb *sfb)
855{
856 void __iomem *regs = sfb->regs;
857 u32 irq_ctrl_reg;
858
859 if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
860 /* IRQ enabled, disable it */
861 irq_ctrl_reg = readl(regs + VIDINTCON0);
862
863 irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
864 irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
865
866 writel(irq_ctrl_reg, regs + VIDINTCON0);
867 }
868}
869
870static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
871{
872 struct s3c_fb *sfb = dev_id;
873 void __iomem *regs = sfb->regs;
874 u32 irq_sts_reg;
875
876 irq_sts_reg = readl(regs + VIDINTCON1);
877
878 if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
879
880 /* VSYNC interrupt, accept it */
881 writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
882
883 sfb->vsync_info.count++;
884 wake_up_interruptible(&sfb->vsync_info.wait);
885 }
886
887 /* We only support waiting for VSYNC for now, so it's safe
888 * to always disable irqs here.
889 */
890 s3c_fb_disable_irq(sfb);
891
892 return IRQ_HANDLED;
893}
894
895/**
896 * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
897 * @sfb: main hardware state
898 * @crtc: head index.
899 */
900static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
901{
902 unsigned long count;
903 int ret;
904
905 if (crtc != 0)
906 return -ENODEV;
907
908 count = sfb->vsync_info.count;
909 s3c_fb_enable_irq(sfb);
910 ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
911 count != sfb->vsync_info.count,
912 msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
913 if (ret == 0)
914 return -ETIMEDOUT;
915
916 return 0;
917}
918
919static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
920 unsigned long arg)
921{
922 struct s3c_fb_win *win = info->par;
923 struct s3c_fb *sfb = win->parent;
924 int ret;
925 u32 crtc;
926
927 switch (cmd) {
928 case FBIO_WAITFORVSYNC:
929 if (get_user(crtc, (u32 __user *)arg)) {
930 ret = -EFAULT;
931 break;
932 }
933
934 ret = s3c_fb_wait_for_vsync(sfb, crtc);
935 break;
936 default:
937 ret = -ENOTTY;
938 }
939
940 return ret;
941}
942
801static struct fb_ops s3c_fb_ops = { 943static struct fb_ops s3c_fb_ops = {
802 .owner = THIS_MODULE, 944 .owner = THIS_MODULE,
803 .fb_check_var = s3c_fb_check_var, 945 .fb_check_var = s3c_fb_check_var,
@@ -808,6 +950,7 @@ static struct fb_ops s3c_fb_ops = {
808 .fb_copyarea = cfb_copyarea, 950 .fb_copyarea = cfb_copyarea,
809 .fb_imageblit = cfb_imageblit, 951 .fb_imageblit = cfb_imageblit,
810 .fb_pan_display = s3c_fb_pan_display, 952 .fb_pan_display = s3c_fb_pan_display,
953 .fb_ioctl = s3c_fb_ioctl,
811}; 954};
812 955
813/** 956/**
@@ -914,6 +1057,8 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
914 1057
915 dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant); 1058 dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
916 1059
1060 init_waitqueue_head(&sfb->vsync_info.wait);
1061
917 palette_size = variant->palette_sz * 4; 1062 palette_size = variant->palette_sz * 4;
918 1063
919 fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) + 1064 fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
@@ -1093,6 +1238,20 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
1093 goto err_req_region; 1238 goto err_req_region;
1094 } 1239 }
1095 1240
1241 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1242 if (!res) {
1243 dev_err(dev, "failed to acquire irq resource\n");
1244 ret = -ENOENT;
1245 goto err_ioremap;
1246 }
1247 sfb->irq_no = res->start;
1248 ret = request_irq(sfb->irq_no, s3c_fb_irq,
1249 0, "s3c_fb", sfb);
1250 if (ret) {
1251 dev_err(dev, "irq request failed\n");
1252 goto err_ioremap;
1253 }
1254
1096 dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); 1255 dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
1097 1256
1098 /* setup gpio and output polarity controls */ 1257 /* setup gpio and output polarity controls */
@@ -1127,7 +1286,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
1127 dev_err(dev, "failed to create window %d\n", win); 1286 dev_err(dev, "failed to create window %d\n", win);
1128 for (; win >= 0; win--) 1287 for (; win >= 0; win--)
1129 s3c_fb_release_win(sfb, sfb->windows[win]); 1288 s3c_fb_release_win(sfb, sfb->windows[win]);
1130 goto err_ioremap; 1289 goto err_irq;
1131 } 1290 }
1132 } 1291 }
1133 1292
@@ -1135,6 +1294,9 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
1135 1294
1136 return 0; 1295 return 0;
1137 1296
1297err_irq:
1298 free_irq(sfb->irq_no, sfb);
1299
1138err_ioremap: 1300err_ioremap:
1139 iounmap(sfb->regs); 1301 iounmap(sfb->regs);
1140 1302
@@ -1167,6 +1329,8 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
1167 if (sfb->windows[win]) 1329 if (sfb->windows[win])
1168 s3c_fb_release_win(sfb, sfb->windows[win]); 1330 s3c_fb_release_win(sfb, sfb->windows[win]);
1169 1331
1332 free_irq(sfb->irq_no, sfb);
1333
1170 iounmap(sfb->regs); 1334 iounmap(sfb->regs);
1171 1335
1172 clk_disable(sfb->bus_clk); 1336 clk_disable(sfb->bus_clk);