mbox series

[v14,00/35] drm/i915: Implement HDCP2.2

Message ID 1550219730-17734-1-git-send-email-ramalingam.c@intel.com (mailing list archive)
Headers show
Series drm/i915: Implement HDCP2.2 | expand

Message

Ramalingam C Feb. 15, 2019, 8:34 a.m. UTC
This series enables the HDCP2.2 Type 0 for I915. The sequence for
HDCP2.2 authentication and encryption is implemented as a generic flow
between HDMI and DP. Encoder specific implementations are moved
into hdcp_shim.

Intel HWs supports HDCP2.2 through ME FW. Hence this series
introduces a client driver for mei bus, so that for HDCP2.2
authentication, HDCP2.2 stack in I915 can avail the services from
ME FW. To enable this client driver set the config variable
CONFIG_INTEL_MEI_HDCP.

Userspace interface remains unchanged as version agnostic. When
userspace request for HDCP enable, Kernel will detect the HDCP source
and sink's HDCP version(1.4/2.2)capability and enable the best capable
version for that combination.

This series enables the HDCP2.2 for Type0 content streams.

Test-with: <1549566452-30175-1-git-send-email-ramalingam.c@intel.com>

Major changes in v14
  - enum port is moved into the drm/i915_drm.h
  - Small fixes for mei_hdcp Kernel-Doc
  - ICL device ID patch is already merged. So dropped it.

To ease the review process, series is hosted at
https://github.com/ramalingampc2008/drm-tip.git hdcp2_2_v14

Ramalingam C (33):
  drm/i915: Gathering the HDCP1.4 routines together
  drm: enum port definition is moved into i915_drm.h
  drm: header for i915 - MEI_HDCP interface
  drm/i915: Initialize HDCP2.2
  drm/i915: MEI interface definition
  drm/i915: hdcp1.4 CP_IRQ handling and SW encryption tracking
  drm/i915: Enable and Disable of HDCP2.2
  drm/i915: Implement HDCP2.2 receiver authentication
  drm: helper functions for hdcp2 seq_num to from u32
  drm/i915: Implement HDCP2.2 repeater authentication
  drm: HDCP2.2 link check period
  drm/i915: Implement HDCP2.2 link integrity check
  drm/i915: Handle HDCP2.2 downstream topology change
  drm: removing the DP Errata msg and its msg id
  drm/i915: Implement the HDCP2.2 support for DP
  drm/i915: Implement the HDCP2.2 support for HDMI
  drm/i915: CP_IRQ handling for DP HDCP2.2 msgs
  drm/i915: Fix KBL HDCP2.2 encrypt status signalling
  misc/mei/hdcp: Client driver for HDCP application
  misc/mei/hdcp: Define ME FW interface for HDCP2.2
  misc/mei/hdcp: Initiate Wired HDCP2.2 Tx Session
  misc/mei/hdcp: Verify Receiver Cert and prepare km
  misc/mei/hdcp: Verify H_prime
  misc/mei/hdcp: Store the HDCP Pairing info
  misc/mei/hdcp: Initiate Locality check
  misc/mei/hdcp: Verify L_prime
  misc/mei/hdcp: Prepare Session Key
  misc/mei/hdcp: Repeater topology verification and ack
  misc/mei/hdcp: Verify M_prime
  misc/mei/hdcp: Enabling the HDCP authentication
  misc/mei/hdcp: Closing wired HDCP2.2 Tx Session
  misc/mei/hdcp: Component framework for I915 Interface
  FOR_TEST_ONLY: i915/Kconfig: Select mei_hdcp by I915

