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