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

Commit 4e0b83a5 authored by Ville Syrjälä's avatar Ville Syrjälä
Browse files

drm/i915: Extract per-platform plane->check() functions



Split up intel_check_primary_plane() and intel_check_sprite_plane()
into per-platform variants. This way we can get a unified behaviour
between the SKL universal planes, and we stop checking for non-SKL
specific scaling limits for the "sprite" planes. And we now get
a natural place where to add more plarform specific checks.

v2: Split the .check_plane() calling convention change out (José)

Reviewed-by: default avatarJosé Roberto de Souza <jose.souza@intel.com>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180907152413.15761-10-ville.syrjala@linux.intel.com
parent fd6e3c6c
Loading
Loading
Loading
Loading
+47 −69
Original line number Diff line number Diff line
@@ -3355,6 +3355,36 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
	return 0;
}

static int
i9xx_plane_check(struct intel_crtc_state *crtc_state,
		 struct intel_plane_state *plane_state)
{
	int ret;

	ret = drm_atomic_helper_check_plane_state(&plane_state->base,
						  &crtc_state->base,
						  DRM_PLANE_HELPER_NO_SCALING,
						  DRM_PLANE_HELPER_NO_SCALING,
						  false, true);
	if (ret)
		return ret;

	if (!plane_state->base.visible)
		return 0;

	ret = intel_plane_check_src_coordinates(plane_state);
	if (ret)
		return ret;

	ret = i9xx_check_plane_surface(plane_state);
	if (ret)
		return ret;

	plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);

	return 0;
}

static void i9xx_update_plane(struct intel_plane *plane,
			      const struct intel_crtc_state *crtc_state,
			      const struct intel_plane_state *plane_state)
@@ -9691,6 +9721,11 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
	u32 offset;
	int ret;

	if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
		DRM_DEBUG_KMS("cursor cannot be tiled\n");
		return -EINVAL;
	}

	ret = drm_atomic_helper_check_plane_state(&plane_state->base,
						  &crtc_state->base,
						  DRM_PLANE_HELPER_NO_SCALING,
@@ -9699,13 +9734,12 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state,
	if (ret)
		return ret;

	if (!fb)
	if (!plane_state->base.visible)
		return 0;

	if (fb->modifier != DRM_FORMAT_MOD_LINEAR) {
		DRM_DEBUG_KMS("cursor cannot be tiled\n");
		return -EINVAL;
	}
	ret = intel_plane_check_src_coordinates(plane_state);
	if (ret)
		return ret;

	intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation);
	plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation);
@@ -13230,19 +13264,17 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
}

int
skl_max_scale(struct intel_crtc *intel_crtc,
	      struct intel_crtc_state *crtc_state,
	      uint32_t pixel_format)