Tomas Winkler (2):
  mei: bus: whitelist hdcp client
  mei: bus: export to_mei_cl_device for mei client device drivers

 drivers/gpu/drm/i915/i915_drv.c        |    1 +
 drivers/gpu/drm/i915/i915_drv.h        |    7 +
 drivers/gpu/drm/i915/intel_connector.c |    2 +
 drivers/gpu/drm/i915/intel_display.c   |    4 +
 drivers/gpu/drm/i915/intel_display.h   |   16 +-
 drivers/gpu/drm/i915/intel_dp.c        |  350 ++++++++-
 drivers/gpu/drm/i915/intel_drv.h       |   83 ++-
 drivers/gpu/drm/i915/intel_hdcp.c      | 1242 +++++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_hdmi.c      |  237 +++++-
 drivers/misc/mei/Kconfig               |    8 +
 drivers/misc/mei/Makefile              |    2 +
 drivers/misc/mei/bus-fixup.c           |   16 +
 drivers/misc/mei/bus.c                 |    1 -
 drivers/misc/mei/hdcp/Makefile         |    7 +
 drivers/misc/mei/hdcp/mei_hdcp.c       |  847 ++++++++++++++++++++++
 drivers/misc/mei/hdcp/mei_hdcp.h       |  377 ++++++++++
 include/drm/drm_hdcp.h                 |   25 +-
 include/drm/i915_component.h           |    3 +
 include/drm/i915_drm.h                 |   15 +
 include/drm/i915_mei_hdcp_interface.h  |  149 ++++
 include/linux/mei_cl_bus.h             |    2 +
 21 files changed, 3254 insertions(+), 140 deletions(-)
 create mode 100644 drivers/misc/mei/hdcp/Makefile
 create mode 100644 drivers/misc/mei/hdcp/mei_hdcp.c
 create mode 100644 drivers/misc/mei/hdcp/mei_hdcp.h
 create mode 100644 include/drm/i915_mei_hdcp_interface.h

Comments

