1/* 2 * SiS DGA handling 3 * 4 * Copyright (C) 2000 by Alan Hourihane, Sychdyn, North Wales, UK. 5 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria 6 * 7 * Portions from radeon_dga.c which is 8 * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and 9 * VA Linux Systems Inc., Fremont, California. 10 * 11 * Licensed under the following terms: 12 * 13 * Permission to use, copy, modify, distribute, and sell this software and its 14 * documentation for any purpose is hereby granted without fee, provided that 15 * the above copyright notice appear in all copies and that both that 16 * copyright notice and this permission notice appear in supporting 17 * documentation, and that the name of the providers not be used in 18 * advertising or publicity pertaining to distribution of the software without 19 * specific, written prior permission. The providers make no representations 20 * about the suitability of this software for any purpose. It is provided 21 * "as is" without express or implied warranty. 22 * 23 * THE PROVIDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 24 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 25 * EVENT SHALL THE PROVIDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 26 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 27 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 28 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 29 * PERFORMANCE OF THIS SOFTWARE. 30 * 31 * Authors: Alan Hourihane, <alanh@fairlite.demon.co.uk> 32 * Thomas Winischhofer <thomas@winischhofer.net> 33 */ 34 35#ifdef HAVE_CONFIG_H 36#include "config.h" 37#endif 38 39#include "sis.h" 40#include "dgaproc.h" 41 42#include "sis_regs.h" 43 44#ifndef NEW_DGAOPENFRAMEBUFFER 45static Bool SIS_OpenFramebuffer(ScrnInfoPtr, char **, UChar **, 46 int *, int *, int *); 47#else 48static Bool SIS_OpenFramebuffer(ScrnInfoPtr, char **, unsigned int *, 49 unsigned int *, unsigned int *, unsigned int *); 50#endif 51static Bool SIS_SetMode(ScrnInfoPtr, DGAModePtr); 52static void SIS_Sync(ScrnInfoPtr); 53static int SIS_GetViewport(ScrnInfoPtr); 54static void SIS_SetViewport(ScrnInfoPtr, int, int, int); 55static void SIS_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long); 56static void SIS_BlitRect(ScrnInfoPtr, int, int, int, int, int, int); 57static void SIS_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, unsigned long); 58 59static 60DGAFunctionRec SISDGAFuncs = { 61 SIS_OpenFramebuffer, 62 NULL, 63 SIS_SetMode, 64 SIS_SetViewport, 65 SIS_GetViewport, 66 SIS_Sync, 67 SIS_FillRect, 68 SIS_BlitRect, 69 NULL 70}; 71 72static 73DGAFunctionRec SISDGAFuncs3xx = { 74 SIS_OpenFramebuffer, 75 NULL, 76 SIS_SetMode, 77 SIS_SetViewport, 78 SIS_GetViewport, 79 SIS_Sync, 80 SIS_FillRect, 81 SIS_BlitRect, 82 SIS_BlitTransRect 83}; 84 85static DGAModePtr 86SISSetupDGAMode( 87 ScrnInfoPtr pScrn, 88 DGAModePtr modes, 89 int *num, 90 int bitsPerPixel, 91 int depth, 92 Bool pixmap, 93 int secondPitch, 94 ULong red, 95 ULong green, 96 ULong blue, 97 short visualClass 98){ 99 SISPtr pSiS = SISPTR(pScrn); 100 DGAModePtr newmodes = NULL, currentMode; 101 DisplayModePtr pMode, firstMode; 102 int otherPitch, Bpp = bitsPerPixel >> 3; 103 Bool oneMore; 104 105 pMode = firstMode = pScrn->modes; 106 107 while(pMode) { 108 109#ifdef SISMERGED 110 if(pSiS->MergedFB) { 111 Bool nogood = FALSE; 112 /* Filter out all meta modes that would require driver-side panning */ 113 switch(((SiSMergedDisplayModePtr)pMode->Private)->CRT2Position) { 114 case sisClone: 115 if( (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay != 116 ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->HDisplay) || 117 (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay != 118 ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->VDisplay) || 119 (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay != 120 pMode->HDisplay) || 121 (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay != 122 pMode->VDisplay) ) 123 nogood = TRUE; 124 break; 125 case sisRightOf: 126 case sisLeftOf: 127 if( (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay != 128 ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->VDisplay) || 129 (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay != pMode->VDisplay) ) 130 nogood = TRUE; 131 break; 132 default: 133 if( (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay != 134 ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->HDisplay) || 135 (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay != pMode->HDisplay) ) 136 nogood = TRUE; 137 } 138 if(nogood) { 139 if(depth == 16) { /* Print this only the first time */ 140 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 141 "DGA: MetaMode %dx%d not suitable for DGA, skipping\n", 142 pMode->HDisplay, pMode->VDisplay); 143 } 144 goto mode_nogood; 145 } 146 } 147#endif 148 149 otherPitch = secondPitch ? secondPitch : pMode->HDisplay; 150 151 if(pMode->HDisplay != otherPitch) { 152 153 newmodes = realloc(modes, (*num + 2) * sizeof(DGAModeRec)); 154 oneMore = TRUE; 155 156 } else { 157 158 newmodes = realloc(modes, (*num + 1) * sizeof(DGAModeRec)); 159 oneMore = FALSE; 160 161 } 162 163 if(!newmodes) { 164 free(modes); 165 return NULL; 166 } 167 modes = newmodes; 168 169SECOND_PASS: 170 171 currentMode = modes + *num; 172 (*num)++; 173 174 currentMode->mode = pMode; 175 currentMode->flags = DGA_CONCURRENT_ACCESS; 176 if(pixmap) 177 currentMode->flags |= DGA_PIXMAP_AVAILABLE; 178 if(!pSiS->NoAccel) { 179 currentMode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT; 180 if((pSiS->VGAEngine == SIS_300_VGA) || 181 (pSiS->VGAEngine == SIS_315_VGA) || 182 (pSiS->VGAEngine == SIS_530_VGA)) { 183 currentMode->flags |= DGA_BLIT_RECT_TRANS; 184 } 185 } 186 if(pMode->Flags & V_DBLSCAN) 187 currentMode->flags |= DGA_DOUBLESCAN; 188 if(pMode->Flags & V_INTERLACE) 189 currentMode->flags |= DGA_INTERLACED; 190 currentMode->byteOrder = pScrn->imageByteOrder; 191 currentMode->depth = depth; 192 currentMode->bitsPerPixel = bitsPerPixel; 193 currentMode->red_mask = red; 194 currentMode->green_mask = green; 195 currentMode->blue_mask = blue; 196 currentMode->visualClass = visualClass; 197 currentMode->viewportWidth = pMode->HDisplay; 198 currentMode->viewportHeight = pMode->VDisplay; 199 currentMode->xViewportStep = 1; 200 currentMode->yViewportStep = 1; 201 currentMode->viewportFlags = DGA_FLIP_RETRACE; 202 currentMode->offset = 0; 203 currentMode->address = pSiS->FbBase; 204 205 if(oneMore) { 206 207 /* first one is narrow width */ 208 currentMode->bytesPerScanline = (((pMode->HDisplay * Bpp) + 3) & ~3L); 209 currentMode->imageWidth = pMode->HDisplay; 210 currentMode->imageHeight = pMode->VDisplay; 211 currentMode->pixmapWidth = currentMode->imageWidth; 212 currentMode->pixmapHeight = currentMode->imageHeight; 213 currentMode->maxViewportX = currentMode->imageWidth - 214 currentMode->viewportWidth; 215 /* this might need to get clamped to some maximum */ 216 currentMode->maxViewportY = (currentMode->imageHeight - 217 currentMode->viewportHeight); 218 oneMore = FALSE; 219 goto SECOND_PASS; 220 221 } else { 222 223 currentMode->bytesPerScanline = ((otherPitch * Bpp) + 3) & ~3L; 224 currentMode->imageWidth = otherPitch; 225 currentMode->imageHeight = pMode->VDisplay; 226 currentMode->pixmapWidth = currentMode->imageWidth; 227 currentMode->pixmapHeight = currentMode->imageHeight; 228 currentMode->maxViewportX = (currentMode->imageWidth - 229 currentMode->viewportWidth); 230 /* this might need to get clamped to some maximum */ 231 currentMode->maxViewportY = (currentMode->imageHeight - 232 currentMode->viewportHeight); 233 } 234 235#ifdef SISMERGED 236mode_nogood: 237#endif 238 239 pMode = pMode->next; 240 if(pMode == firstMode) 241 break; 242 } 243 244 return modes; 245} 246 247Bool 248SISDGAInit(ScreenPtr pScreen) 249{ 250 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 251 SISPtr pSiS = SISPTR(pScrn); 252 DGAModePtr modes = NULL; 253 int num = 0; 254 255 /* 8 */ 256 /* We don't support 8bpp modes in dual head or MergedFB mode, 257 * so don't offer them to DGA either. 258 */ 259#ifdef SISDUALHEAD 260 if(!pSiS->DualHeadMode) { 261#endif 262#ifdef SISMERGED 263 if(!(pSiS->MergedFB)) { 264#endif 265 modes = SISSetupDGAMode(pScrn, modes, &num, 8, 8, 266 (pScrn->bitsPerPixel == 8), 267 ((pScrn->bitsPerPixel != 8) 268 ? 0 : pScrn->displayWidth), 269 0, 0, 0, PseudoColor); 270#ifdef SISMERGED 271 } 272#endif 273#ifdef SISDUALHEAD 274 } 275#endif 276 277 /* 16 */ 278 modes = SISSetupDGAMode(pScrn, modes, &num, 16, 16, 279 (pScrn->bitsPerPixel == 16), 280 ((pScrn->depth != 16) 281 ? 0 : pScrn->displayWidth), 282 0xf800, 0x07e0, 0x001f, TrueColor); 283 284 if((pSiS->VGAEngine == SIS_530_VGA) || (pSiS->VGAEngine == SIS_OLD_VGA)) { 285 /* 24 */ 286 modes = SISSetupDGAMode(pScrn, modes, &num, 24, 24, 287 (pScrn->bitsPerPixel == 24), 288 ((pScrn->bitsPerPixel != 24) 289 ? 0 : pScrn->displayWidth), 290 0xff0000, 0x00ff00, 0x0000ff, TrueColor); 291 } 292 293 if(pSiS->VGAEngine != SIS_OLD_VGA) { 294 /* 32 */ 295 modes = SISSetupDGAMode(pScrn, modes, &num, 32, 24, 296 (pScrn->bitsPerPixel == 32), 297 ((pScrn->bitsPerPixel != 32) 298 ? 0 : pScrn->displayWidth), 299 0xff0000, 0x00ff00, 0x0000ff, TrueColor); 300 } 301 302 pSiS->numDGAModes = num; 303 pSiS->DGAModes = modes; 304 305 if(num) { 306 if((pSiS->VGAEngine == SIS_300_VGA) || 307 (pSiS->VGAEngine == SIS_315_VGA) || 308 (pSiS->VGAEngine == SIS_530_VGA)) { 309 return DGAInit(pScreen, &SISDGAFuncs3xx, modes, num); 310 } else { 311 return DGAInit(pScreen, &SISDGAFuncs, modes, num); 312 } 313 } else { 314 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 315 "No DGA-suitable modes found, disabling DGA\n"); 316 return TRUE; 317 } 318} 319 320static Bool 321SIS_OpenFramebuffer( 322 ScrnInfoPtr pScrn, 323 char **name, 324#ifndef NEW_DGAOPENFRAMEBUFFER 325 UChar **mem, 326 int *size, 327 int *offset, 328 int *flags 329#else 330 unsigned int *mem, 331 unsigned int *size, 332 unsigned int *offset, 333 unsigned int *flags 334#endif 335){ 336 SISPtr pSiS = SISPTR(pScrn); 337 338 *name = NULL; /* no special device */ 339#ifndef NEW_DGAOPENFRAMEBUFFER 340 *mem = (UChar *)pSiS->FbAddress; 341#else 342 *mem = pSiS->FbAddress; 343#endif 344 *size = pSiS->maxxfbmem; 345 *offset = 0; 346#ifndef NEW_DGAOPENFRAMEBUFFER 347 *flags = DGA_NEED_ROOT; 348#else 349 *flags = 0; 350#endif 351 352 return TRUE; 353} 354 355static Bool 356SIS_SetMode( 357 ScrnInfoPtr pScrn, 358 DGAModePtr pMode 359){ 360 static SISFBLayout BackupLayouts[MAXSCREENS]; 361 int index = pScrn->pScreen->myNum; 362 SISPtr pSiS = SISPTR(pScrn); 363 364 if(!pMode) { /* restore the original mode */ 365 366 if(pSiS->DGAactive) { 367 /* put the ScreenParameters back */ 368 memcpy(&pSiS->CurrentLayout, &BackupLayouts[index], sizeof(SISFBLayout)); 369 } 370 371 pScrn->currentMode = pSiS->CurrentLayout.mode; 372 pSiS->DGAactive = FALSE; 373 374 (*pScrn->SwitchMode)(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode)); 375 (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0)); 376 377 } else { /* set new mode */ 378 379 if(!pSiS->DGAactive) { 380 /* save the old parameters */ 381 memcpy(&BackupLayouts[index], &pSiS->CurrentLayout, sizeof(SISFBLayout)); 382 pSiS->DGAactive = TRUE; 383 } 384 385 pSiS->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel; 386 pSiS->CurrentLayout.depth = pMode->depth; 387 pSiS->CurrentLayout.displayWidth = pMode->bytesPerScanline / (pMode->bitsPerPixel >> 3); 388 pSiS->CurrentLayout.displayHeight = pMode->imageHeight; 389 390 (*pScrn->SwitchMode)(SWITCH_MODE_ARGS(pScrn, pMode->mode)); 391 /* Adjust viewport to 0/0 after mode switch */ 392 /* This fixes the vmware-in-dualhead problems */ 393 (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, 0, 0)); 394 pSiS->CurrentLayout.DGAViewportX = pSiS->CurrentLayout.DGAViewportY = 0; 395 } 396 397 return TRUE; 398} 399 400static int 401SIS_GetViewport( 402 ScrnInfoPtr pScrn 403){ 404 SISPtr pSiS = SISPTR(pScrn); 405 406 return pSiS->DGAViewportStatus; 407} 408 409static void 410SIS_SetViewport( 411 ScrnInfoPtr pScrn, 412 int x, int y, 413 int flags 414){ 415 SISPtr pSiS = SISPTR(pScrn); 416 417 (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y)); 418 pSiS->DGAViewportStatus = 0; /* There are never pending Adjusts */ 419 pSiS->CurrentLayout.DGAViewportX = x; 420 pSiS->CurrentLayout.DGAViewportY = y; 421} 422 423static void 424SIS_Sync( 425 ScrnInfoPtr pScrn 426){ 427 SISPtr pSiS = SISPTR(pScrn); 428 429 (*pSiS->SyncAccel)(pScrn); 430} 431 432static void 433SIS_FillRect( 434 ScrnInfoPtr pScrn, 435 int x, int y, int w, int h, 436 unsigned long color 437){ 438 SISPtr pSiS = SISPTR(pScrn); 439 440 if(pSiS->FillRect) { 441 (*pSiS->FillRect)(pScrn, x, y, w, h, (int)color); 442#ifdef SIS_USE_XAA 443 if(!pSiS->useEXA && pSiS->AccelInfoPtr) { 444 SET_SYNC_FLAG(pSiS->AccelInfoPtr); 445 } 446#endif 447 } 448} 449 450static void 451SIS_BlitRect( 452 ScrnInfoPtr pScrn, 453 int srcx, int srcy, 454 int w, int h, 455 int dstx, int dsty 456){ 457 SISPtr pSiS = SISPTR(pScrn); 458 459 if(pSiS->BlitRect) { 460 (*pSiS->BlitRect)(pScrn, srcx, srcy, dstx, dsty, w, h, -1); 461#ifdef SIS_USE_XAA 462 if(!pSiS->useEXA && pSiS->AccelInfoPtr) { 463 SET_SYNC_FLAG(pSiS->AccelInfoPtr); 464 } 465#endif 466 } 467} 468 469static void 470SIS_BlitTransRect( 471 ScrnInfoPtr pScrn, 472 int srcx, int srcy, 473 int w, int h, 474 int dstx, int dsty, 475 ULong color 476){ 477 SISPtr pSiS = SISPTR(pScrn); 478 479 if(pSiS->BlitRect) { 480 (*pSiS->BlitRect)(pScrn, srcx, srcy, dstx, dsty, w, h, (int)color); 481#ifdef SIS_USE_XAA 482 if(!pSiS->useEXA && pSiS->AccelInfoPtr) { 483 SET_SYNC_FLAG(pSiS->AccelInfoPtr); 484 } 485#endif 486 } 487} 488 489 490 491