skl_max_scale(const struct intel_crtc_state *crtc_state,
	      u32 pixel_format)
{
	struct drm_i915_private *dev_priv;
	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
	int max_scale, mult;
	int crtc_clock, max_dotclk, tmpclk1, tmpclk2;

	if (!intel_crtc || !crtc_state->base.enable)
	if (!crtc_state->base.enable)
		return DRM_PLANE_HELPER_NO_SCALING;

	dev_priv = to_i915(intel_crtc->base.dev);

	crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
	max_dotclk = to_intel_atomic_state(crtc_state->base.state)->cdclk.logical.cdclk;

@@ -13266,61 +13298,6 @@ skl_max_scale(struct intel_crtc *intel_crtc,
	return max_scale;
}

static int
intel_check_primary_plane(struct intel_crtc_state *crtc_state,
			  struct intel_plane_state *state)
{
	struct intel_plane *plane = to_intel_plane(state->base.plane);
	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
	struct drm_crtc *crtc = state->base.crtc;
	int min_scale = DRM_PLANE_HELPER_NO_SCALING;
	int max_scale = DRM_PLANE_HELPER_NO_SCALING;
	bool can_position = false;
	int ret;
	uint32_t pixel_format = 0;

	if (INTEL_GEN(dev_priv) >= 9) {
		/* use scaler when colorkey is not required */
		if (!state->ckey.flags) {
			min_scale = 1;
			if (state->base.fb)
				pixel_format = state->base.fb->format->format;
			max_scale = skl_max_scale(to_intel_crtc(crtc),
						  crtc_state, pixel_format);
		}
		can_position = true;
	}

	ret = drm_atomic_helper_check_plane_state(&state->base,
						  &crtc_state->base,
						  min_scale, max_scale,
						  can_position, true);
	if (ret)
		return ret;

	if (!state->base.fb)
		return 0;

	if (INTEL_GEN(dev_priv) >= 9) {
		ret = skl_check_plane_surface(crtc_state, state);
		if (ret)
			return ret;

		state->ctl = skl_plane_ctl(crtc_state, state);
	} else {
		ret = i9xx_check_plane_surface(state);
		if (ret)
			return ret;

		state->ctl = i9xx_plane_ctl(crtc_state, state);
	}

	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
		state->color_ctl = glk_plane_color_ctl(crtc_state, state);

	return 0;
}

static void intel_begin_crtc_commit(struct drm_crtc *crtc,
				    struct drm_crtc_state *old_crtc_state)
{
@@ -13770,8 +13747,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
		fbc->possible_framebuffer_bits |= primary->frontbuffer_bit;
	}

	primary->check_plane = intel_check_primary_plane;

	if (INTEL_GEN(dev_priv) >= 9) {
		primary->has_ccs = skl_plane_has_ccs(dev_priv, pipe,
						     PLANE_PRIMARY);
@@ -13793,6 +13768,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
		primary->update_plane = skl_update_plane;
		primary->disable_plane = skl_disable_plane;
		primary->get_hw_state = skl_plane_get_hw_state;
		primary->check_plane = skl_plane_check;

		plane_funcs = &skl_plane_funcs;
	} else if (INTEL_GEN(dev_priv) >= 4) {
@@ -13804,6 +13780,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
		primary->update_plane = i9xx_update_plane;
		primary->disable_plane = i9xx_disable_plane;
		primary->get_hw_state = i9xx_plane_get_hw_state;
		primary->check_plane = i9xx_plane_check;

		plane_funcs = &i965_plane_funcs;
	} else {
@@ -13815,6 +13792,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
		primary->update_plane = i9xx_update_plane;
		primary->disable_plane = i9xx_disable_plane;
		primary->get_hw_state = i9xx_plane_get_hw_state;
		primary->check_plane = i9xx_plane_check;

		plane_funcs = &i8xx_plane_funcs;
	}
+5 −3
Original line number Diff line number Diff line
@@ -1645,8 +1645,8 @@ void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,

u16 skl_scaler_calc_phase(int sub, bool chroma_center);
int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
		  uint32_t pixel_format);
int skl_max_scale(const struct intel_crtc_state *crtc_state,
		  u32 pixel_format);

static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
{
@@ -2137,7 +2137,9 @@ bool skl_plane_has_planar(struct drm_i915_private *dev_priv,
unsigned int skl_plane_max_stride(struct intel_plane *plane,
				  u32 pixel_format, u64 modifier,
				  unsigned int rotation);

int skl_plane_check(struct intel_crtc_state *crtc_state,
		    struct intel_plane_state *plane_state);
int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state);

/* intel_tv.c */
void intel_tv_init(struct drm_i915_private *dev_priv);
+191 −112
Original line number Diff line number Diff line
@@ -230,6 +230,39 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
#endif
}

