drm/i915: Add display WA for planes ending close to right screen edge

As described in the WA on GLK and CNL planes on the right edge of the
screen that have less than 4 pixels visible from the beginning of the
plane to the edge of the screen can cause FIFO underflow and display
corruption.

On GLK/CNL I could trigger the problem only if the plane was at the same
time also aligned to the top edge of the screen (after clipping) and
there were exactly 2 pixels visible from the start of the plane to the
right edge of the screen (so couldn't trigger it with 1 or 3 pixels
visible). Nevertheless, to be sure, I also applied the WA for these cases.

I also couldn't see any problem with the cursor plane and later Art
confirmed that it's not affected, so the WA is applied only for the
other plane types.

v2:
- Use -ERANGE instead of -EINVAL. (Chris)

Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180116112415.22060-1-imre.deak@intel.com
This commit is contained in:
Imre Deak 2018-01-16 13:24:14 +02:00
parent 3393ce1ed8
commit c322c64952
3 changed files with 27 additions and 6 deletions

View File

@ -2931,14 +2931,19 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state
return true;
}
static int skl_check_main_surface(struct intel_plane_state *plane_state)
static int skl_check_main_surface(const struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
unsigned int rotation = plane_state->base.rotation;
int x = plane_state->base.src.x1 >> 16;
int y = plane_state->base.src.y1 >> 16;
int w = drm_rect_width(&plane_state->base.src) >> 16;
int h = drm_rect_height(&plane_state->base.src) >> 16;
int dst_x = plane_state->base.dst.x1;
int pipe_src_w = crtc_state->pipe_src_w;
int max_width = skl_max_plane_width(fb, 0, rotation);
int max_height = 4096;
u32 alignment, offset, aux_offset = plane_state->aux.offset;
@ -2949,6 +2954,20 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
return -EINVAL;
}
/*
* Display WA #1175: cnl,glk
* Planes other than the cursor may cause FIFO underflow and display
* corruption if starting less than 4 pixels from the right edge of
* the screen.
*/
if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) &&
dst_x > pipe_src_w - 4) {
DRM_DEBUG_KMS("requested plane X start position %d invalid (valid range %d-%d)\n",
dst_x,
0, pipe_src_w - 4);
return -ERANGE;
}
intel_add_fb_offsets(&x, &y, plane_state, 0);
offset = intel_compute_tile_offset(&x, &y, plane_state, 0);
alignment = intel_surf_alignment(fb, 0);
@ -3073,7 +3092,8 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
return 0;
}
int skl_check_plane_surface(struct intel_plane_state *plane_state)
int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
unsigned int rotation = plane_state->base.rotation;
@ -3113,7 +3133,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
plane_state->aux.y = 0;
}
ret = skl_check_main_surface(plane_state);
ret = skl_check_main_surface(crtc_state, plane_state);
if (ret)
return ret;
@ -12778,7 +12798,7 @@ intel_check_primary_plane(struct intel_plane *plane,
return 0;
if (INTEL_GEN(dev_priv) >= 9) {
ret = skl_check_plane_surface(state);
ret = skl_check_plane_surface(crtc_state, state);
if (ret)
return ret;

View File

@ -1507,7 +1507,8 @@ u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state);
u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane,
unsigned int rotation);
int skl_check_plane_surface(struct intel_plane_state *plane_state);
int skl_check_plane_surface(const struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state);
int i9xx_check_plane_surface(struct intel_plane_state *plane_state);
/* intel_csr.c */

View File

@ -1028,7 +1028,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
dst->y2 = crtc_y + crtc_h;
if (INTEL_GEN(dev_priv) >= 9) {
ret = skl_check_plane_surface(state);
ret = skl_check_plane_surface(crtc_state, state);
if (ret)
return ret;