1/* mga_state.c -- State support for MGA G200/G400 -*- linux-c -*- 2 * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com 3 */ 4/* 5 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 6 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 7 * All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the next 17 * paragraph) shall be included in all copies or substantial portions of the 18 * Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 * 28 * Authors: 29 * Jeff Hartmann <jhartmann@valinux.com> 30 * Keith Whitwell <keith@tungstengraphics.com> 31 * 32 * Rewritten by: 33 * Gareth Hughes <gareth@valinux.com> 34 */ 35 36#include "drmP.h" 37#include "drm.h" 38#include "mga_drm.h" 39#include "mga_drv.h" 40 41/* ================================================================ 42 * DMA hardware state programming functions 43 */ 44 45static void mga_emit_clip_rect(drm_mga_private_t * dev_priv, 46 struct drm_clip_rect * box) 47{ 48 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 49 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 50 unsigned int pitch = dev_priv->front_pitch; 51 DMA_LOCALS; 52 53 BEGIN_DMA(2); 54 55 /* Force reset of DWGCTL on G400 (eliminates clip disable bit). 56 */ 57 if (dev_priv->chipset >= MGA_CARD_TYPE_G400) { 58 DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl, 59 MGA_LEN + MGA_EXEC, 0x80000000, 60 MGA_DWGCTL, ctx->dwgctl, 61 MGA_LEN + MGA_EXEC, 0x80000000); 62 } 63 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 64 MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1, 65 MGA_YTOP, box->y1 * pitch, MGA_YBOT, (box->y2 - 1) * pitch); 66 67 ADVANCE_DMA(); 68} 69 70static __inline__ void mga_g200_emit_context(drm_mga_private_t * dev_priv) 71{ 72 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 73 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 74 DMA_LOCALS; 75 76 BEGIN_DMA(3); 77 78 DMA_BLOCK(MGA_DSTORG, ctx->dstorg, 79 MGA_MACCESS, ctx->maccess, 80 MGA_PLNWT, ctx->plnwt, MGA_DWGCTL, ctx->dwgctl); 81 82 DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl, 83 MGA_FOGCOL, ctx->fogcolor, 84 MGA_WFLAG, ctx->wflag, MGA_ZORG, dev_priv->depth_offset); 85 86 DMA_BLOCK(MGA_FCOL, ctx->fcol, 87 MGA_DMAPAD, 0x00000000, 88 MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000); 89 90 ADVANCE_DMA(); 91} 92 93static __inline__ void mga_g400_emit_context(drm_mga_private_t * dev_priv) 94{ 95 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 96 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 97 DMA_LOCALS; 98 99 BEGIN_DMA(4); 100 101 DMA_BLOCK(MGA_DSTORG, ctx->dstorg, 102 MGA_MACCESS, ctx->maccess, 103 MGA_PLNWT, ctx->plnwt, 104 MGA_DWGCTL, ctx->dwgctl); 105 106 DMA_BLOCK(MGA_ALPHACTRL, ctx->alphactrl, 107 MGA_FOGCOL, ctx->fogcolor, 108 MGA_WFLAG, ctx->wflag, 109 MGA_ZORG, dev_priv->depth_offset); 110 111 DMA_BLOCK(MGA_WFLAG1, ctx->wflag, 112 MGA_TDUALSTAGE0, ctx->tdualstage0, 113 MGA_TDUALSTAGE1, ctx->tdualstage1, 114 MGA_FCOL, ctx->fcol); 115 116 DMA_BLOCK(MGA_STENCIL, ctx->stencil, 117 MGA_STENCILCTL, ctx->stencilctl, 118 MGA_DMAPAD, 0x00000000, 119 MGA_DMAPAD, 0x00000000); 120 121 ADVANCE_DMA(); 122} 123 124static __inline__ void mga_g200_emit_tex0(drm_mga_private_t * dev_priv) 125{ 126 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 127 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; 128 DMA_LOCALS; 129 130 BEGIN_DMA(4); 131 132 DMA_BLOCK(MGA_TEXCTL2, tex->texctl2, 133 MGA_TEXCTL, tex->texctl, 134 MGA_TEXFILTER, tex->texfilter, 135 MGA_TEXBORDERCOL, tex->texbordercol); 136 137 DMA_BLOCK(MGA_TEXORG, tex->texorg, 138 MGA_TEXORG1, tex->texorg1, 139 MGA_TEXORG2, tex->texorg2, 140 MGA_TEXORG3, tex->texorg3); 141 142 DMA_BLOCK(MGA_TEXORG4, tex->texorg4, 143 MGA_TEXWIDTH, tex->texwidth, 144 MGA_TEXHEIGHT, tex->texheight, 145 MGA_WR24, tex->texwidth); 146 147 DMA_BLOCK(MGA_WR34, tex->texheight, 148 MGA_TEXTRANS, 0x0000ffff, 149 MGA_TEXTRANSHIGH, 0x0000ffff, 150 MGA_DMAPAD, 0x00000000); 151 152 ADVANCE_DMA(); 153} 154 155static __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv) 156{ 157 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 158 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; 159 DMA_LOCALS; 160 161/* printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */ 162/* tex->texctl, tex->texctl2); */ 163 164 BEGIN_DMA(6); 165 166 DMA_BLOCK(MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC, 167 MGA_TEXCTL, tex->texctl, 168 MGA_TEXFILTER, tex->texfilter, 169 MGA_TEXBORDERCOL, tex->texbordercol); 170 171 DMA_BLOCK(MGA_TEXORG, tex->texorg, 172 MGA_TEXORG1, tex->texorg1, 173 MGA_TEXORG2, tex->texorg2, 174 MGA_TEXORG3, tex->texorg3); 175 176 DMA_BLOCK(MGA_TEXORG4, tex->texorg4, 177 MGA_TEXWIDTH, tex->texwidth, 178 MGA_TEXHEIGHT, tex->texheight, 179 MGA_WR49, 0x00000000); 180 181 DMA_BLOCK(MGA_WR57, 0x00000000, 182 MGA_WR53, 0x00000000, 183 MGA_WR61, 0x00000000, 184 MGA_WR52, MGA_G400_WR_MAGIC); 185 186 DMA_BLOCK(MGA_WR60, MGA_G400_WR_MAGIC, 187 MGA_WR54, tex->texwidth | MGA_G400_WR_MAGIC, 188 MGA_WR62, tex->texheight | MGA_G400_WR_MAGIC, 189 MGA_DMAPAD, 0x00000000); 190 191 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 192 MGA_DMAPAD, 0x00000000, 193 MGA_TEXTRANS, 0x0000ffff, 194 MGA_TEXTRANSHIGH, 0x0000ffff); 195 196 ADVANCE_DMA(); 197} 198 199static __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv) 200{ 201 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 202 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1]; 203 DMA_LOCALS; 204 205/* printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg, */ 206/* tex->texctl, tex->texctl2); */ 207 208 BEGIN_DMA(5); 209 210 DMA_BLOCK(MGA_TEXCTL2, (tex->texctl2 | 211 MGA_MAP1_ENABLE | 212 MGA_G400_TC2_MAGIC), 213 MGA_TEXCTL, tex->texctl, 214 MGA_TEXFILTER, tex->texfilter, 215 MGA_TEXBORDERCOL, tex->texbordercol); 216 217 DMA_BLOCK(MGA_TEXORG, tex->texorg, 218 MGA_TEXORG1, tex->texorg1, 219 MGA_TEXORG2, tex->texorg2, 220 MGA_TEXORG3, tex->texorg3); 221 222 DMA_BLOCK(MGA_TEXORG4, tex->texorg4, 223 MGA_TEXWIDTH, tex->texwidth, 224 MGA_TEXHEIGHT, tex->texheight, 225 MGA_WR49, 0x00000000); 226 227 DMA_BLOCK(MGA_WR57, 0x00000000, 228 MGA_WR53, 0x00000000, 229 MGA_WR61, 0x00000000, 230 MGA_WR52, tex->texwidth | MGA_G400_WR_MAGIC); 231 232 DMA_BLOCK(MGA_WR60, tex->texheight | MGA_G400_WR_MAGIC, 233 MGA_TEXTRANS, 0x0000ffff, 234 MGA_TEXTRANSHIGH, 0x0000ffff, 235 MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC); 236 237 ADVANCE_DMA(); 238} 239 240static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv) 241{ 242 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 243 unsigned int pipe = sarea_priv->warp_pipe; 244 DMA_LOCALS; 245 246 BEGIN_DMA(3); 247 248 DMA_BLOCK(MGA_WIADDR, MGA_WMODE_SUSPEND, 249 MGA_WVRTXSZ, 0x00000007, 250 MGA_WFLAG, 0x00000000, 251 MGA_WR24, 0x00000000); 252 253 DMA_BLOCK(MGA_WR25, 0x00000100, 254 MGA_WR34, 0x00000000, 255 MGA_WR42, 0x0000ffff, 256 MGA_WR60, 0x0000ffff); 257 258 /* Padding required to to hardware bug. 259 */ 260 DMA_BLOCK(MGA_DMAPAD, 0xffffffff, 261 MGA_DMAPAD, 0xffffffff, 262 MGA_DMAPAD, 0xffffffff, 263 MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] | 264 MGA_WMODE_START | dev_priv->wagp_enable)); 265 266 ADVANCE_DMA(); 267} 268 269static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv) 270{ 271 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 272 unsigned int pipe = sarea_priv->warp_pipe; 273 DMA_LOCALS; 274 275/* printk("mga_g400_emit_pipe %x\n", pipe); */ 276 277 BEGIN_DMA(10); 278 279 DMA_BLOCK(MGA_WIADDR2, MGA_WMODE_SUSPEND, 280 MGA_DMAPAD, 0x00000000, 281 MGA_DMAPAD, 0x00000000, 282 MGA_DMAPAD, 0x00000000); 283 284 if (pipe & MGA_T2) { 285 DMA_BLOCK(MGA_WVRTXSZ, 0x00001e09, 286 MGA_DMAPAD, 0x00000000, 287 MGA_DMAPAD, 0x00000000, 288 MGA_DMAPAD, 0x00000000); 289 290 DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000, 291 MGA_WACCEPTSEQ, 0x00000000, 292 MGA_WACCEPTSEQ, 0x00000000, 293 MGA_WACCEPTSEQ, 0x1e000000); 294 } else { 295 if (dev_priv->warp_pipe & MGA_T2) { 296 /* Flush the WARP pipe */ 297 DMA_BLOCK(MGA_YDST, 0x00000000, 298 MGA_FXLEFT, 0x00000000, 299 MGA_FXRIGHT, 0x00000001, 300 MGA_DWGCTL, MGA_DWGCTL_FLUSH); 301 302 DMA_BLOCK(MGA_LEN + MGA_EXEC, 0x00000001, 303 MGA_DWGSYNC, 0x00007000, 304 MGA_TEXCTL2, MGA_G400_TC2_MAGIC, 305 MGA_LEN + MGA_EXEC, 0x00000000); 306 307 DMA_BLOCK(MGA_TEXCTL2, (MGA_DUALTEX | 308 MGA_G400_TC2_MAGIC), 309 MGA_LEN + MGA_EXEC, 0x00000000, 310 MGA_TEXCTL2, MGA_G400_TC2_MAGIC, 311 MGA_DMAPAD, 0x00000000); 312 } 313 314 DMA_BLOCK(MGA_WVRTXSZ, 0x00001807, 315 MGA_DMAPAD, 0x00000000, 316 MGA_DMAPAD, 0x00000000, 317 MGA_DMAPAD, 0x00000000); 318 319 DMA_BLOCK(MGA_WACCEPTSEQ, 0x00000000, 320 MGA_WACCEPTSEQ, 0x00000000, 321 MGA_WACCEPTSEQ, 0x00000000, 322 MGA_WACCEPTSEQ, 0x18000000); 323 } 324 325 DMA_BLOCK(MGA_WFLAG, 0x00000000, 326 MGA_WFLAG1, 0x00000000, 327 MGA_WR56, MGA_G400_WR56_MAGIC, 328 MGA_DMAPAD, 0x00000000); 329 330 DMA_BLOCK(MGA_WR49, 0x00000000, /* tex0 */ 331 MGA_WR57, 0x00000000, /* tex0 */ 332 MGA_WR53, 0x00000000, /* tex1 */ 333 MGA_WR61, 0x00000000); /* tex1 */ 334 335 DMA_BLOCK(MGA_WR54, MGA_G400_WR_MAGIC, /* tex0 width */ 336 MGA_WR62, MGA_G400_WR_MAGIC, /* tex0 height */ 337 MGA_WR52, MGA_G400_WR_MAGIC, /* tex1 width */ 338 MGA_WR60, MGA_G400_WR_MAGIC); /* tex1 height */ 339 340 /* Padding required to to hardware bug */ 341 DMA_BLOCK(MGA_DMAPAD, 0xffffffff, 342 MGA_DMAPAD, 0xffffffff, 343 MGA_DMAPAD, 0xffffffff, 344 MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] | 345 MGA_WMODE_START | dev_priv->wagp_enable)); 346 347 ADVANCE_DMA(); 348} 349 350static void mga_g200_emit_state(drm_mga_private_t * dev_priv) 351{ 352 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 353 unsigned int dirty = sarea_priv->dirty; 354 355 if (sarea_priv->warp_pipe != dev_priv->warp_pipe) { 356 mga_g200_emit_pipe(dev_priv); 357 dev_priv->warp_pipe = sarea_priv->warp_pipe; 358 } 359 360 if (dirty & MGA_UPLOAD_CONTEXT) { 361 mga_g200_emit_context(dev_priv); 362 sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT; 363 } 364 365 if (dirty & MGA_UPLOAD_TEX0) { 366 mga_g200_emit_tex0(dev_priv); 367 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; 368 } 369} 370 371static void mga_g400_emit_state(drm_mga_private_t * dev_priv) 372{ 373 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 374 unsigned int dirty = sarea_priv->dirty; 375 int multitex = sarea_priv->warp_pipe & MGA_T2; 376 377 if (sarea_priv->warp_pipe != dev_priv->warp_pipe) { 378 mga_g400_emit_pipe(dev_priv); 379 dev_priv->warp_pipe = sarea_priv->warp_pipe; 380 } 381 382 if (dirty & MGA_UPLOAD_CONTEXT) { 383 mga_g400_emit_context(dev_priv); 384 sarea_priv->dirty &= ~MGA_UPLOAD_CONTEXT; 385 } 386 387 if (dirty & MGA_UPLOAD_TEX0) { 388 mga_g400_emit_tex0(dev_priv); 389 sarea_priv->dirty &= ~MGA_UPLOAD_TEX0; 390 } 391 392 if ((dirty & MGA_UPLOAD_TEX1) && multitex) { 393 mga_g400_emit_tex1(dev_priv); 394 sarea_priv->dirty &= ~MGA_UPLOAD_TEX1; 395 } 396} 397 398/* ================================================================ 399 * SAREA state verification 400 */ 401 402/* Disallow all write destinations except the front and backbuffer. 403 */ 404static int mga_verify_context(drm_mga_private_t * dev_priv) 405{ 406 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 407 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 408 409 if (ctx->dstorg != dev_priv->front_offset && 410 ctx->dstorg != dev_priv->back_offset) { 411 DRM_ERROR("*** bad DSTORG: %x (front %x, back %x)\n\n", 412 ctx->dstorg, dev_priv->front_offset, 413 dev_priv->back_offset); 414 ctx->dstorg = 0; 415 return -EINVAL; 416 } 417 418 return 0; 419} 420 421/* Disallow texture reads from PCI space. 422 */ 423static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit) 424{ 425 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 426 drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit]; 427 unsigned int org; 428 429 org = tex->texorg & (MGA_TEXORGMAP_MASK | MGA_TEXORGACC_MASK); 430 431 if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) { 432 DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit); 433 tex->texorg = 0; 434 return -EINVAL; 435 } 436 437 return 0; 438} 439 440static int mga_verify_state(drm_mga_private_t * dev_priv) 441{ 442 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 443 unsigned int dirty = sarea_priv->dirty; 444 int ret = 0; 445 446 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 447 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 448 449 if (dirty & MGA_UPLOAD_CONTEXT) 450 ret |= mga_verify_context(dev_priv); 451 452 if (dirty & MGA_UPLOAD_TEX0) 453 ret |= mga_verify_tex(dev_priv, 0); 454 455 if (dev_priv->chipset >= MGA_CARD_TYPE_G400) { 456 if (dirty & MGA_UPLOAD_TEX1) 457 ret |= mga_verify_tex(dev_priv, 1); 458 459 if (dirty & MGA_UPLOAD_PIPE) 460 ret |= (sarea_priv->warp_pipe > MGA_MAX_G400_PIPES); 461 } else { 462 if (dirty & MGA_UPLOAD_PIPE) 463 ret |= (sarea_priv->warp_pipe > MGA_MAX_G200_PIPES); 464 } 465 466 return (ret == 0); 467} 468 469static int mga_verify_iload(drm_mga_private_t * dev_priv, 470 unsigned int dstorg, unsigned int length) 471{ 472 if (dstorg < dev_priv->texture_offset || 473 dstorg + length > (dev_priv->texture_offset + 474 dev_priv->texture_size)) { 475 DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg); 476 return -EINVAL; 477 } 478 479 if (length & MGA_ILOAD_MASK) { 480 DRM_ERROR("*** bad iload length: 0x%x\n", 481 length & MGA_ILOAD_MASK); 482 return -EINVAL; 483 } 484 485 return 0; 486} 487 488static int mga_verify_blit(drm_mga_private_t * dev_priv, 489 unsigned int srcorg, unsigned int dstorg) 490{ 491 if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) || 492 (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) { 493 DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg); 494 return -EINVAL; 495 } 496 return 0; 497} 498 499/* ================================================================ 500 * 501 */ 502 503static void mga_dma_dispatch_clear(struct drm_device * dev, drm_mga_clear_t * clear) 504{ 505 drm_mga_private_t *dev_priv = dev->dev_private; 506 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 507 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 508 struct drm_clip_rect *pbox = sarea_priv->boxes; 509 int nbox = sarea_priv->nbox; 510 int i; 511 DMA_LOCALS; 512 DRM_DEBUG("\n"); 513 514 BEGIN_DMA(1); 515 516 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 517 MGA_DMAPAD, 0x00000000, 518 MGA_DWGSYNC, 0x00007100, 519 MGA_DWGSYNC, 0x00007000); 520 521 ADVANCE_DMA(); 522 523 for (i = 0; i < nbox; i++) { 524 struct drm_clip_rect *box = &pbox[i]; 525 u32 height = box->y2 - box->y1; 526 527 DRM_DEBUG(" from=%d,%d to=%d,%d\n", 528 box->x1, box->y1, box->x2, box->y2); 529 530 if (clear->flags & MGA_FRONT) { 531 BEGIN_DMA(2); 532 533 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 534 MGA_PLNWT, clear->color_mask, 535 MGA_YDSTLEN, (box->y1 << 16) | height, 536 MGA_FXBNDRY, (box->x2 << 16) | box->x1); 537 538 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 539 MGA_FCOL, clear->clear_color, 540 MGA_DSTORG, dev_priv->front_offset, 541 MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd); 542 543 ADVANCE_DMA(); 544 } 545 546 if (clear->flags & MGA_BACK) { 547 BEGIN_DMA(2); 548 549 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 550 MGA_PLNWT, clear->color_mask, 551 MGA_YDSTLEN, (box->y1 << 16) | height, 552 MGA_FXBNDRY, (box->x2 << 16) | box->x1); 553 554 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 555 MGA_FCOL, clear->clear_color, 556 MGA_DSTORG, dev_priv->back_offset, 557 MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd); 558 559 ADVANCE_DMA(); 560 } 561 562 if (clear->flags & MGA_DEPTH) { 563 BEGIN_DMA(2); 564 565 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 566 MGA_PLNWT, clear->depth_mask, 567 MGA_YDSTLEN, (box->y1 << 16) | height, 568 MGA_FXBNDRY, (box->x2 << 16) | box->x1); 569 570 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 571 MGA_FCOL, clear->clear_depth, 572 MGA_DSTORG, dev_priv->depth_offset, 573 MGA_DWGCTL + MGA_EXEC, dev_priv->clear_cmd); 574 575 ADVANCE_DMA(); 576 } 577 578 } 579 580 BEGIN_DMA(1); 581 582 /* Force reset of DWGCTL */ 583 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 584 MGA_DMAPAD, 0x00000000, 585 MGA_PLNWT, ctx->plnwt, 586 MGA_DWGCTL, ctx->dwgctl); 587 588 ADVANCE_DMA(); 589 590 FLUSH_DMA(); 591} 592 593static void mga_dma_dispatch_swap(struct drm_device * dev) 594{ 595 drm_mga_private_t *dev_priv = dev->dev_private; 596 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 597 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 598 struct drm_clip_rect *pbox = sarea_priv->boxes; 599 int nbox = sarea_priv->nbox; 600 int i; 601 DMA_LOCALS; 602 DRM_DEBUG("\n"); 603 604 sarea_priv->last_frame.head = dev_priv->prim.tail; 605 sarea_priv->last_frame.wrap = dev_priv->prim.last_wrap; 606 607 BEGIN_DMA(4 + nbox); 608 609 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 610 MGA_DMAPAD, 0x00000000, 611 MGA_DWGSYNC, 0x00007100, 612 MGA_DWGSYNC, 0x00007000); 613 614 DMA_BLOCK(MGA_DSTORG, dev_priv->front_offset, 615 MGA_MACCESS, dev_priv->maccess, 616 MGA_SRCORG, dev_priv->back_offset, 617 MGA_AR5, dev_priv->front_pitch); 618 619 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 620 MGA_DMAPAD, 0x00000000, 621 MGA_PLNWT, 0xffffffff, 622 MGA_DWGCTL, MGA_DWGCTL_COPY); 623 624 for (i = 0; i < nbox; i++) { 625 struct drm_clip_rect *box = &pbox[i]; 626 u32 height = box->y2 - box->y1; 627 u32 start = box->y1 * dev_priv->front_pitch; 628 629 DRM_DEBUG(" from=%d,%d to=%d,%d\n", 630 box->x1, box->y1, box->x2, box->y2); 631 632 DMA_BLOCK(MGA_AR0, start + box->x2 - 1, 633 MGA_AR3, start + box->x1, 634 MGA_FXBNDRY, ((box->x2 - 1) << 16) | box->x1, 635 MGA_YDSTLEN + MGA_EXEC, (box->y1 << 16) | height); 636 } 637 638 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 639 MGA_PLNWT, ctx->plnwt, 640 MGA_SRCORG, dev_priv->front_offset, 641 MGA_DWGCTL, ctx->dwgctl); 642 643 ADVANCE_DMA(); 644 645 FLUSH_DMA(); 646 647 DRM_DEBUG("... done.\n"); 648} 649 650static void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf) 651{ 652 drm_mga_private_t *dev_priv = dev->dev_private; 653 drm_mga_buf_priv_t *buf_priv = buf->dev_private; 654 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 655 u32 address = (u32) buf->bus_address; 656 u32 length = (u32) buf->used; 657 int i = 0; 658 DMA_LOCALS; 659 DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used); 660 661 if (buf->used) { 662 buf_priv->dispatched = 1; 663 664 MGA_EMIT_STATE(dev_priv, sarea_priv->dirty); 665 666 do { 667 if (i < sarea_priv->nbox) { 668 mga_emit_clip_rect(dev_priv, 669 &sarea_priv->boxes[i]); 670 } 671 672 BEGIN_DMA(1); 673 674 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 675 MGA_DMAPAD, 0x00000000, 676 MGA_SECADDRESS, (address | 677 MGA_DMA_VERTEX), 678 MGA_SECEND, ((address + length) | 679 dev_priv->dma_access)); 680 681 ADVANCE_DMA(); 682 } while (++i < sarea_priv->nbox); 683 } 684 685 if (buf_priv->discard) { 686 AGE_BUFFER(buf_priv); 687 buf->pending = 0; 688 buf->used = 0; 689 buf_priv->dispatched = 0; 690 691 mga_freelist_put(dev, buf); 692 } 693 694 FLUSH_DMA(); 695} 696 697static void mga_dma_dispatch_indices(struct drm_device * dev, struct drm_buf * buf, 698 unsigned int start, unsigned int end) 699{ 700 drm_mga_private_t *dev_priv = dev->dev_private; 701 drm_mga_buf_priv_t *buf_priv = buf->dev_private; 702 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 703 u32 address = (u32) buf->bus_address; 704 int i = 0; 705 DMA_LOCALS; 706 DRM_DEBUG("buf=%d start=%d end=%d\n", buf->idx, start, end); 707 708 if (start != end) { 709 buf_priv->dispatched = 1; 710 711 MGA_EMIT_STATE(dev_priv, sarea_priv->dirty); 712 713 do { 714 if (i < sarea_priv->nbox) { 715 mga_emit_clip_rect(dev_priv, 716 &sarea_priv->boxes[i]); 717 } 718 719 BEGIN_DMA(1); 720 721 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 722 MGA_DMAPAD, 0x00000000, 723 MGA_SETUPADDRESS, address + start, 724 MGA_SETUPEND, ((address + end) | 725 dev_priv->dma_access)); 726 727 ADVANCE_DMA(); 728 } while (++i < sarea_priv->nbox); 729 } 730 731 if (buf_priv->discard) { 732 AGE_BUFFER(buf_priv); 733 buf->pending = 0; 734 buf->used = 0; 735 buf_priv->dispatched = 0; 736 737 mga_freelist_put(dev, buf); 738 } 739 740 FLUSH_DMA(); 741} 742 743/* This copies a 64 byte aligned agp region to the frambuffer with a 744 * standard blit, the ioctl needs to do checking. 745 */ 746static void mga_dma_dispatch_iload(struct drm_device * dev, struct drm_buf * buf, 747 unsigned int dstorg, unsigned int length) 748{ 749 drm_mga_private_t *dev_priv = dev->dev_private; 750 drm_mga_buf_priv_t *buf_priv = buf->dev_private; 751 drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state; 752 u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM; 753 u32 y2; 754 DMA_LOCALS; 755 DRM_DEBUG("buf=%d used=%d\n", buf->idx, buf->used); 756 757 y2 = length / 64; 758 759 BEGIN_DMA(5); 760 761 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 762 MGA_DMAPAD, 0x00000000, 763 MGA_DWGSYNC, 0x00007100, 764 MGA_DWGSYNC, 0x00007000); 765 766 DMA_BLOCK(MGA_DSTORG, dstorg, 767 MGA_MACCESS, 0x00000000, 768 MGA_SRCORG, srcorg, 769 MGA_AR5, 64); 770 771 DMA_BLOCK(MGA_PITCH, 64, 772 MGA_PLNWT, 0xffffffff, 773 MGA_DMAPAD, 0x00000000, 774 MGA_DWGCTL, MGA_DWGCTL_COPY); 775 776 DMA_BLOCK(MGA_AR0, 63, 777 MGA_AR3, 0, 778 MGA_FXBNDRY, (63 << 16) | 0, 779 MGA_YDSTLEN + MGA_EXEC, y2); 780 781 DMA_BLOCK(MGA_PLNWT, ctx->plnwt, 782 MGA_SRCORG, dev_priv->front_offset, 783 MGA_PITCH, dev_priv->front_pitch, 784 MGA_DWGSYNC, 0x00007000); 785 786 ADVANCE_DMA(); 787 788 AGE_BUFFER(buf_priv); 789 790 buf->pending = 0; 791 buf->used = 0; 792 buf_priv->dispatched = 0; 793 794 mga_freelist_put(dev, buf); 795 796 FLUSH_DMA(); 797} 798 799static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit) 800{ 801 drm_mga_private_t *dev_priv = dev->dev_private; 802 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 803 drm_mga_context_regs_t *ctx = &sarea_priv->context_state; 804 struct drm_clip_rect *pbox = sarea_priv->boxes; 805 int nbox = sarea_priv->nbox; 806 u32 scandir = 0, i; 807 DMA_LOCALS; 808 DRM_DEBUG("\n"); 809 810 BEGIN_DMA(4 + nbox); 811 812 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 813 MGA_DMAPAD, 0x00000000, 814 MGA_DWGSYNC, 0x00007100, 815 MGA_DWGSYNC, 0x00007000); 816 817 DMA_BLOCK(MGA_DWGCTL, MGA_DWGCTL_COPY, 818 MGA_PLNWT, blit->planemask, 819 MGA_SRCORG, blit->srcorg, 820 MGA_DSTORG, blit->dstorg); 821 822 DMA_BLOCK(MGA_SGN, scandir, 823 MGA_MACCESS, dev_priv->maccess, 824 MGA_AR5, blit->ydir * blit->src_pitch, 825 MGA_PITCH, blit->dst_pitch); 826 827 for (i = 0; i < nbox; i++) { 828 int srcx = pbox[i].x1 + blit->delta_sx; 829 int srcy = pbox[i].y1 + blit->delta_sy; 830 int dstx = pbox[i].x1 + blit->delta_dx; 831 int dsty = pbox[i].y1 + blit->delta_dy; 832 int h = pbox[i].y2 - pbox[i].y1; 833 int w = pbox[i].x2 - pbox[i].x1 - 1; 834 int start; 835 836 if (blit->ydir == -1) { 837 srcy = blit->height - srcy - 1; 838 } 839 840 start = srcy * blit->src_pitch + srcx; 841 842 DMA_BLOCK(MGA_AR0, start + w, 843 MGA_AR3, start, 844 MGA_FXBNDRY, ((dstx + w) << 16) | (dstx & 0xffff), 845 MGA_YDSTLEN + MGA_EXEC, (dsty << 16) | h); 846 } 847 848 /* Do something to flush AGP? 849 */ 850 851 /* Force reset of DWGCTL */ 852 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 853 MGA_PLNWT, ctx->plnwt, 854 MGA_PITCH, dev_priv->front_pitch, 855 MGA_DWGCTL, ctx->dwgctl); 856 857 ADVANCE_DMA(); 858} 859 860/* ================================================================ 861 * 862 */ 863 864static int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) 865{ 866 drm_mga_private_t *dev_priv = dev->dev_private; 867 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 868 drm_mga_clear_t *clear = data; 869 870 LOCK_TEST_WITH_RETURN(dev, file_priv); 871 872 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 873 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 874 875 WRAP_TEST_WITH_RETURN(dev_priv); 876 877 mga_dma_dispatch_clear(dev, clear); 878 879 /* Make sure we restore the 3D state next time. 880 */ 881 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 882 883 return 0; 884} 885 886static int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) 887{ 888 drm_mga_private_t *dev_priv = dev->dev_private; 889 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 890 891 LOCK_TEST_WITH_RETURN(dev, file_priv); 892 893 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 894 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 895 896 WRAP_TEST_WITH_RETURN(dev_priv); 897 898 mga_dma_dispatch_swap(dev); 899 900 /* Make sure we restore the 3D state next time. 901 */ 902 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 903 904 return 0; 905} 906 907static int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) 908{ 909 drm_mga_private_t *dev_priv = dev->dev_private; 910 struct drm_device_dma *dma = dev->dma; 911 struct drm_buf *buf; 912 drm_mga_buf_priv_t *buf_priv; 913 drm_mga_vertex_t *vertex = data; 914 915 LOCK_TEST_WITH_RETURN(dev, file_priv); 916 917 if (vertex->idx < 0 || vertex->idx > dma->buf_count) 918 return -EINVAL; 919 buf = dma->buflist[vertex->idx]; 920 buf_priv = buf->dev_private; 921 922 buf->used = vertex->used; 923 buf_priv->discard = vertex->discard; 924 925 if (!mga_verify_state(dev_priv)) { 926 if (vertex->discard) { 927 if (buf_priv->dispatched == 1) 928 AGE_BUFFER(buf_priv); 929 buf_priv->dispatched = 0; 930 mga_freelist_put(dev, buf); 931 } 932 return -EINVAL; 933 } 934 935 WRAP_TEST_WITH_RETURN(dev_priv); 936 937 mga_dma_dispatch_vertex(dev, buf); 938 939 return 0; 940} 941 942static int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) 943{ 944 drm_mga_private_t *dev_priv = dev->dev_private; 945 struct drm_device_dma *dma = dev->dma; 946 struct drm_buf *buf; 947 drm_mga_buf_priv_t *buf_priv; 948 drm_mga_indices_t *indices = data; 949 950 LOCK_TEST_WITH_RETURN(dev, file_priv); 951 952 if (indices->idx < 0 || indices->idx > dma->buf_count) 953 return -EINVAL; 954 955 buf = dma->buflist[indices->idx]; 956 buf_priv = buf->dev_private; 957 958 buf_priv->discard = indices->discard; 959 960 if (!mga_verify_state(dev_priv)) { 961 if (indices->discard) { 962 if (buf_priv->dispatched == 1) 963 AGE_BUFFER(buf_priv); 964 buf_priv->dispatched = 0; 965 mga_freelist_put(dev, buf); 966 } 967 return -EINVAL; 968 } 969 970 WRAP_TEST_WITH_RETURN(dev_priv); 971 972 mga_dma_dispatch_indices(dev, buf, indices->start, indices->end); 973 974 return 0; 975} 976 977static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv) 978{ 979 struct drm_device_dma *dma = dev->dma; 980 drm_mga_private_t *dev_priv = dev->dev_private; 981 struct drm_buf *buf; 982 drm_mga_iload_t *iload = data; 983 DRM_DEBUG("\n"); 984 985 LOCK_TEST_WITH_RETURN(dev, file_priv); 986 987#if 0 988 if (mga_do_wait_for_idle(dev_priv) < 0) { 989 if (MGA_DMA_DEBUG) 990 DRM_INFO("-EBUSY\n"); 991 return -EBUSY; 992 } 993#endif 994 if (iload->idx < 0 || iload->idx > dma->buf_count) 995 return -EINVAL; 996 997 buf = dma->buflist[iload->idx]; 998 999 if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) { 1000 mga_freelist_put(dev, buf); 1001 return -EINVAL; 1002 } 1003 1004 WRAP_TEST_WITH_RETURN(dev_priv); 1005 1006 mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length); 1007 1008 /* Make sure we restore the 3D state next time. 1009 */ 1010 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 1011 1012 return 0; 1013} 1014 1015static int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv) 1016{ 1017 drm_mga_private_t *dev_priv = dev->dev_private; 1018 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 1019 drm_mga_blit_t *blit = data; 1020 DRM_DEBUG("\n"); 1021 1022 LOCK_TEST_WITH_RETURN(dev, file_priv); 1023 1024 if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) 1025 sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; 1026 1027 if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg)) 1028 return -EINVAL; 1029 1030 WRAP_TEST_WITH_RETURN(dev_priv); 1031 1032 mga_dma_dispatch_blit(dev, blit); 1033 1034 /* Make sure we restore the 3D state next time. 1035 */ 1036 dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; 1037 1038 return 0; 1039} 1040 1041static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) 1042{ 1043 drm_mga_private_t *dev_priv = dev->dev_private; 1044 drm_mga_getparam_t *param = data; 1045 int value; 1046 1047 if (!dev_priv) { 1048 DRM_ERROR("called with no initialization\n"); 1049 return -EINVAL; 1050 } 1051 1052 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 1053 1054 switch (param->param) { 1055 case MGA_PARAM_IRQ_NR: 1056 value = dev->irq; 1057 break; 1058 case MGA_PARAM_CARD_TYPE: 1059 value = dev_priv->chipset; 1060 break; 1061 default: 1062 return -EINVAL; 1063 } 1064 1065 if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { 1066 DRM_ERROR("copy_to_user\n"); 1067 return -EFAULT; 1068 } 1069 1070 return 0; 1071} 1072 1073static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv) 1074{ 1075 drm_mga_private_t *dev_priv = dev->dev_private; 1076 u32 *fence = data; 1077 DMA_LOCALS; 1078 1079 if (!dev_priv) { 1080 DRM_ERROR("called with no initialization\n"); 1081 return -EINVAL; 1082 } 1083 1084 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 1085 1086 /* I would normal do this assignment in the declaration of fence, 1087 * but dev_priv may be NULL. 1088 */ 1089 1090 *fence = dev_priv->next_fence_to_post; 1091 dev_priv->next_fence_to_post++; 1092 1093 BEGIN_DMA(1); 1094 DMA_BLOCK(MGA_DMAPAD, 0x00000000, 1095 MGA_DMAPAD, 0x00000000, 1096 MGA_DMAPAD, 0x00000000, 1097 MGA_SOFTRAP, 0x00000000); 1098 ADVANCE_DMA(); 1099 1100 return 0; 1101} 1102 1103static int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file *file_priv) 1104{ 1105 drm_mga_private_t *dev_priv = dev->dev_private; 1106 u32 *fence = data; 1107 1108 if (!dev_priv) { 1109 DRM_ERROR("called with no initialization\n"); 1110 return -EINVAL; 1111 } 1112 1113 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 1114 1115 mga_driver_fence_wait(dev, fence); 1116 1117 return 0; 1118} 1119 1120struct drm_ioctl_desc mga_ioctls[] = { 1121 DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 1122 DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH), 1123 DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH), 1124 DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH), 1125 DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH), 1126 DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH), 1127 DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH), 1128 DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH), 1129 DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH), 1130 DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH), 1131 DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH), 1132 DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH), 1133 DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 1134 1135}; 1136 1137int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); 1138