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 
cg14_loadcmap(struct fb_info_sbusfb * fb,struct display * p,int index,int count)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 
cg14_margins(struct fb_info_sbusfb * fb,struct display * p,int x_margin,int y_margin)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 
cg14_setcursormap(struct fb_info_sbusfb * fb,u8 * red,u8 * green,u8 * blue)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 */
cg14_setcurshape(struct fb_info_sbusfb * fb)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 */
cg14_setcursor(struct fb_info_sbusfb * fb)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 
cg14_switch_from_graph(struct fb_info_sbusfb * fb)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 
cg14_reset(struct fb_info_sbusfb * fb)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 
cg14_ioctl(struct fb_info_sbusfb * fb,unsigned int cmd,unsigned long arg)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 
get_phys(unsigned long addr)351 static unsigned long __init get_phys(unsigned long addr)
352 {
353 	return __get_phys(addr);
354 }
355 
get_iospace(unsigned long addr)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 
cgfourteenfb_init(struct fb_info_sbusfb * fb)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