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, ®s[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