File: /usr/src/linux/drivers/video/cgfourteenfb.c

1     /* $Id: cgfourteenfb.c,v 1.11 2001/09/19 00:04:33 davem Exp $
2      * cgfourteenfb.c: CGfourteen frame buffer driver
3      *
4      * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
5      * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
6      */
7     
8     #include <linux/module.h>
9     #include <linux/sched.h>
10     #include <linux/kernel.h>
11     #include <linux/errno.h>
12     #include <linux/string.h>
13     #include <linux/mm.h>
14     #include <linux/tty.h>
15     #include <linux/slab.h>
16     #include <linux/vmalloc.h>
17     #include <linux/delay.h>
18     #include <linux/interrupt.h>
19     #include <linux/fb.h>
20     #include <linux/init.h>
21     #include <linux/selection.h>
22     
23     #include <video/sbusfb.h>
24     #include <asm/io.h>
25     #include <asm/pgtable.h>
26     #include <asm/uaccess.h>
27     
28     #include <video/fbcon-cfb8.h>
29     
30     #define CG14_MCR_INTENABLE_SHIFT	7
31     #define CG14_MCR_INTENABLE_MASK		0x80
32     #define CG14_MCR_VIDENABLE_SHIFT	6
33     #define CG14_MCR_VIDENABLE_MASK		0x40
34     #define CG14_MCR_PIXMODE_SHIFT		4
35     #define CG14_MCR_PIXMODE_MASK		0x30
36     #define CG14_MCR_TMR_SHIFT		2
37     #define CG14_MCR_TMR_MASK		0x0c
38     #define CG14_MCR_TMENABLE_SHIFT		1
39     #define CG14_MCR_TMENABLE_MASK		0x02
40     #define CG14_MCR_RESET_SHIFT		0
41     #define CG14_MCR_RESET_MASK		0x01
42     #define CG14_REV_REVISION_SHIFT		4
43     #define CG14_REV_REVISION_MASK		0xf0
44     #define CG14_REV_IMPL_SHIFT		0
45     #define CG14_REV_IMPL_MASK		0x0f
46     #define CG14_VBR_FRAMEBASE_SHIFT	12
47     #define CG14_VBR_FRAMEBASE_MASK		0x00fff000
48     #define CG14_VMCR1_SETUP_SHIFT		0
49     #define CG14_VMCR1_SETUP_MASK		0x000001ff
50     #define CG14_VMCR1_VCONFIG_SHIFT	9
51     #define CG14_VMCR1_VCONFIG_MASK		0x00000e00
52     #define CG14_VMCR2_REFRESH_SHIFT	0
53     #define CG14_VMCR2_REFRESH_MASK		0x00000001
54     #define CG14_VMCR2_TESTROWCNT_SHIFT	1
55     #define CG14_VMCR2_TESTROWCNT_MASK	0x00000002
56     #define CG14_VMCR2_FBCONFIG_SHIFT	2
57     #define CG14_VMCR2_FBCONFIG_MASK	0x0000000c
58     #define CG14_VCR_REFRESHREQ_SHIFT	0
59     #define CG14_VCR_REFRESHREQ_MASK	0x000003ff
60     #define CG14_VCR1_REFRESHENA_SHIFT	10
61     #define CG14_VCR1_REFRESHENA_MASK	0x00000400
62     #define CG14_VCA_CAD_SHIFT		0
63     #define CG14_VCA_CAD_MASK		0x000003ff
64     #define CG14_VCA_VERS_SHIFT		10
65     #define CG14_VCA_VERS_MASK		0x00000c00
66     #define CG14_VCA_RAMSPEED_SHIFT		12
67     #define CG14_VCA_RAMSPEED_MASK		0x00001000
68     #define CG14_VCA_8MB_SHIFT		13
69     #define CG14_VCA_8MB_MASK		0x00002000
70     
71     #define CG14_MCR_PIXMODE_8		0
72     #define CG14_MCR_PIXMODE_16		2
73     #define CG14_MCR_PIXMODE_32		3
74     
75     MODULE_LICENSE("GPL");
76     
77     struct cg14_regs{
78     	volatile u8 mcr;	/* Master Control Reg */
79     	volatile u8 ppr;	/* Packed Pixel Reg */
80     	volatile u8 tms[2];	/* Test Mode Status Regs */
81     	volatile u8 msr;	/* Master Status Reg */
82     	volatile u8 fsr;	/* Fault Status Reg */
83     	volatile u8 rev;	/* Revision & Impl */
84     	volatile u8 ccr;	/* Clock Control Reg */
85     	volatile u32 tmr;	/* Test Mode Read Back */
86     	volatile u8 mod;	/* Monitor Operation Data Reg */
87     	volatile u8 acr;	/* Aux Control */
88     	u8 xxx0[6];
89     	volatile u16 hct;	/* Hor Counter */
90     	volatile u16 vct;	/* Vert Counter */
91     	volatile u16 hbs;	/* Hor Blank Start */
92     	volatile u16 hbc;	/* Hor Blank Clear */
93     	volatile u16 hss;	/* Hor Sync Start */
94     	volatile u16 hsc;	/* Hor Sync Clear */
95     	volatile u16 csc;	/* Composite Sync Clear */
96     	volatile u16 vbs;	/* Vert Blank Start */
97     	volatile u16 vbc;	/* Vert Blank Clear */
98     	volatile u16 vss;	/* Vert Sync Start */
99     	volatile u16 vsc;	/* Vert Sync Clear */
100     	volatile u16 xcs;
101     	volatile u16 xcc;
102     	volatile u16 fsa;	/* Fault Status Address */
103     	volatile u16 adr;	/* Address Registers */
104     	u8 xxx1[0xce];
105     	volatile u8 pcg[0x100]; /* Pixel Clock Generator */
106     	volatile u32 vbr;	/* Frame Base Row */
107     	volatile u32 vmcr;	/* VBC Master Control */
108     	volatile u32 vcr;	/* VBC refresh */
109     	volatile u32 vca;	/* VBC Config */
110     };
111     
112     #define CG14_CCR_ENABLE	0x04
113     #define CG14_CCR_SELECT 0x02	/* HW/Full screen */
114     
115     struct cg14_cursor {
116     	volatile u32 cpl0[32];	/* Enable plane 0 */
117     	volatile u32 cpl1[32];  /* Color selection plane */
118     	volatile u8 ccr;	/* Cursor Control Reg */
119     	u8 xxx0[3];
120     	volatile u16 cursx;	/* Cursor x,y position */
121     	volatile u16 cursy;	/* Cursor x,y position */
122     	volatile u32 color0;
123     	volatile u32 color1;
124     	u32 xxx1[0x1bc];
125     	volatile u32 cpl0i[32];	/* Enable plane 0 autoinc */
126     	volatile u32 cpl1i[32]; /* Color selection autoinc */
127     };
128     
129     struct cg14_dac {
130     	volatile u8 addr;	/* Address Register */
131     	u8 xxx0[255];
132     	volatile u8 glut;	/* Gamma table */
133     	u8 xxx1[255];
134     	volatile u8 select;	/* Register Select */
135     	u8 xxx2[255];
136     	volatile u8 mode;	/* Mode Register */
137     };
138     
139     struct cg14_xlut{
140     	volatile u8 x_xlut [256];
141     	volatile u8 x_xlutd [256];
142     	u8 xxx0[0x600];
143     	volatile u8 x_xlut_inc [256];
144     	volatile u8 x_xlutd_inc [256];
145     };
146     
147     /* Color look up table (clut) */
148     /* Each one of these arrays hold the color lookup table (for 256
149      * colors) for each MDI page (I assume then there should be 4 MDI
150      * pages, I still wonder what they are.  I have seen NeXTStep split
151      * the screen in four parts, while operating in 24 bits mode.  Each
152      * integer holds 4 values: alpha value (transparency channel, thanks
153      * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
154      *
155      * I currently use the clut instead of the Xlut
156      */
157     struct cg14_clut {
158     	u32 c_clut [256];
159     	u32 c_clutd [256];    /* i wonder what the 'd' is for */
160     	u32 c_clut_inc [256];
161     	u32 c_clutd_inc [256];
162     };
163     
164     static struct sbus_mmap_map cg14_mmap_map[] __initdata = {
165     	{ CG14_REGS,		0x80000000,		0x1000		    },
166     	{ CG14_XLUT,		0x80003000,		0x1000		    },
167     	{ CG14_CLUT1,		0x80004000,		0x1000		    },
168     	{ CG14_CLUT2,		0x80005000,		0x1000		    },
169     	{ CG14_CLUT3,		0x80006000,		0x1000		    },
170     	{ CG3_MMAP_OFFSET - 
171     	  0x7000,		0x80000000,		0x7000		    },
172     	{ CG3_MMAP_OFFSET,	0x00000000,		SBUS_MMAP_FBSIZE(1) },
173     	{ MDI_CURSOR_MAP,	0x80001000,		0x1000		    },
174     	{ MDI_CHUNKY_BGR_MAP,	0x01000000,		0x400000	    },
175     	{ MDI_PLANAR_X16_MAP,	0x02000000,		0x200000	    },
176     	{ MDI_PLANAR_C16_MAP,	0x02800000,		0x200000	    },
177     	{ MDI_PLANAR_X32_MAP,	0x03000000,		0x100000	    },
178     	{ MDI_PLANAR_B32_MAP,	0x03400000,		0x100000	    },
179     	{ MDI_PLANAR_G32_MAP,	0x03800000,		0x100000	    },
180     	{ MDI_PLANAR_R32_MAP,	0x03c00000,		0x100000	    },
181     	{ 0,			0,			0		    }
182     };
183     
184     static void cg14_loadcmap (struct fb_info_sbusfb *fb, struct display *p,
185     			   int index, int count)
186     {
187     	struct cg14_clut *clut = fb->s.cg14.clut;
188     	unsigned long flags;
189     	        
190     	spin_lock_irqsave(&fb->lock, flags);
191     	for (; count--; index++) {
192     		u32 val;
193     
194     		val = ((fb->color_map CM(index,2) << 16) |
195     		       (fb->color_map CM(index,1) << 8) |
196     		       (fb->color_map CM(index,0)));
197     		sbus_writel(val, &clut->c_clut[index]);
198     	}
199     	spin_unlock_irqrestore(&fb->lock, flags);
200     }
201     
202     static void cg14_margins (struct fb_info_sbusfb *fb, struct display *p,
203     			  int x_margin, int y_margin)
204     {
205     	p->screen_base += (y_margin - fb->y_margin) *
206     		p->line_length + (x_margin - fb->x_margin);
207     }
208     
209     static void cg14_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
210     {
211     	struct cg14_cursor *cur = fb->s.cg14.cursor;
212     	unsigned long flags;
213     	
214     	spin_lock_irqsave(&fb->lock, flags);
215     	sbus_writel(((red[0]) | (green[0] << 8) | (blue[0] << 16)), &cur->color0);
216     	sbus_writel(((red[1]) | (green[1] << 8) | (blue[1] << 16)), &cur->color1);
217     	spin_unlock_irqrestore(&fb->lock, flags);
218     }
219     
220     /* Set cursor shape */
221     static void cg14_setcurshape (struct fb_info_sbusfb *fb)
222     {
223     	struct cg14_cursor *cur = fb->s.cg14.cursor;
224     	unsigned long flags;
225     	int i;
226     
227     	spin_lock_irqsave(&fb->lock, flags);
228     	for (i = 0; i < 32; i++){
229     		sbus_writel(fb->cursor.bits[0][i], &cur->cpl0[i]);
230     		sbus_writel(fb->cursor.bits[1][i], &cur->cpl1[i]);
231     	}
232     	spin_unlock_irqrestore(&fb->lock, flags);
233     }
234     
235     /* Load cursor information */
236     static void cg14_setcursor (struct fb_info_sbusfb *fb)
237     {
238     	struct cg_cursor *c = &fb->cursor;
239     	struct cg14_cursor *cur = fb->s.cg14.cursor;
240     	unsigned long flags;
241                     
242     	spin_lock_irqsave(&fb->lock, flags);
243     	if (c->enable) {
244     		u8 tmp = sbus_readb(&cur->ccr);
245     
246     		tmp |= CG14_CCR_ENABLE;
247     		sbus_writeb(tmp, &cur->ccr);
248     	} else {
249     		u8 tmp = sbus_readb(&cur->ccr);
250     
251     		tmp &= ~CG14_CCR_ENABLE;
252     		sbus_writeb(tmp, &cur->ccr);
253     	}
254     	sbus_writew(((c->cpos.fbx - c->chot.fbx) & 0xfff), &cur->cursx);
255     	sbus_writew(((c->cpos.fby - c->chot.fby) & 0xfff), &cur->cursy);
256     	spin_unlock_irqrestore(&fb->lock, flags);
257     }
258     
259     static void cg14_switch_from_graph (struct fb_info_sbusfb *fb)
260     {
261     	unsigned long flags;
262     
263     	spin_lock_irqsave(&fb->lock, flags);
264     
265     	/* Set the 8-bpp mode */
266     	if (fb->open && fb->mmaped){
267     		volatile char *mcr = &fb->s.cg14.regs->mcr;
268     		char tmp;
269     	                                
270     		fb->s.cg14.mode = 8;
271     		tmp = sbus_readb(mcr);
272     		tmp &= ~(CG14_MCR_PIXMODE_MASK);
273     		sbus_writeb(tmp, mcr);
274     	}
275     	spin_unlock_irqrestore(&fb->lock, flags);
276     }
277     
278     static void cg14_reset (struct fb_info_sbusfb *fb)
279     {
280     	volatile char *mcr = &fb->s.cg14.regs->mcr;
281     	unsigned long flags;
282     	char tmp;
283     	        
284     	spin_lock_irqsave(&fb->lock, flags);
285     	tmp = sbus_readb(mcr);
286     	tmp &= ~(CG14_MCR_PIXMODE_MASK);
287     	sbus_writeb(tmp, mcr);
288     	spin_unlock_irqrestore(&fb->lock, flags);
289     }
290     
291     static int cg14_ioctl (struct fb_info_sbusfb *fb, unsigned int cmd, unsigned long arg)
292     {
293     	volatile char *mcr = &fb->s.cg14.regs->mcr;
294     	struct mdi_cfginfo *mdii;
295     	unsigned long flags;
296     	int mode, ret = 0;
297     	char tmp;
298     	        
299     	switch (cmd) {
300     	case MDI_RESET:
301     		spin_lock_irqsave(&fb->lock, flags);
302     		tmp = sbus_readb(mcr);
303     		tmp &= ~CG14_MCR_PIXMODE_MASK;
304     		sbus_writeb(tmp, mcr);
305     		spin_unlock_irqrestore(&fb->lock, flags);
306     		break;
307     	case MDI_GET_CFGINFO:
308     		mdii = (struct mdi_cfginfo *)arg;
309     		if (put_user(FBTYPE_MDICOLOR, &mdii->mdi_type) ||
310     		    __put_user(fb->type.fb_height, &mdii->mdi_height) ||
311     		    __put_user(fb->type.fb_width, &mdii->mdi_width) ||
312     		    __put_user(fb->s.cg14.mode, &mdii->mdi_mode) ||
313     		    __put_user(72, &mdii->mdi_pixfreq) || /* FIXME */
314     		    __put_user(fb->s.cg14.ramsize, &mdii->mdi_size))
315     			return -EFAULT;
316     		break;
317     	case MDI_SET_PIXELMODE:
318     		if (get_user(mode, (int *)arg))
319     			return -EFAULT;
320     
321     		spin_lock_irqsave(&fb->lock, flags);
322     		tmp = sbus_readb(mcr);
323     		switch (mode){
324     		case MDI_32_PIX:
325     			tmp = (tmp & ~CG14_MCR_PIXMODE_MASK) |
326     				(CG14_MCR_PIXMODE_32 << CG14_MCR_PIXMODE_SHIFT);
327     			break;
328     		case MDI_16_PIX:
329     			tmp = (tmp & ~CG14_MCR_PIXMODE_MASK) | 0x20;
330     			break;
331     		case MDI_8_PIX:
332     			tmp = (tmp & ~CG14_MCR_PIXMODE_MASK);
333     			break;
334     		default:
335     			ret = -ENOSYS;
336     			break;
337     		};
338     		if (ret == 0) {
339     			sbus_writeb(tmp, mcr);
340     			fb->s.cg14.mode = mode;
341     		}
342     		spin_unlock_irqrestore(&fb->lock, flags);
343     		break;
344     	default:
345     		ret = -EINVAL;
346     	};
347     
348     	return ret;
349     }
350     
351     static unsigned long __init get_phys(unsigned long addr)
352     {
353     	return __get_phys(addr);
354     }
355     
356     static int __init get_iospace(unsigned long addr)
357     {
358     	return __get_iospace(addr);
359     }
360     
361     static char idstring[60] __initdata = { 0 };
362     
363     char __init *cgfourteenfb_init(struct fb_info_sbusfb *fb)
364     {
365     	struct fb_fix_screeninfo *fix = &fb->fix;
366     	struct display *disp = &fb->disp;
367     	struct fbtype *type = &fb->type;
368     	unsigned long rphys, phys;
369     	u32 bases[6];
370     	int is_8mb, i;
371     
372     #ifndef FBCON_HAS_CFB8
373     	return NULL;
374     #endif
375     	prom_getproperty (fb->prom_node, "address", (char *) &bases[0], 8);
376     	if (!bases[0]) {
377     		printk("cg14 not mmaped\n");
378     		return NULL;
379     	}
380     	if (get_iospace(bases[0]) != get_iospace(bases[1])) {
381     		printk("Ugh. cg14 iospaces don't match\n");
382     		return NULL;
383     	}
384     	fb->physbase = phys = get_phys(bases[1]);
385     	rphys = get_phys(bases[0]);
386     	fb->iospace = get_iospace(bases[0]);
387     	fb->s.cg14.regs = (struct cg14_regs *)(unsigned long)bases[0];
388     	fb->s.cg14.clut = (void *)((unsigned long)bases[0]+CG14_CLUT1);
389     	fb->s.cg14.cursor = (void *)((unsigned long)bases[0]+CG14_CURSORREGS);
390     	disp->screen_base = (char *)bases[1];
391     	
392     	/* CG14_VCA_8MB_MASK is not correctly set on the 501-2482
393     	 * VSIMM, so we read the memory size from the PROM
394     	 */
395     	prom_getproperty(fb->prom_node, "reg", (char *) &bases[0], 24);
396     	is_8mb = bases[5] == 0x800000;
397     
398     	fb->mmap_map = kmalloc(sizeof(cg14_mmap_map), GFP_KERNEL);
399     	if (!fb->mmap_map)
400     		return NULL;
401     
402     	for (i = 0; ; i++) {
403     		fb->mmap_map[i].voff = cg14_mmap_map[i].voff;
404     		fb->mmap_map[i].poff = (cg14_mmap_map[i].poff & 0x80000000) ?
405     				       (cg14_mmap_map[i].poff & 0x7fffffff) + rphys - phys :
406     				       cg14_mmap_map[i].poff;
407     		fb->mmap_map[i].size = cg14_mmap_map[i].size;
408     		if (is_8mb && fb->mmap_map[i].size >= 0x100000 &&
409     		    fb->mmap_map[i].size <= 0x400000)
410     			fb->mmap_map[i].size <<= 1;
411     		if (!cg14_mmap_map[i].size)
412     			break;
413     	}
414     
415     	strcpy(fb->info.modename, "CGfourteen");
416     	strcpy(fix->id, "CGfourteen");
417     	fix->line_length = fb->var.xres_virtual;
418     	fix->accel = FB_ACCEL_SUN_CG14;
419     	
420     	disp->scrollmode = SCROLL_YREDRAW;
421     	disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
422     	fb->dispsw = fbcon_cfb8;
423     	
424     	type->fb_depth = 24;
425     	fb->emulations[1] = FBTYPE_SUN3COLOR;
426     
427     	fb->margins = cg14_margins;
428     	fb->loadcmap = cg14_loadcmap;
429     	fb->setcursor = cg14_setcursor;
430     	fb->setcursormap = cg14_setcursormap;
431     	fb->setcurshape = cg14_setcurshape;
432     	fb->reset = cg14_reset;
433     	fb->switch_from_graph = cg14_switch_from_graph;
434     	fb->ioctl = cg14_ioctl;
435     
436     	fb->s.cg14.mode = 8;
437     	fb->s.cg14.ramsize = (is_8mb) ? 0x800000 : 0x400000;
438     	
439     	cg14_reset(fb);
440     	
441     	sprintf(idstring, "cgfourteen at %x.%08lx, %dMB, rev=%d, impl=%d", fb->iospace, phys,
442     		is_8mb ? 8 : 4, fb->s.cg14.regs->rev >> 4, fb->s.cg14.regs->rev & 0xf);
443     	
444     	return idstring;
445     }
446