From patchwork Tue May 29 18:28:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?VmlsbGUgU3lyasOkbMOk?= X-Patchwork-Id: 10436723 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 91392601C7 for ; Tue, 29 May 2018 18:28:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98A40285FF for ; Tue, 29 May 2018 18:28:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8D89028635; Tue, 29 May 2018 18:28:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id A7D69285FF for ; Tue, 29 May 2018 18:28:21 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 13E336E513; Tue, 29 May 2018 18:28:21 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTPS id 010ED6E50D for ; Tue, 29 May 2018 18:28:16 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 29 May 2018 11:28:16 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,457,1520924400"; d="scan'208";a="43731307" Received: from stinkbox.fi.intel.com (HELO stinkbox) ([10.237.72.174]) by fmsmga008.fm.intel.com with SMTP; 29 May 2018 11:28:14 -0700 Received: by stinkbox (sSMTP sendmail emulation); Tue, 29 May 2018 21:28:13 +0300 From: Ville Syrjala To: intel-gfx@lists.freedesktop.org Date: Tue, 29 May 2018 21:28:03 +0300 Message-Id: <20180529182804.8571-4-ville.syrjala@linux.intel.com> X-Mailer: git-send-email 2.16.1 In-Reply-To: <20180529182804.8571-1-ville.syrjala@linux.intel.com> References: <20180529182804.8571-1-ville.syrjala@linux.intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 4/5] drm/i915: Make primary/sprite zpos configurable on VLV/CHV X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 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-Virus-Scanned: ClamAV using ClamSMTP From: Ville Syrjälä VLV/CHV can change the z order between the primary and sprite planes freely. Let's expose that capability by making the zpos property mutable. The cursor plane is always on top, so the cursor zpos is left as an immutable property. The way the hardware is configured is a bit awkward. Both sprite planes have a "bottom" and "zorder" bits, but the way they interact betweens the sprites doesn't seem entirely logical. The spec doesn't even list all 16 possible combinations (just 10 are listed), but I've gone through them all the discovered the following relationship: sprite 0 sprite 1 resulting plane order (bottom to top) B Z B Z 0 0 0 0 P 0 1 d0(see note),d1,d01,d01p 0 0 0 1 P 0 1 * 0 0 1 0 1 P 0 * d0 0 0 1 1 1 P 0 0 1 0 0 P 1 0 * 0 1 0 1 P 0 1 0 1 1 0 1 0 P * dp 0 1 1 1 1 0 P 1 0 0 0 0 P 1 * d1 1 0 0 1 0 1 P * dp 1 0 1 0 P 0 1 1 0 1 1 P 0 1 1 1 0 0 0 P 1 1 1 0 1 0 1 P 1 1 1 0 P 0 1 1 1 1 1 P 0 1 [B=bottom bit Z=zorder bit, 0=sprite 0, 1=sprite 1, P=primary, d0=sprite 0 disabled, d1=sprite 1 disabled, dp=primary disabled, d01=both sprites, d01p=both sprites and primary disabled] Disabling any one or two planes doesn't seem to interfere with the resulting plane order in an unexpected way. The bottom and zorder bits of the disabled planes are still effective though, so we must be careful what we leave in those bits when the plane is disabled. What we do for enabled sprite planes is set bottom=1 if the plane is at the bottom, else we set zorder=1 if the plane is just above the other sprite plane. This will end up picking the configurations marked with * from the table when both sprite planes are enabled. For the disabled plane cases we just leave bottom=0 and zorder=0 for any disabled sprite plane. Any enabled sprite plane will still follow the rule laid out before. For the purposes of that rule, we'll consider any disabled plane to be stacked on top of the enabled planes. This will end up picking the configurations marked d0 when sprite 0 is disabled, d1 when sprite 1 is disabled, dp when the primary is disabled, and d01 when both sprites are disabled (and d01p is actually the same thing with just primary disabled as well). The use of the 'P 0 1' configuration for the first d0 case doesn't really make sense based on the above, but given the way the zorder bits work, there's no nice way to pick the 'P 1 0' (which would be the logical thing) when sprite 0 is disabled as that would require setting the zorder bit in the sprite 0 control register, but as stated we always set both bits to 0 for disabled planes. That way we don't have to reconfigure already disabled planes to change the zorder between the currently active planes, and more imporantly we don't need to consult any plane/crtc state in the .disable_plane() hook. This slight irregularity doesn't matter in the end as both of these configuratios will give us the expected visible 'P 1' result. v2: Redo the final zpos computation to not require every plane on the crtc to be part of the state v3: More polish Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_atomic_plane.c | 8 ++ drivers/gpu/drm/i915/intel_display.c | 146 +++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_display.h | 9 ++ drivers/gpu/drm/i915/intel_drv.h | 7 ++ drivers/gpu/drm/i915/intel_sprite.c | 24 ++++- 6 files changed, 192 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f238b7b33cd9..44eac5ffc2ce 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6265,6 +6265,8 @@ enum { #define SP_ROTATE_180 (1<<15) #define SP_TILED (1<<10) #define SP_MIRROR (1<<8) /* CHV pipe B */ +#define SP_BOTTOM (1<<2) +#define SP_ZORDER (1<<0) #define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184) #define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188) #define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 6d068786eb41..a5a3123589e7 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -193,6 +193,14 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ else crtc_state->nv12_planes &= ~BIT(intel_plane->id); + /* + * Copy over the zpos to the crtc state so that we don't + * need to add every plane on the crtc to the state to + * recompute the final zpos. + */ + crtc_state->raw_zpos[intel_plane->id] = + intel_plane_raw_zpos(crtc_state, intel_state); + return intel_plane_atomic_calc_changes(old_crtc_state, &crtc_state->base, old_plane_state, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bc3de1b5bb89..111cb0c1da54 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -2760,6 +2761,8 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state, crtc_state->active_planes &= ~BIT(plane->id); } + crtc_state->raw_zpos[plane->id] = intel_plane_raw_zpos(crtc_state, plane_state); + DRM_DEBUG_KMS("%s active planes 0x%x\n", crtc_state->base.crtc->name, crtc_state->active_planes); @@ -3208,8 +3211,8 @@ int skl_check_plane_surface(const struct intel_crtc_state *crtc_state, static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = - to_i915(plane_state->base.plane->dev); + struct intel_plane *plane = to_intel_plane(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); const struct drm_framebuffer *fb = plane_state->base.fb; unsigned int rotation = plane_state->base.rotation; @@ -10932,6 +10935,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) struct intel_dpll_hw_state dpll_hw_state; struct intel_shared_dpll *shared_dpll; struct intel_crtc_wm_state wm_state; + u8 raw_zpos[I915_MAX_PLANES]; bool force_thru, ips_force_disable; /* FIXME: before the switch to atomic started, a new pipe_config was @@ -10947,6 +10951,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) wm_state = crtc_state->wm; + memcpy(raw_zpos, crtc_state->raw_zpos, sizeof(raw_zpos)); /* Keep base drm_crtc_state intact, only clear our extended struct */ BUILD_BUG_ON(offsetof(struct intel_crtc_state, base)); @@ -10961,6 +10966,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) crtc_state->wm = wm_state; + memcpy(crtc_state->raw_zpos, raw_zpos, sizeof(raw_zpos)); } static int @@ -12161,6 +12167,130 @@ static int calc_watermark_data(struct drm_atomic_state *state) return 0; } +int intel_plane_raw_zpos(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + + /* + * We'll keep the cursor always at the top regardless of + * whether it's enabled or not. This avoids changes to the + * sorted zpos of other planes when turning the cursor on/off, + * and thus we can easily avoid having to add the other + * planes to the atomic state. + */ + if (plane->id == PLANE_CURSOR) + return 0x20; + + /* + * For other planes we stack the disabled planes on top + * of any enabled planes. This simplifies our life by + * allowing us to keep the SP_BOTTOM and SP_ZORDER bits + * cleared for any disabled planes on VLV/CHV. Thus we + * don't have to worry about zpos in .disable_plane(). + */ + if (plane_state->base.visible) + return plane_state->base.zpos; + else + return 0x10; +} + +struct intel_plane_zpos { + u32 obj_id; + enum plane_id plane_id; + u8 zpos; +}; + +static int intel_zpos_cmp(const void *a, const void *b) +{ + const struct intel_plane_zpos *za = (const struct intel_plane_zpos *)a; + const struct intel_plane_zpos *zb = (const struct intel_plane_zpos *)b; + + if (za->zpos != zb->zpos) + return za->zpos - zb->zpos; + else + return za->obj_id - zb->obj_id; +} + +static void vlv_normalize_zpos(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + struct intel_plane_zpos zpos[I915_MAX_PLANES] = {}; + struct intel_plane *plane; + int i, num_planes; + + i = 0; + for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { + zpos[i].obj_id = plane->base.base.id; + zpos[i].plane_id = plane->id; + zpos[i].zpos = crtc_state->raw_zpos[plane->id]; + i++; + } + + num_planes = i; + + /* sort according to zpos/plane obj id */ + sort(zpos, num_planes, sizeof(zpos[0]), + intel_zpos_cmp, NULL); + + /* copy over sorted zpos */ + for (i = 0; i < num_planes; i++) { + enum plane_id plane_id = zpos[i].plane_id; + + crtc_state->zpos[plane_id] = i; + } +} + +static int vlv_update_zpos(struct drm_i915_private *dev_priv, + struct intel_atomic_state *state) +{ + struct intel_crtc *crtc; + struct intel_crtc_state *old_crtc_state, *new_crtc_state; + int i; + + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + struct drm_plane *plane; + bool sprites_changed; + + vlv_normalize_zpos(new_crtc_state); + + sprites_changed = + memcmp(new_crtc_state->zpos, + old_crtc_state->zpos, + sizeof(new_crtc_state->zpos)) != 0; + + if (!sprites_changed) + continue; + + drm_for_each_plane_mask(plane, &dev_priv->drm, + new_crtc_state->base.plane_mask) { + struct drm_plane_state *plane_state; + enum plane_id plane_id = to_intel_plane(plane)->id; + + if (plane_id == PLANE_CURSOR || + plane_id == PLANE_PRIMARY) + continue; + + /* + * zpos is configured via sprite registers, so must + * add them to the state if anything significant + * changed. + */ + plane_state = drm_atomic_get_plane_state(&state->base, plane); + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); + } + + DRM_DEBUG_KMS("pipe %c zpos sprite %c: %d, sprite %c: %d\n", + pipe_name(crtc->pipe), + sprite_name(crtc->pipe, 0), new_crtc_state->zpos[PLANE_SPRITE0], + sprite_name(crtc->pipe, 1), new_crtc_state->zpos[PLANE_SPRITE1]); + } + + return 0; +} + /** * intel_atomic_check - validate state object * @dev: drm device @@ -12236,7 +12366,14 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + ret = vlv_update_zpos(dev_priv, intel_state); + if (ret) + return ret; + } + intel_fbc_choose_crtc(dev_priv, intel_state); + return calc_watermark_data(state); } @@ -13592,7 +13729,10 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) DRM_COLOR_YCBCR_LIMITED_RANGE); zpos = 0; - drm_plane_create_zpos_immutable_property(&primary->base, zpos); + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + drm_plane_create_zpos_property(&primary->base, zpos, 0, 2); + else + drm_plane_create_zpos_immutable_property(&primary->base, zpos); drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs); diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index 2ef31617614a..09bbd9a3efd6 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -333,6 +333,15 @@ struct intel_link_m_n { (__i)++) \ for_each_if(plane) +#define for_each_oldnew_intel_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \ + for ((__i) = 0; \ + (__i) < (__state)->base.dev->mode_config.num_crtc && \ + ((crtc) = to_intel_crtc((__state)->base.crtcs[__i].ptr), \ + (old_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].old_state), \ + (new_crtc_state) = to_intel_crtc_state((__state)->base.crtcs[__i].new_state), 1); \ + (__i)++) \ + for_each_if(crtc) + void intel_link_compute_m_n(int bpp, int nlanes, int pixel_clock, int link_clock, struct intel_link_m_n *m_n, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fd6256632482..994b9473b817 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -890,6 +890,10 @@ struct intel_crtc_state { u8 active_planes; u8 nv12_planes; + /* VLV/CHV zpos for each plane */ + u8 raw_zpos[I915_MAX_PLANES]; /* raw property value (or 0xff for disabled planes) */ + u8 zpos[I915_MAX_PLANES]; /* final zpos for each plane */ + /* HDMI scrambling status */ bool hdmi_scrambling; @@ -1457,6 +1461,9 @@ void intel_dump_cdclk_state(const struct intel_cdclk_state *cdclk_state, const char *context); /* intel_display.c */ +int intel_plane_raw_zpos(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state); +void intel__enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe); void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe); void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe); enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index a6f4524adff4..228eba582d44 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -511,6 +511,22 @@ static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, return sprctl; } +static u32 vlv_sprctl_zpos(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + enum plane_id plane_id = plane->id; + enum plane_id other_plane_id = plane_id == PLANE_SPRITE0 ? + PLANE_SPRITE1 : PLANE_SPRITE0; + + if (crtc_state->zpos[plane_id] == 0) + return SP_BOTTOM; + else if (crtc_state->zpos[plane_id] == + crtc_state->zpos[other_plane_id] + 1) + return SP_ZORDER; + + return 0; +} + static void vlv_update_plane(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -538,6 +554,9 @@ vlv_update_plane(struct intel_plane *plane, linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); + /* final zpos value is computed after vlv_sprite_ctl() */ + sprctl |= vlv_sprctl_zpos(plane, crtc_state); + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); vlv_update_clrc(plane_state); @@ -1553,7 +1572,10 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, DRM_COLOR_YCBCR_LIMITED_RANGE); zpos = plane + 1; - drm_plane_create_zpos_immutable_property(&intel_plane->base, zpos); + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + drm_plane_create_zpos_property(&intel_plane->base, zpos, 0, 2); + else + drm_plane_create_zpos_immutable_property(&intel_plane->base, zpos); drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);