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