1 /* bw2.c: BWTWO frame buffer driver
3 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
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)
8 * Driver layout based loosely on tgafb.c, see that file for credits.
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>
22 #include <asm/oplib.h>
24 #include <asm/of_device.h>
33 static int bw2_blank(int, struct fb_info *);
35 static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
36 static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
39 * Frame buffer operations
42 static struct fb_ops bw2_ops = {
44 .fb_blank = bw2_blank,
45 .fb_fillrect = cfb_fillrect,
46 .fb_copyarea = cfb_copyarea,
47 .fb_imageblit = cfb_imageblit,
49 .fb_ioctl = bw2_ioctl,
51 .fb_compat_ioctl = sbusfb_compat_ioctl,
55 /* OBio addresses for the bwtwo registers */
56 #define BWTWO_REGISTER_OFFSET 0x400000
76 u8 v_blank_start_high;
81 u8 xfer_holdoff_start;
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
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
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
111 struct bw2_regs __iomem *regs;
114 #define BW2_FLAG_BLANKED 0x00000001
116 unsigned long physbase;
117 unsigned long which_io;
118 unsigned long fbsize;
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
127 bw2_blank(int blank, struct fb_info *info)
129 struct bw2_par *par = (struct bw2_par *) info->par;
130 struct bw2_regs __iomem *regs = par->regs;
134 spin_lock_irqsave(&par->lock, flags);
137 case FB_BLANK_UNBLANK: /* Unblanking */
138 val = sbus_readb(®s->control);
139 val |= BWTWO_CTL_ENABLE_VIDEO;
140 sbus_writeb(val, ®s->control);
141 par->flags &= ~BW2_FLAG_BLANKED;
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(®s->control);
149 val &= ~BWTWO_CTL_ENABLE_VIDEO;
150 sbus_writeb(val, ®s->control);
151 par->flags |= BW2_FLAG_BLANKED;
155 spin_unlock_irqrestore(&par->lock, flags);
160 static struct sbus_mmap_map bw2_mmap_map[] = {
162 .size = SBUS_MMAP_FBSIZE(1)
167 static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
169 struct bw2_par *par = (struct bw2_par *)info->par;
171 return sbusfb_mmap_helper(bw2_mmap_map,
172 par->physbase, par->fbsize,
177 static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
179 struct bw2_par *par = (struct bw2_par *) info->par;
181 return sbusfb_ioctl_helper(cmd, arg, info,
182 FBTYPE_SUN2BW, 1, par->fbsize);
190 bw2_init_fix(struct fb_info *info, int linebytes)
192 strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
194 info->fix.type = FB_TYPE_PACKED_PIXELS;
195 info->fix.visual = FB_VISUAL_MONO01;
197 info->fix.line_length = linebytes;
199 info->fix.accel = FB_ACCEL_SUN_BWTWO;
202 static u8 bw2regs_1600[] __initdata = {
203 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
204 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
205 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
209 static u8 bw2regs_ecl[] __initdata = {
210 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
211 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
212 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
216 static u8 bw2regs_analog[] __initdata = {
217 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
218 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
219 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
223 static u8 bw2regs_76hz[] __initdata = {
224 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
225 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
226 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
230 static u8 bw2regs_66hz[] __initdata = {
231 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
232 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
233 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
237 static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
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) {
249 info->var.xres = info->var.xres_virtual = 1600;
250 info->var.yres = info->var.yres_virtual = 1280;
251 *linebytes = 1600 / 8;
256 case BWTWO_SR_ID_MONO:
260 case BWTWO_SR_ID_MSYNC:
261 if (mon == BWTWO_SR_1152_900_76_A ||
262 mon == BWTWO_SR_1152_900_76_B)
268 case BWTWO_SR_ID_NOCONN:
272 prom_printf("bw2: can't handle SR %02x\n",
276 for ( ; *p; p += 2) {
277 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
278 sbus_writeb(p[1], regp);
287 static int __devinit bw2_init_one(struct of_device *op)
289 struct device_node *dp = op->node;
290 struct all_info *all;
293 all = kzalloc(sizeof(*all), GFP_KERNEL);
297 spin_lock_init(&all->par.lock);
299 all->par.physbase = op->resource[0].start;
300 all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
302 sbusfb_fill_var(&all->info.var, dp->node, 1);
303 linebytes = of_getintprop_default(dp, "linebytes",
306 all->info.var.red.length = all->info.var.green.length =
307 all->info.var.blue.length = all->info.var.bits_per_pixel;
308 all->info.var.red.offset = all->info.var.green.offset =
309 all->info.var.blue.offset = 0;
311 all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
312 sizeof(struct bw2_regs), "bw2 regs");
314 if (!of_find_property(dp, "width", NULL))
315 bw2_do_default_mode(&all->par, &all->info, &linebytes);
317 all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
319 all->info.flags = FBINFO_DEFAULT;
320 all->info.fbops = &bw2_ops;
322 all->info.screen_base =
323 sbus_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram");
324 all->info.par = &all->par;
326 bw2_blank(0, &all->info);
328 bw2_init_fix(&all->info, linebytes);
330 err= register_framebuffer(&all->info);
332 of_iounmap(all->par.regs, sizeof(struct bw2_regs));
333 of_iounmap(all->info.screen_base, all->par.fbsize);
338 dev_set_drvdata(&op->dev, all);
340 printk("%s: bwtwo at %lx:%lx\n",
342 all->par.which_io, all->par.physbase);
347 static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match)
349 struct of_device *op = to_of_device(&dev->dev);
351 return bw2_init_one(op);
354 static int __devexit bw2_remove(struct of_device *dev)
356 struct all_info *all = dev_get_drvdata(&dev->dev);
358 unregister_framebuffer(&all->info);
360 of_iounmap(all->par.regs, sizeof(struct bw2_regs));
361 of_iounmap(all->info.screen_base, all->par.fbsize);
365 dev_set_drvdata(&dev->dev, NULL);
370 static struct of_device_id bw2_match[] = {
376 MODULE_DEVICE_TABLE(of, bw2_match);
378 static struct of_platform_driver bw2_driver = {
380 .match_table = bw2_match,
382 .remove = __devexit_p(bw2_remove),
385 static int __init bw2_init(void)
387 if (fb_get_options("bw2fb", NULL))
390 return of_register_driver(&bw2_driver, &of_bus_type);
393 static void __exit bw2_exit(void)
395 return of_unregister_driver(&bw2_driver);
399 module_init(bw2_init);
400 module_exit(bw2_exit);
402 MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
403 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
404 MODULE_VERSION("2.0");
405 MODULE_LICENSE("GPL");