Message ID | 1548917996-28081-7-git-send-email-ramalingam.c@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/i915: Implement HDCP2.2 | expand |
On Thu, Jan 31, 2019 at 12:29:22PM +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] > > Signed-off-by: Ramalingam C <ramalingam.c@intel.com> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> When you make substantial changes to a patch (like here) and decide to keep the r-b, then please indicate that it was for an earlier version. I most definitely didn't review this one that re-adds all the locking :-) What's missing here is the component_del. Not exactly sure why this doesn't blow up. Luckily we don't need a component_del_typed because component_del already takes the (dev, ops) pair, and that's unique. -Daniel > --- > drivers/gpu/drm/i915/i915_drv.c | 1 + > drivers/gpu/drm/i915/i915_drv.h | 7 + > drivers/gpu/drm/i915/intel_drv.h | 5 + > drivers/gpu/drm/i915/intel_hdcp.c | 378 +++++++++++++++++++++++++++++++++++++- > include/drm/i915_component.h | 3 + > 5 files changed, 393 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c > index a7aaa1ac4c99..75aff907ba69 100644 > --- a/drivers/gpu/drm/i915/i915_drv.c > +++ b/drivers/gpu/drm/i915/i915_drv.c > @@ -904,6 +904,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 22da9df1f0a7..d9a0771af4d1 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" > @@ -2043,6 +2044,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_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 0ac870feb5e9..63e009286d5f 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; > @@ -385,6 +386,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 { > @@ -405,6 +409,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 { > diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c > index 1a85dc46692d..e0bb5f32ba90 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,348 @@ 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->mei_dev = NULL; > + 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 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; > +} > + > bool is_hdcp2_supported(struct drm_i915_private *dev_priv) > { > if (!IS_ENABLED(CONFIG_INTEL_MEI_HDCP)) > @@ -845,10 +1189,42 @@ static void intel_hdcp2_init(struct intel_connector *connector) > { > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); > struct intel_hdcp *hdcp = &connector->hdcp; > + bool add_component = false; > + int ret; > > WARN_ON(!is_hdcp2_supported(dev_priv)); > > - /* TODO: MEI interface needs to be initialized here */ > + ret = initialize_hdcp_port_data(connector); > + if (ret) { > + DRM_DEBUG_KMS("Mei hdcp data init failed\n"); > + return; > + } > + > + mutex_lock(&dev_priv->hdcp_comp_mutex); > + /* > + * Component for mei is common across the connector. > + * Adding the component once is sufficient. > + */ > + if (!dev_priv->hdcp_comp_added) { > + dev_priv->hdcp_comp_added = true; > + add_component = true; > + } > + mutex_unlock(&dev_priv->hdcp_comp_mutex); > + > + if (add_component) { > + 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); > + kfree(hdcp->port_data.streams); > + return; > + } > + } > + > hdcp->hdcp2_supported = true; > } > > 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> > + > #include "drm_audio_component.h" > > enum i915_component_type { > I915_COMPONENT_AUDIO = 1, > + I915_COMPONENT_HDCP, > }; > > /* MAX_PORT is the number of port > -- > 2.7.4 >
On 1/31/2019 1:47 PM, Daniel Vetter wrote: > On Thu, Jan 31, 2019 at 12:29:22PM +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] >> >> Signed-off-by: Ramalingam C <ramalingam.c@intel.com> >> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> > When you make substantial changes to a patch (like here) and decide to > keep the r-b, then please indicate that it was for an earlier version. I > most definitely didn't review this one that re-adds all the locking :-) sure :) > > What's missing here is the component_del. Not exactly sure why this > doesn't blow up. That is weird. But yes note the absence of _del. I will introduce the the call to hdcp_exit at unload and handle the component_del. > Luckily we don't need a component_del_typed because > component_del already takes the (dev, ops) pair, and that's unique. yes true. -Ram > -Daniel > > >> --- >> drivers/gpu/drm/i915/i915_drv.c | 1 + >> drivers/gpu/drm/i915/i915_drv.h | 7 + >> drivers/gpu/drm/i915/intel_drv.h | 5 + >> drivers/gpu/drm/i915/intel_hdcp.c | 378 +++++++++++++++++++++++++++++++++++++- >> include/drm/i915_component.h | 3 + >> 5 files changed, 393 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c >> index a7aaa1ac4c99..75aff907ba69 100644 >> --- a/drivers/gpu/drm/i915/i915_drv.c >> +++ b/drivers/gpu/drm/i915/i915_drv.c >> @@ -904,6 +904,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 22da9df1f0a7..d9a0771af4d1 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" >> @@ -2043,6 +2044,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_drv.h b/drivers/gpu/drm/i915/intel_drv.h >> index 0ac870feb5e9..63e009286d5f 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; >> @@ -385,6 +386,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 { >> @@ -405,6 +409,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 { >> diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c >> index 1a85dc46692d..e0bb5f32ba90 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,348 @@ 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->mei_dev = NULL; >> + 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 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; >> +} >> + >> bool is_hdcp2_supported(struct drm_i915_private *dev_priv) >> { >> if (!IS_ENABLED(CONFIG_INTEL_MEI_HDCP)) >> @@ -845,10 +1189,42 @@ static void intel_hdcp2_init(struct intel_connector *connector) >> { >> struct drm_i915_private *dev_priv = to_i915(connector->base.dev); >> struct intel_hdcp *hdcp = &connector->hdcp; >> + bool add_component = false; >> + int ret; >> >> WARN_ON(!is_hdcp2_supported(dev_priv)); >> >> - /* TODO: MEI interface needs to be initialized here */ >> + ret = initialize_hdcp_port_data(connector); >> + if (ret) { >> + DRM_DEBUG_KMS("Mei hdcp data init failed\n"); >> + return; >> + } >> + >> + mutex_lock(&dev_priv->hdcp_comp_mutex); >> + /* >> + * Component for mei is common across the connector. >> + * Adding the component once is sufficient. >> + */ >> + if (!dev_priv->hdcp_comp_added) { >> + dev_priv->hdcp_comp_added = true; >> + add_component = true; >> + } >> + mutex_unlock(&dev_priv->hdcp_comp_mutex); >> + >> + if (add_component) { >> + 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); >> + kfree(hdcp->port_data.streams); >> + return; >> + } >> + } >> + >> hdcp->hdcp2_supported = true; >> } >> >> 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> >> + >> #include "drm_audio_component.h" >> >> enum i915_component_type { >> I915_COMPONENT_AUDIO = 1, >> + I915_COMPONENT_HDCP, >> }; >> >> /* MAX_PORT is the number of port >> -- >> 2.7.4 >>
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a7aaa1ac4c99..75aff907ba69 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -904,6 +904,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 22da9df1f0a7..d9a0771af4d1 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" @@ -2043,6 +2044,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_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0ac870feb5e9..63e009286d5f 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; @@ -385,6 +386,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 { @@ -405,6 +409,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 { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 1a85dc46692d..e0bb5f32ba90 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,348 @@ 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->mei_dev = NULL; + 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 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; +} + bool is_hdcp2_supported(struct drm_i915_private *dev_priv) { if (!IS_ENABLED(CONFIG_INTEL_MEI_HDCP)) @@ -845,10 +1189,42 @@ static void intel_hdcp2_init(struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; + bool add_component = false; + int ret; WARN_ON(!is_hdcp2_supported(dev_priv)); - /* TODO: MEI interface needs to be initialized here */ + ret = initialize_hdcp_port_data(connector); + if (ret) { + DRM_DEBUG_KMS("Mei hdcp data init failed\n"); + return; + } + + mutex_lock(&dev_priv->hdcp_comp_mutex); + /* + * Component for mei is common across the connector. + * Adding the component once is sufficient. + */ + if (!dev_priv->hdcp_comp_added) { + dev_priv->hdcp_comp_added = true; + add_component = true; + } + mutex_unlock(&dev_priv->hdcp_comp_mutex); + + if (add_component) { + 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); + kfree(hdcp->port_data.streams); + return; + } + } + hdcp->hdcp2_supported = true; } 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> + #include "drm_audio_component.h" enum i915_component_type { I915_COMPONENT_AUDIO = 1, + I915_COMPONENT_HDCP, }; /* MAX_PORT is the number of port