2 * SiS 300/540/630[S]/730[S],
3 * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX],
5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the named License,
12 * or any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
23 * Based on the XFree86/X.org driver which is
24 * Copyright (C) 2001-2005 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/module.h>
32 #include <linux/kernel.h>
34 #include <linux/ioport.h>
35 #include <linux/types.h>
39 #include "sis_accel.h"
41 static const u8 sisALUConv
[] =
43 0x00, /* dest = 0; 0, GXclear, 0 */
44 0x88, /* dest &= src; DSa, GXand, 0x1 */
45 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */
46 0xCC, /* dest = src; S, GXcopy, 0x3 */
47 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */
48 0xAA, /* dest = dest; D, GXnoop, 0x5 */
49 0x66, /* dest = ^src; DSx, GXxor, 0x6 */
50 0xEE, /* dest |= src; DSo, GXor, 0x7 */
51 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */
52 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */
53 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
54 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */
55 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */
56 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */
57 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */
58 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
60 /* same ROP but with Pattern as Source */
61 static const u8 sisPatALUConv
[] =
63 0x00, /* dest = 0; 0, GXclear, 0 */
64 0xA0, /* dest &= src; DPa, GXand, 0x1 */
65 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */
66 0xF0, /* dest = src; P, GXcopy, 0x3 */
67 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */
68 0xAA, /* dest = dest; D, GXnoop, 0x5 */
69 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */
70 0xFA, /* dest |= src; DPo, GXor, 0x7 */
71 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */
72 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */
73 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
74 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */
75 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */
76 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */
77 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */
78 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
81 static const int myrops
[] = {
82 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
85 /* 300 series ----------------------------------------------------- */
86 #ifdef CONFIG_FB_SIS_300
88 SiS300Sync(struct sis_video_info
*ivideo
)
94 SiS300SetupForScreenToScreenCopy(struct sis_video_info
*ivideo
, int xdir
, int ydir
,
95 int rop
, int trans_color
)
97 SiS300SetupDSTColorDepth(ivideo
->DstColor
);
98 SiS300SetupSRCPitch(ivideo
->video_linelength
)
99 SiS300SetupDSTRect(ivideo
->video_linelength
, 0xffff)
101 if(trans_color
!= -1) {
103 SiS300SetupSRCTrans(trans_color
)
104 SiS300SetupCMDFlag(TRANSPARENT_BITBLT
)
106 SiS300SetupROP(sisALUConv
[rop
])
109 SiS300SetupCMDFlag(X_INC
)
112 SiS300SetupCMDFlag(Y_INC
)
117 SiS300SubsequentScreenToScreenCopy(struct sis_video_info
*ivideo
, int src_x
,
118 int src_y
, int dst_x
, int dst_y
, int width
, int height
)
120 u32 srcbase
= 0, dstbase
= 0;
123 srcbase
= ivideo
->video_linelength
* src_y
;
127 dstbase
= ivideo
->video_linelength
* dst_y
;
131 SiS300SetupSRCBase(srcbase
);
132 SiS300SetupDSTBase(dstbase
);
134 if(!(ivideo
->CommandReg
& X_INC
)) {
138 if(!(ivideo
->CommandReg
& Y_INC
)) {
142 SiS300SetupRect(width
, height
)
143 SiS300SetupSRCXY(src_x
, src_y
)
144 SiS300SetupDSTXY(dst_x
, dst_y
)
149 SiS300SetupForSolidFill(struct sis_video_info
*ivideo
, u32 color
, int rop
)
151 SiS300SetupPATFG(color
)
152 SiS300SetupDSTRect(ivideo
->video_linelength
, 0xffff)
153 SiS300SetupDSTColorDepth(ivideo
->DstColor
);
154 SiS300SetupROP(sisPatALUConv
[rop
])
155 SiS300SetupCMDFlag(PATFG
)
159 SiS300SubsequentSolidFillRect(struct sis_video_info
*ivideo
, int x
, int y
, int w
, int h
)
164 dstbase
= ivideo
->video_linelength
* y
;
167 SiS300SetupDSTBase(dstbase
)
168 SiS300SetupDSTXY(x
,y
)
170 SiS300SetupCMDFlag(X_INC
| Y_INC
| BITBLT
)
175 /* 315/330/340 series ---------------------------------------------- */
177 #ifdef CONFIG_FB_SIS_315
179 SiS310Sync(struct sis_video_info
*ivideo
)
185 SiS310SetupForScreenToScreenCopy(struct sis_video_info
*ivideo
, int rop
, int trans_color
)
187 SiS310SetupDSTColorDepth(ivideo
->DstColor
);
188 SiS310SetupSRCPitch(ivideo
->video_linelength
)
189 SiS310SetupDSTRect(ivideo
->video_linelength
, 0x0fff)
190 if(trans_color
!= -1) {
192 SiS310SetupSRCTrans(trans_color
)
193 SiS310SetupCMDFlag(TRANSPARENT_BITBLT
)
195 SiS310SetupROP(sisALUConv
[rop
])
196 /* Set command - not needed, both 0 */
197 /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
199 SiS310SetupCMDFlag(ivideo
->SiS310_AccelDepth
)
200 /* The chip is smart enough to know the direction */
204 SiS310SubsequentScreenToScreenCopy(struct sis_video_info
*ivideo
, int src_x
, int src_y
,
205 int dst_x
, int dst_y
, int width
, int height
)
207 u32 srcbase
= 0, dstbase
= 0;
208 int mymin
= min(src_y
, dst_y
);
209 int mymax
= max(src_y
, dst_y
);
211 /* Although the chip knows the direction to use
212 * if the source and destination areas overlap,
213 * that logic fails if we fiddle with the bitmap
214 * addresses. Therefore, we check if the source
215 * and destination blitting areas overlap and
216 * adapt the bitmap addresses synchronously
217 * if the coordinates exceed the valid range.
218 * The the areas do not overlap, we do our
221 if((mymax
- mymin
) < height
) {
222 if((src_y
>= 2048) || (dst_y
>= 2048)) {
223 srcbase
= ivideo
->video_linelength
* mymin
;
224 dstbase
= ivideo
->video_linelength
* mymin
;
230 srcbase
= ivideo
->video_linelength
* src_y
;
234 dstbase
= ivideo
->video_linelength
* dst_y
;
239 srcbase
+= ivideo
->video_offset
;
240 dstbase
+= ivideo
->video_offset
;
242 SiS310SetupSRCBase(srcbase
);
243 SiS310SetupDSTBase(dstbase
);
244 SiS310SetupRect(width
, height
)
245 SiS310SetupSRCXY(src_x
, src_y
)
246 SiS310SetupDSTXY(dst_x
, dst_y
)
251 SiS310SetupForSolidFill(struct sis_video_info
*ivideo
, u32 color
, int rop
)
253 SiS310SetupPATFG(color
)
254 SiS310SetupDSTRect(ivideo
->video_linelength
, 0x0fff)
255 SiS310SetupDSTColorDepth(ivideo
->DstColor
);
256 SiS310SetupROP(sisPatALUConv
[rop
])
257 SiS310SetupCMDFlag(PATFG
| ivideo
->SiS310_AccelDepth
)
261 SiS310SubsequentSolidFillRect(struct sis_video_info
*ivideo
, int x
, int y
, int w
, int h
)
266 dstbase
= ivideo
->video_linelength
* y
;
269 dstbase
+= ivideo
->video_offset
;
270 SiS310SetupDSTBase(dstbase
)
271 SiS310SetupDSTXY(x
,y
)
273 SiS310SetupCMDFlag(BITBLT
)
278 /* --------------------------------------------------------------------- */
280 /* The exported routines */
282 int sisfb_initaccel(struct sis_video_info
*ivideo
)
284 #ifdef SISFB_USE_SPINLOCKS
285 spin_lock_init(&ivideo
->lockaccel
);
290 void sisfb_syncaccel(struct sis_video_info
*ivideo
)
292 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
293 #ifdef CONFIG_FB_SIS_300
297 #ifdef CONFIG_FB_SIS_315
303 int fbcon_sis_sync(struct fb_info
*info
)
305 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
308 if((!ivideo
->accel
) || (!ivideo
->engineok
))
312 sisfb_syncaccel(ivideo
);
318 void fbcon_sis_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
320 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
322 u32 vxres
= info
->var
.xres_virtual
;
323 u32 vyres
= info
->var
.yres_virtual
;
327 if(info
->state
!= FBINFO_STATE_RUNNING
)
330 if((!ivideo
->accel
) || (!ivideo
->engineok
)) {
331 cfb_fillrect(info
, rect
);
335 if(!rect
->width
|| !rect
->height
|| rect
->dx
>= vxres
|| rect
->dy
>= vyres
)
339 width
= ((rect
->dx
+ rect
->width
) > vxres
) ? (vxres
- rect
->dx
) : rect
->width
;
340 height
= ((rect
->dy
+ rect
->height
) > vyres
) ? (vyres
- rect
->dy
) : rect
->height
;
342 switch(info
->var
.bits_per_pixel
) {
343 case 8: col
= rect
->color
;
346 case 32: col
= ((u32
*)(info
->pseudo_palette
))[rect
->color
];
350 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
351 #ifdef CONFIG_FB_SIS_300
353 SiS300SetupForSolidFill(ivideo
, col
, myrops
[rect
->rop
]);
354 SiS300SubsequentSolidFillRect(ivideo
, rect
->dx
, rect
->dy
, width
, height
);
358 #ifdef CONFIG_FB_SIS_315
360 SiS310SetupForSolidFill(ivideo
, col
, myrops
[rect
->rop
]);
361 SiS310SubsequentSolidFillRect(ivideo
, rect
->dx
, rect
->dy
, width
, height
);
366 sisfb_syncaccel(ivideo
);
369 void fbcon_sis_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
371 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
372 u32 vxres
= info
->var
.xres_virtual
;
373 u32 vyres
= info
->var
.yres_virtual
;
374 int width
= area
->width
;
375 int height
= area
->height
;
378 if(info
->state
!= FBINFO_STATE_RUNNING
)
381 if((!ivideo
->accel
) || (!ivideo
->engineok
)) {
382 cfb_copyarea(info
, area
);
386 if(!width
|| !height
||
387 area
->sx
>= vxres
|| area
->sy
>= vyres
||
388 area
->dx
>= vxres
|| area
->dy
>= vyres
)
392 if((area
->sx
+ width
) > vxres
) width
= vxres
- area
->sx
;
393 if((area
->dx
+ width
) > vxres
) width
= vxres
- area
->dx
;
394 if((area
->sy
+ height
) > vyres
) height
= vyres
- area
->sy
;
395 if((area
->dy
+ height
) > vyres
) height
= vyres
- area
->dy
;
397 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
398 #ifdef CONFIG_FB_SIS_300
401 if(area
->sx
< area
->dx
) xdir
= 0;
403 if(area
->sy
< area
->dy
) ydir
= 0;
407 SiS300SetupForScreenToScreenCopy(ivideo
, xdir
, ydir
, 3, -1);
408 SiS300SubsequentScreenToScreenCopy(ivideo
, area
->sx
, area
->sy
,
409 area
->dx
, area
->dy
, width
, height
);
413 #ifdef CONFIG_FB_SIS_315
415 SiS310SetupForScreenToScreenCopy(ivideo
, 3, -1);
416 SiS310SubsequentScreenToScreenCopy(ivideo
, area
->sx
, area
->sy
,
417 area
->dx
, area
->dy
, width
, height
);
422 sisfb_syncaccel(ivideo
);