drm: introduce share plane
authorMark Yao <mark.yao@rock-chips.com>
Tue, 26 Apr 2016 11:46:57 +0000 (19:46 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 4 May 2016 10:16:50 +0000 (18:16 +0800)
The plane hardware is used when the display scanout run into plane active
scanout, that means we can reuse the plane hardware resources on plane
non-active scanout.

Because resource share, There are some limit on share plane: one group
of share planes need use same zpos, can't not overlap, etc.

We assume share plane is a universal plane with some limit flags.
people who use the share plane need know the limit, should call the ioctl
DRM_CLIENT_CAP_SHARE_PLANES, and judge the planes limit before use it.

Change-Id: Iecc3d8e7f1ce29d567cdbad689ba4dbad3d594e1
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_ioctl.c
include/drm/drmP.h
include/drm/drm_crtc.h
include/uapi/drm/drm.h

index 555141a..030d2db 100644 (file)
@@ -1249,6 +1249,96 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 }
 EXPORT_SYMBOL(drm_plane_init);
 
+/**
+ * drm_share_plane_init - Initialize a share plane
+ * @dev: DRM device
+ * @plane: plane object to init
+ * @parent: this plane share some resources with parent plane.
+ * @possible_crtcs: bitmask of possible CRTCs
+ * @funcs: callbacks for the new plane
+ * @formats: array of supported formats (%DRM_FORMAT_*)
+ * @format_count: number of elements in @formats
+ * @type: type of plane (overlay, primary, cursor)
+ *
+ * With this API, the plane can share hardware resources with other planes.
+ *
+ *   --------------------------------------------------
+ *   |  scanout                                       |
+ *   |         ------------------                     |
+ *   |         |  parent plane  |                     |
+ *   |         | active scanout |                     |
+ *   |         |                |   ----------------- |
+ *   |         ------------------   | share plane 1 | |
+ *   |  -----------------           |active scanout | |
+ *   |  | share plane 0 |           |               | |
+ *   |  |active scanout |           ----------------- |
+ *   |  |               |                             |
+ *   |  -----------------                             |
+ *   --------------------------------------------------
+ *
+ *    parent plane
+ *        |---share plane 0
+ *        |---share plane 1
+ *        ...
+ *
+ * The plane hardware is used when the display scanout run into plane active
+ * scanout, that means we can reuse the plane hardware resources on plane
+ * non-active scanout.
+ *
+ * Because resource share, There are some limit on share plane: one group
+ * of share planes need use same zpos, can't not overlap, etc.
+ *
+ * Here assume share plane is a universal plane with some limit flags.
+ * people who use the share plane need know the limit, should call the ioctl
+ * DRM_CLIENT_CAP_SHARE_PLANES, and judge the planes limit before use it.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+
+int drm_share_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                        struct drm_plane *parent,
+                        unsigned long possible_crtcs,
+                        const struct drm_plane_funcs *funcs,
+                        const uint32_t *formats, unsigned int format_count,
+                        enum drm_plane_type type)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       int ret;
+       int share_id;
+
+       /*
+        * TODO: only verified on ATOMIC drm driver.
+        */
+       if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
+               return -EINVAL;
+
+       ret = drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
+                                      formats, format_count, type, NULL);
+       if (ret)
+               return ret;
+
+       if (parent) {
+               /*
+                * Can't support more than two level plane share.
+                */
+               WARN_ON(parent->parent);
+               share_id = parent->base.id;
+               plane->parent = parent;
+
+               config->num_share_plane++;
+               if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+                       config->num_share_overlay_plane++;
+       } else {
+               share_id = plane->base.id;
+       }
+
+       drm_object_attach_property(&plane->base,
+                                  config->prop_share_id, share_id);
+       return 0;
+}
+EXPORT_SYMBOL(drm_share_plane_init);
+
 /**
  * drm_plane_cleanup - Clean up the core plane usage
  * @plane: plane to cleanup
@@ -1271,6 +1361,11 @@ void drm_plane_cleanup(struct drm_plane *plane)
        dev->mode_config.num_total_plane--;
        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
                dev->mode_config.num_overlay_plane--;
+       if (plane->parent) {
+               dev->mode_config.num_share_plane--;
+               if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+                       dev->mode_config.num_share_overlay_plane--;
+       }
        drm_modeset_unlock_all(dev);
 
        WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
@@ -1402,6 +1497,18 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
                return -ENOMEM;
        dev->mode_config.plane_type_property = prop;
 
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
+                                        "SHARE_ID", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+
+       dev->mode_config.prop_share_id = prop;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
+                                        "SHARE_FLAGS", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_share_flags = prop;
+
        prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
                        "SRC_X", 0, UINT_MAX);
        if (!prop)
@@ -2208,6 +2315,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
                num_planes = config->num_total_plane;
        else
                num_planes = config->num_overlay_plane;
+       if (!file_priv->share_planes) {
+               if (file_priv->universal_planes)
+                       num_planes -= config->num_share_plane;
+               else
+                       num_planes -= config->num_share_overlay_plane;
+       }
 
        /*
         * This ioctl is called twice, once to determine how much space is
@@ -2226,6 +2339,8 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
                        if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
                            !file_priv->universal_planes)
                                continue;
+                       if (plane->parent && !file_priv->share_planes)
+                               continue;
 
                        if (put_user(plane->base.id, plane_ptr + copied))
                                return -EFAULT;
index 8ce2a0c..081ba35 100644 (file)
@@ -337,6 +337,11 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
                        return -EINVAL;
                file_priv->universal_planes = req->value;
                break;
+       case DRM_CLIENT_CAP_SHARE_PLANES:
+               if (req->value > 1)
+                       return -EINVAL;
+               file_priv->share_planes = req->value;
+               break;
        case DRM_CLIENT_CAP_ATOMIC:
                if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
                        return -EINVAL;
index 0a271ca..6f664f4 100644 (file)
@@ -309,6 +309,11 @@ struct drm_file {
        unsigned universal_planes:1;
        /* true if client understands atomic properties */
        unsigned atomic:1;
