1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
---
drivers/video/sidsafb.c | 68 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 61 insertions(+), 7 deletions(-)
Index: linux-2.6.18-rc6-mm1/drivers/video/sidsafb.c
===================================================================
--- linux-2.6.18-rc6-mm1.orig/drivers/video/sidsafb.c 2006-09-11 13:03:46.000000000 +0200
+++ linux-2.6.18-rc6-mm1/drivers/video/sidsafb.c 2006-09-11 13:38:52.000000000 +0200
@@ -11,6 +11,7 @@
#include <linux/config.h>
#include <linux/clk.h>
+#include <linux/completion.h>
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
@@ -38,7 +39,8 @@ struct sidsafb_info {
struct fb_info * info;
void __iomem * regs;
unsigned long irq_base;
- wait_queue_head_t vsync_wait;
+ int wait_for_vsync;
+ struct completion vsync_complete;
unsigned int guard_time;
struct clk *hclk;
struct clk *pixclk;
@@ -169,6 +171,38 @@ static struct fb_fix_screeninfo sidsafb_
.accel = FB_ACCEL_NONE,
};
+/*
+ * Let the user decide whether FBIOPAN_DISPLAY waits for the next
+ * vsync or not.
+ */
+static ssize_t
+vsync_pan_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sidsafb_info *sinfo = info->par;
+
+ return sprintf(buf, "%d\n", sinfo->wait_for_vsync);
+}
+
+static ssize_t
+vsync_pan_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct sidsafb_info *sinfo = info->par;
+ unsigned long val;
+
+ val = simple_strtoul(buf, NULL, 0);
+ if (val)
+ sinfo->wait_for_vsync = 1;
+ else
+ sinfo->wait_for_vsync = 0;
+
+ return count;
+}
+
+static DEVICE_ATTR(vsync_pan, 0644, vsync_pan_show, vsync_pan_store);
+
static void sidsafb_update_dma(struct fb_info *info,
struct fb_var_screeninfo *var)
{
@@ -513,10 +547,25 @@ static int sidsafb_setcolreg(unsigned in
static int sidsafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
+ struct sidsafb_info *sinfo = info->par;
+
pr_debug("sidsafb_pan_display\n");
sidsafb_update_dma(info, var);
+ if (sinfo->wait_for_vsync) {
+ spin_lock_irq(&sinfo->lock);
+ lcdc_writel(sinfo, LCD_ICR, LCDC_BIT(LCD_ICR_EOFIC));
+ lcdc_writel(sinfo, LCD_IER, LCDC_BIT(LCD_IER_EOFIE));
+ init_completion(&sinfo->vsync_complete);
+ lcdc_readl(sinfo, LCD_IMR);
+ spin_unlock_irq(&sinfo->lock);
+
+ wait_for_completion(&sinfo->vsync_complete);
+
+ lcdc_writel(sinfo, LCD_IDR, LCDC_BIT(LCD_IDR_EOFID));
+ }
+
return 0;
}
@@ -545,7 +594,7 @@ static irqreturn_t sidsafb_interrupt(int
lcdc_writel(sinfo, LCD_ICR, LCDC_BIT(LCD_ICR_EOFIC));
status &= ~LCDC_BIT(LCD_ISR_EOFIS);
- wake_up(&sinfo->vsync_wait);
+ complete(&sinfo->vsync_complete);
}
if (status) {
@@ -600,8 +649,6 @@ static int __devinit sidsafb_set_fbinfo(
info->fbops = &sidsafb_ops;
info->pseudo_palette = sinfo->pseudo_palette;
- init_waitqueue_head(&sinfo->vsync_wait);
-
return 0;
}
@@ -700,18 +747,21 @@ static int __devinit sidsafb_probe(struc
goto unregister_irqs;
}
+ platform_set_drvdata(pdev, info);
+ ret = device_create_file(&pdev->dev, &dev_attr_vsync_pan);
+ if (ret)
+ goto free_cmap;
+
/*
* Tell the world that we're ready to go
*/
ret = register_framebuffer(info);
if (ret)
- goto free_cmap;
+ goto remove_attrs;
printk("fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
info->node, info->fix.mmio_start, sinfo->regs, sinfo->irq_base);
- platform_set_drvdata(pdev, info);
-
memset_io(info->screen_base, 0, info->fix.smem_len);
info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
ret = fb_set_var(info, &info->var);
@@ -724,6 +774,8 @@ static int __devinit sidsafb_probe(struc
return 0;
+remove_attrs:
+ device_remove_file(&pdev->dev, &dev_attr_vsync_pan);
free_cmap:
fb_dealloc_cmap(&info->cmap);
unregister_irqs:
@@ -761,6 +813,8 @@ static int __devexit sidsafb_remove(stru
/* TODO: Restore original state */
unregister_framebuffer(info);
+ device_remove_file(&pdev->dev, &dev_attr_vsync_pan);
+
fb_dealloc_cmap(&info->cmap);
free_irq(sinfo->irq_base, info);
iounmap(sinfo->regs);
|