2090 lines · c
1/*2 * Copyright © 2014 Intel Corporation3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice (including the next12 * paragraph) shall be included in all copies or substantial portions of the13 * Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER21 * DEALINGS IN THE SOFTWARE.22 */23 24/**25 * DOC: Frame Buffer Compression (FBC)26 *27 * FBC tries to save memory bandwidth (and so power consumption) by28 * compressing the amount of memory used by the display. It is total29 * transparent to user space and completely handled in the kernel.30 *31 * The benefits of FBC are mostly visible with solid backgrounds and32 * variation-less patterns. It comes from keeping the memory footprint small33 * and having fewer memory pages opened and accessed for refreshing the display.34 *35 * i915 is responsible to reserve stolen memory for FBC and configure its36 * offset on proper registers. The hardware takes care of all37 * compress/decompress. However there are many known cases where we have to38 * forcibly disable it to allow proper screen updates.39 */40 41#include <linux/string_helpers.h>42 43#include <drm/drm_blend.h>44#include <drm/drm_fourcc.h>45 46#include "gem/i915_gem_stolen.h"47#include "gt/intel_gt_types.h"48#include "i915_drv.h"49#include "i915_reg.h"50#include "i915_utils.h"51#include "i915_vgpu.h"52#include "i915_vma.h"53#include "i9xx_plane_regs.h"54#include "intel_cdclk.h"55#include "intel_de.h"56#include "intel_display_device.h"57#include "intel_display_trace.h"58#include "intel_display_types.h"59#include "intel_display_wa.h"60#include "intel_fbc.h"61#include "intel_fbc_regs.h"62#include "intel_frontbuffer.h"63 64#define for_each_fbc_id(__display, __fbc_id) \65 for ((__fbc_id) = INTEL_FBC_A; (__fbc_id) < I915_MAX_FBCS; (__fbc_id)++) \66 for_each_if(DISPLAY_RUNTIME_INFO(__display)->fbc_mask & BIT(__fbc_id))67 68#define for_each_intel_fbc(__display, __fbc, __fbc_id) \69 for_each_fbc_id((__display), (__fbc_id)) \70 for_each_if((__fbc) = (__display)->fbc[(__fbc_id)])71 72struct intel_fbc_funcs {73 void (*activate)(struct intel_fbc *fbc);74 void (*deactivate)(struct intel_fbc *fbc);75 bool (*is_active)(struct intel_fbc *fbc);76 bool (*is_compressing)(struct intel_fbc *fbc);77 void (*nuke)(struct intel_fbc *fbc);78 void (*program_cfb)(struct intel_fbc *fbc);79 void (*set_false_color)(struct intel_fbc *fbc, bool enable);80};81 82struct intel_fbc_state {83 struct intel_plane *plane;84 unsigned int cfb_stride;85 unsigned int cfb_size;86 unsigned int fence_y_offset;87 u16 override_cfb_stride;88 u16 interval;89 s8 fence_id;90};91 92struct intel_fbc {93 struct intel_display *display;94 const struct intel_fbc_funcs *funcs;95 96 /*97 * This is always the inner lock when overlapping with98 * struct_mutex and it's the outer lock when overlapping99 * with stolen_lock.100 */101 struct mutex lock;102 unsigned int busy_bits;103 104 struct i915_stolen_fb compressed_fb, compressed_llb;105 106 enum intel_fbc_id id;107 108 u8 limit;109 110 bool false_color;111 112 bool active;113 bool activated;114 bool flip_pending;115 116 bool underrun_detected;117 struct work_struct underrun_work;118 119 /*120 * This structure contains everything that's relevant to program the121 * hardware registers. When we want to figure out if we need to disable122 * and re-enable FBC for a new configuration we just check if there's123 * something different in the struct. The genx_fbc_activate functions124 * are supposed to read from it in order to program the registers.125 */126 struct intel_fbc_state state;127 const char *no_fbc_reason;128};129 130/* plane stride in pixels */131static unsigned int intel_fbc_plane_stride(const struct intel_plane_state *plane_state)132{133 const struct drm_framebuffer *fb = plane_state->hw.fb;134 unsigned int stride;135 136 stride = plane_state->view.color_plane[0].mapping_stride;137 if (!drm_rotation_90_or_270(plane_state->hw.rotation))138 stride /= fb->format->cpp[0];139 140 return stride;141}142 143static unsigned int intel_fbc_cfb_cpp(void)144{145 return 4; /* FBC always 4 bytes per pixel */146}147 148/* plane stride based cfb stride in bytes, assuming 1:1 compression limit */149static unsigned int intel_fbc_plane_cfb_stride(const struct intel_plane_state *plane_state)150{151 unsigned int cpp = intel_fbc_cfb_cpp();152 153 return intel_fbc_plane_stride(plane_state) * cpp;154}155 156/* minimum acceptable cfb stride in bytes, assuming 1:1 compression limit */157static unsigned int skl_fbc_min_cfb_stride(struct intel_display *display,158 unsigned int cpp, unsigned int width)159{160 unsigned int limit = 4; /* 1:4 compression limit is the worst case */161 unsigned int height = 4; /* FBC segment is 4 lines */162 unsigned int stride;163 164 /* minimum segment stride we can use */165 stride = width * cpp * height / limit;166 167 /*168 * Wa_16011863758: icl+169 * Avoid some hardware segment address miscalculation.170 */171 if (DISPLAY_VER(display) >= 11)172 stride += 64;173 174 /*175 * At least some of the platforms require each 4 line segment to176 * be 512 byte aligned. Just do it always for simplicity.177 */178 stride = ALIGN(stride, 512);179 180 /* convert back to single line equivalent with 1:1 compression limit */181 return stride * limit / height;182}183 184/* properly aligned cfb stride in bytes, assuming 1:1 compression limit */185static unsigned int _intel_fbc_cfb_stride(struct intel_display *display,186 unsigned int cpp, unsigned int width,187 unsigned int stride)188{189 /*190 * At least some of the platforms require each 4 line segment to191 * be 512 byte aligned. Aligning each line to 512 bytes guarantees192 * that regardless of the compression limit we choose later.193 */194 if (DISPLAY_VER(display) >= 9)195 return max(ALIGN(stride, 512), skl_fbc_min_cfb_stride(display, cpp, width));196 else197 return stride;198}199 200static unsigned int intel_fbc_cfb_stride(const struct intel_plane_state *plane_state)201{202 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);203 unsigned int stride = intel_fbc_plane_cfb_stride(plane_state);204 unsigned int width = drm_rect_width(&plane_state->uapi.src) >> 16;205 unsigned int cpp = intel_fbc_cfb_cpp();206 207 return _intel_fbc_cfb_stride(display, cpp, width, stride);208}209 210/*211 * Maximum height the hardware will compress, on HSW+212 * additional lines (up to the actual plane height) will213 * remain uncompressed.214 */215static unsigned int intel_fbc_max_cfb_height(struct intel_display *display)216{217 struct drm_i915_private *i915 = to_i915(display->drm);218 219 if (DISPLAY_VER(display) >= 8)220 return 2560;221 else if (DISPLAY_VER(display) >= 5 || IS_G4X(i915))222 return 2048;223 else224 return 1536;225}226 227static unsigned int _intel_fbc_cfb_size(struct intel_display *display,228 unsigned int height, unsigned int stride)229{230 return min(height, intel_fbc_max_cfb_height(display)) * stride;231}232 233static unsigned int intel_fbc_cfb_size(const struct intel_plane_state *plane_state)234{235 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);236 unsigned int height = drm_rect_height(&plane_state->uapi.src) >> 16;237 238 return _intel_fbc_cfb_size(display, height, intel_fbc_cfb_stride(plane_state));239}240 241static u16 intel_fbc_override_cfb_stride(const struct intel_plane_state *plane_state)242{243 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);244 unsigned int stride_aligned = intel_fbc_cfb_stride(plane_state);245 unsigned int stride = intel_fbc_plane_cfb_stride(plane_state);246 const struct drm_framebuffer *fb = plane_state->hw.fb;247 248 /*249 * Override stride in 64 byte units per 4 line segment.250 *251 * Gen9 hw miscalculates cfb stride for linear as252 * PLANE_STRIDE*512 instead of PLANE_STRIDE*64, so253 * we always need to use the override there.254 */255 if (stride != stride_aligned ||256 (DISPLAY_VER(display) == 9 && fb->modifier == DRM_FORMAT_MOD_LINEAR))257 return stride_aligned * 4 / 64;258 259 return 0;260}261 262static bool intel_fbc_has_fences(struct intel_display *display)263{264 struct drm_i915_private __maybe_unused *i915 = to_i915(display->drm);265 266 return intel_gt_support_legacy_fencing(to_gt(i915));267}268 269static u32 i8xx_fbc_ctl(struct intel_fbc *fbc)270{271 const struct intel_fbc_state *fbc_state = &fbc->state;272 struct intel_display *display = fbc->display;273 struct drm_i915_private *i915 = to_i915(display->drm);274 unsigned int cfb_stride;275 u32 fbc_ctl;276 277 cfb_stride = fbc_state->cfb_stride / fbc->limit;278 279 /* FBC_CTL wants 32B or 64B units */280 if (DISPLAY_VER(display) == 2)281 cfb_stride = (cfb_stride / 32) - 1;282 else283 cfb_stride = (cfb_stride / 64) - 1;284 285 fbc_ctl = FBC_CTL_PERIODIC |286 FBC_CTL_INTERVAL(fbc_state->interval) |287 FBC_CTL_STRIDE(cfb_stride);288 289 if (IS_I945GM(i915))290 fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */291 292 if (fbc_state->fence_id >= 0)293 fbc_ctl |= FBC_CTL_FENCENO(fbc_state->fence_id);294 295 return fbc_ctl;296}297 298static u32 i965_fbc_ctl2(struct intel_fbc *fbc)299{300 const struct intel_fbc_state *fbc_state = &fbc->state;301 u32 fbc_ctl2;302 303 fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM |304 FBC_CTL_PLANE(fbc_state->plane->i9xx_plane);305 306 if (fbc_state->fence_id >= 0)307 fbc_ctl2 |= FBC_CTL_CPU_FENCE_EN;308 309 return fbc_ctl2;310}311 312static void i8xx_fbc_deactivate(struct intel_fbc *fbc)313{314 struct intel_display *display = fbc->display;315 u32 fbc_ctl;316 317 /* Disable compression */318 fbc_ctl = intel_de_read(display, FBC_CONTROL);319 if ((fbc_ctl & FBC_CTL_EN) == 0)320 return;321 322 fbc_ctl &= ~FBC_CTL_EN;323 intel_de_write(display, FBC_CONTROL, fbc_ctl);324 325 /* Wait for compressing bit to clear */326 if (intel_de_wait_for_clear(display, FBC_STATUS,327 FBC_STAT_COMPRESSING, 10)) {328 drm_dbg_kms(display->drm, "FBC idle timed out\n");329 return;330 }331}332 333static void i8xx_fbc_activate(struct intel_fbc *fbc)334{335 const struct intel_fbc_state *fbc_state = &fbc->state;336 struct intel_display *display = fbc->display;337 int i;338 339 /* Clear old tags */340 for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)341 intel_de_write(display, FBC_TAG(i), 0);342 343 if (DISPLAY_VER(display) == 4) {344 intel_de_write(display, FBC_CONTROL2,345 i965_fbc_ctl2(fbc));346 intel_de_write(display, FBC_FENCE_OFF,347 fbc_state->fence_y_offset);348 }349 350 intel_de_write(display, FBC_CONTROL,351 FBC_CTL_EN | i8xx_fbc_ctl(fbc));352}353 354static bool i8xx_fbc_is_active(struct intel_fbc *fbc)355{356 return intel_de_read(fbc->display, FBC_CONTROL) & FBC_CTL_EN;357}358 359static bool i8xx_fbc_is_compressing(struct intel_fbc *fbc)360{361 return intel_de_read(fbc->display, FBC_STATUS) &362 (FBC_STAT_COMPRESSING | FBC_STAT_COMPRESSED);363}364 365static void i8xx_fbc_nuke(struct intel_fbc *fbc)366{367 struct intel_fbc_state *fbc_state = &fbc->state;368 enum i9xx_plane_id i9xx_plane = fbc_state->plane->i9xx_plane;369 struct drm_i915_private *dev_priv = to_i915(fbc->display->drm);370 371 intel_de_write_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane),372 intel_de_read_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane)));373}374 375static void i8xx_fbc_program_cfb(struct intel_fbc *fbc)376{377 struct intel_display *display = fbc->display;378 struct drm_i915_private *i915 = to_i915(display->drm);379 380 drm_WARN_ON(display->drm,381 range_overflows_end_t(u64, i915_gem_stolen_area_address(i915),382 i915_gem_stolen_node_offset(&fbc->compressed_fb),383 U32_MAX));384 drm_WARN_ON(display->drm,385 range_overflows_end_t(u64, i915_gem_stolen_area_address(i915),386 i915_gem_stolen_node_offset(&fbc->compressed_llb),387 U32_MAX));388 intel_de_write(i915, FBC_CFB_BASE,389 i915_gem_stolen_node_address(i915, &fbc->compressed_fb));390 intel_de_write(i915, FBC_LL_BASE,391 i915_gem_stolen_node_address(i915, &fbc->compressed_llb));392}393 394static const struct intel_fbc_funcs i8xx_fbc_funcs = {395 .activate = i8xx_fbc_activate,396 .deactivate = i8xx_fbc_deactivate,397 .is_active = i8xx_fbc_is_active,398 .is_compressing = i8xx_fbc_is_compressing,399 .nuke = i8xx_fbc_nuke,400 .program_cfb = i8xx_fbc_program_cfb,401};402 403static void i965_fbc_nuke(struct intel_fbc *fbc)404{405 struct intel_fbc_state *fbc_state = &fbc->state;406 enum i9xx_plane_id i9xx_plane = fbc_state->plane->i9xx_plane;407 struct drm_i915_private *dev_priv = to_i915(fbc->display->drm);408 409 intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane),410 intel_de_read_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane)));411}412 413static const struct intel_fbc_funcs i965_fbc_funcs = {414 .activate = i8xx_fbc_activate,415 .deactivate = i8xx_fbc_deactivate,416 .is_active = i8xx_fbc_is_active,417 .is_compressing = i8xx_fbc_is_compressing,418 .nuke = i965_fbc_nuke,419 .program_cfb = i8xx_fbc_program_cfb,420};421 422static u32 g4x_dpfc_ctl_limit(struct intel_fbc *fbc)423{424 switch (fbc->limit) {425 default:426 MISSING_CASE(fbc->limit);427 fallthrough;428 case 1:429 return DPFC_CTL_LIMIT_1X;430 case 2:431 return DPFC_CTL_LIMIT_2X;432 case 4:433 return DPFC_CTL_LIMIT_4X;434 }435}436 437static u32 g4x_dpfc_ctl(struct intel_fbc *fbc)438{439 const struct intel_fbc_state *fbc_state = &fbc->state;440 struct intel_display *display = fbc->display;441 struct drm_i915_private *i915 = to_i915(display->drm);442 u32 dpfc_ctl;443 444 dpfc_ctl = g4x_dpfc_ctl_limit(fbc) |445 DPFC_CTL_PLANE_G4X(fbc_state->plane->i9xx_plane);446 447 if (IS_G4X(i915))448 dpfc_ctl |= DPFC_CTL_SR_EN;449 450 if (fbc_state->fence_id >= 0) {451 dpfc_ctl |= DPFC_CTL_FENCE_EN_G4X;452 453 if (DISPLAY_VER(display) < 6)454 dpfc_ctl |= DPFC_CTL_FENCENO(fbc_state->fence_id);455 }456 457 return dpfc_ctl;458}459 460static void g4x_fbc_activate(struct intel_fbc *fbc)461{462 const struct intel_fbc_state *fbc_state = &fbc->state;463 struct intel_display *display = fbc->display;464 465 intel_de_write(display, DPFC_FENCE_YOFF,466 fbc_state->fence_y_offset);467 468 intel_de_write(display, DPFC_CONTROL,469 DPFC_CTL_EN | g4x_dpfc_ctl(fbc));470}471 472static void g4x_fbc_deactivate(struct intel_fbc *fbc)473{474 struct intel_display *display = fbc->display;475 u32 dpfc_ctl;476 477 /* Disable compression */478 dpfc_ctl = intel_de_read(display, DPFC_CONTROL);479 if (dpfc_ctl & DPFC_CTL_EN) {480 dpfc_ctl &= ~DPFC_CTL_EN;481 intel_de_write(display, DPFC_CONTROL, dpfc_ctl);482 }483}484 485static bool g4x_fbc_is_active(struct intel_fbc *fbc)486{487 return intel_de_read(fbc->display, DPFC_CONTROL) & DPFC_CTL_EN;488}489 490static bool g4x_fbc_is_compressing(struct intel_fbc *fbc)491{492 return intel_de_read(fbc->display, DPFC_STATUS) & DPFC_COMP_SEG_MASK;493}494 495static void g4x_fbc_program_cfb(struct intel_fbc *fbc)496{497 struct intel_display *display = fbc->display;498 499 intel_de_write(display, DPFC_CB_BASE,500 i915_gem_stolen_node_offset(&fbc->compressed_fb));501}502 503static const struct intel_fbc_funcs g4x_fbc_funcs = {504 .activate = g4x_fbc_activate,505 .deactivate = g4x_fbc_deactivate,506 .is_active = g4x_fbc_is_active,507 .is_compressing = g4x_fbc_is_compressing,508 .nuke = i965_fbc_nuke,509 .program_cfb = g4x_fbc_program_cfb,510};511 512static void ilk_fbc_activate(struct intel_fbc *fbc)513{514 struct intel_fbc_state *fbc_state = &fbc->state;515 struct intel_display *display = fbc->display;516 517 intel_de_write(display, ILK_DPFC_FENCE_YOFF(fbc->id),518 fbc_state->fence_y_offset);519 520 intel_de_write(display, ILK_DPFC_CONTROL(fbc->id),521 DPFC_CTL_EN | g4x_dpfc_ctl(fbc));522}523 524static void ilk_fbc_deactivate(struct intel_fbc *fbc)525{526 struct intel_display *display = fbc->display;527 u32 dpfc_ctl;528 529 /* Disable compression */530 dpfc_ctl = intel_de_read(display, ILK_DPFC_CONTROL(fbc->id));531 if (dpfc_ctl & DPFC_CTL_EN) {532 dpfc_ctl &= ~DPFC_CTL_EN;533 intel_de_write(display, ILK_DPFC_CONTROL(fbc->id), dpfc_ctl);534 }535}536 537static bool ilk_fbc_is_active(struct intel_fbc *fbc)538{539 return intel_de_read(fbc->display, ILK_DPFC_CONTROL(fbc->id)) & DPFC_CTL_EN;540}541 542static bool ilk_fbc_is_compressing(struct intel_fbc *fbc)543{544 return intel_de_read(fbc->display, ILK_DPFC_STATUS(fbc->id)) & DPFC_COMP_SEG_MASK;545}546 547static void ilk_fbc_program_cfb(struct intel_fbc *fbc)548{549 struct intel_display *display = fbc->display;550 551 intel_de_write(display, ILK_DPFC_CB_BASE(fbc->id),552 i915_gem_stolen_node_offset(&fbc->compressed_fb));553}554 555static const struct intel_fbc_funcs ilk_fbc_funcs = {556 .activate = ilk_fbc_activate,557 .deactivate = ilk_fbc_deactivate,558 .is_active = ilk_fbc_is_active,559 .is_compressing = ilk_fbc_is_compressing,560 .nuke = i965_fbc_nuke,561 .program_cfb = ilk_fbc_program_cfb,562};563 564static void snb_fbc_program_fence(struct intel_fbc *fbc)565{566 const struct intel_fbc_state *fbc_state = &fbc->state;567 struct intel_display *display = fbc->display;568 u32 ctl = 0;569 570 if (fbc_state->fence_id >= 0)571 ctl = SNB_DPFC_FENCE_EN | SNB_DPFC_FENCENO(fbc_state->fence_id);572 573 intel_de_write(display, SNB_DPFC_CTL_SA, ctl);574 intel_de_write(display, SNB_DPFC_CPU_FENCE_OFFSET, fbc_state->fence_y_offset);575}576 577static void snb_fbc_activate(struct intel_fbc *fbc)578{579 snb_fbc_program_fence(fbc);580 581 ilk_fbc_activate(fbc);582}583 584static void snb_fbc_nuke(struct intel_fbc *fbc)585{586 struct intel_display *display = fbc->display;587 588 intel_de_write(display, MSG_FBC_REND_STATE(fbc->id), FBC_REND_NUKE);589 intel_de_posting_read(display, MSG_FBC_REND_STATE(fbc->id));590}591 592static const struct intel_fbc_funcs snb_fbc_funcs = {593 .activate = snb_fbc_activate,594 .deactivate = ilk_fbc_deactivate,595 .is_active = ilk_fbc_is_active,596 .is_compressing = ilk_fbc_is_compressing,597 .nuke = snb_fbc_nuke,598 .program_cfb = ilk_fbc_program_cfb,599};600 601static void glk_fbc_program_cfb_stride(struct intel_fbc *fbc)602{603 const struct intel_fbc_state *fbc_state = &fbc->state;604 struct intel_display *display = fbc->display;605 u32 val = 0;606 607 if (fbc_state->override_cfb_stride)608 val |= FBC_STRIDE_OVERRIDE |609 FBC_STRIDE(fbc_state->override_cfb_stride / fbc->limit);610 611 intel_de_write(display, GLK_FBC_STRIDE(fbc->id), val);612}613 614static void skl_fbc_program_cfb_stride(struct intel_fbc *fbc)615{616 const struct intel_fbc_state *fbc_state = &fbc->state;617 struct intel_display *display = fbc->display;618 u32 val = 0;619 620 /* Display WA #0529: skl, kbl, bxt. */621 if (fbc_state->override_cfb_stride)622 val |= CHICKEN_FBC_STRIDE_OVERRIDE |623 CHICKEN_FBC_STRIDE(fbc_state->override_cfb_stride / fbc->limit);624 625 intel_de_rmw(display, CHICKEN_MISC_4,626 CHICKEN_FBC_STRIDE_OVERRIDE |627 CHICKEN_FBC_STRIDE_MASK, val);628}629 630static u32 ivb_dpfc_ctl(struct intel_fbc *fbc)631{632 const struct intel_fbc_state *fbc_state = &fbc->state;633 struct intel_display *display = fbc->display;634 struct drm_i915_private *i915 = to_i915(display->drm);635 u32 dpfc_ctl;636 637 dpfc_ctl = g4x_dpfc_ctl_limit(fbc);638 639 if (IS_IVYBRIDGE(i915))640 dpfc_ctl |= DPFC_CTL_PLANE_IVB(fbc_state->plane->i9xx_plane);641 642 if (DISPLAY_VER(display) >= 20)643 dpfc_ctl |= DPFC_CTL_PLANE_BINDING(fbc_state->plane->id);644 645 if (fbc_state->fence_id >= 0)646 dpfc_ctl |= DPFC_CTL_FENCE_EN_IVB;647 648 if (fbc->false_color)649 dpfc_ctl |= DPFC_CTL_FALSE_COLOR;650 651 return dpfc_ctl;652}653 654static void ivb_fbc_activate(struct intel_fbc *fbc)655{656 struct intel_display *display = fbc->display;657 u32 dpfc_ctl;658 659 if (DISPLAY_VER(display) >= 10)660 glk_fbc_program_cfb_stride(fbc);661 else if (DISPLAY_VER(display) == 9)662 skl_fbc_program_cfb_stride(fbc);663 664 if (intel_fbc_has_fences(display))665 snb_fbc_program_fence(fbc);666 667 /* wa_14019417088 Alternative WA*/668 dpfc_ctl = ivb_dpfc_ctl(fbc);669 if (DISPLAY_VER(display) >= 20)670 intel_de_write(display, ILK_DPFC_CONTROL(fbc->id), dpfc_ctl);671 672 intel_de_write(display, ILK_DPFC_CONTROL(fbc->id),673 DPFC_CTL_EN | dpfc_ctl);674}675 676static bool ivb_fbc_is_compressing(struct intel_fbc *fbc)677{678 return intel_de_read(fbc->display, ILK_DPFC_STATUS2(fbc->id)) & DPFC_COMP_SEG_MASK_IVB;679}680 681static void ivb_fbc_set_false_color(struct intel_fbc *fbc,682 bool enable)683{684 intel_de_rmw(fbc->display, ILK_DPFC_CONTROL(fbc->id),685 DPFC_CTL_FALSE_COLOR, enable ? DPFC_CTL_FALSE_COLOR : 0);686}687 688static const struct intel_fbc_funcs ivb_fbc_funcs = {689 .activate = ivb_fbc_activate,690 .deactivate = ilk_fbc_deactivate,691 .is_active = ilk_fbc_is_active,692 .is_compressing = ivb_fbc_is_compressing,693 .nuke = snb_fbc_nuke,694 .program_cfb = ilk_fbc_program_cfb,695 .set_false_color = ivb_fbc_set_false_color,696};697 698static bool intel_fbc_hw_is_active(struct intel_fbc *fbc)699{700 return fbc->funcs->is_active(fbc);701}702 703static void intel_fbc_hw_activate(struct intel_fbc *fbc)704{705 trace_intel_fbc_activate(fbc->state.plane);706 707 fbc->active = true;708 fbc->activated = true;709 710 fbc->funcs->activate(fbc);711}712 713static void intel_fbc_hw_deactivate(struct intel_fbc *fbc)714{715 trace_intel_fbc_deactivate(fbc->state.plane);716 717 fbc->active = false;718 719 fbc->funcs->deactivate(fbc);720}721 722static bool intel_fbc_is_compressing(struct intel_fbc *fbc)723{724 return fbc->funcs->is_compressing(fbc);725}726 727static void intel_fbc_nuke(struct intel_fbc *fbc)728{729 struct intel_display *display = fbc->display;730 731 lockdep_assert_held(&fbc->lock);732 drm_WARN_ON(display->drm, fbc->flip_pending);733 734 trace_intel_fbc_nuke(fbc->state.plane);735 736 fbc->funcs->nuke(fbc);737}738 739static void intel_fbc_activate(struct intel_fbc *fbc)740{741 lockdep_assert_held(&fbc->lock);742 743 intel_fbc_hw_activate(fbc);744 intel_fbc_nuke(fbc);745 746 fbc->no_fbc_reason = NULL;747}748 749static void intel_fbc_deactivate(struct intel_fbc *fbc, const char *reason)750{751 lockdep_assert_held(&fbc->lock);752 753 if (fbc->active)754 intel_fbc_hw_deactivate(fbc);755 756 fbc->no_fbc_reason = reason;757}758 759static u64 intel_fbc_cfb_base_max(struct intel_display *display)760{761 struct drm_i915_private *i915 = to_i915(display->drm);762 763 if (DISPLAY_VER(display) >= 5 || IS_G4X(i915))764 return BIT_ULL(28);765 else766 return BIT_ULL(32);767}768 769static u64 intel_fbc_stolen_end(struct intel_display *display)770{771 struct drm_i915_private __maybe_unused *i915 = to_i915(display->drm);772 u64 end;773 774 /* The FBC hardware for BDW/SKL doesn't have access to the stolen775 * reserved range size, so it always assumes the maximum (8mb) is used.776 * If we enable FBC using a CFB on that memory range we'll get FIFO777 * underruns, even if that range is not reserved by the BIOS. */778 if (IS_BROADWELL(i915) ||779 (DISPLAY_VER(display) == 9 && !IS_BROXTON(i915)))780 end = i915_gem_stolen_area_size(i915) - 8 * 1024 * 1024;781 else782 end = U64_MAX;783 784 return min(end, intel_fbc_cfb_base_max(display));785}786 787static int intel_fbc_min_limit(const struct intel_plane_state *plane_state)788{789 return plane_state->hw.fb->format->cpp[0] == 2 ? 2 : 1;790}791 792static int intel_fbc_max_limit(struct intel_display *display)793{794 struct drm_i915_private *i915 = to_i915(display->drm);795 796 /* WaFbcOnly1to1Ratio:ctg */797 if (IS_G4X(i915))798 return 1;799 800 /*801 * FBC2 can only do 1:1, 1:2, 1:4, we limit802 * FBC1 to the same out of convenience.803 */804 return 4;805}806 807static int find_compression_limit(struct intel_fbc *fbc,808 unsigned int size, int min_limit)809{810 struct intel_display *display = fbc->display;811 struct drm_i915_private *i915 = to_i915(display->drm);812 u64 end = intel_fbc_stolen_end(display);813 int ret, limit = min_limit;814 815 size /= limit;816 817 /* Try to over-allocate to reduce reallocations and fragmentation. */818 ret = i915_gem_stolen_insert_node_in_range(i915, &fbc->compressed_fb,819 size <<= 1, 4096, 0, end);820 if (ret == 0)821 return limit;822 823 for (; limit <= intel_fbc_max_limit(display); limit <<= 1) {824 ret = i915_gem_stolen_insert_node_in_range(i915, &fbc->compressed_fb,825 size >>= 1, 4096, 0, end);826 if (ret == 0)827 return limit;828 }829 830 return 0;831}832 833static int intel_fbc_alloc_cfb(struct intel_fbc *fbc,834 unsigned int size, int min_limit)835{836 struct intel_display *display = fbc->display;837 struct drm_i915_private *i915 = to_i915(display->drm);838 int ret;839 840 drm_WARN_ON(display->drm,841 i915_gem_stolen_node_allocated(&fbc->compressed_fb));842 drm_WARN_ON(display->drm,843 i915_gem_stolen_node_allocated(&fbc->compressed_llb));844 845 if (DISPLAY_VER(display) < 5 && !IS_G4X(i915)) {846 ret = i915_gem_stolen_insert_node(i915, &fbc->compressed_llb,847 4096, 4096);848 if (ret)849 goto err;850 }851 852 ret = find_compression_limit(fbc, size, min_limit);853 if (!ret)854 goto err_llb;855 else if (ret > min_limit)856 drm_info_once(display->drm,857 "Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n");858 859 fbc->limit = ret;860 861 drm_dbg_kms(display->drm,862 "reserved %llu bytes of contiguous stolen space for FBC, limit: %d\n",863 i915_gem_stolen_node_size(&fbc->compressed_fb), fbc->limit);864 return 0;865 866err_llb:867 if (i915_gem_stolen_node_allocated(&fbc->compressed_llb))868 i915_gem_stolen_remove_node(i915, &fbc->compressed_llb);869err:870 if (i915_gem_stolen_initialized(i915))871 drm_info_once(display->drm,872 "not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size);873 return -ENOSPC;874}875 876static void intel_fbc_program_cfb(struct intel_fbc *fbc)877{878 fbc->funcs->program_cfb(fbc);879}880 881static void intel_fbc_program_workarounds(struct intel_fbc *fbc)882{883 struct intel_display *display = fbc->display;884 struct drm_i915_private *i915 = to_i915(display->drm);885 886 if (IS_SKYLAKE(i915) || IS_BROXTON(i915)) {887 /*888 * WaFbcHighMemBwCorruptionAvoidance:skl,bxt889 * Display WA #0883: skl,bxt890 */891 intel_de_rmw(display, ILK_DPFC_CHICKEN(fbc->id),892 0, DPFC_DISABLE_DUMMY0);893 }894 895 if (IS_SKYLAKE(i915) || IS_KABYLAKE(i915) ||896 IS_COFFEELAKE(i915) || IS_COMETLAKE(i915)) {897 /*898 * WaFbcNukeOnHostModify:skl,kbl,cfl899 * Display WA #0873: skl,kbl,cfl900 */901 intel_de_rmw(display, ILK_DPFC_CHICKEN(fbc->id),902 0, DPFC_NUKE_ON_ANY_MODIFICATION);903 }904 905 /* Wa_1409120013:icl,jsl,tgl,dg1 */906 if (IS_DISPLAY_VER(display, 11, 12))907 intel_de_rmw(display, ILK_DPFC_CHICKEN(fbc->id),908 0, DPFC_CHICKEN_COMP_DUMMY_PIXEL);909 910 /* Wa_22014263786:icl,jsl,tgl,dg1,rkl,adls,adlp,mtl */911 if (DISPLAY_VER(display) >= 11 && !IS_DG2(i915))912 intel_de_rmw(display, ILK_DPFC_CHICKEN(fbc->id),913 0, DPFC_CHICKEN_FORCE_SLB_INVALIDATION);914}915 916static void __intel_fbc_cleanup_cfb(struct intel_fbc *fbc)917{918 struct intel_display *display = fbc->display;919 struct drm_i915_private *i915 = to_i915(display->drm);920 921 if (WARN_ON(intel_fbc_hw_is_active(fbc)))922 return;923 924 if (i915_gem_stolen_node_allocated(&fbc->compressed_llb))925 i915_gem_stolen_remove_node(i915, &fbc->compressed_llb);926 if (i915_gem_stolen_node_allocated(&fbc->compressed_fb))927 i915_gem_stolen_remove_node(i915, &fbc->compressed_fb);928}929 930void intel_fbc_cleanup(struct intel_display *display)931{932 struct intel_fbc *fbc;933 enum intel_fbc_id fbc_id;934 935 for_each_intel_fbc(display, fbc, fbc_id) {936 mutex_lock(&fbc->lock);937 __intel_fbc_cleanup_cfb(fbc);938 mutex_unlock(&fbc->lock);939 940 kfree(fbc);941 }942}943 944static bool i8xx_fbc_stride_is_valid(const struct intel_plane_state *plane_state)945{946 const struct drm_framebuffer *fb = plane_state->hw.fb;947 unsigned int stride = intel_fbc_plane_stride(plane_state) *948 fb->format->cpp[0];949 950 return stride == 4096 || stride == 8192;951}952 953static bool i965_fbc_stride_is_valid(const struct intel_plane_state *plane_state)954{955 const struct drm_framebuffer *fb = plane_state->hw.fb;956 unsigned int stride = intel_fbc_plane_stride(plane_state) *957 fb->format->cpp[0];958 959 return stride >= 2048 && stride <= 16384;960}961 962static bool g4x_fbc_stride_is_valid(const struct intel_plane_state *plane_state)963{964 return true;965}966 967static bool skl_fbc_stride_is_valid(const struct intel_plane_state *plane_state)968{969 const struct drm_framebuffer *fb = plane_state->hw.fb;970 unsigned int stride = intel_fbc_plane_stride(plane_state) *971 fb->format->cpp[0];972 973 /* Display WA #1105: skl,bxt,kbl,cfl,glk */974 if (fb->modifier == DRM_FORMAT_MOD_LINEAR && stride & 511)975 return false;976 977 return true;978}979 980static bool icl_fbc_stride_is_valid(const struct intel_plane_state *plane_state)981{982 return true;983}984 985static bool stride_is_valid(const struct intel_plane_state *plane_state)986{987 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);988 struct drm_i915_private *i915 = to_i915(display->drm);989 990 if (DISPLAY_VER(display) >= 11)991 return icl_fbc_stride_is_valid(plane_state);992 else if (DISPLAY_VER(display) >= 9)993 return skl_fbc_stride_is_valid(plane_state);994 else if (DISPLAY_VER(display) >= 5 || IS_G4X(i915))995 return g4x_fbc_stride_is_valid(plane_state);996 else if (DISPLAY_VER(display) == 4)997 return i965_fbc_stride_is_valid(plane_state);998 else999 return i8xx_fbc_stride_is_valid(plane_state);1000}1001 1002static bool i8xx_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state)1003{1004 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1005 const struct drm_framebuffer *fb = plane_state->hw.fb;1006 1007 switch (fb->format->format) {1008 case DRM_FORMAT_XRGB8888:1009 case DRM_FORMAT_XBGR8888:1010 return true;1011 case DRM_FORMAT_XRGB1555:1012 case DRM_FORMAT_RGB565:1013 /* 16bpp not supported on gen2 */1014 if (DISPLAY_VER(display) == 2)1015 return false;1016 return true;1017 default:1018 return false;1019 }1020}1021 1022static bool g4x_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state)1023{1024 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1025 struct drm_i915_private *i915 = to_i915(display->drm);1026 const struct drm_framebuffer *fb = plane_state->hw.fb;1027 1028 switch (fb->format->format) {1029 case DRM_FORMAT_XRGB8888:1030 case DRM_FORMAT_XBGR8888:1031 return true;1032 case DRM_FORMAT_RGB565:1033 /* WaFbcOnly1to1Ratio:ctg */1034 if (IS_G4X(i915))1035 return false;1036 return true;1037 default:1038 return false;1039 }1040}1041 1042static bool lnl_fbc_pixel_format_is_valid(const struct intel_plane_state *plane_state)1043{1044 const struct drm_framebuffer *fb = plane_state->hw.fb;1045 1046 switch (fb->format->format) {1047 case DRM_FORMAT_XRGB8888:1048 case DRM_FORMAT_XBGR8888:1049 case DRM_FORMAT_ARGB8888:1050 case DRM_FORMAT_ABGR8888:1051 case DRM_FORMAT_RGB565:1052 return true;1053 default:1054 return false;1055 }1056}1057 1058static bool pixel_format_is_valid(const struct intel_plane_state *plane_state)1059{1060 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1061 struct drm_i915_private *i915 = to_i915(display->drm);1062 1063 if (DISPLAY_VER(display) >= 20)1064 return lnl_fbc_pixel_format_is_valid(plane_state);1065 else if (DISPLAY_VER(display) >= 5 || IS_G4X(i915))1066 return g4x_fbc_pixel_format_is_valid(plane_state);1067 else1068 return i8xx_fbc_pixel_format_is_valid(plane_state);1069}1070 1071static bool i8xx_fbc_rotation_is_valid(const struct intel_plane_state *plane_state)1072{1073 return plane_state->hw.rotation == DRM_MODE_ROTATE_0;1074}1075 1076static bool g4x_fbc_rotation_is_valid(const struct intel_plane_state *plane_state)1077{1078 return true;1079}1080 1081static bool skl_fbc_rotation_is_valid(const struct intel_plane_state *plane_state)1082{1083 const struct drm_framebuffer *fb = plane_state->hw.fb;1084 unsigned int rotation = plane_state->hw.rotation;1085 1086 if (fb->format->format == DRM_FORMAT_RGB565 &&1087 drm_rotation_90_or_270(rotation))1088 return false;1089 1090 return true;1091}1092 1093static bool rotation_is_valid(const struct intel_plane_state *plane_state)1094{1095 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1096 struct drm_i915_private *i915 = to_i915(display->drm);1097 1098 if (DISPLAY_VER(display) >= 9)1099 return skl_fbc_rotation_is_valid(plane_state);1100 else if (DISPLAY_VER(display) >= 5 || IS_G4X(i915))1101 return g4x_fbc_rotation_is_valid(plane_state);1102 else1103 return i8xx_fbc_rotation_is_valid(plane_state);1104}1105 1106static void intel_fbc_max_surface_size(struct intel_display *display,1107 unsigned int *w, unsigned int *h)1108{1109 struct drm_i915_private *i915 = to_i915(display->drm);1110 1111 if (DISPLAY_VER(display) >= 11) {1112 *w = 8192;1113 *h = 4096;1114 } else if (DISPLAY_VER(display) >= 10) {1115 *w = 5120;1116 *h = 4096;1117 } else if (DISPLAY_VER(display) >= 7) {1118 *w = 4096;1119 *h = 4096;1120 } else if (DISPLAY_VER(display) >= 5 || IS_G4X(i915)) {1121 *w = 4096;1122 *h = 2048;1123 } else {1124 *w = 2048;1125 *h = 1536;1126 }1127}1128 1129/*1130 * For some reason, the hardware tracking starts looking at whatever we1131 * programmed as the display plane base address register. It does not look at1132 * the X and Y offset registers. That's why we include the src x/y offsets1133 * instead of just looking at the plane size.1134 */1135static bool intel_fbc_surface_size_ok(const struct intel_plane_state *plane_state)1136{1137 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1138 unsigned int effective_w, effective_h, max_w, max_h;1139 1140 intel_fbc_max_surface_size(display, &max_w, &max_h);1141 1142 effective_w = plane_state->view.color_plane[0].x +1143 (drm_rect_width(&plane_state->uapi.src) >> 16);1144 effective_h = plane_state->view.color_plane[0].y +1145 (drm_rect_height(&plane_state->uapi.src) >> 16);1146 1147 return effective_w <= max_w && effective_h <= max_h;1148}1149 1150static void intel_fbc_max_plane_size(struct intel_display *display,1151 unsigned int *w, unsigned int *h)1152{1153 struct drm_i915_private *i915 = to_i915(display->drm);1154 1155 if (DISPLAY_VER(display) >= 10) {1156 *w = 5120;1157 *h = 4096;1158 } else if (DISPLAY_VER(display) >= 8 || IS_HASWELL(i915)) {1159 *w = 4096;1160 *h = 4096;1161 } else if (DISPLAY_VER(display) >= 5 || IS_G4X(i915)) {1162 *w = 4096;1163 *h = 2048;1164 } else {1165 *w = 2048;1166 *h = 1536;1167 }1168}1169 1170static bool intel_fbc_plane_size_valid(const struct intel_plane_state *plane_state)1171{1172 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1173 unsigned int w, h, max_w, max_h;1174 1175 intel_fbc_max_plane_size(display, &max_w, &max_h);1176 1177 w = drm_rect_width(&plane_state->uapi.src) >> 16;1178 h = drm_rect_height(&plane_state->uapi.src) >> 16;1179 1180 return w <= max_w && h <= max_h;1181}1182 1183static bool i8xx_fbc_tiling_valid(const struct intel_plane_state *plane_state)1184{1185 const struct drm_framebuffer *fb = plane_state->hw.fb;1186 1187 return fb->modifier == I915_FORMAT_MOD_X_TILED;1188}1189 1190static bool skl_fbc_tiling_valid(const struct intel_plane_state *plane_state)1191{1192 return true;1193}1194 1195static bool tiling_is_valid(const struct intel_plane_state *plane_state)1196{1197 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1198 1199 if (DISPLAY_VER(display) >= 9)1200 return skl_fbc_tiling_valid(plane_state);1201 else1202 return i8xx_fbc_tiling_valid(plane_state);1203}1204 1205static void intel_fbc_update_state(struct intel_atomic_state *state,1206 struct intel_crtc *crtc,1207 struct intel_plane *plane)1208{1209 struct intel_display *display = to_intel_display(state->base.dev);1210 const struct intel_crtc_state *crtc_state =1211 intel_atomic_get_new_crtc_state(state, crtc);1212 const struct intel_plane_state *plane_state =1213 intel_atomic_get_new_plane_state(state, plane);1214 struct intel_fbc *fbc = plane->fbc;1215 struct intel_fbc_state *fbc_state = &fbc->state;1216 1217 WARN_ON(plane_state->no_fbc_reason);1218 WARN_ON(fbc_state->plane && fbc_state->plane != plane);1219 1220 fbc_state->plane = plane;1221 1222 /* FBC1 compression interval: arbitrary choice of 1 second */1223 fbc_state->interval = drm_mode_vrefresh(&crtc_state->hw.adjusted_mode);1224 1225 fbc_state->fence_y_offset = intel_plane_fence_y_offset(plane_state);1226 1227 drm_WARN_ON(display->drm, plane_state->flags & PLANE_HAS_FENCE &&1228 !intel_fbc_has_fences(display));1229 1230 if (plane_state->flags & PLANE_HAS_FENCE)1231 fbc_state->fence_id = i915_vma_fence_id(plane_state->ggtt_vma);1232 else1233 fbc_state->fence_id = -1;1234 1235 fbc_state->cfb_stride = intel_fbc_cfb_stride(plane_state);1236 fbc_state->cfb_size = intel_fbc_cfb_size(plane_state);1237 fbc_state->override_cfb_stride = intel_fbc_override_cfb_stride(plane_state);1238}1239 1240static bool intel_fbc_is_fence_ok(const struct intel_plane_state *plane_state)1241{1242 struct intel_display *display = to_intel_display(plane_state->uapi.plane->dev);1243 1244 /*1245 * The use of a CPU fence is one of two ways to detect writes by the1246 * CPU to the scanout and trigger updates to the FBC.1247 *1248 * The other method is by software tracking (see1249 * intel_fbc_invalidate/flush()), it will manually notify FBC and nuke1250 * the current compressed buffer and recompress it.1251 *1252 * Note that is possible for a tiled surface to be unmappable (and1253 * so have no fence associated with it) due to aperture constraints1254 * at the time of pinning.1255 */1256 return DISPLAY_VER(display) >= 9 ||1257 (plane_state->flags & PLANE_HAS_FENCE &&1258 i915_vma_fence_id(plane_state->ggtt_vma) != -1);1259}1260 1261static bool intel_fbc_is_cfb_ok(const struct intel_plane_state *plane_state)1262{1263 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);1264 struct intel_fbc *fbc = plane->fbc;1265 1266 return intel_fbc_min_limit(plane_state) <= fbc->limit &&1267 intel_fbc_cfb_size(plane_state) <= fbc->limit *1268 i915_gem_stolen_node_size(&fbc->compressed_fb);1269}1270 1271static bool intel_fbc_is_ok(const struct intel_plane_state *plane_state)1272{1273 return !plane_state->no_fbc_reason &&1274 intel_fbc_is_fence_ok(plane_state) &&1275 intel_fbc_is_cfb_ok(plane_state);1276}1277 1278static int intel_fbc_check_plane(struct intel_atomic_state *state,1279 struct intel_plane *plane)1280{1281 struct intel_display *display = to_intel_display(state->base.dev);1282 struct drm_i915_private *i915 = to_i915(display->drm);1283 struct intel_plane_state *plane_state =1284 intel_atomic_get_new_plane_state(state, plane);1285 const struct drm_framebuffer *fb = plane_state->hw.fb;1286 struct intel_crtc *crtc = to_intel_crtc(plane_state->hw.crtc);1287 const struct intel_crtc_state *crtc_state;1288 struct intel_fbc *fbc = plane->fbc;1289 1290 if (!fbc)1291 return 0;1292 1293 if (!i915_gem_stolen_initialized(i915)) {1294 plane_state->no_fbc_reason = "stolen memory not initialised";1295 return 0;1296 }1297 1298 if (intel_vgpu_active(i915)) {1299 plane_state->no_fbc_reason = "VGPU active";1300 return 0;1301 }1302 1303 if (!display->params.enable_fbc) {1304 plane_state->no_fbc_reason = "disabled per module param or by default";1305 return 0;1306 }1307 1308 if (!plane_state->uapi.visible) {1309 plane_state->no_fbc_reason = "plane not visible";1310 return 0;1311 }1312 1313 if (intel_display_needs_wa_16023588340(i915)) {1314 plane_state->no_fbc_reason = "Wa_16023588340";1315 return 0;1316 }1317 1318 /* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */1319 if (i915_vtd_active(i915) && (IS_SKYLAKE(i915) || IS_BROXTON(i915))) {1320 plane_state->no_fbc_reason = "VT-d enabled";1321 return 0;1322 }1323 1324 crtc_state = intel_atomic_get_new_crtc_state(state, crtc);1325 1326 if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {1327 plane_state->no_fbc_reason = "interlaced mode not supported";1328 return 0;1329 }1330 1331 if (crtc_state->double_wide) {1332 plane_state->no_fbc_reason = "double wide pipe not supported";1333 return 0;1334 }1335 1336 /*1337 * Display 12+ is not supporting FBC with PSR2.1338 * Recommendation is to keep this combination disabled1339 * Bspec: 50422 HSD: 140102600021340 */1341 if (IS_DISPLAY_VER(display, 12, 14) && crtc_state->has_sel_update &&1342 !crtc_state->has_panel_replay) {1343 plane_state->no_fbc_reason = "PSR2 enabled";1344 return 0;1345 }1346 1347 /* Wa_14016291713 */1348 if ((IS_DISPLAY_VER(display, 12, 13) ||1349 IS_DISPLAY_VER_STEP(i915, IP_VER(14, 0), STEP_A0, STEP_C0)) &&1350 crtc_state->has_psr && !crtc_state->has_panel_replay) {1351 plane_state->no_fbc_reason = "PSR1 enabled (Wa_14016291713)";1352 return 0;1353 }1354 1355 if (!pixel_format_is_valid(plane_state)) {1356 plane_state->no_fbc_reason = "pixel format not supported";1357 return 0;1358 }1359 1360 if (!tiling_is_valid(plane_state)) {1361 plane_state->no_fbc_reason = "tiling not supported";1362 return 0;1363 }1364 1365 if (!rotation_is_valid(plane_state)) {1366 plane_state->no_fbc_reason = "rotation not supported";1367 return 0;1368 }1369 1370 if (!stride_is_valid(plane_state)) {1371 plane_state->no_fbc_reason = "stride not supported";1372 return 0;1373 }1374 1375 if (DISPLAY_VER(display) < 20 &&1376 plane_state->hw.pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE &&1377 fb->format->has_alpha) {1378 plane_state->no_fbc_reason = "per-pixel alpha not supported";1379 return 0;1380 }1381 1382 if (!intel_fbc_plane_size_valid(plane_state)) {1383 plane_state->no_fbc_reason = "plane size too big";1384 return 0;1385 }1386 1387 if (!intel_fbc_surface_size_ok(plane_state)) {1388 plane_state->no_fbc_reason = "surface size too big";1389 return 0;1390 }1391 1392 /*1393 * Work around a problem on GEN9+ HW, where enabling FBC on a plane1394 * having a Y offset that isn't divisible by 4 causes FIFO underrun1395 * and screen flicker.1396 */1397 if (DISPLAY_VER(display) >= 9 &&1398 plane_state->view.color_plane[0].y & 3) {1399 plane_state->no_fbc_reason = "plane start Y offset misaligned";1400 return 0;1401 }1402 1403 /* Wa_22010751166: icl, ehl, tgl, dg1, rkl */1404 if (DISPLAY_VER(display) >= 11 &&1405 (plane_state->view.color_plane[0].y +1406 (drm_rect_height(&plane_state->uapi.src) >> 16)) & 3) {1407 plane_state->no_fbc_reason = "plane end Y offset misaligned";1408 return 0;1409 }1410 1411 /* WaFbcExceedCdClockThreshold:hsw,bdw */1412 if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {1413 const struct intel_cdclk_state *cdclk_state;1414 1415 cdclk_state = intel_atomic_get_cdclk_state(state);1416 if (IS_ERR(cdclk_state))1417 return PTR_ERR(cdclk_state);1418 1419 if (crtc_state->pixel_rate >= cdclk_state->logical.cdclk * 95 / 100) {1420 plane_state->no_fbc_reason = "pixel rate too high";1421 return 0;1422 }1423 }1424 1425 plane_state->no_fbc_reason = NULL;1426 1427 return 0;1428}1429 1430 1431static bool intel_fbc_can_flip_nuke(struct intel_atomic_state *state,1432 struct intel_crtc *crtc,1433 struct intel_plane *plane)1434{1435 const struct intel_crtc_state *new_crtc_state =1436 intel_atomic_get_new_crtc_state(state, crtc);1437 const struct intel_plane_state *old_plane_state =1438 intel_atomic_get_old_plane_state(state, plane);1439 const struct intel_plane_state *new_plane_state =1440 intel_atomic_get_new_plane_state(state, plane);1441 const struct drm_framebuffer *old_fb = old_plane_state->hw.fb;1442 const struct drm_framebuffer *new_fb = new_plane_state->hw.fb;1443 1444 if (intel_crtc_needs_modeset(new_crtc_state))1445 return false;1446 1447 if (!intel_fbc_is_ok(old_plane_state) ||1448 !intel_fbc_is_ok(new_plane_state))1449 return false;1450 1451 if (old_fb->format->format != new_fb->format->format)1452 return false;1453 1454 if (old_fb->modifier != new_fb->modifier)1455 return false;1456 1457 if (intel_fbc_plane_stride(old_plane_state) !=1458 intel_fbc_plane_stride(new_plane_state))1459 return false;1460 1461 if (intel_fbc_cfb_stride(old_plane_state) !=1462 intel_fbc_cfb_stride(new_plane_state))1463 return false;1464 1465 if (intel_fbc_cfb_size(old_plane_state) !=1466 intel_fbc_cfb_size(new_plane_state))1467 return false;1468 1469 if (intel_fbc_override_cfb_stride(old_plane_state) !=1470 intel_fbc_override_cfb_stride(new_plane_state))1471 return false;1472 1473 return true;1474}1475 1476static bool __intel_fbc_pre_update(struct intel_atomic_state *state,1477 struct intel_crtc *crtc,1478 struct intel_plane *plane)1479{1480 struct intel_display *display = to_intel_display(state->base.dev);1481 struct intel_fbc *fbc = plane->fbc;1482 bool need_vblank_wait = false;1483 1484 lockdep_assert_held(&fbc->lock);1485 1486 fbc->flip_pending = true;1487 1488 if (intel_fbc_can_flip_nuke(state, crtc, plane))1489 return need_vblank_wait;1490 1491 intel_fbc_deactivate(fbc, "update pending");1492 1493 /*1494 * Display WA #1198: glk+1495 * Need an extra vblank wait between FBC disable and most plane1496 * updates. Bspec says this is only needed for plane disable, but1497 * that is not true. Touching most plane registers will cause the1498 * corruption to appear. Also SKL/derivatives do not seem to be1499 * affected.1500 *1501 * TODO: could optimize this a bit by sampling the frame1502 * counter when we disable FBC (if it was already done earlier)1503 * and skipping the extra vblank wait before the plane update1504 * if at least one frame has already passed.1505 */1506 if (fbc->activated && DISPLAY_VER(display) >= 10)1507 need_vblank_wait = true;1508 fbc->activated = false;1509 1510 return need_vblank_wait;1511}1512 1513bool intel_fbc_pre_update(struct intel_atomic_state *state,1514 struct intel_crtc *crtc)1515{1516 const struct intel_plane_state __maybe_unused *plane_state;1517 bool need_vblank_wait = false;1518 struct intel_plane *plane;1519 int i;1520 1521 for_each_new_intel_plane_in_state(state, plane, plane_state, i) {1522 struct intel_fbc *fbc = plane->fbc;1523 1524 if (!fbc || plane->pipe != crtc->pipe)1525 continue;1526 1527 mutex_lock(&fbc->lock);1528 1529 if (fbc->state.plane == plane)1530 need_vblank_wait |= __intel_fbc_pre_update(state, crtc, plane);1531 1532 mutex_unlock(&fbc->lock);1533 }1534 1535 return need_vblank_wait;1536}1537 1538static void __intel_fbc_disable(struct intel_fbc *fbc)1539{1540 struct intel_display *display = fbc->display;1541 struct intel_plane *plane = fbc->state.plane;1542 1543 lockdep_assert_held(&fbc->lock);1544 drm_WARN_ON(display->drm, fbc->active);1545 1546 drm_dbg_kms(display->drm, "Disabling FBC on [PLANE:%d:%s]\n",1547 plane->base.base.id, plane->base.name);1548 1549 __intel_fbc_cleanup_cfb(fbc);1550 1551 fbc->state.plane = NULL;1552 fbc->flip_pending = false;1553 fbc->busy_bits = 0;1554}1555 1556static void __intel_fbc_post_update(struct intel_fbc *fbc)1557{1558 lockdep_assert_held(&fbc->lock);1559 1560 fbc->flip_pending = false;1561 fbc->busy_bits = 0;1562 1563 intel_fbc_activate(fbc);1564}1565 1566void intel_fbc_post_update(struct intel_atomic_state *state,1567 struct intel_crtc *crtc)1568{1569 const struct intel_plane_state __maybe_unused *plane_state;1570 struct intel_plane *plane;1571 int i;1572 1573 for_each_new_intel_plane_in_state(state, plane, plane_state, i) {1574 struct intel_fbc *fbc = plane->fbc;1575 1576 if (!fbc || plane->pipe != crtc->pipe)1577 continue;1578 1579 mutex_lock(&fbc->lock);1580 1581 if (fbc->state.plane == plane)1582 __intel_fbc_post_update(fbc);1583 1584 mutex_unlock(&fbc->lock);1585 }1586}1587 1588static unsigned int intel_fbc_get_frontbuffer_bit(struct intel_fbc *fbc)1589{1590 if (fbc->state.plane)1591 return fbc->state.plane->frontbuffer_bit;1592 else1593 return 0;1594}1595 1596static void __intel_fbc_invalidate(struct intel_fbc *fbc,1597 unsigned int frontbuffer_bits,1598 enum fb_op_origin origin)1599{1600 if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE)1601 return;1602 1603 mutex_lock(&fbc->lock);1604 1605 frontbuffer_bits &= intel_fbc_get_frontbuffer_bit(fbc);1606 if (!frontbuffer_bits)1607 goto out;1608 1609 fbc->busy_bits |= frontbuffer_bits;1610 intel_fbc_deactivate(fbc, "frontbuffer write");1611 1612out:1613 mutex_unlock(&fbc->lock);1614}1615 1616void intel_fbc_invalidate(struct drm_i915_private *i915,1617 unsigned int frontbuffer_bits,1618 enum fb_op_origin origin)1619{1620 struct intel_fbc *fbc;1621 enum intel_fbc_id fbc_id;1622 1623 for_each_intel_fbc(&i915->display, fbc, fbc_id)1624 __intel_fbc_invalidate(fbc, frontbuffer_bits, origin);1625 1626}1627 1628static void __intel_fbc_flush(struct intel_fbc *fbc,1629 unsigned int frontbuffer_bits,1630 enum fb_op_origin origin)1631{1632 mutex_lock(&fbc->lock);1633 1634 frontbuffer_bits &= intel_fbc_get_frontbuffer_bit(fbc);1635 if (!frontbuffer_bits)1636 goto out;1637 1638 fbc->busy_bits &= ~frontbuffer_bits;1639 1640 if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE)1641 goto out;1642 1643 if (fbc->busy_bits || fbc->flip_pending)1644 goto out;1645 1646 if (fbc->active)1647 intel_fbc_nuke(fbc);1648 else1649 intel_fbc_activate(fbc);1650 1651out:1652 mutex_unlock(&fbc->lock);1653}1654 1655void intel_fbc_flush(struct drm_i915_private *i915,1656 unsigned int frontbuffer_bits,1657 enum fb_op_origin origin)1658{1659 struct intel_fbc *fbc;1660 enum intel_fbc_id fbc_id;1661 1662 for_each_intel_fbc(&i915->display, fbc, fbc_id)1663 __intel_fbc_flush(fbc, frontbuffer_bits, origin);1664}1665 1666int intel_fbc_atomic_check(struct intel_atomic_state *state)1667{1668 struct intel_plane_state __maybe_unused *plane_state;1669 struct intel_plane *plane;1670 int i;1671 1672 for_each_new_intel_plane_in_state(state, plane, plane_state, i) {1673 int ret;1674 1675 ret = intel_fbc_check_plane(state, plane);1676 if (ret)1677 return ret;1678 }1679 1680 return 0;1681}1682 1683static void __intel_fbc_enable(struct intel_atomic_state *state,1684 struct intel_crtc *crtc,1685 struct intel_plane *plane)1686{1687 struct intel_display *display = to_intel_display(state->base.dev);1688 const struct intel_plane_state *plane_state =1689 intel_atomic_get_new_plane_state(state, plane);1690 struct intel_fbc *fbc = plane->fbc;1691 1692 lockdep_assert_held(&fbc->lock);1693 1694 if (fbc->state.plane) {1695 if (fbc->state.plane != plane)1696 return;1697 1698 if (intel_fbc_is_ok(plane_state)) {1699 intel_fbc_update_state(state, crtc, plane);1700 return;1701 }1702 1703 __intel_fbc_disable(fbc);1704 }1705 1706 drm_WARN_ON(display->drm, fbc->active);1707 1708 fbc->no_fbc_reason = plane_state->no_fbc_reason;1709 if (fbc->no_fbc_reason)1710 return;1711 1712 if (!intel_fbc_is_fence_ok(plane_state)) {1713 fbc->no_fbc_reason = "framebuffer not fenced";1714 return;1715 }1716 1717 if (fbc->underrun_detected) {1718 fbc->no_fbc_reason = "FIFO underrun";1719 return;1720 }1721 1722 if (intel_fbc_alloc_cfb(fbc, intel_fbc_cfb_size(plane_state),1723 intel_fbc_min_limit(plane_state))) {1724 fbc->no_fbc_reason = "not enough stolen memory";1725 return;1726 }1727 1728 drm_dbg_kms(display->drm, "Enabling FBC on [PLANE:%d:%s]\n",1729 plane->base.base.id, plane->base.name);1730 fbc->no_fbc_reason = "FBC enabled but not active yet\n";1731 1732 intel_fbc_update_state(state, crtc, plane);1733 1734 intel_fbc_program_workarounds(fbc);1735 intel_fbc_program_cfb(fbc);1736}1737 1738/**1739 * intel_fbc_disable - disable FBC if it's associated with crtc1740 * @crtc: the CRTC1741 *1742 * This function disables FBC if it's associated with the provided CRTC.1743 */1744void intel_fbc_disable(struct intel_crtc *crtc)1745{1746 struct intel_display *display = to_intel_display(crtc->base.dev);1747 struct intel_plane *plane;1748 1749 for_each_intel_plane(display->drm, plane) {1750 struct intel_fbc *fbc = plane->fbc;1751 1752 if (!fbc || plane->pipe != crtc->pipe)1753 continue;1754 1755 mutex_lock(&fbc->lock);1756 if (fbc->state.plane == plane)1757 __intel_fbc_disable(fbc);1758 mutex_unlock(&fbc->lock);1759 }1760}1761 1762void intel_fbc_update(struct intel_atomic_state *state,1763 struct intel_crtc *crtc)1764{1765 const struct intel_crtc_state *crtc_state =1766 intel_atomic_get_new_crtc_state(state, crtc);1767 const struct intel_plane_state *plane_state;1768 struct intel_plane *plane;1769 int i;1770 1771 for_each_new_intel_plane_in_state(state, plane, plane_state, i) {1772 struct intel_fbc *fbc = plane->fbc;1773 1774 if (!fbc || plane->pipe != crtc->pipe)1775 continue;1776 1777 mutex_lock(&fbc->lock);1778 1779 if (intel_crtc_needs_fastset(crtc_state) &&1780 plane_state->no_fbc_reason) {1781 if (fbc->state.plane == plane)1782 __intel_fbc_disable(fbc);1783 } else {1784 __intel_fbc_enable(state, crtc, plane);1785 }1786 1787 mutex_unlock(&fbc->lock);1788 }1789}1790 1791static void intel_fbc_underrun_work_fn(struct work_struct *work)1792{1793 struct intel_fbc *fbc = container_of(work, typeof(*fbc), underrun_work);1794 struct intel_display *display = fbc->display;1795 struct drm_i915_private *i915 = to_i915(display->drm);1796 1797 mutex_lock(&fbc->lock);1798 1799 /* Maybe we were scheduled twice. */1800 if (fbc->underrun_detected || !fbc->state.plane)1801 goto out;1802 1803 drm_dbg_kms(display->drm, "Disabling FBC due to FIFO underrun.\n");1804 fbc->underrun_detected = true;1805 1806 intel_fbc_deactivate(fbc, "FIFO underrun");1807 if (!fbc->flip_pending)1808 intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(i915, fbc->state.plane->pipe));1809 __intel_fbc_disable(fbc);1810out:1811 mutex_unlock(&fbc->lock);1812}1813 1814static void __intel_fbc_reset_underrun(struct intel_fbc *fbc)1815{1816 struct intel_display *display = fbc->display;1817 1818 cancel_work_sync(&fbc->underrun_work);1819 1820 mutex_lock(&fbc->lock);1821 1822 if (fbc->underrun_detected) {1823 drm_dbg_kms(display->drm,1824 "Re-allowing FBC after fifo underrun\n");1825 fbc->no_fbc_reason = "FIFO underrun cleared";1826 }1827 1828 fbc->underrun_detected = false;1829 mutex_unlock(&fbc->lock);1830}1831 1832/*1833 * intel_fbc_reset_underrun - reset FBC fifo underrun status.1834 * @display: display1835 *1836 * See intel_fbc_handle_fifo_underrun_irq(). For automated testing we1837 * want to re-enable FBC after an underrun to increase test coverage.1838 */1839void intel_fbc_reset_underrun(struct intel_display *display)1840{1841 struct intel_fbc *fbc;1842 enum intel_fbc_id fbc_id;1843 1844 for_each_intel_fbc(display, fbc, fbc_id)1845 __intel_fbc_reset_underrun(fbc);1846}1847 1848static void __intel_fbc_handle_fifo_underrun_irq(struct intel_fbc *fbc)1849{1850 struct drm_i915_private *i915 = to_i915(fbc->display->drm);1851 1852 /*1853 * There's no guarantee that underrun_detected won't be set to true1854 * right after this check and before the work is scheduled, but that's1855 * not a problem since we'll check it again under the work function1856 * while FBC is locked. This check here is just to prevent us from1857 * unnecessarily scheduling the work, and it relies on the fact that we1858 * never switch underrun_detect back to false after it's true.1859 */1860 if (READ_ONCE(fbc->underrun_detected))1861 return;1862 1863 queue_work(i915->unordered_wq, &fbc->underrun_work);1864}1865 1866/**1867 * intel_fbc_handle_fifo_underrun_irq - disable FBC when we get a FIFO underrun1868 * @display: display1869 *1870 * Without FBC, most underruns are harmless and don't really cause too many1871 * problems, except for an annoying message on dmesg. With FBC, underruns can1872 * become black screens or even worse, especially when paired with bad1873 * watermarks. So in order for us to be on the safe side, completely disable FBC1874 * in case we ever detect a FIFO underrun on any pipe. An underrun on any pipe1875 * already suggests that watermarks may be bad, so try to be as safe as1876 * possible.1877 *1878 * This function is called from the IRQ handler.1879 */1880void intel_fbc_handle_fifo_underrun_irq(struct intel_display *display)1881{1882 struct intel_fbc *fbc;1883 enum intel_fbc_id fbc_id;1884 1885 for_each_intel_fbc(display, fbc, fbc_id)1886 __intel_fbc_handle_fifo_underrun_irq(fbc);1887}1888 1889/*1890 * The DDX driver changes its behavior depending on the value it reads from1891 * i915.enable_fbc, so sanitize it by translating the default value into either1892 * 0 or 1 in order to allow it to know what's going on.1893 *1894 * Notice that this is done at driver initialization and we still allow user1895 * space to change the value during runtime without sanitizing it again. IGT1896 * relies on being able to change i915.enable_fbc at runtime.1897 */1898static int intel_sanitize_fbc_option(struct intel_display *display)1899{1900 struct drm_i915_private *i915 = to_i915(display->drm);1901 1902 if (display->params.enable_fbc >= 0)1903 return !!display->params.enable_fbc;1904 1905 if (!HAS_FBC(display))1906 return 0;1907 1908 if (IS_BROADWELL(i915) || DISPLAY_VER(display) >= 9)1909 return 1;1910 1911 return 0;1912}1913 1914void intel_fbc_add_plane(struct intel_fbc *fbc, struct intel_plane *plane)1915{1916 plane->fbc = fbc;1917}1918 1919static struct intel_fbc *intel_fbc_create(struct intel_display *display,1920 enum intel_fbc_id fbc_id)1921{1922 struct drm_i915_private *i915 = to_i915(display->drm);1923 struct intel_fbc *fbc;1924 1925 fbc = kzalloc(sizeof(*fbc), GFP_KERNEL);1926 if (!fbc)1927 return NULL;1928 1929 fbc->id = fbc_id;1930 fbc->display = display;1931 INIT_WORK(&fbc->underrun_work, intel_fbc_underrun_work_fn);1932 mutex_init(&fbc->lock);1933 1934 if (DISPLAY_VER(display) >= 7)1935 fbc->funcs = &ivb_fbc_funcs;1936 else if (DISPLAY_VER(display) == 6)1937 fbc->funcs = &snb_fbc_funcs;1938 else if (DISPLAY_VER(display) == 5)1939 fbc->funcs = &ilk_fbc_funcs;1940 else if (IS_G4X(i915))1941 fbc->funcs = &g4x_fbc_funcs;1942 else if (DISPLAY_VER(display) == 4)1943 fbc->funcs = &i965_fbc_funcs;1944 else1945 fbc->funcs = &i8xx_fbc_funcs;1946 1947 return fbc;1948}1949 1950/**1951 * intel_fbc_init - Initialize FBC1952 * @display: display1953 *1954 * This function might be called during PM init process.1955 */1956void intel_fbc_init(struct intel_display *display)1957{1958 enum intel_fbc_id fbc_id;1959 1960 display->params.enable_fbc = intel_sanitize_fbc_option(display);1961 drm_dbg_kms(display->drm, "Sanitized enable_fbc value: %d\n",1962 display->params.enable_fbc);1963 1964 for_each_fbc_id(display, fbc_id)1965 display->fbc[fbc_id] = intel_fbc_create(display, fbc_id);1966}1967 1968/**1969 * intel_fbc_sanitize - Sanitize FBC1970 * @display: display1971 *1972 * Make sure FBC is initially disabled since we have no1973 * idea eg. into which parts of stolen it might be scribbling1974 * into.1975 */1976void intel_fbc_sanitize(struct intel_display *display)1977{1978 struct intel_fbc *fbc;1979 enum intel_fbc_id fbc_id;1980 1981 for_each_intel_fbc(display, fbc, fbc_id) {1982 if (intel_fbc_hw_is_active(fbc))1983 intel_fbc_hw_deactivate(fbc);1984 }1985}1986 1987static int intel_fbc_debugfs_status_show(struct seq_file *m, void *unused)1988{1989 struct intel_fbc *fbc = m->private;1990 struct intel_display *display = fbc->display;1991 struct drm_i915_private *i915 = to_i915(display->drm);1992 struct intel_plane *plane;1993 intel_wakeref_t wakeref;1994 1995 drm_modeset_lock_all(display->drm);1996 1997 wakeref = intel_runtime_pm_get(&i915->runtime_pm);1998 mutex_lock(&fbc->lock);1999 2000 if (fbc->active) {2001 seq_puts(m, "FBC enabled\n");2002 seq_printf(m, "Compressing: %s\n",2003 str_yes_no(intel_fbc_is_compressing(fbc)));2004 } else {2005 seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason);2006 }2007 2008 for_each_intel_plane(display->drm, plane) {2009 const struct intel_plane_state *plane_state =2010 to_intel_plane_state(plane->base.state);2011 2012 if (plane->fbc != fbc)2013 continue;2014 2015 seq_printf(m, "%c [PLANE:%d:%s]: %s\n",2016 fbc->state.plane == plane ? '*' : ' ',2017 plane->base.base.id, plane->base.name,2018 plane_state->no_fbc_reason ?: "FBC possible");2019 }2020 2021 mutex_unlock(&fbc->lock);2022 intel_runtime_pm_put(&i915->runtime_pm, wakeref);2023 2024 drm_modeset_unlock_all(display->drm);2025 2026 return 0;2027}2028 2029DEFINE_SHOW_ATTRIBUTE(intel_fbc_debugfs_status);2030 2031static int intel_fbc_debugfs_false_color_get(void *data, u64 *val)2032{2033 struct intel_fbc *fbc = data;2034 2035 *val = fbc->false_color;2036 2037 return 0;2038}2039 2040static int intel_fbc_debugfs_false_color_set(void *data, u64 val)2041{2042 struct intel_fbc *fbc = data;2043 2044 mutex_lock(&fbc->lock);2045 2046 fbc->false_color = val;2047 2048 if (fbc->active)2049 fbc->funcs->set_false_color(fbc, fbc->false_color);2050 2051 mutex_unlock(&fbc->lock);2052 2053 return 0;2054}2055 2056DEFINE_DEBUGFS_ATTRIBUTE(intel_fbc_debugfs_false_color_fops,2057 intel_fbc_debugfs_false_color_get,2058 intel_fbc_debugfs_false_color_set,2059 "%llu\n");2060 2061static void intel_fbc_debugfs_add(struct intel_fbc *fbc,2062 struct dentry *parent)2063{2064 debugfs_create_file("i915_fbc_status", 0444, parent,2065 fbc, &intel_fbc_debugfs_status_fops);2066 2067 if (fbc->funcs->set_false_color)2068 debugfs_create_file_unsafe("i915_fbc_false_color", 0644, parent,2069 fbc, &intel_fbc_debugfs_false_color_fops);2070}2071 2072void intel_fbc_crtc_debugfs_add(struct intel_crtc *crtc)2073{2074 struct intel_plane *plane = to_intel_plane(crtc->base.primary);2075 2076 if (plane->fbc)2077 intel_fbc_debugfs_add(plane->fbc, crtc->base.debugfs_entry);2078}2079 2080/* FIXME: remove this once igt is on board with per-crtc stuff */2081void intel_fbc_debugfs_register(struct intel_display *display)2082{2083 struct drm_minor *minor = display->drm->primary;2084 struct intel_fbc *fbc;2085 2086 fbc = display->fbc[INTEL_FBC_A];2087 if (fbc)2088 intel_fbc_debugfs_add(fbc, minor->debugfs_root);2089}2090