1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include <drm/drm_framebuffer.h> 7 #include <drm/drm_modeset_helper.h> 8 9 #include "intel_display.h" 10 #include "intel_display_types.h" 11 #include "intel_dpt.h" 12 #include "intel_fb.h" 13 14 #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a)) 15 16 bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) 17 { 18 if (!is_ccs_modifier(fb->modifier)) 19 return false; 20 21 return plane >= fb->format->num_planes / 2; 22 } 23 24 bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane) 25 { 26 return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane); 27 } 28 29 bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane) 30 { 31 return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC && 32 plane == 2; 33 } 34 35 bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane) 36 { 37 return intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && 38 color_plane == 1; 39 } 40 41 bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane) 42 { 43 return fb->modifier == DRM_FORMAT_MOD_LINEAR || 44 is_gen12_ccs_plane(fb, color_plane); 45 } 46 47 int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane) 48 { 49 drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || 50 (main_plane && main_plane >= fb->format->num_planes / 2)); 51 52 return fb->format->num_planes / 2 + main_plane; 53 } 54 55 int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) 56 { 57 drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || 58 ccs_plane < fb->format->num_planes / 2); 59 60 if (is_gen12_ccs_cc_plane(fb, ccs_plane)) 61 return 0; 62 63 return ccs_plane - fb->format->num_planes / 2; 64 } 65 66 static unsigned int gen12_aligned_scanout_stride(const struct intel_framebuffer *fb, 67 int color_plane) 68 { 69 struct drm_i915_private *i915 = to_i915(fb->base.dev); 70 unsigned int stride = fb->base.pitches[color_plane]; 71 72 if (IS_ALDERLAKE_P(i915)) 73 return roundup_pow_of_two(max(stride, 74 8u * intel_tile_width_bytes(&fb->base, color_plane))); 75 76 return stride; 77 } 78 79 static unsigned int gen12_ccs_aux_stride(struct intel_framebuffer *fb, int ccs_plane) 80 { 81 struct drm_i915_private *i915 = to_i915(fb->base.dev); 82 int main_plane = skl_ccs_to_main_plane(&fb->base, ccs_plane); 83 unsigned int main_stride = fb->base.pitches[main_plane]; 84 unsigned int main_tile_width = intel_tile_width_bytes(&fb->base, main_plane); 85 86 /* 87 * On ADL-P the AUX stride must align with a power-of-two aligned main 88 * surface stride. The stride of the allocated main surface object can 89 * be less than this POT stride, which is then autopadded to the POT 90 * size. 91 */ 92 if (IS_ALDERLAKE_P(i915)) 93 main_stride = gen12_aligned_scanout_stride(fb, main_plane); 94 95 return DIV_ROUND_UP(main_stride, 4 * main_tile_width) * 64; 96 } 97 98 int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) 99 { 100 struct drm_i915_private *i915 = to_i915(fb->dev); 101 102 if (is_ccs_modifier(fb->modifier)) 103 return main_to_ccs_plane(fb, main_plane); 104 else if (DISPLAY_VER(i915) < 11 && 105 intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) 106 return 1; 107 else 108 return 0; 109 } 110 111 unsigned int intel_tile_size(const struct drm_i915_private *i915) 112 { 113 return DISPLAY_VER(i915) == 2 ? 2048 : 4096; 114 } 115 116 unsigned int 117 intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) 118 { 119 struct drm_i915_private *dev_priv = to_i915(fb->dev); 120 unsigned int cpp = fb->format->cpp[color_plane]; 121 122 switch (fb->modifier) { 123 case DRM_FORMAT_MOD_LINEAR: 124 return intel_tile_size(dev_priv); 125 case I915_FORMAT_MOD_X_TILED: 126 if (DISPLAY_VER(dev_priv) == 2) 127 return 128; 128 else 129 return 512; 130 case I915_FORMAT_MOD_Y_TILED_CCS: 131 if (is_ccs_plane(fb, color_plane)) 132 return 128; 133 fallthrough; 134 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 135 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 136 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 137 if (is_ccs_plane(fb, color_plane)) 138 return 64; 139 fallthrough; 140 case I915_FORMAT_MOD_Y_TILED: 141 if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv)) 142 return 128; 143 else 144 return 512; 145 case I915_FORMAT_MOD_Yf_TILED_CCS: 146 if (is_ccs_plane(fb, color_plane)) 147 return 128; 148 fallthrough; 149 case I915_FORMAT_MOD_Yf_TILED: 150 switch (cpp) { 151 case 1: 152 return 64; 153 case 2: 154 case 4: 155 return 128; 156 case 8: 157 case 16: 158 return 256; 159 default: 160 MISSING_CASE(cpp); 161 return cpp; 162 } 163 break; 164 default: 165 MISSING_CASE(fb->modifier); 166 return cpp; 167 } 168 } 169 170 unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane) 171 { 172 return intel_tile_size(to_i915(fb->dev)) / 173 intel_tile_width_bytes(fb, color_plane); 174 } 175 176 /* 177 * Return the tile dimensions in pixel units, based on the (2 or 4 kbyte) GTT 178 * page tile size. 179 */ 180 static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane, 181 unsigned int *tile_width, 182 unsigned int *tile_height) 183 { 184 unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane); 185 unsigned int cpp = fb->format->cpp[color_plane]; 186 187 *tile_width = tile_width_bytes / cpp; 188 *tile_height = intel_tile_height(fb, color_plane); 189 } 190 191 /* 192 * Return the tile dimensions in pixel units, based on the tile block size. 193 * The block covers the full GTT page sized tile on all tiled surfaces and 194 * it's a 64 byte portion of the tile on TGL+ CCS surfaces. 195 */ 196 static void intel_tile_block_dims(const struct drm_framebuffer *fb, int color_plane, 197 unsigned int *tile_width, 198 unsigned int *tile_height) 199 { 200 intel_tile_dims(fb, color_plane, tile_width, tile_height); 201 202 if (is_gen12_ccs_plane(fb, color_plane)) 203 *tile_height = 1; 204 } 205 206 unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane) 207 { 208 unsigned int tile_width, tile_height; 209 210 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 211 212 return fb->pitches[color_plane] * tile_height; 213 } 214 215 unsigned int 216 intel_fb_align_height(const struct drm_framebuffer *fb, 217 int color_plane, unsigned int height) 218 { 219 unsigned int tile_height = intel_tile_height(fb, color_plane); 220 221 return ALIGN(height, tile_height); 222 } 223 224 static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) 225 { 226 switch (fb_modifier) { 227 case I915_FORMAT_MOD_X_TILED: 228 return I915_TILING_X; 229 case I915_FORMAT_MOD_Y_TILED: 230 case I915_FORMAT_MOD_Y_TILED_CCS: 231 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 232 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 233 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 234 return I915_TILING_Y; 235 default: 236 return I915_TILING_NONE; 237 } 238 } 239 240 unsigned int intel_cursor_alignment(const struct drm_i915_private *i915) 241 { 242 if (IS_I830(i915)) 243 return 16 * 1024; 244 else if (IS_I85X(i915)) 245 return 256; 246 else if (IS_I845G(i915) || IS_I865G(i915)) 247 return 32; 248 else 249 return 4 * 1024; 250 } 251 252 static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv) 253 { 254 if (DISPLAY_VER(dev_priv) >= 9) 255 return 256 * 1024; 256 else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) || 257 IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) 258 return 128 * 1024; 259 else if (DISPLAY_VER(dev_priv) >= 4) 260 return 4 * 1024; 261 else 262 return 0; 263 } 264 265 unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, 266 int color_plane) 267 { 268 struct drm_i915_private *dev_priv = to_i915(fb->dev); 269 270 if (intel_fb_uses_dpt(fb)) 271 return 512 * 4096; 272 273 /* AUX_DIST needs only 4K alignment */ 274 if (is_ccs_plane(fb, color_plane)) 275 return 4096; 276 277 if (is_semiplanar_uv_plane(fb, color_plane)) { 278 /* 279 * TODO: cross-check wrt. the bspec stride in bytes * 64 bytes 280 * alignment for linear UV planes on all platforms. 281 */ 282 if (DISPLAY_VER(dev_priv) >= 12) { 283 if (fb->modifier == DRM_FORMAT_MOD_LINEAR) 284 return intel_linear_alignment(dev_priv); 285 286 return intel_tile_row_size(fb, color_plane); 287 } 288 289 return 4096; 290 } 291 292 drm_WARN_ON(&dev_priv->drm, color_plane != 0); 293 294 switch (fb->modifier) { 295 case DRM_FORMAT_MOD_LINEAR: 296 return intel_linear_alignment(dev_priv); 297 case I915_FORMAT_MOD_X_TILED: 298 if (HAS_ASYNC_FLIPS(dev_priv)) 299 return 256 * 1024; 300 return 0; 301 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: 302 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: 303 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: 304 return 16 * 1024; 305 case I915_FORMAT_MOD_Y_TILED_CCS: 306 case I915_FORMAT_MOD_Yf_TILED_CCS: 307 case I915_FORMAT_MOD_Y_TILED: 308 case I915_FORMAT_MOD_Yf_TILED: 309 return 1 * 1024 * 1024; 310 default: 311 MISSING_CASE(fb->modifier); 312 return 0; 313 } 314 } 315 316 void intel_fb_plane_get_subsampling(int *hsub, int *vsub, 317 const struct drm_framebuffer *fb, 318 int color_plane) 319 { 320 int main_plane; 321 322 if (color_plane == 0) { 323 *hsub = 1; 324 *vsub = 1; 325 326 return; 327 } 328 329 /* 330 * TODO: Deduct the subsampling from the char block for all CCS 331 * formats and planes. 332 */ 333 if (!is_gen12_ccs_plane(fb, color_plane)) { 334 *hsub = fb->format->hsub; 335 *vsub = fb->format->vsub; 336 337 return; 338 } 339 340 main_plane = skl_ccs_to_main_plane(fb, color_plane); 341 *hsub = drm_format_info_block_width(fb->format, color_plane) / 342 drm_format_info_block_width(fb->format, main_plane); 343 344 /* 345 * The min stride check in the core framebuffer_check() function 346 * assumes that format->hsub applies to every plane except for the 347 * first plane. That's incorrect for the CCS AUX plane of the first 348 * plane, but for the above check to pass we must define the block 349 * width with that subsampling applied to it. Adjust the width here 350 * accordingly, so we can calculate the actual subsampling factor. 351 */ 352 if (main_plane == 0) 353 *hsub *= fb->format->hsub; 354 355 *vsub = 32; 356 } 357 358 static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h) 359 { 360 struct drm_i915_private *i915 = to_i915(fb->base.dev); 361 int main_plane = is_ccs_plane(&fb->base, color_plane) ? 362 skl_ccs_to_main_plane(&fb->base, color_plane) : 0; 363 unsigned int main_width = fb->base.width; 364 unsigned int main_height = fb->base.height; 365 int main_hsub, main_vsub; 366 int hsub, vsub; 367 368 /* 369 * On ADL-P the CCS AUX surface layout always aligns with the 370 * power-of-two aligned main surface stride. The main surface 371 * stride in the allocated FB object may not be power-of-two 372 * sized, in which case it is auto-padded to the POT size. 373 */ 374 if (IS_ALDERLAKE_P(i915) && is_ccs_plane(&fb->base, color_plane)) 375 main_width = gen12_aligned_scanout_stride(fb, 0) / 376 fb->base.format->cpp[0]; 377 378 intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane); 379 intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane); 380 381 *w = DIV_ROUND_UP(main_width, main_hsub * hsub); 382 *h = DIV_ROUND_UP(main_height, main_vsub * vsub); 383 } 384 385 static u32 intel_adjust_tile_offset(int *x, int *y, 386 unsigned int tile_width, 387 unsigned int tile_height, 388 unsigned int tile_size, 389 unsigned int pitch_tiles, 390 u32 old_offset, 391 u32 new_offset) 392 { 393 unsigned int pitch_pixels = pitch_tiles * tile_width; 394 unsigned int tiles; 395 396 WARN_ON(old_offset & (tile_size - 1)); 397 WARN_ON(new_offset & (tile_size - 1)); 398 WARN_ON(new_offset > old_offset); 399 400 tiles = (old_offset - new_offset) / tile_size; 401 402 *y += tiles / pitch_tiles * tile_height; 403 *x += tiles % pitch_tiles * tile_width; 404 405 /* minimize x in case it got needlessly big */ 406 *y += *x / pitch_pixels * tile_height; 407 *x %= pitch_pixels; 408 409 return new_offset; 410 } 411 412 static u32 intel_adjust_aligned_offset(int *x, int *y, 413 const struct drm_framebuffer *fb, 414 int color_plane, 415 unsigned int rotation, 416 unsigned int pitch, 417 u32 old_offset, u32 new_offset) 418 { 419 struct drm_i915_private *i915 = to_i915(fb->dev); 420 unsigned int cpp = fb->format->cpp[color_plane]; 421 422 drm_WARN_ON(&i915->drm, new_offset > old_offset); 423 424 if (!is_surface_linear(fb, color_plane)) { 425 unsigned int tile_size, tile_width, tile_height; 426 unsigned int pitch_tiles; 427 428 tile_size = intel_tile_size(i915); 429 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 430 431 if (drm_rotation_90_or_270(rotation)) { 432 pitch_tiles = pitch / tile_height; 433 swap(tile_width, tile_height); 434 } else { 435 pitch_tiles = pitch / (tile_width * cpp); 436 } 437 438 intel_adjust_tile_offset(x, y, tile_width, tile_height, 439 tile_size, pitch_tiles, 440 old_offset, new_offset); 441 } else { 442 old_offset += *y * pitch + *x * cpp; 443 444 *y = (old_offset - new_offset) / pitch; 445 *x = ((old_offset - new_offset) - *y * pitch) / cpp; 446 } 447 448 return new_offset; 449 } 450 451 /* 452 * Adjust the tile offset by moving the difference into 453 * the x/y offsets. 454 */ 455 u32 intel_plane_adjust_aligned_offset(int *x, int *y, 456 const struct intel_plane_state *state, 457 int color_plane, 458 u32 old_offset, u32 new_offset) 459 { 460 return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane, 461 state->hw.rotation, 462 state->view.color_plane[color_plane].stride, 463 old_offset, new_offset); 464 } 465 466 /* 467 * Computes the aligned offset to the base tile and adjusts 468 * x, y. bytes per pixel is assumed to be a power-of-two. 469 * 470 * In the 90/270 rotated case, x and y are assumed 471 * to be already rotated to match the rotated GTT view, and 472 * pitch is the tile_height aligned framebuffer height. 473 * 474 * This function is used when computing the derived information 475 * under intel_framebuffer, so using any of that information 476 * here is not allowed. Anything under drm_framebuffer can be 477 * used. This is why the user has to pass in the pitch since it 478 * is specified in the rotated orientation. 479 */ 480 static u32 intel_compute_aligned_offset(struct drm_i915_private *i915, 481 int *x, int *y, 482 const struct drm_framebuffer *fb, 483 int color_plane, 484 unsigned int pitch, 485 unsigned int rotation, 486 u32 alignment) 487 { 488 unsigned int cpp = fb->format->cpp[color_plane]; 489 u32 offset, offset_aligned; 490 491 if (!is_surface_linear(fb, color_plane)) { 492 unsigned int tile_size, tile_width, tile_height; 493 unsigned int tile_rows, tiles, pitch_tiles; 494 495 tile_size = intel_tile_size(i915); 496 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 497 498 if (drm_rotation_90_or_270(rotation)) { 499 pitch_tiles = pitch / tile_height; 500 swap(tile_width, tile_height); 501 } else { 502 pitch_tiles = pitch / (tile_width * cpp); 503 } 504 505 tile_rows = *y / tile_height; 506 *y %= tile_height; 507 508 tiles = *x / tile_width; 509 *x %= tile_width; 510 511 offset = (tile_rows * pitch_tiles + tiles) * tile_size; 512 513 offset_aligned = offset; 514 if (alignment) 515 offset_aligned = rounddown(offset_aligned, alignment); 516 517 intel_adjust_tile_offset(x, y, tile_width, tile_height, 518 tile_size, pitch_tiles, 519 offset, offset_aligned); 520 } else { 521 offset = *y * pitch + *x * cpp; 522 offset_aligned = offset; 523 if (alignment) { 524 offset_aligned = rounddown(offset_aligned, alignment); 525 *y = (offset % alignment) / pitch; 526 *x = ((offset % alignment) - *y * pitch) / cpp; 527 } else { 528 *y = *x = 0; 529 } 530 } 531 532 return offset_aligned; 533 } 534 535 u32 intel_plane_compute_aligned_offset(int *x, int *y, 536 const struct intel_plane_state *state, 537 int color_plane) 538 { 539 struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane); 540 struct drm_i915_private *i915 = to_i915(intel_plane->base.dev); 541 const struct drm_framebuffer *fb = state->hw.fb; 542 unsigned int rotation = state->hw.rotation; 543 int pitch = state->view.color_plane[color_plane].stride; 544 u32 alignment; 545 546 if (intel_plane->id == PLANE_CURSOR) 547 alignment = intel_cursor_alignment(i915); 548 else 549 alignment = intel_surf_alignment(fb, color_plane); 550 551 return intel_compute_aligned_offset(i915, x, y, fb, color_plane, 552 pitch, rotation, alignment); 553 } 554 555 /* Convert the fb->offset[] into x/y offsets */ 556 static int intel_fb_offset_to_xy(int *x, int *y, 557 const struct drm_framebuffer *fb, 558 int color_plane) 559 { 560 struct drm_i915_private *i915 = to_i915(fb->dev); 561 unsigned int height; 562 u32 alignment; 563 564 if (DISPLAY_VER(i915) >= 12 && 565 is_semiplanar_uv_plane(fb, color_plane)) 566 alignment = intel_tile_row_size(fb, color_plane); 567 else if (fb->modifier != DRM_FORMAT_MOD_LINEAR) 568 alignment = intel_tile_size(i915); 569 else 570 alignment = 0; 571 572 if (alignment != 0 && fb->offsets[color_plane] % alignment) { 573 drm_dbg_kms(&i915->drm, 574 "Misaligned offset 0x%08x for color plane %d\n", 575 fb->offsets[color_plane], color_plane); 576 return -EINVAL; 577 } 578 579 height = drm_framebuffer_plane_height(fb->height, fb, color_plane); 580 height = ALIGN(height, intel_tile_height(fb, color_plane)); 581 582 /* Catch potential overflows early */ 583 if (add_overflows_t(u32, mul_u32_u32(height, fb->pitches[color_plane]), 584 fb->offsets[color_plane])) { 585 drm_dbg_kms(&i915->drm, 586 "Bad offset 0x%08x or pitch %d for color plane %d\n", 587 fb->offsets[color_plane], fb->pitches[color_plane], 588 color_plane); 589 return -ERANGE; 590 } 591 592 *x = 0; 593 *y = 0; 594 595 intel_adjust_aligned_offset(x, y, 596 fb, color_plane, DRM_MODE_ROTATE_0, 597 fb->pitches[color_plane], 598 fb->offsets[color_plane], 0); 599 600 return 0; 601 } 602 603 static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane, int x, int y) 604 { 605 struct drm_i915_private *i915 = to_i915(fb->dev); 606 const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 607 int main_plane; 608 int hsub, vsub; 609 int tile_width, tile_height; 610 int ccs_x, ccs_y; 611 int main_x, main_y; 612 613 if (!is_ccs_plane(fb, ccs_plane) || is_gen12_ccs_cc_plane(fb, ccs_plane)) 614 return 0; 615 616 /* 617 * While all the tile dimensions are based on a 2k or 4k GTT page size 618 * here the main and CCS coordinates must match only within a (64 byte 619 * on TGL+) block inside the tile. 620 */ 621 intel_tile_block_dims(fb, ccs_plane, &tile_width, &tile_height); 622 intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); 623 624 tile_width *= hsub; 625 tile_height *= vsub; 626 627 ccs_x = (x * hsub) % tile_width; 628 ccs_y = (y * vsub) % tile_height; 629 630 main_plane = skl_ccs_to_main_plane(fb, ccs_plane); 631 main_x = intel_fb->normal_view.color_plane[main_plane].x % tile_width; 632 main_y = intel_fb->normal_view.color_plane[main_plane].y % tile_height; 633 634 /* 635 * CCS doesn't have its own x/y offset register, so the intra CCS tile 636 * x/y offsets must match between CCS and the main surface. 637 */ 638 if (main_x != ccs_x || main_y != ccs_y) { 639 drm_dbg_kms(&i915->drm, 640 "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n", 641 main_x, main_y, 642 ccs_x, ccs_y, 643 intel_fb->normal_view.color_plane[main_plane].x, 644 intel_fb->normal_view.color_plane[main_plane].y, 645 x, y); 646 return -EINVAL; 647 } 648 649 return 0; 650 } 651 652 static bool intel_plane_can_remap(const struct intel_plane_state *plane_state) 653 { 654 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 655 struct drm_i915_private *i915 = to_i915(plane->base.dev); 656 const struct drm_framebuffer *fb = plane_state->hw.fb; 657 int i; 658 659 /* We don't want to deal with remapping with cursors */ 660 if (plane->id == PLANE_CURSOR) 661 return false; 662 663 /* 664 * The display engine limits already match/exceed the 665 * render engine limits, so not much point in remapping. 666 * Would also need to deal with the fence POT alignment 667 * and gen2 2KiB GTT tile size. 668 */ 669 if (DISPLAY_VER(i915) < 4) 670 return false; 671 672 /* 673 * The new CCS hash mode isn't compatible with remapping as 674 * the virtual address of the pages affects the compressed data. 675 */ 676 if (is_ccs_modifier(fb->modifier)) 677 return false; 678 679 /* Linear needs a page aligned stride for remapping */ 680 if (fb->modifier == DRM_FORMAT_MOD_LINEAR) { 681 unsigned int alignment = intel_tile_size(i915) - 1; 682 683 for (i = 0; i < fb->format->num_planes; i++) { 684 if (fb->pitches[i] & alignment) 685 return false; 686 } 687 } 688 689 return true; 690 } 691 692 bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb) 693 { 694 struct drm_i915_private *i915 = to_i915(fb->base.dev); 695 696 return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR; 697 } 698 699 static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation) 700 { 701 if (drm_rotation_90_or_270(rotation)) 702 return fb->rotated_view.color_plane[color_plane].stride; 703 else if (intel_fb_needs_pot_stride_remap(fb)) 704 return fb->remapped_view.color_plane[color_plane].stride; 705 else 706 return fb->normal_view.color_plane[color_plane].stride; 707 } 708 709 static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state) 710 { 711 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 712 const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb); 713 unsigned int rotation = plane_state->hw.rotation; 714 u32 stride, max_stride; 715 716 /* 717 * No remapping for invisible planes since we don't have 718 * an actual source viewport to remap. 719 */ 720 if (!plane_state->uapi.visible) 721 return false; 722 723 if (!intel_plane_can_remap(plane_state)) 724 return false; 725 726 /* 727 * FIXME: aux plane limits on gen9+ are 728 * unclear in Bspec, for now no checking. 729 */ 730 stride = intel_fb_pitch(fb, 0, rotation); 731 max_stride = plane->max_stride(plane, fb->base.format->format, 732 fb->base.modifier, rotation); 733 734 return stride > max_stride; 735 } 736 737 static int convert_plane_offset_to_xy(const struct intel_framebuffer *fb, int color_plane, 738 int plane_width, int *x, int *y) 739 { 740 struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base); 741 int ret; 742 743 ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane); 744 if (ret) { 745 drm_dbg_kms(fb->base.dev, 746 "bad fb plane %d offset: 0x%x\n", 747 color_plane, fb->base.offsets[color_plane]); 748 return ret; 749 } 750 751 ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y); 752 if (ret) 753 return ret; 754 755 /* 756 * The fence (if used) is aligned to the start of the object 757 * so having the framebuffer wrap around across the edge of the 758 * fenced region doesn't really work. We have no API to configure 759 * the fence start offset within the object (nor could we probably 760 * on gen2/3). So it's just easier if we just require that the 761 * fb layout agrees with the fence layout. We already check that the 762 * fb stride matches the fence stride elsewhere. 763 */ 764 if (color_plane == 0 && i915_gem_object_is_tiled(obj) && 765 (*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) { 766 drm_dbg_kms(fb->base.dev, 767 "bad fb plane %d offset: 0x%x\n", 768 color_plane, fb->base.offsets[color_plane]); 769 return -EINVAL; 770 } 771 772 return 0; 773 } 774 775 static u32 calc_plane_aligned_offset(const struct intel_framebuffer *fb, int color_plane, int *x, int *y) 776 { 777 struct drm_i915_private *i915 = to_i915(fb->base.dev); 778 unsigned int tile_size = intel_tile_size(i915); 779 u32 offset; 780 781 offset = intel_compute_aligned_offset(i915, x, y, &fb->base, color_plane, 782 fb->base.pitches[color_plane], 783 DRM_MODE_ROTATE_0, 784 tile_size); 785 786 return offset / tile_size; 787 } 788 789 struct fb_plane_view_dims { 790 unsigned int width, height; 791 unsigned int tile_width, tile_height; 792 }; 793 794 static void init_plane_view_dims(const struct intel_framebuffer *fb, int color_plane, 795 unsigned int width, unsigned int height, 796 struct fb_plane_view_dims *dims) 797 { 798 dims->width = width; 799 dims->height = height; 800 801 intel_tile_dims(&fb->base, color_plane, &dims->tile_width, &dims->tile_height); 802 } 803 804 static unsigned int 805 plane_view_src_stride_tiles(const struct intel_framebuffer *fb, int color_plane, 806 const struct fb_plane_view_dims *dims) 807 { 808 return DIV_ROUND_UP(fb->base.pitches[color_plane], 809 dims->tile_width * fb->base.format->cpp[color_plane]); 810 } 811 812 static unsigned int 813 plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane, 814 unsigned int pitch_tiles) 815 { 816 if (intel_fb_needs_pot_stride_remap(fb)) { 817 unsigned int min_stride = is_ccs_plane(&fb->base, color_plane) ? 2 : 8; 818 /* 819 * ADL_P, the only platform needing a POT stride has a minimum 820 * of 8 main surface and 2 CCS AUX stride tiles. 821 */ 822 return roundup_pow_of_two(max(pitch_tiles, min_stride)); 823 } else { 824 return pitch_tiles; 825 } 826 } 827 828 static unsigned int 829 plane_view_width_tiles(const struct intel_framebuffer *fb, int color_plane, 830 const struct fb_plane_view_dims *dims, 831 int x) 832 { 833 return DIV_ROUND_UP(x + dims->width, dims->tile_width); 834 } 835 836 static unsigned int 837 plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane, 838 const struct fb_plane_view_dims *dims, 839 int y) 840 { 841 return DIV_ROUND_UP(y + dims->height, dims->tile_height); 842 } 843 844 #define assign_chk_ovf(i915, var, val) ({ \ 845 drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \ 846 (var) = (val); \ 847 }) 848 849 static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane, 850 const struct fb_plane_view_dims *dims, 851 u32 obj_offset, u32 gtt_offset, int x, int y, 852 struct intel_fb_view *view) 853 { 854 struct drm_i915_private *i915 = to_i915(fb->base.dev); 855 struct intel_remapped_plane_info *remap_info = &view->gtt.remapped.plane[color_plane]; 856 struct i915_color_plane_view *color_plane_info = &view->color_plane[color_plane]; 857 unsigned int tile_width = dims->tile_width; 858 unsigned int tile_height = dims->tile_height; 859 unsigned int tile_size = intel_tile_size(i915); 860 struct drm_rect r; 861 u32 size = 0; 862 863 assign_chk_ovf(i915, remap_info->offset, obj_offset); 864 assign_chk_ovf(i915, remap_info->src_stride, plane_view_src_stride_tiles(fb, color_plane, dims)); 865 assign_chk_ovf(i915, remap_info->width, plane_view_width_tiles(fb, color_plane, dims, x)); 866 assign_chk_ovf(i915, remap_info->height, plane_view_height_tiles(fb, color_plane, dims, y)); 867 868 if (view->gtt.type == I915_GGTT_VIEW_ROTATED) { 869 check_array_bounds(i915, view->gtt.rotated.plane, color_plane); 870 871 assign_chk_ovf(i915, remap_info->dst_stride, 872 plane_view_dst_stride_tiles(fb, color_plane, remap_info->height)); 873 874 /* rotate the x/y offsets to match the GTT view */ 875 drm_rect_init(&r, x, y, dims->width, dims->height); 876 drm_rect_rotate(&r, 877 remap_info->width * tile_width, 878 remap_info->height * tile_height, 879 DRM_MODE_ROTATE_270); 880 881 color_plane_info->x = r.x1; 882 color_plane_info->y = r.y1; 883 884 color_plane_info->stride = remap_info->dst_stride * tile_height; 885 886 size += remap_info->dst_stride * remap_info->width; 887 888 /* rotate the tile dimensions to match the GTT view */ 889 swap(tile_width, tile_height); 890 } else { 891 drm_WARN_ON(&i915->drm, view->gtt.type != I915_GGTT_VIEW_REMAPPED); 892 893 check_array_bounds(i915, view->gtt.remapped.plane, color_plane); 894 895 if (view->gtt.remapped.plane_alignment) { 896 unsigned int aligned_offset = ALIGN(gtt_offset, 897 view->gtt.remapped.plane_alignment); 898 899 size += aligned_offset - gtt_offset; 900 gtt_offset = aligned_offset; 901 } 902 903 assign_chk_ovf(i915, remap_info->dst_stride, 904 plane_view_dst_stride_tiles(fb, color_plane, remap_info->width)); 905 906 color_plane_info->x = x; 907 color_plane_info->y = y; 908 909 color_plane_info->stride = remap_info->dst_stride * tile_width * 910 fb->base.format->cpp[color_plane]; 911 912 size += remap_info->dst_stride * remap_info->height; 913 } 914 915 /* 916 * We only keep the x/y offsets, so push all of the gtt offset into 917 * the x/y offsets. x,y will hold the first pixel of the framebuffer 918 * plane from the start of the remapped/rotated gtt mapping. 919 */ 920 intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y, 921 tile_width, tile_height, 922 tile_size, remap_info->dst_stride, 923 gtt_offset * tile_size, 0); 924 925 return size; 926 } 927 928 #undef assign_chk_ovf 929 930 /* Return number of tiles @color_plane needs. */ 931 static unsigned int 932 calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane, 933 const struct fb_plane_view_dims *dims, 934 int x, int y) 935 { 936 struct drm_i915_private *i915 = to_i915(fb->base.dev); 937 unsigned int tiles; 938 939 if (is_surface_linear(&fb->base, color_plane)) { 940 unsigned int size; 941 942 size = (y + dims->height) * fb->base.pitches[color_plane] + 943 x * fb->base.format->cpp[color_plane]; 944 tiles = DIV_ROUND_UP(size, intel_tile_size(i915)); 945 } else { 946 tiles = plane_view_src_stride_tiles(fb, color_plane, dims) * 947 plane_view_height_tiles(fb, color_plane, dims, y); 948 /* 949 * If the plane isn't horizontally tile aligned, 950 * we need one more tile. 951 */ 952 if (x != 0) 953 tiles++; 954 } 955 956 return tiles; 957 } 958 959 static void intel_fb_view_init(struct drm_i915_private *i915, struct intel_fb_view *view, 960 enum i915_ggtt_view_type view_type) 961 { 962 memset(view, 0, sizeof(*view)); 963 view->gtt.type = view_type; 964 965 if (view_type == I915_GGTT_VIEW_REMAPPED && IS_ALDERLAKE_P(i915)) 966 view->gtt.remapped.plane_alignment = SZ_2M / PAGE_SIZE; 967 } 968 969 bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb) 970 { 971 if (DISPLAY_VER(to_i915(fb->base.dev)) >= 13) 972 return false; 973 974 return fb->base.modifier == I915_FORMAT_MOD_Y_TILED || 975 fb->base.modifier == I915_FORMAT_MOD_Yf_TILED; 976 } 977 978 int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *fb) 979 { 980 struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base); 981 u32 gtt_offset_rotated = 0; 982 u32 gtt_offset_remapped = 0; 983 unsigned int max_size = 0; 984 int i, num_planes = fb->base.format->num_planes; 985 unsigned int tile_size = intel_tile_size(i915); 986 987 intel_fb_view_init(i915, &fb->normal_view, I915_GGTT_VIEW_NORMAL); 988 989 drm_WARN_ON(&i915->drm, 990 intel_fb_supports_90_270_rotation(fb) && 991 intel_fb_needs_pot_stride_remap(fb)); 992 993 if (intel_fb_supports_90_270_rotation(fb)) 994 intel_fb_view_init(i915, &fb->rotated_view, I915_GGTT_VIEW_ROTATED); 995 if (intel_fb_needs_pot_stride_remap(fb)) 996 intel_fb_view_init(i915, &fb->remapped_view, I915_GGTT_VIEW_REMAPPED); 997 998 for (i = 0; i < num_planes; i++) { 999 struct fb_plane_view_dims view_dims; 1000 unsigned int width, height; 1001 unsigned int cpp, size; 1002 u32 offset; 1003 int x, y; 1004 int ret; 1005 1006 /* 1007 * Plane 2 of Render Compression with Clear Color fb modifier 1008 * is consumed by the driver and not passed to DE. Skip the 1009 * arithmetic related to alignment and offset calculation. 1010 */ 1011 if (is_gen12_ccs_cc_plane(&fb->base, i)) { 1012 if (IS_ALIGNED(fb->base.offsets[i], PAGE_SIZE)) 1013 continue; 1014 else 1015 return -EINVAL; 1016 } 1017 1018 cpp = fb->base.format->cpp[i]; 1019 intel_fb_plane_dims(fb, i, &width, &height); 1020 1021 ret = convert_plane_offset_to_xy(fb, i, width, &x, &y); 1022 if (ret) 1023 return ret; 1024 1025 init_plane_view_dims(fb, i, width, height, &view_dims); 1026 1027 /* 1028 * First pixel of the framebuffer from 1029 * the start of the normal gtt mapping. 1030 */ 1031 fb->normal_view.color_plane[i].x = x; 1032 fb->normal_view.color_plane[i].y = y; 1033 fb->normal_view.color_plane[i].stride = fb->base.pitches[i]; 1034 1035 offset = calc_plane_aligned_offset(fb, i, &x, &y); 1036 1037 if (intel_fb_supports_90_270_rotation(fb)) 1038 gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims, 1039 offset, gtt_offset_rotated, x, y, 1040 &fb->rotated_view); 1041 1042 if (intel_fb_needs_pot_stride_remap(fb)) 1043 gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims, 1044 offset, gtt_offset_remapped, x, y, 1045 &fb->remapped_view); 1046 1047 size = calc_plane_normal_size(fb, i, &view_dims, x, y); 1048 /* how many tiles in total needed in the bo */ 1049 max_size = max(max_size, offset + size); 1050 } 1051 1052 if (mul_u32_u32(max_size, tile_size) > obj->base.size) { 1053 drm_dbg_kms(&i915->drm, 1054 "fb too big for bo (need %llu bytes, have %zu bytes)\n", 1055 mul_u32_u32(max_size, tile_size), obj->base.size); 1056 return -EINVAL; 1057 } 1058 1059 return 0; 1060 } 1061 1062 static void intel_plane_remap_gtt(struct intel_plane_state *plane_state) 1063 { 1064 struct drm_i915_private *i915 = 1065 to_i915(plane_state->uapi.plane->dev); 1066 struct drm_framebuffer *fb = plane_state->hw.fb; 1067 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 1068 unsigned int rotation = plane_state->hw.rotation; 1069 int i, num_planes = fb->format->num_planes; 1070 unsigned int src_x, src_y; 1071 unsigned int src_w, src_h; 1072 u32 gtt_offset = 0; 1073 1074 intel_fb_view_init(i915, &plane_state->view, 1075 drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED : 1076 I915_GGTT_VIEW_REMAPPED); 1077 1078 src_x = plane_state->uapi.src.x1 >> 16; 1079 src_y = plane_state->uapi.src.y1 >> 16; 1080 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; 1081 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; 1082 1083 drm_WARN_ON(&i915->drm, is_ccs_modifier(fb->modifier)); 1084 1085 /* Make src coordinates relative to the viewport */ 1086 drm_rect_translate(&plane_state->uapi.src, 1087 -(src_x << 16), -(src_y << 16)); 1088 1089 /* Rotate src coordinates to match rotated GTT view */ 1090 if (drm_rotation_90_or_270(rotation)) 1091 drm_rect_rotate(&plane_state->uapi.src, 1092 src_w << 16, src_h << 16, 1093 DRM_MODE_ROTATE_270); 1094 1095 for (i = 0; i < num_planes; i++) { 1096 unsigned int hsub = i ? fb->format->hsub : 1; 1097 unsigned int vsub = i ? fb->format->vsub : 1; 1098 struct fb_plane_view_dims view_dims; 1099 unsigned int width, height; 1100 unsigned int x, y; 1101 u32 offset; 1102 1103 x = src_x / hsub; 1104 y = src_y / vsub; 1105 width = src_w / hsub; 1106 height = src_h / vsub; 1107 1108 init_plane_view_dims(intel_fb, i, width, height, &view_dims); 1109 1110 /* 1111 * First pixel of the src viewport from the 1112 * start of the normal gtt mapping. 1113 */ 1114 x += intel_fb->normal_view.color_plane[i].x; 1115 y += intel_fb->normal_view.color_plane[i].y; 1116 1117 offset = calc_plane_aligned_offset(intel_fb, i, &x, &y); 1118 1119 gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims, 1120 offset, gtt_offset, x, y, 1121 &plane_state->view); 1122 } 1123 } 1124 1125 void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation, 1126 struct intel_fb_view *view) 1127 { 1128 if (drm_rotation_90_or_270(rotation)) 1129 *view = fb->rotated_view; 1130 else if (intel_fb_needs_pot_stride_remap(fb)) 1131 *view = fb->remapped_view; 1132 else 1133 *view = fb->normal_view; 1134 } 1135 1136 static 1137 u32 intel_fb_max_stride(struct drm_i915_private *dev_priv, 1138 u32 pixel_format, u64 modifier) 1139 { 1140 /* 1141 * Arbitrary limit for gen4+ chosen to match the 1142 * render engine max stride. 1143 * 1144 * The new CCS hash mode makes remapping impossible 1145 */ 1146 if (DISPLAY_VER(dev_priv) < 4 || is_ccs_modifier(modifier) || 1147 intel_modifier_uses_dpt(dev_priv, modifier)) 1148 return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier); 1149 else if (DISPLAY_VER(dev_priv) >= 7) 1150 return 256 * 1024; 1151 else 1152 return 128 * 1024; 1153 } 1154 1155 static u32 1156 intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane) 1157 { 1158 struct drm_i915_private *dev_priv = to_i915(fb->dev); 1159 u32 tile_width; 1160 1161 if (is_surface_linear(fb, color_plane)) { 1162 u32 max_stride = intel_plane_fb_max_stride(dev_priv, 1163 fb->format->format, 1164 fb->modifier); 1165 1166 /* 1167 * To make remapping with linear generally feasible 1168 * we need the stride to be page aligned. 1169 */ 1170 if (fb->pitches[color_plane] > max_stride && 1171 !is_ccs_modifier(fb->modifier)) 1172 return intel_tile_size(dev_priv); 1173 else 1174 return 64; 1175 } 1176 1177 tile_width = intel_tile_width_bytes(fb, color_plane); 1178 if (is_ccs_modifier(fb->modifier)) { 1179 /* 1180 * On ADL-P the stride must be either 8 tiles or a stride 1181 * that is aligned to 16 tiles, required by the 16 tiles = 1182 * 64 kbyte CCS AUX PTE granularity, allowing CCS FBs to be 1183 * remapped. 1184 */ 1185 if (IS_ALDERLAKE_P(dev_priv)) 1186 tile_width *= fb->pitches[0] <= tile_width * 8 ? 8 : 16; 1187 /* 1188 * On TGL the surface stride must be 4 tile aligned, mapped by 1189 * one 64 byte cacheline on the CCS AUX surface. 1190 */ 1191 else if (DISPLAY_VER(dev_priv) >= 12) 1192 tile_width *= 4; 1193 /* 1194 * Display WA #0531: skl,bxt,kbl,glk 1195 * 1196 * Render decompression and plane width > 3840 1197 * combined with horizontal panning requires the 1198 * plane stride to be a multiple of 4. We'll just 1199 * require the entire fb to accommodate that to avoid 1200 * potential runtime errors at plane configuration time. 1201 */ 1202 else if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) && 1203 color_plane == 0 && fb->width > 3840) 1204 tile_width *= 4; 1205 } 1206 return tile_width; 1207 } 1208 1209 static int intel_plane_check_stride(const struct intel_plane_state *plane_state) 1210 { 1211 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 1212 const struct drm_framebuffer *fb = plane_state->hw.fb; 1213 unsigned int rotation = plane_state->hw.rotation; 1214 u32 stride, max_stride; 1215 1216 /* 1217 * We ignore stride for all invisible planes that 1218 * can be remapped. Otherwise we could end up 1219 * with a false positive when the remapping didn't 1220 * kick in due the plane being invisible. 1221 */ 1222 if (intel_plane_can_remap(plane_state) && 1223 !plane_state->uapi.visible) 1224 return 0; 1225 1226 /* FIXME other color planes? */ 1227 stride = plane_state->view.color_plane[0].stride; 1228 max_stride = plane->max_stride(plane, fb->format->format, 1229 fb->modifier, rotation); 1230 1231 if (stride > max_stride) { 1232 DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n", 1233 fb->base.id, stride, 1234 plane->base.base.id, plane->base.name, max_stride); 1235 return -EINVAL; 1236 } 1237 1238 return 0; 1239 } 1240 1241 int intel_plane_compute_gtt(struct intel_plane_state *plane_state) 1242 { 1243 const struct intel_framebuffer *fb = 1244 to_intel_framebuffer(plane_state->hw.fb); 1245 unsigned int rotation = plane_state->hw.rotation; 1246 1247 if (!fb) 1248 return 0; 1249 1250 if (intel_plane_needs_remap(plane_state)) { 1251 intel_plane_remap_gtt(plane_state); 1252 1253 /* 1254 * Sometimes even remapping can't overcome 1255 * the stride limitations :( Can happen with 1256 * big plane sizes and suitably misaligned 1257 * offsets. 1258 */ 1259 return intel_plane_check_stride(plane_state); 1260 } 1261 1262 intel_fb_fill_view(fb, rotation, &plane_state->view); 1263 1264 /* Rotate src coordinates to match rotated GTT view */ 1265 if (drm_rotation_90_or_270(rotation)) 1266 drm_rect_rotate(&plane_state->uapi.src, 1267 fb->base.width << 16, fb->base.height << 16, 1268 DRM_MODE_ROTATE_270); 1269 1270 return intel_plane_check_stride(plane_state); 1271 } 1272 1273 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) 1274 { 1275 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 1276 1277 drm_framebuffer_cleanup(fb); 1278 1279 if (intel_fb_uses_dpt(fb)) 1280 intel_dpt_destroy(intel_fb->dpt_vm); 1281 1282 intel_frontbuffer_put(intel_fb->frontbuffer); 1283 1284 kfree(intel_fb); 1285 } 1286 1287 static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, 1288 struct drm_file *file, 1289 unsigned int *handle) 1290 { 1291 struct drm_i915_gem_object *obj = intel_fb_obj(fb); 1292 struct drm_i915_private *i915 = to_i915(obj->base.dev); 1293 1294 if (i915_gem_object_is_userptr(obj)) { 1295 drm_dbg(&i915->drm, 1296 "attempting to use a userptr for a framebuffer, denied\n"); 1297 return -EINVAL; 1298 } 1299 1300 return drm_gem_handle_create(file, &obj->base, handle); 1301 } 1302 1303 static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, 1304 struct drm_file *file, 1305 unsigned int flags, unsigned int color, 1306 struct drm_clip_rect *clips, 1307 unsigned int num_clips) 1308 { 1309 struct drm_i915_gem_object *obj = intel_fb_obj(fb); 1310 1311 i915_gem_object_flush_if_display(obj); 1312 intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB); 1313 1314 return 0; 1315 } 1316 1317 static const struct drm_framebuffer_funcs intel_fb_funcs = { 1318 .destroy = intel_user_framebuffer_destroy, 1319 .create_handle = intel_user_framebuffer_create_handle, 1320 .dirty = intel_user_framebuffer_dirty, 1321 }; 1322 1323 int intel_framebuffer_init(struct intel_framebuffer *intel_fb, 1324 struct drm_i915_gem_object *obj, 1325 struct drm_mode_fb_cmd2 *mode_cmd) 1326 { 1327 struct drm_i915_private *dev_priv = to_i915(obj->base.dev); 1328 struct drm_framebuffer *fb = &intel_fb->base; 1329 u32 max_stride; 1330 unsigned int tiling, stride; 1331 int ret = -EINVAL; 1332 int i; 1333 1334 intel_fb->frontbuffer = intel_frontbuffer_get(obj); 1335 if (!intel_fb->frontbuffer) 1336 return -ENOMEM; 1337 1338 i915_gem_object_lock(obj, NULL); 1339 tiling = i915_gem_object_get_tiling(obj); 1340 stride = i915_gem_object_get_stride(obj); 1341 i915_gem_object_unlock(obj); 1342 1343 if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) { 1344 /* 1345 * If there's a fence, enforce that 1346 * the fb modifier and tiling mode match. 1347 */ 1348 if (tiling != I915_TILING_NONE && 1349 tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { 1350 drm_dbg_kms(&dev_priv->drm, 1351 "tiling_mode doesn't match fb modifier\n"); 1352 goto err; 1353 } 1354 } else { 1355 if (tiling == I915_TILING_X) { 1356 mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED; 1357 } else if (tiling == I915_TILING_Y) { 1358 drm_dbg_kms(&dev_priv->drm, 1359 "No Y tiling for legacy addfb\n"); 1360 goto err; 1361 } 1362 } 1363 1364 if (!drm_any_plane_has_format(&dev_priv->drm, 1365 mode_cmd->pixel_format, 1366 mode_cmd->modifier[0])) { 1367 drm_dbg_kms(&dev_priv->drm, 1368 "unsupported pixel format %p4cc / modifier 0x%llx\n", 1369 &mode_cmd->pixel_format, mode_cmd->modifier[0]); 1370 goto err; 1371 } 1372 1373 /* 1374 * gen2/3 display engine uses the fence if present, 1375 * so the tiling mode must match the fb modifier exactly. 1376 */ 1377 if (DISPLAY_VER(dev_priv) < 4 && 1378 tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { 1379 drm_dbg_kms(&dev_priv->drm, 1380 "tiling_mode must match fb modifier exactly on gen2/3\n"); 1381 goto err; 1382 } 1383 1384 max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format, 1385 mode_cmd->modifier[0]); 1386 if (mode_cmd->pitches[0] > max_stride) { 1387 drm_dbg_kms(&dev_priv->drm, 1388 "%s pitch (%u) must be at most %d\n", 1389 mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ? 1390 "tiled" : "linear", 1391 mode_cmd->pitches[0], max_stride); 1392 goto err; 1393 } 1394 1395 /* 1396 * If there's a fence, enforce that 1397 * the fb pitch and fence stride match. 1398 */ 1399 if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) { 1400 drm_dbg_kms(&dev_priv->drm, 1401 "pitch (%d) must match tiling stride (%d)\n", 1402 mode_cmd->pitches[0], stride); 1403 goto err; 1404 } 1405 1406 /* FIXME need to adjust LINOFF/TILEOFF accordingly. */ 1407 if (mode_cmd->offsets[0] != 0) { 1408 drm_dbg_kms(&dev_priv->drm, 1409 "plane 0 offset (0x%08x) must be 0\n", 1410 mode_cmd->offsets[0]); 1411 goto err; 1412 } 1413 1414 drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd); 1415 1416 for (i = 0; i < fb->format->num_planes; i++) { 1417 u32 stride_alignment; 1418 1419 if (mode_cmd->handles[i] != mode_cmd->handles[0]) { 1420 drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n", 1421 i); 1422 goto err; 1423 } 1424 1425 stride_alignment = intel_fb_stride_alignment(fb, i); 1426 if (fb->pitches[i] & (stride_alignment - 1)) { 1427 drm_dbg_kms(&dev_priv->drm, 1428 "plane %d pitch (%d) must be at least %u byte aligned\n", 1429 i, fb->pitches[i], stride_alignment); 1430 goto err; 1431 } 1432 1433 if (is_gen12_ccs_plane(fb, i) && !is_gen12_ccs_cc_plane(fb, i)) { 1434 int ccs_aux_stride = gen12_ccs_aux_stride(intel_fb, i); 1435 1436 if (fb->pitches[i] != ccs_aux_stride) { 1437 drm_dbg_kms(&dev_priv->drm, 1438 "ccs aux plane %d pitch (%d) must be %d\n", 1439 i, 1440 fb->pitches[i], ccs_aux_stride); 1441 goto err; 1442 } 1443 } 1444 1445 fb->obj[i] = &obj->base; 1446 } 1447 1448 ret = intel_fill_fb_info(dev_priv, intel_fb); 1449 if (ret) 1450 goto err; 1451 1452 if (intel_fb_uses_dpt(fb)) { 1453 struct i915_address_space *vm; 1454 1455 vm = intel_dpt_create(intel_fb); 1456 if (IS_ERR(vm)) { 1457 ret = PTR_ERR(vm); 1458 goto err; 1459 } 1460 1461 intel_fb->dpt_vm = vm; 1462 } 1463 1464 ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs); 1465 if (ret) { 1466 drm_err(&dev_priv->drm, "framebuffer init failed %d\n", ret); 1467 goto err; 1468 } 1469 1470 return 0; 1471 1472 err: 1473 intel_frontbuffer_put(intel_fb->frontbuffer); 1474 return ret; 1475 } 1476 1477 struct drm_framebuffer * 1478 intel_user_framebuffer_create(struct drm_device *dev, 1479 struct drm_file *filp, 1480 const struct drm_mode_fb_cmd2 *user_mode_cmd) 1481 { 1482 struct drm_framebuffer *fb; 1483 struct drm_i915_gem_object *obj; 1484 struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd; 1485 struct drm_i915_private *i915; 1486 1487 obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]); 1488 if (!obj) 1489 return ERR_PTR(-ENOENT); 1490 1491 /* object is backed with LMEM for discrete */ 1492 i915 = to_i915(obj->base.dev); 1493 if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM)) { 1494 /* object is "remote", not in local memory */ 1495 i915_gem_object_put(obj); 1496 return ERR_PTR(-EREMOTE); 1497 } 1498 1499 fb = intel_framebuffer_create(obj, &mode_cmd); 1500 i915_gem_object_put(obj); 1501 1502 return fb; 1503 } 1504 1505 struct drm_framebuffer * 1506 intel_framebuffer_create(struct drm_i915_gem_object *obj, 1507 struct drm_mode_fb_cmd2 *mode_cmd) 1508 { 1509 struct intel_framebuffer *intel_fb; 1510 int ret; 1511 1512 intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); 1513 if (!intel_fb) 1514 return ERR_PTR(-ENOMEM); 1515 1516 ret = intel_framebuffer_init(intel_fb, obj, mode_cmd); 1517 if (ret) 1518 goto err; 1519 1520 return &intel_fb->base; 1521 1522 err: 1523 kfree(intel_fb); 1524 return ERR_PTR(ret); 1525 } 1526