int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state)
{
	const struct drm_framebuffer *fb = plane_state->base.fb;
	struct drm_rect *src = &plane_state->base.src;
	u32 src_x, src_y, src_w, src_h;

	/*
	 * Hardware doesn't handle subpixel coordinates.
	 * Adjust to (macro)pixel boundary, but be careful not to
	 * increase the source viewport size, because that could
	 * push the downscaling factor out of bounds.
	 */
	src_x = src->x1 >> 16;
	src_w = drm_rect_width(src) >> 16;
	src_y = src->y1 >> 16;
	src_h = drm_rect_height(src) >> 16;

	src->x1 = src_x << 16;
	src->x2 = (src_x + src_w) << 16;
	src->y1 = src_y << 16;
	src->y2 = (src_y + src_h) << 16;

	if (fb->format->is_yuv &&
	    fb->format->format != DRM_FORMAT_NV12 &&
	    (src_x & 1 || src_w & 1)) {
		DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n",
			      src_x, src_w);
		return -EINVAL;
	}

	return 0;
}

unsigned int
skl_plane_max_stride(struct intel_plane *plane,
		     u32 pixel_format, u64 modifier,
@@ -985,49 +1018,75 @@ g4x_plane_get_hw_state(struct intel_plane *plane,
}

static int
intel_check_sprite_plane(struct intel_crtc_state *crtc_state,
			 struct intel_plane_state *state)
g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,
			 struct intel_plane_state *plane_state)
{
	struct intel_plane *plane = to_intel_plane(state->base.plane);
	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
	struct drm_framebuffer *fb = state->base.fb;
	int max_scale, min_scale;
	int ret;
	uint32_t pixel_format = 0;
	const struct drm_framebuffer *fb = plane_state->base.fb;
	const struct drm_rect *src = &plane_state->base.src;
	const struct drm_rect *dst = &plane_state->base.dst;
	int src_x, src_y, src_w, src_h, crtc_w, crtc_h;
	const struct drm_display_mode *adjusted_mode =
		&crtc_state->base.adjusted_mode;
	unsigned int cpp = fb->format->cpp[0];
	unsigned int width_bytes;
	int min_width, min_height;

	crtc_w = drm_rect_width(dst);
	crtc_h = drm_rect_height(dst);

	src_x = src->x1 >> 16;
	src_y = src->y1 >> 16;
	src_w = drm_rect_width(src) >> 16;
	src_h = drm_rect_height(src) >> 16;

	if (!fb) {
		state->base.visible = false;
	if (src_w == crtc_w && src_h == crtc_h)
		return 0;

	min_width = 3;

	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
		if (src_h & 1) {
			DRM_DEBUG_KMS("Source height must be even with interlaced modes\n");
			return -EINVAL;
		}
		min_height = 6;
	} else {
		min_height = 3;
	}

