[Intel-gfx] [PATCH] drm/i915/gen11: Link nv12 Y and UV planes in the atomic state, v5.
Ville Syrjälä
ville.syrjala at linux.intel.com
Mon Oct 22 15:48:22 UTC 2018
On Mon, Oct 22, 2018 at 03:51:52PM +0200, Maarten Lankhorst wrote:
> To make NV12 working on icl, we need to update 2 planes simultaneously.
> I've chosen to do this in the CRTC step after plane validation is done,
> so we know what planes are (in)visible. The linked Y plane will get
> updated in intel_plane_update_planes_on_crtc(), by the call to
> update_slave, which gets the master's plane_state as argument.
>
> The link requires both planes for atomic_update to work,
> so make sure skl_ddb_add_affected_planes() adds both states.
>
> Changes since v1:
> - Introduce icl_is_nv12_y_plane(), instead of hardcoding sprite numbers.
> - Put all the state updating login in intel_plane_atomic_check_with_state().
> - Clean up changes in intel_plane_atomic_check().
> Changes since v2:
> - Fix intel_atomic_get_old_plane_state() to actually return old state.
> - Move visibility changes to preparation patch.
> - Only try to find a Y plane on gen11, earlier platforms only require
> a single plane.
> Changes since v3:
> - Fix checkpatch warning about to_intel_crtc() usage.
> - Add affected planes from icl_add_linked_planes() before check_planes(),
> it's a cleaner way to do this. (Ville)
> Changes since v4:
> - Clear plane links in icl_check_nv12_planes() for clarity.
> - Only pass crtc_state to icl_check_nv12_planes().
> - Use for_each_new_intel_plane_in_state() in icl_check_nv12_planes.
> - Rename aux to linked. (Ville)
>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> ---
> drivers/gpu/drm/i915/intel_atomic_plane.c | 19 +++++
> drivers/gpu/drm/i915/intel_display.c | 95 +++++++++++++++++++++++
> drivers/gpu/drm/i915/intel_drv.h | 53 +++++++++++++
> drivers/gpu/drm/i915/intel_pm.c | 12 ++-
> 4 files changed, 178 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
> index b957ad63cd87..7d3685075201 100644
> --- a/drivers/gpu/drm/i915/intel_atomic_plane.c
> +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
> @@ -188,6 +188,25 @@ void intel_update_planes_on_crtc(struct intel_atomic_state *old_state,
> trace_intel_update_plane(&plane->base, crtc);
>
> plane->update_plane(plane, new_crtc_state, new_plane_state);
> + } else if (new_plane_state->slave) {
> + struct intel_plane *master =
> + new_plane_state->linked_plane;
> +
> + /*
> + * We update the slave plane from this function because
> + * programming it from the master plane's update_plane
> + * callback runs into issues when the Y plane is
> + * reassigned, disabled or used by a different plane.
> + *
> + * The slave plane is updated with the master plane's
> + * plane_state.
> + */
> + new_plane_state =
> + intel_atomic_get_new_plane_state(old_state, master);
> +
> + trace_intel_update_plane(&plane->base, crtc);
> +
> + plane->update_slave(plane, new_crtc_state, new_plane_state);
> } else {
> trace_intel_disable_plane(&plane->base, crtc);
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 68c9aeeee05c..680895982e4f 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10723,6 +10723,95 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state,
> return true;
> }
>
> +static int icl_add_linked_planes(struct intel_atomic_state *state)
> +{
> + struct intel_plane *plane, *linked;
> + struct intel_plane_state *plane_state, *linked_plane_state;
> + int i;
> +
> + for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
> + linked = plane_state->linked_plane;
> +
> + if (!linked)
> + continue;
> +
> + linked_plane_state = intel_atomic_get_plane_state(state, linked);
> + if (IS_ERR(linked_plane_state))
> + return PTR_ERR(linked_plane_state);
WARN_ON(linked_plane_state->linked != plane);
WARN_ON(linked_plane_state->slave == plane_state->slave);
perhaps?
> + }
> +
> + return 0;
> +}
> +
> +static int icl_check_nv12_planes(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_atomic_state *state = to_intel_atomic_state(crtc_state->base.state);
> + struct intel_plane *plane, *linked;
> + struct intel_plane_state *plane_state;
> + int i;
> +
> + if (INTEL_GEN(dev_priv) < 11)
> + return 0;
> +
> + /*
> + * Destroy all old plane links and make the slave plane invisible
> + * in the crtc_state->active_planes mask.
> + */
> + for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
> + if (plane->pipe != crtc->pipe || !plane_state->linked_plane)
> + continue;
> +
> + plane_state->linked_plane = NULL;
> + if (plane_state->slave && !plane_state->base.visible)
Hmm. Was confused for a moment here. Since we do this after the check_plane()
we could indeed have a visible slave plane here.
I wonder if it would be cleaner to do this in icl_add_linked_planes()
instead? Not sure.
Feel free to ignore my bikesheds you think this is better.
Reviewed-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> + crtc_state->active_planes &= ~BIT(plane->id);
> +
> + plane_state->slave = false;
> + }
> +
> + if (!crtc_state->nv12_planes)
> + return 0;
> +
> + for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
> + struct intel_plane_state *linked_state = NULL;
> +
> + if (plane->pipe != crtc->pipe ||
> + !(crtc_state->nv12_planes & BIT(plane->id)))
> + continue;
> +
> + for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, linked) {
> + if (!icl_is_nv12_y_plane(linked->id))
> + continue;
> +
> + if (crtc_state->active_planes & BIT(linked->id))
> + continue;
> +
> + linked_state = intel_atomic_get_plane_state(state, linked);
> + if (IS_ERR(linked_state))
> + return PTR_ERR(linked_state);
> +
> + break;
> + }
> +
> + if (!linked_state) {
> + DRM_DEBUG_KMS("Need %d free Y planes for NV12\n",
> + hweight8(crtc_state->nv12_planes));
> +
> + return -EINVAL;
> + }
> +
> + plane_state->linked_plane = linked;
> +
> + linked_state->slave = true;
> + linked_state->linked_plane = plane;
> + crtc_state->active_planes |= BIT(linked->id);
> + DRM_DEBUG_KMS("Using %s as Y plane for %s\n", linked->base.name, plane->base.name);
> + }
> +
> + return 0;
> +}
> +
> static int intel_crtc_atomic_check(struct drm_crtc *crtc,
> struct drm_crtc_state *crtc_state)
> {
> @@ -10794,6 +10883,8 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
> if (mode_changed)
> ret = skl_update_scaler_crtc(pipe_config);
>
> + if (!ret)
> + ret = icl_check_nv12_planes(pipe_config);
> if (!ret)
> ret = skl_check_pipe_max_pixel_rate(intel_crtc,
> pipe_config);
> @@ -12460,6 +12551,10 @@ static int intel_atomic_check(struct drm_device *dev,
> intel_state->cdclk.logical = dev_priv->cdclk.logical;
> }
>
> + ret = icl_add_linked_planes(intel_state);
> + if (ret)
> + return ret;
> +
> ret = drm_atomic_helper_check_planes(dev, state);
> if (ret)
> return ret;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 0e9a926fca04..59b35293a5f6 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -539,6 +539,26 @@ struct intel_plane_state {
> */
> int scaler_id;
>
> + /*
> + * linked_plane:
> + *
> + * ICL planar formats require 2 planes that are updated as pairs.
> + * This member is used to make sure the other plane is also updated
> + * when required, and for update_slave() to find the correct
> + * plane_state to pass as argument.
> + */
> + struct intel_plane *linked_plane;
> +
> + /*
> + * slave:
> + * If set don't update use the linked plane's state for updating
> + * this plane during atomic commit with the update_slave() callback.
> + *
> + * It's also used by the watermark code to ignore wm calculations on
> + * this plane. They're calculated by the linked plane's wm code.
> + */
> + bool slave;
> +
> struct drm_intel_sprite_colorkey ckey;
> };
>
> @@ -983,6 +1003,9 @@ struct intel_plane {
> void (*update_plane)(struct intel_plane *plane,
> const struct intel_crtc_state *crtc_state,
> const struct intel_plane_state *plane_state);
> + void (*update_slave)(struct intel_plane *plane,
> + const struct intel_crtc_state *crtc_state,
> + const struct intel_plane_state *plane_state);
> void (*disable_plane)(struct intel_plane *plane,
> struct intel_crtc *crtc);
> bool (*get_hw_state)(struct intel_plane *plane, enum pipe *pipe);
> @@ -1351,6 +1374,27 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
> return container_of(intel_hdmi, struct intel_digital_port, hdmi);
> }
>
> +static inline struct intel_plane_state *
> +intel_atomic_get_plane_state(struct intel_atomic_state *state,
> + struct intel_plane *plane)
> +{
> + struct drm_plane_state *ret =
> + drm_atomic_get_plane_state(&state->base, &plane->base);
> +
> + if (IS_ERR(ret))
> + return ERR_CAST(ret);
> +
> + return to_intel_plane_state(ret);
> +}
> +
> +static inline struct intel_plane_state *
> +intel_atomic_get_old_plane_state(struct intel_atomic_state *state,
> + struct intel_plane *plane)
> +{
> + return to_intel_plane_state(drm_atomic_get_old_plane_state(&state->base,
> + &plane->base));
> +}
> +
> static inline struct intel_plane_state *
> intel_atomic_get_new_plane_state(struct intel_atomic_state *state,
> struct intel_plane *plane)
> @@ -2158,6 +2202,15 @@ struct intel_plane *
> skl_universal_plane_create(struct drm_i915_private *dev_priv,
> enum pipe pipe, enum plane_id plane_id);
>
> +static inline bool icl_is_nv12_y_plane(enum plane_id id)
> +{
> + /* Don't need to do a gen check, these planes are only available on gen11 */
> + if (id == PLANE_SPRITE4 || id == PLANE_SPRITE5)
> + return true;
> +
> + return false;
> +}
> +
> /* intel_tv.c */
> void intel_tv_init(struct drm_i915_private *dev_priv);
>
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index f42b8c319046..9ba39a9c7d1c 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -5153,11 +5153,12 @@ skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
> struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
> struct skl_ddb_allocation *new_ddb = &intel_state->wm_results.ddb;
> struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
> - struct drm_plane_state *plane_state;
> struct drm_plane *plane;
> enum pipe pipe = intel_crtc->pipe;
>
> drm_for_each_plane_mask(plane, dev, cstate->base.plane_mask) {
> + struct drm_plane_state *plane_state;
> + struct intel_plane *linked;
> enum plane_id plane_id = to_intel_plane(plane)->id;
>
> if (skl_ddb_entry_equal(&cur_ddb->plane[pipe][plane_id],
> @@ -5169,6 +5170,15 @@ skl_ddb_add_affected_planes(struct intel_crtc_state *cstate)
> plane_state = drm_atomic_get_plane_state(state, plane);
> if (IS_ERR(plane_state))
> return PTR_ERR(plane_state);
> +
> + /* Make sure linked plane is updated too */
> + linked = to_intel_plane_state(plane_state)->linked_plane;
> + if (!linked)
> + continue;
> +
> + plane_state = drm_atomic_get_plane_state(state, &linked->base);
> + if (IS_ERR(plane_state))
> + return PTR_ERR(plane_state);
> }
>
> return 0;
> --
> 2.19.1
--
Ville Syrjälä
Intel
More information about the Intel-gfx
mailing list