1174 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2020 Intel Corporation4 */5#include <linux/kernel.h>6 7#include <drm/drm_atomic_helper.h>8#include <drm/drm_blend.h>9#include <drm/drm_fourcc.h>10 11#include "i915_reg.h"12#include "i9xx_plane.h"13#include "i9xx_plane_regs.h"14#include "intel_atomic.h"15#include "intel_atomic_plane.h"16#include "intel_de.h"17#include "intel_display_irq.h"18#include "intel_display_types.h"19#include "intel_fb.h"20#include "intel_fbc.h"21#include "intel_frontbuffer.h"22#include "intel_sprite.h"23 24/* Primary plane formats for gen <= 3 */25static const u32 i8xx_primary_formats[] = {26 DRM_FORMAT_C8,27 DRM_FORMAT_XRGB1555,28 DRM_FORMAT_RGB565,29 DRM_FORMAT_XRGB8888,30};31 32/* Primary plane formats for ivb (no fp16 due to hw issue) */33static const u32 ivb_primary_formats[] = {34 DRM_FORMAT_C8,35 DRM_FORMAT_RGB565,36 DRM_FORMAT_XRGB8888,37 DRM_FORMAT_XBGR8888,38 DRM_FORMAT_XRGB2101010,39 DRM_FORMAT_XBGR2101010,40};41 42/* Primary plane formats for gen >= 4, except ivb */43static const u32 i965_primary_formats[] = {44 DRM_FORMAT_C8,45 DRM_FORMAT_RGB565,46 DRM_FORMAT_XRGB8888,47 DRM_FORMAT_XBGR8888,48 DRM_FORMAT_XRGB2101010,49 DRM_FORMAT_XBGR2101010,50 DRM_FORMAT_XBGR16161616F,51};52 53/* Primary plane formats for vlv/chv */54static const u32 vlv_primary_formats[] = {55 DRM_FORMAT_C8,56 DRM_FORMAT_RGB565,57 DRM_FORMAT_XRGB8888,58 DRM_FORMAT_XBGR8888,59 DRM_FORMAT_ARGB8888,60 DRM_FORMAT_ABGR8888,61 DRM_FORMAT_XRGB2101010,62 DRM_FORMAT_XBGR2101010,63 DRM_FORMAT_ARGB2101010,64 DRM_FORMAT_ABGR2101010,65 DRM_FORMAT_XBGR16161616F,66};67 68static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane,69 u32 format, u64 modifier)70{71 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))72 return false;73 74 switch (format) {75 case DRM_FORMAT_C8:76 case DRM_FORMAT_RGB565:77 case DRM_FORMAT_XRGB1555:78 case DRM_FORMAT_XRGB8888:79 return modifier == DRM_FORMAT_MOD_LINEAR ||80 modifier == I915_FORMAT_MOD_X_TILED;81 default:82 return false;83 }84}85 86static bool i965_plane_format_mod_supported(struct drm_plane *_plane,87 u32 format, u64 modifier)88{89 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))90 return false;91 92 switch (format) {93 case DRM_FORMAT_C8:94 case DRM_FORMAT_RGB565:95 case DRM_FORMAT_XRGB8888:96 case DRM_FORMAT_XBGR8888:97 case DRM_FORMAT_ARGB8888:98 case DRM_FORMAT_ABGR8888:99 case DRM_FORMAT_XRGB2101010:100 case DRM_FORMAT_XBGR2101010:101 case DRM_FORMAT_ARGB2101010:102 case DRM_FORMAT_ABGR2101010:103 case DRM_FORMAT_XBGR16161616F:104 return modifier == DRM_FORMAT_MOD_LINEAR ||105 modifier == I915_FORMAT_MOD_X_TILED;106 default:107 return false;108 }109}110 111static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,112 enum i9xx_plane_id i9xx_plane)113{114 if (!HAS_FBC(dev_priv))115 return false;116 117 if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))118 return i9xx_plane == PLANE_A; /* tied to pipe A */119 else if (IS_IVYBRIDGE(dev_priv))120 return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||121 i9xx_plane == PLANE_C;122 else if (DISPLAY_VER(dev_priv) >= 4)123 return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;124 else125 return i9xx_plane == PLANE_A;126}127 128static struct intel_fbc *i9xx_plane_fbc(struct drm_i915_private *dev_priv,129 enum i9xx_plane_id i9xx_plane)130{131 if (i9xx_plane_has_fbc(dev_priv, i9xx_plane))132 return dev_priv->display.fbc[INTEL_FBC_A];133 else134 return NULL;135}136 137static bool i9xx_plane_has_windowing(struct intel_plane *plane)138{139 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);140 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;141 142 if (IS_CHERRYVIEW(dev_priv))143 return i9xx_plane == PLANE_B;144 else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))145 return false;146 else if (DISPLAY_VER(dev_priv) == 4)147 return i9xx_plane == PLANE_C;148 else149 return i9xx_plane == PLANE_B ||150 i9xx_plane == PLANE_C;151}152 153static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,154 const struct intel_plane_state *plane_state)155{156 struct drm_i915_private *dev_priv =157 to_i915(plane_state->uapi.plane->dev);158 const struct drm_framebuffer *fb = plane_state->hw.fb;159 unsigned int rotation = plane_state->hw.rotation;160 u32 dspcntr;161 162 dspcntr = DISP_ENABLE;163 164 if (IS_G4X(dev_priv) || IS_IRONLAKE(dev_priv) ||165 IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv))166 dspcntr |= DISP_TRICKLE_FEED_DISABLE;167 168 switch (fb->format->format) {169 case DRM_FORMAT_C8:170 dspcntr |= DISP_FORMAT_8BPP;171 break;172 case DRM_FORMAT_XRGB1555:173 dspcntr |= DISP_FORMAT_BGRX555;174 break;175 case DRM_FORMAT_ARGB1555:176 dspcntr |= DISP_FORMAT_BGRA555;177 break;178 case DRM_FORMAT_RGB565:179 dspcntr |= DISP_FORMAT_BGRX565;180 break;181 case DRM_FORMAT_XRGB8888:182 dspcntr |= DISP_FORMAT_BGRX888;183 break;184 case DRM_FORMAT_XBGR8888:185 dspcntr |= DISP_FORMAT_RGBX888;186 break;187 case DRM_FORMAT_ARGB8888:188 dspcntr |= DISP_FORMAT_BGRA888;189 break;190 case DRM_FORMAT_ABGR8888:191 dspcntr |= DISP_FORMAT_RGBA888;192 break;193 case DRM_FORMAT_XRGB2101010:194 dspcntr |= DISP_FORMAT_BGRX101010;195 break;196 case DRM_FORMAT_XBGR2101010:197 dspcntr |= DISP_FORMAT_RGBX101010;198 break;199 case DRM_FORMAT_ARGB2101010:200 dspcntr |= DISP_FORMAT_BGRA101010;201 break;202 case DRM_FORMAT_ABGR2101010:203 dspcntr |= DISP_FORMAT_RGBA101010;204 break;205 case DRM_FORMAT_XBGR16161616F:206 dspcntr |= DISP_FORMAT_RGBX161616;207 break;208 default:209 MISSING_CASE(fb->format->format);210 return 0;211 }212 213 if (DISPLAY_VER(dev_priv) >= 4 &&214 fb->modifier == I915_FORMAT_MOD_X_TILED)215 dspcntr |= DISP_TILED;216 217 if (rotation & DRM_MODE_ROTATE_180)218 dspcntr |= DISP_ROTATE_180;219 220 if (rotation & DRM_MODE_REFLECT_X)221 dspcntr |= DISP_MIRROR;222 223 return dspcntr;224}225 226int i9xx_check_plane_surface(struct intel_plane_state *plane_state)227{228 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);229 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);230 const struct drm_framebuffer *fb = plane_state->hw.fb;231 int src_x, src_y, src_w;232 u32 offset;233 int ret;234 235 ret = intel_plane_compute_gtt(plane_state);236 if (ret)237 return ret;238 239 if (!plane_state->uapi.visible)240 return 0;241 242 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;243 src_x = plane_state->uapi.src.x1 >> 16;244 src_y = plane_state->uapi.src.y1 >> 16;245 246 /* Undocumented hardware limit on i965/g4x/vlv/chv */247 if (HAS_GMCH(dev_priv) && fb->format->cpp[0] == 8 && src_w > 2048)248 return -EINVAL;249 250 intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);251 252 if (DISPLAY_VER(dev_priv) >= 4)253 offset = intel_plane_compute_aligned_offset(&src_x, &src_y,254 plane_state, 0);255 else256 offset = 0;257 258 /*259 * When using an X-tiled surface the plane starts to260 * misbehave if the x offset + width exceeds the stride.261 * hsw/bdw: underrun galore262 * ilk/snb/ivb: wrap to the next tile row mid scanout263 * i965/g4x: so far appear immune to this264 * vlv/chv: TODO check265 *266 * Linear surfaces seem to work just fine, even on hsw/bdw267 * despite them not using the linear offset anymore.268 */269 if (DISPLAY_VER(dev_priv) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) {270 unsigned int alignment = plane->min_alignment(plane, fb, 0);271 int cpp = fb->format->cpp[0];272 273 while ((src_x + src_w) * cpp > plane_state->view.color_plane[0].mapping_stride) {274 if (offset == 0) {275 drm_dbg_kms(&dev_priv->drm,276 "Unable to find suitable display surface offset due to X-tiling\n");277 return -EINVAL;278 }279 280 offset = intel_plane_adjust_aligned_offset(&src_x, &src_y, plane_state, 0,281 offset, offset - alignment);282 }283 }284 285 /*286 * Put the final coordinates back so that the src287 * coordinate checks will see the right values.288 */289 drm_rect_translate_to(&plane_state->uapi.src,290 src_x << 16, src_y << 16);291 292 /* HSW/BDW do this automagically in hardware */293 if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {294 unsigned int rotation = plane_state->hw.rotation;295 int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;296 int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;297 298 if (rotation & DRM_MODE_ROTATE_180) {299 src_x += src_w - 1;300 src_y += src_h - 1;301 } else if (rotation & DRM_MODE_REFLECT_X) {302 src_x += src_w - 1;303 }304 }305 306 if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {307 drm_WARN_ON(&dev_priv->drm, src_x > 8191 || src_y > 4095);308 } else if (DISPLAY_VER(dev_priv) >= 4 &&309 fb->modifier == I915_FORMAT_MOD_X_TILED) {310 drm_WARN_ON(&dev_priv->drm, src_x > 4095 || src_y > 4095);311 }312 313 plane_state->view.color_plane[0].offset = offset;314 plane_state->view.color_plane[0].x = src_x;315 plane_state->view.color_plane[0].y = src_y;316 317 return 0;318}319 320static int321i9xx_plane_check(struct intel_crtc_state *crtc_state,322 struct intel_plane_state *plane_state)323{324 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);325 int ret;326 327 ret = chv_plane_check_rotation(plane_state);328 if (ret)329 return ret;330 331 ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,332 DRM_PLANE_NO_SCALING,333 DRM_PLANE_NO_SCALING,334 i9xx_plane_has_windowing(plane));335 if (ret)336 return ret;337 338 ret = i9xx_check_plane_surface(plane_state);339 if (ret)340 return ret;341 342 if (!plane_state->uapi.visible)343 return 0;344 345 ret = intel_plane_check_src_coordinates(plane_state);346 if (ret)347 return ret;348 349 plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);350 351 return 0;352}353 354static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)355{356 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);357 struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);358 u32 dspcntr = 0;359 360 if (crtc_state->gamma_enable)361 dspcntr |= DISP_PIPE_GAMMA_ENABLE;362 363 if (crtc_state->csc_enable)364 dspcntr |= DISP_PIPE_CSC_ENABLE;365 366 if (DISPLAY_VER(dev_priv) < 5)367 dspcntr |= DISP_PIPE_SEL(crtc->pipe);368 369 return dspcntr;370}371 372static void i9xx_plane_ratio(const struct intel_crtc_state *crtc_state,373 const struct intel_plane_state *plane_state,374 unsigned int *num, unsigned int *den)375{376 const struct drm_framebuffer *fb = plane_state->hw.fb;377 unsigned int cpp = fb->format->cpp[0];378 379 /*380 * g4x bspec says 64bpp pixel rate can't exceed 80%381 * of cdclk when the sprite plane is enabled on the382 * same pipe. ilk/snb bspec says 64bpp pixel rate is383 * never allowed to exceed 80% of cdclk. Let's just go384 * with the ilk/snb limit always.385 */386 if (cpp == 8) {387 *num = 10;388 *den = 8;389 } else {390 *num = 1;391 *den = 1;392 }393}394 395static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state,396 const struct intel_plane_state *plane_state)397{398 unsigned int pixel_rate;399 unsigned int num, den;400 401 /*402 * Note that crtc_state->pixel_rate accounts for both403 * horizontal and vertical panel fitter downscaling factors.404 * Pre-HSW bspec tells us to only consider the horizontal405 * downscaling factor here. We ignore that and just consider406 * both for simplicity.407 */408 pixel_rate = crtc_state->pixel_rate;409 410 i9xx_plane_ratio(crtc_state, plane_state, &num, &den);411 412 /* two pixels per clock with double wide pipe */413 if (crtc_state->double_wide)414 den *= 2;415 416 return DIV_ROUND_UP(pixel_rate * num, den);417}418 419static void i9xx_plane_update_noarm(struct intel_plane *plane,420 const struct intel_crtc_state *crtc_state,421 const struct intel_plane_state *plane_state)422{423 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);424 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;425 426 intel_de_write_fw(dev_priv, DSPSTRIDE(dev_priv, i9xx_plane),427 plane_state->view.color_plane[0].mapping_stride);428 429 if (DISPLAY_VER(dev_priv) < 4) {430 int crtc_x = plane_state->uapi.dst.x1;431 int crtc_y = plane_state->uapi.dst.y1;432 int crtc_w = drm_rect_width(&plane_state->uapi.dst);433 int crtc_h = drm_rect_height(&plane_state->uapi.dst);434 435 /*436 * PLANE_A doesn't actually have a full window437 * generator but let's assume we still need to438 * program whatever is there.439 */440 intel_de_write_fw(dev_priv, DSPPOS(dev_priv, i9xx_plane),441 DISP_POS_Y(crtc_y) | DISP_POS_X(crtc_x));442 intel_de_write_fw(dev_priv, DSPSIZE(dev_priv, i9xx_plane),443 DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1));444 }445}446 447static void i9xx_plane_update_arm(struct intel_plane *plane,448 const struct intel_crtc_state *crtc_state,449 const struct intel_plane_state *plane_state)450{451 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);452 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;453 int x = plane_state->view.color_plane[0].x;454 int y = plane_state->view.color_plane[0].y;455 u32 dspcntr, dspaddr_offset, linear_offset;456 457 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);458 459 /* see intel_plane_atomic_calc_changes() */460 if (plane->need_async_flip_toggle_wa &&461 crtc_state->async_flip_planes & BIT(plane->id))462 dspcntr |= DISP_ASYNC_FLIP;463 464 linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);465 466 if (DISPLAY_VER(dev_priv) >= 4)467 dspaddr_offset = plane_state->view.color_plane[0].offset;468 else469 dspaddr_offset = linear_offset;470 471 if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {472 int crtc_x = plane_state->uapi.dst.x1;473 int crtc_y = plane_state->uapi.dst.y1;474 int crtc_w = drm_rect_width(&plane_state->uapi.dst);475 int crtc_h = drm_rect_height(&plane_state->uapi.dst);476 477 intel_de_write_fw(dev_priv, PRIMPOS(dev_priv, i9xx_plane),478 PRIM_POS_Y(crtc_y) | PRIM_POS_X(crtc_x));479 intel_de_write_fw(dev_priv, PRIMSIZE(dev_priv, i9xx_plane),480 PRIM_HEIGHT(crtc_h - 1) | PRIM_WIDTH(crtc_w - 1));481 intel_de_write_fw(dev_priv,482 PRIMCNSTALPHA(dev_priv, i9xx_plane), 0);483 }484 485 if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {486 intel_de_write_fw(dev_priv, DSPOFFSET(dev_priv, i9xx_plane),487 DISP_OFFSET_Y(y) | DISP_OFFSET_X(x));488 } else if (DISPLAY_VER(dev_priv) >= 4) {489 intel_de_write_fw(dev_priv, DSPLINOFF(dev_priv, i9xx_plane),490 linear_offset);491 intel_de_write_fw(dev_priv, DSPTILEOFF(dev_priv, i9xx_plane),492 DISP_OFFSET_Y(y) | DISP_OFFSET_X(x));493 }494 495 /*496 * The control register self-arms if the plane was previously497 * disabled. Try to make the plane enable atomic by writing498 * the control register just before the surface register.499 */500 intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr);501 502 if (DISPLAY_VER(dev_priv) >= 4)503 intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane),504 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);505 else506 intel_de_write_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane),507 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);508}509 510static void i830_plane_update_arm(struct intel_plane *plane,511 const struct intel_crtc_state *crtc_state,512 const struct intel_plane_state *plane_state)513{514 /*515 * On i830/i845 all registers are self-arming [ALM040].516 *517 * Additional breakage on i830 causes register reads to return518 * the last latched value instead of the last written value [ALM026].519 */520 i9xx_plane_update_noarm(plane, crtc_state, plane_state);521 i9xx_plane_update_arm(plane, crtc_state, plane_state);522}523 524static void i9xx_plane_disable_arm(struct intel_plane *plane,525 const struct intel_crtc_state *crtc_state)526{527 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);528 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;529 u32 dspcntr;530 531 /*532 * DSPCNTR pipe gamma enable on g4x+ and pipe csc533 * enable on ilk+ affect the pipe bottom color as534 * well, so we must configure them even if the plane535 * is disabled.536 *537 * On pre-g4x there is no way to gamma correct the538 * pipe bottom color but we'll keep on doing this539 * anyway so that the crtc state readout works correctly.540 */541 dspcntr = i9xx_plane_ctl_crtc(crtc_state);542 543 intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr);544 545 if (DISPLAY_VER(dev_priv) >= 4)546 intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane), 0);547 else548 intel_de_write_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane), 0);549}550 551static void552g4x_primary_async_flip(struct intel_plane *plane,553 const struct intel_crtc_state *crtc_state,554 const struct intel_plane_state *plane_state,555 bool async_flip)556{557 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);558 u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);559 u32 dspaddr_offset = plane_state->view.color_plane[0].offset;560 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;561 562 if (async_flip)563 dspcntr |= DISP_ASYNC_FLIP;564 565 intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr);566 567 intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane),568 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);569}570 571static void572vlv_primary_async_flip(struct intel_plane *plane,573 const struct intel_crtc_state *crtc_state,574 const struct intel_plane_state *plane_state,575 bool async_flip)576{577 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);578 u32 dspaddr_offset = plane_state->view.color_plane[0].offset;579 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;580 581 intel_de_write_fw(dev_priv, DSPADDR_VLV(dev_priv, i9xx_plane),582 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);583}584 585static void586bdw_primary_enable_flip_done(struct intel_plane *plane)587{588 struct drm_i915_private *i915 = to_i915(plane->base.dev);589 enum pipe pipe = plane->pipe;590 591 spin_lock_irq(&i915->irq_lock);592 bdw_enable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);593 spin_unlock_irq(&i915->irq_lock);594}595 596static void597bdw_primary_disable_flip_done(struct intel_plane *plane)598{599 struct drm_i915_private *i915 = to_i915(plane->base.dev);600 enum pipe pipe = plane->pipe;601 602 spin_lock_irq(&i915->irq_lock);603 bdw_disable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);604 spin_unlock_irq(&i915->irq_lock);605}606 607static void608ivb_primary_enable_flip_done(struct intel_plane *plane)609{610 struct drm_i915_private *i915 = to_i915(plane->base.dev);611 612 spin_lock_irq(&i915->irq_lock);613 ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane));614 spin_unlock_irq(&i915->irq_lock);615}616 617static void618ivb_primary_disable_flip_done(struct intel_plane *plane)619{620 struct drm_i915_private *i915 = to_i915(plane->base.dev);621 622 spin_lock_irq(&i915->irq_lock);623 ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane));624 spin_unlock_irq(&i915->irq_lock);625}626 627static void628ilk_primary_enable_flip_done(struct intel_plane *plane)629{630 struct drm_i915_private *i915 = to_i915(plane->base.dev);631 632 spin_lock_irq(&i915->irq_lock);633 ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane));634 spin_unlock_irq(&i915->irq_lock);635}636 637static void638ilk_primary_disable_flip_done(struct intel_plane *plane)639{640 struct drm_i915_private *i915 = to_i915(plane->base.dev);641 642 spin_lock_irq(&i915->irq_lock);643 ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane));644 spin_unlock_irq(&i915->irq_lock);645}646 647static void648vlv_primary_enable_flip_done(struct intel_plane *plane)649{650 struct drm_i915_private *i915 = to_i915(plane->base.dev);651 enum pipe pipe = plane->pipe;652 653 spin_lock_irq(&i915->irq_lock);654 i915_enable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV);655 spin_unlock_irq(&i915->irq_lock);656}657 658static void659vlv_primary_disable_flip_done(struct intel_plane *plane)660{661 struct drm_i915_private *i915 = to_i915(plane->base.dev);662 enum pipe pipe = plane->pipe;663 664 spin_lock_irq(&i915->irq_lock);665 i915_disable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV);666 spin_unlock_irq(&i915->irq_lock);667}668 669static bool i9xx_plane_get_hw_state(struct intel_plane *plane,670 enum pipe *pipe)671{672 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);673 enum intel_display_power_domain power_domain;674 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;675 intel_wakeref_t wakeref;676 bool ret;677 u32 val;678 679 /*680 * Not 100% correct for planes that can move between pipes,681 * but that's only the case for gen2-4 which don't have any682 * display power wells.683 */684 power_domain = POWER_DOMAIN_PIPE(plane->pipe);685 wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);686 if (!wakeref)687 return false;688 689 val = intel_de_read(dev_priv, DSPCNTR(dev_priv, i9xx_plane));690 691 ret = val & DISP_ENABLE;692 693 if (DISPLAY_VER(dev_priv) >= 5)694 *pipe = plane->pipe;695 else696 *pipe = REG_FIELD_GET(DISP_PIPE_SEL_MASK, val);697 698 intel_display_power_put(dev_priv, power_domain, wakeref);699 700 return ret;701}702 703static unsigned int704hsw_primary_max_stride(struct intel_plane *plane,705 u32 pixel_format, u64 modifier,706 unsigned int rotation)707{708 const struct drm_format_info *info = drm_format_info(pixel_format);709 int cpp = info->cpp[0];710 711 /* Limit to 8k pixels to guarantee OFFSET.x doesn't get too big. */712 return min(8192 * cpp, 32 * 1024);713}714 715static unsigned int716ilk_primary_max_stride(struct intel_plane *plane,717 u32 pixel_format, u64 modifier,718 unsigned int rotation)719{720 const struct drm_format_info *info = drm_format_info(pixel_format);721 int cpp = info->cpp[0];722 723 /* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */724 if (modifier == I915_FORMAT_MOD_X_TILED)725 return min(4096 * cpp, 32 * 1024);726 else727 return 32 * 1024;728}729 730unsigned int731i965_plane_max_stride(struct intel_plane *plane,732 u32 pixel_format, u64 modifier,733 unsigned int rotation)734{735 const struct drm_format_info *info = drm_format_info(pixel_format);736 int cpp = info->cpp[0];737 738 /* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */739 if (modifier == I915_FORMAT_MOD_X_TILED)740 return min(4096 * cpp, 16 * 1024);741 else742 return 32 * 1024;743}744 745static unsigned int746i915_plane_max_stride(struct intel_plane *plane,747 u32 pixel_format, u64 modifier,748 unsigned int rotation)749{750 if (modifier == I915_FORMAT_MOD_X_TILED)751 return 8 * 1024;752 else753 return 16 * 1024;754}755 756static unsigned int757i8xx_plane_max_stride(struct intel_plane *plane,758 u32 pixel_format, u64 modifier,759 unsigned int rotation)760{761 if (plane->i9xx_plane == PLANE_C)762 return 4 * 1024;763 else764 return 8 * 1024;765}766 767static unsigned int vlv_primary_min_alignment(struct intel_plane *plane,768 const struct drm_framebuffer *fb,769 int color_plane)770{771 struct drm_i915_private *i915 = to_i915(plane->base.dev);772 773 switch (fb->modifier) {774 case I915_FORMAT_MOD_X_TILED:775 if (HAS_ASYNC_FLIPS(i915))776 return 256 * 1024;777 return 4 * 1024;778 case DRM_FORMAT_MOD_LINEAR:779 return 128 * 1024;780 default:781 MISSING_CASE(fb->modifier);782 return 0;783 }784}785 786static unsigned int g4x_primary_min_alignment(struct intel_plane *plane,787 const struct drm_framebuffer *fb,788 int color_plane)789{790 struct drm_i915_private *i915 = to_i915(plane->base.dev);791 792 switch (fb->modifier) {793 case I915_FORMAT_MOD_X_TILED:794 if (HAS_ASYNC_FLIPS(i915))795 return 256 * 1024;796 return 4 * 1024;797 case DRM_FORMAT_MOD_LINEAR:798 return 4 * 1024;799 default:800 MISSING_CASE(fb->modifier);801 return 0;802 }803}804 805static unsigned int i965_plane_min_alignment(struct intel_plane *plane,806 const struct drm_framebuffer *fb,807 int color_plane)808{809 switch (fb->modifier) {810 case I915_FORMAT_MOD_X_TILED:811 return 4 * 1024;812 case DRM_FORMAT_MOD_LINEAR:813 return 128 * 1024;814 default:815 MISSING_CASE(fb->modifier);816 return 0;817 }818}819 820static unsigned int i9xx_plane_min_alignment(struct intel_plane *plane,821 const struct drm_framebuffer *fb,822 int color_plane)823{824 return 0;825}826 827static const struct drm_plane_funcs i965_plane_funcs = {828 .update_plane = drm_atomic_helper_update_plane,829 .disable_plane = drm_atomic_helper_disable_plane,830 .destroy = intel_plane_destroy,831 .atomic_duplicate_state = intel_plane_duplicate_state,832 .atomic_destroy_state = intel_plane_destroy_state,833 .format_mod_supported = i965_plane_format_mod_supported,834};835 836static const struct drm_plane_funcs i8xx_plane_funcs = {837 .update_plane = drm_atomic_helper_update_plane,838 .disable_plane = drm_atomic_helper_disable_plane,839 .destroy = intel_plane_destroy,840 .atomic_duplicate_state = intel_plane_duplicate_state,841 .atomic_destroy_state = intel_plane_destroy_state,842 .format_mod_supported = i8xx_plane_format_mod_supported,843};844 845struct intel_plane *846intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)847{848 struct intel_plane *plane;849 const struct drm_plane_funcs *plane_funcs;850 unsigned int supported_rotations;851 const u64 *modifiers;852 const u32 *formats;853 int num_formats;854 int ret, zpos;855 856 plane = intel_plane_alloc();857 if (IS_ERR(plane))858 return plane;859 860 plane->pipe = pipe;861 /*862 * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS863 * port is hooked to pipe B. Hence we want plane A feeding pipe B.864 */865 if (HAS_FBC(dev_priv) && DISPLAY_VER(dev_priv) < 4 &&866 INTEL_NUM_PIPES(dev_priv) == 2)867 plane->i9xx_plane = (enum i9xx_plane_id) !pipe;868 else869 plane->i9xx_plane = (enum i9xx_plane_id) pipe;870 plane->id = PLANE_PRIMARY;871 plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);872 873 intel_fbc_add_plane(i9xx_plane_fbc(dev_priv, plane->i9xx_plane), plane);874 875 if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {876 formats = vlv_primary_formats;877 num_formats = ARRAY_SIZE(vlv_primary_formats);878 } else if (DISPLAY_VER(dev_priv) >= 4) {879 /*880 * WaFP16GammaEnabling:ivb881 * "Workaround : When using the 64-bit format, the plane882 * output on each color channel has one quarter amplitude.883 * It can be brought up to full amplitude by using pipe884 * gamma correction or pipe color space conversion to885 * multiply the plane output by four."886 *887 * There is no dedicated plane gamma for the primary plane,888 * and using the pipe gamma/csc could conflict with other889 * planes, so we choose not to expose fp16 on IVB primary890 * planes. HSW primary planes no longer have this problem.891 */892 if (IS_IVYBRIDGE(dev_priv)) {893 formats = ivb_primary_formats;894 num_formats = ARRAY_SIZE(ivb_primary_formats);895 } else {896 formats = i965_primary_formats;897 num_formats = ARRAY_SIZE(i965_primary_formats);898 }899 } else {900 formats = i8xx_primary_formats;901 num_formats = ARRAY_SIZE(i8xx_primary_formats);902 }903 904 if (DISPLAY_VER(dev_priv) >= 4)905 plane_funcs = &i965_plane_funcs;906 else907 plane_funcs = &i8xx_plane_funcs;908 909 if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))910 plane->min_cdclk = vlv_plane_min_cdclk;911 else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))912 plane->min_cdclk = hsw_plane_min_cdclk;913 else if (IS_IVYBRIDGE(dev_priv))914 plane->min_cdclk = ivb_plane_min_cdclk;915 else916 plane->min_cdclk = i9xx_plane_min_cdclk;917 918 if (HAS_GMCH(dev_priv)) {919 if (DISPLAY_VER(dev_priv) >= 4)920 plane->max_stride = i965_plane_max_stride;921 else if (DISPLAY_VER(dev_priv) == 3)922 plane->max_stride = i915_plane_max_stride;923 else924 plane->max_stride = i8xx_plane_max_stride;925 } else {926 if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))927 plane->max_stride = hsw_primary_max_stride;928 else929 plane->max_stride = ilk_primary_max_stride;930 }931 932 if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))933 plane->min_alignment = vlv_primary_min_alignment;934 else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))935 plane->min_alignment = g4x_primary_min_alignment;936 else if (DISPLAY_VER(dev_priv) == 4)937 plane->min_alignment = i965_plane_min_alignment;938 else939 plane->min_alignment = i9xx_plane_min_alignment;940 941 if (IS_I830(dev_priv) || IS_I845G(dev_priv)) {942 plane->update_arm = i830_plane_update_arm;943 } else {944 plane->update_noarm = i9xx_plane_update_noarm;945 plane->update_arm = i9xx_plane_update_arm;946 }947 plane->disable_arm = i9xx_plane_disable_arm;948 plane->get_hw_state = i9xx_plane_get_hw_state;949 plane->check_plane = i9xx_plane_check;950 951 if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {952 plane->async_flip = vlv_primary_async_flip;953 plane->enable_flip_done = vlv_primary_enable_flip_done;954 plane->disable_flip_done = vlv_primary_disable_flip_done;955 } else if (IS_BROADWELL(dev_priv)) {956 plane->need_async_flip_toggle_wa = true;957 plane->async_flip = g4x_primary_async_flip;958 plane->enable_flip_done = bdw_primary_enable_flip_done;959 plane->disable_flip_done = bdw_primary_disable_flip_done;960 } else if (DISPLAY_VER(dev_priv) >= 7) {961 plane->async_flip = g4x_primary_async_flip;962 plane->enable_flip_done = ivb_primary_enable_flip_done;963 plane->disable_flip_done = ivb_primary_disable_flip_done;964 } else if (DISPLAY_VER(dev_priv) >= 5) {965 plane->async_flip = g4x_primary_async_flip;966 plane->enable_flip_done = ilk_primary_enable_flip_done;967 plane->disable_flip_done = ilk_primary_disable_flip_done;968 }969 970 modifiers = intel_fb_plane_get_modifiers(dev_priv, INTEL_PLANE_CAP_TILING_X);971 972 if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))973 ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,974 0, plane_funcs,975 formats, num_formats,976 modifiers,977 DRM_PLANE_TYPE_PRIMARY,978 "primary %c", pipe_name(pipe));979 else980 ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,981 0, plane_funcs,982 formats, num_formats,983 modifiers,984 DRM_PLANE_TYPE_PRIMARY,985 "plane %c",986 plane_name(plane->i9xx_plane));987 988 kfree(modifiers);989 990 if (ret)991 goto fail;992 993 if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {994 supported_rotations =995 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |996 DRM_MODE_REFLECT_X;997 } else if (DISPLAY_VER(dev_priv) >= 4) {998 supported_rotations =999 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;1000 } else {1001 supported_rotations = DRM_MODE_ROTATE_0;1002 }1003 1004 if (DISPLAY_VER(dev_priv) >= 4)1005 drm_plane_create_rotation_property(&plane->base,1006 DRM_MODE_ROTATE_0,1007 supported_rotations);1008 1009 zpos = 0;1010 drm_plane_create_zpos_immutable_property(&plane->base, zpos);1011 1012 intel_plane_helper_add(plane);1013 1014 return plane;1015 1016fail:1017 intel_plane_free(plane);1018 1019 return ERR_PTR(ret);1020}1021 1022static int i9xx_format_to_fourcc(int format)1023{1024 switch (format) {1025 case DISP_FORMAT_8BPP:1026 return DRM_FORMAT_C8;1027 case DISP_FORMAT_BGRA555:1028 return DRM_FORMAT_ARGB1555;1029 case DISP_FORMAT_BGRX555:1030 return DRM_FORMAT_XRGB1555;1031 case DISP_FORMAT_BGRX565:1032 return DRM_FORMAT_RGB565;1033 default:1034 case DISP_FORMAT_BGRX888:1035 return DRM_FORMAT_XRGB8888;1036 case DISP_FORMAT_RGBX888:1037 return DRM_FORMAT_XBGR8888;1038 case DISP_FORMAT_BGRA888:1039 return DRM_FORMAT_ARGB8888;1040 case DISP_FORMAT_RGBA888:1041 return DRM_FORMAT_ABGR8888;1042 case DISP_FORMAT_BGRX101010:1043 return DRM_FORMAT_XRGB2101010;1044 case DISP_FORMAT_RGBX101010:1045 return DRM_FORMAT_XBGR2101010;1046 case DISP_FORMAT_BGRA101010:1047 return DRM_FORMAT_ARGB2101010;1048 case DISP_FORMAT_RGBA101010:1049 return DRM_FORMAT_ABGR2101010;1050 case DISP_FORMAT_RGBX161616:1051 return DRM_FORMAT_XBGR16161616F;1052 }1053}1054 1055void1056i9xx_get_initial_plane_config(struct intel_crtc *crtc,1057 struct intel_initial_plane_config *plane_config)1058{1059 struct drm_device *dev = crtc->base.dev;1060 struct drm_i915_private *dev_priv = to_i915(dev);1061 struct intel_plane *plane = to_intel_plane(crtc->base.primary);1062 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;1063 enum pipe pipe;1064 u32 val, base, offset;1065 int fourcc, pixel_format;1066 unsigned int aligned_height;1067 struct drm_framebuffer *fb;1068 struct intel_framebuffer *intel_fb;1069 1070 if (!plane->get_hw_state(plane, &pipe))1071 return;1072 1073 drm_WARN_ON(dev, pipe != crtc->pipe);1074 1075 intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);1076 if (!intel_fb) {1077 drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n");1078 return;1079 }1080 1081 fb = &intel_fb->base;1082 1083 fb->dev = dev;1084 1085 val = intel_de_read(dev_priv, DSPCNTR(dev_priv, i9xx_plane));1086 1087 if (DISPLAY_VER(dev_priv) >= 4) {1088 if (val & DISP_TILED) {1089 plane_config->tiling = I915_TILING_X;1090 fb->modifier = I915_FORMAT_MOD_X_TILED;1091 }1092 1093 if (val & DISP_ROTATE_180)1094 plane_config->rotation = DRM_MODE_ROTATE_180;1095 }1096 1097 if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B &&1098 val & DISP_MIRROR)1099 plane_config->rotation |= DRM_MODE_REFLECT_X;1100 1101 pixel_format = val & DISP_FORMAT_MASK;1102 fourcc = i9xx_format_to_fourcc(pixel_format);1103 fb->format = drm_format_info(fourcc);1104 1105 if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {1106 offset = intel_de_read(dev_priv,1107 DSPOFFSET(dev_priv, i9xx_plane));1108 base = intel_de_read(dev_priv, DSPSURF(dev_priv, i9xx_plane)) & DISP_ADDR_MASK;1109 } else if (DISPLAY_VER(dev_priv) >= 4) {1110 if (plane_config->tiling)1111 offset = intel_de_read(dev_priv,1112 DSPTILEOFF(dev_priv, i9xx_plane));1113 else1114 offset = intel_de_read(dev_priv,1115 DSPLINOFF(dev_priv, i9xx_plane));1116 base = intel_de_read(dev_priv, DSPSURF(dev_priv, i9xx_plane)) & DISP_ADDR_MASK;1117 } else {1118 offset = 0;1119 base = intel_de_read(dev_priv, DSPADDR(dev_priv, i9xx_plane));1120 }1121 plane_config->base = base;1122 1123 drm_WARN_ON(&dev_priv->drm, offset != 0);1124 1125 val = intel_de_read(dev_priv, PIPESRC(dev_priv, pipe));1126 fb->width = REG_FIELD_GET(PIPESRC_WIDTH_MASK, val) + 1;1127 fb->height = REG_FIELD_GET(PIPESRC_HEIGHT_MASK, val) + 1;1128 1129 val = intel_de_read(dev_priv, DSPSTRIDE(dev_priv, i9xx_plane));1130 fb->pitches[0] = val & 0xffffffc0;1131 1132 aligned_height = intel_fb_align_height(fb, 0, fb->height);1133 1134 plane_config->size = fb->pitches[0] * aligned_height;1135 1136 drm_dbg_kms(&dev_priv->drm,1137 "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",1138 crtc->base.name, plane->base.name, fb->width, fb->height,1139 fb->format->cpp[0] * 8, base, fb->pitches[0],1140 plane_config->size);1141 1142 plane_config->fb = intel_fb;1143}1144 1145bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc,1146 const struct intel_initial_plane_config *plane_config)1147{1148 struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);1149 struct intel_plane *plane = to_intel_plane(crtc->base.primary);1150 const struct intel_plane_state *plane_state =1151 to_intel_plane_state(plane->base.state);1152 enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;1153 u32 base;1154 1155 if (!plane_state->uapi.visible)1156 return false;1157 1158 base = intel_plane_ggtt_offset(plane_state);1159 1160 /*1161 * We may have moved the surface to a different1162 * part of ggtt, make the plane aware of that.1163 */1164 if (plane_config->base == base)1165 return false;1166 1167 if (DISPLAY_VER(dev_priv) >= 4)1168 intel_de_write(dev_priv, DSPSURF(dev_priv, i9xx_plane), base);1169 else1170 intel_de_write(dev_priv, DSPADDR(dev_priv, i9xx_plane), base);1171 1172 return true;1173}1174