diff mbox

[v2,32/42] drm/i915: Initialize HDCP2.2 and its MEI interface

Message ID 1520510349-8385-33-git-send-email-ramalingam.c@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ramalingam C March 8, 2018, 11:58 a.m. UTC
Initialize HDCP2.2 support. This includes the mei interface
initialization also.

v2:
  mei interface handle is protected with mutex. [Chris Wilson]

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

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index aaa861b51024..d178b3ec0a60 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -917,6 +917,7 @@  static int i915_driver_init_early(struct drm_i915_private *dev_priv,
 	mutex_init(&dev_priv->av_mutex);
 	mutex_init(&dev_priv->wm.wm_mutex);
 	mutex_init(&dev_priv->pps_mutex);
+	mutex_init(&dev_priv->mei_interface_mutex);
 
 	intel_uc_init_early(dev_priv);
 	i915_memcpy_init_early(dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 82a106b1bdbc..0e35e24948a3 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1815,6 +1815,8 @@  struct intel_cdclk_state {
 	u8 voltage_level;
 };
 
+struct mei_cl_device;
+
 struct drm_i915_private {
 	struct drm_device drm;
 
@@ -2375,6 +2377,11 @@  struct drm_i915_private {
 
 	struct i915_pmu pmu;
 
+	/* MEI Interface for HDCP2.2 */
+	struct mei_cl_device *mei_cldev;
+	bool mei_init_deferred;
+	struct mutex mei_interface_mutex;
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 2c3eb90b9499..42f3b3331e90 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -6421,7 +6421,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,
+					  false);
 		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 67f507bb4d0d..b431e7027bc9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1922,7 +1922,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,
+		    bool hdcp2_supported);
 int intel_hdcp_enable(struct intel_connector *connector);
 int intel_hdcp_disable(struct intel_connector *connector);
 int intel_hdcp_check_link(struct intel_connector *connector);
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
index 2cb50db3b063..2265121e1102 100644
--- a/drivers/gpu/drm/i915/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/intel_hdcp.c
@@ -25,6 +25,7 @@  static int _intel_hdcp2_enable(struct intel_connector *connector);
 static int _intel_hdcp2_disable(struct intel_connector *connector);
 static void intel_hdcp2_check_work(struct work_struct *work);
 static int intel_hdcp2_check_link(struct intel_connector *connector);
+static int intel_hdcp2_init(struct intel_connector *connector);
 
 static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port,
 				    const struct intel_hdcp_shim *shim)
@@ -686,11 +687,15 @@  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
 }
 
 int intel_hdcp_init(struct intel_connector *connector,
-		    const struct intel_hdcp_shim *hdcp_shim)
+		    const struct intel_hdcp_shim *hdcp_shim,
+		    bool hdcp2_supported)
 {
 	struct intel_hdcp *hdcp = &connector->hdcp;
 	int ret;
 
+	if (!hdcp_shim)
+		return -EINVAL;
+
 	ret = drm_connector_attach_content_protection_property(
 			&connector->base);
 	if (ret)
@@ -699,7 +704,12 @@  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_DELAYED_WORK(&hdcp->hdcp2_check_work, intel_hdcp2_check_work);
 	INIT_WORK(&hdcp->hdcp_prop_work, intel_hdcp_prop_work);
+
+	if (hdcp2_supported)
+		intel_hdcp2_init(connector);
+
 	return 0;
 }
 
@@ -1565,3 +1575,114 @@  static void intel_hdcp2_check_work(struct work_struct *work)
 		schedule_delayed_work(&hdcp->hdcp2_check_work,
 				      DRM_HDCP2_CHECK_PERIOD_MS);
 }
+
+static inline int initialize_mei_hdcp_data(struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct intel_hdcp *hdcp = &connector->hdcp;
+	struct mei_hdcp_data *data = &hdcp->mei_data;
+	enum port port;
+
+	mutex_lock(&dev_priv->mei_interface_mutex);
+	data->cldev = dev_priv->mei_cldev;
+	mutex_unlock(&dev_priv->mei_interface_mutex);
+
+	if (connector->encoder) {
+		port = connector->encoder->port;
+		data->port = GET_MEI_DDI_INDEX(port);
+	}
+
+	data->port_type = INTEGRATED;
+	data->protocol = hdcp->hdcp_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;
+}
+
+static void intel_hdcp2_exit(struct intel_connector *connector)
+{
+	intel_hdcp_disable(connector);
+	connector->hdcp.hdcp2_supported = false;
+
+	kfree(connector->hdcp.mei_data.streams);
+}
+
+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");
+
+	mutex_lock(&dev_priv->mei_interface_mutex);
+	dev_priv->mei_cldev = cldev;
+	mutex_unlock(&dev_priv->mei_interface_mutex);
+
+	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.hdcp2_supported))
+			continue;
+		if (cldev)
+			initialize_mei_hdcp_data(intel_connector);
+		else
+			intel_hdcp2_exit(intel_connector);
+	}
+	drm_connector_list_iter_end(&conn_iter);
+}
+
+static inline
+bool is_hdcp2_supported(struct drm_i915_private *dev_priv)
+{
+	return (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) ||
+		IS_KABYLAKE(dev_priv));
+}
+
+static int intel_hdcp2_init(struct intel_connector *connector)
+{
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct intel_hdcp *hdcp = &connector->hdcp;
+	int ret;
+
+	if (!is_hdcp2_supported(dev_priv))
+		return -EINVAL;
+
+	mutex_lock(&dev_priv->mei_interface_mutex);
+	if (!dev_priv->mei_cldev && !dev_priv->mei_init_deferred) {
+		ret = mei_hdcp_cldev_get_reference((void *)dev_priv,
+					&dev_priv->mei_cldev,
+					intel_mei_cldev_reference_notify);
+		if (ret < 0) {
+			mutex_unlock(&dev_priv->mei_interface_mutex);
+			return ret;
+		}
+	}
+
+	/* Get reference is success but still handle is NULL */
+	if (!dev_priv->mei_cldev)
+		dev_priv->mei_init_deferred = true;
+
+	mutex_unlock(&dev_priv->mei_interface_mutex);
+
+	ret = initialize_mei_hdcp_data(connector);
+	if (ret)
+		return ret;
+
+	hdcp->hdcp2_supported = true;
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index f5d7bfb43006..41d2505a964b 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, false);
 		if (ret)
 			DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
 	}