1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * SiS 300/540/630[S]/730[S],
4 * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX],
6 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
10 * Based on the XFree86/X.org driver which is
11 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
13 * Author: Thomas Winischhofer <thomas@winischhofer.net>
14 * (see http://www.winischhofer.net/
15 * for more information and updates)
18 #include <linux/module.h>
19 #include <linux/kernel.h>
21 #include <linux/ioport.h>
22 #include <linux/types.h>
26 #include "sis_accel.h"
28 static const u8 sisALUConv
[] =
30 0x00, /* dest = 0; 0, GXclear, 0 */
31 0x88, /* dest &= src; DSa, GXand, 0x1 */
32 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */
33 0xCC, /* dest = src; S, GXcopy, 0x3 */
34 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */
35 0xAA, /* dest = dest; D, GXnoop, 0x5 */
36 0x66, /* dest = ^src; DSx, GXxor, 0x6 */
37 0xEE, /* dest |= src; DSo, GXor, 0x7 */
38 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */
39 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */
40 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
41 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */
42 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */
43 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */
44 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */
45 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
47 /* same ROP but with Pattern as Source */
48 static const u8 sisPatALUConv
[] =
50 0x00, /* dest = 0; 0, GXclear, 0 */
51 0xA0, /* dest &= src; DPa, GXand, 0x1 */
52 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */
53 0xF0, /* dest = src; P, GXcopy, 0x3 */
54 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */
55 0xAA, /* dest = dest; D, GXnoop, 0x5 */
56 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */
57 0xFA, /* dest |= src; DPo, GXor, 0x7 */
58 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */
59 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */
60 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
61 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */
62 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */
63 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */
64 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */
65 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
68 static const int myrops
[] = {
69 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
72 /* 300 series ----------------------------------------------------- */
73 #ifdef CONFIG_FB_SIS_300
75 SiS300Sync(struct sis_video_info
*ivideo
)
81 SiS300SetupForScreenToScreenCopy(struct sis_video_info
*ivideo
, int xdir
, int ydir
,
82 int rop
, int trans_color
)
84 SiS300SetupDSTColorDepth(ivideo
->DstColor
);
85 SiS300SetupSRCPitch(ivideo
->video_linelength
)
86 SiS300SetupDSTRect(ivideo
->video_linelength
, 0xffff)
88 if(trans_color
!= -1) {
90 SiS300SetupSRCTrans(trans_color
)
91 SiS300SetupCMDFlag(TRANSPARENT_BITBLT
)
93 SiS300SetupROP(sisALUConv
[rop
])
96 SiS300SetupCMDFlag(X_INC
)
99 SiS300SetupCMDFlag(Y_INC
)
104 SiS300SubsequentScreenToScreenCopy(struct sis_video_info
*ivideo
, int src_x
,
105 int src_y
, int dst_x
, int dst_y
, int width
, int height
)
107 u32 srcbase
= 0, dstbase
= 0;
110 srcbase
= ivideo
->video_linelength
* src_y
;
114 dstbase
= ivideo
->video_linelength
* dst_y
;
118 SiS300SetupSRCBase(srcbase
);
119 SiS300SetupDSTBase(dstbase
);
121 if(!(ivideo
->CommandReg
& X_INC
)) {
125 if(!(ivideo
->CommandReg
& Y_INC
)) {
129 SiS300SetupRect(width
, height
)
130 SiS300SetupSRCXY(src_x
, src_y
)
131 SiS300SetupDSTXY(dst_x
, dst_y
)
136 SiS300SetupForSolidFill(struct sis_video_info
*ivideo
, u32 color
, int rop
)
138 SiS300SetupPATFG(color
)
139 SiS300SetupDSTRect(ivideo
->video_linelength
, 0xffff)
140 SiS300SetupDSTColorDepth(ivideo
->DstColor
);
141 SiS300SetupROP(sisPatALUConv
[rop
])
142 SiS300SetupCMDFlag(PATFG
)
146 SiS300SubsequentSolidFillRect(struct sis_video_info
*ivideo
, int x
, int y
, int w
, int h
)
151 dstbase
= ivideo
->video_linelength
* y
;
154 SiS300SetupDSTBase(dstbase
)
155 SiS300SetupDSTXY(x
,y
)
157 SiS300SetupCMDFlag(X_INC
| Y_INC
| BITBLT
)
162 /* 315/330/340 series ---------------------------------------------- */
164 #ifdef CONFIG_FB_SIS_315
166 SiS310Sync(struct sis_video_info
*ivideo
)
172 SiS310SetupForScreenToScreenCopy(struct sis_video_info
*ivideo
, int rop
, int trans_color
)
174 SiS310SetupDSTColorDepth(ivideo
->DstColor
);
175 SiS310SetupSRCPitch(ivideo
->video_linelength
)
176 SiS310SetupDSTRect(ivideo
->video_linelength
, 0x0fff)
177 if(trans_color
!= -1) {
179 SiS310SetupSRCTrans(trans_color
)
180 SiS310SetupCMDFlag(TRANSPARENT_BITBLT
)
182 SiS310SetupROP(sisALUConv
[rop
])
183 /* Set command - not needed, both 0 */
184 /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
186 SiS310SetupCMDFlag(ivideo
->SiS310_AccelDepth
)
187 /* The chip is smart enough to know the direction */
191 SiS310SubsequentScreenToScreenCopy(struct sis_video_info
*ivideo
, int src_x
, int src_y
,
192 int dst_x
, int dst_y
, int width
, int height
)
194 u32 srcbase
= 0, dstbase
= 0;
195 int mymin
= min(src_y
, dst_y
);
196 int mymax
= max(src_y
, dst_y
);
198 /* Although the chip knows the direction to use
199 * if the source and destination areas overlap,
200 * that logic fails if we fiddle with the bitmap
201 * addresses. Therefore, we check if the source
202 * and destination blitting areas overlap and
203 * adapt the bitmap addresses synchronously
204 * if the coordinates exceed the valid range.
205 * The the areas do not overlap, we do our
208 if((mymax
- mymin
) < height
) {
209 if((src_y
>= 2048) || (dst_y
>= 2048)) {
210 srcbase
= ivideo
->video_linelength
* mymin
;
211 dstbase
= ivideo
->video_linelength
* mymin
;
217 srcbase
= ivideo
->video_linelength
* src_y
;
221 dstbase
= ivideo
->video_linelength
* dst_y
;
226 srcbase
+= ivideo
->video_offset
;
227 dstbase
+= ivideo
->video_offset
;
229 SiS310SetupSRCBase(srcbase
);
230 SiS310SetupDSTBase(dstbase
);
231 SiS310SetupRect(width
, height
)
232 SiS310SetupSRCXY(src_x
, src_y
)
233 SiS310SetupDSTXY(dst_x
, dst_y
)
238 SiS310SetupForSolidFill(struct sis_video_info
*ivideo
, u32 color
, int rop
)
240 SiS310SetupPATFG(color
)
241 SiS310SetupDSTRect(ivideo
->video_linelength
, 0x0fff)
242 SiS310SetupDSTColorDepth(ivideo
->DstColor
);
243 SiS310SetupROP(sisPatALUConv
[rop
])
244 SiS310SetupCMDFlag(PATFG
| ivideo
->SiS310_AccelDepth
)
248 SiS310SubsequentSolidFillRect(struct sis_video_info
*ivideo
, int x
, int y
, int w
, int h
)
253 dstbase
= ivideo
->video_linelength
* y
;
256 dstbase
+= ivideo
->video_offset
;
257 SiS310SetupDSTBase(dstbase
)
258 SiS310SetupDSTXY(x
,y
)
260 SiS310SetupCMDFlag(BITBLT
)
265 /* --------------------------------------------------------------------- */
267 /* The exported routines */
269 int sisfb_initaccel(struct sis_video_info
*ivideo
)
271 #ifdef SISFB_USE_SPINLOCKS
272 spin_lock_init(&ivideo
->lockaccel
);
277 void sisfb_syncaccel(struct sis_video_info
*ivideo
)
279 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
280 #ifdef CONFIG_FB_SIS_300
284 #ifdef CONFIG_FB_SIS_315
290 int fbcon_sis_sync(struct fb_info
*info
)
292 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
295 if((!ivideo
->accel
) || (!ivideo
->engineok
))
299 sisfb_syncaccel(ivideo
);
305 void fbcon_sis_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
307 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
309 u32 vxres
= info
->var
.xres_virtual
;
310 u32 vyres
= info
->var
.yres_virtual
;
314 if(info
->state
!= FBINFO_STATE_RUNNING
)
317 if((!ivideo
->accel
) || (!ivideo
->engineok
)) {
318 cfb_fillrect(info
, rect
);
322 if(!rect
->width
|| !rect
->height
|| rect
->dx
>= vxres
|| rect
->dy
>= vyres
)
326 width
= ((rect
->dx
+ rect
->width
) > vxres
) ? (vxres
- rect
->dx
) : rect
->width
;
327 height
= ((rect
->dy
+ rect
->height
) > vyres
) ? (vyres
- rect
->dy
) : rect
->height
;
329 switch(info
->var
.bits_per_pixel
) {
330 case 8: col
= rect
->color
;
333 case 32: col
= ((u32
*)(info
->pseudo_palette
))[rect
->color
];
337 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
338 #ifdef CONFIG_FB_SIS_300
340 SiS300SetupForSolidFill(ivideo
, col
, myrops
[rect
->rop
]);
341 SiS300SubsequentSolidFillRect(ivideo
, rect
->dx
, rect
->dy
, width
, height
);
345 #ifdef CONFIG_FB_SIS_315
347 SiS310SetupForSolidFill(ivideo
, col
, myrops
[rect
->rop
]);
348 SiS310SubsequentSolidFillRect(ivideo
, rect
->dx
, rect
->dy
, width
, height
);
353 sisfb_syncaccel(ivideo
);
356 void fbcon_sis_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
358 struct sis_video_info
*ivideo
= (struct sis_video_info
*)info
->par
;
359 u32 vxres
= info
->var
.xres_virtual
;
360 u32 vyres
= info
->var
.yres_virtual
;
361 int width
= area
->width
;
362 int height
= area
->height
;
365 if(info
->state
!= FBINFO_STATE_RUNNING
)
368 if((!ivideo
->accel
) || (!ivideo
->engineok
)) {
369 cfb_copyarea(info
, area
);
373 if(!width
|| !height
||
374 area
->sx
>= vxres
|| area
->sy
>= vyres
||
375 area
->dx
>= vxres
|| area
->dy
>= vyres
)
379 if((area
->sx
+ width
) > vxres
) width
= vxres
- area
->sx
;
380 if((area
->dx
+ width
) > vxres
) width
= vxres
- area
->dx
;
381 if((area
->sy
+ height
) > vyres
) height
= vyres
- area
->sy
;
382 if((area
->dy
+ height
) > vyres
) height
= vyres
- area
->dy
;
384 if(ivideo
->sisvga_engine
== SIS_300_VGA
) {
385 #ifdef CONFIG_FB_SIS_300
388 if(area
->sx
< area
->dx
) xdir
= 0;
390 if(area
->sy
< area
->dy
) ydir
= 0;
394 SiS300SetupForScreenToScreenCopy(ivideo
, xdir
, ydir
, 3, -1);
395 SiS300SubsequentScreenToScreenCopy(ivideo
, area
->sx
, area
->sy
,
396 area
->dx
, area
->dy
, width
, height
);
400 #ifdef CONFIG_FB_SIS_315
402 SiS310SetupForScreenToScreenCopy(ivideo
, 3, -1);
403 SiS310SubsequentScreenToScreenCopy(ivideo
, area
->sx
, area
->sy
,
404 area
->dx
, area
->dy
, width
, height
);
409 sisfb_syncaccel(ivideo
);