drm: Add Content Protection property
authorYi Zhou <yi.zhou@amlogic.com>
Thu, 5 Jul 2018 06:00:10 +0000 (14:00 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Thu, 5 Jul 2018 12:19:57 +0000 (05:19 -0700)
PD#158474: drm: Add Content Protection property

This patch adds a new optional connector property to allow userspace to enable
protection over the content it is displaying. This will typically be implemented
by the driver using HDCP.

The property is a tri-state with the following values:
- OFF: Self explanatory, no content protection
- DESIRED: Userspace requests that the driver enable protection
- ENABLED: Once the driver has authenticated the link, it sets this value

The driver is responsible for downgrading ENABLED to DESIRED if the link becomes
unprotected. The driver should also maintain the desiredness of protection
across hotplug/dpms/suspend.

If this looks familiar, I posted [1] this 3 years ago. We have been using this
in ChromeOS across exynos, mediatek, and rockchip over that time.

Changes in v2:
- Pimp kerneldoc for content_protection_property (Daniel)
- Drop sysfs attribute
Changes in v3:
- None
Changes in v4:
- Changed kerneldoc to recommend userspace polling (Daniel)
- Changed kerneldoc to briefly describe how to attach the property (Daniel)
Changes in v5:
- checkpatch whitespace noise
- Change DRM_MODE_CONTENT_PROTECTION_OFF to DRM_MODE_CONTENT_PROTECTION_UNDESIRED
Changes in v6:
- None

commit 24557865c8b1a6d0eaccaac47aabd9b23badf8fd
Author: Sean Paul <seanpaul@chromium.org>
Date:   Mon Jan 8 14:55:37 2018 -0500

Change-Id: Ief031a46681d88369454ebbc56ed0bb203258ab5
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Yi Zhou <yi.zhou@amlogic.com>
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_connector.c
include/drm/drm_connector.h
include/uapi/drm/drm_mode.h

index 33778bf..2cdab98 100644 (file)
@@ -1032,12 +1032,19 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
                 * now?) atomic writes to DPMS property:
                 */
                return -EINVAL;
+       } else if (property == connector->content_protection_property) {
+               if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+                       DRM_DEBUG_KMS("only drivers can set CP Enabled\n");
+                       return -EINVAL;
+               }
+               state->content_protection = val;
        } else if (connector->funcs->atomic_set_property) {
                return connector->funcs->atomic_set_property(connector,
                                state, property, val);
        } else {
                return -EINVAL;
        }
+       return 0;
 }
 EXPORT_SYMBOL(drm_atomic_connector_set_property);
 
@@ -1068,6 +1075,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
                *val = (state->crtc) ? state->crtc->base.id : 0;
        } else if (property == config->dpms_property) {
                *val = connector->dpms;
+       } else if (property == connector->content_protection_property) {
+               *val = state->content_protection;
        } else if (connector->funcs->atomic_get_property) {
                return connector->funcs->atomic_get_property(connector,
                                state, property, val);
index 0e934a9..634d438 100644 (file)
@@ -601,6 +601,13 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
 DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
                 drm_tv_subconnector_enum_list)
 
+static struct drm_prop_enum_list drm_cp_enum_list[] = {
+       { DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" },
+       { DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" },
+       { DRM_MODE_CONTENT_PROTECTION_ENABLED, "Enabled" },
+};
+DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list)
+
 int drm_connector_create_standard_properties(struct drm_device *dev)
 {
        struct drm_property *prop;
@@ -807,6 +814,42 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev)
 EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
 
 /**
+ * drm_connector_attach_content_protection_property - attach content protection
+ * property
+ *
+ * @connector: connector to attach CP property on.
+ *
+ * This is used to add support for content protection on select connectors.
+ * Content Protection is intentionally vague to allow for different underlying
+ * technologies, however it is most implemented by HDCP.
+ *
+ * The content protection will be set to &drm_connector_state.content_protection
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int drm_connector_attach_content_protection_property(
+               struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_property *prop;
+
+       prop = drm_property_create_enum(dev, 0, "Content Protection",
+                                       drm_cp_enum_list,
+                                       ARRAY_SIZE(drm_cp_enum_list));
+       if (!prop)
+               return -ENOMEM;
+
+       drm_object_attach_property(&connector->base, prop,
+                                  DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
+
+       connector->content_protection_property = prop;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_content_protection_property);
+
+/**
  * drm_mode_create_aspect_ratio_property - create aspect ratio property
  * @dev: DRM device
  *
index d8bb8d1..ba12fb4 100644 (file)
@@ -213,6 +213,12 @@ struct drm_connector_state {
        struct drm_encoder *best_encoder;
 
        struct drm_atomic_state *state;
+
+       /**
+        * @content_protection: Connector property to request content
+        * protection. This is most commonly used for HDCP.
+        */
+       unsigned int content_protection;
 };
 
 /**
@@ -546,6 +552,7 @@ struct drm_cmdline_mode {
  * @tile_v_loc: vertical location of this tile
  * @tile_h_size: horizontal size of this tile.
  * @tile_v_size: vertical size of this tile.
+ * @content_protection_property: Optional property to control content protection
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -608,6 +615,12 @@ struct drm_connector {
        struct drm_object_properties properties;
 
        /**
+        * @content_protection_property: DRM ENUM property for content
+        * protection
+        */
+       struct drm_property *content_protection_property;
+
+       /**
         * @path_blob_ptr:
         *
         * DRM blob property data for the DP MST path property.
@@ -760,12 +773,15 @@ const char *drm_get_dvi_i_subconnector_name(int val);
 const char *drm_get_dvi_i_select_name(int val);
 const char *drm_get_tv_subconnector_name(int val);
 const char *drm_get_tv_select_name(int val);
+const char *drm_get_content_protection_name(int val);
 
 int drm_mode_create_dvi_i_properties(struct drm_device *dev);
 int drm_mode_create_tv_properties(struct drm_device *dev,
                                  unsigned int num_modes,
                                  const char * const modes[]);
 int drm_mode_create_scaling_mode_property(struct drm_device *dev);
+int drm_connector_attach_content_protection_property(
+               struct drm_connector *connector);
 int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
 int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
 
index df0e350..254a11c 100644 (file)
@@ -107,6 +107,11 @@ extern "C" {
 #define DRM_MODE_DIRTY_ON       1
 #define DRM_MODE_DIRTY_ANNOTATE 2
 
+/* Content Protection Flags */
+#define DRM_MODE_CONTENT_PROTECTION_UNDESIRED  0
+#define DRM_MODE_CONTENT_PROTECTION_DESIRED     1
+#define DRM_MODE_CONTENT_PROTECTION_ENABLED     2
+
 struct drm_mode_modeinfo {
        __u32 clock;
        __u16 hdisplay;