On Mon, Mar 27, 2017 at 03:00:59PM -0700, Sinclair Yeh wrote:
> Refactor previous FB and cursor plane update code into their
> atomic counterparts: check, update, prepare, cleanup, and disable.
> 
> These helpers won't be called until we flip on the atomic support
> flag or set drm_crtc_funcs->set_config to using the atomic
> helper.
> 
> v2:
> * Removed unnecessary pinning of cursor surface
> * Added a few function headers
> 
> v3:
> * Set clip region equal to the destination region
> * Fixed surface pinning policy
> * Enable SVGA mode in vmw_sou_primary_plane_prepare_fb
> 
> Signed-off-by: Sinclair Yeh <s...@vmware.com>
> Signed-off-by: Thomas Hellstrom <thellst...@vmware.com>
> Reviewed-by: Thomas Hellstrom <thellst...@vmware.com>
> ---
>  drivers/gpu/drm/vmwgfx/vmwgfx_kms.c  | 256 
> +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/vmwgfx/vmwgfx_kms.h  |  15 ++
>  drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c  |  66 ++++++++-
>  drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 115 ++++++++++++++++
>  drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 244 +++++++++++++++++++++++++++++++++
>  5 files changed, 695 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c 
> b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> index 6f0f160..d00ff21 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> @@ -26,8 +26,10 @@
>   **************************************************************************/
>  
>  #include "vmwgfx_kms.h"
> +#include <drm/drm_plane_helper.h>
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_rect.h>
>  
>  
>  /* Might need a hrtimer here? */
> @@ -399,6 +401,260 @@ void vmw_du_primary_plane_destroy(struct drm_plane 
> *plane)
>  }
>  
>  
> +/**
> + * vmw_du_vps_unpin_surf - unpins resource associated with a framebuffer 
> surface
> + *
> + * @vps: plane state associated with the display surface
> + * @unreference: true if we also want to unreference the display.
> + */
> +void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
> +                          bool unreference)
> +{
> +     if (vps->surf) {
> +             if (vps->pinned) {
> +                     vmw_resource_unpin(&vps->surf->res);
> +                     vps->pinned--;
> +             }
> +
> +             if (unreference) {
> +                     if (vps->pinned)
> +                             DRM_ERROR("Surface still pinned\n");
> +                     vmw_surface_unreference(&vps->surf);
> +             }
> +     }
> +}
> +
> +
> +/**
> + * vmw_du_plane_cleanup_fb - Unpins the cursor
> + *
> + * @plane:  display plane
> + * @old_state: Contains the FB to clean up
> + *
> + * Unpins the framebuffer surface
> + *
> + * Returns 0 on success
> + */
> +void
> +vmw_du_plane_cleanup_fb(struct drm_plane *plane,
> +                     struct drm_plane_state *old_state)
> +{
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
> +
> +     vmw_du_plane_unpin_surf(vps, false);
> +}
> +
> +
> +/**
> + * vmw_du_cursor_plane_prepare_fb - Readies the cursor by referencing it
> + *
> + * @plane:  display plane
> + * @new_state: info on the new plane state, including the FB
> + *
> + * Returns 0 on success
> + */
> +int
> +vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
> +                            struct drm_plane_state *new_state)
> +{
> +     struct drm_framebuffer *fb = new_state->fb;
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
> +
> +
> +     if (vps->surf)
> +             vmw_surface_unreference(&vps->surf);
> +
> +     if (vps->dmabuf)
> +             vmw_dmabuf_unreference(&vps->dmabuf);
> +
> +     if (fb) {
> +             if (vmw_framebuffer_to_vfb(fb)->dmabuf) {
> +                     vps->dmabuf = vmw_framebuffer_to_vfbd(fb)->buffer;
> +                     vmw_dmabuf_reference(vps->dmabuf);
> +             } else {
> +                     vps->surf = vmw_framebuffer_to_vfbs(fb)->surface;
> +                     vmw_surface_reference(vps->surf);
> +             }
> +     }
> +
> +     return 0;
> +}
> +
> +
> +void
> +vmw_du_cursor_plane_atomic_disable(struct drm_plane *plane,
> +                                struct drm_plane_state *old_state)
> +{
> +     struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
> +     struct vmw_private *dev_priv = vmw_priv(crtc->dev);
> +
> +     drm_atomic_set_fb_for_plane(plane->state, NULL);
> +     vmw_cursor_update_position(dev_priv, false, 0, 0);
> +}
> +
> +
> +void
> +vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
> +                               struct drm_plane_state *old_state)
> +{
> +     struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
> +     struct vmw_private *dev_priv = vmw_priv(crtc->dev);
> +     struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state);
> +     s32 hotspot_x, hotspot_y;
> +     int ret = 0;
> +
> +
> +     hotspot_x = du->hotspot_x;
> +     hotspot_y = du->hotspot_y;
> +     du->cursor_surface = vps->surf;
> +     du->cursor_dmabuf = vps->dmabuf;
> +
> +     /* setup new image */
> +     if (vps->surf) {
> +             du->cursor_age = du->cursor_surface->snooper.age;
> +
> +             ret = vmw_cursor_update_image(dev_priv,
> +                                           vps->surf->snooper.image,
> +                                           64, 64, hotspot_x, hotspot_y);
> +     } else if (vps->dmabuf) {
> +             ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf,
> +                                            plane->state->crtc_w,
> +                                            plane->state->crtc_h,
> +                                            hotspot_x, hotspot_y);
> +     } else {
> +             vmw_cursor_update_position(dev_priv, false, 0, 0);
> +             return;
> +     }
> +
> +     if (!ret) {
> +             du->cursor_x = plane->state->crtc_x + du->set_gui_x;
> +             du->cursor_y = plane->state->crtc_y + du->set_gui_y;
> +
> +             vmw_cursor_update_position(dev_priv, true,
> +                                        du->cursor_x + hotspot_x,
> +                                        du->cursor_y + hotspot_y);
> +     } else {
> +             DRM_ERROR("Failed to update cursor image\n");
> +     }
> +}
> +
> +
> +/**
> + * vmw_du_primary_plane_atomic_check - check if the new state is okay
> + *
> + * @plane: display plane
> + * @state: info on the new plane state, including the FB
> + *
> + * Check if the new state is settable given the current state.  Other
> + * than what the atomic helper checks, we care about crtc fitting
> + * the FB and maintaining one active framebuffer.
> + *
> + * Returns 0 on success
> + */
> +int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
> +                                   struct drm_plane_state *state)
> +{
> +     struct drm_framebuffer *new_fb = state->fb;
> +     bool visible;
> +
> +     struct drm_rect src = {
> +             .x1 = state->src_x,
> +             .y1 = state->src_y,
> +             .x2 = state->src_x + state->src_w,
> +             .y2 = state->src_y + state->src_h,
> +     };
> +     struct drm_rect dest = {
> +             .x1 = state->crtc_x,
> +             .y1 = state->crtc_y,
> +             .x2 = state->crtc_x + state->crtc_w,
> +             .y2 = state->crtc_y + state->crtc_h,
> +     };
> +     struct drm_rect clip = dest;
> +     int ret;
> +
> +     ret = drm_plane_helper_check_update(plane, state->crtc, new_fb,
> +                                         &src, &dest, &clip,
> +                                         DRM_ROTATE_0,
> +                                         DRM_PLANE_HELPER_NO_SCALING,
> +                                         DRM_PLANE_HELPER_NO_SCALING,
> +                                         false, true, &visible);

There's a new atomic version of this, drm_plane_helper_check_state(), for
less boilerplate.

> +
> +
> +     if (!ret && new_fb) {
> +             struct drm_crtc *crtc = state->crtc;
> +             struct vmw_connector_state *vcs;
> +             struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
> +             struct vmw_private *dev_priv = vmw_priv(crtc->dev);
> +             struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
> +
> +             vcs = vmw_connector_state_to_vcs(du->connector.state);
> +
> +             if ((dest.x2 > new_fb->width ||
> +                  dest.y2 > new_fb->height)) {
> +                     DRM_ERROR("CRTC area outside of framebuffer\n");
> +                     return -EINVAL;
> +             }
> +
> +             /* Only one active implicit framebuffer at a time. */
> +             mutex_lock(&dev_priv->global_kms_state_mutex);

It hasn't (yet) merged, but my recommendation for global kms state is to
mirror the main atomic framework, i.e.
- state struct, with duplicate/commit semantics
- separate ww_mutex
We should also be merging a new helper for driver private state objects
rsn, to make this pattern a lot easier/direct to implement.

You can make this work too, but since it's a different way of atomic
commit it means more work trying to understand it.
-Daniel

> +             if (vcs->is_implicit && dev_priv->implicit_fb &&
> +                 !(dev_priv->num_implicit == 1 && du->active_implicit)
> +                 && dev_priv->implicit_fb != vfb) {
> +                     DRM_ERROR("Multiple implicit framebuffers "
> +                               "not supported.\n");
> +                     ret = -EINVAL;
> +             }
> +             mutex_unlock(&dev_priv->global_kms_state_mutex);
> +     }
> +
> +
> +     return ret;
> +}
> +
> +
> +/**
> + * vmw_du_cursor_plane_atomic_check - check if the new state is okay
> + *
> + * @plane: cursor plane
> + * @state: info on the new plane state
> + *
> + * This is a chance to fail if the new cursor state does not fit
> + * our requirements.
> + *
> + * Returns 0 on success
> + */
> +int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
> +                                  struct drm_plane_state *new_state)
> +{
> +     int ret = 0;
> +     struct vmw_surface *surface = NULL;
> +     struct drm_framebuffer *fb = new_state->fb;
> +
> +
> +     /* Turning off */
> +     if (!fb)
> +             return ret;
> +
> +     /* A lot of the code assumes this */
> +     if (new_state->crtc_w != 64 || new_state->crtc_h != 64) {
> +             DRM_ERROR("Invalid cursor dimensions (%d, %d)\n",
> +                       new_state->crtc_w, new_state->crtc_h);
> +             ret = -EINVAL;
> +     }
> +
> +     if (!vmw_framebuffer_to_vfb(fb)->dmabuf)
> +             surface = vmw_framebuffer_to_vfbs(fb)->surface;
> +
> +     if (surface && !surface->snooper.image) {
> +             DRM_ERROR("surface not suitable for cursor\n");
> +             ret = -EINVAL;
> +     }
> +
> +     return ret;
> +}
> +
> +
>  int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
>                            struct drm_crtc_state *new_state)
>  {
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h 
> b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
> index f711b5d..de6a0b6 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
> @@ -345,10 +345,25 @@ int vmw_du_cursor_plane_update(struct drm_plane *plane,
>                              uint32_t src_w, uint32_t src_h);
>  
>  /* Atomic Helpers */
> +int vmw_du_primary_plane_atomic_check(struct drm_plane *plane,
> +                                   struct drm_plane_state *state);
> +int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane,
> +                                  struct drm_plane_state *state);
> +void vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
> +                                    struct drm_plane_state *old_state);
> +void vmw_du_cursor_plane_atomic_disable(struct drm_plane *plane,
> +                                     struct drm_plane_state *old_state);
> +int vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane,
> +                                struct drm_plane_state *new_state);
> +void vmw_du_plane_cleanup_fb(struct drm_plane *plane,
> +                          struct drm_plane_state *old_state);
>  void vmw_du_plane_reset(struct drm_plane *plane);
>  struct drm_plane_state *vmw_du_plane_duplicate_state(struct drm_plane 
> *plane);
>  void vmw_du_plane_destroy_state(struct drm_plane *plane,
>                               struct drm_plane_state *state);
> +void vmw_du_plane_unpin_surf(struct vmw_plane_state *vps,
> +                          bool unreference);
> +
>  int vmw_du_crtc_atomic_check(struct drm_crtc *crtc,
>                            struct drm_crtc_state *state);
>  void vmw_du_crtc_atomic_begin(struct drm_crtc *crtc,
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c 
> b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> index d547e80..1d734de 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
> @@ -234,7 +234,7 @@ static void vmw_ldu_crtc_helper_commit(struct drm_crtc 
> *crtc)
>  
>       ldu = vmw_crtc_to_ldu(crtc);
>       dev_priv = vmw_priv(crtc->dev);
> -     fb       = crtc->primary->fb;
> +     fb       = crtc->primary->state->fb;
>  
>       vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
>  
> @@ -242,6 +242,8 @@ static void vmw_ldu_crtc_helper_commit(struct drm_crtc 
> *crtc)
>               vmw_ldu_add_active(dev_priv, ldu, vfb);
>       else
>               vmw_ldu_del_active(dev_priv, ldu);
> +
> +     vmw_ldu_commit_list(dev_priv);
>  }
>  
>  /**
> @@ -391,6 +393,46 @@ static const struct drm_connector_funcs 
> vmw_legacy_connector_funcs = {
>   * Legacy Display Plane Functions
>   */
>  
> +/**
> + * vmw_ldu_primary_plane_cleanup_fb - Unpin fb
> + *
> + * @plane:  display plane
> + * @old_state: Contains the FB to clean up
> + *
> + * Unpins the display surface
> + *
> + * Returns 0 on success
> + */
> +static void
> +vmw_ldu_primary_plane_cleanup_fb(struct drm_plane *plane,
> +                              struct drm_plane_state *old_state)
> +{
> +}
> +
> +
> +/**
> + * vmw_ldu_primary_plane_prepare_fb -
> + *
> + * @plane:  display plane
> + * @new_state: info on the new plane state, including the FB
> + *
> + * Returns 0 on success
> + */
> +static int
> +vmw_ldu_primary_plane_prepare_fb(struct drm_plane *plane,
> +                              struct drm_plane_state *new_state)
> +{
> +     return 0;
> +}
> +
> +
> +static void
> +vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane,
> +                                 struct drm_plane_state *old_state)
> +{
> +}
> +
> +
>  static const struct drm_plane_funcs vmw_ldu_plane_funcs = {
>       .update_plane = drm_primary_helper_update,
>       .disable_plane = drm_primary_helper_disable,
> @@ -412,6 +454,22 @@ static const struct drm_plane_funcs vmw_ldu_cursor_funcs 
> = {
>  /*
>   * Atomic Helpers
>   */
> +static const struct
> +drm_plane_helper_funcs vmw_ldu_cursor_plane_helper_funcs = {
> +     .atomic_check = vmw_du_cursor_plane_atomic_check,
> +     .atomic_update = vmw_du_cursor_plane_atomic_update,
> +     .prepare_fb = vmw_du_cursor_plane_prepare_fb,
> +     .cleanup_fb = vmw_du_plane_cleanup_fb,
> +};
> +
> +static const struct
> +drm_plane_helper_funcs vmw_ldu_primary_plane_helper_funcs = {
> +     .atomic_check = vmw_du_primary_plane_atomic_check,
> +     .atomic_update = vmw_ldu_primary_plane_atomic_update,
> +     .prepare_fb = vmw_ldu_primary_plane_prepare_fb,
> +     .cleanup_fb = vmw_ldu_primary_plane_cleanup_fb,
> +};
> +
>  static const struct drm_crtc_helper_funcs vmw_ldu_crtc_helper_funcs = {
>       .prepare = vmw_ldu_crtc_helper_prepare,
>       .commit = vmw_ldu_crtc_helper_commit,
> @@ -471,6 +529,8 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, 
> unsigned unit)
>               goto err_free;
>       }
>  
> +     drm_plane_helper_add(primary, &vmw_ldu_primary_plane_helper_funcs);
> +
>       /* Initialize cursor plane */
>       vmw_du_plane_reset(cursor);
>  
> @@ -485,6 +545,10 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, 
> unsigned unit)
>               goto err_free;
>       }
>  
> +     drm_plane_helper_add(cursor, &vmw_ldu_cursor_plane_helper_funcs);
> +
> +
> +     vmw_du_connector_reset(connector);
>       ret = drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
>                                DRM_MODE_CONNECTOR_VIRTUAL);
>       if (ret) {
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c 
> b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> index 662024c..eca055e 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
> @@ -612,6 +612,100 @@ static const struct drm_connector_funcs 
> vmw_sou_connector_funcs = {
>   * Screen Object Display Plane Functions
>   */
>  
> +/**
> + * vmw_sou_primary_plane_cleanup_fb - Frees sou backing buffer
> + *
> + * @plane:  display plane
> + * @old_state: Contains the FB to clean up
> + *
> + * Unpins the display surface
> + *
> + * Returns 0 on success
> + */
> +static void
> +vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane,
> +                              struct drm_plane_state *old_state)
> +{
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
> +
> +     vmw_dmabuf_unreference(&vps->dmabuf);
> +     vps->dmabuf_size = 0;
> +
> +     vmw_du_plane_cleanup_fb(plane, old_state);
> +}
> +
> +
> +/**
> + * vmw_sou_primary_plane_prepare_fb - allocate backing buffer
> + *
> + * @plane:  display plane
> + * @new_state: info on the new plane state, including the FB
> + *
> + * The SOU backing buffer is our equivalent of the display plane.
> + *
> + * Returns 0 on success
> + */
> +static int
> +vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane,
> +                              struct drm_plane_state *new_state)
> +{
> +     struct drm_framebuffer *new_fb = new_state->fb;
> +     struct drm_crtc *crtc = plane->state->crtc ?: new_state->crtc;
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
> +     struct vmw_private *dev_priv;
> +     size_t size;
> +     int ret;
> +
> +
> +     if (!new_fb) {
> +             vmw_dmabuf_unreference(&vps->dmabuf);
> +             vps->dmabuf_size = 0;
> +
> +             return 0;
> +     }
> +
> +     size = new_state->crtc_w * new_state->crtc_h * 4;
> +
> +     if (vps->dmabuf) {
> +             if (vps->dmabuf_size == size)
> +                     return 0;
> +
> +             vmw_dmabuf_unreference(&vps->dmabuf);
> +             vps->dmabuf_size = 0;
> +     }
> +
> +     vps->dmabuf = kzalloc(sizeof(*vps->dmabuf), GFP_KERNEL);
> +     if (!vps->dmabuf)
> +             return -ENOMEM;
> +
> +     dev_priv = vmw_priv(crtc->dev);
> +     vmw_svga_enable(dev_priv);
> +
> +     /* After we have alloced the backing store might not be able to
> +      * resume the overlays, this is preferred to failing to alloc.
> +      */
> +     vmw_overlay_pause_all(dev_priv);
> +     ret = vmw_dmabuf_init(dev_priv, vps->dmabuf, size,
> +                           &vmw_vram_ne_placement,
> +                           false, &vmw_dmabuf_bo_free);
> +     vmw_overlay_resume_all(dev_priv);
> +
> +     if (ret != 0)
> +             vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */
> +     else
> +             vps->dmabuf_size = size;
> +
> +     return ret;
> +}
> +
> +
> +static void
> +vmw_sou_primary_plane_atomic_update(struct drm_plane *plane,
> +                                 struct drm_plane_state *old_state)
> +{
> +}
> +
> +
>  static const struct drm_plane_funcs vmw_sou_plane_funcs = {
>       .update_plane = drm_primary_helper_update,
>       .disable_plane = drm_primary_helper_disable,
> @@ -633,6 +727,22 @@ static const struct drm_plane_funcs vmw_sou_cursor_funcs 
> = {
>  /*
>   * Atomic Helpers
>   */
> +static const struct
> +drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = {
> +     .atomic_check = vmw_du_cursor_plane_atomic_check,
> +     .atomic_update = vmw_du_cursor_plane_atomic_update,
> +     .prepare_fb = vmw_du_cursor_plane_prepare_fb,
> +     .cleanup_fb = vmw_du_plane_cleanup_fb,
> +};
> +
> +static const struct
> +drm_plane_helper_funcs vmw_sou_primary_plane_helper_funcs = {
> +     .atomic_check = vmw_du_primary_plane_atomic_check,
> +     .atomic_update = vmw_sou_primary_plane_atomic_update,
> +     .prepare_fb = vmw_sou_primary_plane_prepare_fb,
> +     .cleanup_fb = vmw_sou_primary_plane_cleanup_fb,
> +};
> +
>  static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
>       .prepare = vmw_sou_crtc_helper_prepare,
>       .commit = vmw_sou_crtc_helper_commit,
> @@ -691,6 +801,8 @@ static int vmw_sou_init(struct vmw_private *dev_priv, 
> unsigned unit)
>               goto err_free;
>       }
>  
> +     drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs);
> +
>       /* Initialize cursor plane */
>       vmw_du_plane_reset(cursor);
>  
> @@ -705,6 +817,9 @@ static int vmw_sou_init(struct vmw_private *dev_priv, 
> unsigned unit)
>               goto err_free;
>       }
>  
> +     drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs);
> +
> +     vmw_du_connector_reset(connector);
>       ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
>                                DRM_MODE_CONNECTOR_VIRTUAL);
>       if (ret) {
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c 
> b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
> index 6e3cfad..cce5e5b 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
> @@ -1194,6 +1194,230 @@ static const struct drm_connector_funcs 
> vmw_stdu_connector_funcs = {
>   * Screen Target Display Plane Functions
>   
> *****************************************************************************/
>  
> +
> +
> +/**
> + * vmw_stdu_primary_plane_cleanup_fb - Unpins the display surface
> + *
> + * @plane:  display plane
> + * @old_state: Contains the FB to clean up
> + *
> + * Unpins the display surface
> + *
> + * Returns 0 on success
> + */
> +static void
> +vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
> +                               struct drm_plane_state *old_state)
> +{
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
> +
> +     if (vps->surf)
> +             WARN_ON(!vps->pinned);
> +
> +     vmw_du_plane_cleanup_fb(plane, old_state);
> +
> +     vps->content_fb_type = SAME_AS_DISPLAY;
> +}
> +
> +
> +
> +/**
> + * vmw_stdu_primary_plane_prepare_fb - Readies the display surface
> + *
> + * @plane:  display plane
> + * @new_state: info on the new plane state, including the FB
> + *
> + * This function allocates a new display surface if the content is
> + * backed by a DMA.  The display surface is pinned here, and it'll
> + * be unpinned in .cleanup_fb()
> + *
> + * Returns 0 on success
> + */
> +static int
> +vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
> +                               struct drm_plane_state *new_state)
> +{
> +     struct drm_framebuffer *new_fb = new_state->fb;
> +     struct vmw_framebuffer *vfb;
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
> +     enum stdu_content_type new_content_type;
> +     struct vmw_framebuffer_surface *new_vfbs;
> +     struct drm_crtc *crtc = new_state->crtc;
> +     uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h;
> +     int ret;
> +
> +     /* No FB to prepare */
> +     if (!new_fb) {
> +             if (vps->surf) {
> +                     WARN_ON(vps->pinned != 0);
> +                     vmw_surface_unreference(&vps->surf);
> +             }
> +
> +             return 0;
> +     }
> +
> +     vfb = vmw_framebuffer_to_vfb(new_fb);
> +     new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb);
> +
> +     if (new_vfbs && new_vfbs->surface->base_size.width == hdisplay &&
> +         new_vfbs->surface->base_size.height == vdisplay)
> +             new_content_type = SAME_AS_DISPLAY;
> +     else if (vfb->dmabuf)
> +             new_content_type = SEPARATE_DMA;
> +     else
> +             new_content_type = SEPARATE_SURFACE;
> +
> +     if (new_content_type != SAME_AS_DISPLAY) {
> +             struct vmw_surface content_srf;
> +             struct drm_vmw_size display_base_size = {0};
> +
> +             display_base_size.width  = hdisplay;
> +             display_base_size.height = vdisplay;
> +             display_base_size.depth  = 1;
> +
> +             /*
> +              * If content buffer is a DMA buf, then we have to construct
> +              * surface info
> +              */
> +             if (new_content_type == SEPARATE_DMA) {
> +
> +                     switch (new_fb->format->cpp[0]*8) {
> +                     case 32:
> +                             content_srf.format = SVGA3D_X8R8G8B8;
> +                             break;
> +
> +                     case 16:
> +                             content_srf.format = SVGA3D_R5G6B5;
> +                             break;
> +
> +                     case 8:
> +                             content_srf.format = SVGA3D_P8;
> +                             break;
> +
> +                     default:
> +                             DRM_ERROR("Invalid format\n");
> +                             return -EINVAL;
> +                     }
> +
> +                     content_srf.flags             = 0;
> +                     content_srf.mip_levels[0]     = 1;
> +                     content_srf.multisample_count = 0;
> +             } else {
> +                     content_srf = *new_vfbs->surface;
> +             }
> +
> +             if (vps->surf) {
> +                     struct drm_vmw_size cur_base_size = 
> vps->surf->base_size;
> +
> +                     if (cur_base_size.width != display_base_size.width ||
> +                         cur_base_size.height != display_base_size.height ||
> +                         vps->surf->format != content_srf.format) {
> +                             WARN_ON(vps->pinned != 0);
> +                             vmw_surface_unreference(&vps->surf);
> +                     }
> +
> +             }
> +
> +             if (!vps->surf) {
> +                     ret = vmw_surface_gb_priv_define
> +                             (crtc->dev,
> +                              /* Kernel visible only */
> +                              0,
> +                              content_srf.flags,
> +                              content_srf.format,
> +                              true,  /* a scanout buffer */
> +                              content_srf.mip_levels[0],
> +                              content_srf.multisample_count,
> +                              0,
> +                              display_base_size,
> +                              &vps->surf);
> +                     if (ret != 0) {
> +                             DRM_ERROR("Couldn't allocate STDU surface.\n");
> +                             return ret;
> +                     }
> +             }
> +     } else {
> +             /*
> +              * prepare_fb and clean_fb should only take care of pinning
> +              * and unpinning.  References are tracked by state objects.
> +              * The only time we add a reference in prepare_fb is if the
> +              * state object doesn't have a reference to begin with
> +              */
> +             if (vps->surf) {
> +                     WARN_ON(vps->pinned != 0);
> +                     vmw_surface_unreference(&vps->surf);
> +             }
> +
> +             vps->surf = vmw_surface_reference(new_vfbs->surface);
> +     }
> +
> +     if (vps->surf) {
> +
> +             /* Pin new surface before flipping */
> +             ret = vmw_resource_pin(&vps->surf->res, false);
> +             if (ret)
> +                     goto out_srf_unref;
> +
> +             vps->pinned++;
> +     }
> +
> +     vps->content_fb_type = new_content_type;
> +     return 0;
> +
> +out_srf_unref:
> +     vmw_surface_unreference(&vps->surf);
> +     return ret;
> +}
> +
> +
> +
> +/**
> + * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
> + *
> + * @plane: display plane
> + * @old_state: Only used to get crtc info
> + *
> + * Formally update stdu->display_srf to the new plane, and bind the new
> + * plane STDU.  This function is called during the commit phase when
> + * all the preparation have been done and all the configurations have
> + * been checked.
> + */
> +static void
> +vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
> +                                  struct drm_plane_state *old_state)
> +{
> +     struct vmw_private *dev_priv;
> +     struct vmw_screen_target_display_unit *stdu;
> +     struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state);
> +     struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
> +     int ret;
> +
> +     stdu     = vmw_crtc_to_stdu(crtc);
> +     dev_priv = vmw_priv(crtc->dev);
> +
> +     stdu->display_srf = vps->surf;
> +     stdu->content_fb_type = vps->content_fb_type;
> +
> +     if (!stdu->defined)
> +             return;
> +
> +     if (plane->state->fb)
> +             ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
> +     else
> +             ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
> +
> +     /*
> +      * We cannot really fail this function, so if we do, then output an
> +      * error and quit
> +      */
> +     if (ret)
> +             DRM_ERROR("Failed to bind surface to STDU.\n");
> +     else
> +             crtc->primary->fb = plane->state->fb;
> +}
> +
> +
>  static const struct drm_plane_funcs vmw_stdu_plane_funcs = {
>       .update_plane = drm_primary_helper_update,
>       .disable_plane = drm_primary_helper_disable,
> @@ -1216,6 +1440,22 @@ static const struct drm_plane_funcs 
> vmw_stdu_cursor_funcs = {
>  /*
>   * Atomic Helpers
>   */
> +static const struct
> +drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = {
> +     .atomic_check = vmw_du_cursor_plane_atomic_check,
> +     .atomic_update = vmw_du_cursor_plane_atomic_update,
> +     .prepare_fb = vmw_du_cursor_plane_prepare_fb,
> +     .cleanup_fb = vmw_du_plane_cleanup_fb,
> +};
> +
> +static const struct
> +drm_plane_helper_funcs vmw_stdu_primary_plane_helper_funcs = {
> +     .atomic_check = vmw_du_primary_plane_atomic_check,
> +     .atomic_update = vmw_stdu_primary_plane_atomic_update,
> +     .prepare_fb = vmw_stdu_primary_plane_prepare_fb,
> +     .cleanup_fb = vmw_stdu_primary_plane_cleanup_fb,
> +};
> +
>  static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
>       .prepare = vmw_stdu_crtc_helper_prepare,
>       .commit = vmw_stdu_crtc_helper_commit,
> @@ -1283,6 +1523,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, 
> unsigned unit)
>               goto err_free;
>       }
>  
> +     drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs);
> +
>       /* Initialize cursor plane */
>       vmw_du_plane_reset(cursor);
>  
> @@ -1297,6 +1539,8 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, 
> unsigned unit)
>               goto err_free;
>       }
>  
> +     drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs);
> +
>       vmw_du_connector_reset(connector);
>  
>       ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs,
> -- 
> 2.7.4
> 

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

Reply via email to