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