diff mbox

[37/43] drm/i915: Initialize HDCP2.2 and its MEI interface

Message ID 1518617638-21684-38-git-send-email-ramalingam.c@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ramalingam C Feb. 14, 2018, 2:13 p.m. UTC
Implements the init and exit for hdcp2.2 support. This includes the
mei interface initialization also.

Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c   |   3 +-
 drivers/gpu/drm/i915/intel_drv.h  |   3 +-
 drivers/gpu/drm/i915/intel_hdcp.c | 145 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_hdmi.c |   2 +-
 4 files changed, 147 insertions(+), 6 deletions(-)

Comments

Chris Wilson Feb. 14, 2018, 2:45 p.m. UTC | #1
Quoting Ramalingam C (2018-02-14 14:13:52)
> Implements the init and exit for hdcp2.2 support. This includes the
> mei interface initialization also.
> 
> Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
> ---
> +static int intel_hdcp2_init(struct intel_hdcp *hdcp,
> +                           const struct intel_hdcp2_shim *shim)
>  {
> +       struct intel_connector *connector = hdcp->connector;
> +       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>         int ret;
> +
> +       if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv) &&
> +           !IS_KABYLAKE(dev_priv))
> +               return -EINVAL;
> +
> +       if (!dev_priv->mei_cldev && !dev_priv->mei_ref_cnt) {
> +               ret = mei_hdcp_cldev_get_reference((void *)dev_priv,
> +                                       &dev_priv->mei_cldev,
> +                                       intel_mei_cldev_reference_notify);
> +               if (ret < 0)
> +                       return ret;
> +       }
> +
> +       dev_priv->mei_ref_cnt++;

So this is more or less unprotected? As there need not be any
serialisation between the construction of two connectors.
-Chris
Ramalingam C Feb. 14, 2018, 2:45 p.m. UTC | #2
On Wednesday 14 February 2018 08:15 PM, Chris Wilson wrote:
> Quoting Ramalingam C (2018-02-14 14:13:52)
>> Implements the init and exit for hdcp2.2 support. This includes the
>> mei interface initialization also.
>>
>> Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
>> ---
>> +static int intel_hdcp2_init(struct intel_hdcp *hdcp,
>> +                           const struct intel_hdcp2_shim *shim)
>>   {
>> +       struct intel_connector *connector = hdcp->connector;
>> +       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
>>          int ret;
>> +
>> +       if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv) &&
>> +           !IS_KABYLAKE(dev_priv))
>> +               return -EINVAL;
>> +
>> +       if (!dev_priv->mei_cldev && !dev_priv->mei_ref_cnt) {
>> +               ret = mei_hdcp_cldev_get_reference((void *)dev_priv,
>> +                                       &dev_priv->mei_cldev,
>> +                                       intel_mei_cldev_reference_notify);
>> +               if (ret < 0)
>> +                       return ret;
>> +       }
>> +
>> +       dev_priv->mei_ref_cnt++;
> So this is more or less unprotected? As there need not be any
> serialisation between the construction of two connectors.
> -Chris
yes. sorry for missing it. I will address it. Might need a lock in 
I915_priv.

-Ram
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 8847f1a36504..6f6b4c8e3a42 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -6463,7 +6463,8 @@  intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	intel_dp_add_properties(intel_dp, connector);
 
 	if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) {
-		int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim);
+		int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim,
+					  NULL);
 		if (ret)
 			DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
 	}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9c05049c25d5..842a22502763 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1950,7 +1950,8 @@  void intel_hdcp_atomic_check(struct drm_connector *connector,
 			     struct drm_connector_state *old_state,
 			     struct drm_connector_state *new_state);
 int intel_hdcp_init(struct intel_connector *connector,
-		    const struct intel_hdcp_shim *hdcp_shim);
+		    const struct intel_hdcp_shim *hdcp_shim,
+		    const struct intel_hdcp2_shim *hdcp2_shim);
 int intel_hdcp_enable(struct intel_connector *connector);
 int intel_hdcp_disable(struct intel_connector *connector);
 int intel_hdcp_check_link(struct intel_hdcp *hdcp);
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
index 9d01d1ff8c73..bb56e4e595d8 100644
--- a/drivers/gpu/drm/i915/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/intel_hdcp.c
@@ -26,6 +26,7 @@  static int _intel_hdcp2_enable(struct intel_hdcp *hdcp);
 static int _intel_hdcp2_disable(struct intel_hdcp *hdcp);
 static void intel_hdcp2_check_work(struct work_struct *work);
 static int intel_hdcp2_check_link(struct intel_hdcp *hdcp);
+static void intel_hdcp2_exit(struct intel_connector *connector);
 
 static inline bool intel_hdcp1_supported(struct intel_hdcp *hdcp)
 {
@@ -738,11 +739,136 @@  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
 		!IS_CHERRYVIEW(dev_priv) && port < PORT_E);
 }
 
