1 /* 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], 4 * XGI V3XT/V5/V8, Z7 5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 6 * 7 * 2D acceleration part 8 * 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. 13 * 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. 18 * 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 22 * 23 * Based on the XFree86/X.org driver which is 24 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria 25 * 26 * Author: Thomas Winischhofer <thomas@winischhofer.net> 27 * (see http://www.winischhofer.net/ 28 * for more information and updates) 29 */ 30 31 #include <linux/module.h> 32 #include <linux/kernel.h> 33 #include <linux/fb.h> 34 #include <linux/ioport.h> 35 #include <linux/types.h> 36 #include <asm/io.h> 37 38 #include "sis.h" 39 #include "sis_accel.h" 40 41 static const u8 sisALUConv[] = 42 { 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 */ 59 }; 60 /* same ROP but with Pattern as Source */ 61 static const u8 sisPatALUConv[] = 62 { 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 */ 79 }; 80 81 static const int myrops[] = { 82 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 83 }; 84 85 /* 300 series ----------------------------------------------------- */ 86 #ifdef CONFIG_FB_SIS_300 87 static void 88 SiS300Sync(struct sis_video_info *ivideo) 89 { 90 SiS300Idle 91 } 92 93 static void 94 SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir, 95 int rop, int trans_color) 96 { 97 SiS300SetupDSTColorDepth(ivideo->DstColor); 98 SiS300SetupSRCPitch(ivideo->video_linelength) 99 SiS300SetupDSTRect(ivideo->video_linelength, 0xffff) 100 101 if(trans_color != -1) { 102 SiS300SetupROP(0x0A) 103 SiS300SetupSRCTrans(trans_color) 104 SiS300SetupCMDFlag(TRANSPARENT_BITBLT) 105 } else { 106 SiS300SetupROP(sisALUConv[rop]) 107 } 108 if(xdir > 0) { 109 SiS300SetupCMDFlag(X_INC) 110 } 111 if(ydir > 0) { 112 SiS300SetupCMDFlag(Y_INC) 113 } 114 } 115 116 static void 117 SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, 118 int src_y, int dst_x, int dst_y, int width, int height) 119 { 120 u32 srcbase = 0, dstbase = 0; 121 122 if(src_y >= 2048) { 123 srcbase = ivideo->video_linelength * src_y; 124 src_y = 0; 125 } 126 if(dst_y >= 2048) { 127 dstbase = ivideo->video_linelength * dst_y; 128 dst_y = 0; 129 } 130 131 SiS300SetupSRCBase(srcbase); 132 SiS300SetupDSTBase(dstbase); 133 134 if(!(ivideo->CommandReg & X_INC)) { 135 src_x += width-1; 136 dst_x += width-1; 137 } 138 if(!(ivideo->CommandReg & Y_INC)) { 139 src_y += height-1; 140 dst_y += height-1; 141 } 142 SiS300SetupRect(width, height) 143 SiS300SetupSRCXY(src_x, src_y) 144 SiS300SetupDSTXY(dst_x, dst_y) 145 SiS300DoCMD 146 } 147 148 static void 149 SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop) 150 { 151 SiS300SetupPATFG(color) 152 SiS300SetupDSTRect(ivideo->video_linelength, 0xffff) 153 SiS300SetupDSTColorDepth(ivideo->DstColor); 154 SiS300SetupROP(sisPatALUConv[rop]) 155 SiS300SetupCMDFlag(PATFG) 156 } 157 158 static void 159 SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h) 160 { 161 u32 dstbase = 0; 162 163 if(y >= 2048) { 164 dstbase = ivideo->video_linelength * y; 165 y = 0; 166 } 167 SiS300SetupDSTBase(dstbase) 168 SiS300SetupDSTXY(x,y) 169 SiS300SetupRect(w,h) 170 SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT) 171 SiS300DoCMD 172 } 173 #endif 174 175 /* 315/330/340 series ---------------------------------------------- */ 176 177 #ifdef CONFIG_FB_SIS_315 178 static void 179 SiS310Sync(struct sis_video_info *ivideo) 180 { 181 SiS310Idle 182 } 183 184 static void 185 SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color) 186 { 187 SiS310SetupDSTColorDepth(ivideo->DstColor); 188 SiS310SetupSRCPitch(ivideo->video_linelength) 189 SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff) 190 if(trans_color != -1) { 191 SiS310SetupROP(0x0A) 192 SiS310SetupSRCTrans(trans_color) 193 SiS310SetupCMDFlag(TRANSPARENT_BITBLT) 194 } else { 195 SiS310SetupROP(sisALUConv[rop]) 196 /* Set command - not needed, both 0 */ 197 /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */ 198 } 199 SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth) 200 /* The chip is smart enough to know the direction */ 201 } 202 203 static void 204 SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y, 205 int dst_x, int dst_y, int width, int height) 206 { 207 u32 srcbase = 0, dstbase = 0; 208 int mymin = min(src_y, dst_y); 209 int mymax = max(src_y, dst_y); 210 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 219 * normal check. 220 */ 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; 225 src_y -= mymin; 226 dst_y -= mymin; 227 } 228 } else { 229 if(src_y >= 2048) { 230 srcbase = ivideo->video_linelength * src_y; 231 src_y = 0; 232 } 233 if(dst_y >= 2048) { 234 dstbase = ivideo->video_linelength * dst_y; 235 dst_y = 0; 236 } 237 } 238 239 srcbase += ivideo->video_offset; 240 dstbase += ivideo->video_offset; 241 242 SiS310SetupSRCBase(srcbase); 243 SiS310SetupDSTBase(dstbase); 244 SiS310SetupRect(width, height) 245 SiS310SetupSRCXY(src_x, src_y) 246 SiS310SetupDSTXY(dst_x, dst_y) 247 SiS310DoCMD 248 } 249 250 static void 251 SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop) 252 { 253 SiS310SetupPATFG(color) 254 SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff) 255 SiS310SetupDSTColorDepth(ivideo->DstColor); 256 SiS310SetupROP(sisPatALUConv[rop]) 257 SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth) 258 } 259 260 static void 261 SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h) 262 { 263 u32 dstbase = 0; 264 265 if(y >= 2048) { 266 dstbase = ivideo->video_linelength * y; 267 y = 0; 268 } 269 dstbase += ivideo->video_offset; 270 SiS310SetupDSTBase(dstbase) 271 SiS310SetupDSTXY(x,y) 272 SiS310SetupRect(w,h) 273 SiS310SetupCMDFlag(BITBLT) 274 SiS310DoCMD 275 } 276 #endif 277 278 /* --------------------------------------------------------------------- */ 279 280 /* The exported routines */ 281 282 int sisfb_initaccel(struct sis_video_info *ivideo) 283 { 284 #ifdef SISFB_USE_SPINLOCKS 285 spin_lock_init(&ivideo->lockaccel); 286 #endif 287 return 0; 288 } 289 290 void sisfb_syncaccel(struct sis_video_info *ivideo) 291 { 292 if(ivideo->sisvga_engine == SIS_300_VGA) { 293 #ifdef CONFIG_FB_SIS_300 294 SiS300Sync(ivideo); 295 #endif 296 } else { 297 #ifdef CONFIG_FB_SIS_315 298 SiS310Sync(ivideo); 299 #endif 300 } 301 } 302 303 int fbcon_sis_sync(struct fb_info *info) 304 { 305 struct sis_video_info *ivideo = (struct sis_video_info *)info->par; 306 CRITFLAGS 307 308 if((!ivideo->accel) || (!ivideo->engineok)) 309 return 0; 310 311 CRITBEGIN 312 sisfb_syncaccel(ivideo); 313 CRITEND 314 315 return 0; 316 } 317 318 void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 319 { 320 struct sis_video_info *ivideo = (struct sis_video_info *)info->par; 321 u32 col = 0; 322 u32 vxres = info->var.xres_virtual; 323 u32 vyres = info->var.yres_virtual; 324 int width, height; 325 CRITFLAGS 326 327 if(info->state != FBINFO_STATE_RUNNING) 328 return; 329 330 if((!ivideo->accel) || (!ivideo->engineok)) { 331 cfb_fillrect(info, rect); 332 return; 333 } 334 335 if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres) 336 return; 337 338 /* Clipping */ 339 width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width; 340 height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height; 341 342 switch(info->var.bits_per_pixel) { 343 case 8: col = rect->color; 344 break; 345 case 16: 346 case 32: col = ((u32 *)(info->pseudo_palette))[rect->color]; 347 break; 348 } 349 350 if(ivideo->sisvga_engine == SIS_300_VGA) { 351 #ifdef CONFIG_FB_SIS_300 352 CRITBEGIN 353 SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]); 354 SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); 355 CRITEND 356 #endif 357 } else { 358 #ifdef CONFIG_FB_SIS_315 359 CRITBEGIN 360 SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]); 361 SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); 362 CRITEND 363 #endif 364 } 365 366 sisfb_syncaccel(ivideo); 367 } 368 369 void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area) 370 { 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; 376 CRITFLAGS 377 378 if(info->state != FBINFO_STATE_RUNNING) 379 return; 380 381 if((!ivideo->accel) || (!ivideo->engineok)) { 382 cfb_copyarea(info, area); 383 return; 384 } 385 386 if(!width || !height || 387 area->sx >= vxres || area->sy >= vyres || 388 area->dx >= vxres || area->dy >= vyres) 389 return; 390 391 /* Clipping */ 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; 396 397 if(ivideo->sisvga_engine == SIS_300_VGA) { 398 #ifdef CONFIG_FB_SIS_300 399 int xdir, ydir; 400 401 if(area->sx < area->dx) xdir = 0; 402 else xdir = 1; 403 if(area->sy < area->dy) ydir = 0; 404 else ydir = 1; 405 406 CRITBEGIN 407 SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1); 408 SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, 409 area->dx, area->dy, width, height); 410 CRITEND 411 #endif 412 } else { 413 #ifdef CONFIG_FB_SIS_315 414 CRITBEGIN 415 SiS310SetupForScreenToScreenCopy(ivideo, 3, -1); 416 SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, 417 area->dx, area->dy, width, height); 418 CRITEND 419 #endif 420 } 421 422 sisfb_syncaccel(ivideo); 423 } 424