1145132Sanholt/* savage_state.c -- State and drawing support for Savage 2145132Sanholt * 3145132Sanholt * Copyright 2004 Felix Kuehling 4145132Sanholt * All Rights Reserved. 5145132Sanholt * 6145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 7145132Sanholt * copy of this software and associated documentation files (the "Software"), 8145132Sanholt * to deal in the Software without restriction, including without limitation 9145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sub license, 10145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the 11145132Sanholt * Software is furnished to do so, subject to the following conditions: 12145132Sanholt * 13145132Sanholt * The above copyright notice and this permission notice (including the 14145132Sanholt * next paragraph) shall be included in all copies or substantial portions 15145132Sanholt * of the Software. 16145132Sanholt * 17145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18145132Sanholt * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19145132Sanholt * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20145132Sanholt * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR 21145132Sanholt * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 22145132Sanholt * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23145132Sanholt * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24145132Sanholt */ 25145132Sanholt 26152909Sanholt#include <sys/cdefs.h> 27152909Sanholt__FBSDID("$FreeBSD$"); 28152909Sanholt#include "dev/drm/drmP.h" 29152909Sanholt#include "dev/drm/savage_drm.h" 30152909Sanholt#include "dev/drm/savage_drv.h" 31145132Sanholt 32145132Sanholtvoid savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv, 33182080Srnoland const struct drm_clip_rect *pbox) 34145132Sanholt{ 35145132Sanholt uint32_t scstart = dev_priv->state.s3d.new_scstart; 36182080Srnoland uint32_t scend = dev_priv->state.s3d.new_scend; 37145132Sanholt scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) | 38182080Srnoland ((uint32_t)pbox->x1 & 0x000007ff) | 39145132Sanholt (((uint32_t)pbox->y1 << 16) & 0x07ff0000); 40182080Srnoland scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) | 41182080Srnoland (((uint32_t)pbox->x2 - 1) & 0x000007ff) | 42182080Srnoland ((((uint32_t)pbox->y2 - 1) << 16) & 0x07ff0000); 43145132Sanholt if (scstart != dev_priv->state.s3d.scstart || 44145132Sanholt scend != dev_priv->state.s3d.scend) { 45145132Sanholt DMA_LOCALS; 46145132Sanholt BEGIN_DMA(4); 47182080Srnoland DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); 48145132Sanholt DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2); 49145132Sanholt DMA_WRITE(scstart); 50145132Sanholt DMA_WRITE(scend); 51145132Sanholt dev_priv->state.s3d.scstart = scstart; 52182080Srnoland dev_priv->state.s3d.scend = scend; 53145132Sanholt dev_priv->waiting = 1; 54145132Sanholt DMA_COMMIT(); 55145132Sanholt } 56145132Sanholt} 57145132Sanholt 58145132Sanholtvoid savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv, 59182080Srnoland const struct drm_clip_rect *pbox) 60145132Sanholt{ 61145132Sanholt uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0; 62145132Sanholt uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1; 63145132Sanholt drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) | 64145132Sanholt ((uint32_t)pbox->x1 & 0x000007ff) | 65145132Sanholt (((uint32_t)pbox->y1 << 12) & 0x00fff000); 66145132Sanholt drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) | 67182080Srnoland (((uint32_t)pbox->x2 - 1) & 0x000007ff) | 68182080Srnoland ((((uint32_t)pbox->y2 - 1) << 12) & 0x00fff000); 69145132Sanholt if (drawctrl0 != dev_priv->state.s4.drawctrl0 || 70145132Sanholt drawctrl1 != dev_priv->state.s4.drawctrl1) { 71145132Sanholt DMA_LOCALS; 72145132Sanholt BEGIN_DMA(4); 73182080Srnoland DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); 74145132Sanholt DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2); 75145132Sanholt DMA_WRITE(drawctrl0); 76145132Sanholt DMA_WRITE(drawctrl1); 77145132Sanholt dev_priv->state.s4.drawctrl0 = drawctrl0; 78145132Sanholt dev_priv->state.s4.drawctrl1 = drawctrl1; 79145132Sanholt dev_priv->waiting = 1; 80145132Sanholt DMA_COMMIT(); 81145132Sanholt } 82145132Sanholt} 83145132Sanholt 84145132Sanholtstatic int savage_verify_texaddr(drm_savage_private_t *dev_priv, int unit, 85145132Sanholt uint32_t addr) 86145132Sanholt{ 87145132Sanholt if ((addr & 6) != 2) { /* reserved bits */ 88145132Sanholt DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr); 89182080Srnoland return -EINVAL; 90145132Sanholt } 91145132Sanholt if (!(addr & 1)) { /* local */ 92145132Sanholt addr &= ~7; 93182080Srnoland if (addr < dev_priv->texture_offset || 94182080Srnoland addr >= dev_priv->texture_offset + dev_priv->texture_size) { 95157617Sanholt DRM_ERROR 96157617Sanholt ("bad texAddr%d %08x (local addr out of range)\n", 97157617Sanholt unit, addr); 98182080Srnoland return -EINVAL; 99145132Sanholt } 100145132Sanholt } else { /* AGP */ 101145132Sanholt if (!dev_priv->agp_textures) { 102145132Sanholt DRM_ERROR("bad texAddr%d %08x (AGP not available)\n", 103145132Sanholt unit, addr); 104182080Srnoland return -EINVAL; 105145132Sanholt } 106145132Sanholt addr &= ~7; 107145132Sanholt if (addr < dev_priv->agp_textures->offset || 108145132Sanholt addr >= (dev_priv->agp_textures->offset + 109145132Sanholt dev_priv->agp_textures->size)) { 110157617Sanholt DRM_ERROR 111157617Sanholt ("bad texAddr%d %08x (AGP addr out of range)\n", 112157617Sanholt unit, addr); 113182080Srnoland return -EINVAL; 114145132Sanholt } 115145132Sanholt } 116145132Sanholt return 0; 117145132Sanholt} 118145132Sanholt 119145132Sanholt#define SAVE_STATE(reg,where) \ 120182080Srnoland if(start <= reg && start + count > reg) \ 121152909Sanholt dev_priv->state.where = regs[reg - start] 122145132Sanholt#define SAVE_STATE_MASK(reg,where,mask) do { \ 123182080Srnoland if(start <= reg && start + count > reg) { \ 124145132Sanholt uint32_t tmp; \ 125152909Sanholt tmp = regs[reg - start]; \ 126145132Sanholt dev_priv->state.where = (tmp & (mask)) | \ 127145132Sanholt (dev_priv->state.where & ~(mask)); \ 128145132Sanholt } \ 129145132Sanholt} while (0) 130145132Sanholtstatic int savage_verify_state_s3d(drm_savage_private_t *dev_priv, 131145132Sanholt unsigned int start, unsigned int count, 132152909Sanholt const uint32_t *regs) 133145132Sanholt{ 134145132Sanholt if (start < SAVAGE_TEXPALADDR_S3D || 135182080Srnoland start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) { 136145132Sanholt DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", 137182080Srnoland start, start + count - 1); 138182080Srnoland return -EINVAL; 139145132Sanholt } 140145132Sanholt 141145132Sanholt SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart, 142145132Sanholt ~SAVAGE_SCISSOR_MASK_S3D); 143145132Sanholt SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend, 144145132Sanholt ~SAVAGE_SCISSOR_MASK_S3D); 145145132Sanholt 146145132Sanholt /* if any texture regs were changed ... */ 147145132Sanholt if (start <= SAVAGE_TEXCTRL_S3D && 148182080Srnoland start + count > SAVAGE_TEXPALADDR_S3D) { 149145132Sanholt /* ... check texture state */ 150145132Sanholt SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl); 151145132Sanholt SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr); 152145132Sanholt if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK) 153157617Sanholt return savage_verify_texaddr(dev_priv, 0, 154157617Sanholt dev_priv->state.s3d.texaddr); 155145132Sanholt } 156145132Sanholt 157145132Sanholt return 0; 158145132Sanholt} 159145132Sanholt 160145132Sanholtstatic int savage_verify_state_s4(drm_savage_private_t *dev_priv, 161145132Sanholt unsigned int start, unsigned int count, 162152909Sanholt const uint32_t *regs) 163145132Sanholt{ 164145132Sanholt int ret = 0; 165145132Sanholt 166145132Sanholt if (start < SAVAGE_DRAWLOCALCTRL_S4 || 167182080Srnoland start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) { 168145132Sanholt DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", 169182080Srnoland start, start + count - 1); 170182080Srnoland return -EINVAL; 171145132Sanholt } 172145132Sanholt 173145132Sanholt SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0, 174145132Sanholt ~SAVAGE_SCISSOR_MASK_S4); 175145132Sanholt SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1, 176145132Sanholt ~SAVAGE_SCISSOR_MASK_S4); 177145132Sanholt 178145132Sanholt /* if any texture regs were changed ... */ 179145132Sanholt if (start <= SAVAGE_TEXDESCR_S4 && 180157617Sanholt start + count > SAVAGE_TEXPALADDR_S4) { 181145132Sanholt /* ... check texture state */ 182145132Sanholt SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr); 183145132Sanholt SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0); 184145132Sanholt SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1); 185145132Sanholt if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK) 186157617Sanholt ret |= savage_verify_texaddr(dev_priv, 0, 187157617Sanholt dev_priv->state.s4.texaddr0); 188145132Sanholt if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK) 189157617Sanholt ret |= savage_verify_texaddr(dev_priv, 1, 190157617Sanholt dev_priv->state.s4.texaddr1); 191145132Sanholt } 192145132Sanholt 193145132Sanholt return ret; 194145132Sanholt} 195145132Sanholt#undef SAVE_STATE 196145132Sanholt#undef SAVE_STATE_MASK 197145132Sanholt 198145132Sanholtstatic int savage_dispatch_state(drm_savage_private_t *dev_priv, 199145132Sanholt const drm_savage_cmd_header_t *cmd_header, 200152909Sanholt const uint32_t *regs) 201145132Sanholt{ 202145132Sanholt unsigned int count = cmd_header->state.count; 203145132Sanholt unsigned int start = cmd_header->state.start; 204145132Sanholt unsigned int count2 = 0; 205145132Sanholt unsigned int bci_size; 206145132Sanholt int ret; 207152909Sanholt DMA_LOCALS; 208145132Sanholt 209145132Sanholt if (!count) 210145132Sanholt return 0; 211145132Sanholt 212145132Sanholt if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 213145132Sanholt ret = savage_verify_state_s3d(dev_priv, start, count, regs); 214145132Sanholt if (ret != 0) 215145132Sanholt return ret; 216145132Sanholt /* scissor regs are emitted in savage_dispatch_draw */ 217145132Sanholt if (start < SAVAGE_SCSTART_S3D) { 218182080Srnoland if (start + count > SAVAGE_SCEND_S3D + 1) 219182080Srnoland count2 = count - (SAVAGE_SCEND_S3D + 1 - start); 220182080Srnoland if (start + count > SAVAGE_SCSTART_S3D) 221145132Sanholt count = SAVAGE_SCSTART_S3D - start; 222145132Sanholt } else if (start <= SAVAGE_SCEND_S3D) { 223182080Srnoland if (start + count > SAVAGE_SCEND_S3D + 1) { 224182080Srnoland count -= SAVAGE_SCEND_S3D + 1 - start; 225182080Srnoland start = SAVAGE_SCEND_S3D + 1; 226145132Sanholt } else 227145132Sanholt return 0; 228145132Sanholt } 229145132Sanholt } else { 230145132Sanholt ret = savage_verify_state_s4(dev_priv, start, count, regs); 231145132Sanholt if (ret != 0) 232145132Sanholt return ret; 233145132Sanholt /* scissor regs are emitted in savage_dispatch_draw */ 234145132Sanholt if (start < SAVAGE_DRAWCTRL0_S4) { 235182080Srnoland if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) 236157617Sanholt count2 = count - 237157617Sanholt (SAVAGE_DRAWCTRL1_S4 + 1 - start); 238182080Srnoland if (start + count > SAVAGE_DRAWCTRL0_S4) 239145132Sanholt count = SAVAGE_DRAWCTRL0_S4 - start; 240145132Sanholt } else if (start <= SAVAGE_DRAWCTRL1_S4) { 241182080Srnoland if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) { 242182080Srnoland count -= SAVAGE_DRAWCTRL1_S4 + 1 - start; 243182080Srnoland start = SAVAGE_DRAWCTRL1_S4 + 1; 244145132Sanholt } else 245145132Sanholt return 0; 246145132Sanholt } 247145132Sanholt } 248145132Sanholt 249182080Srnoland bci_size = count + (count + 254) / 255 + count2 + (count2 + 254) / 255; 250145132Sanholt 251145132Sanholt if (cmd_header->state.global) { 252182080Srnoland BEGIN_DMA(bci_size + 1); 253145132Sanholt DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); 254145132Sanholt dev_priv->waiting = 1; 255145132Sanholt } else { 256145132Sanholt BEGIN_DMA(bci_size); 257145132Sanholt } 258145132Sanholt 259145132Sanholt do { 260145132Sanholt while (count > 0) { 261145132Sanholt unsigned int n = count < 255 ? count : 255; 262145132Sanholt DMA_SET_REGISTERS(start, n); 263152909Sanholt DMA_COPY(regs, n); 264145132Sanholt count -= n; 265145132Sanholt start += n; 266145132Sanholt regs += n; 267145132Sanholt } 268145132Sanholt start += 2; 269145132Sanholt regs += 2; 270145132Sanholt count = count2; 271145132Sanholt count2 = 0; 272145132Sanholt } while (count); 273145132Sanholt 274145132Sanholt DMA_COMMIT(); 275145132Sanholt 276145132Sanholt return 0; 277145132Sanholt} 278145132Sanholt 279145132Sanholtstatic int savage_dispatch_dma_prim(drm_savage_private_t *dev_priv, 280145132Sanholt const drm_savage_cmd_header_t *cmd_header, 281182080Srnoland const struct drm_buf *dmabuf) 282145132Sanholt{ 283145132Sanholt unsigned char reorder = 0; 284145132Sanholt unsigned int prim = cmd_header->prim.prim; 285145132Sanholt unsigned int skip = cmd_header->prim.skip; 286145132Sanholt unsigned int n = cmd_header->prim.count; 287145132Sanholt unsigned int start = cmd_header->prim.start; 288145132Sanholt unsigned int i; 289152909Sanholt BCI_LOCALS; 290145132Sanholt 291145132Sanholt if (!dmabuf) { 292182080Srnoland DRM_ERROR("called without dma buffers!\n"); 293182080Srnoland return -EINVAL; 294145132Sanholt } 295145132Sanholt 296145132Sanholt if (!n) 297145132Sanholt return 0; 298145132Sanholt 299145132Sanholt switch (prim) { 300145132Sanholt case SAVAGE_PRIM_TRILIST_201: 301145132Sanholt reorder = 1; 302145132Sanholt prim = SAVAGE_PRIM_TRILIST; 303145132Sanholt case SAVAGE_PRIM_TRILIST: 304145132Sanholt if (n % 3 != 0) { 305145132Sanholt DRM_ERROR("wrong number of vertices %u in TRILIST\n", 306145132Sanholt n); 307182080Srnoland return -EINVAL; 308145132Sanholt } 309145132Sanholt break; 310145132Sanholt case SAVAGE_PRIM_TRISTRIP: 311145132Sanholt case SAVAGE_PRIM_TRIFAN: 312145132Sanholt if (n < 3) { 313157617Sanholt DRM_ERROR 314157617Sanholt ("wrong number of vertices %u in TRIFAN/STRIP\n", 315157617Sanholt n); 316182080Srnoland return -EINVAL; 317145132Sanholt } 318145132Sanholt break; 319145132Sanholt default: 320145132Sanholt DRM_ERROR("invalid primitive type %u\n", prim); 321182080Srnoland return -EINVAL; 322145132Sanholt } 323145132Sanholt 324145132Sanholt if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 325145132Sanholt if (skip != 0) { 326157617Sanholt DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 327182080Srnoland return -EINVAL; 328145132Sanholt } 329145132Sanholt } else { 330145132Sanholt unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - 331145132Sanholt (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) - 332145132Sanholt (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); 333145132Sanholt if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { 334157617Sanholt DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 335182080Srnoland return -EINVAL; 336145132Sanholt } 337145132Sanholt if (reorder) { 338145132Sanholt DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); 339182080Srnoland return -EINVAL; 340145132Sanholt } 341145132Sanholt } 342145132Sanholt 343182080Srnoland if (start + n > dmabuf->total / 32) { 344145132Sanholt DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", 345182080Srnoland start, start + n - 1, dmabuf->total / 32); 346182080Srnoland return -EINVAL; 347145132Sanholt } 348145132Sanholt 349145132Sanholt /* Vertex DMA doesn't work with command DMA at the same time, 350145132Sanholt * so we use BCI_... to submit commands here. Flush buffered 351145132Sanholt * faked DMA first. */ 352145132Sanholt DMA_FLUSH(); 353145132Sanholt 354145132Sanholt if (dmabuf->bus_address != dev_priv->state.common.vbaddr) { 355145132Sanholt BEGIN_BCI(2); 356145132Sanholt BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1); 357145132Sanholt BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type); 358145132Sanholt dev_priv->state.common.vbaddr = dmabuf->bus_address; 359145132Sanholt } 360145132Sanholt if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) { 361145132Sanholt /* Workaround for what looks like a hardware bug. If a 362145132Sanholt * WAIT_3D_IDLE was emitted some time before the 363145132Sanholt * indexed drawing command then the engine will lock 364145132Sanholt * up. There are two known workarounds: 365145132Sanholt * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */ 366145132Sanholt BEGIN_BCI(63); 367145132Sanholt for (i = 0; i < 63; ++i) 368145132Sanholt BCI_WRITE(BCI_CMD_WAIT); 369145132Sanholt dev_priv->waiting = 0; 370145132Sanholt } 371145132Sanholt 372145132Sanholt prim <<= 25; 373145132Sanholt while (n != 0) { 374145132Sanholt /* Can emit up to 255 indices (85 triangles) at once. */ 375145132Sanholt unsigned int count = n > 255 ? 255 : n; 376145132Sanholt if (reorder) { 377145132Sanholt /* Need to reorder indices for correct flat 378145132Sanholt * shading while preserving the clock sense 379145132Sanholt * for correct culling. Only on Savage3D. */ 380182080Srnoland int reorder[3] = { -1, -1, -1 }; 381182080Srnoland reorder[start % 3] = 2; 382145132Sanholt 383182080Srnoland BEGIN_BCI((count + 1 + 1) / 2); 384182080Srnoland BCI_DRAW_INDICES_S3D(count, prim, start + 2); 385145132Sanholt 386182080Srnoland for (i = start + 1; i + 1 < start + count; i += 2) 387145132Sanholt BCI_WRITE((i + reorder[i % 3]) | 388157617Sanholt ((i + 1 + 389157617Sanholt reorder[(i + 1) % 3]) << 16)); 390182080Srnoland if (i < start + count) 391182080Srnoland BCI_WRITE(i + reorder[i % 3]); 392145132Sanholt } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 393182080Srnoland BEGIN_BCI((count + 1 + 1) / 2); 394145132Sanholt BCI_DRAW_INDICES_S3D(count, prim, start); 395145132Sanholt 396182080Srnoland for (i = start + 1; i + 1 < start + count; i += 2) 397182080Srnoland BCI_WRITE(i | ((i + 1) << 16)); 398182080Srnoland if (i < start + count) 399145132Sanholt BCI_WRITE(i); 400145132Sanholt } else { 401182080Srnoland BEGIN_BCI((count + 2 + 1) / 2); 402145132Sanholt BCI_DRAW_INDICES_S4(count, prim, skip); 403145132Sanholt 404182080Srnoland for (i = start; i + 1 < start + count; i += 2) 405182080Srnoland BCI_WRITE(i | ((i + 1) << 16)); 406182080Srnoland if (i < start + count) 407145132Sanholt BCI_WRITE(i); 408145132Sanholt } 409145132Sanholt 410145132Sanholt start += count; 411145132Sanholt n -= count; 412145132Sanholt 413145132Sanholt prim |= BCI_CMD_DRAW_CONT; 414145132Sanholt } 415145132Sanholt 416145132Sanholt return 0; 417145132Sanholt} 418145132Sanholt 419145132Sanholtstatic int savage_dispatch_vb_prim(drm_savage_private_t *dev_priv, 420145132Sanholt const drm_savage_cmd_header_t *cmd_header, 421152909Sanholt const uint32_t *vtxbuf, unsigned int vb_size, 422145132Sanholt unsigned int vb_stride) 423145132Sanholt{ 424145132Sanholt unsigned char reorder = 0; 425145132Sanholt unsigned int prim = cmd_header->prim.prim; 426145132Sanholt unsigned int skip = cmd_header->prim.skip; 427145132Sanholt unsigned int n = cmd_header->prim.count; 428145132Sanholt unsigned int start = cmd_header->prim.start; 429145132Sanholt unsigned int vtx_size; 430145132Sanholt unsigned int i; 431152909Sanholt DMA_LOCALS; 432145132Sanholt 433145132Sanholt if (!n) 434145132Sanholt return 0; 435145132Sanholt 436145132Sanholt switch (prim) { 437145132Sanholt case SAVAGE_PRIM_TRILIST_201: 438145132Sanholt reorder = 1; 439145132Sanholt prim = SAVAGE_PRIM_TRILIST; 440145132Sanholt case SAVAGE_PRIM_TRILIST: 441145132Sanholt if (n % 3 != 0) { 442145132Sanholt DRM_ERROR("wrong number of vertices %u in TRILIST\n", 443145132Sanholt n); 444182080Srnoland return -EINVAL; 445145132Sanholt } 446145132Sanholt break; 447145132Sanholt case SAVAGE_PRIM_TRISTRIP: 448145132Sanholt case SAVAGE_PRIM_TRIFAN: 449145132Sanholt if (n < 3) { 450157617Sanholt DRM_ERROR 451157617Sanholt ("wrong number of vertices %u in TRIFAN/STRIP\n", 452157617Sanholt n); 453182080Srnoland return -EINVAL; 454145132Sanholt } 455145132Sanholt break; 456145132Sanholt default: 457145132Sanholt DRM_ERROR("invalid primitive type %u\n", prim); 458182080Srnoland return -EINVAL; 459145132Sanholt } 460145132Sanholt 461145132Sanholt if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 462145132Sanholt if (skip > SAVAGE_SKIP_ALL_S3D) { 463145132Sanholt DRM_ERROR("invalid skip flags 0x%04x\n", skip); 464182080Srnoland return -EINVAL; 465145132Sanholt } 466145132Sanholt vtx_size = 8; /* full vertex */ 467145132Sanholt } else { 468145132Sanholt if (skip > SAVAGE_SKIP_ALL_S4) { 469145132Sanholt DRM_ERROR("invalid skip flags 0x%04x\n", skip); 470182080Srnoland return -EINVAL; 471145132Sanholt } 472145132Sanholt vtx_size = 10; /* full vertex */ 473145132Sanholt } 474145132Sanholt 475145132Sanholt vtx_size -= (skip & 1) + (skip >> 1 & 1) + 476145132Sanholt (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) + 477145132Sanholt (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1); 478145132Sanholt 479145132Sanholt if (vtx_size > vb_stride) { 480145132Sanholt DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", 481145132Sanholt vtx_size, vb_stride); 482182080Srnoland return -EINVAL; 483145132Sanholt } 484145132Sanholt 485182080Srnoland if (start + n > vb_size / (vb_stride * 4)) { 486145132Sanholt DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", 487182080Srnoland start, start + n - 1, vb_size / (vb_stride * 4)); 488182080Srnoland return -EINVAL; 489145132Sanholt } 490145132Sanholt 491145132Sanholt prim <<= 25; 492145132Sanholt while (n != 0) { 493145132Sanholt /* Can emit up to 255 vertices (85 triangles) at once. */ 494145132Sanholt unsigned int count = n > 255 ? 255 : n; 495145132Sanholt if (reorder) { 496145132Sanholt /* Need to reorder vertices for correct flat 497145132Sanholt * shading while preserving the clock sense 498145132Sanholt * for correct culling. Only on Savage3D. */ 499182080Srnoland int reorder[3] = { -1, -1, -1 }; 500182080Srnoland reorder[start % 3] = 2; 501145132Sanholt 502182080Srnoland BEGIN_DMA(count * vtx_size + 1); 503145132Sanholt DMA_DRAW_PRIMITIVE(count, prim, skip); 504145132Sanholt 505182080Srnoland for (i = start; i < start + count; ++i) { 506145132Sanholt unsigned int j = i + reorder[i % 3]; 507182080Srnoland DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 508145132Sanholt } 509145132Sanholt 510145132Sanholt DMA_COMMIT(); 511145132Sanholt } else { 512182080Srnoland BEGIN_DMA(count * vtx_size + 1); 513145132Sanholt DMA_DRAW_PRIMITIVE(count, prim, skip); 514145132Sanholt 515145132Sanholt if (vb_stride == vtx_size) { 516182080Srnoland DMA_COPY(&vtxbuf[vb_stride * start], 517182080Srnoland vtx_size * count); 518145132Sanholt } else { 519182080Srnoland for (i = start; i < start + count; ++i) { 520182080Srnoland DMA_COPY(&vtxbuf[vb_stride * i], 521152909Sanholt vtx_size); 522145132Sanholt } 523145132Sanholt } 524145132Sanholt 525145132Sanholt DMA_COMMIT(); 526145132Sanholt } 527145132Sanholt 528145132Sanholt start += count; 529145132Sanholt n -= count; 530145132Sanholt 531145132Sanholt prim |= BCI_CMD_DRAW_CONT; 532145132Sanholt } 533145132Sanholt 534145132Sanholt return 0; 535145132Sanholt} 536145132Sanholt 537145132Sanholtstatic int savage_dispatch_dma_idx(drm_savage_private_t *dev_priv, 538145132Sanholt const drm_savage_cmd_header_t *cmd_header, 539152909Sanholt const uint16_t *idx, 540182080Srnoland const struct drm_buf *dmabuf) 541145132Sanholt{ 542145132Sanholt unsigned char reorder = 0; 543145132Sanholt unsigned int prim = cmd_header->idx.prim; 544145132Sanholt unsigned int skip = cmd_header->idx.skip; 545145132Sanholt unsigned int n = cmd_header->idx.count; 546145132Sanholt unsigned int i; 547152909Sanholt BCI_LOCALS; 548145132Sanholt 549145132Sanholt if (!dmabuf) { 550182080Srnoland DRM_ERROR("called without dma buffers!\n"); 551182080Srnoland return -EINVAL; 552145132Sanholt } 553145132Sanholt 554145132Sanholt if (!n) 555145132Sanholt return 0; 556145132Sanholt 557145132Sanholt switch (prim) { 558145132Sanholt case SAVAGE_PRIM_TRILIST_201: 559145132Sanholt reorder = 1; 560145132Sanholt prim = SAVAGE_PRIM_TRILIST; 561145132Sanholt case SAVAGE_PRIM_TRILIST: 562145132Sanholt if (n % 3 != 0) { 563157617Sanholt DRM_ERROR("wrong number of indices %u in TRILIST\n", n); 564182080Srnoland return -EINVAL; 565145132Sanholt } 566145132Sanholt break; 567145132Sanholt case SAVAGE_PRIM_TRISTRIP: 568145132Sanholt case SAVAGE_PRIM_TRIFAN: 569145132Sanholt if (n < 3) { 570157617Sanholt DRM_ERROR 571157617Sanholt ("wrong number of indices %u in TRIFAN/STRIP\n", n); 572182080Srnoland return -EINVAL; 573145132Sanholt } 574145132Sanholt break; 575145132Sanholt default: 576145132Sanholt DRM_ERROR("invalid primitive type %u\n", prim); 577182080Srnoland return -EINVAL; 578145132Sanholt } 579145132Sanholt 580145132Sanholt if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 581145132Sanholt if (skip != 0) { 582157617Sanholt DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 583182080Srnoland return -EINVAL; 584145132Sanholt } 585145132Sanholt } else { 586145132Sanholt unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - 587145132Sanholt (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) - 588145132Sanholt (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); 589145132Sanholt if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { 590157617Sanholt DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 591182080Srnoland return -EINVAL; 592145132Sanholt } 593145132Sanholt if (reorder) { 594145132Sanholt DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); 595182080Srnoland return -EINVAL; 596145132Sanholt } 597145132Sanholt } 598145132Sanholt 599145132Sanholt /* Vertex DMA doesn't work with command DMA at the same time, 600145132Sanholt * so we use BCI_... to submit commands here. Flush buffered 601145132Sanholt * faked DMA first. */ 602145132Sanholt DMA_FLUSH(); 603145132Sanholt 604145132Sanholt if (dmabuf->bus_address != dev_priv->state.common.vbaddr) { 605145132Sanholt BEGIN_BCI(2); 606145132Sanholt BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1); 607145132Sanholt BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type); 608145132Sanholt dev_priv->state.common.vbaddr = dmabuf->bus_address; 609145132Sanholt } 610145132Sanholt if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) { 611145132Sanholt /* Workaround for what looks like a hardware bug. If a 612145132Sanholt * WAIT_3D_IDLE was emitted some time before the 613145132Sanholt * indexed drawing command then the engine will lock 614145132Sanholt * up. There are two known workarounds: 615145132Sanholt * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */ 616145132Sanholt BEGIN_BCI(63); 617145132Sanholt for (i = 0; i < 63; ++i) 618145132Sanholt BCI_WRITE(BCI_CMD_WAIT); 619145132Sanholt dev_priv->waiting = 0; 620145132Sanholt } 621145132Sanholt 622145132Sanholt prim <<= 25; 623145132Sanholt while (n != 0) { 624145132Sanholt /* Can emit up to 255 indices (85 triangles) at once. */ 625145132Sanholt unsigned int count = n > 255 ? 255 : n; 626145132Sanholt 627152909Sanholt /* check indices */ 628145132Sanholt for (i = 0; i < count; ++i) { 629182080Srnoland if (idx[i] > dmabuf->total / 32) { 630145132Sanholt DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", 631182080Srnoland i, idx[i], dmabuf->total / 32); 632182080Srnoland return -EINVAL; 633145132Sanholt } 634145132Sanholt } 635145132Sanholt 636145132Sanholt if (reorder) { 637145132Sanholt /* Need to reorder indices for correct flat 638145132Sanholt * shading while preserving the clock sense 639145132Sanholt * for correct culling. Only on Savage3D. */ 640182080Srnoland int reorder[3] = { 2, -1, -1 }; 641145132Sanholt 642182080Srnoland BEGIN_BCI((count + 1 + 1) / 2); 643145132Sanholt BCI_DRAW_INDICES_S3D(count, prim, idx[2]); 644145132Sanholt 645182080Srnoland for (i = 1; i + 1 < count; i += 2) 646145132Sanholt BCI_WRITE(idx[i + reorder[i % 3]] | 647157617Sanholt (idx[i + 1 + 648157617Sanholt reorder[(i + 1) % 3]] << 16)); 649145132Sanholt if (i < count) 650182080Srnoland BCI_WRITE(idx[i + reorder[i % 3]]); 651145132Sanholt } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 652182080Srnoland BEGIN_BCI((count + 1 + 1) / 2); 653145132Sanholt BCI_DRAW_INDICES_S3D(count, prim, idx[0]); 654145132Sanholt 655182080Srnoland for (i = 1; i + 1 < count; i += 2) 656182080Srnoland BCI_WRITE(idx[i] | (idx[i + 1] << 16)); 657145132Sanholt if (i < count) 658145132Sanholt BCI_WRITE(idx[i]); 659145132Sanholt } else { 660182080Srnoland BEGIN_BCI((count + 2 + 1) / 2); 661145132Sanholt BCI_DRAW_INDICES_S4(count, prim, skip); 662145132Sanholt 663182080Srnoland for (i = 0; i + 1 < count; i += 2) 664182080Srnoland BCI_WRITE(idx[i] | (idx[i + 1] << 16)); 665145132Sanholt if (i < count) 666145132Sanholt BCI_WRITE(idx[i]); 667145132Sanholt } 668145132Sanholt 669152909Sanholt idx += count; 670145132Sanholt n -= count; 671145132Sanholt 672145132Sanholt prim |= BCI_CMD_DRAW_CONT; 673145132Sanholt } 674145132Sanholt 675145132Sanholt return 0; 676145132Sanholt} 677145132Sanholt 678145132Sanholtstatic int savage_dispatch_vb_idx(drm_savage_private_t *dev_priv, 679145132Sanholt const drm_savage_cmd_header_t *cmd_header, 680152909Sanholt const uint16_t *idx, 681152909Sanholt const uint32_t *vtxbuf, 682157617Sanholt unsigned int vb_size, unsigned int vb_stride) 683145132Sanholt{ 684145132Sanholt unsigned char reorder = 0; 685145132Sanholt unsigned int prim = cmd_header->idx.prim; 686145132Sanholt unsigned int skip = cmd_header->idx.skip; 687145132Sanholt unsigned int n = cmd_header->idx.count; 688145132Sanholt unsigned int vtx_size; 689145132Sanholt unsigned int i; 690152909Sanholt DMA_LOCALS; 691145132Sanholt 692145132Sanholt if (!n) 693145132Sanholt return 0; 694145132Sanholt 695145132Sanholt switch (prim) { 696145132Sanholt case SAVAGE_PRIM_TRILIST_201: 697145132Sanholt reorder = 1; 698145132Sanholt prim = SAVAGE_PRIM_TRILIST; 699145132Sanholt case SAVAGE_PRIM_TRILIST: 700145132Sanholt if (n % 3 != 0) { 701157617Sanholt DRM_ERROR("wrong number of indices %u in TRILIST\n", n); 702182080Srnoland return -EINVAL; 703145132Sanholt } 704145132Sanholt break; 705145132Sanholt case SAVAGE_PRIM_TRISTRIP: 706145132Sanholt case SAVAGE_PRIM_TRIFAN: 707145132Sanholt if (n < 3) { 708157617Sanholt DRM_ERROR 709157617Sanholt ("wrong number of indices %u in TRIFAN/STRIP\n", n); 710182080Srnoland return -EINVAL; 711145132Sanholt } 712145132Sanholt break; 713145132Sanholt default: 714145132Sanholt DRM_ERROR("invalid primitive type %u\n", prim); 715182080Srnoland return -EINVAL; 716145132Sanholt } 717145132Sanholt 718145132Sanholt if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 719145132Sanholt if (skip > SAVAGE_SKIP_ALL_S3D) { 720145132Sanholt DRM_ERROR("invalid skip flags 0x%04x\n", skip); 721182080Srnoland return -EINVAL; 722145132Sanholt } 723145132Sanholt vtx_size = 8; /* full vertex */ 724145132Sanholt } else { 725145132Sanholt if (skip > SAVAGE_SKIP_ALL_S4) { 726145132Sanholt DRM_ERROR("invalid skip flags 0x%04x\n", skip); 727182080Srnoland return -EINVAL; 728145132Sanholt } 729145132Sanholt vtx_size = 10; /* full vertex */ 730145132Sanholt } 731145132Sanholt 732145132Sanholt vtx_size -= (skip & 1) + (skip >> 1 & 1) + 733145132Sanholt (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) + 734145132Sanholt (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1); 735145132Sanholt 736145132Sanholt if (vtx_size > vb_stride) { 737145132Sanholt DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", 738145132Sanholt vtx_size, vb_stride); 739182080Srnoland return -EINVAL; 740145132Sanholt } 741145132Sanholt 742145132Sanholt prim <<= 25; 743145132Sanholt while (n != 0) { 744145132Sanholt /* Can emit up to 255 vertices (85 triangles) at once. */ 745145132Sanholt unsigned int count = n > 255 ? 255 : n; 746145132Sanholt 747152909Sanholt /* Check indices */ 748145132Sanholt for (i = 0; i < count; ++i) { 749182080Srnoland if (idx[i] > vb_size / (vb_stride * 4)) { 750145132Sanholt DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", 751182080Srnoland i, idx[i], vb_size / (vb_stride * 4)); 752182080Srnoland return -EINVAL; 753145132Sanholt } 754145132Sanholt } 755145132Sanholt 756145132Sanholt if (reorder) { 757145132Sanholt /* Need to reorder vertices for correct flat 758145132Sanholt * shading while preserving the clock sense 759145132Sanholt * for correct culling. Only on Savage3D. */ 760182080Srnoland int reorder[3] = { 2, -1, -1 }; 761145132Sanholt 762182080Srnoland BEGIN_DMA(count * vtx_size + 1); 763145132Sanholt DMA_DRAW_PRIMITIVE(count, prim, skip); 764145132Sanholt 765145132Sanholt for (i = 0; i < count; ++i) { 766145132Sanholt unsigned int j = idx[i + reorder[i % 3]]; 767182080Srnoland DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 768145132Sanholt } 769145132Sanholt 770145132Sanholt DMA_COMMIT(); 771145132Sanholt } else { 772182080Srnoland BEGIN_DMA(count * vtx_size + 1); 773145132Sanholt DMA_DRAW_PRIMITIVE(count, prim, skip); 774145132Sanholt 775145132Sanholt for (i = 0; i < count; ++i) { 776145132Sanholt unsigned int j = idx[i]; 777182080Srnoland DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 778145132Sanholt } 779145132Sanholt 780145132Sanholt DMA_COMMIT(); 781145132Sanholt } 782145132Sanholt 783152909Sanholt idx += count; 784145132Sanholt n -= count; 785145132Sanholt 786145132Sanholt prim |= BCI_CMD_DRAW_CONT; 787145132Sanholt } 788145132Sanholt 789145132Sanholt return 0; 790145132Sanholt} 791145132Sanholt 792145132Sanholtstatic int savage_dispatch_clear(drm_savage_private_t *dev_priv, 793145132Sanholt const drm_savage_cmd_header_t *cmd_header, 794152909Sanholt const drm_savage_cmd_header_t *data, 795145132Sanholt unsigned int nbox, 796182080Srnoland const struct drm_clip_rect *boxes) 797145132Sanholt{ 798152909Sanholt unsigned int flags = cmd_header->clear0.flags; 799145132Sanholt unsigned int clear_cmd; 800145132Sanholt unsigned int i, nbufs; 801152909Sanholt DMA_LOCALS; 802145132Sanholt 803145132Sanholt if (nbox == 0) 804145132Sanholt return 0; 805145132Sanholt 806145132Sanholt clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | 807145132Sanholt BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW; 808145132Sanholt BCI_CMD_SET_ROP(clear_cmd,0xCC); 809145132Sanholt 810145132Sanholt nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) + 811157617Sanholt ((flags & SAVAGE_BACK) ? 1 : 0) + ((flags & SAVAGE_DEPTH) ? 1 : 0); 812145132Sanholt if (nbufs == 0) 813145132Sanholt return 0; 814145132Sanholt 815152909Sanholt if (data->clear1.mask != 0xffffffff) { 816145132Sanholt /* set mask */ 817145132Sanholt BEGIN_DMA(2); 818145132Sanholt DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); 819152909Sanholt DMA_WRITE(data->clear1.mask); 820145132Sanholt DMA_COMMIT(); 821145132Sanholt } 822145132Sanholt for (i = 0; i < nbox; ++i) { 823145132Sanholt unsigned int x, y, w, h; 824145132Sanholt unsigned int buf; 825152909Sanholt 826152909Sanholt x = boxes[i].x1, y = boxes[i].y1; 827152909Sanholt w = boxes[i].x2 - boxes[i].x1; 828152909Sanholt h = boxes[i].y2 - boxes[i].y1; 829182080Srnoland BEGIN_DMA(nbufs * 6); 830145132Sanholt for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) { 831145132Sanholt if (!(flags & buf)) 832145132Sanholt continue; 833145132Sanholt DMA_WRITE(clear_cmd); 834182080Srnoland switch (buf) { 835145132Sanholt case SAVAGE_FRONT: 836145132Sanholt DMA_WRITE(dev_priv->front_offset); 837145132Sanholt DMA_WRITE(dev_priv->front_bd); 838145132Sanholt break; 839145132Sanholt case SAVAGE_BACK: 840145132Sanholt DMA_WRITE(dev_priv->back_offset); 841145132Sanholt DMA_WRITE(dev_priv->back_bd); 842145132Sanholt break; 843145132Sanholt case SAVAGE_DEPTH: 844145132Sanholt DMA_WRITE(dev_priv->depth_offset); 845145132Sanholt DMA_WRITE(dev_priv->depth_bd); 846145132Sanholt break; 847145132Sanholt } 848152909Sanholt DMA_WRITE(data->clear1.value); 849145132Sanholt DMA_WRITE(BCI_X_Y(x, y)); 850145132Sanholt DMA_WRITE(BCI_W_H(w, h)); 851145132Sanholt } 852145132Sanholt DMA_COMMIT(); 853145132Sanholt } 854152909Sanholt if (data->clear1.mask != 0xffffffff) { 855145132Sanholt /* reset mask */ 856145132Sanholt BEGIN_DMA(2); 857145132Sanholt DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); 858145132Sanholt DMA_WRITE(0xffffffff); 859145132Sanholt DMA_COMMIT(); 860145132Sanholt } 861145132Sanholt 862145132Sanholt return 0; 863145132Sanholt} 864145132Sanholt 865145132Sanholtstatic int savage_dispatch_swap(drm_savage_private_t *dev_priv, 866182080Srnoland unsigned int nbox, const struct drm_clip_rect *boxes) 867145132Sanholt{ 868145132Sanholt unsigned int swap_cmd; 869145132Sanholt unsigned int i; 870152909Sanholt DMA_LOCALS; 871145132Sanholt 872145132Sanholt if (nbox == 0) 873145132Sanholt return 0; 874145132Sanholt 875145132Sanholt swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | 876145132Sanholt BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD; 877145132Sanholt BCI_CMD_SET_ROP(swap_cmd,0xCC); 878145132Sanholt 879145132Sanholt for (i = 0; i < nbox; ++i) { 880145132Sanholt BEGIN_DMA(6); 881145132Sanholt DMA_WRITE(swap_cmd); 882145132Sanholt DMA_WRITE(dev_priv->back_offset); 883145132Sanholt DMA_WRITE(dev_priv->back_bd); 884152909Sanholt DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 885152909Sanholt DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 886182080Srnoland DMA_WRITE(BCI_W_H(boxes[i].x2 - boxes[i].x1, 887182080Srnoland boxes[i].y2 - boxes[i].y1)); 888145132Sanholt DMA_COMMIT(); 889145132Sanholt } 890145132Sanholt 891145132Sanholt return 0; 892145132Sanholt} 893145132Sanholt 894145132Sanholtstatic int savage_dispatch_draw(drm_savage_private_t *dev_priv, 895152909Sanholt const drm_savage_cmd_header_t *start, 896152909Sanholt const drm_savage_cmd_header_t *end, 897182080Srnoland const struct drm_buf *dmabuf, 898152909Sanholt const unsigned int *vtxbuf, 899145132Sanholt unsigned int vb_size, unsigned int vb_stride, 900145132Sanholt unsigned int nbox, 901182080Srnoland const struct drm_clip_rect *boxes) 902145132Sanholt{ 903145132Sanholt unsigned int i, j; 904145132Sanholt int ret; 905145132Sanholt 906145132Sanholt for (i = 0; i < nbox; ++i) { 907152909Sanholt const drm_savage_cmd_header_t *cmdbuf; 908152909Sanholt dev_priv->emit_clip_rect(dev_priv, &boxes[i]); 909145132Sanholt 910152909Sanholt cmdbuf = start; 911152909Sanholt while (cmdbuf < end) { 912145132Sanholt drm_savage_cmd_header_t cmd_header; 913152909Sanholt cmd_header = *cmdbuf; 914152909Sanholt cmdbuf++; 915145132Sanholt switch (cmd_header.cmd.cmd) { 916145132Sanholt case SAVAGE_CMD_DMA_PRIM: 917145132Sanholt ret = savage_dispatch_dma_prim( 918145132Sanholt dev_priv, &cmd_header, dmabuf); 919145132Sanholt break; 920145132Sanholt case SAVAGE_CMD_VB_PRIM: 921145132Sanholt ret = savage_dispatch_vb_prim( 922145132Sanholt dev_priv, &cmd_header, 923152909Sanholt vtxbuf, vb_size, vb_stride); 924145132Sanholt break; 925145132Sanholt case SAVAGE_CMD_DMA_IDX: 926145132Sanholt j = (cmd_header.idx.count + 3) / 4; 927145132Sanholt /* j was check in savage_bci_cmdbuf */ 928152909Sanholt ret = savage_dispatch_dma_idx(dev_priv, 929152909Sanholt &cmd_header, (const uint16_t *)cmdbuf, 930145132Sanholt dmabuf); 931152909Sanholt cmdbuf += j; 932145132Sanholt break; 933145132Sanholt case SAVAGE_CMD_VB_IDX: 934145132Sanholt j = (cmd_header.idx.count + 3) / 4; 935145132Sanholt /* j was check in savage_bci_cmdbuf */ 936152909Sanholt ret = savage_dispatch_vb_idx(dev_priv, 937152909Sanholt &cmd_header, (const uint16_t *)cmdbuf, 938152909Sanholt (const uint32_t *)vtxbuf, vb_size, 939152909Sanholt vb_stride); 940152909Sanholt cmdbuf += j; 941145132Sanholt break; 942145132Sanholt default: 943145132Sanholt /* What's the best return code? EFAULT? */ 944145132Sanholt DRM_ERROR("IMPLEMENTATION ERROR: " 945145132Sanholt "non-drawing-command %d\n", 946145132Sanholt cmd_header.cmd.cmd); 947182080Srnoland return -EINVAL; 948145132Sanholt } 949145132Sanholt 950145132Sanholt if (ret != 0) 951145132Sanholt return ret; 952145132Sanholt } 953145132Sanholt } 954145132Sanholt 955145132Sanholt return 0; 956145132Sanholt} 957145132Sanholt 958182080Srnolandint savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv) 959145132Sanholt{ 960145132Sanholt drm_savage_private_t *dev_priv = dev->dev_private; 961182080Srnoland struct drm_device_dma *dma = dev->dma; 962182080Srnoland struct drm_buf *dmabuf; 963182080Srnoland drm_savage_cmdbuf_t *cmdbuf = data; 964152909Sanholt drm_savage_cmd_header_t *kcmd_addr = NULL; 965152909Sanholt drm_savage_cmd_header_t *first_draw_cmd; 966152909Sanholt unsigned int *kvb_addr = NULL; 967182080Srnoland struct drm_clip_rect *kbox_addr = NULL; 968145132Sanholt unsigned int i, j; 969145132Sanholt int ret = 0; 970145132Sanholt 971145132Sanholt DRM_DEBUG("\n"); 972145132Sanholt 973182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 974145132Sanholt 975145132Sanholt if (dma && dma->buflist) { 976182080Srnoland if (cmdbuf->dma_idx > dma->buf_count) { 977157617Sanholt DRM_ERROR 978157617Sanholt ("vertex buffer index %u out of range (0-%u)\n", 979182080Srnoland cmdbuf->dma_idx, dma->buf_count - 1); 980182080Srnoland return -EINVAL; 981145132Sanholt } 982182080Srnoland dmabuf = dma->buflist[cmdbuf->dma_idx]; 983145132Sanholt } else { 984145132Sanholt dmabuf = NULL; 985145132Sanholt } 986145132Sanholt 987152909Sanholt /* Copy the user buffers into kernel temporary areas. This hasn't been 988152909Sanholt * a performance loss compared to VERIFYAREA_READ/ 989152909Sanholt * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct 990152909Sanholt * for locking on FreeBSD. 991152909Sanholt */ 992182080Srnoland if (cmdbuf->size) { 993182080Srnoland kcmd_addr = drm_alloc(cmdbuf->size * 8, DRM_MEM_DRIVER); 994152909Sanholt if (kcmd_addr == NULL) 995182080Srnoland return -ENOMEM; 996145132Sanholt 997182080Srnoland if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr, 998182080Srnoland cmdbuf->size * 8)) 999152909Sanholt { 1000182080Srnoland drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); 1001182080Srnoland return -EFAULT; 1002152909Sanholt } 1003182080Srnoland cmdbuf->cmd_addr = kcmd_addr; 1004152909Sanholt } 1005182080Srnoland if (cmdbuf->vb_size) { 1006182080Srnoland kvb_addr = drm_alloc(cmdbuf->vb_size, DRM_MEM_DRIVER); 1007152909Sanholt if (kvb_addr == NULL) { 1008182080Srnoland ret = -ENOMEM; 1009152909Sanholt goto done; 1010152909Sanholt } 1011152909Sanholt 1012182080Srnoland if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf->vb_addr, 1013182080Srnoland cmdbuf->vb_size)) { 1014182080Srnoland ret = -EFAULT; 1015152909Sanholt goto done; 1016152909Sanholt } 1017182080Srnoland cmdbuf->vb_addr = kvb_addr; 1018152909Sanholt } 1019182080Srnoland if (cmdbuf->nbox) { 1020182080Srnoland kbox_addr = drm_alloc(cmdbuf->nbox * 1021182080Srnoland sizeof(struct drm_clip_rect), 1022182080Srnoland DRM_MEM_DRIVER); 1023152909Sanholt if (kbox_addr == NULL) { 1024182080Srnoland ret = -ENOMEM; 1025152909Sanholt goto done; 1026152909Sanholt } 1027152909Sanholt 1028182080Srnoland if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf->box_addr, 1029182080Srnoland cmdbuf->nbox * 1030182080Srnoland sizeof(struct drm_clip_rect))) { 1031182080Srnoland ret = -EFAULT; 1032152909Sanholt goto done; 1033152909Sanholt } 1034182080Srnoland cmdbuf->box_addr = kbox_addr; 1035152909Sanholt } 1036152909Sanholt 1037145132Sanholt /* Make sure writes to DMA buffers are finished before sending 1038145132Sanholt * DMA commands to the graphics hardware. */ 1039145132Sanholt DRM_MEMORYBARRIER(); 1040145132Sanholt 1041145132Sanholt /* Coming from user space. Don't know if the Xserver has 1042145132Sanholt * emitted wait commands. Assuming the worst. */ 1043145132Sanholt dev_priv->waiting = 1; 1044145132Sanholt 1045145132Sanholt i = 0; 1046145132Sanholt first_draw_cmd = NULL; 1047182080Srnoland while (i < cmdbuf->size) { 1048145132Sanholt drm_savage_cmd_header_t cmd_header; 1049182080Srnoland cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr; 1050182080Srnoland cmdbuf->cmd_addr++; 1051145132Sanholt i++; 1052145132Sanholt 1053145132Sanholt /* Group drawing commands with same state to minimize 1054145132Sanholt * iterations over clip rects. */ 1055145132Sanholt j = 0; 1056145132Sanholt switch (cmd_header.cmd.cmd) { 1057145132Sanholt case SAVAGE_CMD_DMA_IDX: 1058145132Sanholt case SAVAGE_CMD_VB_IDX: 1059145132Sanholt j = (cmd_header.idx.count + 3) / 4; 1060182080Srnoland if (i + j > cmdbuf->size) { 1061145132Sanholt DRM_ERROR("indexed drawing command extends " 1062145132Sanholt "beyond end of command buffer\n"); 1063145132Sanholt DMA_FLUSH(); 1064182080Srnoland return -EINVAL; 1065145132Sanholt } 1066145132Sanholt /* fall through */ 1067145132Sanholt case SAVAGE_CMD_DMA_PRIM: 1068145132Sanholt case SAVAGE_CMD_VB_PRIM: 1069145132Sanholt if (!first_draw_cmd) 1070182080Srnoland first_draw_cmd = cmdbuf->cmd_addr - 1; 1071182080Srnoland cmdbuf->cmd_addr += j; 1072145132Sanholt i += j; 1073145132Sanholt break; 1074145132Sanholt default: 1075145132Sanholt if (first_draw_cmd) { 1076182080Srnoland ret = savage_dispatch_draw( 1077152909Sanholt dev_priv, first_draw_cmd, 1078182080Srnoland cmdbuf->cmd_addr - 1, 1079182080Srnoland dmabuf, cmdbuf->vb_addr, 1080182080Srnoland cmdbuf->vb_size, 1081182080Srnoland cmdbuf->vb_stride, 1082182080Srnoland cmdbuf->nbox, cmdbuf->box_addr); 1083145132Sanholt if (ret != 0) 1084145132Sanholt return ret; 1085145132Sanholt first_draw_cmd = NULL; 1086145132Sanholt } 1087145132Sanholt } 1088145132Sanholt if (first_draw_cmd) 1089145132Sanholt continue; 1090145132Sanholt 1091145132Sanholt switch (cmd_header.cmd.cmd) { 1092145132Sanholt case SAVAGE_CMD_STATE: 1093145132Sanholt j = (cmd_header.state.count + 1) / 2; 1094182080Srnoland if (i + j > cmdbuf->size) { 1095145132Sanholt DRM_ERROR("command SAVAGE_CMD_STATE extends " 1096145132Sanholt "beyond end of command buffer\n"); 1097145132Sanholt DMA_FLUSH(); 1098182080Srnoland ret = -EINVAL; 1099152909Sanholt goto done; 1100145132Sanholt } 1101152909Sanholt ret = savage_dispatch_state(dev_priv, &cmd_header, 1102182080Srnoland (const uint32_t *)cmdbuf->cmd_addr); 1103182080Srnoland cmdbuf->cmd_addr += j; 1104145132Sanholt i += j; 1105145132Sanholt break; 1106145132Sanholt case SAVAGE_CMD_CLEAR: 1107182080Srnoland if (i + 1 > cmdbuf->size) { 1108145132Sanholt DRM_ERROR("command SAVAGE_CMD_CLEAR extends " 1109145132Sanholt "beyond end of command buffer\n"); 1110145132Sanholt DMA_FLUSH(); 1111182080Srnoland ret = -EINVAL; 1112152909Sanholt goto done; 1113145132Sanholt } 1114145132Sanholt ret = savage_dispatch_clear(dev_priv, &cmd_header, 1115182080Srnoland cmdbuf->cmd_addr, 1116182080Srnoland cmdbuf->nbox, 1117182080Srnoland cmdbuf->box_addr); 1118182080Srnoland cmdbuf->cmd_addr++; 1119145132Sanholt i++; 1120145132Sanholt break; 1121145132Sanholt case SAVAGE_CMD_SWAP: 1122182080Srnoland ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox, 1123182080Srnoland cmdbuf->box_addr); 1124145132Sanholt break; 1125145132Sanholt default: 1126182080Srnoland DRM_ERROR("invalid command 0x%x\n", 1127182080Srnoland cmd_header.cmd.cmd); 1128145132Sanholt DMA_FLUSH(); 1129182080Srnoland ret = -EINVAL; 1130152909Sanholt goto done; 1131145132Sanholt } 1132145132Sanholt 1133145132Sanholt if (ret != 0) { 1134145132Sanholt DMA_FLUSH(); 1135152909Sanholt goto done; 1136145132Sanholt } 1137145132Sanholt } 1138145132Sanholt 1139145132Sanholt if (first_draw_cmd) { 1140182080Srnoland ret = savage_dispatch_draw( 1141182080Srnoland dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf, 1142182080Srnoland cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride, 1143182080Srnoland cmdbuf->nbox, cmdbuf->box_addr); 1144145132Sanholt if (ret != 0) { 1145145132Sanholt DMA_FLUSH(); 1146152909Sanholt goto done; 1147145132Sanholt } 1148145132Sanholt } 1149145132Sanholt 1150145132Sanholt DMA_FLUSH(); 1151145132Sanholt 1152182080Srnoland if (dmabuf && cmdbuf->discard) { 1153145132Sanholt drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private; 1154145132Sanholt uint16_t event; 1155145132Sanholt event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D); 1156145132Sanholt SET_AGE(&buf_priv->age, event, dev_priv->event_wrap); 1157145132Sanholt savage_freelist_put(dev, dmabuf); 1158145132Sanholt } 1159145132Sanholt 1160152909Sanholtdone: 1161152909Sanholt /* If we didn't need to allocate them, these'll be NULL */ 1162182080Srnoland drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); 1163182080Srnoland drm_free(kvb_addr, cmdbuf->vb_size, DRM_MEM_DRIVER); 1164182080Srnoland drm_free(kbox_addr, cmdbuf->nbox * sizeof(struct drm_clip_rect), 1165152909Sanholt DRM_MEM_DRIVER); 1166152909Sanholt 1167152909Sanholt return ret; 1168145132Sanholt} 1169