]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/staging/xgifb/XGI_accel.c
staging: Add framebuffer driver for XGI chipsets
[net-next-2.6.git] / drivers / staging / xgifb / XGI_accel.c
1 /*
2  * XGI 300/630/730/540/315/550/650/740 frame buffer driver
3  * for Linux kernels 2.4.x and 2.5.x
4  *
5  * 2D acceleration part
6  *
7  * Based on the X driver's XGI300_accel.c which is
8  *     Copyright Xavier Ducoin <x.ducoin@lectra.com>
9  *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
10  * and XGI310_accel.c which is
11  *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
12  *
13  * Author: Thomas Winischhofer <thomas@winischhofer.net>
14  *                      (see http://www.winischhofer.net/
15  *                      for more information and updates)
16  */
17
18 //#include <linux/config.h>
19 #include <linux/version.h>
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/string.h>
24 #include <linux/mm.h>
25 #include <linux/tty.h>
26 #include <linux/slab.h>
27 #include <linux/delay.h>
28 #include <linux/fb.h>
29 #include <linux/console.h>
30 #include <linux/selection.h>
31 #include <linux/ioport.h>
32 #include <linux/init.h>
33 #include <linux/pci.h>
34 #include <linux/vt_kern.h>
35 #include <linux/capability.h>
36 #include <linux/fs.h>
37 #include <linux/agp_backend.h>
38
39 #include <linux/types.h>
40 /*
41 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
42 #include <linux/XGIfb.h>
43 #else
44 #include <video/XGIfb.h>
45 #endif
46 */
47 #include <asm/io.h>
48
49 #ifdef CONFIG_MTRR
50 #include <asm/mtrr.h>
51 #endif
52
53 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
54 #include <video/fbcon.h>
55 #include <video/fbcon-cfb8.h>
56 #include <video/fbcon-cfb16.h>
57 #include <video/fbcon-cfb24.h>
58 #include <video/fbcon-cfb32.h>
59 #endif
60
61 #include "osdef.h"
62 #include "vgatypes.h"
63 #include "vb_struct.h"
64 #include "XGIfb.h"
65 #include "XGI_accel.h"
66
67
68 extern struct     video_info xgi_video_info;
69 extern int XGIfb_accel;
70
71 static const int XGIALUConv[] =
72 {
73     0x00,       /* dest = 0;            0,      GXclear,        0 */
74     0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
75     0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
76     0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
77     0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
78     0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
79     0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
80     0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
81     0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
82     0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
83     0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
84     0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
85     0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
86     0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
87     0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
88     0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
89 };
90 /* same ROP but with Pattern as Source */
91 static const int XGIPatALUConv[] =
92 {
93     0x00,       /* dest = 0;            0,      GXclear,        0 */
94     0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
95     0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
96     0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
97     0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
98     0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
99     0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
100     0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
101     0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
102     0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
103     0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
104     0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
105     0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
106     0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
107     0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
108     0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
109 };
110
111 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
112 static const unsigned char myrops[] = {
113         3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
114    };
115 #endif
116
117 /* 300 series */
118 #if 0
119 static void
120 XGI300Sync(void)
121 {
122         XGI300Idle
123 }
124 #endif
125 static void
126 XGI310Sync(void)
127 {
128         XGI310Idle
129 }
130 #if 0
131 static void
132 XGI300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
133                                 unsigned int planemask, int trans_color)
134 {
135         XGI300SetupDSTColorDepth(xgi_video_info.DstColor);
136         XGI300SetupSRCPitch(xgi_video_info.video_linelength)
137         XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
138
139         if(trans_color != -1) {
140                 XGI300SetupROP(0x0A)
141                 XGI300SetupSRCTrans(trans_color)
142                 XGI300SetupCMDFlag(TRANSPARENT_BITBLT)
143         } else {
144                 XGI300SetupROP(XGIALUConv[rop])
145         }
146         if(xdir > 0) {
147                 XGI300SetupCMDFlag(X_INC)
148         }
149         if(ydir > 0) {
150                 XGI300SetupCMDFlag(Y_INC)
151         }
152 }
153
154 static void
155 XGI300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
156                                 int width, int height)
157 {
158         long srcbase, dstbase;
159
160         srcbase = dstbase = 0;
161         if (src_y >= 2048) {
162                 srcbase = xgi_video_info.video_linelength * src_y;
163                 src_y = 0;
164         }
165         if (dst_y >= 2048) {
166                 dstbase = xgi_video_info.video_linelength * dst_y;
167                 dst_y = 0;
168         }
169
170         XGI300SetupSRCBase(srcbase);
171         XGI300SetupDSTBase(dstbase);
172
173         if(!(xgi_video_info.CommandReg & X_INC))  {
174                 src_x += width-1;
175                 dst_x += width-1;
176         }
177         if(!(xgi_video_info.CommandReg & Y_INC))  {
178                 src_y += height-1;
179                 dst_y += height-1;
180         }
181         XGI300SetupRect(width, height)
182         XGI300SetupSRCXY(src_x, src_y)
183         XGI300SetupDSTXY(dst_x, dst_y)
184         XGI300DoCMD
185 }
186
187 static void
188 XGI300SetupForSolidFill(int color, int rop, unsigned int planemask)
189 {
190         XGI300SetupPATFG(color)
191         XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
192         XGI300SetupDSTColorDepth(xgi_video_info.DstColor);
193         XGI300SetupROP(XGIPatALUConv[rop])
194         XGI300SetupCMDFlag(PATFG)
195 }
196
197 static void
198 XGI300SubsequentSolidFillRect(int x, int y, int w, int h)
199 {
200         long dstbase;
201
202         dstbase = 0;
203         if(y >= 2048) {
204                 dstbase = xgi_video_info.video_linelength * y;
205                 y = 0;
206         }
207         XGI300SetupDSTBase(dstbase)
208         XGI300SetupDSTXY(x,y)
209         XGI300SetupRect(w,h)
210         XGI300SetupCMDFlag(X_INC | Y_INC | BITBLT)
211         XGI300DoCMD
212 }
213 #endif
214 /* 310/325 series ------------------------------------------------ */
215
216 static void
217 XGI310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
218                                 unsigned int planemask, int trans_color)
219 {
220         XGI310SetupDSTColorDepth(xgi_video_info.DstColor);
221         XGI310SetupSRCPitch(xgi_video_info.video_linelength)
222         XGI310SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
223         if (trans_color != -1) {
224                 XGI310SetupROP(0x0A)
225                 XGI310SetupSRCTrans(trans_color)
226                 XGI310SetupCMDFlag(TRANSPARENT_BITBLT)
227         } else {
228                 XGI310SetupROP(XGIALUConv[rop])
229                 /* Set command - not needed, both 0 */
230                 /* XGISetupCMDFlag(BITBLT | SRCVIDEO) */
231         }
232         XGI310SetupCMDFlag(xgi_video_info.XGI310_AccelDepth)
233         /* TW: The 310/325 series is smart enough to know the direction */
234 }
235
236 static void
237 XGI310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
238                                 int width, int height)
239 {
240         long srcbase, dstbase;
241         int mymin, mymax;
242
243         srcbase = dstbase = 0;
244         mymin = min(src_y, dst_y);
245         mymax = max(src_y, dst_y);
246
247         /* Although the chip knows the direction to use
248          * if the source and destination areas overlap,
249          * that logic fails if we fiddle with the bitmap
250          * addresses. Therefore, we check if the source
251          * and destination blitting areas overlap and
252          * adapt the bitmap addresses synchronously
253          * if the coordinates exceed the valid range.
254          * The the areas do not overlap, we do our
255          * normal check.
256          */
257         if((mymax - mymin) < height) {
258            if((src_y >= 2048) || (dst_y >= 2048)) {
259               srcbase = xgi_video_info.video_linelength * mymin;
260               dstbase = xgi_video_info.video_linelength * mymin;
261               src_y -= mymin;
262               dst_y -= mymin;
263            }
264         } else {
265            if(src_y >= 2048) {
266               srcbase = xgi_video_info.video_linelength * src_y;
267               src_y = 0;
268            }
269            if(dst_y >= 2048) {
270               dstbase = xgi_video_info.video_linelength * dst_y;
271               dst_y = 0;
272            }
273         }
274
275         XGI310SetupSRCBase(srcbase);
276         XGI310SetupDSTBase(dstbase);
277         XGI310SetupRect(width, height)
278         XGI310SetupSRCXY(src_x, src_y)
279         XGI310SetupDSTXY(dst_x, dst_y)
280         XGI310DoCMD
281 }
282
283 static void
284 XGI310SetupForSolidFill(int color, int rop, unsigned int planemask)
285 {
286         XGI310SetupPATFG(color)
287         XGI310SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
288         XGI310SetupDSTColorDepth(xgi_video_info.DstColor);
289         XGI310SetupROP(XGIPatALUConv[rop])
290         XGI310SetupCMDFlag(PATFG | xgi_video_info.XGI310_AccelDepth)
291 }
292
293 static void
294 XGI310SubsequentSolidFillRect(int x, int y, int w, int h)
295 {
296         long dstbase;
297
298         dstbase = 0;
299         if(y >= 2048) {
300                 dstbase = xgi_video_info.video_linelength * y;
301                 y = 0;
302         }
303         XGI310SetupDSTBase(dstbase)
304         XGI310SetupDSTXY(x,y)
305         XGI310SetupRect(w,h)
306         XGI310SetupCMDFlag(BITBLT)
307         XGI310DoCMD
308 }
309
310 /* --------------------------------------------------------------------- */
311
312 /* The exported routines */
313
314 int XGIfb_initaccel(void)
315 {
316 #ifdef XGIFB_USE_SPINLOCKS
317     spin_lock_init(&xgi_video_info.lockaccel);
318 #endif
319     return(0);
320 }
321
322 void XGIfb_syncaccel(void)
323 {
324
325     XGI310Sync();
326
327 }
328
329 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)  /* --- KERNEL 2.5.34 and later --- */
330
331 int fbcon_XGI_sync(struct fb_info *info)
332 {
333     if(!XGIfb_accel) return 0;
334     CRITFLAGS
335
336     XGI310Sync();
337
338    CRITEND
339    return 0;
340 }
341
342 void fbcon_XGI_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
343 {
344    int col=0;
345    CRITFLAGS
346
347
348    if(!rect->width || !rect->height)
349         return;
350
351    if(!XGIfb_accel) {
352         cfb_fillrect(info, rect);
353         return;
354    }
355
356    switch(info->var.bits_per_pixel) {
357                 case 8: col = rect->color;
358                         break;
359                 case 16: col = ((u32 *)(info->pseudo_palette))[rect->color];
360                          break;
361                 case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
362                          break;
363         }
364
365
366            CRITBEGIN
367            XGI310SetupForSolidFill(col, myrops[rect->rop], 0);
368            XGI310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
369            CRITEND
370            XGI310Sync();
371
372
373 }
374
375 void fbcon_XGI_copyarea(struct fb_info *info, const struct fb_copyarea *area)
376 {
377    int xdir, ydir;
378    CRITFLAGS
379
380
381    if(!XGIfb_accel) {
382         cfb_copyarea(info, area);
383         return;
384    }
385
386    if(!area->width || !area->height)
387         return;
388
389    if(area->sx < area->dx) xdir = 0;
390    else                    xdir = 1;
391    if(area->sy < area->dy) ydir = 0;
392    else                    ydir = 1;
393
394       CRITBEGIN
395       XGI310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
396       XGI310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
397       CRITEND
398       XGI310Sync();
399
400 }
401
402 #endif
403
404 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)  /* ------ KERNEL <2.5.34 ------ */
405
406 void fbcon_XGI_bmove(struct display *p, int srcy, int srcx,
407                             int dsty, int dstx, int height, int width)
408 {
409         int xdir, ydir;
410         CRITFLAGS
411
412         if(!xgi_video_info.accel) {
413             switch(xgi_video_info.video_bpp) {
414             case 8:
415 #ifdef FBCON_HAS_CFB8
416                fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
417 #endif
418                break;
419             case 16:
420 #ifdef FBCON_HAS_CFB16
421                fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width);
422 #endif
423                break;
424             case 32:
425 #ifdef FBCON_HAS_CFB32
426                fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width);
427 #endif
428                break;
429             }
430             return;
431         }
432
433         srcx *= fontwidth(p);
434         srcy *= fontheight(p);
435         dstx *= fontwidth(p);
436         dsty *= fontheight(p);
437         width *= fontwidth(p);
438         height *= fontheight(p);
439
440         if(srcx < dstx) xdir = 0;
441         else            xdir = 1;
442         if(srcy < dsty) ydir = 0;
443         else            ydir = 1;
444
445
446            CRITBEGIN
447            XGI310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
448            XGI310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
449            CRITEND
450            XGI310Sync();
451 #if 0
452            printk(KERN_INFO "XGI_bmove sx %d sy %d dx %d dy %d w %d h %d\n",
453                 srcx, srcy, dstx, dsty, width, height);
454 #endif
455
456 }
457
458
459 static void fbcon_XGI_clear(struct vc_data *conp, struct display *p,
460                         int srcy, int srcx, int height, int width, int color)
461 {
462         CRITFLAGS
463
464         srcx *= fontwidth(p);
465         srcy *= fontheight(p);
466         width *= fontwidth(p);
467         height *= fontheight(p);
468
469
470            CRITBEGIN
471            XGI310SetupForSolidFill(color, 3, 0);
472            XGI310SubsequentSolidFillRect(srcx, srcy, width, height);
473            CRITEND
474            XGI310Sync();
475
476 }
477
478 void fbcon_XGI_clear8(struct vc_data *conp, struct display *p,
479                         int srcy, int srcx, int height, int width)
480 {
481         u32 bgx;
482
483         if(!xgi_video_info.accel) {
484 #ifdef FBCON_HAS_CFB8
485             fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
486 #endif
487             return;
488         }
489
490         bgx = attr_bgcol_ec(p, conp);
491         fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
492 }
493
494 void fbcon_XGI_clear16(struct vc_data *conp, struct display *p,
495                         int srcy, int srcx, int height, int width)
496 {
497         u32 bgx;
498         if(!xgi_video_info.accel) {
499 #ifdef FBCON_HAS_CFB16
500             fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
501 #endif
502             return;
503         }
504
505         bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
506         fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
507 }
508
509 void fbcon_XGI_clear32(struct vc_data *conp, struct display *p,
510                         int srcy, int srcx, int height, int width)
511 {
512         u32 bgx;
513
514         if(!xgi_video_info.accel) {
515 #ifdef FBCON_HAS_CFB32
516             fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
517 #endif
518             return;
519         }
520
521         bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
522         fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
523 }
524
525 void fbcon_XGI_revc(struct display *p, int srcx, int srcy)
526 {
527         CRITFLAGS
528
529         if(!xgi_video_info.accel) {
530             switch(xgi_video_info.video_bpp) {
531             case 16:
532 #ifdef FBCON_HAS_CFB16
533                fbcon_cfb16_revc(p, srcx, srcy);
534 #endif
535                break;
536             case 32:
537 #ifdef FBCON_HAS_CFB32
538                fbcon_cfb32_revc(p, srcx, srcy);
539 #endif
540                break;
541             }
542             return;
543         }
544
545         srcx *= fontwidth(p);
546         srcy *= fontheight(p);
547
548
549            CRITBEGIN
550            XGI310SetupForSolidFill(0, 0x0a, 0);
551            XGI310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
552            CRITEND
553            XGI310Sync();
554
555 }
556
557 #ifdef FBCON_HAS_CFB8
558 struct display_switch fbcon_XGI8 = {
559         setup:                  fbcon_cfb8_setup,
560         bmove:                  fbcon_XGI_bmove,
561         clear:                  fbcon_XGI_clear8,
562         putc:                   fbcon_cfb8_putc,
563         putcs:                  fbcon_cfb8_putcs,
564         revc:                   fbcon_cfb8_revc,
565         clear_margins:          fbcon_cfb8_clear_margins,
566         fontwidthmask:          FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
567 };
568 #endif
569 #ifdef FBCON_HAS_CFB16
570 struct display_switch fbcon_XGI16 = {
571         setup:                  fbcon_cfb16_setup,
572         bmove:                  fbcon_XGI_bmove,
573         clear:                  fbcon_XGI_clear16,
574         putc:                   fbcon_cfb16_putc,
575         putcs:                  fbcon_cfb16_putcs,
576         revc:                   fbcon_XGI_revc,
577         clear_margins:          fbcon_cfb16_clear_margins,
578         fontwidthmask:          FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
579 };
580 #endif
581 #ifdef FBCON_HAS_CFB32
582 struct display_switch fbcon_XGI32 = {
583         setup:                  fbcon_cfb32_setup,
584         bmove:                  fbcon_XGI_bmove,
585         clear:                  fbcon_XGI_clear32,
586         putc:                   fbcon_cfb32_putc,
587         putcs:                  fbcon_cfb32_putcs,
588         revc:                   fbcon_XGI_revc,
589         clear_margins:          fbcon_cfb32_clear_margins,
590         fontwidthmask:          FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
591 };
592 #endif
593
594 #endif /* KERNEL VERSION */
595
596