diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/i9xx_plane.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/i9xx_plane.c | 224 |
1 files changed, 171 insertions, 53 deletions
diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index 91f2bc405cba..48e657a80a16 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -8,8 +8,10 @@ #include <drm/drm_blend.h> #include <drm/drm_fourcc.h> +#include "i915_drv.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" @@ -224,8 +226,8 @@ static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state, 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_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); const struct drm_framebuffer *fb = plane_state->hw.fb; int src_x, src_y, src_w; u32 offset; @@ -266,7 +268,7 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) * 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); + 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].mapping_stride) { @@ -415,14 +417,15 @@ static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state, return DIV_ROUND_UP(pixel_rate * num, den); } -static void i9xx_plane_update_noarm(struct intel_plane *plane, +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); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane), + intel_de_write_fw(dev_priv, DSPSTRIDE(dev_priv, i9xx_plane), plane_state->view.color_plane[0].mapping_stride); if (DISPLAY_VER(dev_priv) < 4) { @@ -436,14 +439,15 @@ static void i9xx_plane_update_noarm(struct intel_plane *plane, * generator but let's assume we still need to * program whatever is there. */ - intel_de_write_fw(dev_priv, DSPPOS(i9xx_plane), + intel_de_write_fw(dev_priv, DSPPOS(dev_priv, i9xx_plane), DISP_POS_Y(crtc_y) | DISP_POS_X(crtc_x)); - intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane), + intel_de_write_fw(dev_priv, DSPSIZE(dev_priv, i9xx_plane), DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1)); } } -static void i9xx_plane_update_arm(struct intel_plane *plane, +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) { @@ -455,6 +459,11 @@ static void i9xx_plane_update_arm(struct intel_plane *plane, 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; + linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); if (DISPLAY_VER(dev_priv) >= 4) @@ -468,20 +477,21 @@ static void i9xx_plane_update_arm(struct intel_plane *plane, int crtc_w = drm_rect_width(&plane_state->uapi.dst); int crtc_h = drm_rect_height(&plane_state->uapi.dst); - intel_de_write_fw(dev_priv, PRIMPOS(i9xx_plane), + intel_de_write_fw(dev_priv, PRIMPOS(dev_priv, i9xx_plane), PRIM_POS_Y(crtc_y) | PRIM_POS_X(crtc_x)); - intel_de_write_fw(dev_priv, PRIMSIZE(i9xx_plane), + intel_de_write_fw(dev_priv, PRIMSIZE(dev_priv, i9xx_plane), PRIM_HEIGHT(crtc_h - 1) | PRIM_WIDTH(crtc_w - 1)); - intel_de_write_fw(dev_priv, PRIMCNSTALPHA(i9xx_plane), 0); + intel_de_write_fw(dev_priv, + PRIMCNSTALPHA(dev_priv, i9xx_plane), 0); } if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - intel_de_write_fw(dev_priv, DSPOFFSET(i9xx_plane), + intel_de_write_fw(dev_priv, DSPOFFSET(dev_priv, i9xx_plane), DISP_OFFSET_Y(y) | DISP_OFFSET_X(x)); } else if (DISPLAY_VER(dev_priv) >= 4) { - intel_de_write_fw(dev_priv, DSPLINOFF(i9xx_plane), + intel_de_write_fw(dev_priv, DSPLINOFF(dev_priv, i9xx_plane), linear_offset); - intel_de_write_fw(dev_priv, DSPTILEOFF(i9xx_plane), + intel_de_write_fw(dev_priv, DSPTILEOFF(dev_priv, i9xx_plane), DISP_OFFSET_Y(y) | DISP_OFFSET_X(x)); } @@ -490,17 +500,18 @@ static void i9xx_plane_update_arm(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); + intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr); if (DISPLAY_VER(dev_priv) >= 4) - intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), + intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); else - intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), + intel_de_write_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); } -static void i830_plane_update_arm(struct intel_plane *plane, +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) { @@ -510,11 +521,12 @@ static void i830_plane_update_arm(struct intel_plane *plane, * Additional breakage on i830 causes register reads to return * the last latched value instead of the last written value [ALM026]. */ - i9xx_plane_update_noarm(plane, crtc_state, plane_state); - i9xx_plane_update_arm(plane, crtc_state, plane_state); + i9xx_plane_update_noarm(dsb, plane, crtc_state, plane_state); + i9xx_plane_update_arm(dsb, plane, crtc_state, plane_state); } -static void i9xx_plane_disable_arm(struct intel_plane *plane, +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); @@ -533,16 +545,17 @@ static void i9xx_plane_disable_arm(struct intel_plane *plane, */ dspcntr = i9xx_plane_ctl_crtc(crtc_state); - intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); + intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr); if (DISPLAY_VER(dev_priv) >= 4) - intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0); + intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane), 0); else - intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0); + intel_de_write_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane), 0); } 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) @@ -555,14 +568,15 @@ g4x_primary_async_flip(struct intel_plane *plane, if (async_flip) dspcntr |= DISP_ASYNC_FLIP; - intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); + intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr); - intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), + intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); } 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) @@ -571,7 +585,7 @@ vlv_primary_async_flip(struct intel_plane *plane, u32 dspaddr_offset = plane_state->view.color_plane[0].offset; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - intel_de_write_fw(dev_priv, DSPADDR_VLV(i9xx_plane), + intel_de_write_fw(dev_priv, DSPADDR_VLV(dev_priv, i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); } @@ -679,7 +693,7 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane, if (!wakeref) return false; - val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + val = intel_de_read(dev_priv, DSPCNTR(dev_priv, i9xx_plane)); ret = val & DISP_ENABLE; @@ -736,25 +750,87 @@ i965_plane_max_stride(struct intel_plane *plane, } static unsigned int -i9xx_plane_max_stride(struct intel_plane *plane, +i915_plane_max_stride(struct intel_plane *plane, u32 pixel_format, 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, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + if (plane->i9xx_plane == PLANE_C) + return 4 * 1024; + else + return 8 * 1024; +} + +static unsigned int vlv_primary_min_alignment(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + + switch (fb->modifier) { + case I915_FORMAT_MOD_X_TILED: + if (HAS_ASYNC_FLIPS(i915)) + return 256 * 1024; + 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 drm_i915_private *i915 = to_i915(plane->base.dev); + + switch (fb->modifier) { + case I915_FORMAT_MOD_X_TILED: + if (HAS_ASYNC_FLIPS(i915)) + return 256 * 1024; + return 4 * 1024; + 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, @@ -849,8 +925,10 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) if (HAS_GMCH(dev_priv)) { if (DISPLAY_VER(dev_priv) >= 4) plane->max_stride = i965_plane_max_stride; + else if (DISPLAY_VER(dev_priv) == 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)) plane->max_stride = hsw_primary_max_stride; @@ -858,6 +936,15 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) plane->max_stride = ilk_primary_max_stride; } + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + plane->min_alignment = vlv_primary_min_alignment; + else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv)) + plane->min_alignment = g4x_primary_min_alignment; + else if (DISPLAY_VER(dev_priv) == 4) + plane->min_alignment = i965_plane_min_alignment; + else + plane->min_alignment = i9xx_plane_min_alignment; + if (IS_I830(dev_priv) || IS_I845G(dev_priv)) { plane->update_arm = i830_plane_update_arm; } else { @@ -873,7 +960,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) 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->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; @@ -1002,7 +1089,7 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, fb->dev = dev; - val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + val = intel_de_read(dev_priv, DSPCNTR(dev_priv, i9xx_plane)); if (DISPLAY_VER(dev_priv) >= 4) { if (val & DISP_TILED) { @@ -1023,29 +1110,30 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, 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)) & DISP_ADDR_MASK; + offset = intel_de_read(dev_priv, + DSPOFFSET(dev_priv, i9xx_plane)); + base = intel_de_read(dev_priv, DSPSURF(dev_priv, i9xx_plane)) & DISP_ADDR_MASK; } else if (DISPLAY_VER(dev_priv) >= 4) { if (plane_config->tiling) offset = intel_de_read(dev_priv, - DSPTILEOFF(i9xx_plane)); + DSPTILEOFF(dev_priv, i9xx_plane)); else offset = intel_de_read(dev_priv, - DSPLINOFF(i9xx_plane)); - base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & DISP_ADDR_MASK; + DSPLINOFF(dev_priv, i9xx_plane)); + base = intel_de_read(dev_priv, DSPSURF(dev_priv, i9xx_plane)) & DISP_ADDR_MASK; } else { offset = 0; - base = intel_de_read(dev_priv, DSPADDR(i9xx_plane)); + base = intel_de_read(dev_priv, DSPADDR(dev_priv, i9xx_plane)); } plane_config->base = base; drm_WARN_ON(&dev_priv->drm, offset != 0); - val = intel_de_read(dev_priv, PIPESRC(pipe)); + val = intel_de_read(dev_priv, PIPESRC(dev_priv, 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(dev_priv, DSPSTRIDE(i9xx_plane)); + val = intel_de_read(dev_priv, DSPSTRIDE(dev_priv, i9xx_plane)); fb->pitches[0] = val & 0xffffffc0; aligned_height = intel_fb_align_height(fb, 0, fb->height); @@ -1060,3 +1148,33 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, plane_config->fb = intel_fb; } + +bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc, + const struct intel_initial_plane_config *plane_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + 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; + u32 base; + + if (!plane_state->uapi.visible) + return false; + + base = intel_plane_ggtt_offset(plane_state); + + /* + * We may have moved the surface to a different + * part of ggtt, make the plane aware of that. + */ + if (plane_config->base == base) + return false; + + if (DISPLAY_VER(dev_priv) >= 4) + intel_de_write(dev_priv, DSPSURF(dev_priv, i9xx_plane), base); + else + intel_de_write(dev_priv, DSPADDR(dev_priv, i9xx_plane), base); + + return true; +} |