mach64_state.c revision 182080
160107Sobrien/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*- 225689Sjkh * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com 325689Sjkh */ 425689Sjkh/*- 5111698Sluigi * Copyright 2000 Gareth Hughes 6111698Sluigi * Copyright 2002-2003 Leif Delgass 7111698Sluigi * All Rights Reserved. 8111698Sluigi * 9111698Sluigi * Permission is hereby granted, free of charge, to any person obtaining a 10111698Sluigi * copy of this software and associated documentation files (the "Software"), 11111698Sluigi * to deal in the Software without restriction, including without limitation 12111698Sluigi * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13111698Sluigi * and/or sell copies of the Software, and to permit persons to whom the 1425689Sjkh * Software is furnished to do so, subject to the following conditions: 15111698Sluigi * 16111698Sluigi * The above copyright notice and this permission notice (including the next 17124874Sale * paragraph) shall be included in all copies or substantial portions of the 18111698Sluigi * Software. 19124874Sale * 20124874Sale * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21111698Sluigi * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22111698Sluigi * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23111698Sluigi * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 24111698Sluigi * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25111698Sluigi * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26111698Sluigi * 27111698Sluigi * Authors: 28111698Sluigi * Gareth Hughes <gareth@valinux.com> 29111698Sluigi * Leif Delgass <ldelgass@retinalburn.net> 30111698Sluigi * Jos�� Fonseca <j_r_fonseca@yahoo.co.uk> 31111698Sluigi */ 32111698Sluigi 33111698Sluigi#include <sys/cdefs.h> 34111698Sluigi__FBSDID("$FreeBSD: head/sys/dev/drm/mach64_state.c 182080 2008-08-23 20:59:12Z rnoland $"); 35111698Sluigi 3614408Sjkh#include "dev/drm/drmP.h" 3714408Sjkh#include "dev/drm/drm.h" 3814408Sjkh#include "dev/drm/mach64_drm.h" 3914408Sjkh#include "dev/drm/mach64_drv.h" 4014408Sjkh 4114408Sjkh/* Interface history: 42111698Sluigi * 43111698Sluigi * 1.0 - Initial mach64 DRM 44111698Sluigi * 45111698Sluigi */ 46111698Sluigistruct drm_ioctl_desc mach64_ioctls[] = { 47111698Sluigi DRM_IOCTL_DEF(DRM_MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 48111698Sluigi DRM_IOCTL_DEF(DRM_MACH64_CLEAR, mach64_dma_clear, DRM_AUTH), 49111698Sluigi DRM_IOCTL_DEF(DRM_MACH64_SWAP, mach64_dma_swap, DRM_AUTH), 50111698Sluigi DRM_IOCTL_DEF(DRM_MACH64_IDLE, mach64_dma_idle, DRM_AUTH), 51111698Sluigi DRM_IOCTL_DEF(DRM_MACH64_RESET, mach64_engine_reset, DRM_AUTH), 52111698Sluigi DRM_IOCTL_DEF(DRM_MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH), 53111698Sluigi DRM_IOCTL_DEF(DRM_MACH64_BLIT, mach64_dma_blit, DRM_AUTH), 5414408Sjkh DRM_IOCTL_DEF(DRM_MACH64_FLUSH, mach64_dma_flush, DRM_AUTH), 5514408Sjkh DRM_IOCTL_DEF(DRM_MACH64_GETPARAM, mach64_get_param, DRM_AUTH), 56111698Sluigi}; 57111698Sluigi 5861118Srobertoint mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls); 59111698Sluigi 60111698Sluigi/* ================================================================ 61111698Sluigi * DMA hardware state programming functions 62111698Sluigi */ 63111698Sluigi 64111698Sluigistatic void mach64_print_dirty(const char *msg, unsigned int flags) 65111698Sluigi{ 66111698Sluigi DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n", 6714408Sjkh msg, 6814408Sjkh flags, 6914408Sjkh (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " : 70111698Sluigi "", 71111698Sluigi (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "", 72111698Sluigi (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " : 73111698Sluigi "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "", 74111698Sluigi (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " : 75111698Sluigi "", 7614408Sjkh (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "", 77111698Sluigi (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "", 7814408Sjkh (flags & MACH64_UPLOAD_MISC) ? "misc, " : "", 79111698Sluigi (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "", 80111698Sluigi (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "", 81111698Sluigi (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "", 8214408Sjkh (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : ""); 83111698Sluigi} 84111698Sluigi 85111698Sluigi/* Mach64 doesn't have hardware cliprects, just one hardware scissor, 86111698Sluigi * so the GL scissor is intersected with each cliprect here 87111698Sluigi */ 88111698Sluigi/* This function returns 0 on success, 1 for no intersection, and 8914408Sjkh * negative for an error 90111698Sluigi */ 91111698Sluigistatic int mach64_emit_cliprect(struct drm_file *file_priv, 92111698Sluigi drm_mach64_private_t * dev_priv, 93111698Sluigi struct drm_clip_rect * box) 9414408Sjkh{ 9543334Syokota u32 sc_left_right, sc_top_bottom; 9614408Sjkh struct drm_clip_rect scissor; 9732822Syokota drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 9814408Sjkh drm_mach64_context_regs_t *regs = &sarea_priv->context_state; 9914408Sjkh DMALOCALS; 10014408Sjkh 10114408Sjkh DRM_DEBUG("box=%p\n", box); 10214408Sjkh 10314408Sjkh /* Get GL scissor */ 10414408Sjkh /* FIXME: store scissor in SAREA as a cliprect instead of in 10514408Sjkh * hardware format, or do intersection client-side 10614408Sjkh */ 10714408Sjkh scissor.x1 = regs->sc_left_right & 0xffff; 10814408Sjkh scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16; 10914408Sjkh scissor.y1 = regs->sc_top_bottom & 0xffff; 11014408Sjkh scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16; 11114408Sjkh 11214408Sjkh /* Intersect GL scissor with cliprect */ 11314408Sjkh if (box->x1 > scissor.x1) 11414408Sjkh scissor.x1 = box->x1; 11514408Sjkh if (box->y1 > scissor.y1) 11614408Sjkh scissor.y1 = box->y1; 11714408Sjkh if (box->x2 < scissor.x2) 11814408Sjkh scissor.x2 = box->x2; 11914408Sjkh if (box->y2 < scissor.y2) 12014408Sjkh scissor.y2 = box->y2; 12114408Sjkh /* positive return means skip */ 12214408Sjkh if (scissor.x1 >= scissor.x2) 12314408Sjkh return 1; 12414408Sjkh if (scissor.y1 >= scissor.y2) 12514408Sjkh return 1; 126111698Sluigi 12714408Sjkh DMAGETPTR(file_priv, dev_priv, 2); /* returns on failure to get buffer */ 12814408Sjkh 12918194Ssos sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16)); 13014408Sjkh sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16)); 13114408Sjkh 132111698Sluigi DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right); 13314408Sjkh DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom); 13414408Sjkh 13514408Sjkh DMAADVANCE(dev_priv, 1); 13614408Sjkh 13714408Sjkh return 0; 13814408Sjkh} 13914408Sjkh 14014408Sjkhstatic __inline__ int mach64_emit_state(struct drm_file *file_priv, 14114408Sjkh drm_mach64_private_t * dev_priv) 142111698Sluigi{ 143111698Sluigi drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 14443334Syokota drm_mach64_context_regs_t *regs = &sarea_priv->context_state; 14514408Sjkh unsigned int dirty = sarea_priv->dirty; 14614408Sjkh u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2); 14714408Sjkh DMALOCALS; 148111698Sluigi 149111698Sluigi if (MACH64_VERBOSE) { 150111698Sluigi mach64_print_dirty(__FUNCTION__, dirty); 151111698Sluigi } else { 152111698Sluigi DRM_DEBUG("dirty=0x%08x\n", dirty); 153111698Sluigi } 154111698Sluigi 155111698Sluigi DMAGETPTR(file_priv, dev_priv, 17); /* returns on failure to get buffer */ 156111698Sluigi 157111698Sluigi if (dirty & MACH64_UPLOAD_MISC) { 158111698Sluigi DMAOUTREG(MACH64_DP_MIX, regs->dp_mix); 159111698Sluigi DMAOUTREG(MACH64_DP_SRC, regs->dp_src); 160111698Sluigi DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl); 161111698Sluigi DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl); 162111698Sluigi sarea_priv->dirty &= ~MACH64_UPLOAD_MISC; 163111698Sluigi } 164111698Sluigi 165111698Sluigi if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) { 166111698Sluigi DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch); 167111698Sluigi sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH; 168111698Sluigi } 169111698Sluigi if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) { 170111698Sluigi DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch); 171111698Sluigi sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH; 172111698Sluigi } 173 if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) { 174 DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl); 175 DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl); 176 sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL; 177 } 178 if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) { 179 DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl); 180 sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL; 181 } 182 if (dirty & MACH64_UPLOAD_DP_FOG_CLR) { 183 DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr); 184 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR; 185 } 186 if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) { 187 DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask); 188 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK; 189 } 190 if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) { 191 DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width); 192 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH; 193 } 194 if (dirty & MACH64_UPLOAD_SETUP_CNTL) { 195 DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl); 196 sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL; 197 } 198 199 if (dirty & MACH64_UPLOAD_TEXTURE) { 200 DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch); 201 DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl); 202 DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off); 203 DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset); 204 sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE; 205 } 206 207 DMAADVANCE(dev_priv, 1); 208 209 sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS; 210 211 return 0; 212 213} 214 215/* ================================================================ 216 * DMA command dispatch functions 217 */ 218 219static int mach64_dma_dispatch_clear(struct drm_device * dev, 220 struct drm_file *file_priv, 221 unsigned int flags, 222 int cx, int cy, int cw, int ch, 223 unsigned int clear_color, 224 unsigned int clear_depth) 225{ 226 drm_mach64_private_t *dev_priv = dev->dev_private; 227 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 228 drm_mach64_context_regs_t *ctx = &sarea_priv->context_state; 229 int nbox = sarea_priv->nbox; 230 struct drm_clip_rect *pbox = sarea_priv->boxes; 231 u32 fb_bpp, depth_bpp; 232 int i; 233 DMALOCALS; 234 235 DRM_DEBUG("\n"); 236 237 switch (dev_priv->fb_bpp) { 238 case 16: 239 fb_bpp = MACH64_DATATYPE_RGB565; 240 break; 241 case 32: 242 fb_bpp = MACH64_DATATYPE_ARGB8888; 243 break; 244 default: 245 return -EINVAL; 246 } 247 switch (dev_priv->depth_bpp) { 248 case 16: 249 depth_bpp = MACH64_DATATYPE_RGB565; 250 break; 251 case 24: 252 case 32: 253 depth_bpp = MACH64_DATATYPE_ARGB8888; 254 break; 255 default: 256 return -EINVAL; 257 } 258 259 if (!nbox) 260 return 0; 261 262 DMAGETPTR(file_priv, dev_priv, nbox * 31); /* returns on failure to get buffer */ 263 264 for (i = 0; i < nbox; i++) { 265 int x = pbox[i].x1; 266 int y = pbox[i].y1; 267 int w = pbox[i].x2 - x; 268 int h = pbox[i].y2 - y; 269 270 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n", 271 pbox[i].x1, pbox[i].y1, 272 pbox[i].x2, pbox[i].y2, flags); 273 274 if (flags & (MACH64_FRONT | MACH64_BACK)) { 275 /* Setup for color buffer clears 276 */ 277 278 DMAOUTREG(MACH64_Z_CNTL, 0); 279 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 280 281 DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); 282 DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); 283 284 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 285 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 286 (MACH64_DST_X_LEFT_TO_RIGHT | 287 MACH64_DST_Y_TOP_TO_BOTTOM)); 288 289 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | 290 (fb_bpp << 4) | 291 (fb_bpp << 8) | 292 (fb_bpp << 16) | 293 (fb_bpp << 28))); 294 295 DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color); 296 DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask); 297 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | 298 MACH64_FRGD_MIX_S)); 299 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | 300 MACH64_FRGD_SRC_FRGD_CLR | 301 MACH64_MONO_SRC_ONE)); 302 303 } 304 305 if (flags & MACH64_FRONT) { 306 307 DMAOUTREG(MACH64_DST_OFF_PITCH, 308 dev_priv->front_offset_pitch); 309 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 310 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 311 312 } 313 314 if (flags & MACH64_BACK) { 315 316 DMAOUTREG(MACH64_DST_OFF_PITCH, 317 dev_priv->back_offset_pitch); 318 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 319 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 320 321 } 322 323 if (flags & MACH64_DEPTH) { 324 /* Setup for depth buffer clear 325 */ 326 DMAOUTREG(MACH64_Z_CNTL, 0); 327 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 328 329 DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right); 330 DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom); 331 332 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 333 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 334 (MACH64_DST_X_LEFT_TO_RIGHT | 335 MACH64_DST_Y_TOP_TO_BOTTOM)); 336 337 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) | 338 (depth_bpp << 4) | 339 (depth_bpp << 8) | 340 (depth_bpp << 16) | 341 (depth_bpp << 28))); 342 343 DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth); 344 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); 345 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | 346 MACH64_FRGD_MIX_S)); 347 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR | 348 MACH64_FRGD_SRC_FRGD_CLR | 349 MACH64_MONO_SRC_ONE)); 350 351 DMAOUTREG(MACH64_DST_OFF_PITCH, 352 dev_priv->depth_offset_pitch); 353 DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x); 354 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 355 } 356 } 357 358 DMAADVANCE(dev_priv, 1); 359 360 return 0; 361} 362 363static int mach64_dma_dispatch_swap(struct drm_device * dev, 364 struct drm_file *file_priv) 365{ 366 drm_mach64_private_t *dev_priv = dev->dev_private; 367 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 368 int nbox = sarea_priv->nbox; 369 struct drm_clip_rect *pbox = sarea_priv->boxes; 370 u32 fb_bpp; 371 int i; 372 DMALOCALS; 373 374 DRM_DEBUG("\n"); 375 376 switch (dev_priv->fb_bpp) { 377 case 16: 378 fb_bpp = MACH64_DATATYPE_RGB565; 379 break; 380 case 32: 381 default: 382 fb_bpp = MACH64_DATATYPE_ARGB8888; 383 break; 384 } 385 386 if (!nbox) 387 return 0; 388 389 DMAGETPTR(file_priv, dev_priv, 13 + nbox * 4); /* returns on failure to get buffer */ 390 391 DMAOUTREG(MACH64_Z_CNTL, 0); 392 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 393 394 DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ 395 DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); 396 397 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); 398 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT | 399 MACH64_DST_Y_TOP_TO_BOTTOM)); 400 401 DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) | 402 (fb_bpp << 4) | 403 (fb_bpp << 8) | 404 (fb_bpp << 16) | (fb_bpp << 28))); 405 406 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); 407 DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S)); 408 DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR | 409 MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE)); 410 411 DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch); 412 DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch); 413 414 for (i = 0; i < nbox; i++) { 415 int x = pbox[i].x1; 416 int y = pbox[i].y1; 417 int w = pbox[i].x2 - x; 418 int h = pbox[i].y2 - y; 419 420 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", 421 pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2); 422 423 DMAOUTREG(MACH64_SRC_WIDTH1, w); 424 DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y); 425 DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y); 426 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w); 427 428 } 429 430 DMAADVANCE(dev_priv, 1); 431 432 if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) { 433 for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) { 434 dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1]; 435 } 436 dev_priv->frame_ofs[i] = GETRINGOFFSET(); 437 438 dev_priv->sarea_priv->frames_queued++; 439 } 440 441 return 0; 442} 443 444static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv) 445{ 446 drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 447 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 448 int i, start; 449 u32 head, tail, ofs; 450 451 DRM_DEBUG("\n"); 452 453 if (sarea_priv->frames_queued == 0) 454 return 0; 455 456 tail = ring->tail; 457 mach64_ring_tick(dev_priv, ring); 458 head = ring->head; 459 460 start = (MACH64_MAX_QUEUED_FRAMES - 461 DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued)); 462 463 if (head == tail) { 464 sarea_priv->frames_queued = 0; 465 for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { 466 dev_priv->frame_ofs[i] = ~0; 467 } 468 return 0; 469 } 470 471 for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) { 472 ofs = dev_priv->frame_ofs[i]; 473 DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs); 474 if (ofs == ~0 || 475 (head < tail && (ofs < head || ofs >= tail)) || 476 (head > tail && (ofs < head && ofs >= tail))) { 477 sarea_priv->frames_queued = 478 (MACH64_MAX_QUEUED_FRAMES - 1) - i; 479 dev_priv->frame_ofs[i] = ~0; 480 } 481 } 482 483 return sarea_priv->frames_queued; 484} 485 486/* Copy and verify a client submited buffer. 487 * FIXME: Make an assembly optimized version 488 */ 489static __inline__ int copy_from_user_vertex(u32 *to, 490 const u32 __user *ufrom, 491 unsigned long bytes) 492{ 493 unsigned long n = bytes; /* dwords remaining in buffer */ 494 u32 *from, *orig_from; 495 496 from = drm_alloc(bytes, DRM_MEM_DRIVER); 497 if (from == NULL) 498 return -ENOMEM; 499 500 if (DRM_COPY_FROM_USER(from, ufrom, bytes)) { 501 drm_free(from, bytes, DRM_MEM_DRIVER); 502 return -EFAULT; 503 } 504 orig_from = from; /* we'll be modifying the "from" ptr, so save it */ 505 506 n >>= 2; 507 508 while (n > 1) { 509 u32 data, reg, count; 510 511 data = *from++; 512 513 n--; 514 515 reg = le32_to_cpu(data); 516 count = (reg >> 16) + 1; 517 if (count <= n) { 518 n -= count; 519 reg &= 0xffff; 520 521 /* This is an exact match of Mach64's Setup Engine registers, 522 * excluding SETUP_CNTL (1_C1). 523 */ 524 if ((reg >= 0x0190 && reg < 0x01c1) || 525 (reg >= 0x01ca && reg <= 0x01cf)) { 526 *to++ = data; 527 memcpy(to, from, count << 2); 528 from += count; 529 to += count; 530 } else { 531 DRM_ERROR("Got bad command: 0x%04x\n", reg); 532 drm_free(orig_from, bytes, DRM_MEM_DRIVER); 533 return -EACCES; 534 } 535 } else { 536 DRM_ERROR 537 ("Got bad command count(=%u) dwords remaining=%lu\n", 538 count, n); 539 drm_free(orig_from, bytes, DRM_MEM_DRIVER); 540 return -EINVAL; 541 } 542 } 543 544 drm_free(orig_from, bytes, DRM_MEM_DRIVER); 545 if (n == 0) 546 return 0; 547 else { 548 DRM_ERROR("Bad buf->used(=%lu)\n", bytes); 549 return -EINVAL; 550 } 551} 552 553static int mach64_dma_dispatch_vertex(struct drm_device * dev, 554 struct drm_file *file_priv, 555 drm_mach64_vertex_t * vertex) 556{ 557 drm_mach64_private_t *dev_priv = dev->dev_private; 558 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 559 struct drm_buf *copy_buf; 560 void *buf = vertex->buf; 561 unsigned long used = vertex->used; 562 int ret = 0; 563 int i = 0; 564 int done = 0; 565 int verify_ret = 0; 566 DMALOCALS; 567 568 DRM_DEBUG("buf=%p used=%lu nbox=%d\n", 569 buf, used, sarea_priv->nbox); 570 571 if (!used) 572 goto _vertex_done; 573 574 copy_buf = mach64_freelist_get(dev_priv); 575 if (copy_buf == NULL) { 576 DRM_ERROR("couldn't get buffer\n"); 577 return -EAGAIN; 578 } 579 580 /* Mach64's vertex data is actually register writes. To avoid security 581 * compromises these register writes have to be verified and copied from 582 * user space into a private DMA buffer. 583 */ 584 verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used); 585 586 if (verify_ret != 0) { 587 mach64_freelist_put(dev_priv, copy_buf); 588 goto _vertex_done; 589 } 590 591 copy_buf->used = used; 592 593 DMASETPTR(copy_buf); 594 595 if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { 596 ret = mach64_emit_state(file_priv, dev_priv); 597 if (ret < 0) 598 return ret; 599 } 600 601 do { 602 /* Emit the next cliprect */ 603 if (i < sarea_priv->nbox) { 604 ret = mach64_emit_cliprect(file_priv, dev_priv, 605 &sarea_priv->boxes[i]); 606 if (ret < 0) { 607 /* failed to get buffer */ 608 return ret; 609 } else if (ret != 0) { 610 /* null intersection with scissor */ 611 continue; 612 } 613 } 614 if ((i >= sarea_priv->nbox - 1)) 615 done = 1; 616 617 /* Add the buffer to the DMA queue */ 618 DMAADVANCE(dev_priv, done); 619 620 } while (++i < sarea_priv->nbox); 621 622 if (!done) { 623 if (copy_buf->pending) { 624 DMADISCARDBUF(); 625 } else { 626 /* This buffer wasn't used (no cliprects), so place it 627 * back on the free list 628 */ 629 mach64_freelist_put(dev_priv, copy_buf); 630 } 631 } 632 633_vertex_done: 634 sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS; 635 sarea_priv->nbox = 0; 636 637 return verify_ret; 638} 639 640static __inline__ int copy_from_user_blit(u32 *to, 641 const u32 __user *ufrom, 642 unsigned long bytes) 643{ 644 to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET); 645 646 if (DRM_COPY_FROM_USER(to, ufrom, bytes)) { 647 return -EFAULT; 648 } 649 650 return 0; 651} 652 653static int mach64_dma_dispatch_blit(struct drm_device * dev, 654 struct drm_file *file_priv, 655 drm_mach64_blit_t * blit) 656{ 657 drm_mach64_private_t *dev_priv = dev->dev_private; 658 int dword_shift, dwords; 659 unsigned long used; 660 struct drm_buf *copy_buf; 661 int verify_ret = 0; 662 DMALOCALS; 663 664 /* The compiler won't optimize away a division by a variable, 665 * even if the only legal values are powers of two. Thus, we'll 666 * use a shift instead. 667 */ 668 switch (blit->format) { 669 case MACH64_DATATYPE_ARGB8888: 670 dword_shift = 0; 671 break; 672 case MACH64_DATATYPE_ARGB1555: 673 case MACH64_DATATYPE_RGB565: 674 case MACH64_DATATYPE_VYUY422: 675 case MACH64_DATATYPE_YVYU422: 676 case MACH64_DATATYPE_ARGB4444: 677 dword_shift = 1; 678 break; 679 case MACH64_DATATYPE_CI8: 680 case MACH64_DATATYPE_RGB8: 681 dword_shift = 2; 682 break; 683 default: 684 DRM_ERROR("invalid blit format %d\n", blit->format); 685 return -EINVAL; 686 } 687 688 /* Set buf->used to the bytes of blit data based on the blit dimensions 689 * and verify the size. When the setup is emitted to the buffer with 690 * the DMA* macros below, buf->used is incremented to include the bytes 691 * used for setup as well as the blit data. 692 */ 693 dwords = (blit->width * blit->height) >> dword_shift; 694 used = dwords << 2; 695 if (used <= 0 || 696 used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { 697 DRM_ERROR("Invalid blit size: %lu bytes\n", used); 698 return -EINVAL; 699 } 700 701 copy_buf = mach64_freelist_get(dev_priv); 702 if (copy_buf == NULL) { 703 DRM_ERROR("couldn't get buffer\n"); 704 return -EAGAIN; 705 } 706 707 /* Copy the blit data from userspace. 708 * 709 * XXX: This is overkill. The most efficient solution would be having 710 * two sets of buffers (one set private for vertex data, the other set 711 * client-writable for blits). However that would bring more complexity 712 * and would break backward compatability. The solution currently 713 * implemented is keeping all buffers private, allowing to secure the 714 * driver, without increasing complexity at the expense of some speed 715 * transfering data. 716 */ 717 verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used); 718 719 if (verify_ret != 0) { 720 mach64_freelist_put(dev_priv, copy_buf); 721 goto _blit_done; 722 } 723 724 copy_buf->used = used; 725 726 /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent, 727 * continuation buffers? 728 */ 729 730 /* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require 731 * a register command every 16 dwords. State setup is added at the start of the 732 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET 733 */ 734 DMASETPTR(copy_buf); 735 736 DMAOUTREG(MACH64_Z_CNTL, 0); 737 DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); 738 739 DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */ 740 DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16)); 741 742 DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); /* disable */ 743 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, 744 MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM); 745 746 DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0) /* dst pix width */ 747 |(blit->format << 4) /* composite pix width */ 748 |(blit->format << 8) /* src pix width */ 749 |(blit->format << 16) /* host data pix width */ 750 |(blit->format << 28) /* scaler/3D pix width */ 751 ); 752 753 DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); /* enable all planes */ 754 DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S); 755 DMAOUTREG(MACH64_DP_SRC, 756 MACH64_BKGD_SRC_BKGD_CLR 757 | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE); 758 759 DMAOUTREG(MACH64_DST_OFF_PITCH, 760 (blit->pitch << 22) | (blit->offset >> 3)); 761 DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x); 762 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width); 763 764 DRM_DEBUG("%lu bytes\n", used); 765 766 /* Add the buffer to the queue */ 767 DMAADVANCEHOSTDATA(dev_priv); 768 769_blit_done: 770 return verify_ret; 771} 772 773/* ================================================================ 774 * IOCTL functions 775 */ 776 777int mach64_dma_clear(struct drm_device *dev, void *data, 778 struct drm_file *file_priv) 779{ 780 drm_mach64_private_t *dev_priv = dev->dev_private; 781 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 782 drm_mach64_clear_t *clear = data; 783 int ret; 784 785 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 786 787 LOCK_TEST_WITH_RETURN(dev, file_priv); 788 789 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 790 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 791 792 ret = mach64_dma_dispatch_clear(dev, file_priv, clear->flags, 793 clear->x, clear->y, clear->w, clear->h, 794 clear->clear_color, 795 clear->clear_depth); 796 797 /* Make sure we restore the 3D state next time. 798 */ 799 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); 800 return ret; 801} 802 803int mach64_dma_swap(struct drm_device *dev, void *data, 804 struct drm_file *file_priv) 805{ 806 drm_mach64_private_t *dev_priv = dev->dev_private; 807 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 808 int ret; 809 810 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); 811 812 LOCK_TEST_WITH_RETURN(dev, file_priv); 813 814 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 815 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 816 817 ret = mach64_dma_dispatch_swap(dev, file_priv); 818 819 /* Make sure we restore the 3D state next time. 820 */ 821 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC); 822 return ret; 823} 824 825int mach64_dma_vertex(struct drm_device *dev, void *data, 826 struct drm_file *file_priv) 827{ 828 drm_mach64_private_t *dev_priv = dev->dev_private; 829 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 830 drm_mach64_vertex_t *vertex = data; 831 832 LOCK_TEST_WITH_RETURN(dev, file_priv); 833 834 if (!dev_priv) { 835 DRM_ERROR("called with no initialization\n"); 836 return -EINVAL; 837 } 838 839 DRM_DEBUG("pid=%d buf=%p used=%lu discard=%d\n", 840 DRM_CURRENTPID, 841 vertex->buf, vertex->used, vertex->discard); 842 843 if (vertex->prim < 0 || vertex->prim > MACH64_PRIM_POLYGON) { 844 DRM_ERROR("buffer prim %d\n", vertex->prim); 845 return -EINVAL; 846 } 847 848 if (vertex->used > MACH64_BUFFER_SIZE || (vertex->used & 3) != 0) { 849 DRM_ERROR("Invalid vertex buffer size: %lu bytes\n", 850 vertex->used); 851 return -EINVAL; 852 } 853 854 if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) 855 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; 856 857 return mach64_dma_dispatch_vertex(dev, file_priv, vertex); 858} 859 860int mach64_dma_blit(struct drm_device *dev, void *data, 861 struct drm_file *file_priv) 862{ 863 drm_mach64_private_t *dev_priv = dev->dev_private; 864 drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; 865 drm_mach64_blit_t *blit = data; 866 int ret; 867 868 LOCK_TEST_WITH_RETURN(dev, file_priv); 869 870 ret = mach64_dma_dispatch_blit(dev, file_priv, blit); 871 872 /* Make sure we restore the 3D state next time. 873 */ 874 sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | 875 MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS); 876 877 return ret; 878} 879 880int mach64_get_param(struct drm_device *dev, void *data, 881 struct drm_file *file_priv) 882{ 883 drm_mach64_private_t *dev_priv = dev->dev_private; 884 drm_mach64_getparam_t *param = data; 885 int value; 886 887 DRM_DEBUG("\n"); 888 889 if (!dev_priv) { 890 DRM_ERROR("called with no initialization\n"); 891 return -EINVAL; 892 } 893 894 switch (param->param) { 895 case MACH64_PARAM_FRAMES_QUEUED: 896 /* Needs lock since it calls mach64_ring_tick() */ 897 LOCK_TEST_WITH_RETURN(dev, file_priv); 898 value = mach64_do_get_frames_queued(dev_priv); 899 break; 900 case MACH64_PARAM_IRQ_NR: 901 value = dev->irq; 902 break; 903 default: 904 return -EINVAL; 905 } 906 907 if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) { 908 DRM_ERROR("copy_to_user\n"); 909 return -EFAULT; 910 } 911 912 return 0; 913} 914