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/delay.h>
16 #include <linux/init.h>
19 #include <linux/of_device.h>
30 static int bw2_blank(int, struct fb_info
*);
32 static int bw2_mmap(struct fb_info
*, struct vm_area_struct
*);
33 static int bw2_ioctl(struct fb_info
*, unsigned int, unsigned long);
36 * Frame buffer operations
39 static struct fb_ops bw2_ops
= {
41 .fb_blank
= bw2_blank
,
42 .fb_fillrect
= cfb_fillrect
,
43 .fb_copyarea
= cfb_copyarea
,
44 .fb_imageblit
= cfb_imageblit
,
46 .fb_ioctl
= bw2_ioctl
,
48 .fb_compat_ioctl
= sbusfb_compat_ioctl
,
52 /* OBio addresses for the bwtwo registers */
53 #define BWTWO_REGISTER_OFFSET 0x400000
73 u8 v_blank_start_high
;
78 u8 xfer_holdoff_start
;
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
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
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
108 struct bw2_regs __iomem
*regs
;
111 #define BW2_FLAG_BLANKED 0x00000001
113 unsigned long which_io
;
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
122 bw2_blank(int blank
, struct fb_info
*info
)
124 struct bw2_par
*par
= (struct bw2_par
*) info
->par
;
125 struct bw2_regs __iomem
*regs
= par
->regs
;
129 spin_lock_irqsave(&par
->lock
, flags
);
132 case FB_BLANK_UNBLANK
: /* Unblanking */
133 val
= sbus_readb(®s
->control
);
134 val
|= BWTWO_CTL_ENABLE_VIDEO
;
135 sbus_writeb(val
, ®s
->control
);
136 par
->flags
&= ~BW2_FLAG_BLANKED
;
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(®s
->control
);
144 val
&= ~BWTWO_CTL_ENABLE_VIDEO
;
145 sbus_writeb(val
, ®s
->control
);
146 par
->flags
|= BW2_FLAG_BLANKED
;
150 spin_unlock_irqrestore(&par
->lock
, flags
);
155 static struct sbus_mmap_map bw2_mmap_map
[] = {
157 .size
= SBUS_MMAP_FBSIZE(1)
162 static int bw2_mmap(struct fb_info
*info
, struct vm_area_struct
*vma
)
164 struct bw2_par
*par
= (struct bw2_par
*)info
->par
;
166 return sbusfb_mmap_helper(bw2_mmap_map
,
167 info
->fix
.smem_start
, info
->fix
.smem_len
,
172 static int bw2_ioctl(struct fb_info
*info
, unsigned int cmd
, unsigned long arg
)
174 return sbusfb_ioctl_helper(cmd
, arg
, info
,
175 FBTYPE_SUN2BW
, 1, info
->fix
.smem_len
);
182 static void bw2_init_fix(struct fb_info
*info
, int linebytes
)
184 strlcpy(info
->fix
.id
, "bwtwo", sizeof(info
->fix
.id
));
186 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
187 info
->fix
.visual
= FB_VISUAL_MONO01
;
189 info
->fix
.line_length
= linebytes
;
191 info
->fix
.accel
= FB_ACCEL_SUN_BWTWO
;
194 static u8 bw2regs_1600
[] = {
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,
201 static u8 bw2regs_ecl
[] = {
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,
208 static u8 bw2regs_analog
[] = {
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,
215 static u8 bw2regs_76hz
[] = {
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,
222 static u8 bw2regs_66hz
[] = {
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,
229 static int bw2_do_default_mode(struct bw2_par
*par
, struct fb_info
*info
,
235 status
= sbus_readb(&par
->regs
->status
);
236 mon
= status
& BWTWO_SR_RES_MASK
;
237 switch (status
& BWTWO_SR_ID_MASK
) {
238 case BWTWO_SR_ID_MONO_ECL
:
239 if (mon
== BWTWO_SR_1600_1280
) {
241 info
->var
.xres
= info
->var
.xres_virtual
= 1600;
242 info
->var
.yres
= info
->var
.yres_virtual
= 1280;
243 *linebytes
= 1600 / 8;
248 case BWTWO_SR_ID_MONO
:
252 case BWTWO_SR_ID_MSYNC
:
253 if (mon
== BWTWO_SR_1152_900_76_A
||
254 mon
== BWTWO_SR_1152_900_76_B
)
260 case BWTWO_SR_ID_NOCONN
:
264 printk(KERN_ERR
"bw2: can't handle SR %02x\n",
268 for ( ; *p
; p
+= 2) {
269 u8 __iomem
*regp
= &((u8 __iomem
*)par
->regs
)[p
[0]];
270 sbus_writeb(p
[1], regp
);
275 static int bw2_probe(struct platform_device
*op
)
277 struct device_node
*dp
= op
->dev
.of_node
;
278 struct fb_info
*info
;
282 info
= framebuffer_alloc(sizeof(struct bw2_par
), &op
->dev
);
289 spin_lock_init(&par
->lock
);
291 info
->fix
.smem_start
= op
->resource
[0].start
;
292 par
->which_io
= op
->resource
[0].flags
& IORESOURCE_BITS
;
294 sbusfb_fill_var(&info
->var
, dp
, 1);
295 linebytes
= of_getintprop_default(dp
, "linebytes",
298 info
->var
.red
.length
= info
->var
.green
.length
=
299 info
->var
.blue
.length
= info
->var
.bits_per_pixel
;
300 info
->var
.red
.offset
= info
->var
.green
.offset
=
301 info
->var
.blue
.offset
= 0;
303 par
->regs
= of_ioremap(&op
->resource
[0], BWTWO_REGISTER_OFFSET
,
304 sizeof(struct bw2_regs
), "bw2 regs");
308 if (!of_find_property(dp
, "width", NULL
)) {
309 err
= bw2_do_default_mode(par
, info
, &linebytes
);
314 info
->fix
.smem_len
= PAGE_ALIGN(linebytes
* info
->var
.yres
);
316 info
->flags
= FBINFO_DEFAULT
;
317 info
->fbops
= &bw2_ops
;
319 info
->screen_base
= of_ioremap(&op
->resource
[0], 0,
320 info
->fix
.smem_len
, "bw2 ram");
321 if (!info
->screen_base
) {
326 bw2_blank(FB_BLANK_UNBLANK
, info
);
328 bw2_init_fix(info
, linebytes
);
330 err
= register_framebuffer(info
);
332 goto out_unmap_screen
;
334 dev_set_drvdata(&op
->dev
, info
);
336 printk(KERN_INFO
"%s: bwtwo at %lx:%lx\n",
337 dp
->full_name
, par
->which_io
, info
->fix
.smem_start
);
342 of_iounmap(&op
->resource
[0], info
->screen_base
, info
->fix
.smem_len
);
345 of_iounmap(&op
->resource
[0], par
->regs
, sizeof(struct bw2_regs
));
348 framebuffer_release(info
);
354 static int bw2_remove(struct platform_device
*op
)
356 struct fb_info
*info
= dev_get_drvdata(&op
->dev
);
357 struct bw2_par
*par
= info
->par
;
359 unregister_framebuffer(info
);
361 of_iounmap(&op
->resource
[0], par
->regs
, sizeof(struct bw2_regs
));
362 of_iounmap(&op
->resource
[0], info
->screen_base
, info
->fix
.smem_len
);
364 framebuffer_release(info
);
369 static const struct of_device_id bw2_match
[] = {
375 MODULE_DEVICE_TABLE(of
, bw2_match
);
377 static struct platform_driver bw2_driver
= {
380 .owner
= THIS_MODULE
,
381 .of_match_table
= bw2_match
,
384 .remove
= bw2_remove
,
387 static int __init
bw2_init(void)
389 if (fb_get_options("bw2fb", NULL
))
392 return platform_driver_register(&bw2_driver
);
395 static void __exit
bw2_exit(void)
397 platform_driver_unregister(&bw2_driver
);
400 module_init(bw2_init
);
401 module_exit(bw2_exit
);
403 MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
404 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
405 MODULE_VERSION("2.0");
406 MODULE_LICENSE("GPL");