1 /* cg14.c: CGFOURTEEN 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) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
7 * Driver layout based loosely on tgafb.c, see that file for credits.
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/errno.h>
13 #include <linux/string.h>
14 #include <linux/slab.h>
15 #include <linux/delay.h>
16 #include <linux/init.h>
22 #include <asm/oplib.h>
31 static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned,
32 unsigned, struct fb_info
*);
34 static int cg14_mmap(struct fb_info
*, struct file
*, struct vm_area_struct
*);
35 static int cg14_ioctl(struct inode
*, struct file
*, unsigned int,
36 unsigned long, struct fb_info
*);
37 static int cg14_pan_display(struct fb_var_screeninfo
*, struct fb_info
*);
40 * Frame buffer operations
43 static struct fb_ops cg14_ops
= {
45 .fb_setcolreg
= cg14_setcolreg
,
46 .fb_pan_display
= cg14_pan_display
,
47 .fb_fillrect
= cfb_fillrect
,
48 .fb_copyarea
= cfb_copyarea
,
49 .fb_imageblit
= cfb_imageblit
,
51 .fb_ioctl
= cg14_ioctl
,
53 .fb_compat_ioctl
= sbusfb_compat_ioctl
,
57 #define CG14_MCR_INTENABLE_SHIFT 7
58 #define CG14_MCR_INTENABLE_MASK 0x80
59 #define CG14_MCR_VIDENABLE_SHIFT 6
60 #define CG14_MCR_VIDENABLE_MASK 0x40
61 #define CG14_MCR_PIXMODE_SHIFT 4
62 #define CG14_MCR_PIXMODE_MASK 0x30
63 #define CG14_MCR_TMR_SHIFT 2
64 #define CG14_MCR_TMR_MASK 0x0c
65 #define CG14_MCR_TMENABLE_SHIFT 1
66 #define CG14_MCR_TMENABLE_MASK 0x02
67 #define CG14_MCR_RESET_SHIFT 0
68 #define CG14_MCR_RESET_MASK 0x01
69 #define CG14_REV_REVISION_SHIFT 4
70 #define CG14_REV_REVISION_MASK 0xf0
71 #define CG14_REV_IMPL_SHIFT 0
72 #define CG14_REV_IMPL_MASK 0x0f
73 #define CG14_VBR_FRAMEBASE_SHIFT 12
74 #define CG14_VBR_FRAMEBASE_MASK 0x00fff000
75 #define CG14_VMCR1_SETUP_SHIFT 0
76 #define CG14_VMCR1_SETUP_MASK 0x000001ff
77 #define CG14_VMCR1_VCONFIG_SHIFT 9
78 #define CG14_VMCR1_VCONFIG_MASK 0x00000e00
79 #define CG14_VMCR2_REFRESH_SHIFT 0
80 #define CG14_VMCR2_REFRESH_MASK 0x00000001
81 #define CG14_VMCR2_TESTROWCNT_SHIFT 1
82 #define CG14_VMCR2_TESTROWCNT_MASK 0x00000002
83 #define CG14_VMCR2_FBCONFIG_SHIFT 2
84 #define CG14_VMCR2_FBCONFIG_MASK 0x0000000c
85 #define CG14_VCR_REFRESHREQ_SHIFT 0
86 #define CG14_VCR_REFRESHREQ_MASK 0x000003ff
87 #define CG14_VCR1_REFRESHENA_SHIFT 10
88 #define CG14_VCR1_REFRESHENA_MASK 0x00000400
89 #define CG14_VCA_CAD_SHIFT 0
90 #define CG14_VCA_CAD_MASK 0x000003ff
91 #define CG14_VCA_VERS_SHIFT 10
92 #define CG14_VCA_VERS_MASK 0x00000c00
93 #define CG14_VCA_RAMSPEED_SHIFT 12
94 #define CG14_VCA_RAMSPEED_MASK 0x00001000
95 #define CG14_VCA_8MB_SHIFT 13
96 #define CG14_VCA_8MB_MASK 0x00002000
98 #define CG14_MCR_PIXMODE_8 0
99 #define CG14_MCR_PIXMODE_16 2
100 #define CG14_MCR_PIXMODE_32 3
103 volatile u8 mcr
; /* Master Control Reg */
104 volatile u8 ppr
; /* Packed Pixel Reg */
105 volatile u8 tms
[2]; /* Test Mode Status Regs */
106 volatile u8 msr
; /* Master Status Reg */
107 volatile u8 fsr
; /* Fault Status Reg */
108 volatile u8 rev
; /* Revision & Impl */
109 volatile u8 ccr
; /* Clock Control Reg */
110 volatile u32 tmr
; /* Test Mode Read Back */
111 volatile u8 mod
; /* Monitor Operation Data Reg */
112 volatile u8 acr
; /* Aux Control */
114 volatile u16 hct
; /* Hor Counter */
115 volatile u16 vct
; /* Vert Counter */
116 volatile u16 hbs
; /* Hor Blank Start */
117 volatile u16 hbc
; /* Hor Blank Clear */
118 volatile u16 hss
; /* Hor Sync Start */
119 volatile u16 hsc
; /* Hor Sync Clear */
120 volatile u16 csc
; /* Composite Sync Clear */
121 volatile u16 vbs
; /* Vert Blank Start */
122 volatile u16 vbc
; /* Vert Blank Clear */
123 volatile u16 vss
; /* Vert Sync Start */
124 volatile u16 vsc
; /* Vert Sync Clear */
127 volatile u16 fsa
; /* Fault Status Address */
128 volatile u16 adr
; /* Address Registers */
130 volatile u8 pcg
[0x100]; /* Pixel Clock Generator */
131 volatile u32 vbr
; /* Frame Base Row */
132 volatile u32 vmcr
; /* VBC Master Control */
133 volatile u32 vcr
; /* VBC refresh */
134 volatile u32 vca
; /* VBC Config */
137 #define CG14_CCR_ENABLE 0x04
138 #define CG14_CCR_SELECT 0x02 /* HW/Full screen */
141 volatile u32 cpl0
[32]; /* Enable plane 0 */
142 volatile u32 cpl1
[32]; /* Color selection plane */
143 volatile u8 ccr
; /* Cursor Control Reg */
145 volatile u16 cursx
; /* Cursor x,y position */
146 volatile u16 cursy
; /* Cursor x,y position */
150 volatile u32 cpl0i
[32]; /* Enable plane 0 autoinc */
151 volatile u32 cpl1i
[32]; /* Color selection autoinc */
155 volatile u8 addr
; /* Address Register */
157 volatile u8 glut
; /* Gamma table */
159 volatile u8 select
; /* Register Select */
161 volatile u8 mode
; /* Mode Register */
165 volatile u8 x_xlut
[256];
166 volatile u8 x_xlutd
[256];
168 volatile u8 x_xlut_inc
[256];
169 volatile u8 x_xlutd_inc
[256];
172 /* Color look up table (clut) */
173 /* Each one of these arrays hold the color lookup table (for 256
174 * colors) for each MDI page (I assume then there should be 4 MDI
175 * pages, I still wonder what they are. I have seen NeXTStep split
176 * the screen in four parts, while operating in 24 bits mode. Each
177 * integer holds 4 values: alpha value (transparency channel, thanks
178 * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
180 * I currently use the clut instead of the Xlut
184 u32 c_clutd
[256]; /* i wonder what the 'd' is for */
185 u32 c_clut_inc
[256];
186 u32 c_clutd_inc
[256];
189 #define CG14_MMAP_ENTRIES 16
193 struct cg14_regs __iomem
*regs
;
194 struct cg14_clut __iomem
*clut
;
195 struct cg14_cursor __iomem
*cursor
;
198 #define CG14_FLAG_BLANKED 0x00000001
200 unsigned long physbase
;
201 unsigned long iospace
;
202 unsigned long fbsize
;
204 struct sbus_mmap_map mmap_map
[CG14_MMAP_ENTRIES
];
208 struct sbus_dev
*sdev
;
209 struct list_head list
;
212 static void __cg14_reset(struct cg14_par
*par
)
214 struct cg14_regs __iomem
*regs
= par
->regs
;
217 val
= sbus_readb(®s
->mcr
);
218 val
&= ~(CG14_MCR_PIXMODE_MASK
);
219 sbus_writeb(val
, ®s
->mcr
);
222 static int cg14_pan_display(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
224 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
227 /* We just use this to catch switches out of
230 spin_lock_irqsave(&par
->lock
, flags
);
232 spin_unlock_irqrestore(&par
->lock
, flags
);
234 if (var
->xoffset
|| var
->yoffset
|| var
->vmode
)
240 * cg14_setcolreg - Optional function. Sets a color register.
241 * @regno: boolean, 0 copy local, 1 get_user() function
242 * @red: frame buffer colormap structure
243 * @green: The green value which can be up to 16 bits wide
244 * @blue: The blue value which can be up to 16 bits wide.
245 * @transp: If supported the alpha value which can be up to 16 bits wide.
246 * @info: frame buffer info structure
248 static int cg14_setcolreg(unsigned regno
,
249 unsigned red
, unsigned green
, unsigned blue
,
250 unsigned transp
, struct fb_info
*info
)
252 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
253 struct cg14_clut __iomem
*clut
= par
->clut
;
263 val
= (red
| (green
<< 8) | (blue
<< 16));
265 spin_lock_irqsave(&par
->lock
, flags
);
266 sbus_writel(val
, &clut
->c_clut
[regno
]);
267 spin_unlock_irqrestore(&par
->lock
, flags
);
272 static int cg14_mmap(struct fb_info
*info
, struct file
*file
, struct vm_area_struct
*vma
)
274 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
276 return sbusfb_mmap_helper(par
->mmap_map
,
277 par
->physbase
, par
->fbsize
,
281 static int cg14_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
282 unsigned long arg
, struct fb_info
*info
)
284 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
285 struct cg14_regs __iomem
*regs
= par
->regs
;
286 struct mdi_cfginfo kmdi
, __user
*mdii
;
288 int cur_mode
, mode
, ret
= 0;
292 spin_lock_irqsave(&par
->lock
, flags
);
294 spin_unlock_irqrestore(&par
->lock
, flags
);
297 case MDI_GET_CFGINFO
:
298 memset(&kmdi
, 0, sizeof(kmdi
));
300 spin_lock_irqsave(&par
->lock
, flags
);
301 kmdi
.mdi_type
= FBTYPE_MDICOLOR
;
302 kmdi
.mdi_height
= info
->var
.yres
;
303 kmdi
.mdi_width
= info
->var
.xres
;
304 kmdi
.mdi_mode
= par
->mode
;
305 kmdi
.mdi_pixfreq
= 72; /* FIXME */
306 kmdi
.mdi_size
= par
->ramsize
;
307 spin_unlock_irqrestore(&par
->lock
, flags
);
309 mdii
= (struct mdi_cfginfo __user
*) arg
;
310 if (copy_to_user(mdii
, &kmdi
, sizeof(kmdi
)))
314 case MDI_SET_PIXELMODE
:
315 if (get_user(mode
, (int __user
*) arg
)) {
320 spin_lock_irqsave(&par
->lock
, flags
);
321 cur_mode
= sbus_readb(®s
->mcr
);
322 cur_mode
&= ~CG14_MCR_PIXMODE_MASK
;
325 cur_mode
|= (CG14_MCR_PIXMODE_32
<<
326 CG14_MCR_PIXMODE_SHIFT
);
330 cur_mode
|= (CG14_MCR_PIXMODE_16
<<
331 CG14_MCR_PIXMODE_SHIFT
);
342 sbus_writeb(cur_mode
, ®s
->mcr
);
345 spin_unlock_irqrestore(&par
->lock
, flags
);
349 ret
= sbusfb_ioctl_helper(cmd
, arg
, info
,
350 FBTYPE_MDICOLOR
, 8, par
->fbsize
);
361 static void cg14_init_fix(struct fb_info
*info
, int linebytes
)
363 struct cg14_par
*par
= (struct cg14_par
*)info
->par
;
368 name
= par
->sdev
->prom_name
;
370 strlcpy(info
->fix
.id
, name
, sizeof(info
->fix
.id
));
372 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
373 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
375 info
->fix
.line_length
= linebytes
;
377 info
->fix
.accel
= FB_ACCEL_SUN_CG14
;
380 static struct sbus_mmap_map __cg14_mmap_map
[CG14_MMAP_ENTRIES
] __initdata
= {
407 .voff
= CG3_MMAP_OFFSET
- 0x7000,
412 .voff
= CG3_MMAP_OFFSET
,
414 .size
= SBUS_MMAP_FBSIZE(1)
417 .voff
= MDI_CURSOR_MAP
,
422 .voff
= MDI_CHUNKY_BGR_MAP
,
427 .voff
= MDI_PLANAR_X16_MAP
,
432 .voff
= MDI_PLANAR_C16_MAP
,
437 .voff
= MDI_PLANAR_X32_MAP
,
442 .voff
= MDI_PLANAR_B32_MAP
,
447 .voff
= MDI_PLANAR_G32_MAP
,
452 .voff
= MDI_PLANAR_R32_MAP
,
462 struct list_head list
;
464 static LIST_HEAD(cg14_list
);
466 static void cg14_init_one(struct sbus_dev
*sdev
, int node
, int parent_node
)
468 struct all_info
*all
;
469 unsigned long phys
, rphys
;
471 int is_8mb
, linebytes
, i
;
474 if (prom_getproperty(node
, "address",
475 (char *) &bases
[0], sizeof(bases
)) <= 0
477 printk(KERN_ERR
"cg14: Device is not mapped.\n");
480 if (__get_iospace(bases
[0]) != __get_iospace(bases
[1])) {
481 printk(KERN_ERR
"cg14: I/O spaces don't match.\n");
486 all
= kmalloc(sizeof(*all
), GFP_KERNEL
);
488 printk(KERN_ERR
"cg14: Cannot allocate memory.\n");
491 memset(all
, 0, sizeof(*all
));
493 INIT_LIST_HEAD(&all
->list
);
495 spin_lock_init(&all
->par
.lock
);
497 sbusfb_fill_var(&all
->info
.var
, node
, 8);
498 all
->info
.var
.red
.length
= 8;
499 all
->info
.var
.green
.length
= 8;
500 all
->info
.var
.blue
.length
= 8;
502 linebytes
= prom_getintdefault(node
, "linebytes",
504 all
->par
.fbsize
= PAGE_ALIGN(linebytes
* all
->info
.var
.yres
);
506 all
->par
.sdev
= sdev
;
508 rphys
= sdev
->reg_addrs
[0].phys_addr
;
509 all
->par
.physbase
= phys
= sdev
->reg_addrs
[1].phys_addr
;
510 all
->par
.iospace
= sdev
->reg_addrs
[0].which_io
;
512 all
->par
.regs
= sbus_ioremap(&sdev
->resource
[0], 0,
513 sizeof(struct cg14_regs
),
515 all
->par
.clut
= sbus_ioremap(&sdev
->resource
[0], CG14_CLUT1
,
516 sizeof(struct cg14_clut
),
518 all
->par
.cursor
= sbus_ioremap(&sdev
->resource
[0], CG14_CURSORREGS
,
519 sizeof(struct cg14_cursor
),
521 all
->info
.screen_base
= sbus_ioremap(&sdev
->resource
[1], 0,
522 all
->par
.fbsize
, "cg14 ram");
524 rphys
= __get_phys(bases
[0]);
525 all
->par
.physbase
= phys
= __get_phys(bases
[1]);
526 all
->par
.iospace
= __get_iospace(bases
[0]);
527 all
->par
.regs
= (struct cg14_regs __iomem
*)(unsigned long)bases
[0];
528 all
->par
.clut
= (struct cg14_clut __iomem
*)((unsigned long)bases
[0] +
531 (struct cg14_cursor __iomem
*)((unsigned long)bases
[0] +
534 all
->info
.screen_base
= (char __iomem
*)(unsigned long)bases
[1];
537 prom_getproperty(node
, "reg", (char *) &bases
[0], sizeof(bases
));
538 is_8mb
= (bases
[5] == 0x800000);
540 if (sizeof(all
->par
.mmap_map
) != sizeof(__cg14_mmap_map
)) {
541 extern void __cg14_mmap_sized_wrongly(void);
543 __cg14_mmap_sized_wrongly();
546 memcpy(&all
->par
.mmap_map
, &__cg14_mmap_map
, sizeof(all
->par
.mmap_map
));
547 for (i
= 0; i
< CG14_MMAP_ENTRIES
; i
++) {
548 struct sbus_mmap_map
*map
= &all
->par
.mmap_map
[i
];
552 if (map
->poff
& 0x80000000)
553 map
->poff
= (map
->poff
& 0x7fffffff) + rphys
- phys
;
555 map
->size
>= 0x100000 &&
556 map
->size
<= 0x400000)
560 all
->par
.mode
= MDI_8_PIX
;
561 all
->par
.ramsize
= (is_8mb
? 0x800000 : 0x400000);
563 all
->info
.flags
= FBINFO_DEFAULT
| FBINFO_HWACCEL_YPAN
;
564 all
->info
.fbops
= &cg14_ops
;
565 all
->info
.par
= &all
->par
;
567 __cg14_reset(&all
->par
);
569 if (fb_alloc_cmap(&all
->info
.cmap
, 256, 0)) {
570 printk(KERN_ERR
"cg14: Could not allocate color map.\n");
574 fb_set_cmap(&all
->info
.cmap
, &all
->info
);
576 cg14_init_fix(&all
->info
, linebytes
);
578 if (register_framebuffer(&all
->info
) < 0) {
579 printk(KERN_ERR
"cg14: Could not register framebuffer.\n");
580 fb_dealloc_cmap(&all
->info
.cmap
);
585 list_add(&all
->list
, &cg14_list
);
587 printk("cg14: cgfourteen at %lx:%lx, %dMB\n",
588 all
->par
.iospace
, all
->par
.physbase
, all
->par
.ramsize
>> 20);
592 int __init
cg14_init(void)
594 struct sbus_bus
*sbus
;
595 struct sbus_dev
*sdev
;
597 if (fb_get_options("cg14fb", NULL
))
600 #ifdef CONFIG_SPARC32
604 root
= prom_getchild(prom_root_node
);
605 root
= prom_searchsiblings(root
, "obio");
607 node
= prom_searchsiblings(prom_getchild(root
),
610 cg14_init_one(NULL
, node
, root
);
614 for_all_sbusdev(sdev
, sbus
) {
615 if (!strcmp(sdev
->prom_name
, "cgfourteen"))
616 cg14_init_one(sdev
, sdev
->prom_node
, sbus
->prom_node
);
622 void __exit
cg14_exit(void)
624 struct list_head
*pos
, *tmp
;
626 list_for_each_safe(pos
, tmp
, &cg14_list
) {
627 struct all_info
*all
= list_entry(pos
, typeof(*all
), list
);
629 unregister_framebuffer(&all
->info
);
630 fb_dealloc_cmap(&all
->info
.cmap
);
636 cg14_setup(char *arg
)
638 /* No cmdline options yet... */
642 module_init(cg14_init
);
645 module_exit(cg14_exit
);
648 MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets");
649 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
650 MODULE_LICENSE("GPL");