1 1.2 riastrad /* $NetBSD: savage_state.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /* savage_state.c -- State and drawing support for Savage 4 1.1 riastrad * 5 1.1 riastrad * Copyright 2004 Felix Kuehling 6 1.1 riastrad * All Rights Reserved. 7 1.1 riastrad * 8 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 9 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 10 1.1 riastrad * to deal in the Software without restriction, including without limitation 11 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sub license, 12 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 13 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 14 1.1 riastrad * 15 1.1 riastrad * The above copyright notice and this permission notice (including the 16 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 17 1.1 riastrad * of the Software. 18 1.1 riastrad * 19 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 1.1 riastrad * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 1.1 riastrad * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 1.1 riastrad * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR 23 1.1 riastrad * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 1.1 riastrad * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 1.1 riastrad * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 1.1 riastrad */ 27 1.3 riastrad 28 1.2 riastrad #include <sys/cdefs.h> 29 1.2 riastrad __KERNEL_RCSID(0, "$NetBSD: savage_state.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $"); 30 1.2 riastrad 31 1.3 riastrad #include <linux/slab.h> 32 1.3 riastrad #include <linux/uaccess.h> 33 1.3 riastrad 34 1.3 riastrad #include <drm/drm_device.h> 35 1.3 riastrad #include <drm/drm_file.h> 36 1.3 riastrad #include <drm/drm_print.h> 37 1.1 riastrad #include <drm/savage_drm.h> 38 1.3 riastrad 39 1.1 riastrad #include "savage_drv.h" 40 1.1 riastrad 41 1.1 riastrad void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv, 42 1.1 riastrad const struct drm_clip_rect * pbox) 43 1.1 riastrad { 44 1.1 riastrad uint32_t scstart = dev_priv->state.s3d.new_scstart; 45 1.1 riastrad uint32_t scend = dev_priv->state.s3d.new_scend; 46 1.1 riastrad scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) | 47 1.1 riastrad ((uint32_t) pbox->x1 & 0x000007ff) | 48 1.1 riastrad (((uint32_t) pbox->y1 << 16) & 0x07ff0000); 49 1.1 riastrad scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) | 50 1.1 riastrad (((uint32_t) pbox->x2 - 1) & 0x000007ff) | 51 1.1 riastrad ((((uint32_t) pbox->y2 - 1) << 16) & 0x07ff0000); 52 1.1 riastrad if (scstart != dev_priv->state.s3d.scstart || 53 1.1 riastrad scend != dev_priv->state.s3d.scend) { 54 1.1 riastrad DMA_LOCALS; 55 1.1 riastrad BEGIN_DMA(4); 56 1.1 riastrad DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); 57 1.1 riastrad DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2); 58 1.1 riastrad DMA_WRITE(scstart); 59 1.1 riastrad DMA_WRITE(scend); 60 1.1 riastrad dev_priv->state.s3d.scstart = scstart; 61 1.1 riastrad dev_priv->state.s3d.scend = scend; 62 1.1 riastrad dev_priv->waiting = 1; 63 1.1 riastrad DMA_COMMIT(); 64 1.1 riastrad } 65 1.1 riastrad } 66 1.1 riastrad 67 1.1 riastrad void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv, 68 1.1 riastrad const struct drm_clip_rect * pbox) 69 1.1 riastrad { 70 1.1 riastrad uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0; 71 1.1 riastrad uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1; 72 1.1 riastrad drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) | 73 1.1 riastrad ((uint32_t) pbox->x1 & 0x000007ff) | 74 1.1 riastrad (((uint32_t) pbox->y1 << 12) & 0x00fff000); 75 1.1 riastrad drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) | 76 1.1 riastrad (((uint32_t) pbox->x2 - 1) & 0x000007ff) | 77 1.1 riastrad ((((uint32_t) pbox->y2 - 1) << 12) & 0x00fff000); 78 1.1 riastrad if (drawctrl0 != dev_priv->state.s4.drawctrl0 || 79 1.1 riastrad drawctrl1 != dev_priv->state.s4.drawctrl1) { 80 1.1 riastrad DMA_LOCALS; 81 1.1 riastrad BEGIN_DMA(4); 82 1.1 riastrad DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); 83 1.1 riastrad DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2); 84 1.1 riastrad DMA_WRITE(drawctrl0); 85 1.1 riastrad DMA_WRITE(drawctrl1); 86 1.1 riastrad dev_priv->state.s4.drawctrl0 = drawctrl0; 87 1.1 riastrad dev_priv->state.s4.drawctrl1 = drawctrl1; 88 1.1 riastrad dev_priv->waiting = 1; 89 1.1 riastrad DMA_COMMIT(); 90 1.1 riastrad } 91 1.1 riastrad } 92 1.1 riastrad 93 1.1 riastrad static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit, 94 1.1 riastrad uint32_t addr) 95 1.1 riastrad { 96 1.1 riastrad if ((addr & 6) != 2) { /* reserved bits */ 97 1.1 riastrad DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr); 98 1.1 riastrad return -EINVAL; 99 1.1 riastrad } 100 1.1 riastrad if (!(addr & 1)) { /* local */ 101 1.1 riastrad addr &= ~7; 102 1.1 riastrad if (addr < dev_priv->texture_offset || 103 1.1 riastrad addr >= dev_priv->texture_offset + dev_priv->texture_size) { 104 1.1 riastrad DRM_ERROR 105 1.1 riastrad ("bad texAddr%d %08x (local addr out of range)\n", 106 1.1 riastrad unit, addr); 107 1.1 riastrad return -EINVAL; 108 1.1 riastrad } 109 1.1 riastrad } else { /* AGP */ 110 1.1 riastrad if (!dev_priv->agp_textures) { 111 1.1 riastrad DRM_ERROR("bad texAddr%d %08x (AGP not available)\n", 112 1.1 riastrad unit, addr); 113 1.1 riastrad return -EINVAL; 114 1.1 riastrad } 115 1.1 riastrad addr &= ~7; 116 1.1 riastrad if (addr < dev_priv->agp_textures->offset || 117 1.1 riastrad addr >= (dev_priv->agp_textures->offset + 118 1.1 riastrad dev_priv->agp_textures->size)) { 119 1.1 riastrad DRM_ERROR 120 1.1 riastrad ("bad texAddr%d %08x (AGP addr out of range)\n", 121 1.1 riastrad unit, addr); 122 1.1 riastrad return -EINVAL; 123 1.1 riastrad } 124 1.1 riastrad } 125 1.1 riastrad return 0; 126 1.1 riastrad } 127 1.1 riastrad 128 1.1 riastrad #define SAVE_STATE(reg,where) \ 129 1.1 riastrad if(start <= reg && start+count > reg) \ 130 1.1 riastrad dev_priv->state.where = regs[reg - start] 131 1.1 riastrad #define SAVE_STATE_MASK(reg,where,mask) do { \ 132 1.1 riastrad if(start <= reg && start+count > reg) { \ 133 1.1 riastrad uint32_t tmp; \ 134 1.1 riastrad tmp = regs[reg - start]; \ 135 1.1 riastrad dev_priv->state.where = (tmp & (mask)) | \ 136 1.1 riastrad (dev_priv->state.where & ~(mask)); \ 137 1.1 riastrad } \ 138 1.1 riastrad } while (0) 139 1.1 riastrad 140 1.1 riastrad static int savage_verify_state_s3d(drm_savage_private_t * dev_priv, 141 1.1 riastrad unsigned int start, unsigned int count, 142 1.1 riastrad const uint32_t *regs) 143 1.1 riastrad { 144 1.1 riastrad if (start < SAVAGE_TEXPALADDR_S3D || 145 1.1 riastrad start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) { 146 1.1 riastrad DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", 147 1.1 riastrad start, start + count - 1); 148 1.1 riastrad return -EINVAL; 149 1.1 riastrad } 150 1.1 riastrad 151 1.1 riastrad SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart, 152 1.1 riastrad ~SAVAGE_SCISSOR_MASK_S3D); 153 1.1 riastrad SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend, 154 1.1 riastrad ~SAVAGE_SCISSOR_MASK_S3D); 155 1.1 riastrad 156 1.1 riastrad /* if any texture regs were changed ... */ 157 1.1 riastrad if (start <= SAVAGE_TEXCTRL_S3D && 158 1.1 riastrad start + count > SAVAGE_TEXPALADDR_S3D) { 159 1.1 riastrad /* ... check texture state */ 160 1.1 riastrad SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl); 161 1.1 riastrad SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr); 162 1.1 riastrad if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK) 163 1.1 riastrad return savage_verify_texaddr(dev_priv, 0, 164 1.1 riastrad dev_priv->state.s3d.texaddr); 165 1.1 riastrad } 166 1.1 riastrad 167 1.1 riastrad return 0; 168 1.1 riastrad } 169 1.1 riastrad 170 1.1 riastrad static int savage_verify_state_s4(drm_savage_private_t * dev_priv, 171 1.1 riastrad unsigned int start, unsigned int count, 172 1.1 riastrad const uint32_t *regs) 173 1.1 riastrad { 174 1.1 riastrad int ret = 0; 175 1.1 riastrad 176 1.1 riastrad if (start < SAVAGE_DRAWLOCALCTRL_S4 || 177 1.1 riastrad start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) { 178 1.1 riastrad DRM_ERROR("invalid register range (0x%04x-0x%04x)\n", 179 1.1 riastrad start, start + count - 1); 180 1.1 riastrad return -EINVAL; 181 1.1 riastrad } 182 1.1 riastrad 183 1.1 riastrad SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0, 184 1.1 riastrad ~SAVAGE_SCISSOR_MASK_S4); 185 1.1 riastrad SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1, 186 1.1 riastrad ~SAVAGE_SCISSOR_MASK_S4); 187 1.1 riastrad 188 1.1 riastrad /* if any texture regs were changed ... */ 189 1.1 riastrad if (start <= SAVAGE_TEXDESCR_S4 && 190 1.1 riastrad start + count > SAVAGE_TEXPALADDR_S4) { 191 1.1 riastrad /* ... check texture state */ 192 1.1 riastrad SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr); 193 1.1 riastrad SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0); 194 1.1 riastrad SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1); 195 1.1 riastrad if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK) 196 1.1 riastrad ret |= savage_verify_texaddr(dev_priv, 0, 197 1.1 riastrad dev_priv->state.s4.texaddr0); 198 1.1 riastrad if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK) 199 1.1 riastrad ret |= savage_verify_texaddr(dev_priv, 1, 200 1.1 riastrad dev_priv->state.s4.texaddr1); 201 1.1 riastrad } 202 1.1 riastrad 203 1.1 riastrad return ret; 204 1.1 riastrad } 205 1.1 riastrad 206 1.1 riastrad #undef SAVE_STATE 207 1.1 riastrad #undef SAVE_STATE_MASK 208 1.1 riastrad 209 1.1 riastrad static int savage_dispatch_state(drm_savage_private_t * dev_priv, 210 1.1 riastrad const drm_savage_cmd_header_t * cmd_header, 211 1.1 riastrad const uint32_t *regs) 212 1.1 riastrad { 213 1.1 riastrad unsigned int count = cmd_header->state.count; 214 1.1 riastrad unsigned int start = cmd_header->state.start; 215 1.1 riastrad unsigned int count2 = 0; 216 1.1 riastrad unsigned int bci_size; 217 1.1 riastrad int ret; 218 1.1 riastrad DMA_LOCALS; 219 1.1 riastrad 220 1.1 riastrad if (!count) 221 1.1 riastrad return 0; 222 1.1 riastrad 223 1.1 riastrad if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 224 1.1 riastrad ret = savage_verify_state_s3d(dev_priv, start, count, regs); 225 1.1 riastrad if (ret != 0) 226 1.1 riastrad return ret; 227 1.1 riastrad /* scissor regs are emitted in savage_dispatch_draw */ 228 1.1 riastrad if (start < SAVAGE_SCSTART_S3D) { 229 1.1 riastrad if (start + count > SAVAGE_SCEND_S3D + 1) 230 1.1 riastrad count2 = count - (SAVAGE_SCEND_S3D + 1 - start); 231 1.1 riastrad if (start + count > SAVAGE_SCSTART_S3D) 232 1.1 riastrad count = SAVAGE_SCSTART_S3D - start; 233 1.1 riastrad } else if (start <= SAVAGE_SCEND_S3D) { 234 1.1 riastrad if (start + count > SAVAGE_SCEND_S3D + 1) { 235 1.1 riastrad count -= SAVAGE_SCEND_S3D + 1 - start; 236 1.1 riastrad start = SAVAGE_SCEND_S3D + 1; 237 1.1 riastrad } else 238 1.1 riastrad return 0; 239 1.1 riastrad } 240 1.1 riastrad } else { 241 1.1 riastrad ret = savage_verify_state_s4(dev_priv, start, count, regs); 242 1.1 riastrad if (ret != 0) 243 1.1 riastrad return ret; 244 1.1 riastrad /* scissor regs are emitted in savage_dispatch_draw */ 245 1.1 riastrad if (start < SAVAGE_DRAWCTRL0_S4) { 246 1.1 riastrad if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) 247 1.1 riastrad count2 = count - 248 1.1 riastrad (SAVAGE_DRAWCTRL1_S4 + 1 - start); 249 1.1 riastrad if (start + count > SAVAGE_DRAWCTRL0_S4) 250 1.1 riastrad count = SAVAGE_DRAWCTRL0_S4 - start; 251 1.1 riastrad } else if (start <= SAVAGE_DRAWCTRL1_S4) { 252 1.1 riastrad if (start + count > SAVAGE_DRAWCTRL1_S4 + 1) { 253 1.1 riastrad count -= SAVAGE_DRAWCTRL1_S4 + 1 - start; 254 1.1 riastrad start = SAVAGE_DRAWCTRL1_S4 + 1; 255 1.1 riastrad } else 256 1.1 riastrad return 0; 257 1.1 riastrad } 258 1.1 riastrad } 259 1.1 riastrad 260 1.1 riastrad bci_size = count + (count + 254) / 255 + count2 + (count2 + 254) / 255; 261 1.1 riastrad 262 1.1 riastrad if (cmd_header->state.global) { 263 1.1 riastrad BEGIN_DMA(bci_size + 1); 264 1.1 riastrad DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D); 265 1.1 riastrad dev_priv->waiting = 1; 266 1.1 riastrad } else { 267 1.1 riastrad BEGIN_DMA(bci_size); 268 1.1 riastrad } 269 1.1 riastrad 270 1.1 riastrad do { 271 1.1 riastrad while (count > 0) { 272 1.1 riastrad unsigned int n = count < 255 ? count : 255; 273 1.1 riastrad DMA_SET_REGISTERS(start, n); 274 1.1 riastrad DMA_COPY(regs, n); 275 1.1 riastrad count -= n; 276 1.1 riastrad start += n; 277 1.1 riastrad regs += n; 278 1.1 riastrad } 279 1.1 riastrad start += 2; 280 1.1 riastrad regs += 2; 281 1.1 riastrad count = count2; 282 1.1 riastrad count2 = 0; 283 1.1 riastrad } while (count); 284 1.1 riastrad 285 1.1 riastrad DMA_COMMIT(); 286 1.1 riastrad 287 1.1 riastrad return 0; 288 1.1 riastrad } 289 1.1 riastrad 290 1.1 riastrad static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv, 291 1.1 riastrad const drm_savage_cmd_header_t * cmd_header, 292 1.1 riastrad const struct drm_buf * dmabuf) 293 1.1 riastrad { 294 1.1 riastrad unsigned char reorder = 0; 295 1.1 riastrad unsigned int prim = cmd_header->prim.prim; 296 1.1 riastrad unsigned int skip = cmd_header->prim.skip; 297 1.1 riastrad unsigned int n = cmd_header->prim.count; 298 1.1 riastrad unsigned int start = cmd_header->prim.start; 299 1.1 riastrad unsigned int i; 300 1.1 riastrad BCI_LOCALS; 301 1.1 riastrad 302 1.1 riastrad if (!dmabuf) { 303 1.1 riastrad DRM_ERROR("called without dma buffers!\n"); 304 1.1 riastrad return -EINVAL; 305 1.1 riastrad } 306 1.1 riastrad 307 1.1 riastrad if (!n) 308 1.1 riastrad return 0; 309 1.1 riastrad 310 1.1 riastrad switch (prim) { 311 1.1 riastrad case SAVAGE_PRIM_TRILIST_201: 312 1.1 riastrad reorder = 1; 313 1.1 riastrad prim = SAVAGE_PRIM_TRILIST; 314 1.3 riastrad /* fall through */ 315 1.1 riastrad case SAVAGE_PRIM_TRILIST: 316 1.1 riastrad if (n % 3 != 0) { 317 1.1 riastrad DRM_ERROR("wrong number of vertices %u in TRILIST\n", 318 1.1 riastrad n); 319 1.1 riastrad return -EINVAL; 320 1.1 riastrad } 321 1.1 riastrad break; 322 1.1 riastrad case SAVAGE_PRIM_TRISTRIP: 323 1.1 riastrad case SAVAGE_PRIM_TRIFAN: 324 1.1 riastrad if (n < 3) { 325 1.1 riastrad DRM_ERROR 326 1.1 riastrad ("wrong number of vertices %u in TRIFAN/STRIP\n", 327 1.1 riastrad n); 328 1.1 riastrad return -EINVAL; 329 1.1 riastrad } 330 1.1 riastrad break; 331 1.1 riastrad default: 332 1.1 riastrad DRM_ERROR("invalid primitive type %u\n", prim); 333 1.1 riastrad return -EINVAL; 334 1.1 riastrad } 335 1.1 riastrad 336 1.1 riastrad if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 337 1.1 riastrad if (skip != 0) { 338 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 339 1.1 riastrad return -EINVAL; 340 1.1 riastrad } 341 1.1 riastrad } else { 342 1.1 riastrad unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - 343 1.1 riastrad (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) - 344 1.1 riastrad (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); 345 1.1 riastrad if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { 346 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 347 1.1 riastrad return -EINVAL; 348 1.1 riastrad } 349 1.1 riastrad if (reorder) { 350 1.1 riastrad DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); 351 1.1 riastrad return -EINVAL; 352 1.1 riastrad } 353 1.1 riastrad } 354 1.1 riastrad 355 1.1 riastrad if (start + n > dmabuf->total / 32) { 356 1.1 riastrad DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", 357 1.1 riastrad start, start + n - 1, dmabuf->total / 32); 358 1.1 riastrad return -EINVAL; 359 1.1 riastrad } 360 1.1 riastrad 361 1.1 riastrad /* Vertex DMA doesn't work with command DMA at the same time, 362 1.1 riastrad * so we use BCI_... to submit commands here. Flush buffered 363 1.1 riastrad * faked DMA first. */ 364 1.1 riastrad DMA_FLUSH(); 365 1.1 riastrad 366 1.1 riastrad if (dmabuf->bus_address != dev_priv->state.common.vbaddr) { 367 1.1 riastrad BEGIN_BCI(2); 368 1.1 riastrad BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1); 369 1.1 riastrad BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type); 370 1.1 riastrad dev_priv->state.common.vbaddr = dmabuf->bus_address; 371 1.1 riastrad } 372 1.1 riastrad if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) { 373 1.1 riastrad /* Workaround for what looks like a hardware bug. If a 374 1.1 riastrad * WAIT_3D_IDLE was emitted some time before the 375 1.1 riastrad * indexed drawing command then the engine will lock 376 1.1 riastrad * up. There are two known workarounds: 377 1.1 riastrad * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */ 378 1.1 riastrad BEGIN_BCI(63); 379 1.1 riastrad for (i = 0; i < 63; ++i) 380 1.1 riastrad BCI_WRITE(BCI_CMD_WAIT); 381 1.1 riastrad dev_priv->waiting = 0; 382 1.1 riastrad } 383 1.1 riastrad 384 1.1 riastrad prim <<= 25; 385 1.1 riastrad while (n != 0) { 386 1.1 riastrad /* Can emit up to 255 indices (85 triangles) at once. */ 387 1.1 riastrad unsigned int count = n > 255 ? 255 : n; 388 1.1 riastrad if (reorder) { 389 1.1 riastrad /* Need to reorder indices for correct flat 390 1.1 riastrad * shading while preserving the clock sense 391 1.1 riastrad * for correct culling. Only on Savage3D. */ 392 1.1 riastrad int reorder[3] = { -1, -1, -1 }; 393 1.1 riastrad reorder[start % 3] = 2; 394 1.1 riastrad 395 1.1 riastrad BEGIN_BCI((count + 1 + 1) / 2); 396 1.1 riastrad BCI_DRAW_INDICES_S3D(count, prim, start + 2); 397 1.1 riastrad 398 1.1 riastrad for (i = start + 1; i + 1 < start + count; i += 2) 399 1.1 riastrad BCI_WRITE((i + reorder[i % 3]) | 400 1.1 riastrad ((i + 1 + 401 1.1 riastrad reorder[(i + 1) % 3]) << 16)); 402 1.1 riastrad if (i < start + count) 403 1.1 riastrad BCI_WRITE(i + reorder[i % 3]); 404 1.1 riastrad } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 405 1.1 riastrad BEGIN_BCI((count + 1 + 1) / 2); 406 1.1 riastrad BCI_DRAW_INDICES_S3D(count, prim, start); 407 1.1 riastrad 408 1.1 riastrad for (i = start + 1; i + 1 < start + count; i += 2) 409 1.1 riastrad BCI_WRITE(i | ((i + 1) << 16)); 410 1.1 riastrad if (i < start + count) 411 1.1 riastrad BCI_WRITE(i); 412 1.1 riastrad } else { 413 1.1 riastrad BEGIN_BCI((count + 2 + 1) / 2); 414 1.1 riastrad BCI_DRAW_INDICES_S4(count, prim, skip); 415 1.1 riastrad 416 1.1 riastrad for (i = start; i + 1 < start + count; i += 2) 417 1.1 riastrad BCI_WRITE(i | ((i + 1) << 16)); 418 1.1 riastrad if (i < start + count) 419 1.1 riastrad BCI_WRITE(i); 420 1.1 riastrad } 421 1.1 riastrad 422 1.1 riastrad start += count; 423 1.1 riastrad n -= count; 424 1.1 riastrad 425 1.1 riastrad prim |= BCI_CMD_DRAW_CONT; 426 1.1 riastrad } 427 1.1 riastrad 428 1.1 riastrad return 0; 429 1.1 riastrad } 430 1.1 riastrad 431 1.1 riastrad static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv, 432 1.1 riastrad const drm_savage_cmd_header_t * cmd_header, 433 1.1 riastrad const uint32_t *vtxbuf, unsigned int vb_size, 434 1.1 riastrad unsigned int vb_stride) 435 1.1 riastrad { 436 1.1 riastrad unsigned char reorder = 0; 437 1.1 riastrad unsigned int prim = cmd_header->prim.prim; 438 1.1 riastrad unsigned int skip = cmd_header->prim.skip; 439 1.1 riastrad unsigned int n = cmd_header->prim.count; 440 1.1 riastrad unsigned int start = cmd_header->prim.start; 441 1.1 riastrad unsigned int vtx_size; 442 1.1 riastrad unsigned int i; 443 1.1 riastrad DMA_LOCALS; 444 1.1 riastrad 445 1.1 riastrad if (!n) 446 1.1 riastrad return 0; 447 1.1 riastrad 448 1.1 riastrad switch (prim) { 449 1.1 riastrad case SAVAGE_PRIM_TRILIST_201: 450 1.1 riastrad reorder = 1; 451 1.1 riastrad prim = SAVAGE_PRIM_TRILIST; 452 1.3 riastrad /* fall through */ 453 1.1 riastrad case SAVAGE_PRIM_TRILIST: 454 1.1 riastrad if (n % 3 != 0) { 455 1.1 riastrad DRM_ERROR("wrong number of vertices %u in TRILIST\n", 456 1.1 riastrad n); 457 1.1 riastrad return -EINVAL; 458 1.1 riastrad } 459 1.1 riastrad break; 460 1.1 riastrad case SAVAGE_PRIM_TRISTRIP: 461 1.1 riastrad case SAVAGE_PRIM_TRIFAN: 462 1.1 riastrad if (n < 3) { 463 1.1 riastrad DRM_ERROR 464 1.1 riastrad ("wrong number of vertices %u in TRIFAN/STRIP\n", 465 1.1 riastrad n); 466 1.1 riastrad return -EINVAL; 467 1.1 riastrad } 468 1.1 riastrad break; 469 1.1 riastrad default: 470 1.1 riastrad DRM_ERROR("invalid primitive type %u\n", prim); 471 1.1 riastrad return -EINVAL; 472 1.1 riastrad } 473 1.1 riastrad 474 1.1 riastrad if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 475 1.1 riastrad if (skip > SAVAGE_SKIP_ALL_S3D) { 476 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x\n", skip); 477 1.1 riastrad return -EINVAL; 478 1.1 riastrad } 479 1.1 riastrad vtx_size = 8; /* full vertex */ 480 1.1 riastrad } else { 481 1.1 riastrad if (skip > SAVAGE_SKIP_ALL_S4) { 482 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x\n", skip); 483 1.1 riastrad return -EINVAL; 484 1.1 riastrad } 485 1.1 riastrad vtx_size = 10; /* full vertex */ 486 1.1 riastrad } 487 1.1 riastrad 488 1.1 riastrad vtx_size -= (skip & 1) + (skip >> 1 & 1) + 489 1.1 riastrad (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) + 490 1.1 riastrad (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1); 491 1.1 riastrad 492 1.1 riastrad if (vtx_size > vb_stride) { 493 1.1 riastrad DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", 494 1.1 riastrad vtx_size, vb_stride); 495 1.1 riastrad return -EINVAL; 496 1.1 riastrad } 497 1.1 riastrad 498 1.1 riastrad if (start + n > vb_size / (vb_stride * 4)) { 499 1.1 riastrad DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n", 500 1.1 riastrad start, start + n - 1, vb_size / (vb_stride * 4)); 501 1.1 riastrad return -EINVAL; 502 1.1 riastrad } 503 1.1 riastrad 504 1.1 riastrad prim <<= 25; 505 1.1 riastrad while (n != 0) { 506 1.1 riastrad /* Can emit up to 255 vertices (85 triangles) at once. */ 507 1.1 riastrad unsigned int count = n > 255 ? 255 : n; 508 1.1 riastrad if (reorder) { 509 1.1 riastrad /* Need to reorder vertices for correct flat 510 1.1 riastrad * shading while preserving the clock sense 511 1.1 riastrad * for correct culling. Only on Savage3D. */ 512 1.1 riastrad int reorder[3] = { -1, -1, -1 }; 513 1.1 riastrad reorder[start % 3] = 2; 514 1.1 riastrad 515 1.1 riastrad BEGIN_DMA(count * vtx_size + 1); 516 1.1 riastrad DMA_DRAW_PRIMITIVE(count, prim, skip); 517 1.1 riastrad 518 1.1 riastrad for (i = start; i < start + count; ++i) { 519 1.1 riastrad unsigned int j = i + reorder[i % 3]; 520 1.1 riastrad DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 521 1.1 riastrad } 522 1.1 riastrad 523 1.1 riastrad DMA_COMMIT(); 524 1.1 riastrad } else { 525 1.1 riastrad BEGIN_DMA(count * vtx_size + 1); 526 1.1 riastrad DMA_DRAW_PRIMITIVE(count, prim, skip); 527 1.1 riastrad 528 1.1 riastrad if (vb_stride == vtx_size) { 529 1.1 riastrad DMA_COPY(&vtxbuf[vb_stride * start], 530 1.1 riastrad vtx_size * count); 531 1.1 riastrad } else { 532 1.1 riastrad for (i = start; i < start + count; ++i) { 533 1.1 riastrad DMA_COPY(&vtxbuf [vb_stride * i], 534 1.1 riastrad vtx_size); 535 1.1 riastrad } 536 1.1 riastrad } 537 1.1 riastrad 538 1.1 riastrad DMA_COMMIT(); 539 1.1 riastrad } 540 1.1 riastrad 541 1.1 riastrad start += count; 542 1.1 riastrad n -= count; 543 1.1 riastrad 544 1.1 riastrad prim |= BCI_CMD_DRAW_CONT; 545 1.1 riastrad } 546 1.1 riastrad 547 1.1 riastrad return 0; 548 1.1 riastrad } 549 1.1 riastrad 550 1.1 riastrad static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv, 551 1.1 riastrad const drm_savage_cmd_header_t * cmd_header, 552 1.1 riastrad const uint16_t *idx, 553 1.1 riastrad const struct drm_buf * dmabuf) 554 1.1 riastrad { 555 1.1 riastrad unsigned char reorder = 0; 556 1.1 riastrad unsigned int prim = cmd_header->idx.prim; 557 1.1 riastrad unsigned int skip = cmd_header->idx.skip; 558 1.1 riastrad unsigned int n = cmd_header->idx.count; 559 1.1 riastrad unsigned int i; 560 1.1 riastrad BCI_LOCALS; 561 1.1 riastrad 562 1.1 riastrad if (!dmabuf) { 563 1.1 riastrad DRM_ERROR("called without dma buffers!\n"); 564 1.1 riastrad return -EINVAL; 565 1.1 riastrad } 566 1.1 riastrad 567 1.1 riastrad if (!n) 568 1.1 riastrad return 0; 569 1.1 riastrad 570 1.1 riastrad switch (prim) { 571 1.1 riastrad case SAVAGE_PRIM_TRILIST_201: 572 1.1 riastrad reorder = 1; 573 1.1 riastrad prim = SAVAGE_PRIM_TRILIST; 574 1.3 riastrad /* fall through */ 575 1.1 riastrad case SAVAGE_PRIM_TRILIST: 576 1.1 riastrad if (n % 3 != 0) { 577 1.1 riastrad DRM_ERROR("wrong number of indices %u in TRILIST\n", n); 578 1.1 riastrad return -EINVAL; 579 1.1 riastrad } 580 1.1 riastrad break; 581 1.1 riastrad case SAVAGE_PRIM_TRISTRIP: 582 1.1 riastrad case SAVAGE_PRIM_TRIFAN: 583 1.1 riastrad if (n < 3) { 584 1.1 riastrad DRM_ERROR 585 1.1 riastrad ("wrong number of indices %u in TRIFAN/STRIP\n", n); 586 1.1 riastrad return -EINVAL; 587 1.1 riastrad } 588 1.1 riastrad break; 589 1.1 riastrad default: 590 1.1 riastrad DRM_ERROR("invalid primitive type %u\n", prim); 591 1.1 riastrad return -EINVAL; 592 1.1 riastrad } 593 1.1 riastrad 594 1.1 riastrad if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 595 1.1 riastrad if (skip != 0) { 596 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 597 1.1 riastrad return -EINVAL; 598 1.1 riastrad } 599 1.1 riastrad } else { 600 1.1 riastrad unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) - 601 1.1 riastrad (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) - 602 1.1 riastrad (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1); 603 1.1 riastrad if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) { 604 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip); 605 1.1 riastrad return -EINVAL; 606 1.1 riastrad } 607 1.1 riastrad if (reorder) { 608 1.1 riastrad DRM_ERROR("TRILIST_201 used on Savage4 hardware\n"); 609 1.1 riastrad return -EINVAL; 610 1.1 riastrad } 611 1.1 riastrad } 612 1.1 riastrad 613 1.1 riastrad /* Vertex DMA doesn't work with command DMA at the same time, 614 1.1 riastrad * so we use BCI_... to submit commands here. Flush buffered 615 1.1 riastrad * faked DMA first. */ 616 1.1 riastrad DMA_FLUSH(); 617 1.1 riastrad 618 1.1 riastrad if (dmabuf->bus_address != dev_priv->state.common.vbaddr) { 619 1.1 riastrad BEGIN_BCI(2); 620 1.1 riastrad BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1); 621 1.1 riastrad BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type); 622 1.1 riastrad dev_priv->state.common.vbaddr = dmabuf->bus_address; 623 1.1 riastrad } 624 1.1 riastrad if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) { 625 1.1 riastrad /* Workaround for what looks like a hardware bug. If a 626 1.1 riastrad * WAIT_3D_IDLE was emitted some time before the 627 1.1 riastrad * indexed drawing command then the engine will lock 628 1.1 riastrad * up. There are two known workarounds: 629 1.1 riastrad * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */ 630 1.1 riastrad BEGIN_BCI(63); 631 1.1 riastrad for (i = 0; i < 63; ++i) 632 1.1 riastrad BCI_WRITE(BCI_CMD_WAIT); 633 1.1 riastrad dev_priv->waiting = 0; 634 1.1 riastrad } 635 1.1 riastrad 636 1.1 riastrad prim <<= 25; 637 1.1 riastrad while (n != 0) { 638 1.1 riastrad /* Can emit up to 255 indices (85 triangles) at once. */ 639 1.1 riastrad unsigned int count = n > 255 ? 255 : n; 640 1.1 riastrad 641 1.1 riastrad /* check indices */ 642 1.1 riastrad for (i = 0; i < count; ++i) { 643 1.1 riastrad if (idx[i] > dmabuf->total / 32) { 644 1.1 riastrad DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", 645 1.1 riastrad i, idx[i], dmabuf->total / 32); 646 1.1 riastrad return -EINVAL; 647 1.1 riastrad } 648 1.1 riastrad } 649 1.1 riastrad 650 1.1 riastrad if (reorder) { 651 1.1 riastrad /* Need to reorder indices for correct flat 652 1.1 riastrad * shading while preserving the clock sense 653 1.1 riastrad * for correct culling. Only on Savage3D. */ 654 1.1 riastrad int reorder[3] = { 2, -1, -1 }; 655 1.1 riastrad 656 1.1 riastrad BEGIN_BCI((count + 1 + 1) / 2); 657 1.1 riastrad BCI_DRAW_INDICES_S3D(count, prim, idx[2]); 658 1.1 riastrad 659 1.1 riastrad for (i = 1; i + 1 < count; i += 2) 660 1.1 riastrad BCI_WRITE(idx[i + reorder[i % 3]] | 661 1.1 riastrad (idx[i + 1 + 662 1.1 riastrad reorder[(i + 1) % 3]] << 16)); 663 1.1 riastrad if (i < count) 664 1.1 riastrad BCI_WRITE(idx[i + reorder[i % 3]]); 665 1.1 riastrad } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 666 1.1 riastrad BEGIN_BCI((count + 1 + 1) / 2); 667 1.1 riastrad BCI_DRAW_INDICES_S3D(count, prim, idx[0]); 668 1.1 riastrad 669 1.1 riastrad for (i = 1; i + 1 < count; i += 2) 670 1.1 riastrad BCI_WRITE(idx[i] | (idx[i + 1] << 16)); 671 1.1 riastrad if (i < count) 672 1.1 riastrad BCI_WRITE(idx[i]); 673 1.1 riastrad } else { 674 1.1 riastrad BEGIN_BCI((count + 2 + 1) / 2); 675 1.1 riastrad BCI_DRAW_INDICES_S4(count, prim, skip); 676 1.1 riastrad 677 1.1 riastrad for (i = 0; i + 1 < count; i += 2) 678 1.1 riastrad BCI_WRITE(idx[i] | (idx[i + 1] << 16)); 679 1.1 riastrad if (i < count) 680 1.1 riastrad BCI_WRITE(idx[i]); 681 1.1 riastrad } 682 1.1 riastrad 683 1.1 riastrad idx += count; 684 1.1 riastrad n -= count; 685 1.1 riastrad 686 1.1 riastrad prim |= BCI_CMD_DRAW_CONT; 687 1.1 riastrad } 688 1.1 riastrad 689 1.1 riastrad return 0; 690 1.1 riastrad } 691 1.1 riastrad 692 1.1 riastrad static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv, 693 1.1 riastrad const drm_savage_cmd_header_t * cmd_header, 694 1.1 riastrad const uint16_t *idx, 695 1.1 riastrad const uint32_t *vtxbuf, 696 1.1 riastrad unsigned int vb_size, unsigned int vb_stride) 697 1.1 riastrad { 698 1.1 riastrad unsigned char reorder = 0; 699 1.1 riastrad unsigned int prim = cmd_header->idx.prim; 700 1.1 riastrad unsigned int skip = cmd_header->idx.skip; 701 1.1 riastrad unsigned int n = cmd_header->idx.count; 702 1.1 riastrad unsigned int vtx_size; 703 1.1 riastrad unsigned int i; 704 1.1 riastrad DMA_LOCALS; 705 1.1 riastrad 706 1.1 riastrad if (!n) 707 1.1 riastrad return 0; 708 1.1 riastrad 709 1.1 riastrad switch (prim) { 710 1.1 riastrad case SAVAGE_PRIM_TRILIST_201: 711 1.1 riastrad reorder = 1; 712 1.1 riastrad prim = SAVAGE_PRIM_TRILIST; 713 1.3 riastrad /* fall through */ 714 1.1 riastrad case SAVAGE_PRIM_TRILIST: 715 1.1 riastrad if (n % 3 != 0) { 716 1.1 riastrad DRM_ERROR("wrong number of indices %u in TRILIST\n", n); 717 1.1 riastrad return -EINVAL; 718 1.1 riastrad } 719 1.1 riastrad break; 720 1.1 riastrad case SAVAGE_PRIM_TRISTRIP: 721 1.1 riastrad case SAVAGE_PRIM_TRIFAN: 722 1.1 riastrad if (n < 3) { 723 1.1 riastrad DRM_ERROR 724 1.1 riastrad ("wrong number of indices %u in TRIFAN/STRIP\n", n); 725 1.1 riastrad return -EINVAL; 726 1.1 riastrad } 727 1.1 riastrad break; 728 1.1 riastrad default: 729 1.1 riastrad DRM_ERROR("invalid primitive type %u\n", prim); 730 1.1 riastrad return -EINVAL; 731 1.1 riastrad } 732 1.1 riastrad 733 1.1 riastrad if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { 734 1.1 riastrad if (skip > SAVAGE_SKIP_ALL_S3D) { 735 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x\n", skip); 736 1.1 riastrad return -EINVAL; 737 1.1 riastrad } 738 1.1 riastrad vtx_size = 8; /* full vertex */ 739 1.1 riastrad } else { 740 1.1 riastrad if (skip > SAVAGE_SKIP_ALL_S4) { 741 1.1 riastrad DRM_ERROR("invalid skip flags 0x%04x\n", skip); 742 1.1 riastrad return -EINVAL; 743 1.1 riastrad } 744 1.1 riastrad vtx_size = 10; /* full vertex */ 745 1.1 riastrad } 746 1.1 riastrad 747 1.1 riastrad vtx_size -= (skip & 1) + (skip >> 1 & 1) + 748 1.1 riastrad (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) + 749 1.1 riastrad (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1); 750 1.1 riastrad 751 1.1 riastrad if (vtx_size > vb_stride) { 752 1.1 riastrad DRM_ERROR("vertex size greater than vb stride (%u > %u)\n", 753 1.1 riastrad vtx_size, vb_stride); 754 1.1 riastrad return -EINVAL; 755 1.1 riastrad } 756 1.1 riastrad 757 1.1 riastrad prim <<= 25; 758 1.1 riastrad while (n != 0) { 759 1.1 riastrad /* Can emit up to 255 vertices (85 triangles) at once. */ 760 1.1 riastrad unsigned int count = n > 255 ? 255 : n; 761 1.1 riastrad 762 1.1 riastrad /* Check indices */ 763 1.1 riastrad for (i = 0; i < count; ++i) { 764 1.1 riastrad if (idx[i] > vb_size / (vb_stride * 4)) { 765 1.1 riastrad DRM_ERROR("idx[%u]=%u out of range (0-%u)\n", 766 1.1 riastrad i, idx[i], vb_size / (vb_stride * 4)); 767 1.1 riastrad return -EINVAL; 768 1.1 riastrad } 769 1.1 riastrad } 770 1.1 riastrad 771 1.1 riastrad if (reorder) { 772 1.1 riastrad /* Need to reorder vertices for correct flat 773 1.1 riastrad * shading while preserving the clock sense 774 1.1 riastrad * for correct culling. Only on Savage3D. */ 775 1.1 riastrad int reorder[3] = { 2, -1, -1 }; 776 1.1 riastrad 777 1.1 riastrad BEGIN_DMA(count * vtx_size + 1); 778 1.1 riastrad DMA_DRAW_PRIMITIVE(count, prim, skip); 779 1.1 riastrad 780 1.1 riastrad for (i = 0; i < count; ++i) { 781 1.1 riastrad unsigned int j = idx[i + reorder[i % 3]]; 782 1.1 riastrad DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 783 1.1 riastrad } 784 1.1 riastrad 785 1.1 riastrad DMA_COMMIT(); 786 1.1 riastrad } else { 787 1.1 riastrad BEGIN_DMA(count * vtx_size + 1); 788 1.1 riastrad DMA_DRAW_PRIMITIVE(count, prim, skip); 789 1.1 riastrad 790 1.1 riastrad for (i = 0; i < count; ++i) { 791 1.1 riastrad unsigned int j = idx[i]; 792 1.1 riastrad DMA_COPY(&vtxbuf[vb_stride * j], vtx_size); 793 1.1 riastrad } 794 1.1 riastrad 795 1.1 riastrad DMA_COMMIT(); 796 1.1 riastrad } 797 1.1 riastrad 798 1.1 riastrad idx += count; 799 1.1 riastrad n -= count; 800 1.1 riastrad 801 1.1 riastrad prim |= BCI_CMD_DRAW_CONT; 802 1.1 riastrad } 803 1.1 riastrad 804 1.1 riastrad return 0; 805 1.1 riastrad } 806 1.1 riastrad 807 1.1 riastrad static int savage_dispatch_clear(drm_savage_private_t * dev_priv, 808 1.1 riastrad const drm_savage_cmd_header_t * cmd_header, 809 1.1 riastrad const drm_savage_cmd_header_t *data, 810 1.1 riastrad unsigned int nbox, 811 1.1 riastrad const struct drm_clip_rect *boxes) 812 1.1 riastrad { 813 1.1 riastrad unsigned int flags = cmd_header->clear0.flags; 814 1.1 riastrad unsigned int clear_cmd; 815 1.1 riastrad unsigned int i, nbufs; 816 1.1 riastrad DMA_LOCALS; 817 1.1 riastrad 818 1.1 riastrad if (nbox == 0) 819 1.1 riastrad return 0; 820 1.1 riastrad 821 1.1 riastrad clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | 822 1.1 riastrad BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW; 823 1.1 riastrad BCI_CMD_SET_ROP(clear_cmd, 0xCC); 824 1.1 riastrad 825 1.1 riastrad nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) + 826 1.1 riastrad ((flags & SAVAGE_BACK) ? 1 : 0) + ((flags & SAVAGE_DEPTH) ? 1 : 0); 827 1.1 riastrad if (nbufs == 0) 828 1.1 riastrad return 0; 829 1.1 riastrad 830 1.1 riastrad if (data->clear1.mask != 0xffffffff) { 831 1.1 riastrad /* set mask */ 832 1.1 riastrad BEGIN_DMA(2); 833 1.1 riastrad DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); 834 1.1 riastrad DMA_WRITE(data->clear1.mask); 835 1.1 riastrad DMA_COMMIT(); 836 1.1 riastrad } 837 1.1 riastrad for (i = 0; i < nbox; ++i) { 838 1.1 riastrad unsigned int x, y, w, h; 839 1.1 riastrad unsigned int buf; 840 1.1 riastrad x = boxes[i].x1, y = boxes[i].y1; 841 1.1 riastrad w = boxes[i].x2 - boxes[i].x1; 842 1.1 riastrad h = boxes[i].y2 - boxes[i].y1; 843 1.1 riastrad BEGIN_DMA(nbufs * 6); 844 1.1 riastrad for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) { 845 1.1 riastrad if (!(flags & buf)) 846 1.1 riastrad continue; 847 1.1 riastrad DMA_WRITE(clear_cmd); 848 1.1 riastrad switch (buf) { 849 1.1 riastrad case SAVAGE_FRONT: 850 1.1 riastrad DMA_WRITE(dev_priv->front_offset); 851 1.1 riastrad DMA_WRITE(dev_priv->front_bd); 852 1.1 riastrad break; 853 1.1 riastrad case SAVAGE_BACK: 854 1.1 riastrad DMA_WRITE(dev_priv->back_offset); 855 1.1 riastrad DMA_WRITE(dev_priv->back_bd); 856 1.1 riastrad break; 857 1.1 riastrad case SAVAGE_DEPTH: 858 1.1 riastrad DMA_WRITE(dev_priv->depth_offset); 859 1.1 riastrad DMA_WRITE(dev_priv->depth_bd); 860 1.1 riastrad break; 861 1.1 riastrad } 862 1.1 riastrad DMA_WRITE(data->clear1.value); 863 1.1 riastrad DMA_WRITE(BCI_X_Y(x, y)); 864 1.1 riastrad DMA_WRITE(BCI_W_H(w, h)); 865 1.1 riastrad } 866 1.1 riastrad DMA_COMMIT(); 867 1.1 riastrad } 868 1.1 riastrad if (data->clear1.mask != 0xffffffff) { 869 1.1 riastrad /* reset mask */ 870 1.1 riastrad BEGIN_DMA(2); 871 1.1 riastrad DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1); 872 1.1 riastrad DMA_WRITE(0xffffffff); 873 1.1 riastrad DMA_COMMIT(); 874 1.1 riastrad } 875 1.1 riastrad 876 1.1 riastrad return 0; 877 1.1 riastrad } 878 1.1 riastrad 879 1.1 riastrad static int savage_dispatch_swap(drm_savage_private_t * dev_priv, 880 1.1 riastrad unsigned int nbox, const struct drm_clip_rect *boxes) 881 1.1 riastrad { 882 1.1 riastrad unsigned int swap_cmd; 883 1.1 riastrad unsigned int i; 884 1.1 riastrad DMA_LOCALS; 885 1.1 riastrad 886 1.1 riastrad if (nbox == 0) 887 1.1 riastrad return 0; 888 1.1 riastrad 889 1.1 riastrad swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | 890 1.1 riastrad BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD; 891 1.1 riastrad BCI_CMD_SET_ROP(swap_cmd, 0xCC); 892 1.1 riastrad 893 1.1 riastrad for (i = 0; i < nbox; ++i) { 894 1.1 riastrad BEGIN_DMA(6); 895 1.1 riastrad DMA_WRITE(swap_cmd); 896 1.1 riastrad DMA_WRITE(dev_priv->back_offset); 897 1.1 riastrad DMA_WRITE(dev_priv->back_bd); 898 1.1 riastrad DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 899 1.1 riastrad DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1)); 900 1.1 riastrad DMA_WRITE(BCI_W_H(boxes[i].x2 - boxes[i].x1, 901 1.1 riastrad boxes[i].y2 - boxes[i].y1)); 902 1.1 riastrad DMA_COMMIT(); 903 1.1 riastrad } 904 1.1 riastrad 905 1.1 riastrad return 0; 906 1.1 riastrad } 907 1.1 riastrad 908 1.1 riastrad static int savage_dispatch_draw(drm_savage_private_t * dev_priv, 909 1.1 riastrad const drm_savage_cmd_header_t *start, 910 1.1 riastrad const drm_savage_cmd_header_t *end, 911 1.1 riastrad const struct drm_buf * dmabuf, 912 1.1 riastrad const unsigned int *vtxbuf, 913 1.1 riastrad unsigned int vb_size, unsigned int vb_stride, 914 1.1 riastrad unsigned int nbox, 915 1.1 riastrad const struct drm_clip_rect *boxes) 916 1.1 riastrad { 917 1.1 riastrad unsigned int i, j; 918 1.1 riastrad int ret; 919 1.1 riastrad 920 1.1 riastrad for (i = 0; i < nbox; ++i) { 921 1.1 riastrad const drm_savage_cmd_header_t *cmdbuf; 922 1.1 riastrad dev_priv->emit_clip_rect(dev_priv, &boxes[i]); 923 1.1 riastrad 924 1.1 riastrad cmdbuf = start; 925 1.1 riastrad while (cmdbuf < end) { 926 1.1 riastrad drm_savage_cmd_header_t cmd_header; 927 1.1 riastrad cmd_header = *cmdbuf; 928 1.1 riastrad cmdbuf++; 929 1.1 riastrad switch (cmd_header.cmd.cmd) { 930 1.1 riastrad case SAVAGE_CMD_DMA_PRIM: 931 1.1 riastrad ret = savage_dispatch_dma_prim( 932 1.1 riastrad dev_priv, &cmd_header, dmabuf); 933 1.1 riastrad break; 934 1.1 riastrad case SAVAGE_CMD_VB_PRIM: 935 1.1 riastrad ret = savage_dispatch_vb_prim( 936 1.1 riastrad dev_priv, &cmd_header, 937 1.1 riastrad vtxbuf, vb_size, vb_stride); 938 1.1 riastrad break; 939 1.1 riastrad case SAVAGE_CMD_DMA_IDX: 940 1.1 riastrad j = (cmd_header.idx.count + 3) / 4; 941 1.1 riastrad /* j was check in savage_bci_cmdbuf */ 942 1.1 riastrad ret = savage_dispatch_dma_idx(dev_priv, 943 1.1 riastrad &cmd_header, (const uint16_t *)cmdbuf, 944 1.1 riastrad dmabuf); 945 1.1 riastrad cmdbuf += j; 946 1.1 riastrad break; 947 1.1 riastrad case SAVAGE_CMD_VB_IDX: 948 1.1 riastrad j = (cmd_header.idx.count + 3) / 4; 949 1.1 riastrad /* j was check in savage_bci_cmdbuf */ 950 1.1 riastrad ret = savage_dispatch_vb_idx(dev_priv, 951 1.1 riastrad &cmd_header, (const uint16_t *)cmdbuf, 952 1.1 riastrad (const uint32_t *)vtxbuf, vb_size, 953 1.1 riastrad vb_stride); 954 1.1 riastrad cmdbuf += j; 955 1.1 riastrad break; 956 1.1 riastrad default: 957 1.1 riastrad /* What's the best return code? EFAULT? */ 958 1.1 riastrad DRM_ERROR("IMPLEMENTATION ERROR: " 959 1.1 riastrad "non-drawing-command %d\n", 960 1.1 riastrad cmd_header.cmd.cmd); 961 1.1 riastrad return -EINVAL; 962 1.1 riastrad } 963 1.1 riastrad 964 1.1 riastrad if (ret != 0) 965 1.1 riastrad return ret; 966 1.1 riastrad } 967 1.1 riastrad } 968 1.1 riastrad 969 1.1 riastrad return 0; 970 1.1 riastrad } 971 1.1 riastrad 972 1.1 riastrad int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv) 973 1.1 riastrad { 974 1.1 riastrad drm_savage_private_t *dev_priv = dev->dev_private; 975 1.1 riastrad struct drm_device_dma *dma = dev->dma; 976 1.1 riastrad struct drm_buf *dmabuf; 977 1.1 riastrad drm_savage_cmdbuf_t *cmdbuf = data; 978 1.1 riastrad drm_savage_cmd_header_t *kcmd_addr = NULL; 979 1.1 riastrad drm_savage_cmd_header_t *first_draw_cmd; 980 1.1 riastrad unsigned int *kvb_addr = NULL; 981 1.1 riastrad struct drm_clip_rect *kbox_addr = NULL; 982 1.1 riastrad unsigned int i, j; 983 1.1 riastrad int ret = 0; 984 1.1 riastrad 985 1.1 riastrad DRM_DEBUG("\n"); 986 1.1 riastrad 987 1.1 riastrad LOCK_TEST_WITH_RETURN(dev, file_priv); 988 1.1 riastrad 989 1.1 riastrad if (dma && dma->buflist) { 990 1.3 riastrad if (cmdbuf->dma_idx >= dma->buf_count) { 991 1.1 riastrad DRM_ERROR 992 1.1 riastrad ("vertex buffer index %u out of range (0-%u)\n", 993 1.1 riastrad cmdbuf->dma_idx, dma->buf_count - 1); 994 1.1 riastrad return -EINVAL; 995 1.1 riastrad } 996 1.1 riastrad dmabuf = dma->buflist[cmdbuf->dma_idx]; 997 1.1 riastrad } else { 998 1.1 riastrad dmabuf = NULL; 999 1.1 riastrad } 1000 1.1 riastrad 1001 1.1 riastrad /* Copy the user buffers into kernel temporary areas. This hasn't been 1002 1.1 riastrad * a performance loss compared to VERIFYAREA_READ/ 1003 1.1 riastrad * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct 1004 1.1 riastrad * for locking on FreeBSD. 1005 1.1 riastrad */ 1006 1.1 riastrad if (cmdbuf->size) { 1007 1.1 riastrad kcmd_addr = kmalloc_array(cmdbuf->size, 8, GFP_KERNEL); 1008 1.1 riastrad if (kcmd_addr == NULL) 1009 1.1 riastrad return -ENOMEM; 1010 1.1 riastrad 1011 1.2 riastrad if (copy_from_user(kcmd_addr, cmdbuf->cmd_addr, 1012 1.1 riastrad cmdbuf->size * 8)) 1013 1.1 riastrad { 1014 1.1 riastrad kfree(kcmd_addr); 1015 1.1 riastrad return -EFAULT; 1016 1.1 riastrad } 1017 1.1 riastrad cmdbuf->cmd_addr = kcmd_addr; 1018 1.1 riastrad } 1019 1.1 riastrad if (cmdbuf->vb_size) { 1020 1.3 riastrad kvb_addr = memdup_user(cmdbuf->vb_addr, cmdbuf->vb_size); 1021 1.3 riastrad if (IS_ERR(kvb_addr)) { 1022 1.3 riastrad ret = PTR_ERR(kvb_addr); 1023 1.3 riastrad kvb_addr = NULL; 1024 1.1 riastrad goto done; 1025 1.1 riastrad } 1026 1.1 riastrad cmdbuf->vb_addr = kvb_addr; 1027 1.1 riastrad } 1028 1.1 riastrad if (cmdbuf->nbox) { 1029 1.1 riastrad kbox_addr = kmalloc_array(cmdbuf->nbox, sizeof(struct drm_clip_rect), 1030 1.1 riastrad GFP_KERNEL); 1031 1.1 riastrad if (kbox_addr == NULL) { 1032 1.1 riastrad ret = -ENOMEM; 1033 1.1 riastrad goto done; 1034 1.1 riastrad } 1035 1.1 riastrad 1036 1.2 riastrad if (copy_from_user(kbox_addr, cmdbuf->box_addr, 1037 1.1 riastrad cmdbuf->nbox * sizeof(struct drm_clip_rect))) { 1038 1.1 riastrad ret = -EFAULT; 1039 1.1 riastrad goto done; 1040 1.1 riastrad } 1041 1.1 riastrad cmdbuf->box_addr = kbox_addr; 1042 1.1 riastrad } 1043 1.1 riastrad 1044 1.1 riastrad /* Make sure writes to DMA buffers are finished before sending 1045 1.1 riastrad * DMA commands to the graphics hardware. */ 1046 1.2 riastrad mb(); 1047 1.1 riastrad 1048 1.1 riastrad /* Coming from user space. Don't know if the Xserver has 1049 1.1 riastrad * emitted wait commands. Assuming the worst. */ 1050 1.1 riastrad dev_priv->waiting = 1; 1051 1.1 riastrad 1052 1.1 riastrad i = 0; 1053 1.1 riastrad first_draw_cmd = NULL; 1054 1.1 riastrad while (i < cmdbuf->size) { 1055 1.1 riastrad drm_savage_cmd_header_t cmd_header; 1056 1.1 riastrad cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr; 1057 1.1 riastrad cmdbuf->cmd_addr++; 1058 1.1 riastrad i++; 1059 1.1 riastrad 1060 1.1 riastrad /* Group drawing commands with same state to minimize 1061 1.1 riastrad * iterations over clip rects. */ 1062 1.1 riastrad j = 0; 1063 1.1 riastrad switch (cmd_header.cmd.cmd) { 1064 1.1 riastrad case SAVAGE_CMD_DMA_IDX: 1065 1.1 riastrad case SAVAGE_CMD_VB_IDX: 1066 1.1 riastrad j = (cmd_header.idx.count + 3) / 4; 1067 1.1 riastrad if (i + j > cmdbuf->size) { 1068 1.1 riastrad DRM_ERROR("indexed drawing command extends " 1069 1.1 riastrad "beyond end of command buffer\n"); 1070 1.1 riastrad DMA_FLUSH(); 1071 1.1 riastrad ret = -EINVAL; 1072 1.1 riastrad goto done; 1073 1.1 riastrad } 1074 1.1 riastrad /* fall through */ 1075 1.1 riastrad case SAVAGE_CMD_DMA_PRIM: 1076 1.1 riastrad case SAVAGE_CMD_VB_PRIM: 1077 1.1 riastrad if (!first_draw_cmd) 1078 1.1 riastrad first_draw_cmd = cmdbuf->cmd_addr - 1; 1079 1.1 riastrad cmdbuf->cmd_addr += j; 1080 1.1 riastrad i += j; 1081 1.1 riastrad break; 1082 1.1 riastrad default: 1083 1.1 riastrad if (first_draw_cmd) { 1084 1.1 riastrad ret = savage_dispatch_draw( 1085 1.1 riastrad dev_priv, first_draw_cmd, 1086 1.1 riastrad cmdbuf->cmd_addr - 1, 1087 1.1 riastrad dmabuf, cmdbuf->vb_addr, cmdbuf->vb_size, 1088 1.1 riastrad cmdbuf->vb_stride, 1089 1.1 riastrad cmdbuf->nbox, cmdbuf->box_addr); 1090 1.1 riastrad if (ret != 0) 1091 1.1 riastrad goto done; 1092 1.1 riastrad first_draw_cmd = NULL; 1093 1.1 riastrad } 1094 1.1 riastrad } 1095 1.1 riastrad if (first_draw_cmd) 1096 1.1 riastrad continue; 1097 1.1 riastrad 1098 1.1 riastrad switch (cmd_header.cmd.cmd) { 1099 1.1 riastrad case SAVAGE_CMD_STATE: 1100 1.1 riastrad j = (cmd_header.state.count + 1) / 2; 1101 1.1 riastrad if (i + j > cmdbuf->size) { 1102 1.1 riastrad DRM_ERROR("command SAVAGE_CMD_STATE extends " 1103 1.1 riastrad "beyond end of command buffer\n"); 1104 1.1 riastrad DMA_FLUSH(); 1105 1.1 riastrad ret = -EINVAL; 1106 1.1 riastrad goto done; 1107 1.1 riastrad } 1108 1.1 riastrad ret = savage_dispatch_state(dev_priv, &cmd_header, 1109 1.1 riastrad (const uint32_t *)cmdbuf->cmd_addr); 1110 1.1 riastrad cmdbuf->cmd_addr += j; 1111 1.1 riastrad i += j; 1112 1.1 riastrad break; 1113 1.1 riastrad case SAVAGE_CMD_CLEAR: 1114 1.1 riastrad if (i + 1 > cmdbuf->size) { 1115 1.1 riastrad DRM_ERROR("command SAVAGE_CMD_CLEAR extends " 1116 1.1 riastrad "beyond end of command buffer\n"); 1117 1.1 riastrad DMA_FLUSH(); 1118 1.1 riastrad ret = -EINVAL; 1119 1.1 riastrad goto done; 1120 1.1 riastrad } 1121 1.1 riastrad ret = savage_dispatch_clear(dev_priv, &cmd_header, 1122 1.1 riastrad cmdbuf->cmd_addr, 1123 1.1 riastrad cmdbuf->nbox, 1124 1.1 riastrad cmdbuf->box_addr); 1125 1.1 riastrad cmdbuf->cmd_addr++; 1126 1.1 riastrad i++; 1127 1.1 riastrad break; 1128 1.1 riastrad case SAVAGE_CMD_SWAP: 1129 1.1 riastrad ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox, 1130 1.1 riastrad cmdbuf->box_addr); 1131 1.1 riastrad break; 1132 1.1 riastrad default: 1133 1.1 riastrad DRM_ERROR("invalid command 0x%x\n", 1134 1.1 riastrad cmd_header.cmd.cmd); 1135 1.1 riastrad DMA_FLUSH(); 1136 1.1 riastrad ret = -EINVAL; 1137 1.1 riastrad goto done; 1138 1.1 riastrad } 1139 1.1 riastrad 1140 1.1 riastrad if (ret != 0) { 1141 1.1 riastrad DMA_FLUSH(); 1142 1.1 riastrad goto done; 1143 1.1 riastrad } 1144 1.1 riastrad } 1145 1.1 riastrad 1146 1.1 riastrad if (first_draw_cmd) { 1147 1.1 riastrad ret = savage_dispatch_draw ( 1148 1.1 riastrad dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf, 1149 1.1 riastrad cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride, 1150 1.1 riastrad cmdbuf->nbox, cmdbuf->box_addr); 1151 1.1 riastrad if (ret != 0) { 1152 1.1 riastrad DMA_FLUSH(); 1153 1.1 riastrad goto done; 1154 1.1 riastrad } 1155 1.1 riastrad } 1156 1.1 riastrad 1157 1.1 riastrad DMA_FLUSH(); 1158 1.1 riastrad 1159 1.1 riastrad if (dmabuf && cmdbuf->discard) { 1160 1.1 riastrad drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private; 1161 1.1 riastrad uint16_t event; 1162 1.1 riastrad event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D); 1163 1.1 riastrad SET_AGE(&buf_priv->age, event, dev_priv->event_wrap); 1164 1.1 riastrad savage_freelist_put(dev, dmabuf); 1165 1.1 riastrad } 1166 1.1 riastrad 1167 1.1 riastrad done: 1168 1.1 riastrad /* If we didn't need to allocate them, these'll be NULL */ 1169 1.1 riastrad kfree(kcmd_addr); 1170 1.1 riastrad kfree(kvb_addr); 1171 1.1 riastrad kfree(kbox_addr); 1172 1.1 riastrad 1173 1.1 riastrad return ret; 1174 1.1 riastrad } 1175