@@ -12957,11 +12957,16 @@ intel_check_primary_plane(struct intel_plane *plane,
{
struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
struct drm_crtc *crtc = state->base.crtc;
+ struct drm_framebuffer *fb = state->base.fb;
int min_scale = DRM_PLANE_HELPER_NO_SCALING;
int max_scale = DRM_PLANE_HELPER_NO_SCALING;
- bool can_position = false;
- int ret;
+ bool can_position = false, can_scale = false;
uint32_t pixel_format = 0;
+ int crtc_x, crtc_y, hscale, vscale, ret;
+ uint32_t src_x, src_y, src_w, src_h, crtc_w, crtc_h;
+ struct drm_rect *src = &state->base.src;
+ struct drm_rect *dst = &state->base.dst;
+ struct drm_rect clip = {};
if (INTEL_GEN(dev_priv) >= 9) {
/* use scaler when colorkey is not required */
@@ -12973,6 +12978,7 @@ intel_check_primary_plane(struct intel_plane *plane,
crtc_state, pixel_format);
}
can_position = true;
+ can_scale = true;
}
ret = drm_atomic_helper_check_plane_state(&state->base,
@@ -12985,6 +12991,123 @@ intel_check_primary_plane(struct intel_plane *plane,
if (!state->base.fb)
return 0;
+ *src = drm_plane_state_src(&state->base);
+ *dst = drm_plane_state_dest(&state->base);
+
+ drm_rect_rotate(src, fb->width << 16, fb->height << 16,
+ state->base.rotation);
+
+ hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
+ WARN_ON(hscale < 0);
+
+ vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
+ WARN_ON(vscale < 0);
+
+ if (crtc_state->base.enable)
+ drm_mode_get_hv_timing(&crtc_state->base.mode,
+ &clip.x2, &clip.y2);
+
+ state->base.visible =
+ drm_rect_clip_scaled(src, dst, &clip, hscale, vscale);
+
+ crtc_x = dst->x1;
+ crtc_y = dst->y1;
+ crtc_w = drm_rect_width(dst);
+ crtc_h = drm_rect_height(dst);
+
+ if (state->base.visible) {
+ /* check again in case clipping clamped the results */
+ hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
+ if (hscale < 0) {
+ DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dst, false);
+
+ return hscale;
+ }
+
+ vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
+ if (vscale < 0) {
+ DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
+ drm_rect_debug_print("src: ", src, true);
+ drm_rect_debug_print("dst: ", dst, false);
+
+ return vscale;
+ }
+
+ /*
+ * Make the source viewport size an exact
+ * multiple of the scaling factors.
+ */
+ drm_rect_adjust_size(src,
+ drm_rect_width(dst) * hscale - drm_rect_width(src),
+ drm_rect_height(dst) * vscale - drm_rect_height(src));
+
+ drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
+ state->base.rotation);
+
+ /*
+ * sanity check to make sure the src
+ * viewport wasn't enlarged
+ */
+ WARN_ON(src->x1 < (int) state->base.src_x ||
+ src->y1 < (int) state->base.src_y ||
+ src->x2 > (int) state->base.src_x + state->base.src_w ||
+ src->y2 > (int) state->base.src_y + state->base.src_h);
+
+ 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 (intel_format_is_yuv(fb->format->format)) {
+ src_x &= ~1;
+ src_w &= ~1;
+
+ if (!can_scale)
+ crtc_w &= ~1;
+
+ if (crtc_w == 0)
+ state->base.visible = false;
+ }
+ }
+
+ /* Check size restrictions when scaling */
+ if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) {
+ unsigned int width_bytes;
+ int cpp = fb->format->cpp[0];
+
+ WARN_ON(!can_scale);
+
+ /* FIXME interlacing min height is 6 */
+
+ if (crtc_w < 3 || crtc_h < 3)
+ state->base.visible = false;
+
+ if (src_w < 3 || src_h < 3)
+ state->base.visible = false;
+
+ width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
+
+ if (INTEL_GEN(dev_priv) < 9 && (src_w > 2048 || src_h > 2048 ||
+ width_bytes > 4096 || fb->pitches[0] > 4096)) {
+ DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
+ return -EINVAL;
+ }
+ }
+
+ if (state->base.visible) {
+ src->x1 = src_x << 16;
+ src->x2 = (src_x + src_w) << 16;
+ src->y1 = src_y << 16;
+ src->y2 = (src_y + src_h) << 16;
+ }
+
+ dst->x1 = crtc_x;
+ dst->x2 = crtc_x + crtc_w;
+ dst->y1 = crtc_y;
+ dst->y2 = crtc_y + crtc_h;
+
if (INTEL_GEN(dev_priv) >= 9) {
ret = skl_check_plane_surface(crtc_state, state);
if (ret)
Patch adds checks to primary plane related to scaling, clipping, rotation and fb formats. These checks currently, were being done only for sprites. These are required for primary plane as well. Credits-to: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Vidya Srinivas <vidya.srinivas@intel.com> --- drivers/gpu/drm/i915/intel_display.c | 127 ++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-)