1 /* $Id: creatorfb.c,v 1.37 2001/10/16 05:44:44 davem Exp $
2  * creatorfb.c: Creator/Creator3D frame buffer driver
3  *
4  * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
5  */
6 
7 #include <linux/module.h>
8 #include <linux/sched.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/string.h>
12 #include <linux/mm.h>
13 #include <linux/tty.h>
14 #include <linux/slab.h>
15 #include <linux/vmalloc.h>
16 #include <linux/delay.h>
17 #include <linux/interrupt.h>
18 #include <linux/fb.h>
19 #include <linux/init.h>
20 #include <linux/selection.h>
21 
22 #include <video/sbusfb.h>
23 
24 #include <asm/upa.h>
25 
26 #define	FFB_SFB8R_VOFF		0x00000000
27 #define	FFB_SFB8G_VOFF		0x00400000
28 #define	FFB_SFB8B_VOFF		0x00800000
29 #define	FFB_SFB8X_VOFF		0x00c00000
30 #define	FFB_SFB32_VOFF		0x01000000
31 #define	FFB_SFB64_VOFF		0x02000000
32 #define	FFB_FBC_REGS_VOFF	0x04000000
33 #define	FFB_BM_FBC_REGS_VOFF	0x04002000
34 #define	FFB_DFB8R_VOFF		0x04004000
35 #define	FFB_DFB8G_VOFF		0x04404000
36 #define	FFB_DFB8B_VOFF		0x04804000
37 #define	FFB_DFB8X_VOFF		0x04c04000
38 #define	FFB_DFB24_VOFF		0x05004000
39 #define	FFB_DFB32_VOFF		0x06004000
40 #define	FFB_DFB422A_VOFF	0x07004000	/* DFB 422 mode write to A */
41 #define	FFB_DFB422AD_VOFF	0x07804000	/* DFB 422 mode with line doubling */
42 #define	FFB_DFB24B_VOFF		0x08004000	/* DFB 24bit mode write to B */
43 #define	FFB_DFB422B_VOFF	0x09004000	/* DFB 422 mode write to B */
44 #define	FFB_DFB422BD_VOFF	0x09804000	/* DFB 422 mode with line doubling */
45 #define	FFB_SFB16Z_VOFF		0x0a004000	/* 16bit mode Z planes */
46 #define	FFB_SFB8Z_VOFF		0x0a404000	/* 8bit mode Z planes */
47 #define	FFB_SFB422_VOFF		0x0ac04000	/* SFB 422 mode write to A/B */
48 #define	FFB_SFB422D_VOFF	0x0b404000	/* SFB 422 mode with line doubling */
49 #define	FFB_FBC_KREGS_VOFF	0x0bc04000
50 #define	FFB_DAC_VOFF		0x0bc06000
51 #define	FFB_PROM_VOFF		0x0bc08000
52 #define	FFB_EXP_VOFF		0x0bc18000
53 
54 #define	FFB_SFB8R_POFF		0x04000000UL
55 #define	FFB_SFB8G_POFF		0x04400000UL
56 #define	FFB_SFB8B_POFF		0x04800000UL
57 #define	FFB_SFB8X_POFF		0x04c00000UL
58 #define	FFB_SFB32_POFF		0x05000000UL
59 #define	FFB_SFB64_POFF		0x06000000UL
60 #define	FFB_FBC_REGS_POFF	0x00600000UL
61 #define	FFB_BM_FBC_REGS_POFF	0x00600000UL
62 #define	FFB_DFB8R_POFF		0x01000000UL
63 #define	FFB_DFB8G_POFF		0x01400000UL
64 #define	FFB_DFB8B_POFF		0x01800000UL
65 #define	FFB_DFB8X_POFF		0x01c00000UL
66 #define	FFB_DFB24_POFF		0x02000000UL
67 #define	FFB_DFB32_POFF		0x03000000UL
68 #define	FFB_FBC_KREGS_POFF	0x00610000UL
69 #define	FFB_DAC_POFF		0x00400000UL
70 #define	FFB_PROM_POFF		0x00000000UL
71 #define	FFB_EXP_POFF		0x00200000UL
72 #define FFB_DFB422A_POFF	0x09000000UL
73 #define FFB_DFB422AD_POFF	0x09800000UL
74 #define FFB_DFB24B_POFF		0x0a000000UL
75 #define FFB_DFB422B_POFF	0x0b000000UL
76 #define FFB_DFB422BD_POFF	0x0b800000UL
77 #define FFB_SFB16Z_POFF		0x0c800000UL
78 #define FFB_SFB8Z_POFF		0x0c000000UL
79 #define FFB_SFB422_POFF		0x0d000000UL
80 #define FFB_SFB422D_POFF	0x0d800000UL
81 
82 /* Draw operations */
83 #define FFB_DRAWOP_DOT		0x00
84 #define FFB_DRAWOP_AADOT	0x01
85 #define FFB_DRAWOP_BRLINECAP	0x02
86 #define FFB_DRAWOP_BRLINEOPEN	0x03
87 #define FFB_DRAWOP_DDLINE	0x04
88 #define FFB_DRAWOP_AALINE	0x05
89 #define FFB_DRAWOP_TRIANGLE	0x06
90 #define FFB_DRAWOP_POLYGON	0x07
91 #define FFB_DRAWOP_RECTANGLE	0x08
92 #define FFB_DRAWOP_FASTFILL	0x09
93 #define FFB_DRAWOP_BCOPY	0x0a
94 #define FFB_DRAWOP_VSCROLL	0x0b
95 
96 /* Pixel processor control */
97 /* Force WID */
98 #define FFB_PPC_FW_DISABLE	0x800000
99 #define FFB_PPC_FW_ENABLE	0xc00000
100 /* Auxiliary clip */
101 #define FFB_PPC_ACE_DISABLE	0x040000
102 #define FFB_PPC_ACE_AUX_SUB	0x080000
103 #define FFB_PPC_ACE_AUX_ADD	0x0c0000
104 /* Depth cue */
105 #define FFB_PPC_DCE_DISABLE	0x020000
106 #define FFB_PPC_DCE_ENABLE	0x030000
107 /* Alpha blend */
108 #define FFB_PPC_ABE_DISABLE	0x008000
109 #define FFB_PPC_ABE_ENABLE	0x00c000
110 /* View clip */
111 #define FFB_PPC_VCE_DISABLE	0x001000
112 #define FFB_PPC_VCE_2D		0x002000
113 #define FFB_PPC_VCE_3D		0x003000
114 /* Area pattern */
115 #define FFB_PPC_APE_DISABLE	0x000800
116 #define FFB_PPC_APE_ENABLE	0x000c00
117 /* Transparent background */
118 #define FFB_PPC_TBE_OPAQUE	0x000200
119 #define FFB_PPC_TBE_TRANSPARENT	0x000300
120 /* Z source */
121 #define FFB_PPC_ZS_VAR		0x000080
122 #define FFB_PPC_ZS_CONST	0x0000c0
123 /* Y source */
124 #define FFB_PPC_YS_VAR		0x000020
125 #define FFB_PPC_YS_CONST	0x000030
126 /* X source */
127 #define FFB_PPC_XS_WID		0x000004
128 #define FFB_PPC_XS_VAR		0x000008
129 #define FFB_PPC_XS_CONST	0x00000c
130 /* Color (BGR) source */
131 #define FFB_PPC_CS_VAR		0x000002
132 #define FFB_PPC_CS_CONST	0x000003
133 
134 #define FFB_ROP_NEW                  0x83
135 
136 #define FFB_UCSR_FIFO_MASK     0x00000fff
137 #define FFB_UCSR_FB_BUSY       0x01000000
138 #define FFB_UCSR_RP_BUSY       0x02000000
139 #define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
140 #define FFB_UCSR_READ_ERR      0x40000000
141 #define FFB_UCSR_FIFO_OVFL     0x80000000
142 #define FFB_UCSR_ALL_ERRORS    (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
143 
144 struct ffb_fbc {
145 	/* Next vertex registers */
146 	u32		xxx1[3];
147 	volatile u32	alpha;
148 	volatile u32	red;
149 	volatile u32	green;
150 	volatile u32	blue;
151 	volatile u32	depth;
152 	volatile u32	y;
153 	volatile u32	x;
154 	u32		xxx2[2];
155 	volatile u32	ryf;
156 	volatile u32	rxf;
157 	u32		xxx3[2];
158 
159 	volatile u32	dmyf;
160 	volatile u32	dmxf;
161 	u32		xxx4[2];
162 	volatile u32	ebyi;
163 	volatile u32	ebxi;
164 	u32		xxx5[2];
165 	volatile u32	by;
166 	volatile u32	bx;
167 	u32		dy;
168 	u32		dx;
169 	volatile u32	bh;
170 	volatile u32	bw;
171 	u32		xxx6[2];
172 
173 	u32		xxx7[32];
174 
175 	/* Setup unit vertex state register */
176 	volatile u32	suvtx;
177 	u32		xxx8[63];
178 
179 	/* Control registers */
180 	volatile u32	ppc;
181 	volatile u32	wid;
182 	volatile u32	fg;
183 	volatile u32	bg;
184 	volatile u32	consty;
185 	volatile u32	constz;
186 	volatile u32	xclip;
187 	volatile u32	dcss;
188 	volatile u32	vclipmin;
189 	volatile u32	vclipmax;
190 	volatile u32	vclipzmin;
191 	volatile u32	vclipzmax;
192 	volatile u32	dcsf;
193 	volatile u32	dcsb;
194 	volatile u32	dczf;
195 	volatile u32	dczb;
196 
197 	u32		xxx9;
198 	volatile u32	blendc;
199 	volatile u32	blendc1;
200 	volatile u32	blendc2;
201 	volatile u32	fbramitc;
202 	volatile u32	fbc;
203 	volatile u32	rop;
204 	volatile u32	cmp;
205 	volatile u32	matchab;
206 	volatile u32	matchc;
207 	volatile u32	magnab;
208 	volatile u32	magnc;
209 	volatile u32	fbcfg0;
210 	volatile u32	fbcfg1;
211 	volatile u32	fbcfg2;
212 	volatile u32	fbcfg3;
213 
214 	u32		ppcfg;
215 	volatile u32	pick;
216 	volatile u32	fillmode;
217 	volatile u32	fbramwac;
218 	volatile u32	pmask;
219 	volatile u32	xpmask;
220 	volatile u32	ypmask;
221 	volatile u32	zpmask;
222 	volatile u32	clip0min;
223 	volatile u32	clip0max;
224 	volatile u32	clip1min;
225 	volatile u32	clip1max;
226 	volatile u32	clip2min;
227 	volatile u32	clip2max;
228 	volatile u32	clip3min;
229 	volatile u32	clip3max;
230 
231 	/* New 3dRAM III support regs */
232 	volatile u32	rawblend2;
233 	volatile u32	rawpreblend;
234 	volatile u32	rawstencil;
235 	volatile u32	rawstencilctl;
236 	volatile u32	threedram1;
237 	volatile u32	threedram2;
238 	volatile u32	passin;
239 	volatile u32	rawclrdepth;
240 	volatile u32	rawpmask;
241 	volatile u32	rawcsrc;
242 	volatile u32	rawmatch;
243 	volatile u32	rawmagn;
244 	volatile u32	rawropblend;
245 	volatile u32	rawcmp;
246 	volatile u32	rawwac;
247 	volatile u32	fbramid;
248 
249 	volatile u32	drawop;
250 	u32		xxx10[2];
251 	volatile u32	fontlpat;
252 	u32		xxx11;
253 	volatile u32	fontxy;
254 	volatile u32	fontw;
255 	volatile u32	fontinc;
256 	volatile u32	font;
257 	u32		xxx12[3];
258 	volatile u32	blend2;
259 	volatile u32	preblend;
260 	volatile u32	stencil;
261 	volatile u32	stencilctl;
262 
263 	u32		xxx13[4];
264 	volatile u32	dcss1;
265 	volatile u32	dcss2;
266 	volatile u32	dcss3;
267 	volatile u32	widpmask;
268 	volatile u32	dcs2;
269 	volatile u32	dcs3;
270 	volatile u32	dcs4;
271 	u32		xxx14;
272 	volatile u32	dcd2;
273 	volatile u32	dcd3;
274 	volatile u32	dcd4;
275 	u32		xxx15;
276 
277 	volatile u32	pattern[32];
278 
279 	u32		xxx16[256];
280 
281 	volatile u32	devid;
282 	u32		xxx17[63];
283 
284 	volatile u32	ucsr;
285 	u32		xxx18[31];
286 
287 	volatile u32	mer;
288 };
289 
FFBFifo(struct fb_info_sbusfb * fb,int n)290 static __inline__ void FFBFifo(struct fb_info_sbusfb *fb, int n)
291 {
292 	struct ffb_fbc *fbc;
293 	int cache = fb->s.ffb.fifo_cache;
294 
295 	if (cache - n < 0) {
296 		fbc = fb->s.ffb.fbc;
297 		do {	cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
298 		} while (cache - n < 0);
299 	}
300 	fb->s.ffb.fifo_cache = cache - n;
301 }
302 
FFBWait(struct ffb_fbc * ffb)303 static __inline__ void FFBWait(struct ffb_fbc *ffb)
304 {
305 	int limit = 10000;
306 
307 	do {
308 		if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
309 			break;
310 		if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
311 			upa_writel(FFB_UCSR_ALL_ERRORS, &ffb->ucsr);
312 		}
313 	} while(--limit > 0);
314 }
315 
316 struct ffb_dac {
317 	volatile u32	type;
318 	volatile u32	value;
319 	volatile u32	type2;
320 	volatile u32	value2;
321 };
322 
323 static struct sbus_mmap_map ffb_mmap_map[] = {
324 	{ FFB_SFB8R_VOFF,	FFB_SFB8R_POFF,		0x0400000 },
325 	{ FFB_SFB8G_VOFF,	FFB_SFB8G_POFF,		0x0400000 },
326 	{ FFB_SFB8B_VOFF,	FFB_SFB8B_POFF,		0x0400000 },
327 	{ FFB_SFB8X_VOFF,	FFB_SFB8X_POFF,		0x0400000 },
328 	{ FFB_SFB32_VOFF,	FFB_SFB32_POFF,		0x1000000 },
329 	{ FFB_SFB64_VOFF,	FFB_SFB64_POFF,		0x2000000 },
330 	{ FFB_FBC_REGS_VOFF,	FFB_FBC_REGS_POFF,	0x0002000 },
331 	{ FFB_BM_FBC_REGS_VOFF,	FFB_BM_FBC_REGS_POFF,	0x0002000 },
332 	{ FFB_DFB8R_VOFF,	FFB_DFB8R_POFF,		0x0400000 },
333 	{ FFB_DFB8G_VOFF,	FFB_DFB8G_POFF,		0x0400000 },
334 	{ FFB_DFB8B_VOFF,	FFB_DFB8B_POFF,		0x0400000 },
335 	{ FFB_DFB8X_VOFF,	FFB_DFB8X_POFF,		0x0400000 },
336 	{ FFB_DFB24_VOFF,	FFB_DFB24_POFF,		0x1000000 },
337 	{ FFB_DFB32_VOFF,	FFB_DFB32_POFF,		0x1000000 },
338 	{ FFB_FBC_KREGS_VOFF,	FFB_FBC_KREGS_POFF,	0x0002000 },
339 	{ FFB_DAC_VOFF,		FFB_DAC_POFF,		0x0002000 },
340 	{ FFB_PROM_VOFF,	FFB_PROM_POFF,		0x0010000 },
341 	{ FFB_EXP_VOFF,		FFB_EXP_POFF,		0x0002000 },
342 	{ FFB_DFB422A_VOFF,	FFB_DFB422A_POFF,	0x0800000 },
343 	{ FFB_DFB422AD_VOFF,	FFB_DFB422AD_POFF,	0x0800000 },
344 	{ FFB_DFB24B_VOFF,	FFB_DFB24B_POFF,	0x1000000 },
345 	{ FFB_DFB422B_VOFF,	FFB_DFB422B_POFF,	0x0800000 },
346 	{ FFB_DFB422BD_VOFF,	FFB_DFB422BD_POFF,	0x0800000 },
347 	{ FFB_SFB16Z_VOFF,	FFB_SFB16Z_POFF,	0x0800000 },
348 	{ FFB_SFB8Z_VOFF,	FFB_SFB8Z_POFF,		0x0800000 },
349 	{ FFB_SFB422_VOFF,	FFB_SFB422_POFF,	0x0800000 },
350 	{ FFB_SFB422D_VOFF,	FFB_SFB422D_POFF,	0x0800000 },
351 	{ 0,			0,			0	  }
352 };
353 
ffb_setup(struct display * p)354 static void ffb_setup(struct display *p)
355 {
356 	p->next_line = 8192;
357 	p->next_plane = 0;
358 }
359 
ffb_clear(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)360 static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
361 		      int height, int width)
362 {
363 	struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
364 	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
365 	unsigned long flags;
366 	u64 yx, hw;
367 	int fg;
368 
369 	spin_lock_irqsave(&fb->lock, flags);
370 	fg = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p,conp)];
371 	if (fg != fb->s.ffb.fg_cache) {
372 		FFBFifo(fb, 5);
373 		upa_writel(fg, &fbc->fg);
374 		fb->s.ffb.fg_cache = fg;
375 	} else
376 		FFBFifo(fb, 4);
377 
378 	if (fontheightlog(p)) {
379 		yx = (u64)sy << (fontheightlog(p) + 32); hw = (u64)height << (fontheightlog(p) + 32);
380 	} else {
381 		yx = (u64)(sy * fontheight(p)) << 32; hw = (u64)(height * fontheight(p)) << 32;
382 	}
383 	if (fontwidthlog(p)) {
384 		yx += sx << fontwidthlog(p); hw += width << fontwidthlog(p);
385 	} else {
386 		yx += sx * fontwidth(p); hw += width * fontwidth(p);
387 	}
388 	upa_writeq(yx + fb->s.ffb.yx_margin, &fbc->by);
389 	upa_writeq(hw, &fbc->bh);
390 	spin_unlock_irqrestore(&fb->lock, flags);
391 }
392 
ffb_fill(struct fb_info_sbusfb * fb,struct display * p,int s,int count,unsigned short * boxes)393 static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
394 		     int count, unsigned short *boxes)
395 {
396 	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
397 	unsigned long flags;
398 	int fg;
399 
400 	spin_lock_irqsave(&fb->lock, flags);
401 	fg = ((u32 *)p->dispsw_data)[attr_bgcol(p,s)];
402 	if (fg != fb->s.ffb.fg_cache) {
403 		FFBFifo(fb, 1);
404 		upa_writel(fg, &fbc->fg);
405 		fb->s.ffb.fg_cache = fg;
406 	}
407 	while (count-- > 0) {
408 		FFBFifo(fb, 4);
409 		upa_writel(boxes[1], &fbc->by);
410 		upa_writel(boxes[0], &fbc->bx);
411 		upa_writel(boxes[3] - boxes[1], &fbc->bh);
412 		upa_writel(boxes[2] - boxes[0], &fbc->bw);
413 		boxes += 4;
414 	}
415 	spin_unlock_irqrestore(&fb->lock, flags);
416 }
417 
ffb_putc(struct vc_data * conp,struct display * p,int c,int yy,int xx)418 static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
419 {
420 	struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
421 	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
422 	unsigned long flags;
423 	int i, xy;
424 	u8 *fd;
425 	u64 fgbg;
426 
427 	spin_lock_irqsave(&fb->lock, flags);
428 	if (fontheightlog(p)) {
429 		xy = (yy << (16 + fontheightlog(p)));
430 		i = ((c & p->charmask) << fontheightlog(p));
431 	} else {
432 		xy = ((yy * fontheight(p)) << 16);
433 		i = (c & p->charmask) * fontheight(p);
434 	}
435 	if (fontwidth(p) <= 8)
436 		fd = p->fontdata + i;
437 	else
438 		fd = p->fontdata + (i << 1);
439 	if (fontwidthlog(p))
440 		xy += (xx << fontwidthlog(p)) + fb->s.ffb.xy_margin;
441 	else
442 		xy += (xx * fontwidth(p)) + fb->s.ffb.xy_margin;
443 	fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p,c)])) << 32) |
444 	       ((u32 *)p->dispsw_data)[attr_bgcol(p,c)];
445 	if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
446 		FFBFifo(fb, 2);
447 		upa_writeq(fgbg, &fbc->fg);
448 		*(u64 *)&fb->s.ffb.fg_cache = fgbg;
449 	}
450 	FFBFifo(fb, 2 + fontheight(p));
451 	upa_writel(xy, &fbc->fontxy);
452 	upa_writel(fontwidth(p), &fbc->fontw);
453 	if (fontwidth(p) <= 8) {
454 		for (i = 0; i < fontheight(p); i++) {
455 			u32 val = *fd++ << 24;
456 
457 			upa_writel(val, &fbc->font);
458 		}
459 	} else {
460 		for (i = 0; i < fontheight(p); i++) {
461 			u32 val = *(u16 *)fd << 16;
462 
463 			upa_writel(val, &fbc->font);
464 			fd += 2;
465 		}
466 	}
467 	spin_unlock_irqrestore(&fb->lock, flags);
468 }
469 
ffb_putcs(struct vc_data * conp,struct display * p,const unsigned short * s,int count,int yy,int xx)470 static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
471 		      int count, int yy, int xx)
472 {
473 	struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
474 	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
475 	unsigned long flags;
476 	int i, xy;
477 	u8 *fd1, *fd2, *fd3, *fd4;
478 	u16 c;
479 	u64 fgbg;
480 
481 	spin_lock_irqsave(&fb->lock, flags);
482 	c = scr_readw(s);
483 	fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p, c)])) << 32) |
484 	       ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
485 	if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
486 		FFBFifo(fb, 2);
487 		upa_writeq(fgbg, &fbc->fg);
488 		*(u64 *)&fb->s.ffb.fg_cache = fgbg;
489 	}
490 	xy = fb->s.ffb.xy_margin;
491 	if (fontwidthlog(p))
492 		xy += (xx << fontwidthlog(p));
493 	else
494 		xy += xx * fontwidth(p);
495 	if (fontheightlog(p))
496 		xy += (yy << (16 + fontheightlog(p)));
497 	else
498 		xy += ((yy * fontheight(p)) << 16);
499 	if (fontwidth(p) <= 8) {
500 		while (count >= 4) {
501 			count -= 4;
502 			FFBFifo(fb, 2 + fontheight(p));
503 			upa_writel(4 * fontwidth(p), &fbc->fontw);
504 			upa_writel(xy, &fbc->fontxy);
505 			if (fontheightlog(p)) {
506 				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
507 				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
508 				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
509 				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
510 			} else {
511 				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
512 				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
513 				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
514 				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
515 			}
516 			if (fontwidth(p) == 8) {
517 				for (i = 0; i < fontheight(p); i++) {
518 					u32 val;
519 
520 					val = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
521 						<< 8)) << 8)) << 8);
522 					upa_writel(val, &fbc->font);
523 				}
524 				xy += 32;
525 			} else {
526 				for (i = 0; i < fontheight(p); i++) {
527 					u32 val = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++)
528 						<< fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p));
529 					upa_writel(val, &fbc->font);
530 				}
531 				xy += 4 * fontwidth(p);
532 			}
533 		}
534 	} else {
535 		while (count >= 2) {
536 			count -= 2;
537 			FFBFifo(fb, 2 + fontheight(p));
538 			upa_writel(2 * fontwidth(p), &fbc->fontw);
539 			upa_writel(xy, &fbc->fontxy);
540 			if (fontheightlog(p)) {
541 				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
542 				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
543 			} else {
544 				fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
545 				fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
546 			}
547 			for (i = 0; i < fontheight(p); i++) {
548 				u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
549 
550 				upa_writel(val, &fbc->font);
551 				fd1 += 2; fd2 += 2;
552 			}
553 			xy += 2 * fontwidth(p);
554 		}
555 	}
556 	while (count) {
557 		count--;
558 		FFBFifo(fb, 2 + fontheight(p));
559 		upa_writel(fontwidth(p), &fbc->fontw);
560 		upa_writel(xy, &fbc->fontxy);
561 		if (fontheightlog(p))
562 			i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
563 		else
564 			i = ((scr_readw(s++) & p->charmask) * fontheight(p));
565 		if (fontwidth(p) <= 8) {
566 			fd1 = p->fontdata + i;
567 			for (i = 0; i < fontheight(p); i++) {
568 				u32 val = *fd1++ << 24;
569 
570 				upa_writel(val, &fbc->font);
571 			}
572 		} else {
573 			fd1 = p->fontdata + (i << 1);
574 			for (i = 0; i < fontheight(p); i++) {
575 				u32 val = *(u16 *)fd1 << 16;
576 
577 				upa_writel(val, &fbc->font);
578 				fd1 += 2;
579 			}
580 		}
581 		xy += fontwidth(p);
582 	}
583 	spin_unlock_irqrestore(&fb->lock, flags);
584 }
585 
ffb_revc(struct display * p,int xx,int yy)586 static void ffb_revc(struct display *p, int xx, int yy)
587 {
588 	/* Not used if hw cursor */
589 }
590 
591 #if 0
592 static void ffb_blank(struct fb_info_sbusfb *fb)
593 {
594 	struct ffb_dac *dac = fb->s.ffb.dac;
595 	unsigned long flags;
596 	u32 tmp;
597 
598 	spin_lock_irqsave(&fb->lock, flags);
599 	upa_writel(0x6000, &dac->type);
600 	tmp = (upa_readl(&dac->value) & ~0x1);
601 	upa_writel(0x6000, &dac->type);
602 	upa_writel(tmp, &dac->value);
603 	spin_unlock_irqrestore(&fb->lock, flags);
604 }
605 #endif
606 
ffb_unblank(struct fb_info_sbusfb * fb)607 static void ffb_unblank(struct fb_info_sbusfb *fb)
608 {
609 	struct ffb_dac *dac = fb->s.ffb.dac;
610 	unsigned long flags;
611 	u32 tmp;
612 
613 	spin_lock_irqsave(&fb->lock, flags);
614 	upa_writel(0x6000, &dac->type);
615 	tmp = (upa_readl(&dac->value) | 0x1);
616 	upa_writel(0x6000, &dac->type);
617 	upa_writel(tmp, &dac->value);
618 	spin_unlock_irqrestore(&fb->lock, flags);
619 }
620 
ffb_loadcmap(struct fb_info_sbusfb * fb,struct display * p,int index,int count)621 static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
622 {
623 	struct ffb_dac *dac = fb->s.ffb.dac;
624 	unsigned long flags;
625 	int i, j = count;
626 
627 	spin_lock_irqsave(&fb->lock, flags);
628 	upa_writel(0x2000 | index, &dac->type);
629 	for (i = index; j--; i++) {
630 		u32 val;
631 
632 		/* Feed the colors in :)) */
633 		val = ((fb->color_map CM(i,0))) |
634 			((fb->color_map CM(i,1)) << 8) |
635 			((fb->color_map CM(i,2)) << 16);
636 		upa_writel(val, &dac->value);
637 	}
638 	if (!p)
639 		goto out;
640 	for (i = index, j = count; i < 16 && j--; i++)
641 		((u32 *)p->dispsw_data)[i] = ((fb->color_map CM(i,0))) |
642 			      		     ((fb->color_map CM(i,1)) << 8) |
643 					     ((fb->color_map CM(i,2)) << 16);
644 out:
645 	spin_unlock_irqrestore(&fb->lock, flags);
646 }
647 
648 static struct display_switch ffb_dispsw __initdata = {
649 	setup:		ffb_setup,
650 	bmove:		fbcon_redraw_bmove,
651 	clear:		ffb_clear,
652 	putc:		ffb_putc,
653 	putcs:		ffb_putcs,
654 	revc:		ffb_revc,
655 	fontwidthmask:	FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
656 };
657 
ffb_margins(struct fb_info_sbusfb * fb,struct display * p,int x_margin,int y_margin)658 static void ffb_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
659 {
660 	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
661 	unsigned long flags;
662 
663 	spin_lock_irqsave(&fb->lock, flags);
664 	fb->s.ffb.xy_margin = (y_margin << 16) + x_margin;
665 	fb->s.ffb.yx_margin = (((u64)y_margin) << 32) + x_margin;
666 	p->screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin);
667 	FFBWait(fbc);
668 	spin_unlock_irqrestore(&fb->lock, flags);
669 }
670 
__ffb_curs_enable(struct fb_info_sbusfb * fb,int enable)671 static __inline__ void __ffb_curs_enable (struct fb_info_sbusfb *fb, int enable)
672 {
673 	struct ffb_dac *dac = fb->s.ffb.dac;
674 	u32 val;
675 
676 	upa_writel(0x100, &dac->type2);
677 	if (fb->s.ffb.dac_rev <= 2) {
678 		val = enable ? 3 : 0;
679 	} else {
680 		val = enable ? 0 : 3;
681 	}
682 	upa_writel(val, &dac->value2);
683 }
684 
ffb_setcursormap(struct fb_info_sbusfb * fb,u8 * red,u8 * green,u8 * blue)685 static void ffb_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
686 {
687 	struct ffb_dac *dac = fb->s.ffb.dac;
688 	unsigned long flags;
689 
690 	spin_lock_irqsave(&fb->lock, flags);
691 	__ffb_curs_enable (fb, 0);
692 	upa_writel(0x102, &dac->type2);
693 	upa_writel((red[0] | (green[0]<<8) | (blue[0]<<16)), &dac->value2);
694 	upa_writel((red[1] | (green[1]<<8) | (blue[1]<<16)), &dac->value2);
695 	spin_unlock_irqrestore(&fb->lock, flags);
696 }
697 
698 /* Set cursor shape */
ffb_setcurshape(struct fb_info_sbusfb * fb)699 static void ffb_setcurshape (struct fb_info_sbusfb *fb)
700 {
701 	struct ffb_dac *dac = fb->s.ffb.dac;
702 	unsigned long flags;
703 	int i, j;
704 
705 	spin_lock_irqsave(&fb->lock, flags);
706 	__ffb_curs_enable (fb, 0);
707 	for (j = 0; j < 2; j++) {
708 		u32 val = j ? 0 : 0x80;
709 
710 		upa_writel(val, &dac->type2);
711 		for (i = 0; i < 0x40; i++) {
712 			if (fb->cursor.size.fbx <= 32) {
713 				upa_writel(fb->cursor.bits [j][i], &dac->value2);
714 				upa_writel(0, &dac->value2);
715 			} else {
716 				upa_writel(fb->cursor.bits [j][2*i], &dac->value2);
717 				upa_writel(fb->cursor.bits [j][2*i+1], &dac->value2);
718 			}
719 		}
720 	}
721 	spin_unlock_irqrestore(&fb->lock, flags);
722 }
723 
724 /* Load cursor information */
ffb_setcursor(struct fb_info_sbusfb * fb)725 static void ffb_setcursor (struct fb_info_sbusfb *fb)
726 {
727 	struct ffb_dac *dac = fb->s.ffb.dac;
728 	struct cg_cursor *c = &fb->cursor;
729 	unsigned long flags;
730 	u32 val;
731 
732 	spin_lock_irqsave(&fb->lock, flags);
733 	upa_writel(0x104, &dac->type2);
734 	/* Should this be just 0x7ff??
735 	   Should I do some margin handling and setcurshape in that case? */
736 	val = (((c->cpos.fby - c->chot.fby) & 0xffff) << 16)
737 		|((c->cpos.fbx - c->chot.fbx) & 0xffff);
738 	upa_writel(val, &dac->value2);
739 	__ffb_curs_enable (fb, fb->cursor.enable);
740 	spin_unlock_irqrestore(&fb->lock, flags);
741 }
742 
ffb_switch_from_graph(struct fb_info_sbusfb * fb)743 static void ffb_switch_from_graph (struct fb_info_sbusfb *fb)
744 {
745 	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
746 	unsigned long flags;
747 
748 	spin_lock_irqsave(&fb->lock, flags);
749 	FFBWait(fbc);
750 	fb->s.ffb.fifo_cache = 0;
751 	FFBFifo(fb, 8);
752 	upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
753 		   FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
754 		   &fbc->ppc);
755 	upa_writel(0x2000707f, &fbc->fbc);
756 	upa_writel(FFB_ROP_NEW, &fbc->rop);
757 	upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
758 	upa_writel(0xffffffff, &fbc->pmask);
759 	upa_writel(0x10000, &fbc->fontinc);
760 	upa_writel(fb->s.ffb.fg_cache, &fbc->fg);
761 	upa_writel(fb->s.ffb.bg_cache, &fbc->bg);
762 	FFBWait(fbc);
763 	spin_unlock_irqrestore(&fb->lock, flags);
764 }
765 
ffb_rasterimg(struct fb_info * info,int start)766 static int __init ffb_rasterimg (struct fb_info *info, int start)
767 {
768 	ffb_switch_from_graph (sbusfbinfo(info));
769 	return 0;
770 }
771 
772 static char idstring[60] __initdata = { 0 };
773 
creator_apply_upa_parent_ranges(int parent,struct linux_prom64_registers * regs)774 static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs)
775 {
776 	struct linux_prom64_ranges ranges[PROMREG_MAX];
777 	char name[128];
778 	int len, i;
779 
780 	prom_getproperty(parent, "name", name, sizeof(name));
781 	if (strcmp(name, "upa") != 0)
782 		return 0;
783 
784 	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
785 	if (len <= 0)
786 		return 1;
787 
788 	len /= sizeof(struct linux_prom64_ranges);
789 	for (i = 0; i < len; i++) {
790 		struct linux_prom64_ranges *rng = &ranges[i];
791 		u64 phys_addr = regs->phys_addr;
792 
793 		if (phys_addr >= rng->ot_child_base &&
794 		    phys_addr < (rng->ot_child_base + rng->or_size)) {
795 			regs->phys_addr -= rng->ot_child_base;
796 			regs->phys_addr += rng->ot_parent_base;
797 			return 0;
798 		}
799 	}
800 
801 	return 1;
802 }
803 
creatorfb_init(struct fb_info_sbusfb * fb)804 char __init *creatorfb_init(struct fb_info_sbusfb *fb)
805 {
806 	struct fb_fix_screeninfo *fix = &fb->fix;
807 	struct fb_var_screeninfo *var = &fb->var;
808 	struct display *disp = &fb->disp;
809 	struct fbtype *type = &fb->type;
810 	struct linux_prom64_registers regs[2*PROMREG_MAX];
811 	int i, afb = 0;
812 	unsigned int btype;
813 	char name[64];
814 	struct fb_ops *fbops;
815 
816 	if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0)
817 		return NULL;
818 
819 	if (creator_apply_upa_parent_ranges(fb->prom_parent, &regs[0]))
820 		return NULL;
821 
822 	disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL);
823 	if (disp->dispsw_data == NULL)
824 		return NULL;
825 	memset(disp->dispsw_data, 0, 16 * sizeof(u32));
826 
827 	fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
828 	if (fbops == NULL) {
829 		kfree(disp->dispsw_data);
830 		return NULL;
831 	}
832 
833 	*fbops = *fb->info.fbops;
834 	fbops->fb_rasterimg = ffb_rasterimg;
835 	fb->info.fbops = fbops;
836 
837 	prom_getstring(fb->prom_node, "name", name, sizeof(name));
838 	if (!strcmp(name, "SUNW,afb"))
839 		afb = 1;
840 
841 	btype = prom_getintdefault(fb->prom_node, "board_type", 0);
842 
843 	strcpy(fb->info.modename, "Creator");
844 	if (!afb) {
845 		if ((btype & 7) == 3)
846 		    strcpy(fix->id, "Creator 3D");
847 		else
848 		    strcpy(fix->id, "Creator");
849 	} else
850 		strcpy(fix->id, "Elite 3D");
851 
852 	fix->visual = FB_VISUAL_TRUECOLOR;
853 	fix->line_length = 8192;
854 	fix->accel = FB_ACCEL_SUN_CREATOR;
855 
856 	var->bits_per_pixel = 32;
857 	var->green.offset = 8;
858 	var->blue.offset = 16;
859 	var->accel_flags = FB_ACCELF_TEXT;
860 
861 	disp->scrollmode = SCROLL_YREDRAW;
862 	disp->screen_base = (char *)__va(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin;
863 	fb->s.ffb.xy_margin = (fb->y_margin << 16) + fb->x_margin;
864 	fb->s.ffb.yx_margin = (((u64)fb->y_margin) << 32) + fb->x_margin;
865 	fb->s.ffb.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
866 	fb->s.ffb.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
867 	fb->dispsw = ffb_dispsw;
868 
869 	fb->margins = ffb_margins;
870 	fb->loadcmap = ffb_loadcmap;
871 	fb->setcursor = ffb_setcursor;
872 	fb->setcursormap = ffb_setcursormap;
873 	fb->setcurshape = ffb_setcurshape;
874 	fb->switch_from_graph = ffb_switch_from_graph;
875 	fb->fill = ffb_fill;
876 #if 0
877 	/* XXX Can't enable this for now, I've seen cases
878 	 * XXX where the VC was blanked, and Xsun24 was started
879 	 * XXX via a remote login, the sunfb code did not
880 	 * XXX unblank creator when it was mmap'd for some
881 	 * XXX reason, investigate later... -DaveM
882 	 */
883 	fb->blank = ffb_blank;
884 	fb->unblank = ffb_unblank;
885 #endif
886 
887 	/* If there are any read errors or fifo overflow conditions,
888 	 * clear them now.
889 	 */
890 	if((upa_readl(&fb->s.ffb.fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
891 		upa_writel(FFB_UCSR_ALL_ERRORS, &fb->s.ffb.fbc->ucsr);
892 
893 	ffb_switch_from_graph(fb);
894 
895 	fb->physbase = regs[0].phys_addr;
896 	fb->mmap_map = ffb_mmap_map;
897 
898 	fb->cursor.hwsize.fbx = 64;
899 	fb->cursor.hwsize.fby = 64;
900 
901 	type->fb_depth = 24;
902 
903 	upa_writel(0x8000, &fb->s.ffb.dac->type);
904 	fb->s.ffb.dac_rev = (upa_readl(&fb->s.ffb.dac->value) >> 0x1c);
905 
906 	i = prom_getintdefault (fb->prom_node, "board_type", 8);
907 
908 	sprintf(idstring, "%s at %016lx type %d DAC %d",
909 		fix->id, regs[0].phys_addr, i, fb->s.ffb.dac_rev);
910 
911 	/* Elite3D has different DAC revision numbering, and no DAC revisions
912 	   have the reversed meaning of cursor enable */
913 	if (afb)
914 		fb->s.ffb.dac_rev = 10;
915 
916 	/* Unblank it just to be sure.  When there are multiple
917 	 * FFB/AFB cards in the system, or it is not the OBP
918 	 * chosen console, it will have video outputs off in
919 	 * the DAC.
920 	 */
921 	ffb_unblank(fb);
922 
923 	return idstring;
924 }
925 
926 MODULE_LICENSE("GPL");
927