Commit 659056f2 authored by Ville Syrjälä's avatar Ville Syrjälä

drm/i915: Split cursor check_plane into i845 and i9xx variants

The 845/865 and 830/855/9xx+ style cursor don't have that
much in common with each other, so let's just split the
.check_plane() hook into two variants as well.

v2: Keep the common stuff in one place (Chris)
v3: s/DRM_FORMAT_MOD_NONE/DRM_FORMAT_MOD_LINEAR/

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> #v1
Link: http://patchwork.freedesktop.org/patch/msgid/20170327185546.2977-9-ville.syrjala@linux.intel.com
parent 75343a44
...@@ -9178,6 +9178,31 @@ static u32 intel_cursor_position(const struct intel_plane_state *plane_state) ...@@ -9178,6 +9178,31 @@ static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
return pos; return pos;
} }
static int intel_check_cursor(struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
int ret;
ret = drm_plane_helper_check_state(&plane_state->base,
&plane_state->clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
if (ret)
return ret;
if (!fb)
return 0;
if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
DRM_DEBUG_KMS("cursor cannot be tiled\n");
return -EINVAL;
}
return 0;
}
static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state, static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state) const struct intel_plane_state *plane_state)
{ {
...@@ -9203,6 +9228,68 @@ static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state, ...@@ -9203,6 +9228,68 @@ static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
CURSOR_STRIDE(stride); CURSOR_STRIDE(stride);
} }
static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
int width = plane_state->base.crtc_w;
int height = plane_state->base.crtc_h;
if (width == 0 || height == 0)
return false;
/*
* 845g/865g are only limited by the width of their cursors,
* the height is arbitrary up to the precision of the register.
*/
if (!IS_ALIGNED(width, 64))
return false;
if (width > (IS_I845G(dev_priv) ? 64 : 512))
return false;
if (height > 1023)
return false;
return true;
}
static int i845_check_cursor(struct intel_plane *plane,
struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
const struct drm_framebuffer *fb = plane_state->base.fb;
const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
unsigned int stride;
int ret;
ret = intel_check_cursor(crtc_state, plane_state);
if (ret)
return ret;
/* if we want to turn off the cursor ignore width and height */
if (!obj)
return 0;
/* Check for which cursor types we support */
if (!i845_cursor_size_ok(plane_state)) {
DRM_DEBUG("Cursor dimension %dx%d not supported\n",
plane_state->base.crtc_w,
plane_state->base.crtc_h);
return -EINVAL;
}
stride = roundup_pow_of_two(plane_state->base.crtc_w) * 4;
if (obj->base.size < stride * plane_state->base.crtc_h) {
DRM_DEBUG_KMS("buffer is too small\n");
return -ENOMEM;
}
plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
return 0;
}
static void i845_update_cursor(struct intel_plane *plane, static void i845_update_cursor(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state) const struct intel_plane_state *plane_state)
...@@ -9298,6 +9385,88 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, ...@@ -9298,6 +9385,88 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
return cntl; return cntl;
} }
static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv =
to_i915(plane_state->base.plane->dev);
int width = plane_state->base.crtc_w;
int height = plane_state->base.crtc_h;
if (width == 0 || height == 0)
return false;
/*
* Cursors are limited to a few power-of-two
* sizes, and they must be square.
*/
switch (width | height) {
case 256:
case 128:
if (IS_GEN2(dev_priv))
return false;
case 64:
break;
default:
return false;
}
return true;
}
static int i9xx_check_cursor(struct intel_plane *plane,
struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = plane_state->base.fb;
const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
enum pipe pipe = plane->pipe;
unsigned int stride;
int ret;
ret = intel_check_cursor(crtc_state, plane_state);
if (ret)
return ret;
/* if we want to turn off the cursor ignore width and height */
if (!obj)
return 0;
/* Check for which cursor types we support */
if (!i9xx_cursor_size_ok(plane_state)) {
DRM_DEBUG("Cursor dimension %dx%d not supported\n",
plane_state->base.crtc_w,
plane_state->base.crtc_h);
return -EINVAL;
}
stride = roundup_pow_of_two(plane_state->base.crtc_w) * 4;
if (obj->base.size < stride * plane_state->base.crtc_h) {
DRM_DEBUG_KMS("buffer is too small\n");
return -ENOMEM;
}
/*
* There's something wrong with the cursor on CHV pipe C.
* If it straddles the left edge of the screen then
* moving it away from the edge or disabling it often
* results in a pipe underrun, and often that can lead to
* dead pipe (constant underrun reported, and it scans
* out just a solid color). To recover from that, the
* display power well must be turned off and on again.
* Refuse the put the cursor into that compromised position.
*/
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
plane_state->base.visible && plane_state->base.crtc_x < 0) {
DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
return -EINVAL;
}
plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
return 0;
}
static void i9xx_update_cursor(struct intel_plane *plane, static void i9xx_update_cursor(struct intel_plane *plane,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state) const struct intel_plane_state *plane_state)
...@@ -9340,42 +9509,6 @@ static void i9xx_disable_cursor(struct intel_plane *plane, ...@@ -9340,42 +9509,6 @@ static void i9xx_disable_cursor(struct intel_plane *plane,
i9xx_update_cursor(plane, NULL, NULL); i9xx_update_cursor(plane, NULL, NULL);
} }
static bool cursor_size_ok(struct drm_i915_private *dev_priv,
uint32_t width, uint32_t height)
{
if (width == 0 || height == 0)
return false;
/*
* 845g/865g are special in that they are only limited by
* the width of their cursors, the height is arbitrary up to
* the precision of the register. Everything else requires
* square cursors, limited to a few power-of-two sizes.
*/
if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
if ((width & 63) != 0)
return false;
if (width > (IS_I845G(dev_priv) ? 64 : 512))
return false;
if (height > 1023)
return false;
} else {
switch (width | height) {
case 256:
case 128:
if (IS_GEN2(dev_priv))
return false;
case 64:
break;
default:
return false;
}
}
return true;
}
/* VESA 640x480x72Hz mode to set on the pipe */ /* VESA 640x480x72Hz mode to set on the pipe */
static struct drm_display_mode load_detect_mode = { static struct drm_display_mode load_detect_mode = {
...@@ -13668,73 +13801,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) ...@@ -13668,73 +13801,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
static int
intel_check_cursor_plane(struct intel_plane *plane,
struct intel_crtc_state *crtc_state,
struct intel_plane_state *state)
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
const struct drm_framebuffer *fb = state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
enum pipe pipe = plane->pipe;
unsigned stride;
int ret;
ret = drm_plane_helper_check_state(&state->base,
&state->clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
true, true);
if (ret)
return ret;
/* if we want to turn off the cursor ignore width and height */
if (!obj)
return 0;
/* Check for which cursor types we support */
if (!cursor_size_ok(dev_priv, state->base.crtc_w,
state->base.crtc_h)) {
DRM_DEBUG("Cursor dimension %dx%d not supported\n",
state->base.crtc_w, state->base.crtc_h);
return -EINVAL;
}
stride = roundup_pow_of_two(state->base.crtc_w) * 4;
if (obj->base.size < stride * state->base.crtc_h) {
DRM_DEBUG_KMS("buffer is too small\n");
return -ENOMEM;
}
if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
DRM_DEBUG_KMS("cursor cannot be tiled\n");
return -EINVAL;
}
/*
* There's something wrong with the cursor on CHV pipe C.
* If it straddles the left edge of the screen then
* moving it away from the edge or disabling it often
* results in a pipe underrun, and often that can lead to
* dead pipe (constant underrun reported, and it scans
* out just a solid color). To recover from that, the
* display power well must be turned off and on again.
* Refuse the put the cursor into that compromised position.
*/
if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
state->base.visible && state->base.crtc_x < 0) {
DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
return -EINVAL;
}
if (IS_I845G(dev_priv) || IS_I865G(dev_priv))
state->ctl = i845_cursor_ctl(crtc_state, state);
else
state->ctl = i9xx_cursor_ctl(crtc_state, state);
return 0;
}
static struct intel_plane * static struct intel_plane *
intel_cursor_plane_create(struct drm_i915_private *dev_priv, intel_cursor_plane_create(struct drm_i915_private *dev_priv,
enum pipe pipe) enum pipe pipe)
...@@ -13763,14 +13829,15 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, ...@@ -13763,14 +13829,15 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
cursor->plane = pipe; cursor->plane = pipe;
cursor->id = PLANE_CURSOR; cursor->id = PLANE_CURSOR;
cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe); cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe);
cursor->check_plane = intel_check_cursor_plane;
if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) { if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
cursor->update_plane = i845_update_cursor; cursor->update_plane = i845_update_cursor;
cursor->disable_plane = i845_disable_cursor; cursor->disable_plane = i845_disable_cursor;
cursor->check_plane = i845_check_cursor;
} else { } else {
cursor->update_plane = i9xx_update_cursor; cursor->update_plane = i9xx_update_cursor;
cursor->disable_plane = i9xx_disable_cursor; cursor->disable_plane = i9xx_disable_cursor;
cursor->check_plane = i9xx_check_cursor;
} }
cursor->cursor.base = ~0; cursor->cursor.base = ~0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment