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

1     /* $Id: creatorfb.c,v 1.36 2001/09/19 00:04:33 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     
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     
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     
354     static void ffb_setup(struct display *p)
355     {
356     	p->next_line = 8192;
357     	p->next_plane = 0;
358     }
359     
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     
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     
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     
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     	u64 fgbg;
479     
480     	spin_lock_irqsave(&fb->lock, flags);
481     	fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p,scr_readw(s))])) << 32) |
482     	       ((u32 *)p->dispsw_data)[attr_bgcol(p,scr_readw(s))];
483     	if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
484     		FFBFifo(fb, 2);
485     		upa_writeq(fgbg, &fbc->fg);
486     		*(u64 *)&fb->s.ffb.fg_cache = fgbg;
487     	}
488     	xy = fb->s.ffb.xy_margin;
489     	if (fontwidthlog(p))
490     		xy += (xx << fontwidthlog(p));
491     	else
492     		xy += xx * fontwidth(p);
493     	if (fontheightlog(p))
494     		xy += (yy << (16 + fontheightlog(p)));
495     	else
496     		xy += ((yy * fontheight(p)) << 16);
497     	if (fontwidth(p) <= 8) {
498     		while (count >= 4) {
499     			count -= 4;
500     			FFBFifo(fb, 2 + fontheight(p));
501     			upa_writel(4 * fontwidth(p), &fbc->fontw);
502     			upa_writel(xy, &fbc->fontxy);
503     			if (fontheightlog(p)) {
504     				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
505     				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
506     				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
507     				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
508     			} else {
509     				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
510     				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
511     				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
512     				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
513     			}
514     			if (fontwidth(p) == 8) {
515     				for (i = 0; i < fontheight(p); i++) {
516     					u32 val;
517     
518     					val = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
519     						<< 8)) << 8)) << 8);
520     					upa_writel(val, &fbc->font);
521     				}
522     				xy += 32;
523     			} else {
524     				for (i = 0; i < fontheight(p); i++) {
525     					u32 val = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
526     						<< fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p));
527     					upa_writel(val, &fbc->font);
528     				}
529     				xy += 4 * fontwidth(p);
530     			}
531     		}
532     	} else {
533     		while (count >= 2) {
534     			count -= 2;
535     			FFBFifo(fb, 2 + fontheight(p));
536     			upa_writel(2 * fontwidth(p), &fbc->fontw);
537     			upa_writel(xy, &fbc->fontxy);
538     			if (fontheightlog(p)) {
539     				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
540     				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
541     			} else {
542     				fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
543     				fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
544     			}
545     			for (i = 0; i < fontheight(p); i++) {
546     				u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
547     
548     				upa_writel(val, &fbc->font);
549     				fd1 += 2; fd2 += 2;
550     			}
551     			xy += 2 * fontwidth(p);
552     		}
553     	}
554     	while (count) {
555     		count--;
556     		FFBFifo(fb, 2 + fontheight(p));
557     		upa_writel(fontwidth(p), &fbc->fontw);
558     		upa_writel(xy, &fbc->fontxy);
559     		if (fontheightlog(p))
560     			i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
561     		else
562     			i = ((scr_readw(s++) & p->charmask) * fontheight(p));
563     		if (fontwidth(p) <= 8) {
564     			fd1 = p->fontdata + i;
565     			for (i = 0; i < fontheight(p); i++) {
566     				u32 val = *fd1++ << 24;
567     
568     				upa_writel(val, &fbc->font);
569     			}
570     		} else {
571     			fd1 = p->fontdata + (i << 1);
572     			for (i = 0; i < fontheight(p); i++) {
573     				u32 val = *(u16 *)fd1 << 16;
574     
575     				upa_writel(val, &fbc->font);
576     				fd1 += 2;
577     			}
578     		}
579     		xy += fontwidth(p);
580     	}
581     	spin_unlock_irqrestore(&fb->lock, flags);
582     }
583     
584     static void ffb_revc(struct display *p, int xx, int yy)
585     {
586     	/* Not used if hw cursor */
587     }
588     
589     #if 0
590     static void ffb_blank(struct fb_info_sbusfb *fb)
591     {
592     	struct ffb_dac *dac = fb->s.ffb.dac;
593     	unsigned long flags;
594     	u32 tmp;
595     
596     	spin_lock_irqsave(&fb->lock, flags);
597     	upa_writel(0x6000, &dac->type);
598     	tmp = (upa_readl(&dac->value) & ~0x1);
599     	upa_writel(0x6000, &dac->type);
600     	upa_writel(tmp, &dac->value);
601     	spin_unlock_irqrestore(&fb->lock, flags);
602     }
603     #endif
604     
605     static void ffb_unblank(struct fb_info_sbusfb *fb)
606     {
607     	struct ffb_dac *dac = fb->s.ffb.dac;
608     	unsigned long flags;
609     	u32 tmp;
610     
611     	spin_lock_irqsave(&fb->lock, flags);
612     	upa_writel(0x6000, &dac->type);
613     	tmp = (upa_readl(&dac->value) | 0x1);
614     	upa_writel(0x6000, &dac->type);
615     	upa_writel(tmp, &dac->value);
616     	spin_unlock_irqrestore(&fb->lock, flags);
617     }
618     
619     static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
620     {
621     	struct ffb_dac *dac = fb->s.ffb.dac;
622     	unsigned long flags;
623     	int i, j = count;
624     	
625     	spin_lock_irqsave(&fb->lock, flags);
626     	upa_writel(0x2000 | index, &dac->type);
627     	for (i = index; j--; i++) {
628     		u32 val;
629     
630     		/* Feed the colors in :)) */
631     		val = ((fb->color_map CM(i,0))) |
632     			((fb->color_map CM(i,1)) << 8) |
633     			((fb->color_map CM(i,2)) << 16);
634     		upa_writel(val, &dac->value);
635     	}
636     	if (!p)
637     		goto out;
638     	for (i = index, j = count; i < 16 && j--; i++)
639     		((u32 *)p->dispsw_data)[i] = ((fb->color_map CM(i,0))) |
640     			      		     ((fb->color_map CM(i,1)) << 8) |
641     					     ((fb->color_map CM(i,2)) << 16);
642     out:
643     	spin_unlock_irqrestore(&fb->lock, flags);
644     }
645     
646     static struct display_switch ffb_dispsw __initdata = {
647     	setup:		ffb_setup,
648     	bmove:		fbcon_redraw_bmove,
649     	clear:		ffb_clear,
650     	putc:		ffb_putc,
651     	putcs:		ffb_putcs,
652     	revc:		ffb_revc, 
653     	fontwidthmask:	FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
654     };
655     
656     static void ffb_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
657     {
658     	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
659     	unsigned long flags;
660     
661     	spin_lock_irqsave(&fb->lock, flags);
662     	fb->s.ffb.xy_margin = (y_margin << 16) + x_margin;
663     	fb->s.ffb.yx_margin = (((u64)y_margin) << 32) + x_margin;
664     	p->screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin);
665     	FFBWait(fbc);
666     	spin_unlock_irqrestore(&fb->lock, flags);
667     }
668     
669     static __inline__ void __ffb_curs_enable (struct fb_info_sbusfb *fb, int enable)
670     {
671     	struct ffb_dac *dac = fb->s.ffb.dac;
672     	u32 val;
673     
674     	upa_writel(0x100, &dac->type2);
675     	if (fb->s.ffb.dac_rev <= 2) {
676     		val = enable ? 3 : 0;
677     	} else {
678     		val = enable ? 0 : 3;
679     	}
680     	upa_writel(val, &dac->value2);
681     }
682     
683     static void ffb_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
684     {
685     	struct ffb_dac *dac = fb->s.ffb.dac;
686     	unsigned long flags;
687     	
688     	spin_lock_irqsave(&fb->lock, flags);
689     	__ffb_curs_enable (fb, 0);
690     	upa_writel(0x102, &dac->type2);
691     	upa_writel((red[0] | (green[0]<<8) | (blue[0]<<16)), &dac->value2);
692     	upa_writel((red[1] | (green[1]<<8) | (blue[1]<<16)), &dac->value2);
693     	spin_unlock_irqrestore(&fb->lock, flags);
694     }
695     
696     /* Set cursor shape */
697     static void ffb_setcurshape (struct fb_info_sbusfb *fb)
698     {
699     	struct ffb_dac *dac = fb->s.ffb.dac;
700     	unsigned long flags;
701     	int i, j;
702     
703     	spin_lock_irqsave(&fb->lock, flags);
704     	__ffb_curs_enable (fb, 0);
705     	for (j = 0; j < 2; j++) {
706     		u32 val = j ? 0 : 0x80;
707     
708     		upa_writel(val, &dac->type2);
709     		for (i = 0; i < 0x40; i++) {
710     			if (fb->cursor.size.fbx <= 32) {
711     				upa_writel(fb->cursor.bits [j][i], &dac->value2);
712     				upa_writel(0, &dac->value2);
713     			} else {
714     				upa_writel(fb->cursor.bits [j][2*i], &dac->value2);
715     				upa_writel(fb->cursor.bits [j][2*i+1], &dac->value2);
716     			}
717     		}
718     	}	
719     	spin_unlock_irqrestore(&fb->lock, flags);
720     }
721     
722     /* Load cursor information */
723     static void ffb_setcursor (struct fb_info_sbusfb *fb)
724     {
725     	struct ffb_dac *dac = fb->s.ffb.dac;
726     	struct cg_cursor *c = &fb->cursor;
727     	unsigned long flags;
728     	u32 val;
729     
730     	spin_lock_irqsave(&fb->lock, flags);
731     	upa_writel(0x104, &dac->type2);
732     	/* Should this be just 0x7ff?? 
733     	   Should I do some margin handling and setcurshape in that case? */
734     	val = (((c->cpos.fby - c->chot.fby) & 0xffff) << 16)
735     		|((c->cpos.fbx - c->chot.fbx) & 0xffff);
736     	upa_writel(val, &dac->value2);
737     	__ffb_curs_enable (fb, fb->cursor.enable);
738     	spin_unlock_irqrestore(&fb->lock, flags);
739     }
740     
741     static void ffb_switch_from_graph (struct fb_info_sbusfb *fb)
742     {
743     	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
744     	unsigned long flags;
745     
746     	spin_lock_irqsave(&fb->lock, flags);
747     	FFBWait(fbc);
748     	fb->s.ffb.fifo_cache = 0;
749     	FFBFifo(fb, 8);
750     	upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
751     		   FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
752     		   &fbc->ppc);
753     	upa_writel(0x2000707f, &fbc->fbc);
754     	upa_writel(FFB_ROP_NEW, &fbc->rop);
755     	upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
756     	upa_writel(0xffffffff, &fbc->pmask);
757     	upa_writel(0x10000, &fbc->fontinc);
758     	upa_writel(fb->s.ffb.fg_cache, &fbc->fg);
759     	upa_writel(fb->s.ffb.bg_cache, &fbc->bg);
760     	FFBWait(fbc);
761     	spin_unlock_irqrestore(&fb->lock, flags);
762     }
763     
764     static int __init ffb_rasterimg (struct fb_info *info, int start)
765     {
766     	ffb_switch_from_graph (sbusfbinfo(info));
767     	return 0;
768     }
769     
770     static char idstring[60] __initdata = { 0 };
771     
772     static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs)
773     {
774     	struct linux_prom64_ranges ranges[PROMREG_MAX];
775     	char name[128];
776     	int len, i;
777     
778     	prom_getproperty(parent, "name", name, sizeof(name));
779     	if (strcmp(name, "upa") != 0)
780     		return 0;
781     
782     	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
783     	if (len <= 0)
784     		return 1;
785     
786     	len /= sizeof(struct linux_prom64_ranges);
787     	for (i = 0; i < len; i++) {
788     		struct linux_prom64_ranges *rng = &ranges[i];
789     		u64 phys_addr = regs->phys_addr;
790     
791     		if (phys_addr >= rng->ot_child_base &&
792     		    phys_addr < (rng->ot_child_base + rng->or_size)) {
793     			regs->phys_addr -= rng->ot_child_base;
794     			regs->phys_addr += rng->ot_parent_base;
795     			return 0;
796     		}
797     	}
798     
799     	return 1;
800     }
801     
802     char __init *creatorfb_init(struct fb_info_sbusfb *fb)
803     {
804     	struct fb_fix_screeninfo *fix = &fb->fix;
805     	struct fb_var_screeninfo *var = &fb->var;
806     	struct display *disp = &fb->disp;
807     	struct fbtype *type = &fb->type;
808     	struct linux_prom64_registers regs[2*PROMREG_MAX];
809     	int i, afb = 0;
810     	unsigned int btype;
811     	char name[64];
812     	struct fb_ops *fbops;
813     
814     	if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0)
815     		return NULL;
816     
817     	if (creator_apply_upa_parent_ranges(fb->prom_parent, &regs[0]))
818     		return NULL;
819     		
820     	disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL);
821     	if (disp->dispsw_data == NULL)
822     		return NULL;
823     	memset(disp->dispsw_data, 0, 16 * sizeof(u32));
824     
825     	fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
826     	if (fbops == NULL) {
827     		kfree(disp->dispsw_data);
828     		return NULL;
829     	}
830     	
831     	*fbops = *fb->info.fbops;
832     	fbops->fb_rasterimg = ffb_rasterimg;
833     	fb->info.fbops = fbops;
834     
835     	prom_getstring(fb->prom_node, "name", name, sizeof(name));
836     	if (!strcmp(name, "SUNW,afb"))
837     		afb = 1;
838     		
839     	btype = prom_getintdefault(fb->prom_node, "board_type", 0);
840     		
841     	strcpy(fb->info.modename, "Creator");
842     	if (!afb) {
843     		if ((btype & 7) == 3)
844     		    strcpy(fix->id, "Creator 3D");
845     		else
846     		    strcpy(fix->id, "Creator");
847     	} else
848     		strcpy(fix->id, "Elite 3D");
849     	
850     	fix->visual = FB_VISUAL_TRUECOLOR;
851     	fix->line_length = 8192;
852     	fix->accel = FB_ACCEL_SUN_CREATOR;
853     	
854     	var->bits_per_pixel = 32;
855     	var->green.offset = 8;
856     	var->blue.offset = 16;
857     	var->accel_flags = FB_ACCELF_TEXT;
858     	
859     	disp->scrollmode = SCROLL_YREDRAW;
860     	disp->screen_base = (char *)__va(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin;
861     	fb->s.ffb.xy_margin = (fb->y_margin << 16) + fb->x_margin;
862     	fb->s.ffb.yx_margin = (((u64)fb->y_margin) << 32) + fb->x_margin;
863     	fb->s.ffb.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
864     	fb->s.ffb.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
865     	fb->dispsw = ffb_dispsw;
866     
867     	fb->margins = ffb_margins;
868     	fb->loadcmap = ffb_loadcmap;
869     	fb->setcursor = ffb_setcursor;
870     	fb->setcursormap = ffb_setcursormap;
871     	fb->setcurshape = ffb_setcurshape;
872     	fb->switch_from_graph = ffb_switch_from_graph;
873     	fb->fill = ffb_fill;
874     #if 0
875     	/* XXX Can't enable this for now, I've seen cases
876     	 * XXX where the VC was blanked, and Xsun24 was started
877     	 * XXX via a remote login, the sunfb code did not
878     	 * XXX unblank creator when it was mmap'd for some
879     	 * XXX reason, investigate later... -DaveM
880     	 */
881     	fb->blank = ffb_blank;
882     	fb->unblank = ffb_unblank;
883     #endif
884     	
885     	/* If there are any read errors or fifo overflow conditions,
886     	 * clear them now.
887     	 */
888     	if((upa_readl(&fb->s.ffb.fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
889     		upa_writel(FFB_UCSR_ALL_ERRORS, &fb->s.ffb.fbc->ucsr);
890     
891     	ffb_switch_from_graph(fb);
892     	
893     	fb->physbase = regs[0].phys_addr;
894     	fb->mmap_map = ffb_mmap_map;
895     	
896     	fb->cursor.hwsize.fbx = 64;
897     	fb->cursor.hwsize.fby = 64;
898     	
899     	type->fb_depth = 24;
900     	
901     	upa_writel(0x8000, &fb->s.ffb.dac->type);
902     	fb->s.ffb.dac_rev = (upa_readl(&fb->s.ffb.dac->value) >> 0x1c);
903     	                
904     	i = prom_getintdefault (fb->prom_node, "board_type", 8);
905     
906     	sprintf(idstring, "%s at %016lx type %d DAC %d",
907     		fix->id, regs[0].phys_addr, i, fb->s.ffb.dac_rev);
908     	
909     	/* Elite3D has different DAC revision numbering, and no DAC revisions
910     	   have the reversed meaning of cursor enable */
911     	if (afb)
912     		fb->s.ffb.dac_rev = 10;
913     	
914     	/* Unblank it just to be sure.  When there are multiple
915     	 * FFB/AFB cards in the system, or it is not the OBP
916     	 * chosen console, it will have video outputs off in
917     	 * the DAC.
918     	 */
919     	ffb_unblank(fb);
920     
921     	return idstring;
922     }
923     
924     MODULE_LICENSE("GPL");
925