1/* 2 * Copyright 2008 Advanced Micro Devices, Inc. 3 * Copyright 2008 Red Hat Inc. 4 * Copyright 2009 Jerome Glisse. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Dave Airlie 25 * Alex Deucher 26 * Jerome Glisse 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <dev/drm2/drmP.h> 33#include <dev/drm2/radeon/radeon_drm.h> 34#include "radeon_reg.h" 35#include "radeon.h" 36#include "radeon_asic.h" 37 38#include "r100d.h" 39#include "r200_reg_safe.h" 40 41#include "r100_track.h" 42 43static int r200_get_vtx_size_0(uint32_t vtx_fmt_0) 44{ 45 int vtx_size, i; 46 vtx_size = 2; 47 48 if (vtx_fmt_0 & R200_VTX_Z0) 49 vtx_size++; 50 if (vtx_fmt_0 & R200_VTX_W0) 51 vtx_size++; 52 /* blend weight */ 53 if (vtx_fmt_0 & (0x7 << R200_VTX_WEIGHT_COUNT_SHIFT)) 54 vtx_size += (vtx_fmt_0 >> R200_VTX_WEIGHT_COUNT_SHIFT) & 0x7; 55 if (vtx_fmt_0 & R200_VTX_PV_MATRIX_SEL) 56 vtx_size++; 57 if (vtx_fmt_0 & R200_VTX_N0) 58 vtx_size += 3; 59 if (vtx_fmt_0 & R200_VTX_POINT_SIZE) 60 vtx_size++; 61 if (vtx_fmt_0 & R200_VTX_DISCRETE_FOG) 62 vtx_size++; 63 if (vtx_fmt_0 & R200_VTX_SHININESS_0) 64 vtx_size++; 65 if (vtx_fmt_0 & R200_VTX_SHININESS_1) 66 vtx_size++; 67 for (i = 0; i < 8; i++) { 68 int color_size = (vtx_fmt_0 >> (11 + 2*i)) & 0x3; 69 switch (color_size) { 70 case 0: break; 71 case 1: vtx_size++; break; 72 case 2: vtx_size += 3; break; 73 case 3: vtx_size += 4; break; 74 } 75 } 76 if (vtx_fmt_0 & R200_VTX_XY1) 77 vtx_size += 2; 78 if (vtx_fmt_0 & R200_VTX_Z1) 79 vtx_size++; 80 if (vtx_fmt_0 & R200_VTX_W1) 81 vtx_size++; 82 if (vtx_fmt_0 & R200_VTX_N1) 83 vtx_size += 3; 84 return vtx_size; 85} 86 87int r200_copy_dma(struct radeon_device *rdev, 88 uint64_t src_offset, 89 uint64_t dst_offset, 90 unsigned num_gpu_pages, 91 struct radeon_fence **fence) 92{ 93 struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; 94 uint32_t size; 95 uint32_t cur_size; 96 int i, num_loops; 97 int r = 0; 98 99 /* radeon pitch is /64 */ 100 size = num_gpu_pages << RADEON_GPU_PAGE_SHIFT; 101 num_loops = DIV_ROUND_UP(size, 0x1FFFFF); 102 r = radeon_ring_lock(rdev, ring, num_loops * 4 + 64); 103 if (r) { 104 DRM_ERROR("radeon: moving bo (%d).\n", r); 105 return r; 106 } 107 /* Must wait for 2D idle & clean before DMA or hangs might happen */ 108 radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); 109 radeon_ring_write(ring, (1 << 16)); 110 for (i = 0; i < num_loops; i++) { 111 cur_size = size; 112 if (cur_size > 0x1FFFFF) { 113 cur_size = 0x1FFFFF; 114 } 115 size -= cur_size; 116 radeon_ring_write(ring, PACKET0(0x720, 2)); 117 radeon_ring_write(ring, src_offset); 118 radeon_ring_write(ring, dst_offset); 119 radeon_ring_write(ring, cur_size | (1U << 31) | (1 << 30)); 120 src_offset += cur_size; 121 dst_offset += cur_size; 122 } 123 radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0)); 124 radeon_ring_write(ring, RADEON_WAIT_DMA_GUI_IDLE); 125 if (fence) { 126 r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); 127 } 128 radeon_ring_unlock_commit(rdev, ring); 129 return r; 130} 131 132 133static int r200_get_vtx_size_1(uint32_t vtx_fmt_1) 134{ 135 int vtx_size, i, tex_size; 136 vtx_size = 0; 137 for (i = 0; i < 6; i++) { 138 tex_size = (vtx_fmt_1 >> (i * 3)) & 0x7; 139 if (tex_size > 4) 140 continue; 141 vtx_size += tex_size; 142 } 143 return vtx_size; 144} 145 146int r200_packet0_check(struct radeon_cs_parser *p, 147 struct radeon_cs_packet *pkt, 148 unsigned idx, unsigned reg) 149{ 150 struct radeon_cs_reloc *reloc; 151 struct r100_cs_track *track; 152 volatile uint32_t *ib; 153 uint32_t tmp; 154 int r; 155 int i; 156 int face; 157 u32 tile_flags = 0; 158 u32 idx_value; 159 160 ib = p->ib.ptr; 161 track = (struct r100_cs_track *)p->track; 162 idx_value = radeon_get_ib_value(p, idx); 163 switch (reg) { 164 case RADEON_CRTC_GUI_TRIG_VLINE: 165 r = r100_cs_packet_parse_vline(p); 166 if (r) { 167 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 168 idx, reg); 169 r100_cs_dump_packet(p, pkt); 170 return r; 171 } 172 break; 173 /* FIXME: only allow PACKET3 blit? easier to check for out of 174 * range access */ 175 case RADEON_DST_PITCH_OFFSET: 176 case RADEON_SRC_PITCH_OFFSET: 177 r = r100_reloc_pitch_offset(p, pkt, idx, reg); 178 if (r) 179 return r; 180 break; 181 case RADEON_RB3D_DEPTHOFFSET: 182 r = r100_cs_packet_next_reloc(p, &reloc); 183 if (r) { 184 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 185 idx, reg); 186 r100_cs_dump_packet(p, pkt); 187 return r; 188 } 189 track->zb.robj = reloc->robj; 190 track->zb.offset = idx_value; 191 track->zb_dirty = true; 192 ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); 193 break; 194 case RADEON_RB3D_COLOROFFSET: 195 r = r100_cs_packet_next_reloc(p, &reloc); 196 if (r) { 197 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 198 idx, reg); 199 r100_cs_dump_packet(p, pkt); 200 return r; 201 } 202 track->cb[0].robj = reloc->robj; 203 track->cb[0].offset = idx_value; 204 track->cb_dirty = true; 205 ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); 206 break; 207 case R200_PP_TXOFFSET_0: 208 case R200_PP_TXOFFSET_1: 209 case R200_PP_TXOFFSET_2: 210 case R200_PP_TXOFFSET_3: 211 case R200_PP_TXOFFSET_4: 212 case R200_PP_TXOFFSET_5: 213 i = (reg - R200_PP_TXOFFSET_0) / 24; 214 r = r100_cs_packet_next_reloc(p, &reloc); 215 if (r) { 216 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 217 idx, reg); 218 r100_cs_dump_packet(p, pkt); 219 return r; 220 } 221 if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 222 if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) 223 tile_flags |= R200_TXO_MACRO_TILE; 224 if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) 225 tile_flags |= R200_TXO_MICRO_TILE; 226 227 tmp = idx_value & ~(0x7 << 2); 228 tmp |= tile_flags; 229 ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset); 230 } else 231 ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); 232 track->textures[i].robj = reloc->robj; 233 track->tex_dirty = true; 234 break; 235 case R200_PP_CUBIC_OFFSET_F1_0: 236 case R200_PP_CUBIC_OFFSET_F2_0: 237 case R200_PP_CUBIC_OFFSET_F3_0: 238 case R200_PP_CUBIC_OFFSET_F4_0: 239 case R200_PP_CUBIC_OFFSET_F5_0: 240 case R200_PP_CUBIC_OFFSET_F1_1: 241 case R200_PP_CUBIC_OFFSET_F2_1: 242 case R200_PP_CUBIC_OFFSET_F3_1: 243 case R200_PP_CUBIC_OFFSET_F4_1: 244 case R200_PP_CUBIC_OFFSET_F5_1: 245 case R200_PP_CUBIC_OFFSET_F1_2: 246 case R200_PP_CUBIC_OFFSET_F2_2: 247 case R200_PP_CUBIC_OFFSET_F3_2: 248 case R200_PP_CUBIC_OFFSET_F4_2: 249 case R200_PP_CUBIC_OFFSET_F5_2: 250 case R200_PP_CUBIC_OFFSET_F1_3: 251 case R200_PP_CUBIC_OFFSET_F2_3: 252 case R200_PP_CUBIC_OFFSET_F3_3: 253 case R200_PP_CUBIC_OFFSET_F4_3: 254 case R200_PP_CUBIC_OFFSET_F5_3: 255 case R200_PP_CUBIC_OFFSET_F1_4: 256 case R200_PP_CUBIC_OFFSET_F2_4: 257 case R200_PP_CUBIC_OFFSET_F3_4: 258 case R200_PP_CUBIC_OFFSET_F4_4: 259 case R200_PP_CUBIC_OFFSET_F5_4: 260 case R200_PP_CUBIC_OFFSET_F1_5: 261 case R200_PP_CUBIC_OFFSET_F2_5: 262 case R200_PP_CUBIC_OFFSET_F3_5: 263 case R200_PP_CUBIC_OFFSET_F4_5: 264 case R200_PP_CUBIC_OFFSET_F5_5: 265 i = (reg - R200_PP_TXOFFSET_0) / 24; 266 face = (reg - ((i * 24) + R200_PP_TXOFFSET_0)) / 4; 267 r = r100_cs_packet_next_reloc(p, &reloc); 268 if (r) { 269 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 270 idx, reg); 271 r100_cs_dump_packet(p, pkt); 272 return r; 273 } 274 track->textures[i].cube_info[face - 1].offset = idx_value; 275 ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); 276 track->textures[i].cube_info[face - 1].robj = reloc->robj; 277 track->tex_dirty = true; 278 break; 279 case RADEON_RE_WIDTH_HEIGHT: 280 track->maxy = ((idx_value >> 16) & 0x7FF); 281 track->cb_dirty = true; 282 track->zb_dirty = true; 283 break; 284 case RADEON_RB3D_COLORPITCH: 285 r = r100_cs_packet_next_reloc(p, &reloc); 286 if (r) { 287 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 288 idx, reg); 289 r100_cs_dump_packet(p, pkt); 290 return r; 291 } 292 293 if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) { 294 if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) 295 tile_flags |= RADEON_COLOR_TILE_ENABLE; 296 if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) 297 tile_flags |= RADEON_COLOR_MICROTILE_ENABLE; 298 299 tmp = idx_value & ~(0x7 << 16); 300 tmp |= tile_flags; 301 ib[idx] = tmp; 302 } else 303 ib[idx] = idx_value; 304 305 track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK; 306 track->cb_dirty = true; 307 break; 308 case RADEON_RB3D_DEPTHPITCH: 309 track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK; 310 track->zb_dirty = true; 311 break; 312 case RADEON_RB3D_CNTL: 313 switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) { 314 case 7: 315 case 8: 316 case 9: 317 case 11: 318 case 12: 319 track->cb[0].cpp = 1; 320 break; 321 case 3: 322 case 4: 323 case 15: 324 track->cb[0].cpp = 2; 325 break; 326 case 6: 327 track->cb[0].cpp = 4; 328 break; 329 default: 330 DRM_ERROR("Invalid color buffer format (%d) !\n", 331 ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f)); 332 return -EINVAL; 333 } 334 if (idx_value & RADEON_DEPTHXY_OFFSET_ENABLE) { 335 DRM_ERROR("No support for depth xy offset in kms\n"); 336 return -EINVAL; 337 } 338 339 track->z_enabled = !!(idx_value & RADEON_Z_ENABLE); 340 track->cb_dirty = true; 341 track->zb_dirty = true; 342 break; 343 case RADEON_RB3D_ZSTENCILCNTL: 344 switch (idx_value & 0xf) { 345 case 0: 346 track->zb.cpp = 2; 347 break; 348 case 2: 349 case 3: 350 case 4: 351 case 5: 352 case 9: 353 case 11: 354 track->zb.cpp = 4; 355 break; 356 default: 357 break; 358 } 359 track->zb_dirty = true; 360 break; 361 case RADEON_RB3D_ZPASS_ADDR: 362 r = r100_cs_packet_next_reloc(p, &reloc); 363 if (r) { 364 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 365 idx, reg); 366 r100_cs_dump_packet(p, pkt); 367 return r; 368 } 369 ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset); 370 break; 371 case RADEON_PP_CNTL: 372 { 373 uint32_t temp = idx_value >> 4; 374 for (i = 0; i < track->num_texture; i++) 375 track->textures[i].enabled = !!(temp & (1 << i)); 376 track->tex_dirty = true; 377 } 378 break; 379 case RADEON_SE_VF_CNTL: 380 track->vap_vf_cntl = idx_value; 381 break; 382 case 0x210c: 383 /* VAP_VF_MAX_VTX_INDX */ 384 track->max_indx = idx_value & 0x00FFFFFFUL; 385 break; 386 case R200_SE_VTX_FMT_0: 387 track->vtx_size = r200_get_vtx_size_0(idx_value); 388 break; 389 case R200_SE_VTX_FMT_1: 390 track->vtx_size += r200_get_vtx_size_1(idx_value); 391 break; 392 case R200_PP_TXSIZE_0: 393 case R200_PP_TXSIZE_1: 394 case R200_PP_TXSIZE_2: 395 case R200_PP_TXSIZE_3: 396 case R200_PP_TXSIZE_4: 397 case R200_PP_TXSIZE_5: 398 i = (reg - R200_PP_TXSIZE_0) / 32; 399 track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1; 400 track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1; 401 track->tex_dirty = true; 402 break; 403 case R200_PP_TXPITCH_0: 404 case R200_PP_TXPITCH_1: 405 case R200_PP_TXPITCH_2: 406 case R200_PP_TXPITCH_3: 407 case R200_PP_TXPITCH_4: 408 case R200_PP_TXPITCH_5: 409 i = (reg - R200_PP_TXPITCH_0) / 32; 410 track->textures[i].pitch = idx_value + 32; 411 track->tex_dirty = true; 412 break; 413 case R200_PP_TXFILTER_0: 414 case R200_PP_TXFILTER_1: 415 case R200_PP_TXFILTER_2: 416 case R200_PP_TXFILTER_3: 417 case R200_PP_TXFILTER_4: 418 case R200_PP_TXFILTER_5: 419 i = (reg - R200_PP_TXFILTER_0) / 32; 420 track->textures[i].num_levels = ((idx_value & R200_MAX_MIP_LEVEL_MASK) 421 >> R200_MAX_MIP_LEVEL_SHIFT); 422 tmp = (idx_value >> 23) & 0x7; 423 if (tmp == 2 || tmp == 6) 424 track->textures[i].roundup_w = false; 425 tmp = (idx_value >> 27) & 0x7; 426 if (tmp == 2 || tmp == 6) 427 track->textures[i].roundup_h = false; 428 track->tex_dirty = true; 429 break; 430 case R200_PP_TXMULTI_CTL_0: 431 case R200_PP_TXMULTI_CTL_1: 432 case R200_PP_TXMULTI_CTL_2: 433 case R200_PP_TXMULTI_CTL_3: 434 case R200_PP_TXMULTI_CTL_4: 435 case R200_PP_TXMULTI_CTL_5: 436 i = (reg - R200_PP_TXMULTI_CTL_0) / 32; 437 break; 438 case R200_PP_TXFORMAT_X_0: 439 case R200_PP_TXFORMAT_X_1: 440 case R200_PP_TXFORMAT_X_2: 441 case R200_PP_TXFORMAT_X_3: 442 case R200_PP_TXFORMAT_X_4: 443 case R200_PP_TXFORMAT_X_5: 444 i = (reg - R200_PP_TXFORMAT_X_0) / 32; 445 track->textures[i].txdepth = idx_value & 0x7; 446 tmp = (idx_value >> 16) & 0x3; 447 /* 2D, 3D, CUBE */ 448 switch (tmp) { 449 case 0: 450 case 3: 451 case 4: 452 case 5: 453 case 6: 454 case 7: 455 /* 1D/2D */ 456 track->textures[i].tex_coord_type = 0; 457 break; 458 case 1: 459 /* CUBE */ 460 track->textures[i].tex_coord_type = 2; 461 break; 462 case 2: 463 /* 3D */ 464 track->textures[i].tex_coord_type = 1; 465 break; 466 } 467 track->tex_dirty = true; 468 break; 469 case R200_PP_TXFORMAT_0: 470 case R200_PP_TXFORMAT_1: 471 case R200_PP_TXFORMAT_2: 472 case R200_PP_TXFORMAT_3: 473 case R200_PP_TXFORMAT_4: 474 case R200_PP_TXFORMAT_5: 475 i = (reg - R200_PP_TXFORMAT_0) / 32; 476 if (idx_value & R200_TXFORMAT_NON_POWER2) { 477 track->textures[i].use_pitch = 1; 478 } else { 479 track->textures[i].use_pitch = 0; 480 track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK); 481 track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK); 482 } 483 if (idx_value & R200_TXFORMAT_LOOKUP_DISABLE) 484 track->textures[i].lookup_disable = true; 485 switch ((idx_value & RADEON_TXFORMAT_FORMAT_MASK)) { 486 case R200_TXFORMAT_I8: 487 case R200_TXFORMAT_RGB332: 488 case R200_TXFORMAT_Y8: 489 track->textures[i].cpp = 1; 490 track->textures[i].compress_format = R100_TRACK_COMP_NONE; 491 break; 492 case R200_TXFORMAT_AI88: 493 case R200_TXFORMAT_ARGB1555: 494 case R200_TXFORMAT_RGB565: 495 case R200_TXFORMAT_ARGB4444: 496 case R200_TXFORMAT_VYUY422: 497 case R200_TXFORMAT_YVYU422: 498 case R200_TXFORMAT_LDVDU655: 499 case R200_TXFORMAT_DVDU88: 500 case R200_TXFORMAT_AVYU4444: 501 track->textures[i].cpp = 2; 502 track->textures[i].compress_format = R100_TRACK_COMP_NONE; 503 break; 504 case R200_TXFORMAT_ARGB8888: 505 case R200_TXFORMAT_RGBA8888: 506 case R200_TXFORMAT_ABGR8888: 507 case R200_TXFORMAT_BGR111110: 508 case R200_TXFORMAT_LDVDU8888: 509 track->textures[i].cpp = 4; 510 track->textures[i].compress_format = R100_TRACK_COMP_NONE; 511 break; 512 case R200_TXFORMAT_DXT1: 513 track->textures[i].cpp = 1; 514 track->textures[i].compress_format = R100_TRACK_COMP_DXT1; 515 break; 516 case R200_TXFORMAT_DXT23: 517 case R200_TXFORMAT_DXT45: 518 track->textures[i].cpp = 1; 519 track->textures[i].compress_format = R100_TRACK_COMP_DXT1; 520 break; 521 } 522 track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf); 523 track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf); 524 track->tex_dirty = true; 525 break; 526 case R200_PP_CUBIC_FACES_0: 527 case R200_PP_CUBIC_FACES_1: 528 case R200_PP_CUBIC_FACES_2: 529 case R200_PP_CUBIC_FACES_3: 530 case R200_PP_CUBIC_FACES_4: 531 case R200_PP_CUBIC_FACES_5: 532 tmp = idx_value; 533 i = (reg - R200_PP_CUBIC_FACES_0) / 32; 534 for (face = 0; face < 4; face++) { 535 track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf); 536 track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf); 537 } 538 track->tex_dirty = true; 539 break; 540 default: 541 DRM_ERROR("Forbidden register 0x%04X in cs at %d\n", 542 reg, idx); 543 return -EINVAL; 544 } 545 return 0; 546} 547 548void r200_set_safe_registers(struct radeon_device *rdev) 549{ 550 rdev->config.r100.reg_safe_bm = r200_reg_safe_bm; 551 rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(r200_reg_safe_bm); 552} 553