1 /* 2 * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, 3 * Precision Insight, Inc., Cedar Park, Texas, and 4 * VA Linux Systems Inc., Fremont, California. 5 * 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining 9 * a copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation on the rights to use, copy, modify, merge, 12 * publish, distribute, sublicense, and/or sell copies of the Software, 13 * and to permit persons to whom the Software is furnished to do so, 14 * subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial 18 * portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX 24 * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 * OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 /* 35 * Authors: 36 * Rickard E. Faith <faith (at) valinux.com> 37 * Kevin E. Martin <martin (at) valinux.com> 38 * Alan Hourihane <alanh (at) fairlite.demon.co.uk> 39 * 40 * Credits: 41 * 42 * Thanks to Alan Hourihane <alanh (at) fairlite.demon..co.uk> and SuSE for 43 * providing source code to their 3.3.x Rage 128 driver. Portions of 44 * this file are based on the acceleration code for that driver. 45 * 46 * References: 47 * 48 * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical 49 * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April 50 * 1999. 51 * 52 * RAGE 128 Software Development Manual (Technical Reference Manual P/N 53 * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. 54 * 55 * Notes on unimplemented XAA optimizations: 56 * 57 * SetClipping: The Rage128 doesn't support the full 16bit registers needed 58 * for XAA clip rect support. 59 * SolidFillTrap: This will probably work if we can compute the correct 60 * Bresenham error values. 61 * TwoPointLine: The Rage 128 supports Bresenham lines instead. 62 * DashedLine with non-power-of-two pattern length: Apparently, there is 63 * no way to set the length of the pattern -- it is always 64 * assumed to be 8 or 32 (or 1024?). 65 * ScreenToScreenColorExpandFill: See p. 4-17 of the Technical Reference 66 * Manual where it states that monochrome expansion of frame 67 * buffer data is not supported. 68 * CPUToScreenColorExpandFill, direct: The implementation here uses a hybrid 69 * direct/indirect method. If we had more data registers, 70 * then we could do better. If XAA supported a trigger write 71 * address, the code would be simpler. 72 * (Alan Hourihane) Update. We now use purely indirect and clip the full 73 * rectangle. Seems as the direct method has some problems 74 * with this, although this indirect method is much faster 75 * than the old method of setting up the engine per scanline. 76 * This code was the basis of the Radeon work we did. 77 * Color8x8PatternFill: Apparently, an 8x8 color brush cannot take an 8x8 78 * pattern from frame buffer memory. 79 * ImageWrites: See CPUToScreenColorExpandFill. 80 * 81 */ 82 83 #define R128_TRAPEZOIDS 0 /* Trapezoids don't work */ 84 85 /* Driver data structures */ 86 #include <errno.h> 87 88 #include "r128.h" 89 #include "r128_reg.h" 90 #include "r128_probe.h" 91 #ifdef R128DRI 92 #include "r128_sarea.h" 93 #define _XF86DRI_SERVER_ 94 #include "r128_dri.h" 95 #include "r128_common.h" 96 #endif 97 98 /* Line support */ 99 #include "miline.h" 100 101 /* X and server generic header files */ 102 #include "xf86.h" 103 104 105 /* Flush all dirty data in the Pixel Cache to memory. */ 106 void R128EngineFlush(ScrnInfoPtr pScrn) 107 { 108 R128InfoPtr info = R128PTR(pScrn); 109 unsigned char *R128MMIO = info->MMIO; 110 int i; 111 112 OUTREGP(R128_PC_NGUI_CTLSTAT, R128_PC_FLUSH_ALL, ~R128_PC_FLUSH_ALL); 113 for (i = 0; i < R128_TIMEOUT; i++) { 114 if (!(INREG(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) break; 115 } 116 } 117 118 /* Reset graphics card to known state. */ 119 void R128EngineReset(ScrnInfoPtr pScrn) 120 { 121 R128InfoPtr info = R128PTR(pScrn); 122 unsigned char *R128MMIO = info->MMIO; 123 uint32_t clock_cntl_index; 124 uint32_t mclk_cntl; 125 uint32_t gen_reset_cntl; 126 127 R128EngineFlush(pScrn); 128 129 clock_cntl_index = INREG(R128_CLOCK_CNTL_INDEX); 130 mclk_cntl = INPLL(pScrn, R128_MCLK_CNTL); 131 132 OUTPLL(R128_MCLK_CNTL, mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP); 133 134 gen_reset_cntl = INREG(R128_GEN_RESET_CNTL); 135 136 OUTREG(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI); 137 INREG(R128_GEN_RESET_CNTL); 138 OUTREG(R128_GEN_RESET_CNTL, 139 gen_reset_cntl & (uint32_t)(~R128_SOFT_RESET_GUI)); 140 INREG(R128_GEN_RESET_CNTL); 141 142 OUTPLL(R128_MCLK_CNTL, mclk_cntl); 143 OUTREG(R128_CLOCK_CNTL_INDEX, clock_cntl_index); 144 OUTREG(R128_GEN_RESET_CNTL, gen_reset_cntl); 145 } 146 147 /* The FIFO has 64 slots. This routines waits until at least `entries' of 148 these slots are empty. */ 149 void R128WaitForFifoFunction(ScrnInfoPtr pScrn, int entries) 150 { 151 R128InfoPtr info = R128PTR(pScrn); 152 unsigned char *R128MMIO = info->MMIO; 153 int i; 154 155 for (;;) { 156 for (i = 0; i < R128_TIMEOUT; i++) { 157 info->fifo_slots = INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK; 158 if (info->fifo_slots >= entries) return; 159 } 160 161 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 162 "FIFO timed out: %lu entries, " 163 "stat = 0x%08lx, probe = 0x%08lx\n", 164 INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK, 165 INREG(R128_GUI_STAT), 166 INREG(R128_GUI_PROBE))); 167 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 168 "FIFO timed out, resetting engine...\n"); 169 R128EngineReset(pScrn); 170 #ifdef R128DRI 171 R128CCE_RESET(pScrn, info); 172 if (info->directRenderingEnabled) { 173 R128CCE_START(pScrn, info); 174 } 175 #endif 176 } 177 } 178 179 /* Wait for the graphics engine to be completely idle: the FIFO has 180 drained, the Pixel Cache is flushed, and the engine is idle. This is a 181 standard "sync" function that will make the hardware "quiescent". */ 182 void R128WaitForIdle(ScrnInfoPtr pScrn) 183 { 184 R128InfoPtr info = R128PTR(pScrn); 185 unsigned char *R128MMIO = info->MMIO; 186 int i; 187 188 R128WaitForFifoFunction(pScrn, 64); 189 190 for (;;) { 191 for (i = 0; i < R128_TIMEOUT; i++) { 192 if (!(INREG(R128_GUI_STAT) & R128_GUI_ACTIVE)) { 193 R128EngineFlush(pScrn); 194 return; 195 } 196 } 197 198 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 199 "Idle timed out: %lu entries, " 200 "stat = 0x%08lx, probe = 0x%08lx\n", 201 INREG(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK, 202 INREG(R128_GUI_STAT), 203 INREG(R128_GUI_PROBE))); 204 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 205 "Idle timed out, resetting engine...\n"); 206 #ifdef R128DRI 207 R128CCE_STOP(pScrn, info); 208 #endif 209 R128EngineReset(pScrn); 210 #ifdef R128DRI 211 R128CCE_RESET(pScrn, info); 212 if (info->directRenderingEnabled) { 213 R128CCE_START(pScrn, info); 214 } 215 #endif 216 } 217 } 218 219 #ifdef R128DRI 220 /* Wait until the CCE is completely idle: the FIFO has drained and the 221 * CCE is idle. 222 */ 223 void R128CCEWaitForIdle(ScrnInfoPtr pScrn) 224 { 225 R128InfoPtr info = R128PTR(pScrn); 226 int ret, i; 227 228 FLUSH_RING(); 229 230 for (;;) { 231 i = 0; 232 do { 233 ret = drmCommandNone(info->drmFD, DRM_R128_CCE_IDLE); 234 } while ( ret && errno == EBUSY && i++ < (R128_IDLE_RETRY * R128_IDLE_RETRY) ); 235 236 if (ret && ret != -EBUSY) { 237 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 238 "%s: CCE idle %d\n", __FUNCTION__, ret); 239 } 240 241 if (i > R128_IDLE_RETRY) { 242 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 243 "%s: (DEBUG) CCE idle took i = %d\n", __FUNCTION__, i); 244 } 245 246 if (ret == 0) return; 247 248 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 249 "Idle timed out, resetting engine...\n"); 250 R128CCE_STOP(pScrn, info); 251 R128EngineReset(pScrn); 252 253 /* Always restart the engine when doing CCE 2D acceleration */ 254 R128CCE_RESET(pScrn, info); 255 R128CCE_START(pScrn, info); 256 } 257 } 258 259 int R128CCEStop(ScrnInfoPtr pScrn) 260 { 261 R128InfoPtr info = R128PTR(pScrn); 262 drmR128CCEStop stop; 263 int ret, i; 264 265 stop.flush = 1; 266 stop.idle = 1; 267 268 ret = drmCommandWrite( info->drmFD, DRM_R128_CCE_STOP, 269 &stop, sizeof(drmR128CCEStop) ); 270 271 if ( ret == 0 ) { 272 return 0; 273 } else if ( errno != EBUSY ) { 274 return -errno; 275 } 276 277 stop.flush = 0; 278 279 i = 0; 280 do { 281 ret = drmCommandWrite( info->drmFD, DRM_R128_CCE_STOP, 282 &stop, sizeof(drmR128CCEStop) ); 283 } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); 284 285 if ( ret == 0 ) { 286 return 0; 287 } else if ( errno != EBUSY ) { 288 return -errno; 289 } 290 291 stop.idle = 0; 292 293 if ( drmCommandWrite( info->drmFD, DRM_R128_CCE_STOP, 294 &stop, sizeof(drmR128CCEStop) )) { 295 return -errno; 296 } else { 297 return 0; 298 } 299 } 300 301 #endif 302 303 304 /* Initialize the acceleration hardware. */ 305 void R128EngineInit(ScrnInfoPtr pScrn) 306 { 307 R128InfoPtr info = R128PTR(pScrn); 308 unsigned char *R128MMIO = info->MMIO; 309 310 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 311 "EngineInit (%d/%d)\n", 312 info->CurrentLayout.pixel_code, 313 info->CurrentLayout.bitsPerPixel)); 314 315 OUTREG(R128_SCALE_3D_CNTL, 0); 316 R128EngineReset(pScrn); 317 318 switch (info->CurrentLayout.pixel_code) { 319 case 8: info->datatype = 2; break; 320 case 15: info->datatype = 3; break; 321 case 16: info->datatype = 4; break; 322 case 24: info->datatype = 5; break; 323 case 32: info->datatype = 6; break; 324 default: 325 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 326 "Unknown depth/bpp = %d/%d (code = %d)\n", 327 info->CurrentLayout.depth, 328 info->CurrentLayout.bitsPerPixel, 329 info->CurrentLayout.pixel_code)); 330 } 331 info->pitch = (info->CurrentLayout.displayWidth / 8) * (info->CurrentLayout.pixel_bytes == 3 ? 3 : 1); 332 333 DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, 334 "Pitch for acceleration = %d\n", info->pitch)); 335 336 R128WaitForFifo(pScrn, 2); 337 OUTREG(R128_DEFAULT_OFFSET, pScrn->fbOffset); 338 OUTREG(R128_DEFAULT_PITCH, info->pitch); 339 340 R128WaitForFifo(pScrn, 4); 341 OUTREG(R128_AUX_SC_CNTL, 0); 342 OUTREG(R128_DEFAULT_SC_BOTTOM_RIGHT, (R128_DEFAULT_SC_RIGHT_MAX 343 | R128_DEFAULT_SC_BOTTOM_MAX)); 344 OUTREG(R128_SC_TOP_LEFT, 0); 345 OUTREG(R128_SC_BOTTOM_RIGHT, (R128_DEFAULT_SC_RIGHT_MAX 346 | R128_DEFAULT_SC_BOTTOM_MAX)); 347 348 info->dp_gui_master_cntl = ((info->datatype << R128_GMC_DST_DATATYPE_SHIFT) 349 | R128_GMC_CLR_CMP_CNTL_DIS 350 | R128_GMC_AUX_CLIP_DIS); 351 R128WaitForFifo(pScrn, 1); 352 OUTREG(R128_DP_GUI_MASTER_CNTL, (info->dp_gui_master_cntl 353 | R128_GMC_BRUSH_SOLID_COLOR 354 | R128_GMC_SRC_DATATYPE_COLOR)); 355 356 R128WaitForFifo(pScrn, 8); 357 OUTREG(R128_DST_BRES_ERR, 0); 358 OUTREG(R128_DST_BRES_INC, 0); 359 OUTREG(R128_DST_BRES_DEC, 0); 360 OUTREG(R128_DP_BRUSH_FRGD_CLR, 0xffffffff); 361 OUTREG(R128_DP_BRUSH_BKGD_CLR, 0x00000000); 362 OUTREG(R128_DP_SRC_FRGD_CLR, 0xffffffff); 363 OUTREG(R128_DP_SRC_BKGD_CLR, 0x00000000); 364 OUTREG(R128_DP_WRITE_MASK, 0xffffffff); 365 366 R128WaitForFifo(pScrn, 1); 367 368 #if X_BYTE_ORDER == X_BIG_ENDIAN 369 /* FIXME: this is a kludge for texture uploads in the 3D driver. Look at 370 * how the radeon driver handles HOST_DATA_SWAP if you want to implement 371 * CCE ImageWrite acceleration or anything needing this bit */ 372 #ifdef R128DRI 373 if (info->directRenderingEnabled) 374 OUTREGP(R128_DP_DATATYPE, 0, ~R128_HOST_BIG_ENDIAN_EN); 375 else 376 #endif 377 OUTREGP(R128_DP_DATATYPE, 378 R128_HOST_BIG_ENDIAN_EN, ~R128_HOST_BIG_ENDIAN_EN); 379 #else /* X_LITTLE_ENDIAN */ 380 OUTREGP(R128_DP_DATATYPE, 0, ~R128_HOST_BIG_ENDIAN_EN); 381 #endif 382 383 #ifdef R128DRI 384 info->sc_left = 0x00000000; 385 info->sc_right = R128_DEFAULT_SC_RIGHT_MAX; 386 info->sc_top = 0x00000000; 387 info->sc_bottom = R128_DEFAULT_SC_BOTTOM_MAX; 388 389 info->re_top_left = 0x00000000; 390 info->re_width_height = ((0x7ff << R128_RE_WIDTH_SHIFT) | 391 (0x7ff << R128_RE_HEIGHT_SHIFT)); 392 393 info->aux_sc_cntl = 0x00000000; 394 #endif 395 396 R128WaitForIdle(pScrn); 397 } 398 399 #ifdef R128DRI 400 401 /* Get an indirect buffer for the CCE 2D acceleration commands. 402 */ 403 drmBufPtr R128CCEGetBuffer( ScrnInfoPtr pScrn ) 404 { 405 R128InfoPtr info = R128PTR(pScrn); 406 drmDMAReq dma; 407 drmBufPtr buf = NULL; 408 int indx = 0; 409 int size = 0; 410 int ret, i = 0; 411 412 #if 0 413 /* FIXME: pScrn->pScreen has not been initialized when this is first 414 called from RADEONSelectBuffer via RADEONDRICPInit. We could use 415 the screen index from pScrn, which is initialized, and then get 416 the screen from screenInfo.screens[index], but that is a hack. */ 417 dma.context = DRIGetContext(pScrn->pScreen); 418 #else 419 dma.context = 0x00000001; /* This is the X server's context */ 420 #endif 421 dma.send_count = 0; 422 dma.send_list = NULL; 423 dma.send_sizes = NULL; 424 dma.flags = 0; 425 dma.request_count = 1; 426 dma.request_size = R128_BUFFER_SIZE; 427 dma.request_list = &indx; 428 dma.request_sizes = &size; 429 dma.granted_count = 0; 430 431 while ( 1 ) { 432 do { 433 ret = drmDMA( info->drmFD, &dma ); 434 if ( ret && ret != -EAGAIN ) { 435 xf86DrvMsg( pScrn->scrnIndex, X_ERROR, 436 "%s: CCE GetBuffer %d\n", __FUNCTION__, ret ); 437 } 438 } while ( ( ret == -EAGAIN ) && ( i++ < R128_TIMEOUT ) ); 439 440 if ( ret == 0 ) { 441 buf = &info->buffers->list[indx]; 442 buf->used = 0; 443 if ( R128_VERBOSE ) { 444 xf86DrvMsg( pScrn->scrnIndex, X_INFO, 445 " GetBuffer returning %d\n", buf->idx ); 446 } 447 return buf; 448 } 449 450 xf86DrvMsg( pScrn->scrnIndex, X_ERROR, 451 "GetBuffer timed out, resetting engine...\n"); 452 R128EngineReset( pScrn ); 453 /* R128EngineRestore( pScrn ); FIXME ??? */ 454 455 /* Always restart the engine when doing CCE 2D acceleration */ 456 R128CCE_RESET( pScrn, info ); 457 R128CCE_START( pScrn, info ); 458 } 459 } 460 461 /* Flush the indirect buffer to the kernel for submission to the card. 462 */ 463 void R128CCEFlushIndirect( ScrnInfoPtr pScrn, int discard ) 464 { 465 R128InfoPtr info = R128PTR(pScrn); 466 drmBufPtr buffer = info->indirectBuffer; 467 int start = info->indirectStart; 468 drmR128Indirect indirect; 469 470 if ( !buffer ) 471 return; 472 473 if ( (start == buffer->used) && !discard ) 474 return; 475 476 indirect.idx = buffer->idx; 477 indirect.start = start; 478 indirect.end = buffer->used; 479 indirect.discard = discard; 480 481 drmCommandWriteRead( info->drmFD, DRM_R128_INDIRECT, 482 &indirect, sizeof(drmR128Indirect)); 483 484 if ( discard ) 485 buffer = info->indirectBuffer = R128CCEGetBuffer( pScrn ); 486 487 /* pad to an even number of dwords */ 488 if (buffer->used & 7) 489 buffer->used = ( buffer->used+7 ) & ~7; 490 491 info->indirectStart = buffer->used; 492 } 493 494 /* Flush and release the indirect buffer. 495 */ 496 void R128CCEReleaseIndirect( ScrnInfoPtr pScrn ) 497 { 498 R128InfoPtr info = R128PTR(pScrn); 499 drmBufPtr buffer = info->indirectBuffer; 500 int start = info->indirectStart; 501 drmR128Indirect indirect; 502 503 info->indirectBuffer = NULL; 504 info->indirectStart = 0; 505 506 if ( !buffer ) 507 return; 508 509 indirect.idx = buffer->idx; 510 indirect.start = start; 511 indirect.end = buffer->used; 512 indirect.discard = 1; 513 514 drmCommandWriteRead( info->drmFD, DRM_R128_INDIRECT, 515 &indirect, sizeof(drmR128Indirect)); 516 } 517 518 #endif 519 520 void R128CopySwap(uint8_t *dst, uint8_t *src, unsigned int size, int swap) 521 { 522 switch(swap) { 523 case APER_0_BIG_ENDIAN_32BPP_SWAP: 524 { 525 unsigned int *d = (unsigned int *)dst; 526 unsigned int *s = (unsigned int *)src; 527 unsigned int nwords = size >> 2; 528 529 for (; nwords > 0; --nwords, ++d, ++s) 530 #ifdef __powerpc__ 531 asm volatile("stwbrx %0,0,%1" : : "r" (*s), "r" (d)); 532 #else 533 *d = ((*s >> 24) & 0xff) | ((*s >> 8) & 0xff00) 534 | ((*s & 0xff00) << 8) | ((*s & 0xff) << 24); 535 #endif 536 return; 537 } 538 case APER_0_BIG_ENDIAN_16BPP_SWAP: 539 { 540 unsigned short *d = (unsigned short *)dst; 541 unsigned short *s = (unsigned short *)src; 542 unsigned int nwords = size >> 1; 543 544 for (; nwords > 0; --nwords, ++d, ++s) 545 #ifdef __powerpc__ 546 asm volatile("sthbrx %0,0,%1" : : "r" (*s), "r" (d)); 547 #else 548 *d = (*s >> 8) | (*s << 8); 549 #endif 550 return; 551 } 552 } 553 if (src != dst) 554 memcpy(dst, src, size); 555 } 556