1/* $Id: creatorfb.c,v 1.1.1.1 2008/10/15 03:27:04 james26_jang 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
144struct 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
290static __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
303static __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
316struct ffb_dac {
317	volatile u32	type;
318	volatile u32	value;
319	volatile u32	type2;
320	volatile u32	value2;
321};
322
323static 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
354static void ffb_setup(struct display *p)
355{
356	p->next_line = 8192;
357	p->next_plane = 0;
358}
359
360static 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
393static 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
418static 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
470static 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
586static void ffb_revc(struct display *p, int xx, int yy)
587{
588	/* Not used if hw cursor */
589}
590
591
592static void ffb_unblank(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
606static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
607{
608	struct ffb_dac *dac = fb->s.ffb.dac;
609	unsigned long flags;
610	int i, j = count;
611
612	spin_lock_irqsave(&fb->lock, flags);
613	upa_writel(0x2000 | index, &dac->type);
614	for (i = index; j--; i++) {
615		u32 val;
616
617		/* Feed the colors in :)) */
618		val = ((fb->color_map CM(i,0))) |
619			((fb->color_map CM(i,1)) << 8) |
620			((fb->color_map CM(i,2)) << 16);
621		upa_writel(val, &dac->value);
622	}
623	if (!p)
624		goto out;
625	for (i = index, j = count; i < 16 && j--; i++)
626		((u32 *)p->dispsw_data)[i] = ((fb->color_map CM(i,0))) |
627			      		     ((fb->color_map CM(i,1)) << 8) |
628					     ((fb->color_map CM(i,2)) << 16);
629out:
630	spin_unlock_irqrestore(&fb->lock, flags);
631}
632
633static struct display_switch ffb_dispsw __initdata = {
634	setup:		ffb_setup,
635	bmove:		fbcon_redraw_bmove,
636	clear:		ffb_clear,
637	putc:		ffb_putc,
638	putcs:		ffb_putcs,
639	revc:		ffb_revc,
640	fontwidthmask:	FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
641};
642
643static void ffb_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
644{
645	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
646	unsigned long flags;
647
648	spin_lock_irqsave(&fb->lock, flags);
649	fb->s.ffb.xy_margin = (y_margin << 16) + x_margin;
650	fb->s.ffb.yx_margin = (((u64)y_margin) << 32) + x_margin;
651	p->screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin);
652	FFBWait(fbc);
653	spin_unlock_irqrestore(&fb->lock, flags);
654}
655
656static __inline__ void __ffb_curs_enable (struct fb_info_sbusfb *fb, int enable)
657{
658	struct ffb_dac *dac = fb->s.ffb.dac;
659	u32 val;
660
661	upa_writel(0x100, &dac->type2);
662	if (fb->s.ffb.dac_rev <= 2) {
663		val = enable ? 3 : 0;
664	} else {
665		val = enable ? 0 : 3;
666	}
667	upa_writel(val, &dac->value2);
668}
669
670static void ffb_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
671{
672	struct ffb_dac *dac = fb->s.ffb.dac;
673	unsigned long flags;
674
675	spin_lock_irqsave(&fb->lock, flags);
676	__ffb_curs_enable (fb, 0);
677	upa_writel(0x102, &dac->type2);
678	upa_writel((red[0] | (green[0]<<8) | (blue[0]<<16)), &dac->value2);
679	upa_writel((red[1] | (green[1]<<8) | (blue[1]<<16)), &dac->value2);
680	spin_unlock_irqrestore(&fb->lock, flags);
681}
682
683/* Set cursor shape */
684static void ffb_setcurshape (struct fb_info_sbusfb *fb)
685{
686	struct ffb_dac *dac = fb->s.ffb.dac;
687	unsigned long flags;
688	int i, j;
689
690	spin_lock_irqsave(&fb->lock, flags);
691	__ffb_curs_enable (fb, 0);
692	for (j = 0; j < 2; j++) {
693		u32 val = j ? 0 : 0x80;
694
695		upa_writel(val, &dac->type2);
696		for (i = 0; i < 0x40; i++) {
697			if (fb->cursor.size.fbx <= 32) {
698				upa_writel(fb->cursor.bits [j][i], &dac->value2);
699				upa_writel(0, &dac->value2);
700			} else {
701				upa_writel(fb->cursor.bits [j][2*i], &dac->value2);
702				upa_writel(fb->cursor.bits [j][2*i+1], &dac->value2);
703			}
704		}
705	}
706	spin_unlock_irqrestore(&fb->lock, flags);
707}
708
709/* Load cursor information */
710static void ffb_setcursor (struct fb_info_sbusfb *fb)
711{
712	struct ffb_dac *dac = fb->s.ffb.dac;
713	struct cg_cursor *c = &fb->cursor;
714	unsigned long flags;
715	u32 val;
716
717	spin_lock_irqsave(&fb->lock, flags);
718	upa_writel(0x104, &dac->type2);
719	/* Should this be just 0x7ff??
720	   Should I do some margin handling and setcurshape in that case? */
721	val = (((c->cpos.fby - c->chot.fby) & 0xffff) << 16)
722		|((c->cpos.fbx - c->chot.fbx) & 0xffff);
723	upa_writel(val, &dac->value2);
724	__ffb_curs_enable (fb, fb->cursor.enable);
725	spin_unlock_irqrestore(&fb->lock, flags);
726}
727
728static void ffb_switch_from_graph (struct fb_info_sbusfb *fb)
729{
730	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
731	unsigned long flags;
732
733	spin_lock_irqsave(&fb->lock, flags);
734	FFBWait(fbc);
735	fb->s.ffb.fifo_cache = 0;
736	FFBFifo(fb, 8);
737	upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
738		   FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
739		   &fbc->ppc);
740	upa_writel(0x2000707f, &fbc->fbc);
741	upa_writel(FFB_ROP_NEW, &fbc->rop);
742	upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
743	upa_writel(0xffffffff, &fbc->pmask);
744	upa_writel(0x10000, &fbc->fontinc);
745	upa_writel(fb->s.ffb.fg_cache, &fbc->fg);
746	upa_writel(fb->s.ffb.bg_cache, &fbc->bg);
747	FFBWait(fbc);
748	spin_unlock_irqrestore(&fb->lock, flags);
749}
750
751static int __init ffb_rasterimg (struct fb_info *info, int start)
752{
753	ffb_switch_from_graph (sbusfbinfo(info));
754	return 0;
755}
756
757static char idstring[60] __initdata = { 0 };
758
759static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs)
760{
761	struct linux_prom64_ranges ranges[PROMREG_MAX];
762	char name[128];
763	int len, i;
764
765	prom_getproperty(parent, "name", name, sizeof(name));
766	if (strcmp(name, "upa") != 0)
767		return 0;
768
769	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
770	if (len <= 0)
771		return 1;
772
773	len /= sizeof(struct linux_prom64_ranges);
774	for (i = 0; i < len; i++) {
775		struct linux_prom64_ranges *rng = &ranges[i];
776		u64 phys_addr = regs->phys_addr;
777
778		if (phys_addr >= rng->ot_child_base &&
779		    phys_addr < (rng->ot_child_base + rng->or_size)) {
780			regs->phys_addr -= rng->ot_child_base;
781			regs->phys_addr += rng->ot_parent_base;
782			return 0;
783		}
784	}
785
786	return 1;
787}
788
789char __init *creatorfb_init(struct fb_info_sbusfb *fb)
790{
791	struct fb_fix_screeninfo *fix = &fb->fix;
792	struct fb_var_screeninfo *var = &fb->var;
793	struct display *disp = &fb->disp;
794	struct fbtype *type = &fb->type;
795	struct linux_prom64_registers regs[2*PROMREG_MAX];
796	int i, afb = 0;
797	unsigned int btype;
798	char name[64];
799	struct fb_ops *fbops;
800
801	if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0)
802		return NULL;
803
804	if (creator_apply_upa_parent_ranges(fb->prom_parent, &regs[0]))
805		return NULL;
806
807	disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL);
808	if (disp->dispsw_data == NULL)
809		return NULL;
810	memset(disp->dispsw_data, 0, 16 * sizeof(u32));
811
812	fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
813	if (fbops == NULL) {
814		kfree(disp->dispsw_data);
815		return NULL;
816	}
817
818	*fbops = *fb->info.fbops;
819	fbops->fb_rasterimg = ffb_rasterimg;
820	fb->info.fbops = fbops;
821
822	prom_getstring(fb->prom_node, "name", name, sizeof(name));
823	if (!strcmp(name, "SUNW,afb"))
824		afb = 1;
825
826	btype = prom_getintdefault(fb->prom_node, "board_type", 0);
827
828	strcpy(fb->info.modename, "Creator");
829	if (!afb) {
830		if ((btype & 7) == 3)
831		    strcpy(fix->id, "Creator 3D");
832		else
833		    strcpy(fix->id, "Creator");
834	} else
835		strcpy(fix->id, "Elite 3D");
836
837	fix->visual = FB_VISUAL_TRUECOLOR;
838	fix->line_length = 8192;
839	fix->accel = FB_ACCEL_SUN_CREATOR;
840
841	var->bits_per_pixel = 32;
842	var->green.offset = 8;
843	var->blue.offset = 16;
844	var->accel_flags = FB_ACCELF_TEXT;
845
846	disp->scrollmode = SCROLL_YREDRAW;
847	disp->screen_base = (char *)__va(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin;
848	fb->s.ffb.xy_margin = (fb->y_margin << 16) + fb->x_margin;
849	fb->s.ffb.yx_margin = (((u64)fb->y_margin) << 32) + fb->x_margin;
850	fb->s.ffb.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
851	fb->s.ffb.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
852	fb->dispsw = ffb_dispsw;
853
854	fb->margins = ffb_margins;
855	fb->loadcmap = ffb_loadcmap;
856	fb->setcursor = ffb_setcursor;
857	fb->setcursormap = ffb_setcursormap;
858	fb->setcurshape = ffb_setcurshape;
859	fb->switch_from_graph = ffb_switch_from_graph;
860	fb->fill = ffb_fill;
861
862	/* If there are any read errors or fifo overflow conditions,
863	 * clear them now.
864	 */
865	if((upa_readl(&fb->s.ffb.fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
866		upa_writel(FFB_UCSR_ALL_ERRORS, &fb->s.ffb.fbc->ucsr);
867
868	ffb_switch_from_graph(fb);
869
870	fb->physbase = regs[0].phys_addr;
871	fb->mmap_map = ffb_mmap_map;
872
873	fb->cursor.hwsize.fbx = 64;
874	fb->cursor.hwsize.fby = 64;
875
876	type->fb_depth = 24;
877
878	upa_writel(0x8000, &fb->s.ffb.dac->type);
879	fb->s.ffb.dac_rev = (upa_readl(&fb->s.ffb.dac->value) >> 0x1c);
880
881	i = prom_getintdefault (fb->prom_node, "board_type", 8);
882
883	sprintf(idstring, "%s at %016lx type %d DAC %d",
884		fix->id, regs[0].phys_addr, i, fb->s.ffb.dac_rev);
885
886	/* Elite3D has different DAC revision numbering, and no DAC revisions
887	   have the reversed meaning of cursor enable */
888	if (afb)
889		fb->s.ffb.dac_rev = 10;
890
891	/* Unblank it just to be sure.  When there are multiple
892	 * FFB/AFB cards in the system, or it is not the OBP
893	 * chosen console, it will have video outputs off in
894	 * the DAC.
895	 */
896	ffb_unblank(fb);
897
898	return idstring;
899}
900
901MODULE_LICENSE("GPL");
902