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: Ville 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
This commit is contained in:
parent
75343a44c9
commit
659056f257
|
@ -9178,6 +9178,31 @@ static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
|
|||
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,
|
||||
const struct intel_plane_state *plane_state)
|
||||
{
|
||||
|
@ -9203,6 +9228,68 @@ static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
|
|||
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,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
const struct intel_plane_state *plane_state)
|
||||
|
@ -9298,6 +9385,88 @@ static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
|
|||
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,
|
||||
const struct intel_crtc_state *crtc_state,
|
||||
const struct intel_plane_state *plane_state)
|
||||
|
@ -9340,42 +9509,6 @@ static void i9xx_disable_cursor(struct intel_plane *plane,
|
|||
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 */
|
||||
static struct drm_display_mode load_detect_mode = {
|
||||
|
@ -13668,73 +13801,6 @@ fail:
|
|||
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 *
|
||||
intel_cursor_plane_create(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe)
|
||||
|
@ -13763,14 +13829,15 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv,
|
|||
cursor->plane = pipe;
|
||||
cursor->id = PLANE_CURSOR;
|
||||
cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe);
|
||||
cursor->check_plane = intel_check_cursor_plane;
|
||||
|
||||
if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
|
||||
cursor->update_plane = i845_update_cursor;
|
||||
cursor->disable_plane = i845_disable_cursor;
|
||||
cursor->check_plane = i845_check_cursor;
|
||||
} else {
|
||||
cursor->update_plane = i9xx_update_cursor;
|
||||
cursor->disable_plane = i9xx_disable_cursor;
|
||||
cursor->check_plane = i9xx_check_cursor;
|
||||
}
|
||||
|
||||
cursor->cursor.base = ~0;
|
||||
|
|
Loading…
Reference in New Issue