aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-05-07 01:45:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-05-07 01:45:50 -0400
commit71227521459872c321e7a581e82723bbc1aa33e1 (patch)
tree3e232a92291998a1a274b8171d5741bb4a7df472
parent453e93b348ebabc517149b9d9a05042a3c1ccc82 (diff)
[VIDEO]: Add Sun XVR-2500 framebuffer driver.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/video/Kconfig13
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/sunxvr2500.c277
3 files changed, 291 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0a614beb5fb..344c3759530 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1396,6 +1396,19 @@ config FB_XVR500
1396 mostly initialized the card already. It is treated as a 1396 mostly initialized the card already. It is treated as a
1397 completely dumb framebuffer device. 1397 completely dumb framebuffer device.
1398 1398
1399config FB_XVR2500
1400 bool "Sun XVR-2500 3DLABS Wildcat support"
1401 depends on FB && PCI && SPARC64
1402 select FB_CFB_FILLRECT
1403 select FB_CFB_COPYAREA
1404 select FB_CFB_IMAGEBLIT
1405 help
1406 This is the framebuffer device for the Sun XVR-2500 and similar
1407 graphics cards based upon the 3DLABS Wildcat chipset. The driver
1408 only works on sparc64 systems where the system firwmare has
1409 mostly initialized the card already. It is treated as a
1410 completely dumb framebuffer device.
1411
1399config FB_PCI 1412config FB_PCI
1400 bool "PCI framebuffers" 1413 bool "PCI framebuffers"
1401 depends on (FB = y) && PCI && SPARC 1414 depends on (FB = y) && PCI && SPARC
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a56be581296..558473d040d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \
68obj-$(CONFIG_FB_MAC) += macfb.o 68obj-$(CONFIG_FB_MAC) += macfb.o
69obj-$(CONFIG_FB_HGA) += hgafb.o 69obj-$(CONFIG_FB_HGA) += hgafb.o
70obj-$(CONFIG_FB_XVR500) += sunxvr500.o 70obj-$(CONFIG_FB_XVR500) += sunxvr500.o
71obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o
71obj-$(CONFIG_FB_IGA) += igafb.o 72obj-$(CONFIG_FB_IGA) += igafb.o
72obj-$(CONFIG_FB_APOLLO) += dnfb.o 73obj-$(CONFIG_FB_APOLLO) += dnfb.o
73obj-$(CONFIG_FB_Q40) += q40fb.o 74obj-$(CONFIG_FB_Q40) += q40fb.o
diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c
new file mode 100644
index 00000000000..4010492c692
--- /dev/null
+++ b/drivers/video/sunxvr2500.c
@@ -0,0 +1,277 @@
1/* s3d.c: Sun 3DLABS XVR-2500 et al. driver for sparc64 systems
2 *
3 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
4 */
5
6#include <linux/module.h>
7#include <linux/kernel.h>
8#include <linux/slab.h>
9#include <linux/fb.h>
10#include <linux/pci.h>
11#include <linux/init.h>
12
13#include <asm/io.h>
14#include <asm/prom.h>
15#include <asm/of_device.h>
16
17struct s3d_info {
18 struct fb_info *info;
19 struct pci_dev *pdev;
20
21 char __iomem *fb_base;
22 unsigned long fb_base_phys;
23
24 struct device_node *of_node;
25
26 unsigned int width;
27 unsigned int height;
28 unsigned int depth;
29 unsigned int fb_size;
30
31 u32 pseudo_palette[256];
32};
33
34static int __devinit s3d_get_props(struct s3d_info *sp)
35{
36 sp->width = of_getintprop_default(sp->of_node, "width", 0);
37 sp->height = of_getintprop_default(sp->of_node, "height", 0);
38 sp->depth = of_getintprop_default(sp->of_node, "depth", 8);
39
40 if (!sp->width || !sp->height) {
41 printk(KERN_ERR "s3d: Critical properties missing for %s\n",
42 pci_name(sp->pdev));
43 return -EINVAL;
44 }
45
46 return 0;
47}
48
49static int s3d_setcolreg(unsigned regno,
50 unsigned red, unsigned green, unsigned blue,
51 unsigned transp, struct fb_info *info)
52{
53 u32 value;
54
55 if (regno >= 256)
56 return 1;
57
58 red >>= 8;
59 green >>= 8;
60 blue >>= 8;
61
62 value = (blue << 24) | (green << 16) | (red << 8);
63 ((u32 *)info->pseudo_palette)[regno] = value;
64
65 return 0;
66}
67
68static struct fb_ops s3d_ops = {
69 .owner = THIS_MODULE,
70 .fb_setcolreg = s3d_setcolreg,
71 .fb_fillrect = cfb_fillrect,
72 .fb_copyarea = cfb_copyarea,
73 .fb_imageblit = cfb_imageblit,
74};
75
76static int __devinit s3d_set_fbinfo(struct s3d_info *sp)
77{
78 struct fb_info *info = sp->info;
79 struct fb_var_screeninfo *var = &info->var;
80
81 info->flags = FBINFO_DEFAULT;
82 info->fbops = &s3d_ops;
83 info->screen_base = sp->fb_base;
84 info->screen_size = sp->fb_size;
85
86 info->pseudo_palette = sp->pseudo_palette;
87
88 /* Fill fix common fields */
89 strlcpy(info->fix.id, "s3d", sizeof(info->fix.id));
90 info->fix.smem_start = sp->fb_base_phys;
91 info->fix.smem_len = sp->fb_size;
92 info->fix.type = FB_TYPE_PACKED_PIXELS;
93 if (sp->depth == 32 || sp->depth == 24)
94 info->fix.visual = FB_VISUAL_TRUECOLOR;
95 else
96 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
97
98 var->xres = sp->width;
99 var->yres = sp->height;
100 var->xres_virtual = var->xres;
101 var->yres_virtual = var->yres;
102 var->bits_per_pixel = sp->depth;
103
104 var->red.offset = 8;
105 var->red.length = 8;
106 var->green.offset = 16;
107 var->green.length = 8;
108 var->blue.offset = 24;
109 var->blue.length = 8;
110 var->transp.offset = 0;
111 var->transp.length = 0;
112
113 if (fb_alloc_cmap(&info->cmap, 256, 0)) {
114 printk(KERN_ERR "s3d: Cannot allocate color map.\n");
115 return -ENOMEM;
116 }
117
118 return 0;
119}
120
121static int __devinit s3d_pci_register(struct pci_dev *pdev,
122 const struct pci_device_id *ent)
123{
124 struct fb_info *info;
125 struct s3d_info *sp;
126 int err;
127
128 err = pci_enable_device(pdev);
129 if (err < 0) {
130 printk(KERN_ERR "s3d: Cannot enable PCI device %s\n",
131 pci_name(pdev));
132 goto err_out;
133 }
134
135 info = framebuffer_alloc(sizeof(struct s3d_info), &pdev->dev);
136 if (!info) {
137 printk(KERN_ERR "s3d: Cannot allocate fb_info\n");
138 err = -ENOMEM;
139 goto err_disable;
140 }
141
142 sp = info->par;
143 sp->info = info;
144 sp->pdev = pdev;
145 sp->of_node = pci_device_to_OF_node(pdev);
146 if (!sp->of_node) {
147 printk(KERN_ERR "s3d: Cannot find OF node of %s\n",
148 pci_name(pdev));
149 err = -ENODEV;
150 goto err_release_fb;
151 }
152
153 sp->fb_base_phys = pci_resource_start (pdev, 1);
154
155 err = pci_request_region(pdev, 1, "s3d framebuffer");
156 if (err < 0) {
157 printk("s3d: Cannot request region 1 for %s\n",
158 pci_name(pdev));
159 goto err_release_fb;
160 }
161
162 err = s3d_get_props(sp);
163 if (err)
164 goto err_release_pci;
165
166 /* XXX 'linebytes' is often wrong, it is equal to the width
167 * XXX with depth of 32 on my XVR-2500 which is clearly not
168 * XXX right. So we don't try to use it.
169 */
170 switch (sp->depth) {
171 case 8:
172 info->fix.line_length = sp->width;
173 break;
174 case 16:
175 info->fix.line_length = sp->width * 2;
176 break;
177 case 24:
178 info->fix.line_length = sp->width * 3;
179 break;
180 case 32:
181 info->fix.line_length = sp->width * 4;
182 break;
183 }
184 sp->fb_size = info->fix.line_length * sp->height;
185
186 sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size);
187 if (!sp->fb_base)
188 goto err_release_pci;
189
190 err = s3d_set_fbinfo(sp);
191 if (err)
192 goto err_unmap_fb;
193
194 pci_set_drvdata(pdev, info);
195
196 printk("s3d: Found device at %s\n", pci_name(pdev));
197
198 err = register_framebuffer(info);
199 if (err < 0) {
200 printk(KERN_ERR "s3d: Could not register framebuffer %s\n",
201 pci_name(pdev));
202 goto err_unmap_fb;
203 }
204
205 return 0;
206
207err_unmap_fb:
208 iounmap(sp->fb_base);
209
210err_release_pci:
211 pci_release_region(pdev, 1);
212
213err_release_fb:
214 framebuffer_release(info);
215
216err_disable:
217 pci_disable_device(pdev);
218
219err_out:
220 return err;
221}
222
223static void __devexit s3d_pci_unregister(struct pci_dev *pdev)
224{
225 struct fb_info *info = pci_get_drvdata(pdev);
226 struct s3d_info *sp = info->par;
227
228 unregister_framebuffer(info);
229
230 iounmap(sp->fb_base);
231
232 pci_release_region(pdev, 1);
233
234 framebuffer_release(info);
235
236 pci_disable_device(pdev);
237}
238
239static struct pci_device_id s3d_pci_table[] = {
240 { /* XVR-2500 */
241 PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0032),
242 .driver_data = 1,
243 },
244 { /* XVR-500 */
245 PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x07a2),
246 .driver_data = 0,
247 },
248 { 0, }
249};
250
251static struct pci_driver s3d_driver = {
252 .name = "s3d",
253 .id_table = s3d_pci_table,
254 .probe = s3d_pci_register,
255 .remove = __devexit_p(s3d_pci_unregister),
256};
257
258static int __init s3d_init(void)
259{
260 if (fb_get_options("s3d", NULL))
261 return -ENODEV;
262
263 return pci_register_driver(&s3d_driver);
264}
265
266static void __exit s3d_exit(void)
267{
268 pci_unregister_driver(&s3d_driver);
269}
270
271module_init(s3d_init);
272module_exit(s3d_exit);
273
274MODULE_DESCRIPTION("framebuffer driver for Sun XVR-2500 graphics");
275MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
276MODULE_VERSION("1.0");
277MODULE_LICENSE("GPL");