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
,
54 .fb_cursor
= soft_cursor
,
57 /* OBio addresses for the bwtwo registers */
58 #define BWTWO_REGISTER_OFFSET 0x400000
62 volatile u32 color_map
;
71 volatile u8 cursor_start
;
72 volatile u8 cursor_end
;
73 volatile u8 h_blank_start
;
74 volatile u8 h_blank_end
;
75 volatile u8 h_sync_start
;
76 volatile u8 h_sync_end
;
77 volatile u8 comp_sync_end
;
78 volatile u8 v_blank_start_high
;
79 volatile u8 v_blank_start_low
;
80 volatile u8 v_blank_end
;
81 volatile u8 v_sync_start
;
82 volatile u8 v_sync_end
;
83 volatile u8 xfer_holdoff_start
;
84 volatile u8 xfer_holdoff_end
;
87 /* Status Register Constants */
88 #define BWTWO_SR_RES_MASK 0x70
89 #define BWTWO_SR_1600_1280 0x50
90 #define BWTWO_SR_1152_900_76_A 0x40
91 #define BWTWO_SR_1152_900_76_B 0x60
92 #define BWTWO_SR_ID_MASK 0x0f
93 #define BWTWO_SR_ID_MONO 0x02
94 #define BWTWO_SR_ID_MONO_ECL 0x03
95 #define BWTWO_SR_ID_MSYNC 0x04
96 #define BWTWO_SR_ID_NOCONN 0x0a
98 /* Control Register Constants */
99 #define BWTWO_CTL_ENABLE_INTS 0x80
100 #define BWTWO_CTL_ENABLE_VIDEO 0x40
101 #define BWTWO_CTL_ENABLE_TIMING 0x20
102 #define BWTWO_CTL_ENABLE_CURCMP 0x10
103 #define BWTWO_CTL_XTAL_MASK 0x0C
104 #define BWTWO_CTL_DIVISOR_MASK 0x03
106 /* Status Register Constants */
107 #define BWTWO_STAT_PENDING_INT 0x80
108 #define BWTWO_STAT_MSENSE_MASK 0x70
109 #define BWTWO_STAT_ID_MASK 0x0f
113 struct bw2_regs __iomem
*regs
;
116 #define BW2_FLAG_BLANKED 0x00000001
118 unsigned long physbase
;
119 unsigned long fbsize
;
121 struct sbus_dev
*sdev
;
122 struct list_head list
;
126 * bw2_blank - Optional function. Blanks the display.
127 * @blank_mode: the blank mode we want.
128 * @info: frame buffer structure that represents a single frame buffer
131 bw2_blank(int blank
, struct fb_info
*info
)
133 struct bw2_par
*par
= (struct bw2_par
*) info
->par
;
134 struct bw2_regs __iomem
*regs
= par
->regs
;
138 spin_lock_irqsave(&par
->lock
, flags
);
141 case FB_BLANK_UNBLANK
: /* Unblanking */
142 val
= sbus_readb(®s
->control
);
143 val
|= BWTWO_CTL_ENABLE_VIDEO
;
144 sbus_writeb(val
, ®s
->control
);
145 par
->flags
&= ~BW2_FLAG_BLANKED
;
148 case FB_BLANK_NORMAL
: /* Normal blanking */
149 case FB_BLANK_VSYNC_SUSPEND
: /* VESA blank (vsync off) */
150 case FB_BLANK_HSYNC_SUSPEND
: /* VESA blank (hsync off) */
151 case FB_BLANK_POWERDOWN
: /* Poweroff */
152 val
= sbus_readb(®s
->control
);
153 val
&= ~BWTWO_CTL_ENABLE_VIDEO
;
154 sbus_writeb(val
, ®s
->control
);
155 par
->flags
|= BW2_FLAG_BLANKED
;
159 spin_unlock_irqrestore(&par
->lock
, flags
);
164 static struct sbus_mmap_map bw2_mmap_map
[] = {
166 .size
= SBUS_MMAP_FBSIZE(1)
171 static int bw2_mmap(struct fb_info
*info
, struct file
*file
, struct vm_area_struct
*vma
)
173 struct bw2_par
*par
= (struct bw2_par
*)info
->par
;
175 return sbusfb_mmap_helper(bw2_mmap_map
,
176 par
->physbase
, par
->fbsize
,
178 par
->sdev
->reg_addrs
[0].which_io
:
183 static int bw2_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
184 unsigned long arg
, struct fb_info
*info
)
186 struct bw2_par
*par
= (struct bw2_par
*) info
->par
;
188 return sbusfb_ioctl_helper(cmd
, arg
, info
,
189 FBTYPE_SUN2BW
, 1, par
->fbsize
);
197 bw2_init_fix(struct fb_info
*info
, int linebytes
)
199 strlcpy(info
->fix
.id
, "bwtwo", sizeof(info
->fix
.id
));
201 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
202 info
->fix
.visual
= FB_VISUAL_MONO01
;
204 info
->fix
.line_length
= linebytes
;
206 info
->fix
.accel
= FB_ACCEL_SUN_BWTWO
;
209 static u8 bw2regs_1600
[] __initdata
= {
210 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
211 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
212 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
216 static u8 bw2regs_ecl
[] __initdata
= {
217 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
218 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
219 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
223 static u8 bw2regs_analog
[] __initdata
= {
224 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
225 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
226 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
230 static u8 bw2regs_76hz
[] __initdata
= {
231 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
232 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
233 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
237 static u8 bw2regs_66hz
[] __initdata
= {
238 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
239 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
240 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
244 static void bw2_do_default_mode(struct bw2_par
*par
, struct fb_info
*info
,
250 status
= sbus_readb(&par
->regs
->status
);
251 mon
= status
& BWTWO_SR_RES_MASK
;
252 switch (status
& BWTWO_SR_ID_MASK
) {
253 case BWTWO_SR_ID_MONO_ECL
:
254 if (mon
== BWTWO_SR_1600_1280
) {
256 info
->var
.xres
= info
->var
.xres_virtual
= 1600;
257 info
->var
.yres
= info
->var
.yres_virtual
= 1280;
258 *linebytes
= 1600 / 8;
263 case BWTWO_SR_ID_MONO
:
267 case BWTWO_SR_ID_MSYNC
:
268 if (mon
== BWTWO_SR_1152_900_76_A
||
269 mon
== BWTWO_SR_1152_900_76_B
)
275 case BWTWO_SR_ID_NOCONN
:
279 prom_printf("bw2: can't handle SR %02x\n",
283 for ( ; *p
; p
+= 2) {
284 u8 __iomem
*regp
= &((u8 __iomem
*)par
->regs
)[p
[0]];
285 sbus_writeb(p
[1], regp
);
292 struct list_head list
;
294 static LIST_HEAD(bw2_list
);
296 static void bw2_init_one(struct sbus_dev
*sdev
)
298 struct all_info
*all
;
299 struct resource
*resp
;
305 all
= kmalloc(sizeof(*all
), GFP_KERNEL
);
307 printk(KERN_ERR
"bw2: Cannot allocate memory.\n");
310 memset(all
, 0, sizeof(*all
));
312 INIT_LIST_HEAD(&all
->list
);
314 spin_lock_init(&all
->par
.lock
);
315 all
->par
.sdev
= sdev
;
319 all
->par
.physbase
= sun4_bwtwo_physaddr
;
320 res
.start
= sun4_bwtwo_physaddr
;
321 res
.end
= res
.start
+ BWTWO_REGISTER_OFFSET
+ sizeof(struct bw2_regs
) - 1;
322 res
.flags
= IORESOURCE_IO
;
324 all
->info
.var
.xres
= all
->info
.var
.xres_virtual
= 1152;
325 all
->info
.var
.yres
= all
->info
.var
.yres_virtual
= 900;
326 all
->info
.var
.bits_per_pixel
= 1;
327 linebytes
= 1152 / 8;
333 all
->par
.physbase
= sdev
->reg_addrs
[0].phys_addr
;
334 resp
= &sdev
->resource
[0];
335 sbusfb_fill_var(&all
->info
.var
, (sdev
? sdev
->prom_node
: 0), 1);
336 linebytes
= prom_getintdefault(sdev
->prom_node
, "linebytes",
340 all
->info
.var
.red
.length
= all
->info
.var
.green
.length
=
341 all
->info
.var
.blue
.length
= all
->info
.var
.bits_per_pixel
;
342 all
->info
.var
.red
.offset
= all
->info
.var
.green
.offset
=
343 all
->info
.var
.blue
.offset
= 0;
345 all
->par
.regs
= sbus_ioremap(resp
, BWTWO_REGISTER_OFFSET
,
346 sizeof(struct bw2_regs
), "bw2 regs");
348 if (sdev
&& !prom_getbool(sdev
->prom_node
, "width"))
349 bw2_do_default_mode(&all
->par
, &all
->info
, &linebytes
);
351 all
->par
.fbsize
= PAGE_ALIGN(linebytes
* all
->info
.var
.yres
);
353 all
->info
.flags
= FBINFO_DEFAULT
;
354 all
->info
.fbops
= &bw2_ops
;
355 #if defined(CONFIG_SPARC32)
357 all
->info
.screen_base
= (char __iomem
*)
358 prom_getintdefault(sdev
->prom_node
, "address", 0);
360 if (!all
->info
.screen_base
)
361 all
->info
.screen_base
=
362 sbus_ioremap(resp
, 0, all
->par
.fbsize
, "bw2 ram");
363 all
->info
.par
= &all
->par
;
365 bw2_blank(0, &all
->info
);
367 bw2_init_fix(&all
->info
, linebytes
);
369 if (register_framebuffer(&all
->info
) < 0) {
370 printk(KERN_ERR
"bw2: Could not register framebuffer.\n");
375 list_add(&all
->list
, &bw2_list
);
377 printk("bw2: bwtwo at %lx:%lx\n",
378 (long) (sdev
? sdev
->reg_addrs
[0].which_io
: 0),
379 (long) all
->par
.physbase
);
382 int __init
bw2_init(void)
384 struct sbus_bus
*sbus
;
385 struct sbus_dev
*sdev
;
387 if (fb_get_options("bw2fb", NULL
))
393 for_all_sbusdev(sdev
, sbus
) {
394 if (!strcmp(sdev
->prom_name
, "bwtwo"))
401 void __exit
bw2_exit(void)
403 struct list_head
*pos
, *tmp
;
405 list_for_each_safe(pos
, tmp
, &bw2_list
) {
406 struct all_info
*all
= list_entry(pos
, typeof(*all
), list
);
408 unregister_framebuffer(&all
->info
);
416 /* No cmdline options yet... */
420 module_init(bw2_init
);
423 module_exit(bw2_exit
);
426 MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
427 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
428 MODULE_LICENSE("GPL");