sparc64: Fix accidental syscall restart on child return from clone/fork/vfork.
[linux-2.6-block.git] / drivers / video / bw2.c
CommitLineData
1da177e4
LT
1/* bw2.c: BWTWO frame buffer driver
2 *
50312ce9 3 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
1da177e4
LT
4 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
7 *
8 * Driver layout based loosely on tgafb.c, see that file for credits.
9 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/slab.h>
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/fb.h>
19#include <linux/mm.h>
20
21#include <asm/io.h>
1da177e4 22#include <asm/oplib.h>
50312ce9
DM
23#include <asm/prom.h>
24#include <asm/of_device.h>
1da177e4
LT
25#include <asm/fbio.h>
26
1da177e4
LT
27#include "sbuslib.h"
28
29/*
30 * Local functions.
31 */
32
33static int bw2_blank(int, struct fb_info *);
34
216d526c 35static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
67a6680d 36static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
1da177e4
LT
37
38/*
39 * Frame buffer operations
40 */
41
42static struct fb_ops bw2_ops = {
43 .owner = THIS_MODULE,
44 .fb_blank = bw2_blank,
45 .fb_fillrect = cfb_fillrect,
46 .fb_copyarea = cfb_copyarea,
47 .fb_imageblit = cfb_imageblit,
48 .fb_mmap = bw2_mmap,
49 .fb_ioctl = bw2_ioctl,
9ffb83bc
CH
50#ifdef CONFIG_COMPAT
51 .fb_compat_ioctl = sbusfb_compat_ioctl,
52#endif
1da177e4
LT
53};
54
55/* OBio addresses for the bwtwo registers */
56#define BWTWO_REGISTER_OFFSET 0x400000
57
58struct bt_regs {
50312ce9
DM
59 u32 addr;
60 u32 color_map;
61 u32 control;
62 u32 cursor;
1da177e4
LT
63};
64
65struct bw2_regs {
66 struct bt_regs cmap;
50312ce9
DM
67 u8 control;
68 u8 status;
69 u8 cursor_start;
70 u8 cursor_end;
71 u8 h_blank_start;
72 u8 h_blank_end;
73 u8 h_sync_start;
74 u8 h_sync_end;
75 u8 comp_sync_end;
76 u8 v_blank_start_high;
77 u8 v_blank_start_low;
78 u8 v_blank_end;
79 u8 v_sync_start;
80 u8 v_sync_end;
81 u8 xfer_holdoff_start;
82 u8 xfer_holdoff_end;
1da177e4
LT
83};
84
85/* Status Register Constants */
86#define BWTWO_SR_RES_MASK 0x70
87#define BWTWO_SR_1600_1280 0x50
88#define BWTWO_SR_1152_900_76_A 0x40
89#define BWTWO_SR_1152_900_76_B 0x60
90#define BWTWO_SR_ID_MASK 0x0f
91#define BWTWO_SR_ID_MONO 0x02
92#define BWTWO_SR_ID_MONO_ECL 0x03
93#define BWTWO_SR_ID_MSYNC 0x04
94#define BWTWO_SR_ID_NOCONN 0x0a
95
96/* Control Register Constants */
97#define BWTWO_CTL_ENABLE_INTS 0x80
98#define BWTWO_CTL_ENABLE_VIDEO 0x40
99#define BWTWO_CTL_ENABLE_TIMING 0x20
100#define BWTWO_CTL_ENABLE_CURCMP 0x10
101#define BWTWO_CTL_XTAL_MASK 0x0C
102#define BWTWO_CTL_DIVISOR_MASK 0x03
103
104/* Status Register Constants */
105#define BWTWO_STAT_PENDING_INT 0x80
106#define BWTWO_STAT_MSENSE_MASK 0x70
107#define BWTWO_STAT_ID_MASK 0x0f
108
109struct bw2_par {
110 spinlock_t lock;
111 struct bw2_regs __iomem *regs;
112
113 u32 flags;
114#define BW2_FLAG_BLANKED 0x00000001
115
116 unsigned long physbase;
50312ce9 117 unsigned long which_io;
1da177e4 118 unsigned long fbsize;
1da177e4
LT
119};
120
121/**
122 * bw2_blank - Optional function. Blanks the display.
123 * @blank_mode: the blank mode we want.
124 * @info: frame buffer structure that represents a single frame buffer
125 */
126static int
127bw2_blank(int blank, struct fb_info *info)
128{
129 struct bw2_par *par = (struct bw2_par *) info->par;
130 struct bw2_regs __iomem *regs = par->regs;
131 unsigned long flags;
132 u8 val;
133
134 spin_lock_irqsave(&par->lock, flags);
135
136 switch (blank) {
137 case FB_BLANK_UNBLANK: /* Unblanking */
138 val = sbus_readb(&regs->control);
139 val |= BWTWO_CTL_ENABLE_VIDEO;
140 sbus_writeb(val, &regs->control);
141 par->flags &= ~BW2_FLAG_BLANKED;
142 break;
143
144 case FB_BLANK_NORMAL: /* Normal blanking */
145 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
146 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
147 case FB_BLANK_POWERDOWN: /* Poweroff */
148 val = sbus_readb(&regs->control);
149 val &= ~BWTWO_CTL_ENABLE_VIDEO;
150 sbus_writeb(val, &regs->control);
151 par->flags |= BW2_FLAG_BLANKED;
152 break;
153 }
154
155 spin_unlock_irqrestore(&par->lock, flags);
156
157 return 0;
158}
159
160static struct sbus_mmap_map bw2_mmap_map[] = {
161 {
162 .size = SBUS_MMAP_FBSIZE(1)
163 },
164 { .size = 0 }
165};
166
216d526c 167static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
1da177e4
LT
168{
169 struct bw2_par *par = (struct bw2_par *)info->par;
170
171 return sbusfb_mmap_helper(bw2_mmap_map,
172 par->physbase, par->fbsize,
50312ce9 173 par->which_io,
1da177e4
LT
174 vma);
175}
176
67a6680d 177static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
1da177e4
LT
178{
179 struct bw2_par *par = (struct bw2_par *) info->par;
180
181 return sbusfb_ioctl_helper(cmd, arg, info,
182 FBTYPE_SUN2BW, 1, par->fbsize);
183}
184
185/*
186 * Initialisation
187 */
188
63abdcdc 189static void __devinit bw2_init_fix(struct fb_info *info, int linebytes)
1da177e4
LT
190{
191 strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
192
193 info->fix.type = FB_TYPE_PACKED_PIXELS;
194 info->fix.visual = FB_VISUAL_MONO01;
195
196 info->fix.line_length = linebytes;
197
198 info->fix.accel = FB_ACCEL_SUN_BWTWO;
199}
200
63abdcdc 201static u8 bw2regs_1600[] __devinitdata = {
1da177e4
LT
202 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
203 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
204 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
205 0x10, 0x21, 0
206};
207
63abdcdc 208static u8 bw2regs_ecl[] __devinitdata = {
1da177e4
LT
209 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
210 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
211 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
212 0x10, 0x20, 0
213};
214
63abdcdc 215static u8 bw2regs_analog[] __devinitdata = {
1da177e4
LT
216 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
217 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
218 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
219 0x10, 0x20, 0
220};
221
63abdcdc 222static u8 bw2regs_76hz[] __devinitdata = {
1da177e4
LT
223 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
224 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
225 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
226 0x10, 0x24, 0
227};
228
63abdcdc 229static u8 bw2regs_66hz[] __devinitdata = {
1da177e4
LT
230 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
231 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
232 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
233 0x10, 0x20, 0
234};
235
6c8f5b90
DM
236static int __devinit bw2_do_default_mode(struct bw2_par *par,
237 struct fb_info *info,
238 int *linebytes)
1da177e4
LT
239{
240 u8 status, mon;
241 u8 *p;
242
243 status = sbus_readb(&par->regs->status);
244 mon = status & BWTWO_SR_RES_MASK;
245 switch (status & BWTWO_SR_ID_MASK) {
246 case BWTWO_SR_ID_MONO_ECL:
247 if (mon == BWTWO_SR_1600_1280) {
248 p = bw2regs_1600;
249 info->var.xres = info->var.xres_virtual = 1600;
250 info->var.yres = info->var.yres_virtual = 1280;
251 *linebytes = 1600 / 8;
252 } else
253 p = bw2regs_ecl;
254 break;
255
256 case BWTWO_SR_ID_MONO:
257 p = bw2regs_analog;
258 break;
259
260 case BWTWO_SR_ID_MSYNC:
261 if (mon == BWTWO_SR_1152_900_76_A ||
262 mon == BWTWO_SR_1152_900_76_B)
263 p = bw2regs_76hz;
264 else
265 p = bw2regs_66hz;
266 break;
267
268 case BWTWO_SR_ID_NOCONN:
6c8f5b90 269 return 0;
1da177e4
LT
270
271 default:
6c8f5b90
DM
272 printk(KERN_ERR "bw2: can't handle SR %02x\n",
273 status);
274 return -EINVAL;
1da177e4
LT
275 }
276 for ( ; *p; p += 2) {
277 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
278 sbus_writeb(p[1], regp);
279 }
6c8f5b90 280 return 0;
1da177e4
LT
281}
282
c7f439b9 283static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
1da177e4 284{
50312ce9 285 struct device_node *dp = op->node;
c7f439b9
DM
286 struct fb_info *info;
287 struct bw2_par *par;
50312ce9 288 int linebytes, err;
1da177e4 289
c7f439b9 290 info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);
1da177e4 291
c7f439b9
DM
292 err = -ENOMEM;
293 if (!info)
294 goto out_err;
295 par = info->par;
50312ce9 296
c7f439b9 297 spin_lock_init(&par->lock);
50312ce9 298
c7f439b9
DM
299 par->physbase = op->resource[0].start;
300 par->which_io = op->resource[0].flags & IORESOURCE_BITS;
301
302 sbusfb_fill_var(&info->var, dp->node, 1);
50312ce9 303 linebytes = of_getintprop_default(dp, "linebytes",
c7f439b9 304 info->var.xres);
50312ce9 305
c7f439b9
DM
306 info->var.red.length = info->var.green.length =
307 info->var.blue.length = info->var.bits_per_pixel;
308 info->var.red.offset = info->var.green.offset =
309 info->var.blue.offset = 0;
1da177e4 310
c7f439b9
DM
311 par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
312 sizeof(struct bw2_regs), "bw2 regs");
313 if (!par->regs)
314 goto out_release_fb;
1da177e4 315
6c8f5b90
DM
316 if (!of_find_property(dp, "width", NULL)) {
317 err = bw2_do_default_mode(par, info, &linebytes);
318 if (err)
319 goto out_unmap_regs;
320 }
1da177e4 321
c7f439b9 322 par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
1da177e4 323
c7f439b9
DM
324 info->flags = FBINFO_DEFAULT;
325 info->fbops = &bw2_ops;
50312ce9 326
c7f439b9
DM
327 info->screen_base = of_ioremap(&op->resource[0], 0,
328 par->fbsize, "bw2 ram");
329 if (!info->screen_base)
330 goto out_unmap_regs;
1da177e4 331
c7f439b9 332 bw2_blank(0, info);
1da177e4 333
c7f439b9 334 bw2_init_fix(info, linebytes);
1da177e4 335
c7f439b9
DM
336 err = register_framebuffer(info);
337 if (err < 0)
338 goto out_unmap_screen;
1da177e4 339
c7f439b9 340 dev_set_drvdata(&op->dev, info);
50312ce9
DM
341
342 printk("%s: bwtwo at %lx:%lx\n",
c7f439b9 343 dp->full_name, par->which_io, par->physbase);
1da177e4 344
50312ce9 345 return 0;
1da177e4 346
c7f439b9
DM
347out_unmap_screen:
348 of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
349
350out_unmap_regs:
351 of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
352
353out_release_fb:
354 framebuffer_release(info);
1da177e4 355
c7f439b9
DM
356out_err:
357 return err;
50312ce9 358}
1da177e4 359
e3a411a3 360static int __devexit bw2_remove(struct of_device *op)
50312ce9 361{
c7f439b9
DM
362 struct fb_info *info = dev_get_drvdata(&op->dev);
363 struct bw2_par *par = info->par;
50312ce9 364
c7f439b9 365 unregister_framebuffer(info);
50312ce9 366
c7f439b9
DM
367 of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
368 of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
50312ce9 369
c7f439b9 370 framebuffer_release(info);
50312ce9 371
e3a411a3 372 dev_set_drvdata(&op->dev, NULL);
1da177e4
LT
373
374 return 0;
375}
376
50312ce9
DM
377static struct of_device_id bw2_match[] = {
378 {
379 .name = "bwtwo",
380 },
381 {},
382};
383MODULE_DEVICE_TABLE(of, bw2_match);
1da177e4 384
50312ce9
DM
385static struct of_platform_driver bw2_driver = {
386 .name = "bw2",
387 .match_table = bw2_match,
388 .probe = bw2_probe,
389 .remove = __devexit_p(bw2_remove),
390};
1da177e4 391
50312ce9
DM
392static int __init bw2_init(void)
393{
394 if (fb_get_options("bw2fb", NULL))
395 return -ENODEV;
396
397 return of_register_driver(&bw2_driver, &of_bus_type);
1da177e4
LT
398}
399
50312ce9 400static void __exit bw2_exit(void)
1da177e4 401{
50312ce9 402 return of_unregister_driver(&bw2_driver);
1da177e4
LT
403}
404
1da177e4 405
50312ce9 406module_init(bw2_init);
1da177e4 407module_exit(bw2_exit);
1da177e4
LT
408
409MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
50312ce9
DM
410MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
411MODULE_VERSION("2.0");
1da177e4 412MODULE_LICENSE("GPL");