1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include <drm/drm_framebuffer.h> 7 8 #include "intel_display.h" 9 #include "intel_display_types.h" 10 #include "intel_fb.h" 11 12 #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a)) 13 14 bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) 15 { 16 if (!is_ccs_modifier(fb->modifier)) 17 return false; 18 19 return plane >= fb->format->num_planes / 2; 20 } 21 22 bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane) 23 { 24 return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane); 25 } 26 27 bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane) 28 { 29 return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC && 30 plane == 2; 31 } 32 33 bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane) 34 { 35 return intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && 36 color_plane == 1; 37 } 38 39 bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane) 40 { 41 return fb->modifier == DRM_FORMAT_MOD_LINEAR || 42 is_gen12_ccs_plane(fb, color_plane); 43 } 44 45 int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane) 46 { 47 drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || 48 (main_plane && main_plane >= fb->format->num_planes / 2)); 49 50 return fb->format->num_planes / 2 + main_plane; 51 } 52 53 int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) 54 { 55 drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || 56 ccs_plane < fb->format->num_planes / 2); 57 58 if (is_gen12_ccs_cc_plane(fb, ccs_plane)) 59 return 0; 60 61 return ccs_plane - fb->format->num_planes / 2; 62 } 63 64 int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) 65 { 66 struct drm_i915_private *i915 = to_i915(fb->dev); 67 68 if (is_ccs_modifier(fb->modifier)) 69 return main_to_ccs_plane(fb, main_plane); 70 else if (DISPLAY_VER(i915) < 11 && 71 intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) 72 return 1; 73 else 74 return 0; 75 } 76 77 unsigned int intel_tile_size(const struct drm_i915_private *i915) 78 { 79 return DISPLAY_VER(i915) == 2 ? 2048 : 4096; 80 } 81 82 unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane) 83 { 84 if (is_gen12_ccs_plane(fb, color_plane)) 85 return 1; 86 87 return intel_tile_size(to_i915(fb->dev)) / 88 intel_tile_width_bytes(fb, color_plane); 89 } 90 91 /* Return the tile dimensions in pixel units */ 92 static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane, 93 unsigned int *tile_width, 94 unsigned int *tile_height) 95 { 96 unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane); 97 unsigned int cpp = fb->format->cpp[color_plane]; 98 99 *tile_width = tile_width_bytes / cpp; 100 *tile_height = intel_tile_height(fb, color_plane); 101 } 102 103 unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane) 104 { 105 unsigned int tile_width, tile_height; 106 107 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 108 109 return fb->pitches[color_plane] * tile_height; 110 } 111 112 unsigned int intel_cursor_alignment(const struct drm_i915_private *i915) 113 { 114 if (IS_I830(i915)) 115 return 16 * 1024; 116 else if (IS_I85X(i915)) 117 return 256; 118 else if (IS_I845G(i915) || IS_I865G(i915)) 119 return 32; 120 else 121 return 4 * 1024; 122 } 123 124 void intel_fb_plane_get_subsampling(int *hsub, int *vsub, 125 const struct drm_framebuffer *fb, 126 int color_plane) 127 { 128 int main_plane; 129 130 if (color_plane == 0) { 131 *hsub = 1; 132 *vsub = 1; 133 134 return; 135 } 136 137 /* 138 * TODO: Deduct the subsampling from the char block for all CCS 139 * formats and planes. 140 */ 141 if (!is_gen12_ccs_plane(fb, color_plane)) { 142 *hsub = fb->format->hsub; 143 *vsub = fb->format->vsub; 144 145 return; 146 } 147 148 main_plane = skl_ccs_to_main_plane(fb, color_plane); 149 *hsub = drm_format_info_block_width(fb->format, color_plane) / 150 drm_format_info_block_width(fb->format, main_plane); 151 152 /* 153 * The min stride check in the core framebuffer_check() function 154 * assumes that format->hsub applies to every plane except for the 155 * first plane. That's incorrect for the CCS AUX plane of the first 156 * plane, but for the above check to pass we must define the block 157 * width with that subsampling applied to it. Adjust the width here 158 * accordingly, so we can calculate the actual subsampling factor. 159 */ 160 if (main_plane == 0) 161 *hsub *= fb->format->hsub; 162 163 *vsub = 32; 164 } 165 166 static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h) 167 { 168 int main_plane = is_ccs_plane(&fb->base, color_plane) ? 169 skl_ccs_to_main_plane(&fb->base, color_plane) : 0; 170 int main_hsub, main_vsub; 171 int hsub, vsub; 172 173 intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane); 174 intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane); 175 176 *w = DIV_ROUND_UP(fb->base.width, main_hsub * hsub); 177 *h = DIV_ROUND_UP(fb->base.height, main_vsub * vsub); 178 } 179 180 static u32 intel_adjust_tile_offset(int *x, int *y, 181 unsigned int tile_width, 182 unsigned int tile_height, 183 unsigned int tile_size, 184 unsigned int pitch_tiles, 185 u32 old_offset, 186 u32 new_offset) 187 { 188 unsigned int pitch_pixels = pitch_tiles * tile_width; 189 unsigned int tiles; 190 191 WARN_ON(old_offset & (tile_size - 1)); 192 WARN_ON(new_offset & (tile_size - 1)); 193 WARN_ON(new_offset > old_offset); 194 195 tiles = (old_offset - new_offset) / tile_size; 196 197 *y += tiles / pitch_tiles * tile_height; 198 *x += tiles % pitch_tiles * tile_width; 199 200 /* minimize x in case it got needlessly big */ 201 *y += *x / pitch_pixels * tile_height; 202 *x %= pitch_pixels; 203 204 return new_offset; 205 } 206 207 static u32 intel_adjust_aligned_offset(int *x, int *y, 208 const struct drm_framebuffer *fb, 209 int color_plane, 210 unsigned int rotation, 211 unsigned int pitch, 212 u32 old_offset, u32 new_offset) 213 { 214 struct drm_i915_private *i915 = to_i915(fb->dev); 215 unsigned int cpp = fb->format->cpp[color_plane]; 216 217 drm_WARN_ON(&i915->drm, new_offset > old_offset); 218 219 if (!is_surface_linear(fb, color_plane)) { 220 unsigned int tile_size, tile_width, tile_height; 221 unsigned int pitch_tiles; 222 223 tile_size = intel_tile_size(i915); 224 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 225 226 if (drm_rotation_90_or_270(rotation)) { 227 pitch_tiles = pitch / tile_height; 228 swap(tile_width, tile_height); 229 } else { 230 pitch_tiles = pitch / (tile_width * cpp); 231 } 232 233 intel_adjust_tile_offset(x, y, tile_width, tile_height, 234 tile_size, pitch_tiles, 235 old_offset, new_offset); 236 } else { 237 old_offset += *y * pitch + *x * cpp; 238 239 *y = (old_offset - new_offset) / pitch; 240 *x = ((old_offset - new_offset) - *y * pitch) / cpp; 241 } 242 243 return new_offset; 244 } 245 246 /* 247 * Adjust the tile offset by moving the difference into 248 * the x/y offsets. 249 */ 250 u32 intel_plane_adjust_aligned_offset(int *x, int *y, 251 const struct intel_plane_state *state, 252 int color_plane, 253 u32 old_offset, u32 new_offset) 254 { 255 return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane, 256 state->hw.rotation, 257 state->view.color_plane[color_plane].stride, 258 old_offset, new_offset); 259 } 260 261 /* 262 * Computes the aligned offset to the base tile and adjusts 263 * x, y. bytes per pixel is assumed to be a power-of-two. 264 * 265 * In the 90/270 rotated case, x and y are assumed 266 * to be already rotated to match the rotated GTT view, and 267 * pitch is the tile_height aligned framebuffer height. 268 * 269 * This function is used when computing the derived information 270 * under intel_framebuffer, so using any of that information 271 * here is not allowed. Anything under drm_framebuffer can be 272 * used. This is why the user has to pass in the pitch since it 273 * is specified in the rotated orientation. 274 */ 275 static u32 intel_compute_aligned_offset(struct drm_i915_private *i915, 276 int *x, int *y, 277 const struct drm_framebuffer *fb, 278 int color_plane, 279 unsigned int pitch, 280 unsigned int rotation, 281 u32 alignment) 282 { 283 unsigned int cpp = fb->format->cpp[color_plane]; 284 u32 offset, offset_aligned; 285 286 if (!is_surface_linear(fb, color_plane)) { 287 unsigned int tile_size, tile_width, tile_height; 288 unsigned int tile_rows, tiles, pitch_tiles; 289 290 tile_size = intel_tile_size(i915); 291 intel_tile_dims(fb, color_plane, &tile_width, &tile_height); 292 293 if (drm_rotation_90_or_270(rotation)) { 294 pitch_tiles = pitch / tile_height; 295 swap(tile_width, tile_height); 296 } else { 297 pitch_tiles = pitch / (tile_width * cpp); 298 } 299 300 tile_rows = *y / tile_height; 301 *y %= tile_height; 302 303 tiles = *x / tile_width; 304 *x %= tile_width; 305 306 offset = (tile_rows * pitch_tiles + tiles) * tile_size; 307 308 offset_aligned = offset; 309 if (alignment) 310 offset_aligned = rounddown(offset_aligned, alignment); 311 312 intel_adjust_tile_offset(x, y, tile_width, tile_height, 313 tile_size, pitch_tiles, 314 offset, offset_aligned); 315 } else { 316 offset = *y * pitch + *x * cpp; 317 offset_aligned = offset; 318 if (alignment) { 319 offset_aligned = rounddown(offset_aligned, alignment); 320 *y = (offset % alignment) / pitch; 321 *x = ((offset % alignment) - *y * pitch) / cpp; 322 } else { 323 *y = *x = 0; 324 } 325 } 326 327 return offset_aligned; 328 } 329 330 u32 intel_plane_compute_aligned_offset(int *x, int *y, 331 const struct intel_plane_state *state, 332 int color_plane) 333 { 334 struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane); 335 struct drm_i915_private *i915 = to_i915(intel_plane->base.dev); 336 const struct drm_framebuffer *fb = state->hw.fb; 337 unsigned int rotation = state->hw.rotation; 338 int pitch = state->view.color_plane[color_plane].stride; 339 u32 alignment; 340 341 if (intel_plane->id == PLANE_CURSOR) 342 alignment = intel_cursor_alignment(i915); 343 else 344 alignment = intel_surf_alignment(fb, color_plane); 345 346 return intel_compute_aligned_offset(i915, x, y, fb, color_plane, 347 pitch, rotation, alignment); 348 } 349 350 /* Convert the fb->offset[] into x/y offsets */ 351 static int intel_fb_offset_to_xy(int *x, int *y, 352 const struct drm_framebuffer *fb, 353 int color_plane) 354 { 355 struct drm_i915_private *i915 = to_i915(fb->dev); 356 unsigned int height; 357 u32 alignment; 358 359 /* 360 * All DPT color planes must be 512*4k aligned (the amount mapped by a 361 * single DPT page). For ADL_P CCS FBs this only works by requiring 362 * the allocated offsets to be 2MB aligned. Once supoort to remap 363 * such FBs is added we can remove this requirement, as then all the 364 * planes can be remapped to an aligned offset. 365 */ 366 if (IS_ALDERLAKE_P(i915) && is_ccs_modifier(fb->modifier)) 367 alignment = 512 * 4096; 368 else if (DISPLAY_VER(i915) >= 12 && 369 is_semiplanar_uv_plane(fb, color_plane)) 370 alignment = intel_tile_row_size(fb, color_plane); 371 else if (fb->modifier != DRM_FORMAT_MOD_LINEAR) 372 alignment = intel_tile_size(i915); 373 else 374 alignment = 0; 375 376 if (alignment != 0 && fb->offsets[color_plane] % alignment) { 377 drm_dbg_kms(&i915->drm, 378 "Misaligned offset 0x%08x for color plane %d\n", 379 fb->offsets[color_plane], color_plane); 380 return -EINVAL; 381 } 382 383 height = drm_framebuffer_plane_height(fb->height, fb, color_plane); 384 height = roundup2(height, intel_tile_height(fb, color_plane)); 385 386 /* Catch potential overflows early */ 387 if (add_overflows_t(u32, mul_u32_u32(height, fb->pitches[color_plane]), 388 fb->offsets[color_plane])) { 389 drm_dbg_kms(&i915->drm, 390 "Bad offset 0x%08x or pitch %d for color plane %d\n", 391 fb->offsets[color_plane], fb->pitches[color_plane], 392 color_plane); 393 return -ERANGE; 394 } 395 396 *x = 0; 397 *y = 0; 398 399 intel_adjust_aligned_offset(x, y, 400 fb, color_plane, DRM_MODE_ROTATE_0, 401 fb->pitches[color_plane], 402 fb->offsets[color_plane], 0); 403 404 return 0; 405 } 406 407 static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane, int x, int y) 408 { 409 struct drm_i915_private *i915 = to_i915(fb->dev); 410 const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 411 int main_plane; 412 int hsub, vsub; 413 int tile_width, tile_height; 414 int ccs_x, ccs_y; 415 int main_x, main_y; 416 417 if (!is_ccs_plane(fb, ccs_plane) || is_gen12_ccs_cc_plane(fb, ccs_plane)) 418 return 0; 419 420 intel_tile_dims(fb, ccs_plane, &tile_width, &tile_height); 421 intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); 422 423 tile_width *= hsub; 424 tile_height *= vsub; 425 426 ccs_x = (x * hsub) % tile_width; 427 ccs_y = (y * vsub) % tile_height; 428 429 main_plane = skl_ccs_to_main_plane(fb, ccs_plane); 430 main_x = intel_fb->normal_view.color_plane[main_plane].x % tile_width; 431 main_y = intel_fb->normal_view.color_plane[main_plane].y % tile_height; 432 433 /* 434 * CCS doesn't have its own x/y offset register, so the intra CCS tile 435 * x/y offsets must match between CCS and the main surface. 436 */ 437 if (main_x != ccs_x || main_y != ccs_y) { 438 drm_dbg_kms(&i915->drm, 439 "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n", 440 main_x, main_y, 441 ccs_x, ccs_y, 442 intel_fb->normal_view.color_plane[main_plane].x, 443 intel_fb->normal_view.color_plane[main_plane].y, 444 x, y); 445 return -EINVAL; 446 } 447 448 return 0; 449 } 450 451 static bool intel_plane_can_remap(const struct intel_plane_state *plane_state) 452 { 453 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 454 struct drm_i915_private *i915 = to_i915(plane->base.dev); 455 const struct drm_framebuffer *fb = plane_state->hw.fb; 456 int i; 457 458 /* We don't want to deal with remapping with cursors */ 459 if (plane->id == PLANE_CURSOR) 460 return false; 461 462 /* 463 * The display engine limits already match/exceed the 464 * render engine limits, so not much point in remapping. 465 * Would also need to deal with the fence POT alignment 466 * and gen2 2KiB GTT tile size. 467 */ 468 if (DISPLAY_VER(i915) < 4) 469 return false; 470 471 /* 472 * The new CCS hash mode isn't compatible with remapping as 473 * the virtual address of the pages affects the compressed data. 474 */ 475 if (is_ccs_modifier(fb->modifier)) 476 return false; 477 478 /* Linear needs a page aligned stride for remapping */ 479 if (fb->modifier == DRM_FORMAT_MOD_LINEAR) { 480 unsigned int alignment = intel_tile_size(i915) - 1; 481 482 for (i = 0; i < fb->format->num_planes; i++) { 483 if (fb->pitches[i] & alignment) 484 return false; 485 } 486 } 487 488 return true; 489 } 490 491 bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb) 492 { 493 struct drm_i915_private *i915 = to_i915(fb->base.dev); 494 495 return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR && 496 !is_ccs_modifier(fb->base.modifier); 497 } 498 499 static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation) 500 { 501 if (drm_rotation_90_or_270(rotation)) 502 return fb->rotated_view.color_plane[color_plane].stride; 503 else if (intel_fb_needs_pot_stride_remap(fb)) 504 return fb->remapped_view.color_plane[color_plane].stride; 505 else 506 return fb->normal_view.color_plane[color_plane].stride; 507 } 508 509 static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state) 510 { 511 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 512 const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb); 513 unsigned int rotation = plane_state->hw.rotation; 514 u32 stride, max_stride; 515 516 /* 517 * No remapping for invisible planes since we don't have 518 * an actual source viewport to remap. 519 */ 520 if (!plane_state->uapi.visible) 521 return false; 522 523 if (!intel_plane_can_remap(plane_state)) 524 return false; 525 526 /* 527 * FIXME: aux plane limits on gen9+ are 528 * unclear in Bspec, for now no checking. 529 */ 530 stride = intel_fb_pitch(fb, 0, rotation); 531 max_stride = plane->max_stride(plane, fb->base.format->format, 532 fb->base.modifier, rotation); 533 534 return stride > max_stride; 535 } 536 537 static int convert_plane_offset_to_xy(const struct intel_framebuffer *fb, int color_plane, 538 int plane_width, int *x, int *y) 539 { 540 struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base); 541 int ret; 542 543 ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane); 544 if (ret) { 545 drm_dbg_kms(fb->base.dev, 546 "bad fb plane %d offset: 0x%x\n", 547 color_plane, fb->base.offsets[color_plane]); 548 return ret; 549 } 550 551 ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y); 552 if (ret) 553 return ret; 554 555 /* 556 * The fence (if used) is aligned to the start of the object 557 * so having the framebuffer wrap around across the edge of the 558 * fenced region doesn't really work. We have no API to configure 559 * the fence start offset within the object (nor could we probably 560 * on gen2/3). So it's just easier if we just require that the 561 * fb layout agrees with the fence layout. We already check that the 562 * fb stride matches the fence stride elsewhere. 563 */ 564 if (color_plane == 0 && i915_gem_object_is_tiled(obj) && 565 (*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) { 566 drm_dbg_kms(fb->base.dev, 567 "bad fb plane %d offset: 0x%x\n", 568 color_plane, fb->base.offsets[color_plane]); 569 return -EINVAL; 570 } 571 572 return 0; 573 } 574 575 static u32 calc_plane_aligned_offset(const struct intel_framebuffer *fb, int color_plane, int *x, int *y) 576 { 577 struct drm_i915_private *i915 = to_i915(fb->base.dev); 578 unsigned int tile_size = intel_tile_size(i915); 579 u32 offset; 580 581 offset = intel_compute_aligned_offset(i915, x, y, &fb->base, color_plane, 582 fb->base.pitches[color_plane], 583 DRM_MODE_ROTATE_0, 584 tile_size); 585 586 return offset / tile_size; 587 } 588 589 struct fb_plane_view_dims { 590 unsigned int width, height; 591 unsigned int tile_width, tile_height; 592 }; 593 594 static void init_plane_view_dims(const struct intel_framebuffer *fb, int color_plane, 595 unsigned int width, unsigned int height, 596 struct fb_plane_view_dims *dims) 597 { 598 dims->width = width; 599 dims->height = height; 600 601 intel_tile_dims(&fb->base, color_plane, &dims->tile_width, &dims->tile_height); 602 } 603 604 static unsigned int 605 plane_view_src_stride_tiles(const struct intel_framebuffer *fb, int color_plane, 606 const struct fb_plane_view_dims *dims) 607 { 608 return DIV_ROUND_UP(fb->base.pitches[color_plane], 609 dims->tile_width * fb->base.format->cpp[color_plane]); 610 } 611 612 static unsigned int 613 plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane, 614 unsigned int pitch_tiles) 615 { 616 if (intel_fb_needs_pot_stride_remap(fb)) 617 /* 618 * ADL_P, the only platform needing a POT stride has a minimum 619 * of 8 stride tiles. 620 */ 621 return roundup_pow_of_two(max(pitch_tiles, 8u)); 622 else 623 return pitch_tiles; 624 } 625 626 static unsigned int 627 plane_view_width_tiles(const struct intel_framebuffer *fb, int color_plane, 628 const struct fb_plane_view_dims *dims, 629 int x) 630 { 631 return DIV_ROUND_UP(x + dims->width, dims->tile_width); 632 } 633 634 static unsigned int 635 plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane, 636 const struct fb_plane_view_dims *dims, 637 int y) 638 { 639 return DIV_ROUND_UP(y + dims->height, dims->tile_height); 640 } 641 642 #define assign_chk_ovf(i915, var, val) ({ \ 643 drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \ 644 (var) = (val); \ 645 }) 646 647 static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane, 648 const struct fb_plane_view_dims *dims, 649 u32 obj_offset, u32 gtt_offset, int x, int y, 650 struct intel_fb_view *view) 651 { 652 struct drm_i915_private *i915 = to_i915(fb->base.dev); 653 struct intel_remapped_plane_info *remap_info = &view->gtt.remapped.plane[color_plane]; 654 struct i915_color_plane_view *color_plane_info = &view->color_plane[color_plane]; 655 unsigned int tile_width = dims->tile_width; 656 unsigned int tile_height = dims->tile_height; 657 unsigned int tile_size = intel_tile_size(i915); 658 struct drm_rect r; 659 u32 size; 660 661 assign_chk_ovf(i915, remap_info->offset, obj_offset); 662 assign_chk_ovf(i915, remap_info->src_stride, plane_view_src_stride_tiles(fb, color_plane, dims)); 663 assign_chk_ovf(i915, remap_info->width, plane_view_width_tiles(fb, color_plane, dims, x)); 664 assign_chk_ovf(i915, remap_info->height, plane_view_height_tiles(fb, color_plane, dims, y)); 665 666 if (view->gtt.type == I915_GGTT_VIEW_ROTATED) { 667 check_array_bounds(i915, view->gtt.rotated.plane, color_plane); 668 669 assign_chk_ovf(i915, remap_info->dst_stride, 670 plane_view_dst_stride_tiles(fb, color_plane, remap_info->height)); 671 672 /* rotate the x/y offsets to match the GTT view */ 673 drm_rect_init(&r, x, y, dims->width, dims->height); 674 drm_rect_rotate(&r, 675 remap_info->width * tile_width, 676 remap_info->height * tile_height, 677 DRM_MODE_ROTATE_270); 678 679 color_plane_info->x = r.x1; 680 color_plane_info->y = r.y1; 681 682 color_plane_info->stride = remap_info->dst_stride * tile_height; 683 684 size = remap_info->dst_stride * remap_info->width; 685 686 /* rotate the tile dimensions to match the GTT view */ 687 swap(tile_width, tile_height); 688 } else { 689 drm_WARN_ON(&i915->drm, view->gtt.type != I915_GGTT_VIEW_REMAPPED); 690 691 check_array_bounds(i915, view->gtt.remapped.plane, color_plane); 692 693 assign_chk_ovf(i915, remap_info->dst_stride, 694 plane_view_dst_stride_tiles(fb, color_plane, remap_info->width)); 695 696 color_plane_info->x = x; 697 color_plane_info->y = y; 698 699 color_plane_info->stride = remap_info->dst_stride * tile_width * 700 fb->base.format->cpp[color_plane]; 701 702 size = remap_info->dst_stride * remap_info->height; 703 } 704 705 /* 706 * We only keep the x/y offsets, so push all of the gtt offset into 707 * the x/y offsets. x,y will hold the first pixel of the framebuffer 708 * plane from the start of the remapped/rotated gtt mapping. 709 */ 710 intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y, 711 tile_width, tile_height, 712 tile_size, remap_info->dst_stride, 713 gtt_offset * tile_size, 0); 714 715 return size; 716 } 717 718 #undef assign_chk_ovf 719 720 /* Return number of tiles @color_plane needs. */ 721 static unsigned int 722 calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane, 723 const struct fb_plane_view_dims *dims, 724 int x, int y) 725 { 726 struct drm_i915_private *i915 = to_i915(fb->base.dev); 727 unsigned int tiles; 728 729 if (is_surface_linear(&fb->base, color_plane)) { 730 unsigned int size; 731 732 size = (y + dims->height) * fb->base.pitches[color_plane] + 733 x * fb->base.format->cpp[color_plane]; 734 tiles = DIV_ROUND_UP(size, intel_tile_size(i915)); 735 } else { 736 tiles = plane_view_src_stride_tiles(fb, color_plane, dims) * 737 plane_view_height_tiles(fb, color_plane, dims, y); 738 /* 739 * If the plane isn't horizontally tile aligned, 740 * we need one more tile. 741 */ 742 if (x != 0) 743 tiles++; 744 } 745 746 return tiles; 747 } 748 749 static void intel_fb_view_init(struct intel_fb_view *view, enum i915_ggtt_view_type view_type) 750 { 751 memset(view, 0, sizeof(*view)); 752 view->gtt.type = view_type; 753 } 754 755 bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb) 756 { 757 if (DISPLAY_VER(to_i915(fb->base.dev)) >= 13) 758 return false; 759 760 return fb->base.modifier == I915_FORMAT_MOD_Y_TILED || 761 fb->base.modifier == I915_FORMAT_MOD_Yf_TILED; 762 } 763 764 int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *fb) 765 { 766 struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base); 767 u32 gtt_offset_rotated = 0; 768 u32 gtt_offset_remapped = 0; 769 unsigned int max_size = 0; 770 int i, num_planes = fb->base.format->num_planes; 771 unsigned int tile_size = intel_tile_size(i915); 772 773 intel_fb_view_init(&fb->normal_view, I915_GGTT_VIEW_NORMAL); 774 775 drm_WARN_ON(&i915->drm, 776 intel_fb_supports_90_270_rotation(fb) && 777 intel_fb_needs_pot_stride_remap(fb)); 778 779 if (intel_fb_supports_90_270_rotation(fb)) 780 intel_fb_view_init(&fb->rotated_view, I915_GGTT_VIEW_ROTATED); 781 if (intel_fb_needs_pot_stride_remap(fb)) 782 intel_fb_view_init(&fb->remapped_view, I915_GGTT_VIEW_REMAPPED); 783 784 for (i = 0; i < num_planes; i++) { 785 struct fb_plane_view_dims view_dims; 786 unsigned int width, height; 787 unsigned int cpp, size; 788 u32 offset; 789 int x, y; 790 int ret; 791 792 /* 793 * Plane 2 of Render Compression with Clear Color fb modifier 794 * is consumed by the driver and not passed to DE. Skip the 795 * arithmetic related to alignment and offset calculation. 796 */ 797 if (is_gen12_ccs_cc_plane(&fb->base, i)) { 798 if (IS_ALIGNED(fb->base.offsets[i], PAGE_SIZE)) 799 continue; 800 else 801 return -EINVAL; 802 } 803 804 cpp = fb->base.format->cpp[i]; 805 intel_fb_plane_dims(fb, i, &width, &height); 806 807 ret = convert_plane_offset_to_xy(fb, i, width, &x, &y); 808 if (ret) 809 return ret; 810 811 init_plane_view_dims(fb, i, width, height, &view_dims); 812 813 /* 814 * First pixel of the framebuffer from 815 * the start of the normal gtt mapping. 816 */ 817 fb->normal_view.color_plane[i].x = x; 818 fb->normal_view.color_plane[i].y = y; 819 fb->normal_view.color_plane[i].stride = fb->base.pitches[i]; 820 821 offset = calc_plane_aligned_offset(fb, i, &x, &y); 822 823 if (intel_fb_supports_90_270_rotation(fb)) 824 gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims, 825 offset, gtt_offset_rotated, x, y, 826 &fb->rotated_view); 827 828 if (intel_fb_needs_pot_stride_remap(fb)) 829 gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims, 830 offset, gtt_offset_remapped, x, y, 831 &fb->remapped_view); 832 833 size = calc_plane_normal_size(fb, i, &view_dims, x, y); 834 /* how many tiles in total needed in the bo */ 835 max_size = max(max_size, offset + size); 836 } 837 838 if (mul_u32_u32(max_size, tile_size) > obj->base.size) { 839 drm_dbg_kms(&i915->drm, 840 "fb too big for bo (need %llu bytes, have %zu bytes)\n", 841 mul_u32_u32(max_size, tile_size), obj->base.size); 842 return -EINVAL; 843 } 844 845 return 0; 846 } 847 848 static void intel_plane_remap_gtt(struct intel_plane_state *plane_state) 849 { 850 struct drm_i915_private *i915 = 851 to_i915(plane_state->uapi.plane->dev); 852 struct drm_framebuffer *fb = plane_state->hw.fb; 853 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 854 unsigned int rotation = plane_state->hw.rotation; 855 int i, num_planes = fb->format->num_planes; 856 unsigned int src_x, src_y; 857 unsigned int src_w, src_h; 858 u32 gtt_offset = 0; 859 860 intel_fb_view_init(&plane_state->view, 861 drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED : 862 I915_GGTT_VIEW_REMAPPED); 863 864 src_x = plane_state->uapi.src.x1 >> 16; 865 src_y = plane_state->uapi.src.y1 >> 16; 866 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; 867 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; 868 869 drm_WARN_ON(&i915->drm, is_ccs_modifier(fb->modifier)); 870 871 /* Make src coordinates relative to the viewport */ 872 drm_rect_translate(&plane_state->uapi.src, 873 -(src_x << 16), -(src_y << 16)); 874 875 /* Rotate src coordinates to match rotated GTT view */ 876 if (drm_rotation_90_or_270(rotation)) 877 drm_rect_rotate(&plane_state->uapi.src, 878 src_w << 16, src_h << 16, 879 DRM_MODE_ROTATE_270); 880 881 for (i = 0; i < num_planes; i++) { 882 unsigned int hsub = i ? fb->format->hsub : 1; 883 unsigned int vsub = i ? fb->format->vsub : 1; 884 struct fb_plane_view_dims view_dims; 885 unsigned int width, height; 886 unsigned int x, y; 887 u32 offset; 888 889 x = src_x / hsub; 890 y = src_y / vsub; 891 width = src_w / hsub; 892 height = src_h / vsub; 893 894 init_plane_view_dims(intel_fb, i, width, height, &view_dims); 895 896 /* 897 * First pixel of the src viewport from the 898 * start of the normal gtt mapping. 899 */ 900 x += intel_fb->normal_view.color_plane[i].x; 901 y += intel_fb->normal_view.color_plane[i].y; 902 903 offset = calc_plane_aligned_offset(intel_fb, i, &x, &y); 904 905 gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims, 906 offset, gtt_offset, x, y, 907 &plane_state->view); 908 } 909 } 910 911 void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation, 912 struct intel_fb_view *view) 913 { 914 if (drm_rotation_90_or_270(rotation)) 915 *view = fb->rotated_view; 916 else if (intel_fb_needs_pot_stride_remap(fb)) 917 *view = fb->remapped_view; 918 else 919 *view = fb->normal_view; 920 } 921 922 static int intel_plane_check_stride(const struct intel_plane_state *plane_state) 923 { 924 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); 925 const struct drm_framebuffer *fb = plane_state->hw.fb; 926 unsigned int rotation = plane_state->hw.rotation; 927 u32 stride, max_stride; 928 929 /* 930 * We ignore stride for all invisible planes that 931 * can be remapped. Otherwise we could end up 932 * with a false positive when the remapping didn't 933 * kick in due the plane being invisible. 934 */ 935 if (intel_plane_can_remap(plane_state) && 936 !plane_state->uapi.visible) 937 return 0; 938 939 /* FIXME other color planes? */ 940 stride = plane_state->view.color_plane[0].stride; 941 max_stride = plane->max_stride(plane, fb->format->format, 942 fb->modifier, rotation); 943 944 if (stride > max_stride) { 945 DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n", 946 fb->base.id, stride, 947 plane->base.base.id, plane->base.name, max_stride); 948 return -EINVAL; 949 } 950 951 return 0; 952 } 953 954 int intel_plane_compute_gtt(struct intel_plane_state *plane_state) 955 { 956 const struct intel_framebuffer *fb = 957 to_intel_framebuffer(plane_state->hw.fb); 958 unsigned int rotation = plane_state->hw.rotation; 959 960 if (!fb) 961 return 0; 962 963 if (intel_plane_needs_remap(plane_state)) { 964 intel_plane_remap_gtt(plane_state); 965 966 /* 967 * Sometimes even remapping can't overcome 968 * the stride limitations :( Can happen with 969 * big plane sizes and suitably misaligned 970 * offsets. 971 */ 972 return intel_plane_check_stride(plane_state); 973 } 974 975 intel_fb_fill_view(fb, rotation, &plane_state->view); 976 977 /* Rotate src coordinates to match rotated GTT view */ 978 if (drm_rotation_90_or_270(rotation)) 979 drm_rect_rotate(&plane_state->uapi.src, 980 fb->base.width << 16, fb->base.height << 16, 981 DRM_MODE_ROTATE_270); 982 983 return intel_plane_check_stride(plane_state); 984 } 985