+       /*
+        * true if client understands share planes and
+        * hardware support share planes.
+        */
+       unsigned share_planes:1;
        /*
         * This client is allowed to gain master privileges for @master.
         * Protected by struct drm_device::master_mutex.
index d9becbf..9c37e6b 100644 (file)
@@ -827,6 +827,7 @@ enum drm_plane_type {
 /**
  * struct drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
+ * @parent: this plane share some resources with parent plane.
  * @head: for list management
  * @base: base mode object
  * @possible_crtcs: pipes this plane can be bound to
@@ -844,6 +845,7 @@ enum drm_plane_type {
  */
 struct drm_plane {
        struct drm_device *dev;
+       struct drm_plane *parent;
        struct list_head head;
 
        struct drm_modeset_lock mutex;
@@ -1074,6 +1076,8 @@ struct drm_mode_config {
         */
        int num_overlay_plane;
        int num_total_plane;
+       int num_share_plane;
+       int num_share_overlay_plane;
        struct list_head plane_list;
 
        int num_crtc;
@@ -1094,6 +1098,10 @@ struct drm_mode_config {
 
        struct mutex blob_lock;
 
+       /* pointers to share properties */
+       struct drm_property *prop_share_id;
+       struct drm_property *prop_share_flags;
+
        /* pointers to standard properties */
        struct list_head property_blob_list;
        struct drm_property *edid_property;
@@ -1269,6 +1277,13 @@ extern int drm_plane_init(struct drm_device *dev,
                          const struct drm_plane_funcs *funcs,
                          const uint32_t *formats, unsigned int format_count,
                          bool is_primary);
+extern int drm_share_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                               struct drm_plane *parent,
+                               unsigned long possible_crtcs,
+                               const struct drm_plane_funcs *funcs,
+                               const uint32_t *formats,
+                               unsigned int format_count,
+                               enum drm_plane_type type);
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern unsigned int drm_plane_index(struct drm_plane *plane);
 extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx);
index ad8223e..3b01fb8 100644 (file)
@@ -662,6 +662,13 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_ATOMIC  3
 
+/**
+ * DRM_CLIENT_CAP_SHARE_PLANES
+ *
+ * If set to 1, the DRM core will expose share planes to userspace.
+ */
+#define DRM_CLIENT_CAP_SHARE_PLANES    4
+
 /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
        __u64 capability;