1 /* cg3.c: CGTHREE 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 cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
34 unsigned, struct fb_info
*);
35 static int cg3_blank(int, struct fb_info
*);
37 static int cg3_mmap(struct fb_info
*, struct vm_area_struct
*);
38 static int cg3_ioctl(struct fb_info
*, unsigned int, unsigned long);
41 * Frame buffer operations
44 static struct fb_ops cg3_ops
= {
46 .fb_setcolreg
= cg3_setcolreg
,
47 .fb_blank
= cg3_blank
,
48 .fb_fillrect
= cfb_fillrect
,
49 .fb_copyarea
= cfb_copyarea
,
50 .fb_imageblit
= cfb_imageblit
,
52 .fb_ioctl
= cg3_ioctl
,
54 .fb_compat_ioctl
= sbusfb_compat_ioctl
,
59 /* Control Register Constants */
60 #define CG3_CR_ENABLE_INTS 0x80
61 #define CG3_CR_ENABLE_VIDEO 0x40
62 #define CG3_CR_ENABLE_TIMING 0x20
63 #define CG3_CR_ENABLE_CURCMP 0x10
64 #define CG3_CR_XTAL_MASK 0x0c
65 #define CG3_CR_DIVISOR_MASK 0x03
67 /* Status Register Constants */
68 #define CG3_SR_PENDING_INT 0x80
69 #define CG3_SR_RES_MASK 0x70
70 #define CG3_SR_1152_900_76_A 0x40
71 #define CG3_SR_1152_900_76_B 0x60
72 #define CG3_SR_ID_MASK 0x0f
73 #define CG3_SR_ID_COLOR 0x01
74 #define CG3_SR_ID_MONO 0x02
75 #define CG3_SR_ID_MONO_ECL 0x03
101 u8 v_blank_start_high
;
102 u8 v_blank_start_low
;
106 u8 xfer_holdoff_start
;
110 /* Offset of interesting structures in the OBIO space */
111 #define CG3_REGS_OFFSET 0x400000UL
112 #define CG3_RAM_OFFSET 0x800000UL
116 struct cg3_regs __iomem
*regs
;
117 u32 sw_cmap
[((256 * 3) + 3) / 4];
120 #define CG3_FLAG_BLANKED 0x00000001
121 #define CG3_FLAG_RDI 0x00000002
123 unsigned long physbase
;
124 unsigned long which_io
;
125 unsigned long fbsize
;
129 * cg3_setcolreg - Optional function. Sets a color register.
130 * @regno: boolean, 0 copy local, 1 get_user() function
131 * @red: frame buffer colormap structure
132 * @green: The green value which can be up to 16 bits wide
133 * @blue: The blue value which can be up to 16 bits wide.
134 * @transp: If supported the alpha value which can be up to 16 bits wide.
135 * @info: frame buffer info structure
137 * The cg3 palette is loaded with 4 color values at each time
138 * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
139 * We keep a sw copy of the hw cmap to assist us in this esoteric
142 static int cg3_setcolreg(unsigned regno
,
143 unsigned red
, unsigned green
, unsigned blue
,
144 unsigned transp
, struct fb_info
*info
)
146 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
147 struct bt_regs __iomem
*bt
= &par
->regs
->cmap
;
160 spin_lock_irqsave(&par
->lock
, flags
);
162 p8
= (u8
*)par
->sw_cmap
+ (regno
* 3);
167 #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
168 #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
171 p32
= &par
->sw_cmap
[D4M3(regno
)];
172 sbus_writel(D4M4(regno
), &bt
->addr
);
174 sbus_writel(*p32
++, &bt
->color_map
);
179 spin_unlock_irqrestore(&par
->lock
, flags
);
185 * cg3_blank - Optional function. Blanks the display.
186 * @blank_mode: the blank mode we want.
187 * @info: frame buffer structure that represents a single frame buffer
189 static int cg3_blank(int blank
, struct fb_info
*info
)
191 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
192 struct cg3_regs __iomem
*regs
= par
->regs
;
196 spin_lock_irqsave(&par
->lock
, flags
);
199 case FB_BLANK_UNBLANK
: /* Unblanking */
200 val
= sbus_readb(®s
->control
);
201 val
|= CG3_CR_ENABLE_VIDEO
;
202 sbus_writeb(val
, ®s
->control
);
203 par
->flags
&= ~CG3_FLAG_BLANKED
;
206 case FB_BLANK_NORMAL
: /* Normal blanking */
207 case FB_BLANK_VSYNC_SUSPEND
: /* VESA blank (vsync off) */
208 case FB_BLANK_HSYNC_SUSPEND
: /* VESA blank (hsync off) */
209 case FB_BLANK_POWERDOWN
: /* Poweroff */
210 val
= sbus_readb(®s
->control
);
211 val
&= ~CG3_CR_ENABLE_VIDEO
;
212 sbus_writeb(val
, ®s
->control
);
213 par
->flags
|= CG3_FLAG_BLANKED
;
217 spin_unlock_irqrestore(&par
->lock
, flags
);
222 static struct sbus_mmap_map cg3_mmap_map
[] = {
224 .voff
= CG3_MMAP_OFFSET
,
225 .poff
= CG3_RAM_OFFSET
,
226 .size
= SBUS_MMAP_FBSIZE(1)
231 static int cg3_mmap(struct fb_info
*info
, struct vm_area_struct
*vma
)
233 struct cg3_par
*par
= (struct cg3_par
*)info
->par
;
235 return sbusfb_mmap_helper(cg3_mmap_map
,
236 par
->physbase
, par
->fbsize
,
241 static int cg3_ioctl(struct fb_info
*info
, unsigned int cmd
, unsigned long arg
)
243 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
245 return sbusfb_ioctl_helper(cmd
, arg
, info
,
246 FBTYPE_SUN3COLOR
, 8, par
->fbsize
);
253 static void __devinit
cg3_init_fix(struct fb_info
*info
, int linebytes
,
254 struct device_node
*dp
)
256 strlcpy(info
->fix
.id
, dp
->name
, sizeof(info
->fix
.id
));
258 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
259 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
261 info
->fix
.line_length
= linebytes
;
263 info
->fix
.accel
= FB_ACCEL_SUN_CGTHREE
;
266 static void __devinit
cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo
*var
,
267 struct device_node
*dp
)
273 params
= of_get_property(dp
, "params", NULL
);
275 ww
= simple_strtoul(params
, &p
, 10);
276 if (ww
&& *p
== 'x') {
277 hh
= simple_strtoul(p
+ 1, &p
, 10);
278 if (hh
&& *p
== '-') {
279 if (var
->xres
!= ww
||
281 var
->xres
= var
->xres_virtual
= ww
;
282 var
->yres
= var
->yres_virtual
= hh
;
289 static u8 cg3regvals_66hz
[] __devinitdata
= { /* 1152 x 900, 66 Hz */
290 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
291 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
292 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
296 static u8 cg3regvals_76hz
[] __devinitdata
= { /* 1152 x 900, 76 Hz */
297 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
298 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
299 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
303 static u8 cg3regvals_rdi
[] __devinitdata
= { /* 640 x 480, cgRDI */
304 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
305 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
306 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
310 static u8
*cg3_regvals
[] __devinitdata
= {
311 cg3regvals_66hz
, cg3regvals_76hz
, cg3regvals_rdi
314 static u_char cg3_dacvals
[] __devinitdata
= {
315 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
318 static int __devinit
cg3_do_default_mode(struct cg3_par
*par
)
323 if (par
->flags
& CG3_FLAG_RDI
)
326 u8 status
= sbus_readb(&par
->regs
->status
), mon
;
327 if ((status
& CG3_SR_ID_MASK
) == CG3_SR_ID_COLOR
) {
328 mon
= status
& CG3_SR_RES_MASK
;
329 if (mon
== CG3_SR_1152_900_76_A
||
330 mon
== CG3_SR_1152_900_76_B
)
335 printk(KERN_ERR
"cgthree: can't handle SR %02x\n",
341 for (p
= cg3_regvals
[type
]; *p
; p
+= 2) {
342 u8 __iomem
*regp
= &((u8 __iomem
*)par
->regs
)[p
[0]];
343 sbus_writeb(p
[1], regp
);
345 for (p
= cg3_dacvals
; *p
; p
+= 2) {
348 regp
= (u8 __iomem
*)&par
->regs
->cmap
.addr
;
349 sbus_writeb(p
[0], regp
);
350 regp
= (u8 __iomem
*)&par
->regs
->cmap
.control
;
351 sbus_writeb(p
[1], regp
);
356 static int __devinit
cg3_probe(struct of_device
*op
,
357 const struct of_device_id
*match
)
359 struct device_node
*dp
= op
->node
;
360 struct fb_info
*info
;
364 info
= framebuffer_alloc(sizeof(struct cg3_par
), &op
->dev
);
371 spin_lock_init(&par
->lock
);
373 par
->physbase
= op
->resource
[0].start
;
374 par
->which_io
= op
->resource
[0].flags
& IORESOURCE_BITS
;
376 sbusfb_fill_var(&info
->var
, dp
->node
, 8);
377 info
->var
.red
.length
= 8;
378 info
->var
.green
.length
= 8;
379 info
->var
.blue
.length
= 8;
380 if (!strcmp(dp
->name
, "cgRDI"))
381 par
->flags
|= CG3_FLAG_RDI
;
382 if (par
->flags
& CG3_FLAG_RDI
)
383 cg3_rdi_maybe_fixup_var(&info
->var
, dp
);
385 linebytes
= of_getintprop_default(dp
, "linebytes",
387 par
->fbsize
= PAGE_ALIGN(linebytes
* info
->var
.yres
);
389 par
->regs
= of_ioremap(&op
->resource
[0], CG3_REGS_OFFSET
,
390 sizeof(struct cg3_regs
), "cg3 regs");
394 info
->flags
= FBINFO_DEFAULT
;
395 info
->fbops
= &cg3_ops
;
396 info
->screen_base
= of_ioremap(&op
->resource
[0], CG3_RAM_OFFSET
,
397 par
->fbsize
, "cg3 ram");
398 if (!info
->screen_base
)
401 cg3_blank(FB_BLANK_UNBLANK
, info
);
403 if (!of_find_property(dp
, "width", NULL
)) {
404 err
= cg3_do_default_mode(par
);
406 goto out_unmap_screen
;
409 if (fb_alloc_cmap(&info
->cmap
, 256, 0))
410 goto out_unmap_screen
;
412 fb_set_cmap(&info
->cmap
, info
);
414 cg3_init_fix(info
, linebytes
, dp
);
416 err
= register_framebuffer(info
);
418 goto out_dealloc_cmap
;
420 dev_set_drvdata(&op
->dev
, info
);
422 printk(KERN_INFO
"%s: cg3 at %lx:%lx\n",
423 dp
->full_name
, par
->which_io
, par
->physbase
);
428 fb_dealloc_cmap(&info
->cmap
);
431 of_iounmap(&op
->resource
[0], info
->screen_base
, par
->fbsize
);
434 of_iounmap(&op
->resource
[0], par
->regs
, sizeof(struct cg3_regs
));
437 framebuffer_release(info
);
443 static int __devexit
cg3_remove(struct of_device
*op
)
445 struct fb_info
*info
= dev_get_drvdata(&op
->dev
);
446 struct cg3_par
*par
= info
->par
;
448 unregister_framebuffer(info
);
449 fb_dealloc_cmap(&info
->cmap
);
451 of_iounmap(&op
->resource
[0], par
->regs
, sizeof(struct cg3_regs
));
452 of_iounmap(&op
->resource
[0], info
->screen_base
, par
->fbsize
);
454 framebuffer_release(info
);
456 dev_set_drvdata(&op
->dev
, NULL
);
461 static struct of_device_id cg3_match
[] = {
470 MODULE_DEVICE_TABLE(of
, cg3_match
);
472 static struct of_platform_driver cg3_driver
= {
474 .match_table
= cg3_match
,
476 .remove
= __devexit_p(cg3_remove
),
479 static int __init
cg3_init(void)
481 if (fb_get_options("cg3fb", NULL
))
484 return of_register_driver(&cg3_driver
, &of_bus_type
);
487 static void __exit
cg3_exit(void)
489 of_unregister_driver(&cg3_driver
);
492 module_init(cg3_init
);
493 module_exit(cg3_exit
);
495 MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
496 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
497 MODULE_VERSION("2.0");
498 MODULE_LICENSE("GPL");