@@ -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);
@@ -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.
@@ -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");
}
@@ -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);
@@ -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;
+}
@@ -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");
}
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(-)