	/* Don't modify another pipe's plane */
	if (plane->pipe != crtc->pipe) {
		DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n");
	width_bytes = ((src_x * cpp) & 63) + src_w * cpp;

	if (src_w < min_width || src_h < min_height ||
	    src_w > 2048 || src_h > 2048) {
		DRM_DEBUG_KMS("Source dimensions (%dx%d) exceed hardware limits (%dx%d - %dx%d)\n",
			      src_w, src_h, min_width, min_height, 2048, 2048);
		return -EINVAL;
	}

	/* FIXME check all gen limits */
	if (fb->width < 3 || fb->height < 3 ||
	    fb->pitches[0] > plane->max_stride(plane, fb->format->format,
					       fb->modifier, DRM_MODE_ROTATE_0)) {
		DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
	if (width_bytes > 4096) {
		DRM_DEBUG_KMS("Fetch width (%d) exceeds hardware max with scaling (%u)\n",
			      width_bytes, 4096);
		return -EINVAL;
	}

	if (INTEL_GEN(dev_priv) >= 9) {
		if (state->base.fb)
			pixel_format = state->base.fb->format->format;
		/* use scaler when colorkey is not required */
		if (!state->ckey.flags) {
			min_scale = 1;
			max_scale =
				skl_max_scale(crtc, crtc_state, pixel_format);
		} else {
			min_scale = DRM_PLANE_HELPER_NO_SCALING;
			max_scale = DRM_PLANE_HELPER_NO_SCALING;
	if (width_bytes > 4096 || fb->pitches[0] > 4096) {
		DRM_DEBUG_KMS("Stride (%u) exceeds hardware max with scaling (%u)\n",
			      fb->pitches[0], 4096);
		return -EINVAL;
	}
	} else {

	return 0;
}

static int
g4x_sprite_check(struct intel_crtc_state *crtc_state,
		 struct intel_plane_state *plane_state)
{
	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
	int max_scale, min_scale;
	int ret;

	if (INTEL_GEN(dev_priv) < 7) {
		min_scale = 1;
		max_scale = 16 << 16;
@@ -1038,93 +1097,110 @@ intel_check_sprite_plane(struct intel_crtc_state *crtc_state,
		min_scale = DRM_PLANE_HELPER_NO_SCALING;
		max_scale = DRM_PLANE_HELPER_NO_SCALING;
	}
	}

	ret = drm_atomic_helper_check_plane_state(&state->base,
	ret = drm_atomic_helper_check_plane_state(&plane_state->base,
						  &crtc_state->base,
						  min_scale, max_scale,
						  true, true);
	if (ret)
		return ret;

	if (state->base.visible) {
		struct drm_rect *src = &state->base.src;
		struct drm_rect *dst = &state->base.dst;
		unsigned int crtc_w = drm_rect_width(dst);
		unsigned int crtc_h = drm_rect_height(dst);
		uint32_t src_x, src_y, src_w, src_h;

		/*
		 * Hardware doesn't handle subpixel coordinates.
		 * Adjust to (macro)pixel boundary, but be careful not to
		 * increase the source viewport size, because that could
		 * push the downscaling factor out of bounds.
		 */
		src_x = src->x1 >> 16;
		src_w = drm_rect_width(src) >> 16;
		src_y = src->y1 >> 16;
		src_h = drm_rect_height(src) >> 16;
	if (!plane_state->base.visible)
		return 0;

		src->x1 = src_x << 16;
		src->x2 = (src_x + src_w) << 16;
		src->y1 = src_y << 16;
		src->y2 = (src_y + src_h) << 16;
	ret = intel_plane_check_src_coordinates(plane_state);
	if (ret)
		return ret;

		if (fb->format->is_yuv &&
    		    fb->format->format != DRM_FORMAT_NV12 &&
		    (src_x % 2 || src_w % 2)) {
			DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n",
				      src_x, src_w);
			return -EINVAL;
		}
	ret = g4x_sprite_check_scaling(crtc_state, plane_state);
	if (ret)
		return ret;

		/* Check size restrictions when scaling */
		if (src_w != crtc_w || src_h != crtc_h) {
			unsigned int width_bytes;
			int cpp = fb->format->cpp[0];
	ret = i9xx_check_plane_surface(plane_state);
	if (ret)
		return ret;

			width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
	if (INTEL_GEN(dev_priv) >= 7)
		plane_state->ctl = ivb_sprite_ctl(crtc_state, plane_state);
	else
		plane_state->ctl = g4x_sprite_ctl(crtc_state, plane_state);

			/* FIXME interlacing min height is 6 */
			if (INTEL_GEN(dev_priv) < 9 && (
			     src_w < 3 || src_h < 3 ||
			     src_w > 2048 || src_h > 2048 ||
			     crtc_w < 3 || crtc_h < 3 ||
			     width_bytes > 4096 || fb->pitches[0] > 4096)) {
				DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
				return -EINVAL;
			}
		}
	return 0;
}

	if (INTEL_GEN(dev_priv) >= 9) {
		ret = skl_check_plane_surface(crtc_state, state);
static int
vlv_sprite_check(struct intel_crtc_state *crtc_state,
		 struct intel_plane_state *plane_state)
{
	int ret;

	ret = drm_atomic_helper_check_plane_state(&plane_state->base,
						  &crtc_state->base,
						  DRM_PLANE_HELPER_NO_SCALING,
						  DRM_PLANE_HELPER_NO_SCALING,
						  true, true);
	if (ret)
		return ret;

		state->ctl = skl_plane_ctl(crtc_state, state);
	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
		ret = i9xx_check_plane_surface(state);
	if (!plane_state->base.visible)
		return 0;

	ret = intel_plane_check_src_coordinates(plane_state);
	if (ret)
		return ret;

		state->ctl = vlv_sprite_ctl(crtc_state, state);
	} else if (INTEL_GEN(dev_priv) >= 7) {
		ret = i9xx_check_plane_surface(state);
	ret = i9xx_check_plane_surface(plane_state);
	if (ret)
		return ret;

		state->ctl = ivb_sprite_ctl(crtc_state, state);
	plane_state->ctl = vlv_sprite_ctl(crtc_state, plane_state);

	return 0;
}

int skl_plane_check(struct intel_crtc_state *crtc_state,
		    struct intel_plane_state *plane_state)
{
	struct intel_plane *plane = to_intel_plane(plane_state->base.plane);
	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
	int max_scale, min_scale;
	int ret;

	/* use scaler when colorkey is not required */
	if (!plane_state->ckey.flags) {
		const struct drm_framebuffer *fb = plane_state->base.fb;

		min_scale = 1;
		max_scale = skl_max_scale(crtc_state,
					  fb ? fb->format->format : 0);
	} else {
		ret = i9xx_check_plane_surface(state);
		min_scale = DRM_PLANE_HELPER_NO_SCALING;
		max_scale = DRM_PLANE_HELPER_NO_SCALING;
	}

	ret = drm_atomic_helper_check_plane_state(&plane_state->base,
						  &crtc_state->base,
						  min_scale, max_scale,
						  true, true);
	if (ret)
		return ret;

		state->ctl = g4x_sprite_ctl(crtc_state, state);
	}
	if (!plane_state->base.visible)
		return 0;

	ret = intel_plane_check_src_coordinates(plane_state);
	if (ret)
		return ret;

	ret = skl_check_plane_surface(crtc_state, plane_state);
	if (ret)
		return ret;

	plane_state->ctl = skl_plane_ctl(crtc_state, plane_state);

	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
		state->color_ctl = glk_plane_color_ctl(crtc_state, state);
		plane_state->color_ctl = glk_plane_color_ctl(crtc_state,
							     plane_state);

	return 0;
}
@@ -1560,6 +1636,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
		intel_plane->update_plane = skl_update_plane;
		intel_plane->disable_plane = skl_disable_plane;
		intel_plane->get_hw_state = skl_plane_get_hw_state;
		intel_plane->check_plane = skl_plane_check;

		if (skl_plane_has_planar(dev_priv, pipe,
					 PLANE_SPRITE0 + plane)) {
@@ -1581,6 +1658,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
		intel_plane->update_plane = vlv_update_plane;
		intel_plane->disable_plane = vlv_disable_plane;
		intel_plane->get_hw_state = vlv_plane_get_hw_state;
		intel_plane->check_plane = vlv_sprite_check;

		plane_formats = vlv_plane_formats;
		num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
@@ -1592,6 +1670,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
		intel_plane->update_plane = ivb_update_plane;
		intel_plane->disable_plane = ivb_disable_plane;
		intel_plane->get_hw_state = ivb_plane_get_hw_state;
		intel_plane->check_plane = g4x_sprite_check;

		plane_formats = snb_plane_formats;
		num_plane_formats = ARRAY_SIZE(snb_plane_formats);
@@ -1603,6 +1682,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
		intel_plane->update_plane = g4x_update_plane;
		intel_plane->disable_plane = g4x_disable_plane;
		intel_plane->get_hw_state = g4x_plane_get_hw_state;
		intel_plane->check_plane = g4x_sprite_check;

		modifiers = i9xx_plane_format_modifiers;
		if (IS_GEN6(dev_priv)) {
@@ -1635,7 +1715,6 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv,
	intel_plane->i9xx_plane = plane;
	intel_plane->id = PLANE_SPRITE0 + plane;
	intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id);
	intel_plane->check_plane = intel_check_sprite_plane;

	possible_crtcs = (1 << pipe);