On Fri, Oct 09, 2015 at 06:22:43PM -0300, Paulo Zanoni wrote:
> This is a squash of the following commits:
> 
> Revert "drm/i915: Drop intel_update_sprite_watermarks"
> This reverts commit 47c99438b52d12df50e182583634a4cfede3c920.
> 
> Revert "drm/i915/ivb: Move WaCxSRDisabledForSpriteScaling w/a to atomic check"
> This reverts commit 7809e5ae35b9d8d0710f0874b2e3f10be144e38b.
> 
> Revert "drm/i915/skl: Eliminate usage of pipe_wm_parameters from SKL-style WM 
> (v3)"
> This reverts commit 3a05f5e2e78eab7ffe816abb59b6769e331a1957.
> 
> With these reverts, SKL finally stops failing every single FBC test
> with FIFO underrun error messages. After some brief testing, it also
> seems that this commit prevents the machine from completely freezing
> when we run igt/kms_fbc_crc (see fd.o #92355).
> 
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92355
> Cc: Matt Roper <matthew.d.ro...@intel.com>
> Signed-off-by: Paulo Zanoni <paulo.r.zan...@intel.com>

Queued for -next, thanks for the patch.
-Daniel

> ---
>  drivers/gpu/drm/i915/i915_drv.h      |   4 +
>  drivers/gpu/drm/i915/intel_atomic.c  |   1 -
>  drivers/gpu/drm/i915/intel_display.c |  44 +---
>  drivers/gpu/drm/i915/intel_drv.h     |   9 +-
>  drivers/gpu/drm/i915/intel_pm.c      | 419 
> +++++++++++++++++++++--------------
>  drivers/gpu/drm/i915/intel_sprite.c  |  15 ++
>  6 files changed, 293 insertions(+), 199 deletions(-)
> 
> 
> The fact that I needed more reverts after rebasing suggests that maybe the
> problem is happening due to some sort of timing problem? Maybe we're missing
> some lock?
> 
> The machine freezes while running igt/kms_fbc_crc/blt are also curious, but I
> didn't spend too much time investigating them.
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index bf14096..22c8b0a 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -628,6 +628,10 @@ struct drm_i915_display_funcs {
>                         struct dpll *match_clock,
>                         struct dpll *best_clock);
>       void (*update_wm)(struct drm_crtc *crtc);
> +     void (*update_sprite_wm)(struct drm_plane *plane,
> +                              struct drm_crtc *crtc,
> +                              uint32_t sprite_width, uint32_t sprite_height,
> +                              int pixel_size, bool enable, bool scaled);
>       int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
>       void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
>       /* Returns the active state of the crtc, and if the crtc is active,
> diff --git a/drivers/gpu/drm/i915/intel_atomic.c 
> b/drivers/gpu/drm/i915/intel_atomic.c
> index 05b1203..f1975f2 100644
> --- a/drivers/gpu/drm/i915/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> @@ -94,7 +94,6 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
>       __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base);
>  
>       crtc_state->update_pipe = false;
> -     crtc_state->disable_lp_wm = false;
>  
>       return &crtc_state->base;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_display.c 
> b/drivers/gpu/drm/i915/intel_display.c
> index cddb0c6..66a37d8 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4804,6 +4804,7 @@ static void intel_post_plane_update(struct intel_crtc 
> *crtc)
>       struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
>       struct drm_device *dev = crtc->base.dev;
>       struct drm_i915_private *dev_priv = dev->dev_private;
> +     struct drm_plane *plane;
>  
>       if (atomic->wait_vblank)
>               intel_wait_for_vblank(dev, crtc->pipe);
> @@ -4822,6 +4823,10 @@ static void intel_post_plane_update(struct intel_crtc 
> *crtc)
>       if (atomic->post_enable_primary)
>               intel_post_enable_primary(&crtc->base);
>  
> +     drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks)
> +             intel_update_sprite_watermarks(plane, &crtc->base,
> +                                            0, 0, 0, false, false);
> +
>       memset(atomic, 0, sizeof(*atomic));
>  }
>  
> @@ -11577,30 +11582,16 @@ retry:
>  static bool intel_wm_need_update(struct drm_plane *plane,
>                                struct drm_plane_state *state)
>  {
> -     struct intel_plane_state *new = to_intel_plane_state(state);
> -     struct intel_plane_state *cur = to_intel_plane_state(plane->state);
> -
> -     /* Update watermarks on tiling or size changes. */
> +     /* Update watermarks on tiling changes. */
>       if (!plane->state->fb || !state->fb ||
>           plane->state->fb->modifier[0] != state->fb->modifier[0] ||
> -         plane->state->rotation != state->rotation ||
> -         drm_rect_width(&new->src) != drm_rect_width(&cur->src) ||
> -         drm_rect_height(&new->src) != drm_rect_height(&cur->src) ||
> -         drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) ||
> -         drm_rect_height(&new->dst) != drm_rect_height(&cur->dst))
> +         plane->state->rotation != state->rotation)
>               return true;
>  
> -     return false;
> -}
> -
> -static bool needs_scaling(struct intel_plane_state *state)
> -{
> -     int src_w = drm_rect_width(&state->src) >> 16;
> -     int src_h = drm_rect_height(&state->src) >> 16;
> -     int dst_w = drm_rect_width(&state->dst);
> -     int dst_h = drm_rect_height(&state->dst);
> +     if (plane->state->crtc_w != state->crtc_w)
> +             return true;
>  
> -     return (src_w != dst_w || src_h != dst_h);
> +     return false;
>  }
>  
>  int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
> @@ -11618,6 +11609,7 @@ int intel_plane_atomic_calc_changes(struct 
> drm_crtc_state *crtc_state,
>       bool mode_changed = needs_modeset(crtc_state);
>       bool was_crtc_enabled = crtc->state->active;
>       bool is_crtc_enabled = crtc_state->active;
> +
>       bool turn_off, turn_on, visible, was_visible;
>       struct drm_framebuffer *fb = plane_state->fb;
>  
> @@ -11735,23 +11727,11 @@ int intel_plane_atomic_calc_changes(struct 
> drm_crtc_state *crtc_state,
>       case DRM_PLANE_TYPE_CURSOR:
>               break;
>       case DRM_PLANE_TYPE_OVERLAY:
> -             /*
> -              * WaCxSRDisabledForSpriteScaling:ivb
> -              *
> -              * cstate->update_wm was already set above, so this flag will
> -              * take effect when we commit and program watermarks.
> -              */
> -             if (IS_IVYBRIDGE(dev) &&
> -                 needs_scaling(to_intel_plane_state(plane_state)) &&
> -                 !needs_scaling(old_plane_state)) {
> -                     to_intel_crtc_state(crtc_state)->disable_lp_wm = true;
> -             } else if (turn_off && !mode_changed) {
> +             if (turn_off && !mode_changed) {
>                       intel_crtc->atomic.wait_vblank = true;
>                       intel_crtc->atomic.update_sprite_watermarks |=
>                               1 << i;
>               }
> -
> -             break;
>       }
>       return 0;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h 
> b/drivers/gpu/drm/i915/intel_drv.h
> index 91b6b40..0598932 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -468,9 +468,6 @@ struct intel_crtc_state {
>  
>       /* w/a for waiting 2 vblanks during crtc enable */
>       enum pipe hsw_workaround_pipe;
> -
> -     /* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */
> -     bool disable_lp_wm;
>  };
>  
>  struct vlv_wm_state {
> @@ -1399,6 +1396,12 @@ void intel_init_clock_gating(struct drm_device *dev);
>  void intel_suspend_hw(struct drm_device *dev);
>  int ilk_wm_max_level(const struct drm_device *dev);
>  void intel_update_watermarks(struct drm_crtc *crtc);
> +void intel_update_sprite_watermarks(struct drm_plane *plane,
> +                                 struct drm_crtc *crtc,
> +                                 uint32_t sprite_width,
> +                                 uint32_t sprite_height,
> +                                 int pixel_size,
> +                                 bool enabled, bool scaled);
>  void intel_init_pm(struct drm_device *dev);
>  void intel_pm_setup(struct drm_device *dev);
>  void intel_gpu_ips_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 d031d74..d13551f 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -1765,6 +1765,13 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t 
> horiz_pixels,
>       return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
>  }
>  
> +struct skl_pipe_wm_parameters {
> +     bool active;
> +     uint32_t pipe_htotal;
> +     uint32_t pixel_rate; /* in KHz */
> +     struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
> +};
> +
>  struct ilk_wm_maximums {
>       uint16_t pri;
>       uint16_t spr;
> @@ -2805,40 +2812,18 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
>  #define SKL_DDB_SIZE         896     /* in blocks */
>  #define BXT_DDB_SIZE         512
>  
> -/*
> - * Return the index of a plane in the SKL DDB and wm result arrays.  Primary
> - * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and
> - * other universal planes are in indices 1..n.  Note that this may leave 
> unused
> - * indices between the top "sprite" plane and the cursor.
> - */
> -static int
> -skl_wm_plane_id(const struct intel_plane *plane)
> -{
> -     switch (plane->base.type) {
> -     case DRM_PLANE_TYPE_PRIMARY:
> -             return 0;
> -     case DRM_PLANE_TYPE_CURSOR:
> -             return PLANE_CURSOR;
> -     case DRM_PLANE_TYPE_OVERLAY:
> -             return plane->plane + 1;
> -     default:
> -             MISSING_CASE(plane->base.type);
> -             return plane->plane;
> -     }
> -}
> -
>  static void
>  skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
> -                                const struct intel_crtc_state *cstate,
> +                                struct drm_crtc *for_crtc,
>                                  const struct intel_wm_config *config,
> +                                const struct skl_pipe_wm_parameters *params,
>                                  struct skl_ddb_entry *alloc /* out */)
>  {
> -     struct drm_crtc *for_crtc = cstate->base.crtc;
>       struct drm_crtc *crtc;
>       unsigned int pipe_size, ddb_size;
>       int nth_active_pipe;
>  
> -     if (!cstate->base.active) {
> +     if (!params->active) {
>               alloc->start = 0;
>               alloc->end = 0;
>               return;
> @@ -2904,29 +2889,19 @@ void skl_ddb_get_hw_state(struct drm_i915_private 
> *dev_priv,
>  }
>  
>  static unsigned int
> -skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
> -                          const struct drm_plane_state *pstate,
> -                          int y)
> +skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int 
> y)
>  {
> -     struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
> -     struct drm_framebuffer *fb = pstate->fb;
>  
>       /* for planar format */
> -     if (fb->pixel_format == DRM_FORMAT_NV12) {
> +     if (p->y_bytes_per_pixel) {
>               if (y)  /* y-plane data rate */
> -                     return intel_crtc->config->pipe_src_w *
> -                             intel_crtc->config->pipe_src_h *
> -                             drm_format_plane_cpp(fb->pixel_format, 0);
> +                     return p->horiz_pixels * p->vert_pixels * 
> p->y_bytes_per_pixel;
>               else    /* uv-plane data rate */
> -                     return (intel_crtc->config->pipe_src_w/2) *
> -                             (intel_crtc->config->pipe_src_h/2) *
> -                             drm_format_plane_cpp(fb->pixel_format, 1);
> +                     return (p->horiz_pixels/2) * (p->vert_pixels/2) * 
> p->bytes_per_pixel;
>       }
>  
>       /* for packed formats */
> -     return intel_crtc->config->pipe_src_w *
> -             intel_crtc->config->pipe_src_h *
> -             drm_format_plane_cpp(fb->pixel_format, 0);
> +     return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
>  }
>  
>  /*
> @@ -2935,51 +2910,46 @@ skl_plane_relative_data_rate(const struct 
> intel_crtc_state *cstate,
>   *   3 * 4096 * 8192  * 4 < 2^32
>   */
>  static unsigned int
> -skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate)
> +skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc,
> +                              const struct skl_pipe_wm_parameters *params)
>  {
> -     struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
> -     struct drm_device *dev = intel_crtc->base.dev;
> -     const struct intel_plane *intel_plane;
>       unsigned int total_data_rate = 0;
> +     int plane;
>  
> -     for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
> -             const struct drm_plane_state *pstate = intel_plane->base.state;
> +     for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
> +             const struct intel_plane_wm_parameters *p;
>  
> -             if (pstate->fb == NULL)
> +             p = &params->plane[plane];
> +             if (!p->enabled)
>                       continue;
>  
> -             /* packed/uv */
> -             total_data_rate += skl_plane_relative_data_rate(cstate,
> -                                                             pstate,
> -                                                             0);
> -
> -             if (pstate->fb->pixel_format == DRM_FORMAT_NV12)
> -                     /* y-plane */
> -                     total_data_rate += skl_plane_relative_data_rate(cstate,
> -                                                                     pstate,
> -                                                                     1);
> +             total_data_rate += skl_plane_relative_data_rate(p, 0); /* 
> packed/uv */
> +             if (p->y_bytes_per_pixel) {
> +                     total_data_rate += skl_plane_relative_data_rate(p, 1); 
> /* y-plane */
> +             }
>       }
>  
>       return total_data_rate;
>  }
>  
>  static void
> -skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
> +skl_allocate_pipe_ddb(struct drm_crtc *crtc,
>                     const struct intel_wm_config *config,
> +                   const struct skl_pipe_wm_parameters *params,
>                     struct skl_ddb_allocation *ddb /* out */)
>  {
> -     struct drm_crtc *crtc = cstate->base.crtc;
>       struct drm_device *dev = crtc->dev;
> +     struct drm_i915_private *dev_priv = dev->dev_private;
>       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -     struct intel_plane *intel_plane;
>       enum pipe pipe = intel_crtc->pipe;
>       struct skl_ddb_entry *alloc = &ddb->pipe[pipe];
>       uint16_t alloc_size, start, cursor_blocks;
>       uint16_t minimum[I915_MAX_PLANES];
>       uint16_t y_minimum[I915_MAX_PLANES];
>       unsigned int total_data_rate;
> +     int plane;
>  
> -     skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc);
> +     skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc);
>       alloc_size = skl_ddb_entry_size(alloc);
>       if (alloc_size == 0) {
>               memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
> @@ -2996,20 +2966,17 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
>       alloc->end -= cursor_blocks;
>  
>       /* 1. Allocate the mininum required blocks for each active plane */
> -     for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
> -             struct drm_plane *plane = &intel_plane->base;
> -             struct drm_framebuffer *fb = plane->fb;
> -             int id = skl_wm_plane_id(intel_plane);
> +     for_each_plane(dev_priv, pipe, plane) {
> +             const struct intel_plane_wm_parameters *p;
>  
> -             if (fb == NULL)
> -                     continue;
> -             if (plane->type == DRM_PLANE_TYPE_CURSOR)
> +             p = &params->plane[plane];
> +             if (!p->enabled)
>                       continue;
>  
> -             minimum[id] = 8;
> -             alloc_size -= minimum[id];
> -             y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0;
> -             alloc_size -= y_minimum[id];
> +             minimum[plane] = 8;
> +             alloc_size -= minimum[plane];
> +             y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0;
> +             alloc_size -= y_minimum[plane];
>       }
>  
>       /*
> @@ -3018,50 +2985,45 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
>        *
>        * FIXME: we may not allocate every single block here.
>        */
> -     total_data_rate = skl_get_total_relative_data_rate(cstate);
> +     total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
>  
>       start = alloc->start;
> -     for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
> -             struct drm_plane *plane = &intel_plane->base;
> -             struct drm_plane_state *pstate = intel_plane->base.state;
> +     for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
> +             const struct intel_plane_wm_parameters *p;
>               unsigned int data_rate, y_data_rate;
>               uint16_t plane_blocks, y_plane_blocks = 0;
> -             int id = skl_wm_plane_id(intel_plane);
>  
> -             if (pstate->fb == NULL)
> -                     continue;
> -             if (plane->type == DRM_PLANE_TYPE_CURSOR)
> +             p = &params->plane[plane];
> +             if (!p->enabled)
>                       continue;
>  
> -             data_rate = skl_plane_relative_data_rate(cstate, pstate, 0);
> +             data_rate = skl_plane_relative_data_rate(p, 0);
>  
>               /*
>                * allocation for (packed formats) or (uv-plane part of planar 
> format):
>                * promote the expression to 64 bits to avoid overflowing, the
>                * result is < available as data_rate / total_data_rate < 1
>                */
> -             plane_blocks = minimum[id];
> +             plane_blocks = minimum[plane];
>               plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
>                                       total_data_rate);
>  
> -             ddb->plane[pipe][id].start = start;
> -             ddb->plane[pipe][id].end = start + plane_blocks;
> +             ddb->plane[pipe][plane].start = start;
> +             ddb->plane[pipe][plane].end = start + plane_blocks;
>  
>               start += plane_blocks;
>  
>               /*
>                * allocation for y_plane part of planar format:
>                */
> -             if (pstate->fb->pixel_format == DRM_FORMAT_NV12) {
> -                     y_data_rate = skl_plane_relative_data_rate(cstate,
> -                                                                pstate,
> -                                                                1);
> -                     y_plane_blocks = y_minimum[id];
> +             if (p->y_bytes_per_pixel) {
> +                     y_data_rate = skl_plane_relative_data_rate(p, 1);
> +                     y_plane_blocks = y_minimum[plane];
>                       y_plane_blocks += div_u64((uint64_t)alloc_size * 
> y_data_rate,
>                                               total_data_rate);
>  
> -                     ddb->y_plane[pipe][id].start = start;
> -                     ddb->y_plane[pipe][id].end = start + y_plane_blocks;
> +                     ddb->y_plane[pipe][plane].start = start;
> +                     ddb->y_plane[pipe][plane].end = start + y_plane_blocks;
>  
>                       start += y_plane_blocks;
>               }
> @@ -3148,21 +3110,87 @@ static void skl_compute_wm_global_parameters(struct 
> drm_device *dev,
>                                            struct intel_wm_config *config)
>  {
>       struct drm_crtc *crtc;
> +     struct drm_plane *plane;
>  
>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
>               config->num_pipes_active += to_intel_crtc(crtc)->active;
> +
> +     /* FIXME: I don't think we need those two global parameters on SKL */
> +     list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> +             struct intel_plane *intel_plane = to_intel_plane(plane);
> +
> +             config->sprites_enabled |= intel_plane->wm.enabled;
> +             config->sprites_scaled |= intel_plane->wm.scaled;
> +     }
> +}
> +
> +static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
> +                                        struct skl_pipe_wm_parameters *p)
> +{
> +     struct drm_device *dev = crtc->dev;
> +     struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +     enum pipe pipe = intel_crtc->pipe;
> +     struct drm_plane *plane;
> +     struct drm_framebuffer *fb;
> +     int i = 1; /* Index for sprite planes start */
> +
> +     p->active = intel_crtc->active;
> +     if (p->active) {
> +             p->pipe_htotal = 
> intel_crtc->config->base.adjusted_mode.crtc_htotal;
> +             p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
> +
> +             fb = crtc->primary->state->fb;
> +             /* For planar: Bpp is for uv plane, y_Bpp is for y plane */
> +             if (fb) {
> +                     p->plane[0].enabled = true;
> +                     p->plane[0].bytes_per_pixel = fb->pixel_format == 
> DRM_FORMAT_NV12 ?
> +                             drm_format_plane_cpp(fb->pixel_format, 1) :
> +                             drm_format_plane_cpp(fb->pixel_format, 0);
> +                     p->plane[0].y_bytes_per_pixel = fb->pixel_format == 
> DRM_FORMAT_NV12 ?
> +                             drm_format_plane_cpp(fb->pixel_format, 0) : 0;
> +                     p->plane[0].tiling = fb->modifier[0];
> +             } else {
> +                     p->plane[0].enabled = false;
> +                     p->plane[0].bytes_per_pixel = 0;
> +                     p->plane[0].y_bytes_per_pixel = 0;
> +                     p->plane[0].tiling = DRM_FORMAT_MOD_NONE;
> +             }
> +             p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
> +             p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
> +             p->plane[0].rotation = crtc->primary->state->rotation;
> +
> +             fb = crtc->cursor->state->fb;
> +             p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0;
> +             if (fb) {
> +                     p->plane[PLANE_CURSOR].enabled = true;
> +                     p->plane[PLANE_CURSOR].bytes_per_pixel = 
> fb->bits_per_pixel / 8;
> +                     p->plane[PLANE_CURSOR].horiz_pixels = 
> crtc->cursor->state->crtc_w;
> +                     p->plane[PLANE_CURSOR].vert_pixels = 
> crtc->cursor->state->crtc_h;
> +             } else {
> +                     p->plane[PLANE_CURSOR].enabled = false;
> +                     p->plane[PLANE_CURSOR].bytes_per_pixel = 0;
> +                     p->plane[PLANE_CURSOR].horiz_pixels = 64;
> +                     p->plane[PLANE_CURSOR].vert_pixels = 64;
> +             }
> +     }
> +
> +     list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
> +             struct intel_plane *intel_plane = to_intel_plane(plane);
> +
> +             if (intel_plane->pipe == pipe &&
> +                     plane->type == DRM_PLANE_TYPE_OVERLAY)
> +                     p->plane[i++] = intel_plane->wm;
> +     }
>  }
>  
>  static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
> -                              struct intel_crtc_state *cstate,
> -                              struct intel_plane *intel_plane,
> +                              struct skl_pipe_wm_parameters *p,
> +                              struct intel_plane_wm_parameters *p_params,
>                                uint16_t ddb_allocation,
>                                int level,
>                                uint16_t *out_blocks, /* out */
>                                uint8_t *out_lines /* out */)
>  {
> -     struct drm_plane *plane = &intel_plane->base;
> -     struct drm_framebuffer *fb = plane->state->fb;
>       uint32_t latency = dev_priv->wm.skl_latency[level];
>       uint32_t method1, method2;
>       uint32_t plane_bytes_per_line, plane_blocks_per_line;
> @@ -3170,35 +3198,31 @@ static bool skl_compute_plane_wm(const struct 
> drm_i915_private *dev_priv,
>       uint32_t selected_result;
>       uint8_t bytes_per_pixel;
>  
> -     if (latency == 0 || !cstate->base.active || !fb)
> +     if (latency == 0 || !p->active || !p_params->enabled)
>               return false;
>  
> -     bytes_per_pixel = (fb->pixel_format == DRM_FORMAT_NV12) ?
> -             drm_format_plane_cpp(DRM_FORMAT_NV12, 0) :
> -             drm_format_plane_cpp(DRM_FORMAT_NV12, 1);
> -     method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate),
> +     bytes_per_pixel = p_params->y_bytes_per_pixel ?
> +             p_params->y_bytes_per_pixel :
> +             p_params->bytes_per_pixel;
> +     method1 = skl_wm_method1(p->pixel_rate,
>                                bytes_per_pixel,
>                                latency);
> -     method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate),
> -                              cstate->base.adjusted_mode.crtc_htotal,
> -                              cstate->pipe_src_w,
> +     method2 = skl_wm_method2(p->pixel_rate,
> +                              p->pipe_htotal,
> +                              p_params->horiz_pixels,
>                                bytes_per_pixel,
> -                              fb->modifier[0],
> +                              p_params->tiling,
>                                latency);
>  
> -     plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel;
> +     plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel;
>       plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
>  
> -     if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
> -         fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
> +     if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
> +         p_params->tiling == I915_FORMAT_MOD_Yf_TILED) {
>               uint32_t min_scanlines = 4;
>               uint32_t y_tile_minimum;
> -             if (intel_rotation_90_or_270(plane->state->rotation)) {
> -                     int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ?
> -                             drm_format_plane_cpp(fb->pixel_format, 1) :
> -                             drm_format_plane_cpp(fb->pixel_format, 0);
> -
> -                     switch (bpp) {
> +             if (intel_rotation_90_or_270(p_params->rotation)) {
> +                     switch (p_params->bytes_per_pixel) {
>                       case 1:
>                               min_scanlines = 16;
>                               break;
> @@ -3222,8 +3246,8 @@ static bool skl_compute_plane_wm(const struct 
> drm_i915_private *dev_priv,
>       res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line);
>  
>       if (level >= 1 && level <= 7) {
> -             if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
> -                 fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)
> +             if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
> +                 p_params->tiling == I915_FORMAT_MOD_Yf_TILED)
>                       res_lines += 4;
>               else
>                       res_blocks++;
> @@ -3240,80 +3264,84 @@ static bool skl_compute_plane_wm(const struct 
> drm_i915_private *dev_priv,
>  
>  static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
>                                struct skl_ddb_allocation *ddb,
> -                              struct intel_crtc_state *cstate,
> +                              struct skl_pipe_wm_parameters *p,
> +                              enum pipe pipe,
>                                int level,
> +                              int num_planes,
>                                struct skl_wm_level *result)
>  {
> -     struct drm_device *dev = dev_priv->dev;
> -     struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
> -     struct intel_plane *intel_plane;
>       uint16_t ddb_blocks;
> -     enum pipe pipe = intel_crtc->pipe;
> -
> -     for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
> -             int i = skl_wm_plane_id(intel_plane);
> +     int i;
>  
> +     for (i = 0; i < num_planes; i++) {
>               ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]);
>  
>               result->plane_en[i] = skl_compute_plane_wm(dev_priv,
> -                                             cstate,
> -                                             intel_plane,
> +                                             p, &p->plane[i],
>                                               ddb_blocks,
>                                               level,
>                                               &result->plane_res_b[i],
>                                               &result->plane_res_l[i]);
>       }
> +
> +     ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]);
> +     result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p,
> +                                              &p->plane[PLANE_CURSOR],
> +                                              ddb_blocks, level,
> +                                              
> &result->plane_res_b[PLANE_CURSOR],
> +                                              
> &result->plane_res_l[PLANE_CURSOR]);
>  }
>  
>  static uint32_t
> -skl_compute_linetime_wm(struct intel_crtc_state *cstate)
> +skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters 
> *p)
>  {
> -     if (!cstate->base.active)
> +     if (!to_intel_crtc(crtc)->active)
>               return 0;
>  
> -     if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0))
> +     if (WARN_ON(p->pixel_rate == 0))
>               return 0;
>  
> -     return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000,
> -                         skl_pipe_pixel_rate(cstate));
> +     return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate);
>  }
>  
> -static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
> +static void skl_compute_transition_wm(struct drm_crtc *crtc,
> +                                   struct skl_pipe_wm_parameters *params,
>                                     struct skl_wm_level *trans_wm /* out */)
>  {
> -     struct drm_crtc *crtc = cstate->base.crtc;
>       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -     struct intel_plane *intel_plane;
> +     int i;
>  
> -     if (!cstate->base.active)
> +     if (!params->active)
>               return;
>  
>       /* Until we know more, just disable transition WMs */
> -     for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) {
> -             int i = skl_wm_plane_id(intel_plane);
> -
> +     for (i = 0; i < intel_num_planes(intel_crtc); i++)
>               trans_wm->plane_en[i] = false;
> -     }
> +     trans_wm->plane_en[PLANE_CURSOR] = false;
>  }
>  
> -static void skl_compute_pipe_wm(struct intel_crtc_state *cstate,
> +static void skl_compute_pipe_wm(struct drm_crtc *crtc,
>                               struct skl_ddb_allocation *ddb,
> +                             struct skl_pipe_wm_parameters *params,
>                               struct skl_pipe_wm *pipe_wm)
>  {
> -     struct drm_device *dev = cstate->base.crtc->dev;
> +     struct drm_device *dev = crtc->dev;
>       const struct drm_i915_private *dev_priv = dev->dev_private;
> +     struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>       int level, max_level = ilk_wm_max_level(dev);
>  
>       for (level = 0; level <= max_level; level++) {
> -             skl_compute_wm_level(dev_priv, ddb, cstate,
> -                                  level, &pipe_wm->wm[level]);
> +             skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe,
> +                                  level, intel_num_planes(intel_crtc),
> +                                  &pipe_wm->wm[level]);
>       }
> -     pipe_wm->linetime = skl_compute_linetime_wm(cstate);
> +     pipe_wm->linetime = skl_compute_linetime_wm(crtc, params);
>  
> -     skl_compute_transition_wm(cstate, &pipe_wm->trans_wm);
> +     skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm);
>  }
>  
>  static void skl_compute_wm_results(struct drm_device *dev,
> +                                struct skl_pipe_wm_parameters *p,
>                                  struct skl_pipe_wm *p_wm,
>                                  struct skl_wm_values *r,
>                                  struct intel_crtc *intel_crtc)
> @@ -3557,15 +3585,16 @@ static void skl_flush_wm_values(struct 
> drm_i915_private *dev_priv,
>  }
>  
>  static bool skl_update_pipe_wm(struct drm_crtc *crtc,
> +                            struct skl_pipe_wm_parameters *params,
>                              struct intel_wm_config *config,
>                              struct skl_ddb_allocation *ddb, /* out */
>                              struct skl_pipe_wm *pipe_wm /* out */)
>  {
>       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -     struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
>  
> -     skl_allocate_pipe_ddb(cstate, config, ddb);
> -     skl_compute_pipe_wm(cstate, ddb, pipe_wm);
> +     skl_compute_wm_pipe_parameters(crtc, params);
> +     skl_allocate_pipe_ddb(crtc, config, params, ddb);
> +     skl_compute_pipe_wm(crtc, ddb, params, pipe_wm);
>  
>       if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm)))
>               return false;
> @@ -3598,6 +3627,7 @@ static void skl_update_other_pipe_wm(struct drm_device 
> *dev,
>        */
>       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
>                               base.head) {
> +             struct skl_pipe_wm_parameters params = {};
>               struct skl_pipe_wm pipe_wm = {};
>               bool wm_changed;
>  
> @@ -3607,7 +3637,8 @@ static void skl_update_other_pipe_wm(struct drm_device 
> *dev,
>               if (!intel_crtc->active)
>                       continue;
>  
> -             wm_changed = skl_update_pipe_wm(&intel_crtc->base, config,
> +             wm_changed = skl_update_pipe_wm(&intel_crtc->base,
> +                                             &params, config,
>                                               &r->ddb, &pipe_wm);
>  
>               /*
> @@ -3617,7 +3648,7 @@ static void skl_update_other_pipe_wm(struct drm_device 
> *dev,
>                */
>               WARN_ON(!wm_changed);
>  
> -             skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc);
> +             skl_compute_wm_results(dev, &params, &pipe_wm, r, intel_crtc);
>               r->dirty[intel_crtc->pipe] = true;
>       }
>  }
> @@ -3647,6 +3678,7 @@ static void skl_update_wm(struct drm_crtc *crtc)
>       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>       struct drm_device *dev = crtc->dev;
>       struct drm_i915_private *dev_priv = dev->dev_private;
> +     struct skl_pipe_wm_parameters params = {};
>       struct skl_wm_values *results = &dev_priv->wm.skl_results;
>       struct skl_pipe_wm pipe_wm = {};
>       struct intel_wm_config config = {};
> @@ -3659,10 +3691,11 @@ static void skl_update_wm(struct drm_crtc *crtc)
>  
>       skl_compute_wm_global_parameters(dev, &config);
>  
> -     if (!skl_update_pipe_wm(crtc, &config, &results->ddb, &pipe_wm))
> +     if (!skl_update_pipe_wm(crtc, &params, &config,
> +                             &results->ddb, &pipe_wm))
>               return;
>  
> -     skl_compute_wm_results(dev, &pipe_wm, results, intel_crtc);
> +     skl_compute_wm_results(dev, &params, &pipe_wm, results, intel_crtc);
>       results->dirty[intel_crtc->pipe] = true;
>  
>       skl_update_other_pipe_wm(dev, crtc, &config, results);
> @@ -3673,6 +3706,39 @@ static void skl_update_wm(struct drm_crtc *crtc)
>       dev_priv->wm.skl_hw = *results;
>  }
>  
> +static void
> +skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
> +                  uint32_t sprite_width, uint32_t sprite_height,
> +                  int pixel_size, bool enabled, bool scaled)
> +{
> +     struct intel_plane *intel_plane = to_intel_plane(plane);
> +     struct drm_framebuffer *fb = plane->state->fb;
> +
> +     intel_plane->wm.enabled = enabled;
> +     intel_plane->wm.scaled = scaled;
> +     intel_plane->wm.horiz_pixels = sprite_width;
> +     intel_plane->wm.vert_pixels = sprite_height;
> +     intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE;
> +
> +     /* For planar: Bpp is for UV plane, y_Bpp is for Y plane */
> +     intel_plane->wm.bytes_per_pixel =
> +             (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
> +             drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : 
> pixel_size;
> +     intel_plane->wm.y_bytes_per_pixel =
> +             (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
> +             drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0;
> +
> +     /*
> +      * Framebuffer can be NULL on plane disable, but it does not
> +      * matter for watermarks if we assume no tiling in that case.
> +      */
> +     if (fb)
> +             intel_plane->wm.tiling = fb->modifier[0];
> +     intel_plane->wm.rotation = plane->state->rotation;
> +
> +     skl_update_wm(crtc);
> +}
> +
>  static void ilk_update_wm(struct drm_crtc *crtc)
>  {
>       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -3688,18 +3754,6 @@ static void ilk_update_wm(struct drm_crtc *crtc)
>  
>       WARN_ON(cstate->base.active != intel_crtc->active);
>  
> -     /*
> -      * IVB workaround: must disable low power watermarks for at least
> -      * one frame before enabling scaling.  LP watermarks can be re-enabled
> -      * when scaling is disabled.
> -      *
> -      * WaCxSRDisabledForSpriteScaling:ivb
> -      */
> -     if (cstate->disable_lp_wm) {
> -             ilk_disable_lp_wm(dev);
> -             intel_wait_for_vblank(dev, intel_crtc->pipe);
> -     }
> -
>       intel_compute_pipe_wm(cstate, &pipe_wm);
>  
>       if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
> @@ -3731,6 +3785,28 @@ static void ilk_update_wm(struct drm_crtc *crtc)
>       ilk_write_wm_values(dev_priv, &results);
>  }
>  
> +static void
> +ilk_update_sprite_wm(struct drm_plane *plane,
> +                  struct drm_crtc *crtc,
> +                  uint32_t sprite_width, uint32_t sprite_height,
> +                  int pixel_size, bool enabled, bool scaled)
> +{
> +     struct drm_device *dev = plane->dev;
> +     struct intel_plane *intel_plane = to_intel_plane(plane);
> +
> +     /*
> +      * IVB workaround: must disable low power watermarks for at least
> +      * one frame before enabling scaling.  LP watermarks can be re-enabled
> +      * when scaling is disabled.
> +      *
> +      * WaCxSRDisabledForSpriteScaling:ivb
> +      */
> +     if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
> +             intel_wait_for_vblank(dev, intel_plane->pipe);
> +
> +     ilk_update_wm(crtc);
> +}
> +
>  static void skl_pipe_wm_active_state(uint32_t val,
>                                    struct skl_pipe_wm *active,
>                                    bool is_transwm,
> @@ -4108,6 +4184,21 @@ void intel_update_watermarks(struct drm_crtc *crtc)
>               dev_priv->display.update_wm(crtc);
>  }
>  
> +void intel_update_sprite_watermarks(struct drm_plane *plane,
> +                                 struct drm_crtc *crtc,
> +                                 uint32_t sprite_width,
> +                                 uint32_t sprite_height,
> +                                 int pixel_size,
> +                                 bool enabled, bool scaled)
> +{
> +     struct drm_i915_private *dev_priv = plane->dev->dev_private;
> +
> +     if (dev_priv->display.update_sprite_wm)
> +             dev_priv->display.update_sprite_wm(plane, crtc,
> +                                                sprite_width, sprite_height,
> +                                                pixel_size, enabled, scaled);
> +}
> +
>  /**
>   * Lock protecting IPS related data structures
>   */
> @@ -7022,6 +7113,7 @@ void intel_init_pm(struct drm_device *dev)
>                       dev_priv->display.init_clock_gating =
>                               skl_init_clock_gating;
>               dev_priv->display.update_wm = skl_update_wm;
> +             dev_priv->display.update_sprite_wm = skl_update_sprite_wm;
>       } else if (HAS_PCH_SPLIT(dev)) {
>               ilk_setup_wm_latency(dev);
>  
> @@ -7030,6 +7122,7 @@ void intel_init_pm(struct drm_device *dev)
>                   (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
>                    dev_priv->wm.spr_latency[0] && 
> dev_priv->wm.cur_latency[0])) {
>                       dev_priv->display.update_wm = ilk_update_wm;
> +                     dev_priv->display.update_sprite_wm = 
> ilk_update_sprite_wm;
>               } else {
>                       DRM_DEBUG_KMS("Failed to read display plane latency. "
>                                     "Disable CxSR\n");
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c 
> b/drivers/gpu/drm/i915/intel_sprite.c
> index dd2d568..b229c67 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -192,6 +192,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct 
> drm_crtc *crtc,
>       const int pipe = intel_plane->pipe;
>       const int plane = intel_plane->plane + 1;
>       u32 plane_ctl, stride_div, stride;
> +     int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
>       const struct drm_intel_sprite_colorkey *key =
>               &to_intel_plane_state(drm_plane->state)->ckey;
>       unsigned long surf_addr;
> @@ -210,6 +211,10 @@ skl_update_plane(struct drm_plane *drm_plane, struct 
> drm_crtc *crtc,
>       rotation = drm_plane->state->rotation;
>       plane_ctl |= skl_plane_ctl_rotation(rotation);
>  
> +     intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h,
> +                                    pixel_size, true,
> +                                    src_w != crtc_w || src_h != crtc_h);
> +
>       stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
>                                              fb->pixel_format);
>  
> @@ -291,6 +296,8 @@ skl_disable_plane(struct drm_plane *dplane, struct 
> drm_crtc *crtc)
>  
>       I915_WRITE(PLANE_SURF(pipe, plane), 0);
>       POSTING_READ(PLANE_SURF(pipe, plane));
> +
> +     intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
>  }
>  
>  static void
> @@ -533,6 +540,10 @@ ivb_update_plane(struct drm_plane *plane, struct 
> drm_crtc *crtc,
>       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
>               sprctl |= SPRITE_PIPE_CSC_ENABLE;
>  
> +     intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size,
> +                                    true,
> +                                    src_w != crtc_w || src_h != crtc_h);
> +
>       /* Sizes are 0 based */
>       src_w--;
>       src_h--;
> @@ -666,6 +677,10 @@ ilk_update_plane(struct drm_plane *plane, struct 
> drm_crtc *crtc,
>       if (IS_GEN6(dev))
>               dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
>  
> +     intel_update_sprite_watermarks(plane, crtc, src_w, src_h,
> +                                    pixel_size, true,
> +                                    src_w != crtc_w || src_h != crtc_h);
> +
>       /* Sizes are 0 based */
>       src_w--;
>       src_h--;
> -- 
> 2.5.3
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to