diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/i9xx_plane.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/i9xx_plane.c | 871 |
1 files changed, 551 insertions, 320 deletions
diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index 9643c45a2209..51ccc6bd5f21 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -2,19 +2,29 @@ /* * Copyright © 2020 Intel Corporation */ + #include <linux/kernel.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_print.h> +#include "i915_reg.h" +#include "i9xx_plane.h" +#include "i9xx_plane_regs.h" #include "intel_atomic.h" -#include "intel_atomic_plane.h" #include "intel_de.h" +#include "intel_display_irq.h" +#include "intel_display_regs.h" #include "intel_display_types.h" +#include "intel_display_utils.h" #include "intel_fb.h" +#include "intel_fbc.h" +#include "intel_frontbuffer.h" +#include "intel_panic.h" +#include "intel_plane.h" #include "intel_sprite.h" -#include "i9xx_plane.h" /* Primary plane formats for gen <= 3 */ static const u32 i8xx_primary_formats[] = { @@ -60,22 +70,11 @@ static const u32 vlv_primary_formats[] = { DRM_FORMAT_XBGR16161616F, }; -static const u64 i9xx_format_modifiers[] = { - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane, u32 format, u64 modifier) { - switch (modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - break; - default: + if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier)) return false; - } switch (format) { case DRM_FORMAT_C8: @@ -92,13 +91,8 @@ static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane, static bool i965_plane_format_mod_supported(struct drm_plane *_plane, u32 format, u64 modifier) { - switch (modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - break; - default: + if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier)) return false; - } switch (format) { case DRM_FORMAT_C8: @@ -119,116 +113,123 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane, } } -static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv, +static bool i9xx_plane_has_fbc(struct intel_display *display, enum i9xx_plane_id i9xx_plane) { - if (!HAS_FBC(dev_priv)) + if (!HAS_FBC(display)) return false; - if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) + if (display->platform.broadwell || display->platform.haswell) return i9xx_plane == PLANE_A; /* tied to pipe A */ - else if (IS_IVYBRIDGE(dev_priv)) + else if (display->platform.ivybridge) return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B || i9xx_plane == PLANE_C; - else if (DISPLAY_VER(dev_priv) >= 4) + else if (DISPLAY_VER(display) >= 4) return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B; else return i9xx_plane == PLANE_A; } +static struct intel_fbc *i9xx_plane_fbc(struct intel_display *display, + enum i9xx_plane_id i9xx_plane) +{ + if (i9xx_plane_has_fbc(display, i9xx_plane)) + return display->fbc[INTEL_FBC_A]; + else + return NULL; +} + static bool i9xx_plane_has_windowing(struct intel_plane *plane) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - if (IS_CHERRYVIEW(dev_priv)) + if (display->platform.cherryview) return i9xx_plane == PLANE_B; - else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv)) + else if (DISPLAY_VER(display) >= 5 || display->platform.g4x) return false; - else if (DISPLAY_VER(dev_priv) == 4) + else if (DISPLAY_VER(display) == 4) return i9xx_plane == PLANE_C; else return i9xx_plane == PLANE_B || i9xx_plane == PLANE_C; } -static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static u32 i9xx_plane_ctl(const struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); + struct intel_display *display = to_intel_display(plane_state); const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int rotation = plane_state->hw.rotation; u32 dspcntr; - dspcntr = DISPLAY_PLANE_ENABLE; + dspcntr = DISP_ENABLE; - if (IS_G4X(dev_priv) || IS_IRONLAKE(dev_priv) || - IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv)) - dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + if (display->platform.g4x || display->platform.ironlake || + display->platform.sandybridge || display->platform.ivybridge) + dspcntr |= DISP_TRICKLE_FEED_DISABLE; switch (fb->format->format) { case DRM_FORMAT_C8: - dspcntr |= DISPPLANE_8BPP; + dspcntr |= DISP_FORMAT_8BPP; break; case DRM_FORMAT_XRGB1555: - dspcntr |= DISPPLANE_BGRX555; + dspcntr |= DISP_FORMAT_BGRX555; break; case DRM_FORMAT_ARGB1555: - dspcntr |= DISPPLANE_BGRA555; + dspcntr |= DISP_FORMAT_BGRA555; break; case DRM_FORMAT_RGB565: - dspcntr |= DISPPLANE_BGRX565; + dspcntr |= DISP_FORMAT_BGRX565; break; case DRM_FORMAT_XRGB8888: - dspcntr |= DISPPLANE_BGRX888; + dspcntr |= DISP_FORMAT_BGRX888; break; case DRM_FORMAT_XBGR8888: - dspcntr |= DISPPLANE_RGBX888; + dspcntr |= DISP_FORMAT_RGBX888; break; case DRM_FORMAT_ARGB8888: - dspcntr |= DISPPLANE_BGRA888; + dspcntr |= DISP_FORMAT_BGRA888; break; case DRM_FORMAT_ABGR8888: - dspcntr |= DISPPLANE_RGBA888; + dspcntr |= DISP_FORMAT_RGBA888; break; case DRM_FORMAT_XRGB2101010: - dspcntr |= DISPPLANE_BGRX101010; + dspcntr |= DISP_FORMAT_BGRX101010; break; case DRM_FORMAT_XBGR2101010: - dspcntr |= DISPPLANE_RGBX101010; + dspcntr |= DISP_FORMAT_RGBX101010; break; case DRM_FORMAT_ARGB2101010: - dspcntr |= DISPPLANE_BGRA101010; + dspcntr |= DISP_FORMAT_BGRA101010; break; case DRM_FORMAT_ABGR2101010: - dspcntr |= DISPPLANE_RGBA101010; + dspcntr |= DISP_FORMAT_RGBA101010; break; case DRM_FORMAT_XBGR16161616F: - dspcntr |= DISPPLANE_RGBX161616; + dspcntr |= DISP_FORMAT_RGBX161616; break; default: MISSING_CASE(fb->format->format); return 0; } - if (DISPLAY_VER(dev_priv) >= 4 && + if (DISPLAY_VER(display) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) - dspcntr |= DISPPLANE_TILED; + dspcntr |= DISP_TILED; if (rotation & DRM_MODE_ROTATE_180) - dspcntr |= DISPPLANE_ROTATE_180; + dspcntr |= DISP_ROTATE_180; if (rotation & DRM_MODE_REFLECT_X) - dspcntr |= DISPPLANE_MIRROR; + dspcntr |= DISP_MIRROR; return dspcntr; } int i9xx_check_plane_surface(struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); + struct intel_display *display = to_intel_display(plane_state); + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); const struct drm_framebuffer *fb = plane_state->hw.fb; int src_x, src_y, src_w; u32 offset; @@ -246,12 +247,16 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) src_y = plane_state->uapi.src.y1 >> 16; /* Undocumented hardware limit on i965/g4x/vlv/chv */ - if (HAS_GMCH(dev_priv) && fb->format->cpp[0] == 8 && src_w > 2048) + if (HAS_GMCH(display) && fb->format->cpp[0] == 8 && src_w > 2048) { + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] plane too wide (%d) for 64bpp\n", + plane->base.base.id, plane->base.name, src_w); return -EINVAL; + } intel_add_fb_offsets(&src_x, &src_y, plane_state, 0); - if (DISPLAY_VER(dev_priv) >= 4) + if (DISPLAY_VER(display) >= 4) offset = intel_plane_compute_aligned_offset(&src_x, &src_y, plane_state, 0); else @@ -268,14 +273,15 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) * Linear surfaces seem to work just fine, even on hsw/bdw * despite them not using the linear offset anymore. */ - if (DISPLAY_VER(dev_priv) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) { - u32 alignment = intel_surf_alignment(fb, 0); + if (DISPLAY_VER(display) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) { + unsigned int alignment = plane->min_alignment(plane, fb, 0); int cpp = fb->format->cpp[0]; - while ((src_x + src_w) * cpp > plane_state->view.color_plane[0].stride) { + while ((src_x + src_w) * cpp > plane_state->view.color_plane[0].mapping_stride) { if (offset == 0) { - drm_dbg_kms(&dev_priv->drm, - "Unable to find suitable display surface offset due to X-tiling\n"); + drm_dbg_kms(display->drm, + "[PLANE:%d:%s] unable to find suitable display surface offset due to X-tiling\n", + plane->base.base.id, plane->base.name); return -EINVAL; } @@ -292,7 +298,7 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) src_x << 16, src_y << 16); /* HSW/BDW do this automagically in hardware */ - if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) { + if (!display->platform.haswell && !display->platform.broadwell) { unsigned int rotation = plane_state->hw.rotation; int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; int src_h = drm_rect_height(&plane_state->uapi.src) >> 16; @@ -305,11 +311,11 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) } } - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - drm_WARN_ON(&dev_priv->drm, src_x > 8191 || src_y > 4095); - } else if (DISPLAY_VER(dev_priv) >= 4 && + if (display->platform.haswell || display->platform.broadwell) { + drm_WARN_ON(display->drm, src_x > 8191 || src_y > 4095); + } else if (DISPLAY_VER(display) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) { - drm_WARN_ON(&dev_priv->drm, src_x > 4095 || src_y > 4095); + drm_WARN_ON(display->drm, src_x > 4095 || src_y > 4095); } plane_state->view.color_plane[0].offset = offset; @@ -330,10 +336,10 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - i9xx_plane_has_windowing(plane)); + ret = intel_plane_check_clipping(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + i9xx_plane_has_windowing(plane)); if (ret) return ret; @@ -348,25 +354,38 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state); + plane_state->ctl = i9xx_plane_ctl(plane_state); return 0; } +static u32 i8xx_plane_surf_offset(const struct intel_plane_state *plane_state) +{ + int x = plane_state->view.color_plane[0].x; + int y = plane_state->view.color_plane[0].y; + + return intel_fb_xy_to_linear(x, y, plane_state, 0); +} + +u32 i965_plane_surf_offset(const struct intel_plane_state *plane_state) +{ + return plane_state->view.color_plane[0].offset; +} + static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state) { + struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 dspcntr = 0; if (crtc_state->gamma_enable) - dspcntr |= DISPPLANE_GAMMA_ENABLE; + dspcntr |= DISP_PIPE_GAMMA_ENABLE; if (crtc_state->csc_enable) - dspcntr |= DISPPLANE_PIPE_CSC_ENABLE; + dspcntr |= DISP_PIPE_CSC_ENABLE; - if (DISPLAY_VER(dev_priv) < 5) - dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe); + if (DISPLAY_VER(display) < 5) + dspcntr |= DISP_PIPE_SEL(crtc->pipe); return dspcntr; } @@ -418,63 +437,75 @@ static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state, return DIV_ROUND_UP(pixel_rate * num, den); } -static void i9xx_update_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static void i9xx_plane_update_noarm(struct intel_dsb *dsb, + struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - u32 linear_offset; - int x = plane_state->view.color_plane[0].x; - int y = plane_state->view.color_plane[0].y; - int crtc_x = plane_state->uapi.dst.x1; - int crtc_y = plane_state->uapi.dst.y1; - int crtc_w = drm_rect_width(&plane_state->uapi.dst); - int crtc_h = drm_rect_height(&plane_state->uapi.dst); - unsigned long irqflags; - u32 dspaddr_offset; - u32 dspcntr; - - dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); - linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); + intel_de_write_fw(display, DSPSTRIDE(display, i9xx_plane), + plane_state->view.color_plane[0].mapping_stride); - if (DISPLAY_VER(dev_priv) >= 4) - dspaddr_offset = plane_state->view.color_plane[0].offset; - else - dspaddr_offset = linear_offset; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane), - plane_state->view.color_plane[0].stride); + if (DISPLAY_VER(display) < 4) { + int crtc_x = plane_state->uapi.dst.x1; + int crtc_y = plane_state->uapi.dst.y1; + int crtc_w = drm_rect_width(&plane_state->uapi.dst); + int crtc_h = drm_rect_height(&plane_state->uapi.dst); - if (DISPLAY_VER(dev_priv) < 4) { /* * PLANE_A doesn't actually have a full window * generator but let's assume we still need to * program whatever is there. */ - intel_de_write_fw(dev_priv, DSPPOS(i9xx_plane), - (crtc_y << 16) | crtc_x); - intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane), - ((crtc_h - 1) << 16) | (crtc_w - 1)); - } else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) { - intel_de_write_fw(dev_priv, PRIMPOS(i9xx_plane), - (crtc_y << 16) | crtc_x); - intel_de_write_fw(dev_priv, PRIMSIZE(i9xx_plane), - ((crtc_h - 1) << 16) | (crtc_w - 1)); - intel_de_write_fw(dev_priv, PRIMCNSTALPHA(i9xx_plane), 0); + intel_de_write_fw(display, DSPPOS(display, i9xx_plane), + DISP_POS_Y(crtc_y) | DISP_POS_X(crtc_x)); + intel_de_write_fw(display, DSPSIZE(display, i9xx_plane), + DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1)); + } +} + +static void i9xx_plane_update_arm(struct intel_dsb *dsb, + struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct intel_display *display = to_intel_display(plane); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + int x = plane_state->view.color_plane[0].x; + int y = plane_state->view.color_plane[0].y; + u32 dspcntr; + + dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); + + /* see intel_plane_atomic_calc_changes() */ + if (plane->need_async_flip_toggle_wa && + crtc_state->async_flip_planes & BIT(plane->id)) + dspcntr |= DISP_ASYNC_FLIP; + + if (display->platform.cherryview && i9xx_plane == PLANE_B) { + int crtc_x = plane_state->uapi.dst.x1; + int crtc_y = plane_state->uapi.dst.y1; + int crtc_w = drm_rect_width(&plane_state->uapi.dst); + int crtc_h = drm_rect_height(&plane_state->uapi.dst); + + intel_de_write_fw(display, PRIMPOS(display, i9xx_plane), + PRIM_POS_Y(crtc_y) | PRIM_POS_X(crtc_x)); + intel_de_write_fw(display, PRIMSIZE(display, i9xx_plane), + PRIM_HEIGHT(crtc_h - 1) | PRIM_WIDTH(crtc_w - 1)); + intel_de_write_fw(display, + PRIMCNSTALPHA(display, i9xx_plane), 0); } - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - intel_de_write_fw(dev_priv, DSPOFFSET(i9xx_plane), - (y << 16) | x); - } else if (DISPLAY_VER(dev_priv) >= 4) { - intel_de_write_fw(dev_priv, DSPLINOFF(i9xx_plane), - linear_offset); - intel_de_write_fw(dev_priv, DSPTILEOFF(i9xx_plane), - (y << 16) | x); + if (display->platform.haswell || display->platform.broadwell) { + intel_de_write_fw(display, DSPOFFSET(display, i9xx_plane), + DISP_OFFSET_Y(y) | DISP_OFFSET_X(x)); + } else if (DISPLAY_VER(display) >= 4) { + intel_de_write_fw(display, DSPLINOFF(display, i9xx_plane), + intel_fb_xy_to_linear(x, y, plane_state, 0)); + intel_de_write_fw(display, DSPTILEOFF(display, i9xx_plane), + DISP_OFFSET_Y(y) | DISP_OFFSET_X(x)); } /* @@ -482,23 +513,35 @@ static void i9xx_update_plane(struct intel_plane *plane, * disabled. Try to make the plane enable atomic by writing * the control register just before the surface register. */ - intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); - if (DISPLAY_VER(dev_priv) >= 4) - intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); + intel_de_write_fw(display, DSPCNTR(display, i9xx_plane), dspcntr); + + if (DISPLAY_VER(display) >= 4) + intel_de_write_fw(display, DSPSURF(display, i9xx_plane), plane_state->surf); else - intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); + intel_de_write_fw(display, DSPADDR(display, i9xx_plane), plane_state->surf); +} - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +static void i830_plane_update_arm(struct intel_dsb *dsb, + struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + /* + * On i830/i845 all registers are self-arming [ALM040]. + * + * Additional breakage on i830 causes register reads to return + * the last latched value instead of the last written value [ALM026]. + */ + i9xx_plane_update_noarm(dsb, plane, crtc_state, plane_state); + i9xx_plane_update_arm(dsb, plane, crtc_state, plane_state); } -static void i9xx_disable_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state) +static void i9xx_plane_disable_arm(struct intel_dsb *dsb, + struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - unsigned long irqflags; u32 dspcntr; /* @@ -513,144 +556,172 @@ static void i9xx_disable_plane(struct intel_plane *plane, */ dspcntr = i9xx_plane_ctl_crtc(crtc_state); - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + intel_de_write_fw(display, DSPCNTR(display, i9xx_plane), dspcntr); - intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); - if (DISPLAY_VER(dev_priv) >= 4) - intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0); + if (DISPLAY_VER(display) >= 4) + intel_de_write_fw(display, DSPSURF(display, i9xx_plane), 0); else - intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0); + intel_de_write_fw(display, DSPADDR(display, i9xx_plane), 0); +} + +static void g4x_primary_capture_error(struct intel_crtc *crtc, + struct intel_plane *plane, + struct intel_plane_error *error) +{ + struct intel_display *display = to_intel_display(plane); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + + error->ctl = intel_de_read(display, DSPCNTR(display, i9xx_plane)); + error->surf = intel_de_read(display, DSPSURF(display, i9xx_plane)); + error->surflive = intel_de_read(display, DSPSURFLIVE(display, i9xx_plane)); +} + +static void i965_plane_capture_error(struct intel_crtc *crtc, + struct intel_plane *plane, + struct intel_plane_error *error) +{ + struct intel_display *display = to_intel_display(plane); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + + error->ctl = intel_de_read(display, DSPCNTR(display, i9xx_plane)); + error->surf = intel_de_read(display, DSPSURF(display, i9xx_plane)); +} - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +static void i8xx_plane_capture_error(struct intel_crtc *crtc, + struct intel_plane *plane, + struct intel_plane_error *error) +{ + struct intel_display *display = to_intel_display(plane); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + + error->ctl = intel_de_read(display, DSPCNTR(display, i9xx_plane)); + error->surf = intel_de_read(display, DSPADDR(display, i9xx_plane)); } static void -g4x_primary_async_flip(struct intel_plane *plane, +g4x_primary_async_flip(struct intel_dsb *dsb, + struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, bool async_flip) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); - u32 dspaddr_offset = plane_state->view.color_plane[0].offset; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - unsigned long irqflags; if (async_flip) - dspcntr |= DISPPLANE_ASYNC_FLIP; + dspcntr |= DISP_ASYNC_FLIP; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); - intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + intel_de_write_fw(display, DSPCNTR(display, i9xx_plane), dspcntr); + intel_de_write_fw(display, DSPSURF(display, i9xx_plane), plane_state->surf); } static void -vlv_primary_async_flip(struct intel_plane *plane, +vlv_primary_async_flip(struct intel_dsb *dsb, + struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, bool async_flip) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - u32 dspaddr_offset = plane_state->view.color_plane[0].offset; + struct intel_display *display = to_intel_display(plane); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - unsigned long irqflags; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - intel_de_write_fw(dev_priv, DSPADDR_VLV(i9xx_plane), - intel_plane_ggtt_offset(plane_state) + dspaddr_offset); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + intel_de_write_fw(display, DSPADDR_VLV(display, i9xx_plane), plane_state->surf); } static void bdw_primary_enable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum pipe pipe = plane->pipe; - spin_lock_irq(&i915->irq_lock); - bdw_enable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + bdw_enable_pipe_irq(display, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE); + spin_unlock_irq(&display->irq.lock); } static void bdw_primary_disable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum pipe pipe = plane->pipe; - spin_lock_irq(&i915->irq_lock); - bdw_disable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + bdw_disable_pipe_irq(display, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE); + spin_unlock_irq(&display->irq.lock); } static void ivb_primary_enable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); - spin_lock_irq(&i915->irq_lock); - ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane)); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + ilk_enable_display_irq(display, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane)); + spin_unlock_irq(&display->irq.lock); } static void ivb_primary_disable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); - spin_lock_irq(&i915->irq_lock); - ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane)); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + ilk_disable_display_irq(display, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane)); + spin_unlock_irq(&display->irq.lock); } static void ilk_primary_enable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); - spin_lock_irq(&i915->irq_lock); - ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane)); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + ilk_enable_display_irq(display, DE_PLANE_FLIP_DONE(plane->i9xx_plane)); + spin_unlock_irq(&display->irq.lock); } static void ilk_primary_disable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); - spin_lock_irq(&i915->irq_lock); - ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane)); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + ilk_disable_display_irq(display, DE_PLANE_FLIP_DONE(plane->i9xx_plane)); + spin_unlock_irq(&display->irq.lock); } static void vlv_primary_enable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum pipe pipe = plane->pipe; - spin_lock_irq(&i915->irq_lock); - i915_enable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + i915_enable_pipestat(display, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV); + spin_unlock_irq(&display->irq.lock); } static void vlv_primary_disable_flip_done(struct intel_plane *plane) { - struct drm_i915_private *i915 = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum pipe pipe = plane->pipe; - spin_lock_irq(&i915->irq_lock); - i915_disable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV); - spin_unlock_irq(&i915->irq_lock); + spin_lock_irq(&display->irq.lock); + i915_disable_pipestat(display, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV); + spin_unlock_irq(&display->irq.lock); +} + +static bool i9xx_plane_can_async_flip(u64 modifier) +{ + return modifier == I915_FORMAT_MOD_X_TILED; } static bool i9xx_plane_get_hw_state(struct intel_plane *plane, enum pipe *pipe) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + struct intel_display *display = to_intel_display(plane); enum intel_display_power_domain power_domain; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; intel_wakeref_t wakeref; @@ -663,31 +734,29 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane, * display power wells. */ power_domain = POWER_DOMAIN_PIPE(plane->pipe); - wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); + wakeref = intel_display_power_get_if_enabled(display, power_domain); if (!wakeref) return false; - val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + val = intel_de_read(display, DSPCNTR(display, i9xx_plane)); - ret = val & DISPLAY_PLANE_ENABLE; + ret = val & DISP_ENABLE; - if (DISPLAY_VER(dev_priv) >= 5) + if (DISPLAY_VER(display) >= 5) *pipe = plane->pipe; else - *pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> - DISPPLANE_SEL_PIPE_SHIFT; + *pipe = REG_FIELD_GET(DISP_PIPE_SEL_MASK, val); - intel_display_power_put(dev_priv, power_domain, wakeref); + intel_display_power_put(display, power_domain, wakeref); return ret; } static unsigned int hsw_primary_max_stride(struct intel_plane *plane, - u32 pixel_format, u64 modifier, - unsigned int rotation) + const struct drm_format_info *info, + u64 modifier, unsigned int rotation) { - const struct drm_format_info *info = drm_format_info(pixel_format); int cpp = info->cpp[0]; /* Limit to 8k pixels to guarantee OFFSET.x doesn't get too big. */ @@ -696,10 +765,9 @@ hsw_primary_max_stride(struct intel_plane *plane, static unsigned int ilk_primary_max_stride(struct intel_plane *plane, - u32 pixel_format, u64 modifier, - unsigned int rotation) + const struct drm_format_info *info, + u64 modifier, unsigned int rotation) { - const struct drm_format_info *info = drm_format_info(pixel_format); int cpp = info->cpp[0]; /* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */ @@ -711,10 +779,9 @@ ilk_primary_max_stride(struct intel_plane *plane, unsigned int i965_plane_max_stride(struct intel_plane *plane, - u32 pixel_format, u64 modifier, - unsigned int rotation) + const struct drm_format_info *info, + u64 modifier, unsigned int rotation) { - const struct drm_format_info *info = drm_format_info(pixel_format); int cpp = info->cpp[0]; /* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */ @@ -725,25 +792,95 @@ i965_plane_max_stride(struct intel_plane *plane, } static unsigned int -i9xx_plane_max_stride(struct intel_plane *plane, - u32 pixel_format, u64 modifier, - unsigned int rotation) +i915_plane_max_stride(struct intel_plane *plane, + const struct drm_format_info *info, + u64 modifier, unsigned int rotation) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + if (modifier == I915_FORMAT_MOD_X_TILED) + return 8 * 1024; + else + return 16 * 1024; +} - if (DISPLAY_VER(dev_priv) >= 3) { - if (modifier == I915_FORMAT_MOD_X_TILED) - return 8*1024; - else - return 16*1024; - } else { - if (plane->i9xx_plane == PLANE_C) - return 4*1024; - else - return 8*1024; +static unsigned int +i8xx_plane_max_stride(struct intel_plane *plane, + const struct drm_format_info *info, + u64 modifier, unsigned int rotation) +{ + if (plane->i9xx_plane == PLANE_C) + return 4 * 1024; + else + return 8 * 1024; +} + +unsigned int vlv_plane_min_alignment(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane) +{ + struct intel_display *display = to_intel_display(plane); + + if (intel_plane_can_async_flip(plane, fb->format->format, fb->modifier)) + return 256 * 1024; + + /* FIXME undocumented so not sure what's actually needed */ + if (intel_scanout_needs_vtd_wa(display)) + return 256 * 1024; + + switch (fb->modifier) { + case I915_FORMAT_MOD_X_TILED: + return 4 * 1024; + case DRM_FORMAT_MOD_LINEAR: + return 128 * 1024; + default: + MISSING_CASE(fb->modifier); + return 0; + } +} + +static unsigned int g4x_primary_min_alignment(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane) +{ + struct intel_display *display = to_intel_display(plane); + + if (intel_plane_can_async_flip(plane, fb->format->format, fb->modifier)) + return 256 * 1024; + + if (intel_scanout_needs_vtd_wa(display)) + return 256 * 1024; + + switch (fb->modifier) { + case I915_FORMAT_MOD_X_TILED: + case DRM_FORMAT_MOD_LINEAR: + return 4 * 1024; + default: + MISSING_CASE(fb->modifier); + return 0; + } +} + +static unsigned int i965_plane_min_alignment(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane) +{ + switch (fb->modifier) { + case I915_FORMAT_MOD_X_TILED: + return 4 * 1024; + case DRM_FORMAT_MOD_LINEAR: + return 128 * 1024; + default: + MISSING_CASE(fb->modifier); + return 0; } } +static unsigned int i9xx_plane_min_alignment(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane) +{ + return 0; +} + static const struct drm_plane_funcs i965_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -751,6 +888,7 @@ static const struct drm_plane_funcs i965_plane_funcs = { .atomic_duplicate_state = intel_plane_duplicate_state, .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = i965_plane_format_mod_supported, + .format_mod_supported_async = intel_plane_format_mod_supported_async, }; static const struct drm_plane_funcs i8xx_plane_funcs = { @@ -760,14 +898,37 @@ static const struct drm_plane_funcs i8xx_plane_funcs = { .atomic_duplicate_state = intel_plane_duplicate_state, .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = i8xx_plane_format_mod_supported, + .format_mod_supported_async = intel_plane_format_mod_supported_async, }; +static void i9xx_disable_tiling(struct intel_plane *plane) +{ + struct intel_display *display = to_intel_display(plane); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + u32 dspcntr; + u32 reg; + + dspcntr = intel_de_read_fw(display, DSPCNTR(display, i9xx_plane)); + dspcntr &= ~DISP_TILED; + intel_de_write_fw(display, DSPCNTR(display, i9xx_plane), dspcntr); + + if (DISPLAY_VER(display) >= 4) { + reg = intel_de_read_fw(display, DSPSURF(display, i9xx_plane)); + intel_de_write_fw(display, DSPSURF(display, i9xx_plane), reg); + + } else { + reg = intel_de_read_fw(display, DSPADDR(display, i9xx_plane)); + intel_de_write_fw(display, DSPADDR(display, i9xx_plane), reg); + } +} + struct intel_plane * -intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) +intel_primary_plane_create(struct intel_display *display, enum pipe pipe) { struct intel_plane *plane; const struct drm_plane_funcs *plane_funcs; unsigned int supported_rotations; + const u64 *modifiers; const u32 *formats; int num_formats; int ret, zpos; @@ -781,25 +942,20 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS * port is hooked to pipe B. Hence we want plane A feeding pipe B. */ - if (HAS_FBC(dev_priv) && DISPLAY_VER(dev_priv) < 4 && - INTEL_NUM_PIPES(dev_priv) == 2) + if (HAS_FBC(display) && DISPLAY_VER(display) < 4 && + INTEL_NUM_PIPES(display) == 2) plane->i9xx_plane = (enum i9xx_plane_id) !pipe; else plane->i9xx_plane = (enum i9xx_plane_id) pipe; plane->id = PLANE_PRIMARY; plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id); - plane->has_fbc = i9xx_plane_has_fbc(dev_priv, plane->i9xx_plane); - if (plane->has_fbc) { - struct intel_fbc *fbc = &dev_priv->fbc; - - fbc->possible_framebuffer_bits |= plane->frontbuffer_bit; - } + intel_fbc_add_plane(i9xx_plane_fbc(display, plane->i9xx_plane), plane); - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + if (display->platform.valleyview || display->platform.cherryview) { formats = vlv_primary_formats; num_formats = ARRAY_SIZE(vlv_primary_formats); - } else if (DISPLAY_VER(dev_priv) >= 4) { + } else if (DISPLAY_VER(display) >= 4) { /* * WaFP16GammaEnabling:ivb * "Workaround : When using the 64-bit format, the plane @@ -813,7 +969,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) * planes, so we choose not to expose fp16 on IVB primary * planes. HSW primary planes no longer have this problem. */ - if (IS_IVYBRIDGE(dev_priv)) { + if (display->platform.ivybridge) { formats = ivb_primary_formats; num_formats = ARRAY_SIZE(ivb_primary_formats); } else { @@ -825,86 +981,131 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) num_formats = ARRAY_SIZE(i8xx_primary_formats); } - if (DISPLAY_VER(dev_priv) >= 4) + if (DISPLAY_VER(display) >= 4) plane_funcs = &i965_plane_funcs; else plane_funcs = &i8xx_plane_funcs; - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + if (display->platform.valleyview || display->platform.cherryview) plane->min_cdclk = vlv_plane_min_cdclk; - else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) + else if (display->platform.broadwell || display->platform.haswell) plane->min_cdclk = hsw_plane_min_cdclk; - else if (IS_IVYBRIDGE(dev_priv)) + else if (display->platform.ivybridge) plane->min_cdclk = ivb_plane_min_cdclk; else plane->min_cdclk = i9xx_plane_min_cdclk; - if (HAS_GMCH(dev_priv)) { - if (DISPLAY_VER(dev_priv) >= 4) + if (HAS_GMCH(display)) { + if (DISPLAY_VER(display) >= 4) plane->max_stride = i965_plane_max_stride; + else if (DISPLAY_VER(display) == 3) + plane->max_stride = i915_plane_max_stride; else - plane->max_stride = i9xx_plane_max_stride; + plane->max_stride = i8xx_plane_max_stride; } else { - if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) + if (display->platform.broadwell || display->platform.haswell) plane->max_stride = hsw_primary_max_stride; else plane->max_stride = ilk_primary_max_stride; } - plane->update_plane = i9xx_update_plane; - plane->disable_plane = i9xx_disable_plane; + if (display->platform.valleyview || display->platform.cherryview) + plane->min_alignment = vlv_plane_min_alignment; + else if (DISPLAY_VER(display) >= 5 || display->platform.g4x) + plane->min_alignment = g4x_primary_min_alignment; + else if (DISPLAY_VER(display) == 4) + plane->min_alignment = i965_plane_min_alignment; + else + plane->min_alignment = i9xx_plane_min_alignment; + + /* FIXME undocumented for VLV/CHV so not sure what's actually needed */ + if (intel_scanout_needs_vtd_wa(display)) + plane->vtd_guard = 128; + + if (display->platform.i830 || display->platform.i845g) { + plane->update_arm = i830_plane_update_arm; + } else { + plane->update_noarm = i9xx_plane_update_noarm; + plane->update_arm = i9xx_plane_update_arm; + } + plane->disable_arm = i9xx_plane_disable_arm; plane->get_hw_state = i9xx_plane_get_hw_state; plane->check_plane = i9xx_plane_check; - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - plane->async_flip = vlv_primary_async_flip; - plane->enable_flip_done = vlv_primary_enable_flip_done; - plane->disable_flip_done = vlv_primary_disable_flip_done; - } else if (IS_BROADWELL(dev_priv)) { - plane->need_async_flip_disable_wa = true; - plane->async_flip = g4x_primary_async_flip; - plane->enable_flip_done = bdw_primary_enable_flip_done; - plane->disable_flip_done = bdw_primary_disable_flip_done; - } else if (DISPLAY_VER(dev_priv) >= 7) { - plane->async_flip = g4x_primary_async_flip; - plane->enable_flip_done = ivb_primary_enable_flip_done; - plane->disable_flip_done = ivb_primary_disable_flip_done; - } else if (DISPLAY_VER(dev_priv) >= 5) { - plane->async_flip = g4x_primary_async_flip; - plane->enable_flip_done = ilk_primary_enable_flip_done; - plane->disable_flip_done = ilk_primary_disable_flip_done; + if (DISPLAY_VER(display) >= 4) + plane->surf_offset = i965_plane_surf_offset; + else + plane->surf_offset = i8xx_plane_surf_offset; + + if (DISPLAY_VER(display) >= 5 || display->platform.g4x) + plane->capture_error = g4x_primary_capture_error; + else if (DISPLAY_VER(display) >= 4) + plane->capture_error = i965_plane_capture_error; + else + plane->capture_error = i8xx_plane_capture_error; + + if (HAS_ASYNC_FLIPS(display)) { + if (display->platform.valleyview || display->platform.cherryview) { + plane->async_flip = vlv_primary_async_flip; + plane->enable_flip_done = vlv_primary_enable_flip_done; + plane->disable_flip_done = vlv_primary_disable_flip_done; + plane->can_async_flip = i9xx_plane_can_async_flip; + } else if (display->platform.broadwell) { + plane->need_async_flip_toggle_wa = true; + plane->async_flip = g4x_primary_async_flip; + plane->enable_flip_done = bdw_primary_enable_flip_done; + plane->disable_flip_done = bdw_primary_disable_flip_done; + plane->can_async_flip = i9xx_plane_can_async_flip; + } else if (DISPLAY_VER(display) >= 7) { + plane->async_flip = g4x_primary_async_flip; + plane->enable_flip_done = ivb_primary_enable_flip_done; + plane->disable_flip_done = ivb_primary_disable_flip_done; + plane->can_async_flip = i9xx_plane_can_async_flip; + } else if (DISPLAY_VER(display) >= 5) { + plane->async_flip = g4x_primary_async_flip; + plane->enable_flip_done = ilk_primary_enable_flip_done; + plane->disable_flip_done = ilk_primary_disable_flip_done; + plane->can_async_flip = i9xx_plane_can_async_flip; + } } - if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv)) - ret = drm_universal_plane_init(&dev_priv->drm, &plane->base, + plane->disable_tiling = i9xx_disable_tiling; + + modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X); + + if (DISPLAY_VER(display) >= 5 || display->platform.g4x) + ret = drm_universal_plane_init(display->drm, &plane->base, 0, plane_funcs, formats, num_formats, - i9xx_format_modifiers, + modifiers, DRM_PLANE_TYPE_PRIMARY, "primary %c", pipe_name(pipe)); else - ret = drm_universal_plane_init(&dev_priv->drm, &plane->base, + ret = drm_universal_plane_init(display->drm, &plane->base, 0, plane_funcs, formats, num_formats, - i9xx_format_modifiers, + modifiers, DRM_PLANE_TYPE_PRIMARY, "plane %c", plane_name(plane->i9xx_plane)); + + kfree(modifiers); + if (ret) goto fail; - if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) { + if (display->platform.cherryview && pipe == PIPE_B) { supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | DRM_MODE_REFLECT_X; - } else if (DISPLAY_VER(dev_priv) >= 4) { + } else if (DISPLAY_VER(display) >= 4) { supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180; } else { supported_rotations = DRM_MODE_ROTATE_0; } - if (DISPLAY_VER(dev_priv) >= 4) + if (DISPLAY_VER(display) >= 4) drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0, supported_rotations); @@ -912,7 +1113,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) zpos = 0; drm_plane_create_zpos_immutable_property(&plane->base, zpos); - drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs); + intel_plane_helper_add(plane); return plane; @@ -925,32 +1126,32 @@ fail: static int i9xx_format_to_fourcc(int format) { switch (format) { - case DISPPLANE_8BPP: + case DISP_FORMAT_8BPP: return DRM_FORMAT_C8; - case DISPPLANE_BGRA555: + case DISP_FORMAT_BGRA555: return DRM_FORMAT_ARGB1555; - case DISPPLANE_BGRX555: + case DISP_FORMAT_BGRX555: return DRM_FORMAT_XRGB1555; - case DISPPLANE_BGRX565: + case DISP_FORMAT_BGRX565: return DRM_FORMAT_RGB565; default: - case DISPPLANE_BGRX888: + case DISP_FORMAT_BGRX888: return DRM_FORMAT_XRGB8888; - case DISPPLANE_RGBX888: + case DISP_FORMAT_RGBX888: return DRM_FORMAT_XBGR8888; - case DISPPLANE_BGRA888: + case DISP_FORMAT_BGRA888: return DRM_FORMAT_ARGB8888; - case DISPPLANE_RGBA888: + case DISP_FORMAT_RGBA888: return DRM_FORMAT_ABGR8888; - case DISPPLANE_BGRX101010: + case DISP_FORMAT_BGRX101010: return DRM_FORMAT_XRGB2101010; - case DISPPLANE_RGBX101010: + case DISP_FORMAT_RGBX101010: return DRM_FORMAT_XBGR2101010; - case DISPPLANE_BGRA101010: + case DISP_FORMAT_BGRA101010: return DRM_FORMAT_ARGB2101010; - case DISPPLANE_RGBA101010: + case DISP_FORMAT_RGBA101010: return DRM_FORMAT_ABGR2101010; - case DISPPLANE_RGBX161616: + case DISP_FORMAT_RGBX161616: return DRM_FORMAT_XBGR16161616F; } } @@ -959,8 +1160,7 @@ void i9xx_get_initial_plane_config(struct intel_crtc *crtc, struct intel_initial_plane_config *plane_config) { - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_display *display = to_intel_display(crtc); struct intel_plane *plane = to_intel_plane(crtc->base.primary); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; enum pipe pipe; @@ -973,70 +1173,101 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, if (!plane->get_hw_state(plane, &pipe)) return; - drm_WARN_ON(dev, pipe != crtc->pipe); + drm_WARN_ON(display->drm, pipe != crtc->pipe); - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + intel_fb = intel_framebuffer_alloc(); if (!intel_fb) { - drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); + drm_dbg_kms(display->drm, "failed to alloc fb\n"); return; } fb = &intel_fb->base; - fb->dev = dev; + fb->dev = display->drm; - val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + val = intel_de_read(display, DSPCNTR(display, i9xx_plane)); - if (DISPLAY_VER(dev_priv) >= 4) { - if (val & DISPPLANE_TILED) { - plane_config->tiling = I915_TILING_X; + if (DISPLAY_VER(display) >= 4) { + if (val & DISP_TILED) fb->modifier = I915_FORMAT_MOD_X_TILED; - } - if (val & DISPPLANE_ROTATE_180) + if (val & DISP_ROTATE_180) plane_config->rotation = DRM_MODE_ROTATE_180; } - if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B && - val & DISPPLANE_MIRROR) + if (display->platform.cherryview && + pipe == PIPE_B && val & DISP_MIRROR) plane_config->rotation |= DRM_MODE_REFLECT_X; - pixel_format = val & DISPPLANE_PIXFORMAT_MASK; + pixel_format = val & DISP_FORMAT_MASK; fourcc = i9xx_format_to_fourcc(pixel_format); - fb->format = drm_format_info(fourcc); - - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - offset = intel_de_read(dev_priv, DSPOFFSET(i9xx_plane)); - base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; - } else if (DISPLAY_VER(dev_priv) >= 4) { - if (plane_config->tiling) - offset = intel_de_read(dev_priv, - DSPTILEOFF(i9xx_plane)); + + fb->format = drm_get_format_info(display->drm, fourcc, fb->modifier); + + if (display->platform.haswell || display->platform.broadwell) { + offset = intel_de_read(display, + DSPOFFSET(display, i9xx_plane)); + base = intel_de_read(display, DSPSURF(display, i9xx_plane)) & DISP_ADDR_MASK; + } else if (DISPLAY_VER(display) >= 4) { + if (fb->modifier == I915_FORMAT_MOD_X_TILED) + offset = intel_de_read(display, + DSPTILEOFF(display, i9xx_plane)); else - offset = intel_de_read(dev_priv, - DSPLINOFF(i9xx_plane)); - base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; + offset = intel_de_read(display, + DSPLINOFF(display, i9xx_plane)); + base = intel_de_read(display, DSPSURF(display, i9xx_plane)) & DISP_ADDR_MASK; } else { - base = intel_de_read(dev_priv, DSPADDR(i9xx_plane)); + offset = 0; + base = intel_de_read(display, DSPADDR(display, i9xx_plane)); } plane_config->base = base; - val = intel_de_read(dev_priv, PIPESRC(pipe)); - fb->width = ((val >> 16) & 0xfff) + 1; - fb->height = ((val >> 0) & 0xfff) + 1; + drm_WARN_ON(display->drm, offset != 0); - val = intel_de_read(dev_priv, DSPSTRIDE(i9xx_plane)); + val = intel_de_read(display, PIPESRC(display, pipe)); + fb->width = REG_FIELD_GET(PIPESRC_WIDTH_MASK, val) + 1; + fb->height = REG_FIELD_GET(PIPESRC_HEIGHT_MASK, val) + 1; + + val = intel_de_read(display, DSPSTRIDE(display, i9xx_plane)); fb->pitches[0] = val & 0xffffffc0; aligned_height = intel_fb_align_height(fb, 0, fb->height); plane_config->size = fb->pitches[0] * aligned_height; - drm_dbg_kms(&dev_priv->drm, - "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - crtc->base.name, plane->base.name, fb->width, fb->height, - fb->format->cpp[0] * 8, base, fb->pitches[0], - plane_config->size); + drm_dbg_kms(display->drm, + "[CRTC:%d:%s][PLANE:%d:%s] with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", + crtc->base.base.id, crtc->base.name, + plane->base.base.id, plane->base.name, + fb->width, fb->height, fb->format->cpp[0] * 8, + base, fb->pitches[0], plane_config->size); plane_config->fb = intel_fb; } + +bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config) +{ + struct intel_display *display = to_intel_display(crtc); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + const struct intel_plane_state *plane_state = + to_intel_plane_state(plane->base.state); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + + if (!plane_state->uapi.visible) + return false; + + /* + * We may have moved the surface to a different + * part of ggtt, make the plane aware of that. + */ + if (plane_config->base == plane_state->surf) + return false; + + if (DISPLAY_VER(display) >= 4) + intel_de_write(display, DSPSURF(display, i9xx_plane), plane_state->surf); + else + intel_de_write(display, DSPADDR(display, i9xx_plane), plane_state->surf); + + return true; +} |