-int intel_hdcp_init(struct intel_connector *connector,
-		    const struct intel_hdcp_shim *hdcp_shim)
+static inline int initialize_mei_hdcp_data(struct intel_hdcp *hdcp)
+{
+	struct intel_connector *connector = hdcp->connector;
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct mei_hdcp_data *data = hdcp->mei_hdcp_data;
+	enum port port;
+
+	data->cldev = dev_priv->mei_cldev;
+
+	if (connector->encoder) {
+		port = connector->encoder->port;
+		data->port = GET_MEI_DDI_INDEX(port);
+	}
+
+	data->port_type = INTEGRATED;
+	data->protocol = hdcp->hdcp2_shim->hdcp_protocol();
+
+	data->k = 1;
+	if (!data->streams)
+		data->streams = kcalloc(data->k,
+					sizeof(struct hdcp2_streamid_type),
+					GFP_KERNEL);
+	if (!data->streams)
+		return -ENOMEM;
+
+	data->streams[0].stream_id = 0;
+	data->streams[0].stream_type = hdcp->content_type;
+
+	return 0;
+}
+
+void intel_mei_cldev_reference_notify(void *client,
+				      struct mei_cl_device *cldev)
+{
+	struct drm_i915_private *dev_priv = client;
+	struct drm_device *dev = &dev_priv->drm;
+	struct intel_connector *intel_connector;
+	struct drm_connector *connector;
+	struct drm_connector_list_iter conn_iter;
+
+	DRM_INFO("MEI_HDCP Notification. Interface: %s\n",
+		  cldev ? "UP" : "Down");
+	dev_priv->mei_cldev = cldev;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_for_each_connector_iter(connector, &conn_iter) {
+		intel_connector = to_intel_connector(connector);
+		if (!intel_connector->hdcp ||
+		    !(intel_connector->hdcp->plat_cap & HDCP2_CAPABILITY))
+			continue;
+		if (cldev)
+			initialize_mei_hdcp_data(intel_connector->hdcp);
+		else
+			intel_hdcp2_exit(intel_connector);
+	}
+	drm_connector_list_iter_end(&conn_iter);
+}
+
+static int intel_hdcp2_init(struct intel_hdcp *hdcp,
+			    const struct intel_hdcp2_shim *shim)
 {
+	struct intel_connector *connector = hdcp->connector;
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	int ret;
+
+	if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv) &&
+	    !IS_KABYLAKE(dev_priv))
+		return -EINVAL;
+
+	if (!dev_priv->mei_cldev && !dev_priv->mei_ref_cnt) {
+		ret = mei_hdcp_cldev_get_reference((void *)dev_priv,
+					&dev_priv->mei_cldev,
+					intel_mei_cldev_reference_notify);
+		if (ret < 0)
+			return ret;
+	}
+
+	dev_priv->mei_ref_cnt++;
+
+	hdcp->hdcp2_shim = shim;
+	hdcp->mei_hdcp_data = kzalloc(sizeof(struct mei_hdcp_data), GFP_KERNEL);
+	if (!hdcp->mei_hdcp_data) {
+		ret = -ENOMEM;
+		goto err_exit;
+	}
+
+	ret = initialize_mei_hdcp_data(hdcp);
+	if (ret)
+		goto err2_exit;
+
+	INIT_DELAYED_WORK(&hdcp->hdcp2_check_work, intel_hdcp2_check_work);
+	hdcp->plat_cap |= HDCP2_CAPABILITY;
+	return 0;
+
+err2_exit:
+	kfree(hdcp->mei_hdcp_data);
+err_exit:
+	if (!(--dev_priv->mei_ref_cnt)) {
+		mei_hdcp_cldev_put_reference(dev_priv->mei_cldev);
+		dev_priv->mei_cldev = NULL;
+	}
+	return ret;
+}
+
+static void intel_hdcp2_exit(struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct intel_hdcp *hdcp = connector->hdcp;
+
+	intel_hdcp_disable(connector);
+
+	if (dev_priv->mei_cldev && !(--dev_priv->mei_ref_cnt)) {
+		mei_hdcp_cldev_put_reference(dev_priv->mei_cldev);
+		dev_priv->mei_cldev = NULL;
+	}
+
+	kfree(hdcp->mei_hdcp_data->streams);
+	kfree(hdcp->mei_hdcp_data);
+	hdcp->plat_cap &= ~HDCP2_CAPABILITY;
+}
+
+int intel_hdcp_init(struct intel_connector *connector,
+		    const struct intel_hdcp_shim *hdcp_shim,
+		    const struct intel_hdcp2_shim *hdcp2_shim)
+{
 	struct intel_hdcp *hdcp;
+	int ret;
+
+	if (!hdcp_shim && !hdcp2_shim)
+		return -EINVAL;
 
 	hdcp = kzalloc(sizeof(struct intel_hdcp), GFP_KERNEL);
 	if (!hdcp) {
@@ -750,6 +876,20 @@  int intel_hdcp_init(struct intel_connector *connector,
 		goto err;
 	}
 
+	hdcp->connector = connector;
+	if (hdcp_shim) {
+
+		/* Initialize HDCP1.4 */
+		INIT_DELAYED_WORK(&hdcp->hdcp_check_work,
+				  intel_hdcp_check_work);
+		hdcp->hdcp_shim = hdcp_shim;
+
+		hdcp->plat_cap |= HDCP_CAPABILITY;
+	}
+
+	if (hdcp2_shim)
+		intel_hdcp2_init(hdcp, hdcp2_shim);
+
 	ret = drm_connector_attach_content_protection_property(
 			&connector->base);
 	if (ret)
@@ -757,7 +897,6 @@  int intel_hdcp_init(struct intel_connector *connector,
 
 	hdcp->hdcp_shim = hdcp_shim;
 	mutex_init(&hdcp->hdcp_mutex);
-	INIT_DELAYED_WORK(&hdcp->hdcp_check_work, intel_hdcp_check_work);
 	INIT_WORK(&hdcp->hdcp_prop_work, intel_hdcp_prop_work);
 	INIT_WORK(&hdcp->hdcp_enable_work, intel_hdcp_enable_work);
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index f5d7bfb43006..23986c02dd41 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -2342,7 +2342,7 @@  void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
 
 	if (is_hdcp_supported(dev_priv, port)) {
 		int ret = intel_hdcp_init(intel_connector,
-					  &intel_hdmi_hdcp_shim);
+					  &intel_hdmi_hdcp_shim, NULL);
 		if (ret)
 			DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
 	}