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.lankho...@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.syrj...@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
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to