1 /* bw2.c: BWTWO frame buffer driver
3 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
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>
23 #include <asm/oplib.h>
27 #include <asm/sun4paddr.h>
36 static int bw2_blank(int, struct fb_info *);
38 static int bw2_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
39 static int bw2_ioctl(struct inode *, struct file *, unsigned int,
40 unsigned long, struct fb_info *);
43 * Frame buffer operations
46 static struct fb_ops bw2_ops = {
48 .fb_blank = bw2_blank,
49 .fb_fillrect = cfb_fillrect,
50 .fb_copyarea = cfb_copyarea,
51 .fb_imageblit = cfb_imageblit,
53 .fb_ioctl = bw2_ioctl,
55 .fb_compat_ioctl = sbusfb_compat_ioctl,
59 /* OBio addresses for the bwtwo registers */
60 #define BWTWO_REGISTER_OFFSET 0x400000
64 volatile u32 color_map;
73 volatile u8 cursor_start;
74 volatile u8 cursor_end;
75 volatile u8 h_blank_start;
76 volatile u8 h_blank_end;
77 volatile u8 h_sync_start;
78 volatile u8 h_sync_end;
79 volatile u8 comp_sync_end;
80 volatile u8 v_blank_start_high;
81 volatile u8 v_blank_start_low;
82 volatile u8 v_blank_end;
83 volatile u8 v_sync_start;
84 volatile u8 v_sync_end;
85 volatile u8 xfer_holdoff_start;
86 volatile u8 xfer_holdoff_end;
89 /* Status Register Constants */
90 #define BWTWO_SR_RES_MASK 0x70
91 #define BWTWO_SR_1600_1280 0x50
92 #define BWTWO_SR_1152_900_76_A 0x40
93 #define BWTWO_SR_1152_900_76_B 0x60
94 #define BWTWO_SR_ID_MASK 0x0f
95 #define BWTWO_SR_ID_MONO 0x02
96 #define BWTWO_SR_ID_MONO_ECL 0x03
97 #define BWTWO_SR_ID_MSYNC 0x04
98 #define BWTWO_SR_ID_NOCONN 0x0a
100 /* Control Register Constants */
101 #define BWTWO_CTL_ENABLE_INTS 0x80
102 #define BWTWO_CTL_ENABLE_VIDEO 0x40
103 #define BWTWO_CTL_ENABLE_TIMING 0x20
104 #define BWTWO_CTL_ENABLE_CURCMP 0x10
105 #define BWTWO_CTL_XTAL_MASK 0x0C
106 #define BWTWO_CTL_DIVISOR_MASK 0x03
108 /* Status Register Constants */
109 #define BWTWO_STAT_PENDING_INT 0x80
110 #define BWTWO_STAT_MSENSE_MASK 0x70
111 #define BWTWO_STAT_ID_MASK 0x0f
115 struct bw2_regs __iomem *regs;
118 #define BW2_FLAG_BLANKED 0x00000001
120 unsigned long physbase;
121 unsigned long fbsize;
123 struct sbus_dev *sdev;
127 * bw2_blank - Optional function. Blanks the display.
128 * @blank_mode: the blank mode we want.
129 * @info: frame buffer structure that represents a single frame buffer
132 bw2_blank(int blank, struct fb_info *info)
134 struct bw2_par *par = (struct bw2_par *) info->par;
135 struct bw2_regs __iomem *regs = par->regs;
139 spin_lock_irqsave(&par->lock, flags);
142 case FB_BLANK_UNBLANK: /* Unblanking */
143 val = sbus_readb(®s->control);
144 val |= BWTWO_CTL_ENABLE_VIDEO;
145 sbus_writeb(val, ®s->control);
146 par->flags &= ~BW2_FLAG_BLANKED;
149 case FB_BLANK_NORMAL: /* Normal blanking */
150 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
151 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
152 case FB_BLANK_POWERDOWN: /* Poweroff */
153 val = sbus_readb(®s->control);
154 val &= ~BWTWO_CTL_ENABLE_VIDEO;
155 sbus_writeb(val, ®s->control);
156 par->flags |= BW2_FLAG_BLANKED;
160 spin_unlock_irqrestore(&par->lock, flags);
165 static struct sbus_mmap_map bw2_mmap_map[] = {
167 .size = SBUS_MMAP_FBSIZE(1)
172 static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
174 struct bw2_par *par = (struct bw2_par *)info->par;
176 return sbusfb_mmap_helper(bw2_mmap_map,
177 par->physbase, par->fbsize,
179 par->sdev->reg_addrs[0].which_io :
184 static int bw2_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
185 unsigned long arg, struct fb_info *info)
187 struct bw2_par *par = (struct bw2_par *) info->par;
189 return sbusfb_ioctl_helper(cmd, arg, info,
190 FBTYPE_SUN2BW, 1, par->fbsize);
198 bw2_init_fix(struct fb_info *info, int linebytes)
200 strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
202 info->fix.type = FB_TYPE_PACKED_PIXELS;
203 info->fix.visual = FB_VISUAL_MONO01;
205 info->fix.line_length = linebytes;
207 info->fix.accel = FB_ACCEL_SUN_BWTWO;
210 static u8 bw2regs_1600[] __initdata = {
211 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
212 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
213 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
217 static u8 bw2regs_ecl[] __initdata = {
218 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
219 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
220 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
224 static u8 bw2regs_analog[] __initdata = {
225 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
226 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
227 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
231 static u8 bw2regs_76hz[] __initdata = {
232 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
233 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
234 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
238 static u8 bw2regs_66hz[] __initdata = {
239 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
240 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
241 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
245 static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
251 status = sbus_readb(&par->regs->status);
252 mon = status & BWTWO_SR_RES_MASK;
253 switch (status & BWTWO_SR_ID_MASK) {
254 case BWTWO_SR_ID_MONO_ECL:
255 if (mon == BWTWO_SR_1600_1280) {
257 info->var.xres = info->var.xres_virtual = 1600;
258 info->var.yres = info->var.yres_virtual = 1280;
259 *linebytes = 1600 / 8;
264 case BWTWO_SR_ID_MONO:
268 case BWTWO_SR_ID_MSYNC:
269 if (mon == BWTWO_SR_1152_900_76_A ||
270 mon == BWTWO_SR_1152_900_76_B)
276 case BWTWO_SR_ID_NOCONN:
280 prom_printf("bw2: can't handle SR %02x\n",
284 for ( ; *p; p += 2) {
285 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
286 sbus_writeb(p[1], regp);
293 struct list_head list;
295 static LIST_HEAD(bw2_list);
297 static void bw2_init_one(struct sbus_dev *sdev)
299 struct all_info *all;
300 struct resource *resp;
306 all = kmalloc(sizeof(*all), GFP_KERNEL);
308 printk(KERN_ERR "bw2: Cannot allocate memory.\n");
311 memset(all, 0, sizeof(*all));
313 INIT_LIST_HEAD(&all->list);
315 spin_lock_init(&all->par.lock);
316 all->par.sdev = sdev;
320 all->par.physbase = sun4_bwtwo_physaddr;
321 res.start = sun4_bwtwo_physaddr;
322 res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1;
323 res.flags = IORESOURCE_IO;
325 all->info.var.xres = all->info.var.xres_virtual = 1152;
326 all->info.var.yres = all->info.var.yres_virtual = 900;
327 all->info.var.bits_per_pixel = 1;
328 linebytes = 1152 / 8;
334 all->par.physbase = sdev->reg_addrs[0].phys_addr;
335 resp = &sdev->resource[0];
336 sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1);
337 linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
341 all->info.var.red.length = all->info.var.green.length =
342 all->info.var.blue.length = all->info.var.bits_per_pixel;
343 all->info.var.red.offset = all->info.var.green.offset =
344 all->info.var.blue.offset = 0;
346 all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET,
347 sizeof(struct bw2_regs), "bw2 regs");
349 if (sdev && !prom_getbool(sdev->prom_node, "width"))
350 bw2_do_default_mode(&all->par, &all->info, &linebytes);
352 all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
354 all->info.flags = FBINFO_DEFAULT;
355 all->info.fbops = &bw2_ops;
356 #if defined(CONFIG_SPARC32)
358 all->info.screen_base = (char __iomem *)
359 prom_getintdefault(sdev->prom_node, "address", 0);
361 if (!all->info.screen_base)
362 all->info.screen_base =
363 sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram");
364 all->info.par = &all->par;
366 bw2_blank(0, &all->info);
368 bw2_init_fix(&all->info, linebytes);
370 if (register_framebuffer(&all->info) < 0) {
371 printk(KERN_ERR "bw2: Could not register framebuffer.\n");
376 list_add(&all->list, &bw2_list);
378 printk("bw2: bwtwo at %lx:%lx\n",
379 (long) (sdev ? sdev->reg_addrs[0].which_io : 0),
380 (long) all->par.physbase);
383 int __init bw2_init(void)
385 struct sbus_bus *sbus;
386 struct sbus_dev *sdev;
388 if (fb_get_options("bw2fb", NULL))
394 for_all_sbusdev(sdev, sbus) {
395 if (!strcmp(sdev->prom_name, "bwtwo"))
402 void __exit bw2_exit(void)
404 struct list_head *pos, *tmp;
406 list_for_each_safe(pos, tmp, &bw2_list) {
407 struct all_info *all = list_entry(pos, typeof(*all), list);
409 unregister_framebuffer(&all->info);
417 /* No cmdline options yet... */
421 module_init(bw2_init);
424 module_exit(bw2_exit);
427 MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
428 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
429 MODULE_LICENSE("GPL");