From patchwork Mon Feb 15 20:54:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ville Syrjala X-Patchwork-Id: 8318881 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 5FDC0C02AA for ; Mon, 15 Feb 2016 20:56:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2DDF0202C8 for ; Mon, 15 Feb 2016 20:56:00 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id D7014201B9 for ; Mon, 15 Feb 2016 20:55:58 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 771606E6DD; Mon, 15 Feb 2016 20:55:58 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by gabe.freedesktop.org (Postfix) with ESMTP id A935A6E6DD for ; Mon, 15 Feb 2016 20:55:57 +0000 (UTC) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 15 Feb 2016 12:55:57 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,452,1449561600"; d="scan'208";a="912927080" Received: from stinkbox.fi.intel.com (HELO stinkbox) ([10.237.72.174]) by orsmga002.jf.intel.com with SMTP; 15 Feb 2016 12:55:55 -0800 Received: by stinkbox (sSMTP sendmail emulation); Mon, 15 Feb 2016 22:55:54 +0200 From: ville.syrjala@linux.intel.com To: intel-gfx@lists.freedesktop.org Date: Mon, 15 Feb 2016 22:54:57 +0200 Message-Id: <1455569699-27905-20-git-send-email-ville.syrjala@linux.intel.com> X-Mailer: git-send-email 2.4.10 In-Reply-To: <1455569699-27905-1-git-send-email-ville.syrjala@linux.intel.com> References: <1455569699-27905-1-git-send-email-ville.syrjala@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 19/21] drm/i915: Compute display surface offset in the plane check hook for SKL+ X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Ville Syrjälä SKL has nasty limitations with the display surface offsets: * source x offset + width must be less than the stride for X tiled surfaces or the display engine falls over * the surface offset requires lots of alignment (256K or 1M) These facts mean that we can't just pick any suitably aligned tile boundary as the offset and expect the resulting x offset to be useable. The solution is to start with the closest boundary as before, but then keep searhing backwards until we find one that works, or don't. This means we must be prepared to fail, hence the whole surface offset calculation needs to be moved to the .check_plane() hook from the .update_plane() hook. While at it we can check that the source width/height don't exceed maximum plane size limits. We'll store the results of the computation in the plane state to make it easy for the .update_plane() hook to do its thing. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/intel_display.c | 164 +++++++++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_drv.h | 5 ++ drivers/gpu/drm/i915/intel_sprite.c | 33 +++---- 3 files changed, 151 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b1f45d7612e..ad739f79e710 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3011,6 +3011,120 @@ valid_fb: obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit; } +static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane, + unsigned int rotation) +{ + int cpp = drm_format_plane_cpp(fb->pixel_format, plane); + + switch (fb->modifier[plane]) { + case DRM_FORMAT_MOD_NONE: + case I915_FORMAT_MOD_X_TILED: + switch (cpp) { + case 8: + return 4096; + case 4: + case 2: + case 1: + return 8192; + default: + MISSING_CASE(cpp); + break; + } + break; + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + switch (cpp) { + case 8: + return 2048; + case 4: + return 4096; + case 2: + case 1: + return 8192; + default: + MISSING_CASE(cpp); + break; + } + break; + default: + MISSING_CASE(fb->modifier[plane]); + } + + return 2048; +} + +static int skl_check_main_surface(struct intel_plane_state *plane_state) +{ + const struct drm_i915_private *dev_priv = to_i915(plane_state->base.plane->dev); + const struct drm_framebuffer *fb = plane_state->base.fb; + unsigned int rotation = plane_state->base.rotation; + int x = plane_state->src.x1 >> 16; + int y = plane_state->src.y1 >> 16; + int w = drm_rect_width(&plane_state->src) >> 16; + int h = drm_rect_height(&plane_state->src) >> 16; + int max_width = skl_max_plane_width(fb, 0, rotation); + int max_height = 4096; + u32 alignment, offset; + + if (w > max_width || h > max_height) { + DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n", + w, h, max_width, max_height); + return -EINVAL; + } + + intel_add_fb_offsets(&x, &y, plane_state, 0); + offset = intel_compute_tile_offset(&x, &y, plane_state, 0); + + alignment = intel_surf_alignment(dev_priv, fb->modifier[0]); + + /* + * When using an X-tiled surface, the plane blows up + * if the x offset + width exceed the stride. + * + * TODO: linear and Y-tiled seem fine, Yf untested, + */ + if (fb->modifier[0] == I915_FORMAT_MOD_X_TILED) { + int cpp = drm_format_plane_cpp(fb->pixel_format, 0); + + for (;;) { + if ((x + w) * cpp <= fb->pitches[0]) + break; + + if (offset == 0) { + DRM_DEBUG_KMS("Unable to find suitable display surface offset\n"); + return -EINVAL; + } + + offset = intel_adjust_tile_offset(&x, &y, plane_state, 0, + offset, offset - alignment); + } + } + + plane_state->main.offset = offset; + plane_state->main.x = x; + plane_state->main.y = y; + + return 0; +} + +int skl_check_plane_surface(struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->base.fb; + unsigned int rotation = plane_state->base.rotation; + int ret; + + /* Rotate src coordinates to match rotated GTT view */ + if (intel_rotation_90_or_270(rotation)) + drm_rect_rotate(&plane_state->src, + fb->width, fb->height, BIT(DRM_ROTATE_270)); + + ret = skl_check_main_surface(plane_state); + if (ret) + return ret; + + return 0; +} + static void i9xx_update_primary_plane(struct drm_plane *primary, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) @@ -3385,10 +3499,10 @@ static void skylake_update_primary_plane(struct drm_plane *plane, u32 plane_ctl; unsigned int rotation = plane_state->base.rotation; u32 stride = skl_plane_stride(fb, 0, rotation); - u32 surf_addr; + u32 surf_addr = plane_state->main.offset; int scaler_id = plane_state->scaler_id; - int src_x = plane_state->src.x1 >> 16; - int src_y = plane_state->src.y1 >> 16; + int src_x = plane_state->main.x; + int src_y = plane_state->main.y; int src_w = drm_rect_width(&plane_state->src) >> 16; int src_h = drm_rect_height(&plane_state->src) >> 16; int dst_x = plane_state->dst.x1; @@ -3405,26 +3519,6 @@ static void skylake_update_primary_plane(struct drm_plane *plane, plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; plane_ctl |= skl_plane_ctl_rotation(rotation); - if (intel_rotation_90_or_270(rotation)) { - struct drm_rect r = { - .x1 = src_x, - .x2 = src_x + src_w, - .y1 = src_y, - .y2 = src_y + src_h, - }; - - /* Rotate src coordinates to match rotated GTT view */ - drm_rect_rotate(&r, fb->width, fb->height, BIT(DRM_ROTATE_270)); - - src_x = r.x1; - src_y = r.y1; - src_w = drm_rect_width(&r); - src_h = drm_rect_height(&r); - } - - intel_add_fb_offsets(&src_x, &src_y, plane_state, 0); - surf_addr = intel_compute_tile_offset(&src_x, &src_y, plane_state, 0); - /* Sizes are 0 based */ src_w--; src_h--; @@ -14224,6 +14318,7 @@ intel_check_primary_plane(struct drm_plane *plane, int min_scale = DRM_PLANE_HELPER_NO_SCALING; int max_scale = DRM_PLANE_HELPER_NO_SCALING; bool can_position = false; + int ret; if (INTEL_INFO(plane->dev)->gen >= 9) { /* use scaler when colorkey is not required */ @@ -14234,11 +14329,24 @@ intel_check_primary_plane(struct drm_plane *plane, can_position = true; } - return drm_plane_helper_check_update(plane, crtc, fb, &state->src, - &state->dst, &state->clip, - min_scale, max_scale, - can_position, true, - &state->visible); + ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src, + &state->dst, &state->clip, + min_scale, max_scale, + can_position, true, + &state->visible); + if (ret) + return ret; + + if (!fb) + return 0; + + if (INTEL_INFO(plane->dev)->gen >= 9) { + ret = skl_check_plane_surface(state); + if (ret) + return ret; + } + + return 0; } static void intel_begin_crtc_commit(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0c5e90f3b405..bdc793311a08 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -278,6 +278,10 @@ struct intel_plane_state { struct drm_rect src; struct drm_rect dst; struct drm_rect clip; + struct { + u32 offset; + int x, y; + } main; bool visible; /* @@ -1237,6 +1241,7 @@ u32 skl_plane_ctl_tiling(uint64_t fb_modifier); u32 skl_plane_ctl_rotation(unsigned int rotation); u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, unsigned int rotation); +int skl_check_plane_surface(struct intel_plane_state *plane_state); /* intel_csr.c */ void intel_csr_ucode_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 899dbb4d78a8..75bf01d05f7c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -190,15 +190,15 @@ skl_update_plane(struct drm_plane *drm_plane, const int plane = intel_plane->plane + 1; u32 plane_ctl; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 surf_addr; + u32 surf_addr = plane_state->main.offset; unsigned int rotation = plane_state->base.rotation; u32 stride = skl_plane_stride(fb, 0, rotation); int crtc_x = plane_state->dst.x1; int crtc_y = plane_state->dst.y1; uint32_t crtc_w = drm_rect_width(&plane_state->dst); uint32_t crtc_h = drm_rect_height(&plane_state->dst); - uint32_t x = plane_state->src.x1 >> 16; - uint32_t y = plane_state->src.y1 >> 16; + uint32_t x = plane_state->main.x; + uint32_t y = plane_state->main.y; uint32_t src_w = drm_rect_width(&plane_state->src) >> 16; uint32_t src_h = drm_rect_height(&plane_state->src) >> 16; const struct intel_scaler *scaler = @@ -224,26 +224,6 @@ skl_update_plane(struct drm_plane *drm_plane, else if (key->flags & I915_SET_COLORKEY_SOURCE) plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; - if (intel_rotation_90_or_270(rotation)) { - struct drm_rect r = { - .x1 = x, - .x2 = x + src_w, - .y1 = y, - .y2 = y + src_h, - }; - - /* Rotate src coordinates to match rotated GTT view */ - drm_rect_rotate(&r, fb->width, fb->height, BIT(DRM_ROTATE_270)); - - x = r.x1; - y = r.y1; - src_w = drm_rect_width(&r); - src_h = drm_rect_height(&r); - } - - intel_add_fb_offsets(&x, &y, plane_state, 0); - surf_addr = intel_compute_tile_offset(&x, &y, plane_state, 0); - /* Sizes are 0 based */ src_w--; src_h--; @@ -755,6 +735,7 @@ intel_check_sprite_plane(struct drm_plane *plane, int hscale, vscale; int max_scale, min_scale; bool can_scale; + int ret; if (!fb) { state->visible = false; @@ -909,6 +890,12 @@ intel_check_sprite_plane(struct drm_plane *plane, dst->y1 = crtc_y; dst->y2 = crtc_y + crtc_h; + if (INTEL_INFO(dev)->gen >= 9) { + ret = skl_check_plane_surface(state); + if (ret) + return ret; + } + return 0; }