mach64_state.c revision 145132
1/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*- 2 * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com 3 * 4 * Copyright 2000 Gareth Hughes 5 * Copyright 2002-2003 Leif Delgass 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Gareth Hughes <gareth@valinux.com> 28 * Leif Delgass <ldelgass@retinalburn.net> 29 * Jos���Fonseca <j_r_fonseca@yahoo.co.uk> 30 * 31 * $FreeBSD: head/sys/dev/drm/mach64_state.c 145132 2005-04-16 03:44:47Z anholt $ 32 */ 33 34#include "dev/drm/drmP.h" 35#include "dev/drm/drm.h" 36#include "dev/drm/mach64_drm.h" 37#include "dev/drm/mach64_drv.h" 38 39/* Interface history: 40 * 41 * 1.0 - Initial mach64 DRM 42 * 43 */ 44drm_ioctl_desc_t mach64_ioctls[] = { 45 [DRM_IOCTL_NR(DRM_MACH64_INIT)] = {mach64_dma_init, 1, 1}, 46 [DRM_IOCTL_NR(DRM_MACH64_CLEAR)] = {mach64_dma_clear, 1, 0}, 47 [DRM_IOCTL_NR(DRM_MACH64_SWAP)] = {mach64_dma_swap, 1, 0}, 48 [DRM_IOCTL_NR(DRM_MACH64_IDLE)] = {mach64_dma_idle, 1, 0}, 49 [DRM_IOCTL_NR(DRM_MACH64_RESET)] = {mach64_engine_reset, 1, 0}, 50 [DRM_IOCTL_NR(DRM_MACH64_VERTEX)] = {mach64_dma_vertex, 1, 0}, 51 [DRM_IOCTL_NR(DRM_MACH64_BLIT)] = {mach64_dma_blit, 1, 0}, 52 [DRM_IOCTL_NR(DRM_MACH64_FLUSH)] = {mach64_dma_flush, 1, 0}, 53 [DRM_IOCTL_NR(DRM_MACH64_GETPARAM)] = {mach64_get_param, 1, 0}, 54}; 55 56int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls); 57 58/* ================================================================ 59 * DMA hardware state programming functions 60 */ 61 62static void mach64_print_dirty(const char *msg, unsigned int flags) 63{ 64 DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n", 65 msg, 66 flags, 67 (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " : 68 "", 69 (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "", 70 (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " : 71 "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "", 72 (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " : 73 "", 74 (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "", 75 (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "", 76 (flags & MACH64_UPLOAD_MISC) ? "misc, " : "", 77 (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "", 78 (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "", 79 (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "", 80 (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : ""); 81} 82 83/* Mach64 doesn't have hardware cliprects, just one hardware scissor, 84 * so the GL scissor is intersected with each cliprect here 85 */ 86/* This function returns 0 on success, 1 for no intersection, and 87 * negative for an error 88 */ 89static int mach64_emit_cliprect(DRMFILE filp, drm_mach64_private_t * dev_priv, 90 drm_clip_rect_t * box) 91{ 92 u32 sc_left_right, sc_top_bottom; 93 drm_clip_rect_t scissor; 94 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 95 drm_mach64_context_regs_t *regs = &sarea_priv->context_state; 96 DMALOCALS; 97 98 DRM_DEBUG("%s: box=%p\n", __FUNCTION__, box); 99 100 /* Get GL scissor */ 101 /* FIXME: store scissor in SAREA as a cliprect instead of in 102 * hardware format, or do intersection client-side 103 */ 104 scissor.x1 = regs->sc_left_right & 0xffff; 105 scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16; 106 scissor.y1 = regs->sc_top_bottom & 0xffff; 107 scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16; 108 109 /* Intersect GL scissor with cliprect */ 110 if (box->x1 > scissor.x1) 111 scissor.x1 = box->x1; 112 if (box->y1 > scissor.y1) 113 scissor.y1 = box->y1; 114 if (box->x2 < scissor.x2) 115 scissor.x2 = box->x2; 116 if (box->y2 < scissor.y2) 117 scissor.y2 = box->y2; 118 /* positive return means skip */ 119 if (scissor.x1 >= scissor.x2) 120 return 1; 121 if (scissor.y1 >= scissor.y2) 122 return 1; 123 124 DMAGETPTR(filp, dev_priv, 2); /* returns on failure to get buffer */ 125 126 sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16)); 127 sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16)); 128 129 DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right); 130 DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom); 131 132 DMAADVANCE(dev_priv, 1); 133 134 return 0; 135} 136 137static __inline__ int mach64_emit_state(DRMFILE filp, 138 drm_mach64_private_t * dev_priv) 139{ 140 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 141 drm_mach64_context_regs_t *regs = &sarea_priv->context_state; 142 unsigned int dirty = sarea_priv->dirty; 143 u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2); 144 DMALOCALS; 145 146 if (MACH64_VERBOSE) { 147 mach64_print_dirty(__FUNCTION__, dirty); 148 } else { 149 DRM_DEBUG("%s: dirty=0x%08x\n", __FUNCTION__, dirty); 150 } 151 152 DMAGETPTR(filp, dev_priv, 17); /* returns on failure to get buffer */ 153 154 if (dirty & MACH64_UPLOAD_MISC) { 155 DMAOUTREG(MACH64_DP_MIX, regs->dp_mix); 156 DMAOUTREG(MACH64_DP_SRC, regs->dp_src); 157 DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl); 158 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl); 159 sarea_priv->dirty &= ~MACH64_UPLOAD_MISC; 160 } 161 162 if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) { 163 DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch); 164 sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH; 165 } 166 if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) { 167 DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch); 168 sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH; 169 } 170 if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) { 171 DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl); 172 DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl); 173 sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL; 174 } 175 if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) { 176 DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl); 177 sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL; 178 } 179 if (dirty & MACH64_UPLOAD_DP_FOG_CLR) { 180 DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr); 181 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR; 182 } 183 if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) { 184 DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask); 185 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK; 186 } 187 if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) { 188 DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width); 189 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH; 190 } 191 if (dirty & MACH64_UPLOAD_SETUP_CNTL) { 192 DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl); 193 sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL; 194 } 195 196 if (dirty & MACH64_UPLOAD_TEXTURE) { 197 DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch); 198 DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl); 199 DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off); 200 DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset); 201 sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE; 202 } 203 204 DMAADVANCE(dev_priv, 1); 205 206 sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS; 207 208 return 0; 209 210} 211 212/* ================================================================ 213 * DMA command dispatch functions 214 */ 215 216static int mach64_dma_dispatch_clear(DRMFILE filp, drm_device_t * dev, 217 unsigned int flags, 218 int cx, int cy, int cw, int ch, 219 unsigned int clear_color, 220 unsigned int clear_depth) 221{ 222 drm_mach64_private_t *dev_priv = dev->dev_private; 223 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 224 drm_mach64_context_regs_t *ctx = &sarea_priv->context_state; 225 int nbox = sarea_priv->nbox; 226 drm_clip_rect_t *pbox = sarea_priv->boxes; 227 u32 fb_bpp, depth_bpp; 228 int i; 229 DMALOCALS; 230 231 DRM_DEBUG("%s\n", __FUNCTION__); 232 233 switch (dev_priv->fb_bpp) { 234 case 16: 235 fb_bpp = MACH64_DATATYPE_RGB565; 236 break; 237 case 32: 238 fb_bpp = MACH64_DATATYPE_ARGB8888; 239 break; 240 default: 241 return DRM_ERR(EINVAL); 242 } 243 switch (dev_priv->depth_bpp) { 244 case 16: 245 depth_bpp = MACH64_DATATYPE_RGB565; 246 break; 247 case 24: 248 case 32: 249 depth_bpp = MACH64_DATATYPE_ARGB8888; 250 break; 251 default: 252 return DRM_ERR(EINVAL); 253 } 254 255 if (!nbox) 256 return 0; 257 258 DMAGETPTR(filp, dev_priv, nbox * 31); /* returns on failure to get buffer */ 259 260 for (i = 0; i < nbox; i++) { 261 int x = pbox[i].x1; 262 int y = pbox[i].y1; 263 int w = pbox[i].x2 - x; 264 int h = pbox[i].y2 - y; 265 266 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n", 267 pbox[i].x1, pbox[i].y1, 268 pbox[i].x2, pbox[i].y2, flags); 269 270 if (flags & (MACH64_FRONT | MACH64_BACK)) { 271 /* Setup for color buffer clears 272 */ 273 274 DMAOUTREG(MACH64_Z_CNTL, 0); 275 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 276 277 DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); 278 DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); 279 280 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 281 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 282 (MACH64_DST_X_LEFT_TO_RIGHT | 283 MACH64_DST_Y_TOP_TO_BOTTOM)); 284 285 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | 286 (fb_bpp << 4) | 287 (fb_bpp << 8) | 288 (fb_bpp << 16) | 289 (fb_bpp << 28))); 290 291 DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color); 292 DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask); 293 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | 294 MACH64_FRGD_MIX_S)); 295 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | 296 MACH64_FRGD_SRC_FRGD_CLR | 297 MACH64_MONO_SRC_ONE)); 298 299 } 300 301 if (flags & MACH64_FRONT) { 302 303 DMAOUTREG(MACH64_DST_OFF_PITCH, 304 dev_priv->front_offset_pitch); 305 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 306 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 307 308 } 309 310 if (flags & MACH64_BACK) { 311 312 DMAOUTREG(MACH64_DST_OFF_PITCH, 313 dev_priv->back_offset_pitch); 314 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 315 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 316 317 } 318 319 if (flags & MACH64_DEPTH) { 320 /* Setup for depth buffer clear 321 */ 322 DMAOUTREG(MACH64_Z_CNTL, 0); 323 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 324 325 DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); 326 DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); 327 328 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 329 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 330 (MACH64_DST_X_LEFT_TO_RIGHT | 331 MACH64_DST_Y_TOP_TO_BOTTOM)); 332 333 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) | 334 (depth_bpp << 4) | 335 (depth_bpp << 8) | 336 (depth_bpp << 16) | 337 (depth_bpp << 28))); 338 339 DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth); 340 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); 341 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | 342 MACH64_FRGD_MIX_S)); 343 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | 344 MACH64_FRGD_SRC_FRGD_CLR | 345 MACH64_MONO_SRC_ONE)); 346 347 DMAOUTREG(MACH64_DST_OFF_PITCH, 348 dev_priv->depth_offset_pitch); 349 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 350 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 351 } 352 } 353 354 DMAADVANCE(dev_priv, 1); 355 356 return 0; 357} 358 359static int mach64_dma_dispatch_swap(DRMFILE filp, drm_device_t * dev) 360{ 361 drm_mach64_private_t *dev_priv = dev->dev_private; 362 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 363 int nbox = sarea_priv->nbox; 364 drm_clip_rect_t *pbox = sarea_priv->boxes; 365 u32 fb_bpp; 366 int i; 367 DMALOCALS; 368 369 DRM_DEBUG("%s\n", __FUNCTION__); 370 371 switch (dev_priv->fb_bpp) { 372 case 16: 373 fb_bpp = MACH64_DATATYPE_RGB565; 374 break; 375 case 32: 376 default: 377 fb_bpp = MACH64_DATATYPE_ARGB8888; 378 break; 379 } 380 381 if (!nbox) 382 return 0; 383 384 DMAGETPTR(filp, dev_priv, 13 + nbox * 4); /* returns on failure to get buffer */ 385 386 DMAOUTREG(MACH64_Z_CNTL, 0); 387 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 388 389 DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ 390 DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); 391 392 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 393 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT | 394 MACH64_DST_Y_TOP_TO_BOTTOM)); 395 396 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | 397 (fb_bpp << 4) | 398 (fb_bpp << 8) | 399 (fb_bpp << 16) | (fb_bpp << 28))); 400 401 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); 402 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S)); 403 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR | 404 MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE)); 405 406 DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch); 407 DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch); 408 409 for (i = 0; i < nbox; i++) { 410 int x = pbox[i].x1; 411 int y = pbox[i].y1; 412 int w = pbox[i].x2 - x; 413 int h = pbox[i].y2 - y; 414 415 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", 416 pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2); 417 418 DMAOUTREG(MACH64_SRC_WIDTH1, w); 419 DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y); 420 DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y); 421 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 422 423 } 424 425 DMAADVANCE(dev_priv, 1); 426 427 if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) { 428 for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) { 429 dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1]; 430 } 431 dev_priv->frame_ofs[i] = GETRINGOFFSET(); 432 433 dev_priv->sarea_priv->frames_queued++; 434 } 435 436 return 0; 437} 438 439static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv) 440{ 441 drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 442 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 443 int i, start; 444 u32 head, tail, ofs; 445 446 DRM_DEBUG("%s\n", __FUNCTION__); 447 448 if (sarea_priv->frames_queued == 0) 449 return 0; 450 451 tail = ring->tail; 452 mach64_ring_tick(dev_priv, ring); 453 head = ring->head; 454 455 start = (MACH64_MAX_QUEUED_FRAMES - 456 DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued)); 457 458 if (head == tail) { 459 sarea_priv->frames_queued = 0; 460 for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { 461 dev_priv->frame_ofs[i] = ~0; 462 } 463 return 0; 464 } 465 466 for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { 467 ofs = dev_priv->frame_ofs[i]; 468 DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs); 469 if (ofs == ~0 || 470 (head < tail && (ofs < head || ofs >= tail)) || 471 (head > tail && (ofs < head && ofs >= tail))) { 472 sarea_priv->frames_queued = 473 (MACH64_MAX_QUEUED_FRAMES - 1) - i; 474 dev_priv->frame_ofs[i] = ~0; 475 } 476 } 477 478 return sarea_priv->frames_queued; 479} 480 481/* Copy and verify a client submited buffer. 482 * FIXME: Make an assembly optimized version 483 */ 484static __inline__ int copy_and_verify_from_user(u32 * to, const u32 * from, 485 unsigned long bytes) 486{ 487 unsigned long n = bytes; /* dwords remaining in buffer */ 488 489 if (DRM_VERIFYAREA_READ(from, n)) { 490 DRM_ERROR("%s: verify_area\n", __FUNCTION__); 491 return DRM_ERR(EFAULT); 492 } 493 494 n >>= 2; 495 496 while (n > 1) { 497 u32 data, reg, count; 498 499 if (DRM_GET_USER_UNCHECKED(data, from++)) { 500 DRM_ERROR("%s: get_user\n", __FUNCTION__); 501 return DRM_ERR(EFAULT); 502 } 503 504 n--; 505 506 reg = le32_to_cpu(data); 507 count = (reg >> 16) + 1; 508 if (count <= n) { 509 n -= count; 510 reg &= 0xffff; 511 512 /* This is an exact match of Mach64's Setup Engine registers, 513 * excluding SETUP_CNTL (1_C1). 514 */ 515 if ((reg >= 0x0190 && reg < 0x01c1) || 516 (reg >= 0x01ca && reg <= 0x01cf)) { 517 *to++ = data; 518 if (DRM_COPY_FROM_USER_UNCHECKED 519 (to, from, count << 2)) { 520 DRM_ERROR("%s: copy_from_user\n", 521 __FUNCTION__); 522 return DRM_ERR(EFAULT); 523 } 524 to += count; 525 } else { 526 DRM_ERROR("%s: Got bad command: 0x%04x\n", 527 __FUNCTION__, reg); 528 return DRM_ERR(EACCES); 529 } 530 531 from += count; 532 } else { 533 DRM_ERROR 534 ("%s: Got bad command count(=%u) dwords remaining=%lu\n", 535 __FUNCTION__, count, n); 536 return DRM_ERR(EINVAL); 537 } 538 } 539 540 if (n == 0) 541 return 0; 542 else { 543 DRM_ERROR("%s: Bad buf->used(=%lu)\n", __FUNCTION__, bytes); 544 return DRM_ERR(EINVAL); 545 } 546} 547 548static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev, 549 int prim, void *buf, unsigned long used, 550 int discard) 551{ 552 drm_mach64_private_t *dev_priv = dev->dev_private; 553 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 554 drm_buf_t *copy_buf; 555 int done = 0; 556 int verify_ret = 0; 557 DMALOCALS; 558 559 DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n", 560 __FUNCTION__, buf, used, sarea_priv->nbox); 561 562 if (used) { 563 int ret = 0; 564 int i = 0; 565 566 copy_buf = mach64_freelist_get(dev_priv); 567 if (copy_buf == NULL) { 568 DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n", 569 __FUNCTION__); 570 return DRM_ERR(EAGAIN); 571 } 572 573 if ((verify_ret = 574 copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, 575 used)) == 0) { 576 577 copy_buf->used = used; 578 579 DMASETPTR(copy_buf); 580 581 if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { 582 ret = mach64_emit_state(filp, dev_priv); 583 if (ret < 0) 584 return ret; 585 } 586 587 do { 588 /* Emit the next cliprect */ 589 if (i < sarea_priv->nbox) { 590 ret = 591 mach64_emit_cliprect(filp, dev_priv, 592 &sarea_priv-> 593 boxes[i]); 594 if (ret < 0) { 595 /* failed to get buffer */ 596 return ret; 597 } else if (ret != 0) { 598 /* null intersection with scissor */ 599 continue; 600 } 601 } 602 if ((i >= sarea_priv->nbox - 1)) 603 done = 1; 604 605 /* Add the buffer to the DMA queue */ 606 DMAADVANCE(dev_priv, done); 607 608 } while (++i < sarea_priv->nbox); 609 } 610 611 if (copy_buf->pending && !done) { 612 DMADISCARDBUF(); 613 } else if (!done) { 614 /* This buffer wasn't used (no cliprects or verify failed), so place it back 615 * on the free list 616 */ 617 struct list_head *ptr; 618 drm_mach64_freelist_t *entry; 619#if MACH64_EXTRA_CHECKING 620 list_for_each(ptr, &dev_priv->pending) { 621 entry = 622 list_entry(ptr, drm_mach64_freelist_t, 623 list); 624 if (copy_buf == entry->buf) { 625 DRM_ERROR 626 ("%s: Trying to release a pending buf\n", 627 __FUNCTION__); 628 return DRM_ERR(EFAULT); 629 } 630 } 631#endif 632 ptr = dev_priv->placeholders.next; 633 entry = list_entry(ptr, drm_mach64_freelist_t, list); 634 copy_buf->pending = 0; 635 copy_buf->used = 0; 636 entry->buf = copy_buf; 637 entry->discard = 1; 638 list_del(ptr); 639 list_add_tail(ptr, &dev_priv->free_list); 640 } 641 } 642 643 sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS; 644 sarea_priv->nbox = 0; 645 646 return verify_ret; 647} 648 649static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev, 650 drm_mach64_blit_t * blit) 651{ 652 drm_mach64_private_t *dev_priv = dev->dev_private; 653 drm_device_dma_t *dma = dev->dma; 654 int dword_shift, dwords; 655 drm_buf_t *buf; 656 DMALOCALS; 657 658 /* The compiler won't optimize away a division by a variable, 659 * even if the only legal values are powers of two. Thus, we'll 660 * use a shift instead. 661 */ 662 switch (blit->format) { 663 case MACH64_DATATYPE_ARGB8888: 664 dword_shift = 0; 665 break; 666 case MACH64_DATATYPE_ARGB1555: 667 case MACH64_DATATYPE_RGB565: 668 case MACH64_DATATYPE_VYUY422: 669 case MACH64_DATATYPE_YVYU422: 670 case MACH64_DATATYPE_ARGB4444: 671 dword_shift = 1; 672 break; 673 case MACH64_DATATYPE_CI8: 674 case MACH64_DATATYPE_RGB8: 675 dword_shift = 2; 676 break; 677 default: 678 DRM_ERROR("invalid blit format %d\n", blit->format); 679 return DRM_ERR(EINVAL); 680 } 681 682 /* Dispatch the blit buffer. 683 */ 684 buf = dma->buflist[blit->idx]; 685 686 if (buf->filp != filp) { 687 DRM_ERROR("process %d (filp %p) using buffer with filp %p\n", 688 DRM_CURRENTPID, filp, buf->filp); 689 return DRM_ERR(EINVAL); 690 } 691 692 if (buf->pending) { 693 DRM_ERROR("sending pending buffer %d\n", blit->idx); 694 return DRM_ERR(EINVAL); 695 } 696 697 /* Set buf->used to the bytes of blit data based on the blit dimensions 698 * and verify the size. When the setup is emitted to the buffer with 699 * the DMA* macros below, buf->used is incremented to include the bytes 700 * used for setup as well as the blit data. 701 */ 702 dwords = (blit->width * blit->height) >> dword_shift; 703 buf->used = dwords << 2; 704 if (buf->used <= 0 || 705 buf->used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { 706 DRM_ERROR("Invalid blit size: %d bytes\n", buf->used); 707 return DRM_ERR(EINVAL); 708 } 709 710 /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent, 711 * continuation buffers? 712 */ 713 714 /* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require 715 * a register command every 16 dwords. State setup is added at the start of the 716 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET 717 */ 718 DMASETPTR(buf); 719 720 DMAOUTREG(MACH64_Z_CNTL, 0); 721 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 722 723 DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ 724 DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); 725 726 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); /* disable */ 727 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 728 MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM); 729 730 DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0) /* dst pix width */ 731 |(blit->format << 4) /* composite pix width */ 732 |(blit->format << 8) /* src pix width */ 733 |(blit->format << 16) /* host data pix width */ 734 |(blit->format << 28) /* scaler/3D pix width */ 735 ); 736 737 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); /* enable all planes */ 738 DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S); 739 DMAOUTREG(MACH64_DP_SRC, 740 MACH64_BKGD_SRC_BKGD_CLR 741 | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE); 742 743 DMAOUTREG(MACH64_DST_OFF_PITCH, 744 (blit->pitch << 22) | (blit->offset >> 3)); 745 DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x); 746 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width); 747 748 DRM_DEBUG("%s: %d bytes\n", __FUNCTION__, buf->used); 749 750 /* Add the buffer to the queue */ 751 DMAADVANCEHOSTDATA(dev_priv); 752 753 return 0; 754} 755 756/* ================================================================ 757 * IOCTL functions 758 */ 759 760int mach64_dma_clear(DRM_IOCTL_ARGS) 761{ 762 DRM_DEVICE; 763 drm_mach64_private_t *dev_priv = dev->dev_private; 764 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 765 drm_mach64_clear_t clear; 766 int ret; 767 768 DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID); 769 770 LOCK_TEST_WITH_RETURN(dev, filp); 771 772 DRM_COPY_FROM_USER_IOCTL(clear, (drm_mach64_clear_t *) data, 773 sizeof(clear)); 774 775 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 776 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 777 778 ret = mach64_dma_dispatch_clear(filp, dev, clear.flags, 779 clear.x, clear.y, clear.w, clear.h, 780 clear.clear_color, clear.clear_depth); 781 782 /* Make sure we restore the 3D state next time. 783 */ 784 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); 785 return ret; 786} 787 788int mach64_dma_swap(DRM_IOCTL_ARGS) 789{ 790 DRM_DEVICE; 791 drm_mach64_private_t *dev_priv = dev->dev_private; 792 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 793 int ret; 794 795 DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID); 796 797 LOCK_TEST_WITH_RETURN(dev, filp); 798 799 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 800 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 801 802 ret = mach64_dma_dispatch_swap(filp, dev); 803 804 /* Make sure we restore the 3D state next time. 805 */ 806 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); 807 return ret; 808} 809 810int mach64_dma_vertex(DRM_IOCTL_ARGS) 811{ 812 DRM_DEVICE; 813 drm_mach64_private_t *dev_priv = dev->dev_private; 814 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 815 drm_mach64_vertex_t vertex; 816 817 LOCK_TEST_WITH_RETURN(dev, filp); 818 819 if (!dev_priv) { 820 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 821 return DRM_ERR(EINVAL); 822 } 823 824 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_mach64_vertex_t *) data, 825 sizeof(vertex)); 826 827 DRM_DEBUG("%s: pid=%d buf=%p used=%lu discard=%d\n", 828 __FUNCTION__, DRM_CURRENTPID, 829 vertex.buf, vertex.used, vertex.discard); 830 831 if (vertex.prim < 0 || vertex.prim > MACH64_PRIM_POLYGON) { 832 DRM_ERROR("buffer prim %d\n", vertex.prim); 833 return DRM_ERR(EINVAL); 834 } 835 836 if (vertex.used > MACH64_BUFFER_SIZE || (vertex.used & 3) != 0) { 837 DRM_ERROR("Invalid vertex buffer size: %lu bytes\n", 838 vertex.used); 839 return DRM_ERR(EINVAL); 840 } 841 842 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 843 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 844 845 return mach64_dma_dispatch_vertex(filp, dev, vertex.prim, vertex.buf, 846 vertex.used, vertex.discard); 847} 848 849int mach64_dma_blit(DRM_IOCTL_ARGS) 850{ 851 DRM_DEVICE; 852 drm_device_dma_t *dma = dev->dma; 853 drm_mach64_private_t *dev_priv = dev->dev_private; 854 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 855 drm_mach64_blit_t blit; 856 int ret; 857 858 LOCK_TEST_WITH_RETURN(dev, filp); 859 860 DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data, 861 sizeof(blit)); 862 863 DRM_DEBUG("%s: pid=%d index=%d\n", 864 __FUNCTION__, DRM_CURRENTPID, blit.idx); 865 866 if (blit.idx < 0 || blit.idx >= dma->buf_count) { 867 DRM_ERROR("buffer index %d (of %d max)\n", 868 blit.idx, dma->buf_count - 1); 869 return DRM_ERR(EINVAL); 870 } 871 872 ret = mach64_dma_dispatch_blit(filp, dev, &blit); 873 874 /* Make sure we restore the 3D state next time. 875 */ 876 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | 877 MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS); 878 879 return ret; 880} 881 882int mach64_get_param(DRM_IOCTL_ARGS) 883{ 884 DRM_DEVICE; 885 drm_mach64_private_t *dev_priv = dev->dev_private; 886 drm_mach64_getparam_t param; 887 int value; 888 889 DRM_DEBUG("%s\n", __FUNCTION__); 890 891 if (!dev_priv) { 892 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 893 return DRM_ERR(EINVAL); 894 } 895 896 DRM_COPY_FROM_USER_IOCTL(param, (drm_mach64_getparam_t *) data, 897 sizeof(param)); 898 899 switch (param.param) { 900 case MACH64_PARAM_FRAMES_QUEUED: 901 /* Needs lock since it calls mach64_ring_tick() */ 902 LOCK_TEST_WITH_RETURN(dev, filp); 903 value = mach64_do_get_frames_queued(dev_priv); 904 break; 905 case MACH64_PARAM_IRQ_NR: 906 value = dev->irq; 907 break; 908 default: 909 return DRM_ERR(EINVAL); 910 } 911 912 if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) { 913 DRM_ERROR("copy_to_user\n"); 914 return DRM_ERR(EFAULT); 915 } 916 917 return 0; 918} 919