1 /* cg3.c: CGTHREE 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>
32 static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
33 unsigned, struct fb_info
*);
34 static int cg3_blank(int, struct fb_info
*);
36 static int cg3_mmap(struct fb_info
*, struct file
*, struct vm_area_struct
*);
37 static int cg3_ioctl(struct inode
*, struct file
*, unsigned int,
38 unsigned long, struct fb_info
*);
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
85 volatile u32 color_map
;
94 volatile u8 cursor_start
;
95 volatile u8 cursor_end
;
96 volatile u8 h_blank_start
;
97 volatile u8 h_blank_end
;
98 volatile u8 h_sync_start
;
99 volatile u8 h_sync_end
;
100 volatile u8 comp_sync_end
;
101 volatile u8 v_blank_start_high
;
102 volatile u8 v_blank_start_low
;
103 volatile u8 v_blank_end
;
104 volatile u8 v_sync_start
;
105 volatile u8 v_sync_end
;
106 volatile u8 xfer_holdoff_start
;
107 volatile u8 xfer_holdoff_end
;
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 fbsize
;
126 struct sbus_dev
*sdev
;
127 struct list_head list
;
131 * cg3_setcolreg - Optional function. Sets a color register.
132 * @regno: boolean, 0 copy local, 1 get_user() function
133 * @red: frame buffer colormap structure
134 * @green: The green value which can be up to 16 bits wide
135 * @blue: The blue value which can be up to 16 bits wide.
136 * @transp: If supported the alpha value which can be up to 16 bits wide.
137 * @info: frame buffer info structure
139 * The cg3 palette is loaded with 4 color values at each time
140 * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
141 * We keep a sw copy of the hw cmap to assist us in this esoteric
144 static int cg3_setcolreg(unsigned regno
,
145 unsigned red
, unsigned green
, unsigned blue
,
146 unsigned transp
, struct fb_info
*info
)
148 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
149 struct bt_regs __iomem
*bt
= &par
->regs
->cmap
;
162 spin_lock_irqsave(&par
->lock
, flags
);
164 p8
= (u8
*)par
->sw_cmap
+ (regno
* 3);
169 #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
170 #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
173 p32
= &par
->sw_cmap
[D4M3(regno
)];
174 sbus_writel(D4M4(regno
), &bt
->addr
);
176 sbus_writel(*p32
++, &bt
->color_map
);
181 spin_unlock_irqrestore(&par
->lock
, flags
);
187 * cg3_blank - Optional function. Blanks the display.
188 * @blank_mode: the blank mode we want.
189 * @info: frame buffer structure that represents a single frame buffer
192 cg3_blank(int blank
, struct fb_info
*info
)
194 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
195 struct cg3_regs __iomem
*regs
= par
->regs
;
199 spin_lock_irqsave(&par
->lock
, flags
);
202 case FB_BLANK_UNBLANK
: /* Unblanking */
203 val
= sbus_readb(®s
->control
);
204 val
|= CG3_CR_ENABLE_VIDEO
;
205 sbus_writeb(val
, ®s
->control
);
206 par
->flags
&= ~CG3_FLAG_BLANKED
;
209 case FB_BLANK_NORMAL
: /* Normal blanking */
210 case FB_BLANK_VSYNC_SUSPEND
: /* VESA blank (vsync off) */
211 case FB_BLANK_HSYNC_SUSPEND
: /* VESA blank (hsync off) */
212 case FB_BLANK_POWERDOWN
: /* Poweroff */
213 val
= sbus_readb(®s
->control
);
214 val
&= ~CG3_CR_ENABLE_VIDEO
;
215 sbus_writeb(val
, ®s
->control
);
216 par
->flags
|= CG3_FLAG_BLANKED
;
220 spin_unlock_irqrestore(&par
->lock
, flags
);
225 static struct sbus_mmap_map cg3_mmap_map
[] = {
227 .voff
= CG3_MMAP_OFFSET
,
228 .poff
= CG3_RAM_OFFSET
,
229 .size
= SBUS_MMAP_FBSIZE(1)
234 static int cg3_mmap(struct fb_info
*info
, struct file
*file
, struct vm_area_struct
*vma
)
236 struct cg3_par
*par
= (struct cg3_par
*)info
->par
;
238 return sbusfb_mmap_helper(cg3_mmap_map
,
239 par
->physbase
, par
->fbsize
,
240 par
->sdev
->reg_addrs
[0].which_io
,
244 static int cg3_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
245 unsigned long arg
, struct fb_info
*info
)
247 struct cg3_par
*par
= (struct cg3_par
*) info
->par
;
249 return sbusfb_ioctl_helper(cmd
, arg
, info
,
250 FBTYPE_SUN3COLOR
, 8, par
->fbsize
);
258 cg3_init_fix(struct fb_info
*info
, int linebytes
)
260 struct cg3_par
*par
= (struct cg3_par
*)info
->par
;
262 strlcpy(info
->fix
.id
, par
->sdev
->prom_name
, sizeof(info
->fix
.id
));
264 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
265 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
267 info
->fix
.line_length
= linebytes
;
269 info
->fix
.accel
= FB_ACCEL_SUN_CGTHREE
;
272 static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo
*var
,
273 struct sbus_dev
*sdev
)
280 prom_getstring(sdev
->prom_node
, "params", buffer
, sizeof(buffer
));
282 ww
= simple_strtoul(buffer
, &p
, 10);
283 if (ww
&& *p
== 'x') {
284 hh
= simple_strtoul(p
+ 1, &p
, 10);
285 if (hh
&& *p
== '-') {
286 if (var
->xres
!= ww
||
288 var
->xres
= var
->xres_virtual
= ww
;
289 var
->yres
= var
->yres_virtual
= hh
;
296 static u8 cg3regvals_66hz
[] __initdata
= { /* 1152 x 900, 66 Hz */
297 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
298 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
299 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
303 static u8 cg3regvals_76hz
[] __initdata
= { /* 1152 x 900, 76 Hz */
304 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
305 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
306 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
310 static u8 cg3regvals_rdi
[] __initdata
= { /* 640 x 480, cgRDI */
311 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
312 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
313 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
317 static u8
*cg3_regvals
[] __initdata
= {
318 cg3regvals_66hz
, cg3regvals_76hz
, cg3regvals_rdi
321 static u_char cg3_dacvals
[] __initdata
= {
322 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
325 static void cg3_do_default_mode(struct cg3_par
*par
)
330 if (par
->flags
& CG3_FLAG_RDI
)
333 u8 status
= sbus_readb(&par
->regs
->status
), mon
;
334 if ((status
& CG3_SR_ID_MASK
) == CG3_SR_ID_COLOR
) {
335 mon
= status
& CG3_SR_RES_MASK
;
336 if (mon
== CG3_SR_1152_900_76_A
||
337 mon
== CG3_SR_1152_900_76_B
)
342 prom_printf("cgthree: can't handle SR %02x\n",
349 for (p
= cg3_regvals
[type
]; *p
; p
+= 2) {
350 u8 __iomem
*regp
= &((u8 __iomem
*)par
->regs
)[p
[0]];
351 sbus_writeb(p
[1], regp
);
353 for (p
= cg3_dacvals
; *p
; p
+= 2) {
354 volatile u8 __iomem
*regp
;
356 regp
= (volatile u8 __iomem
*)&par
->regs
->cmap
.addr
;
357 sbus_writeb(p
[0], regp
);
358 regp
= (volatile u8 __iomem
*)&par
->regs
->cmap
.control
;
359 sbus_writeb(p
[1], regp
);
366 struct list_head list
;
368 static LIST_HEAD(cg3_list
);
370 static void cg3_init_one(struct sbus_dev
*sdev
)
372 struct all_info
*all
;
375 all
= kmalloc(sizeof(*all
), GFP_KERNEL
);
377 printk(KERN_ERR
"cg3: Cannot allocate memory.\n");
380 memset(all
, 0, sizeof(*all
));
382 INIT_LIST_HEAD(&all
->list
);
384 spin_lock_init(&all
->par
.lock
);
385 all
->par
.sdev
= sdev
;
387 all
->par
.physbase
= sdev
->reg_addrs
[0].phys_addr
;
389 sbusfb_fill_var(&all
->info
.var
, sdev
->prom_node
, 8);
390 all
->info
.var
.red
.length
= 8;
391 all
->info
.var
.green
.length
= 8;
392 all
->info
.var
.blue
.length
= 8;
393 if (!strcmp(sdev
->prom_name
, "cgRDI"))
394 all
->par
.flags
|= CG3_FLAG_RDI
;
395 if (all
->par
.flags
& CG3_FLAG_RDI
)
396 cg3_rdi_maybe_fixup_var(&all
->info
.var
, sdev
);
398 linebytes
= prom_getintdefault(sdev
->prom_node
, "linebytes",
400 all
->par
.fbsize
= PAGE_ALIGN(linebytes
* all
->info
.var
.yres
);
402 all
->par
.regs
= sbus_ioremap(&sdev
->resource
[0], CG3_REGS_OFFSET
,
403 sizeof(struct cg3_regs
), "cg3 regs");
405 all
->info
.flags
= FBINFO_DEFAULT
;
406 all
->info
.fbops
= &cg3_ops
;
407 #ifdef CONFIG_SPARC32
408 all
->info
.screen_base
= (char __iomem
*)
409 prom_getintdefault(sdev
->prom_node
, "address", 0);
411 if (!all
->info
.screen_base
)
412 all
->info
.screen_base
=
413 sbus_ioremap(&sdev
->resource
[0], CG3_RAM_OFFSET
,
414 all
->par
.fbsize
, "cg3 ram");
415 all
->info
.par
= &all
->par
;
417 cg3_blank(0, &all
->info
);
419 if (!prom_getbool(sdev
->prom_node
, "width"))
420 cg3_do_default_mode(&all
->par
);
422 if (fb_alloc_cmap(&all
->info
.cmap
, 256, 0)) {
423 printk(KERN_ERR
"cg3: Could not allocate color map.\n");
427 fb_set_cmap(&all
->info
.cmap
, &all
->info
);
429 cg3_init_fix(&all
->info
, linebytes
);
431 if (register_framebuffer(&all
->info
) < 0) {
432 printk(KERN_ERR
"cg3: Could not register framebuffer.\n");
433 fb_dealloc_cmap(&all
->info
.cmap
);
438 list_add(&all
->list
, &cg3_list
);
440 printk("cg3: %s at %lx:%lx\n",
442 (long) sdev
->reg_addrs
[0].which_io
,
443 (long) sdev
->reg_addrs
[0].phys_addr
);
446 int __init
cg3_init(void)
448 struct sbus_bus
*sbus
;
449 struct sbus_dev
*sdev
;
451 if (fb_get_options("cg3fb", NULL
))
454 for_all_sbusdev(sdev
, sbus
) {
455 if (!strcmp(sdev
->prom_name
, "cgthree") ||
456 !strcmp(sdev
->prom_name
, "cgRDI"))
463 void __exit
cg3_exit(void)
465 struct list_head
*pos
, *tmp
;
467 list_for_each_safe(pos
, tmp
, &cg3_list
) {
468 struct all_info
*all
= list_entry(pos
, typeof(*all
), list
);
470 unregister_framebuffer(&all
->info
);
471 fb_dealloc_cmap(&all
->info
.cmap
);
479 /* No cmdline options yet... */
483 module_init(cg3_init
);
486 module_exit(cg3_exit
);
489 MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
490 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
491 MODULE_LICENSE("GPL");