Daniel Vetter Feb. 15, 2019, 5:53 p.m. UTC | #1
On Fri, Feb 15, 2019 at 02:05:00PM +0530, Ramalingam C wrote:
> Defining the mei-i915 interface functions and initialization of
> the interface.
> 
> v2:
>   Adjust to the new interface changes. [Tomas]
>   Added further debug logs for the failures at MEI i/f.
>   port in hdcp_port data is equipped to handle -ve values.
> v3:
>   mei comp is matched for global i915 comp master. [Daniel]
>   In hdcp_shim hdcp_protocol() is replaced with const variable. [Daniel]
>   mei wrappers are adjusted as per the i/f change [Daniel]
> v4:
>   port initialization is done only at hdcp2_init only [Danvet]
> v5:
>   I915 registers a subcomponent to be matched with mei_hdcp [Daniel]
> v6:
>   HDCP_disable for all connectors incase of comp_unbind.
>   Tear down HDCP comp interface at i915_unload [Daniel]
> v7:
>   Component init and fini are moved out of connector ops [Daniel]
>   hdcp_disable is not called from unbind. [Daniel]
> 
> Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> [v11]
> ---
>  drivers/gpu/drm/i915/i915_drv.c        |   1 +
>  drivers/gpu/drm/i915/i915_drv.h        |   7 +
>  drivers/gpu/drm/i915/intel_connector.c |   2 +
>  drivers/gpu/drm/i915/intel_display.c   |   4 +
>  drivers/gpu/drm/i915/intel_drv.h       |   8 +
>  drivers/gpu/drm/i915/intel_hdcp.c      | 398 ++++++++++++++++++++++++++++++++-
>  include/drm/i915_component.h           |   3 +
>  7 files changed, 422 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 6630212f2faf..c6354f6cdbdb 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -906,6 +906,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->hdcp_comp_mutex);
>  
>  	i915_memcpy_init_early(dev_priv);
>  	intel_runtime_pm_init_early(dev_priv);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 17fe942eaafa..a09c82c92ea5 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -55,6 +55,7 @@
>  #include <drm/drm_util.h>
>  #include <drm/drm_dsc.h>
>  #include <drm/drm_connector.h>
> +#include <drm/i915_mei_hdcp_interface.h>
>  
>  #include "i915_fixed.h"
>  #include "i915_params.h"
> @@ -2051,6 +2052,12 @@ struct drm_i915_private {
>  
>  	struct i915_pmu pmu;
>  
> +	struct i915_hdcp_comp_master *hdcp_master;
> +	bool hdcp_comp_added;
> +
> +	/* Mutex to protect the above hdcp component related values. */
> +	struct mutex hdcp_comp_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_connector.c b/drivers/gpu/drm/i915/intel_connector.c
> index ee16758747c5..66ed3ee5998a 100644
> --- a/drivers/gpu/drm/i915/intel_connector.c
> +++ b/drivers/gpu/drm/i915/intel_connector.c
> @@ -88,6 +88,8 @@ void intel_connector_destroy(struct drm_connector *connector)
>  
>  	kfree(intel_connector->detect_edid);
>  
> +	intel_hdcp_cleanup(intel_connector);
> +
>  	if (!IS_ERR_OR_NULL(intel_connector->edid))
>  		kfree(intel_connector->edid);
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 0a8913b2059e..97bce4707a4c 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -15459,6 +15459,8 @@ int intel_modeset_init(struct drm_device *dev)
>  	intel_update_czclk(dev_priv);
>  	intel_modeset_init_hw(dev);
>  
> +	intel_hdcp_component_init(dev_priv);
> +
>  	if (dev_priv->max_cdclk_freq == 0)
>  		intel_update_max_cdclk(dev_priv);
>  
> @@ -16320,6 +16322,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
>  	/* flush any delayed tasks or pending work */
>  	flush_scheduled_work();
>  
> +	intel_hdcp_component_fini(dev_priv);
> +
>  	drm_mode_config_cleanup(dev);
>  
>  	intel_overlay_cleanup(dev_priv);
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 11c696025085..f8e8482573c8 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -41,6 +41,7 @@
>  #include <drm/drm_rect.h>
>  #include <drm/drm_vblank.h>
>  #include <drm/drm_atomic.h>
> +#include <drm/i915_mei_hdcp_interface.h>
>  #include <media/cec-notifier.h>
>  
>  struct drm_printer;
> @@ -395,6 +396,9 @@ struct intel_hdcp_shim {
>  	/* Detects panel's hdcp capability. This is optional for HDMI. */
>  	int (*hdcp_capable)(struct intel_digital_port *intel_dig_port,
>  			    bool *hdcp_capable);
> +
> +	/* HDCP adaptation(DP/HDMI) required on the port */
> +	enum hdcp_wired_protocol protocol;
>  };
>  
>  struct intel_hdcp {
> @@ -415,6 +419,7 @@ struct intel_hdcp {
>  	 * content can flow only through a link protected by HDCP2.2.
>  	 */
>  	u8 content_type;
> +	struct hdcp_port_data port_data;
>  };
>  
>  struct intel_connector {
> @@ -2088,6 +2093,9 @@ int intel_hdcp_disable(struct intel_connector *connector);
>  int intel_hdcp_check_link(struct intel_connector *connector);
>  bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
>  bool intel_hdcp_capable(struct intel_connector *connector);
> +void intel_hdcp_component_init(struct drm_i915_private *dev_priv);
> +void intel_hdcp_component_fini(struct drm_i915_private *dev_priv);
> +void intel_hdcp_cleanup(struct intel_connector *connector);
>  
>  /* intel_psr.c */
>  #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
> diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
> index 7b1097d79fb8..d06bef9d1ab2 100644
> --- a/drivers/gpu/drm/i915/intel_hdcp.c
> +++ b/drivers/gpu/drm/i915/intel_hdcp.c
> @@ -7,8 +7,10 @@
>   */
>  
>  #include <drm/drm_hdcp.h>
> +#include <drm/i915_component.h>
>  #include <linux/i2c.h>
>  #include <linux/random.h>
> +#include <linux/component.h>
>  
>  #include "intel_drv.h"
>  #include "i915_reg.h"
> @@ -832,6 +834,347 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
>  	return INTEL_GEN(dev_priv) >= 9 && port < PORT_E;
>  }
>  
> +static __attribute__((unused)) int
> +hdcp2_prepare_ake_init(struct intel_connector *connector,
> +		       struct hdcp2_ake_init *ake_data)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->initiate_hdcp2_session(comp->mei_dev, data, ake_data);
> +	if (ret)
> +		DRM_DEBUG_KMS("Prepare_ake_init failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused)) int
> +hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector,
> +				struct hdcp2_ake_send_cert *rx_cert,
> +				bool *paired,
> +				struct hdcp2_ake_no_stored_km *ek_pub_km,
> +				size_t *msg_sz)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->verify_receiver_cert_prepare_km(comp->mei_dev, data,
> +							 rx_cert, paired,
> +							 ek_pub_km, msg_sz);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Verify rx_cert failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused)) int
> +hdcp2_verify_hprime(struct intel_connector *connector,
> +		    struct hdcp2_ake_send_hprime *rx_hprime)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->verify_hprime(comp->mei_dev, data, rx_hprime);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Verify hprime failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused)) int
> +hdcp2_store_pairing_info(struct intel_connector *connector,
> +			 struct hdcp2_ake_send_pairing_info *pairing_info)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->store_pairing_info(comp->mei_dev, data, pairing_info);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Store pairing info failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused)) int
> +hdcp2_prepare_lc_init(struct intel_connector *connector,
> +		      struct hdcp2_lc_init *lc_init)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->initiate_locality_check(comp->mei_dev, data, lc_init);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Prepare lc_init failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused)) int
> +hdcp2_verify_lprime(struct intel_connector *connector,
> +		    struct hdcp2_lc_send_lprime *rx_lprime)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->verify_lprime(comp->mei_dev, data, rx_lprime);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Verify L_Prime failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused))
> +int hdcp2_prepare_skey(struct intel_connector *connector,
> +		       struct hdcp2_ske_send_eks *ske_data)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->get_session_key(comp->mei_dev, data, ske_data);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Get session key failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused)) int
> +hdcp2_verify_rep_topology_prepare_ack(struct intel_connector *connector,
> +				      struct hdcp2_rep_send_receiverid_list
> +								*rep_topology,
> +				      struct hdcp2_rep_send_ack *rep_send_ack)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->repeater_check_flow_prepare_ack(comp->mei_dev, data,
> +							 rep_topology,
> +							 rep_send_ack);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Verify rep topology failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused)) int
> +hdcp2_verify_mprime(struct intel_connector *connector,
> +		    struct hdcp2_rep_stream_ready *stream_ready)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->verify_mprime(comp->mei_dev, data, stream_ready);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Verify mprime failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused))
> +int hdcp2_authenticate_port(struct intel_connector *connector)
> +{
> +	struct hdcp_port_data *data = &connector->hdcp.port_data;
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->enable_hdcp_authentication(comp->mei_dev, data);
> +	if (ret < 0)
> +		DRM_DEBUG_KMS("Enable hdcp auth failed. %d\n", ret);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused))
> +int hdcp2_close_mei_session(struct intel_connector *connector)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
> +	struct i915_hdcp_comp_master *comp;
> +	int ret;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	comp = dev_priv->hdcp_master;
> +
> +	if (!comp || !comp->ops) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return -EINVAL;
> +	}
> +
> +	ret = comp->ops->close_hdcp_session(comp->mei_dev,
> +					     &connector->hdcp.port_data);
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return ret;
> +}
> +
> +static __attribute__((unused))
> +int hdcp2_deauthenticate_port(struct intel_connector *connector)
> +{
> +	return hdcp2_close_mei_session(connector);
> +}
> +
> +static int i915_hdcp_component_bind(struct device *i915_kdev,
> +				    struct device *mei_kdev, void *data)
> +{
> +	struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
> +
> +	DRM_DEBUG("I915 HDCP comp bind\n");
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	dev_priv->hdcp_master = (struct i915_hdcp_comp_master *)data;
> +	dev_priv->hdcp_master->mei_dev = mei_kdev;
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	return 0;
> +}
> +
> +static void i915_hdcp_component_unbind(struct device *i915_kdev,
> +				       struct device *mei_kdev, void *data)
> +{
> +	struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
> +
> +	DRM_DEBUG("I915 HDCP comp unbind\n");
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	dev_priv->hdcp_master = NULL;
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +}
> +
> +static const struct component_ops i915_hdcp_component_ops = {
> +	.bind   = i915_hdcp_component_bind,
> +	.unbind = i915_hdcp_component_unbind,
> +};
> +
> +static inline int initialize_hdcp_port_data(struct intel_connector *connector)
> +{
> +	struct intel_hdcp *hdcp = &connector->hdcp;
> +	struct hdcp_port_data *data = &hdcp->port_data;
> +
> +	data->port = connector->encoder->port;
> +	data->port_type = (u8)HDCP_PORT_TYPE_INTEGRATED;
> +	data->protocol = (u8)hdcp->shim->protocol;
> +
> +	data->k = 1;
> +	if (!data->streams)
> +		data->streams = kcalloc(data->k,
> +					sizeof(struct hdcp2_streamid_type),
> +					GFP_KERNEL);
> +	if (!data->streams) {
> +		DRM_ERROR("Out of Memory\n");
> +		return -ENOMEM;
> +	}
> +
> +	data->streams[0].stream_id = 0;
> +	data->streams[0].stream_type = hdcp->content_type;
> +
> +	return 0;
> +}
> +
>  static bool is_hdcp2_supported(struct drm_i915_private *dev_priv)
>  {
>  	if (!IS_ENABLED(CONFIG_INTEL_MEI_HDCP))
> @@ -841,11 +1184,40 @@ static bool is_hdcp2_supported(struct drm_i915_private *dev_priv)
>  		IS_KABYLAKE(dev_priv));
>  }
>  
> +void intel_hdcp_component_init(struct drm_i915_private *dev_priv)
> +{
> +	int ret;
> +
> +	if (!is_hdcp2_supported(dev_priv))
> +		return;
> +
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	WARN_ON(dev_priv->hdcp_comp_added);
> +
> +	dev_priv->hdcp_comp_added = true;
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +	ret = component_add_typed(dev_priv->drm.dev, &i915_hdcp_component_ops,
> +				  I915_COMPONENT_HDCP);
> +	if (ret < 0) {
> +		DRM_DEBUG_KMS("Failed at component add(%d)\n", ret);
> +		mutex_lock(&dev_priv->hdcp_comp_mutex);
> +		dev_priv->hdcp_comp_added = false;
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return;
> +	}
> +}
> +
>  static void intel_hdcp2_init(struct intel_connector *connector)
>  {
>  	struct intel_hdcp *hdcp = &connector->hdcp;
> +	int ret;
> +
> +	ret = initialize_hdcp_port_data(connector);
> +	if (ret) {
> +		DRM_DEBUG_KMS("Mei hdcp data init failed\n");
> +		return;
> +	}
>  
> -	/* TODO: MEI interface needs to be initialized here */
>  	hdcp->hdcp2_supported = true;
>  }
>  
> @@ -917,6 +1289,30 @@ int intel_hdcp_disable(struct intel_connector *connector)
>  	return ret;
>  }
>  
> +void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
> +{
> +	mutex_lock(&dev_priv->hdcp_comp_mutex);
> +	if (!dev_priv->hdcp_comp_added) {
> +		mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +		return;
> +	}
> +
> +	dev_priv->hdcp_comp_added = false;
> +	mutex_unlock(&dev_priv->hdcp_comp_mutex);
> +
> +	component_del(dev_priv->drm.dev, &i915_hdcp_component_ops);
> +}
> +
> +void intel_hdcp_cleanup(struct intel_connector *connector)
> +{
> +	if (!connector->hdcp.shim)
> +		return;
> +
> +	mutex_lock(&connector->hdcp.mutex);
> +	kfree(connector->hdcp.port_data.streams);
> +	mutex_unlock(&connector->hdcp.mutex);
> +}
> +
>  void intel_hdcp_atomic_check(struct drm_connector *connector,
>  			     struct drm_connector_state *old_state,
>  			     struct drm_connector_state *new_state)
> diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
> index 72fbb037f9b3..f3851ba3e4c3 100644
> --- a/include/drm/i915_component.h
> +++ b/include/drm/i915_component.h
> @@ -24,10 +24,13 @@
>  #ifndef _I915_COMPONENT_H_
>  #define _I915_COMPONENT_H_
>  
> +#include <linux/device.h>
> +

I think this isn't needed anymore, or at least no there?

>  #include "drm_audio_component.h"
>  
>  enum i915_component_type {
>  	I915_COMPONENT_AUDIO = 1,
> +	I915_COMPONENT_HDCP,

We need this for the topic branch for mei-hdcp, so I merged this patch,
but only with this line, to topic/mei-hdcp. Might get a bit tricky with
rebasing, but should otherwise be all fine.
-Daniel

>  };
>  
>  /* MAX_PORT is the number of port
> -- 
> 2.7.4
>