Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+171 −104
Original line number Diff line number Diff line
@@ -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 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
	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;