2 * SiS 300/630/730/540/315/550/65x/74x/330/760 frame buffer driver
3 * for Linux kernels 2.4.x and 2.6.x
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the named License,
10 * or any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
21 * Based on the XFree86 driver's sis300_accel.c which is
22 * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
23 * and sis310_accel.c which is
24 * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
26 * Author: Thomas Winischhofer <thomas@winischhofer.net>
27 * (see http://www.winischhofer.net/
28 * for more information and updates)
31 #include <linux/config.h>
32 #include <linux/version.h>
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/errno.h>
36 #include <linux/string.h>
38 #include <linux/tty.h>
39 #include <linux/slab.h>
40 #include <linux/delay.h>
42 #include <linux/console.h>
43 #include <linux/selection.h>
44 #include <linux/ioport.h>
45 #include <linux/init.h>
46 #include <linux/pci.h>
47 #include <linux/vt_kern.h>
48 #include <linux/capability.h>
50 #include <linux/agp_backend.h>
52 #include <linux/types.h>
54 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
55 #include <linux/sisfb.h>
57 #include <video/sisfb.h>
66 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
67 #include <video/fbcon.h>
68 #include <video/fbcon-cfb8.h>
69 #include <video/fbcon-cfb16.h>
70 #include <video/fbcon-cfb24.h>
71 #include <video/fbcon-cfb32.h>
77 #include "sis_accel.h"
80 extern struct video_info ivideo;
81 extern VGA_ENGINE sisvga_engine;
82 extern int sisfb_accel;
84 static const int sisALUConv[] =
86 0x00, /* dest = 0; 0, GXclear, 0 */
87 0x88, /* dest &= src; DSa, GXand, 0x1 */
88 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */
89 0xCC, /* dest = src; S, GXcopy, 0x3 */
90 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */
91 0xAA, /* dest = dest; D, GXnoop, 0x5 */
92 0x66, /* dest = ^src; DSx, GXxor, 0x6 */
93 0xEE, /* dest |= src; DSo, GXor, 0x7 */
94 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */
95 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */
96 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
97 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */
98 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */
99 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */
100 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */
101 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
103 /* same ROP but with Pattern as Source */
104 static const int sisPatALUConv[] =
106 0x00, /* dest = 0; 0, GXclear, 0 */
107 0xA0, /* dest &= src; DPa, GXand, 0x1 */
108 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */
109 0xF0, /* dest = src; P, GXcopy, 0x3 */
110 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */
111 0xAA, /* dest = dest; D, GXnoop, 0x5 */
112 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */
113 0xFA, /* dest |= src; DPo, GXor, 0x7 */
114 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */
115 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */
116 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
117 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */
118 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */
119 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */
120 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */
121 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
124 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
125 static const unsigned char myrops[] = {
126 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
130 /* 300 series ----------------------------------------------------- */
131 #ifdef CONFIG_FB_SIS_300
139 SiS300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
140 unsigned int planemask, int trans_color)
142 SiS300SetupDSTColorDepth(ivideo.DstColor);
143 SiS300SetupSRCPitch(ivideo.video_linelength)
144 SiS300SetupDSTRect(ivideo.video_linelength, -1)
146 if(trans_color != -1) {
148 SiS300SetupSRCTrans(trans_color)
149 SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
151 SiS300SetupROP(sisALUConv[rop])
154 SiS300SetupCMDFlag(X_INC)
157 SiS300SetupCMDFlag(Y_INC)
162 SiS300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
163 int width, int height)
165 long srcbase, dstbase;
167 srcbase = dstbase = 0;
169 srcbase = ivideo.video_linelength * src_y;
173 dstbase = ivideo.video_linelength * dst_y;
177 SiS300SetupSRCBase(srcbase);
178 SiS300SetupDSTBase(dstbase);
180 if(!(ivideo.CommandReg & X_INC)) {
184 if(!(ivideo.CommandReg & Y_INC)) {
188 SiS300SetupRect(width, height)
189 SiS300SetupSRCXY(src_x, src_y)
190 SiS300SetupDSTXY(dst_x, dst_y)
195 SiS300SetupForSolidFill(int color, int rop, unsigned int planemask)
197 SiS300SetupPATFG(color)
198 SiS300SetupDSTRect(ivideo.video_linelength, -1)
199 SiS300SetupDSTColorDepth(ivideo.DstColor);
200 SiS300SetupROP(sisPatALUConv[rop])
201 SiS300SetupCMDFlag(PATFG)
205 SiS300SubsequentSolidFillRect(int x, int y, int w, int h)
211 dstbase = ivideo.video_linelength * y;
214 SiS300SetupDSTBase(dstbase)
215 SiS300SetupDSTXY(x,y)
217 SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
222 /* 315/330 series ------------------------------------------------- */
224 #ifdef CONFIG_FB_SIS_315
232 SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
233 unsigned int planemask, int trans_color)
235 SiS310SetupDSTColorDepth(ivideo.DstColor);
236 SiS310SetupSRCPitch(ivideo.video_linelength)
237 SiS310SetupDSTRect(ivideo.video_linelength, -1)
238 if (trans_color != -1) {
240 SiS310SetupSRCTrans(trans_color)
241 SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
243 SiS310SetupROP(sisALUConv[rop])
244 /* Set command - not needed, both 0 */
245 /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
247 SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
248 /* The 315 series is smart enough to know the direction */
252 SiS310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
253 int width, int height)
255 long srcbase, dstbase;
258 srcbase = dstbase = 0;
259 mymin = min(src_y, dst_y);
260 mymax = max(src_y, dst_y);
262 /* Although the chip knows the direction to use
263 * if the source and destination areas overlap,
264 * that logic fails if we fiddle with the bitmap
265 * addresses. Therefore, we check if the source
266 * and destination blitting areas overlap and
267 * adapt the bitmap addresses synchronously
268 * if the coordinates exceed the valid range.
269 * The the areas do not overlap, we do our
272 if((mymax - mymin) < height) {
273 if((src_y >= 2048) || (dst_y >= 2048)) {
274 srcbase = ivideo.video_linelength * mymin;
275 dstbase = ivideo.video_linelength * mymin;
281 srcbase = ivideo.video_linelength * src_y;
285 dstbase = ivideo.video_linelength * dst_y;
290 SiS310SetupSRCBase(srcbase);
291 SiS310SetupDSTBase(dstbase);
292 SiS310SetupRect(width, height)
293 SiS310SetupSRCXY(src_x, src_y)
294 SiS310SetupDSTXY(dst_x, dst_y)
299 SiS310SetupForSolidFill(int color, int rop, unsigned int planemask)
301 SiS310SetupPATFG(color)
302 SiS310SetupDSTRect(ivideo.video_linelength, -1)
303 SiS310SetupDSTColorDepth(ivideo.DstColor);
304 SiS310SetupROP(sisPatALUConv[rop])
305 SiS310SetupCMDFlag(PATFG | ivideo.SiS310_AccelDepth)
309 SiS310SubsequentSolidFillRect(int x, int y, int w, int h)
315 dstbase = ivideo.video_linelength * y;
318 SiS310SetupDSTBase(dstbase)
319 SiS310SetupDSTXY(x,y)
321 SiS310SetupCMDFlag(BITBLT)
326 /* --------------------------------------------------------------------- */
328 /* The exported routines */
330 int sisfb_initaccel(void)
332 #ifdef SISFB_USE_SPINLOCKS
333 spin_lock_init(&ivideo.lockaccel);
338 void sisfb_syncaccel(void)
340 if(sisvga_engine == SIS_300_VGA) {
341 #ifdef CONFIG_FB_SIS_300
345 #ifdef CONFIG_FB_SIS_315
351 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* --------------- 2.5 --------------- */
353 int fbcon_sis_sync(struct fb_info *info)
360 if(sisvga_engine == SIS_300_VGA) {
361 #ifdef CONFIG_FB_SIS_300
365 #ifdef CONFIG_FB_SIS_315
373 void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
378 TWDEBUG("Inside sis_fillrect");
379 if(!rect->width || !rect->height)
383 cfb_fillrect(info, rect);
387 switch(info->var.bits_per_pixel) {
388 case 8: col = rect->color;
390 case 16: col = ((u32 *)(info->pseudo_palette))[rect->color];
392 case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
396 if(sisvga_engine == SIS_300_VGA) {
397 #ifdef CONFIG_FB_SIS_300
399 SiS300SetupForSolidFill(col, myrops[rect->rop], 0);
400 SiS300SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
405 #ifdef CONFIG_FB_SIS_315
407 SiS310SetupForSolidFill(col, myrops[rect->rop], 0);
408 SiS310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
416 void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
421 TWDEBUG("Inside sis_copyarea");
423 cfb_copyarea(info, area);
427 if(!area->width || !area->height)
430 if(area->sx < area->dx) xdir = 0;
432 if(area->sy < area->dy) ydir = 0;
435 if(sisvga_engine == SIS_300_VGA) {
436 #ifdef CONFIG_FB_SIS_300
438 SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
439 SiS300SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
444 #ifdef CONFIG_FB_SIS_315
446 SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
447 SiS310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
456 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* -------------- 2.4 --------------- */
458 void fbcon_sis_bmove(struct display *p, int srcy, int srcx,
459 int dsty, int dstx, int height, int width)
465 switch(ivideo.video_bpp) {
467 #ifdef FBCON_HAS_CFB8
468 fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
472 #ifdef FBCON_HAS_CFB16
473 fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width);
477 #ifdef FBCON_HAS_CFB32
478 fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width);
485 srcx *= fontwidth(p);
486 srcy *= fontheight(p);
487 dstx *= fontwidth(p);
488 dsty *= fontheight(p);
489 width *= fontwidth(p);
490 height *= fontheight(p);
492 if(srcx < dstx) xdir = 0;
494 if(srcy < dsty) ydir = 0;
497 if(sisvga_engine == SIS_300_VGA) {
498 #ifdef CONFIG_FB_SIS_300
500 SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
501 SiS300SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
506 #ifdef CONFIG_FB_SIS_315
508 SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
509 SiS310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
513 printk(KERN_INFO "sis_bmove sx %d sy %d dx %d dy %d w %d h %d\n",
514 srcx, srcy, dstx, dsty, width, height);
520 static void fbcon_sis_clear(struct vc_data *conp, struct display *p,
521 int srcy, int srcx, int height, int width, int color)
525 srcx *= fontwidth(p);
526 srcy *= fontheight(p);
527 width *= fontwidth(p);
528 height *= fontheight(p);
530 if(sisvga_engine == SIS_300_VGA) {
531 #ifdef CONFIG_FB_SIS_300
533 SiS300SetupForSolidFill(color, 3, 0);
534 SiS300SubsequentSolidFillRect(srcx, srcy, width, height);
539 #ifdef CONFIG_FB_SIS_315
541 SiS310SetupForSolidFill(color, 3, 0);
542 SiS310SubsequentSolidFillRect(srcx, srcy, width, height);
549 void fbcon_sis_clear8(struct vc_data *conp, struct display *p,
550 int srcy, int srcx, int height, int width)
555 #ifdef FBCON_HAS_CFB8
556 fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
561 bgx = attr_bgcol_ec(p, conp);
562 fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
565 void fbcon_sis_clear16(struct vc_data *conp, struct display *p,
566 int srcy, int srcx, int height, int width)
570 #ifdef FBCON_HAS_CFB16
571 fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
576 bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
577 fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
580 void fbcon_sis_clear32(struct vc_data *conp, struct display *p,
581 int srcy, int srcx, int height, int width)
586 #ifdef FBCON_HAS_CFB32
587 fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
592 bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
593 fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
596 void fbcon_sis_revc(struct display *p, int srcx, int srcy)
601 switch(ivideo.video_bpp) {
603 #ifdef FBCON_HAS_CFB16
604 fbcon_cfb16_revc(p, srcx, srcy);
608 #ifdef FBCON_HAS_CFB32
609 fbcon_cfb32_revc(p, srcx, srcy);
616 srcx *= fontwidth(p);
617 srcy *= fontheight(p);
619 if(sisvga_engine == SIS_300_VGA) {
620 #ifdef CONFIG_FB_SIS_300
622 SiS300SetupForSolidFill(0, 0x0a, 0);
623 SiS300SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
628 #ifdef CONFIG_FB_SIS_315
630 SiS310SetupForSolidFill(0, 0x0a, 0);
631 SiS310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
638 #ifdef FBCON_HAS_CFB8
639 struct display_switch fbcon_sis8 = {
640 .setup = fbcon_cfb8_setup,
641 .bmove = fbcon_sis_bmove,
642 .clear = fbcon_sis_clear8,
643 .putc = fbcon_cfb8_putc,
644 .putcs = fbcon_cfb8_putcs,
645 .revc = fbcon_cfb8_revc,
646 .clear_margins = fbcon_cfb8_clear_margins,
647 .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
650 #ifdef FBCON_HAS_CFB16
651 struct display_switch fbcon_sis16 = {
652 .setup = fbcon_cfb16_setup,
653 .bmove = fbcon_sis_bmove,
654 .clear = fbcon_sis_clear16,
655 .putc = fbcon_cfb16_putc,
656 .putcs = fbcon_cfb16_putcs,
657 .revc = fbcon_sis_revc,
658 .clear_margins = fbcon_cfb16_clear_margins,
659 .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
662 #ifdef FBCON_HAS_CFB32
663 struct display_switch fbcon_sis32 = {
664 .setup = fbcon_cfb32_setup,
665 .bmove = fbcon_sis_bmove,
666 .clear = fbcon_sis_clear32,
667 .putc = fbcon_cfb32_putc,
668 .putcs = fbcon_cfb32_putcs,
669 .revc = fbcon_sis_revc,
670 .clear_margins = fbcon_cfb32_clear_margins,
671 .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
675 #endif /* KERNEL VERSION */