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>
20 #include <linux/of_device.h>
31 static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
32 unsigned, struct fb_info
*);
33 static int cg3_blank(int, struct fb_info
*);
35 static int cg3_mmap(struct fb_info
*, struct vm_area_struct
*);
36 static int cg3_ioctl(struct fb_info
*, unsigned int, unsigned long);
39 * Frame buffer operations
42 static struct fb_ops cg3_ops
= {
44 .fb_setcolreg
= cg3_setcolreg
,
45 .fb_blank
= cg3_blank
,
46 .fb_fillrect
= cfb_fillrect
,
47 .fb_copyarea
= cfb_copyarea
,
48 .fb_imageblit
= cfb_imageblit
,
50 .fb_ioctl
= cg3_ioctl
,
52 .fb_compat_ioctl
= sbusfb_compat_ioctl
,
57 /* Control Register Constants */
58 #define CG3_CR_ENABLE_INTS 0x80
59 #define CG3_CR_ENABLE_VIDEO 0x40
60 #define CG3_CR_ENABLE_TIMING 0x20
61 #define CG3_CR_ENABLE_CURCMP 0x10
62 #define CG3_CR_XTAL_MASK 0x0c
63 #define CG3_CR_DIVISOR_MASK 0x03
65 /* Status Register Constants */
66 #define CG3_SR_PENDING_INT 0x80
67 #define CG3_SR_RES_MASK 0x70
68 #define CG3_SR_1152_900_76_A 0x40
69 #define CG3_SR_1152_900_76_B 0x60
70 #define CG3_SR_ID_MASK 0x0f
71 #define CG3_SR_ID_COLOR 0x01
72 #define CG3_SR_ID_MONO 0x02
73 #define CG3_SR_ID_MONO_ECL 0x03
99 u8 v_blank_start_high
;
100 u8 v_blank_start_low
;
104 u8 xfer_holdoff_start
;
108 /* Offset of interesting structures in the OBIO space */
109 #define CG3_REGS_OFFSET 0x400000UL
110 #define CG3_RAM_OFFSET 0x800000UL
114 struct cg3_regs __iomem
*regs
;
115 u32 sw_cmap
[((256 * 3) + 3) / 4];
118 #define CG3_FLAG_BLANKED 0x00000001
119 #define CG3_FLAG_RDI 0x00000002
121 unsigned long physbase
;
122 unsigned long which_io
;
123 unsigned long fbsize
;
127 * cg3_setcolreg - Optional function. Sets a color register.
128 * @regno: boolean, 0 copy local, 1 get_user() function
129 * @red: frame buffer colormap structure
130 * @green: The green value which can be up to 16 bits wide
131 * @blue: The blue value which can be up to 16 bits wide.
132 * @transp: If supported the alpha value which can be up to 16 bits wide.
133 * @info: frame buffer info structure
135 * The cg3 palette is loaded with 4 color values at each time
136 * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
137 * We keep a sw copy of the hw cmap to assist us in this esoteric
140 static int cg3_setcolreg(unsigned regno
,
141 unsigned red
, unsigned green
, unsigned blue
,
142 unsigned transp
, struct fb_info
*info
)
144 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
145 struct bt_regs __iomem
*bt
= &par
->regs
->cmap
;
158 spin_lock_irqsave(&par
->lock
, flags
);
160 p8
= (u8
*)par
->sw_cmap
+ (regno
* 3);
165 #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
166 #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
169 p32
= &par
->sw_cmap
[D4M3(regno
)];
170 sbus_writel(D4M4(regno
), &bt
->addr
);
172 sbus_writel(*p32
++, &bt
->color_map
);
177 spin_unlock_irqrestore(&par
->lock
, flags
);
183 * cg3_blank - Optional function. Blanks the display.
184 * @blank_mode: the blank mode we want.
185 * @info: frame buffer structure that represents a single frame buffer
187 static int cg3_blank(int blank
, struct fb_info
*info
)
189 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
190 struct cg3_regs __iomem
*regs
= par
->regs
;
194 spin_lock_irqsave(&par
->lock
, flags
);
197 case FB_BLANK_UNBLANK
: /* Unblanking */
198 val
= sbus_readb(®s
->control
);
199 val
|= CG3_CR_ENABLE_VIDEO
;
200 sbus_writeb(val
, ®s
->control
);
201 par
->flags
&= ~CG3_FLAG_BLANKED
;
204 case FB_BLANK_NORMAL
: /* Normal blanking */
205 case FB_BLANK_VSYNC_SUSPEND
: /* VESA blank (vsync off) */
206 case FB_BLANK_HSYNC_SUSPEND
: /* VESA blank (hsync off) */
207 case FB_BLANK_POWERDOWN
: /* Poweroff */
208 val
= sbus_readb(®s
->control
);
209 val
&= ~CG3_CR_ENABLE_VIDEO
;
210 sbus_writeb(val
, ®s
->control
);
211 par
->flags
|= CG3_FLAG_BLANKED
;
215 spin_unlock_irqrestore(&par
->lock
, flags
);
220 static struct sbus_mmap_map cg3_mmap_map
[] = {
222 .voff
= CG3_MMAP_OFFSET
,
223 .poff
= CG3_RAM_OFFSET
,
224 .size
= SBUS_MMAP_FBSIZE(1)
229 static int cg3_mmap(struct fb_info
*info
, struct vm_area_struct
*vma
)
231 struct cg3_par
*par
= (struct cg3_par
*)info
->par
;
233 return sbusfb_mmap_helper(cg3_mmap_map
,
234 par
->physbase
, par
->fbsize
,
239 static int cg3_ioctl(struct fb_info
*info
, unsigned int cmd
, unsigned long arg
)
241 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
243 return sbusfb_ioctl_helper(cmd
, arg
, info
,
244 FBTYPE_SUN3COLOR
, 8, par
->fbsize
);
251 static void __devinit
cg3_init_fix(struct fb_info
*info
, int linebytes
,
252 struct device_node
*dp
)
254 strlcpy(info
->fix
.id
, dp
->name
, sizeof(info
->fix
.id
));
256 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
257 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
259 info
->fix
.line_length
= linebytes
;
261 info
->fix
.accel
= FB_ACCEL_SUN_CGTHREE
;
264 static void __devinit
cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo
*var
,
265 struct device_node
*dp
)
271 params
= of_get_property(dp
, "params", NULL
);
273 ww
= simple_strtoul(params
, &p
, 10);
274 if (ww
&& *p
== 'x') {
275 hh
= simple_strtoul(p
+ 1, &p
, 10);
276 if (hh
&& *p
== '-') {
277 if (var
->xres
!= ww
||
279 var
->xres
= var
->xres_virtual
= ww
;
280 var
->yres
= var
->yres_virtual
= hh
;
287 static u8 cg3regvals_66hz
[] __devinitdata
= { /* 1152 x 900, 66 Hz */
288 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
289 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
290 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
294 static u8 cg3regvals_76hz
[] __devinitdata
= { /* 1152 x 900, 76 Hz */
295 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
296 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
297 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
301 static u8 cg3regvals_rdi
[] __devinitdata
= { /* 640 x 480, cgRDI */
302 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
303 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
304 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
308 static u8
*cg3_regvals
[] __devinitdata
= {
309 cg3regvals_66hz
, cg3regvals_76hz
, cg3regvals_rdi
312 static u_char cg3_dacvals
[] __devinitdata
= {
313 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
316 static int __devinit
cg3_do_default_mode(struct cg3_par
*par
)
321 if (par
->flags
& CG3_FLAG_RDI
)
324 u8 status
= sbus_readb(&par
->regs
->status
), mon
;
325 if ((status
& CG3_SR_ID_MASK
) == CG3_SR_ID_COLOR
) {
326 mon
= status
& CG3_SR_RES_MASK
;
327 if (mon
== CG3_SR_1152_900_76_A
||
328 mon
== CG3_SR_1152_900_76_B
)
333 printk(KERN_ERR
"cgthree: can't handle SR %02x\n",
339 for (p
= cg3_regvals
[type
]; *p
; p
+= 2) {
340 u8 __iomem
*regp
= &((u8 __iomem
*)par
->regs
)[p
[0]];
341 sbus_writeb(p
[1], regp
);
343 for (p
= cg3_dacvals
; *p
; p
+= 2) {
346 regp
= (u8 __iomem
*)&par
->regs
->cmap
.addr
;
347 sbus_writeb(p
[0], regp
);
348 regp
= (u8 __iomem
*)&par
->regs
->cmap
.control
;
349 sbus_writeb(p
[1], regp
);
354 static int __devinit
cg3_probe(struct of_device
*op
,
355 const struct of_device_id
*match
)
357 struct device_node
*dp
= op
->node
;
358 struct fb_info
*info
;
362 info
= framebuffer_alloc(sizeof(struct cg3_par
), &op
->dev
);
369 spin_lock_init(&par
->lock
);
371 par
->physbase
= op
->resource
[0].start
;
372 par
->which_io
= op
->resource
[0].flags
& IORESOURCE_BITS
;
374 sbusfb_fill_var(&info
->var
, dp
, 8);
375 info
->var
.red
.length
= 8;
376 info
->var
.green
.length
= 8;
377 info
->var
.blue
.length
= 8;
378 if (!strcmp(dp
->name
, "cgRDI"))
379 par
->flags
|= CG3_FLAG_RDI
;
380 if (par
->flags
& CG3_FLAG_RDI
)
381 cg3_rdi_maybe_fixup_var(&info
->var
, dp
);
383 linebytes
= of_getintprop_default(dp
, "linebytes",
385 par
->fbsize
= PAGE_ALIGN(linebytes
* info
->var
.yres
);
387 par
->regs
= of_ioremap(&op
->resource
[0], CG3_REGS_OFFSET
,
388 sizeof(struct cg3_regs
), "cg3 regs");
392 info
->flags
= FBINFO_DEFAULT
;
393 info
->fbops
= &cg3_ops
;
394 info
->screen_base
= of_ioremap(&op
->resource
[0], CG3_RAM_OFFSET
,
395 par
->fbsize
, "cg3 ram");
396 if (!info
->screen_base
)
399 cg3_blank(FB_BLANK_UNBLANK
, info
);
401 if (!of_find_property(dp
, "width", NULL
)) {
402 err
= cg3_do_default_mode(par
);
404 goto out_unmap_screen
;
407 if (fb_alloc_cmap(&info
->cmap
, 256, 0))
408 goto out_unmap_screen
;
410 fb_set_cmap(&info
->cmap
, info
);
412 cg3_init_fix(info
, linebytes
, dp
);
414 err
= register_framebuffer(info
);
416 goto out_dealloc_cmap
;
418 dev_set_drvdata(&op
->dev
, info
);
420 printk(KERN_INFO
"%s: cg3 at %lx:%lx\n",
421 dp
->full_name
, par
->which_io
, par
->physbase
);
426 fb_dealloc_cmap(&info
->cmap
);
429 of_iounmap(&op
->resource
[0], info
->screen_base
, par
->fbsize
);
432 of_iounmap(&op
->resource
[0], par
->regs
, sizeof(struct cg3_regs
));
435 framebuffer_release(info
);
441 static int __devexit
cg3_remove(struct of_device
*op
)
443 struct fb_info
*info
= dev_get_drvdata(&op
->dev
);
444 struct cg3_par
*par
= info
->par
;
446 unregister_framebuffer(info
);
447 fb_dealloc_cmap(&info
->cmap
);
449 of_iounmap(&op
->resource
[0], par
->regs
, sizeof(struct cg3_regs
));
450 of_iounmap(&op
->resource
[0], info
->screen_base
, par
->fbsize
);
452 framebuffer_release(info
);
454 dev_set_drvdata(&op
->dev
, NULL
);
459 static struct of_device_id cg3_match
[] = {
468 MODULE_DEVICE_TABLE(of
, cg3_match
);
470 static struct of_platform_driver cg3_driver
= {
472 .match_table
= cg3_match
,
474 .remove
= __devexit_p(cg3_remove
),
477 static int __init
cg3_init(void)
479 if (fb_get_options("cg3fb", NULL
))
482 return of_register_driver(&cg3_driver
, &of_bus_type
);
485 static void __exit
cg3_exit(void)
487 of_unregister_driver(&cg3_driver
);
490 module_init(cg3_init
);
491 module_exit(cg3_exit
);
493 MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
494 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
495 MODULE_VERSION("2.0");
496 MODULE_LICENSE("GPL");