On Thu, Dec 13, 2018 at 09:31:11AM +0530, Ramalingam C wrote: > Considering that HDCP2.2 is more secure than HDCP1.4, When a setup > supports HDCP2.2 and HDCP1.4, HDCP2.2 will be enabled. > > When HDCP2.2 enabling fails and HDCP1.4 is supported, HDCP1.4 is > enabled. > > This change implements a sequence of enabling and disabling of > HDCP2.2 authentication and HDCP2.2 port encryption. > > v2: > Included few optimization suggestions [Chris Wilson] > Commit message is updated as per the rebased version. > intel_wait_for_register is used instead of wait_for. [Chris Wilson] > v3: > Extra comment added and Style issue fixed [Uma] > v4: > Rebased as part of patch reordering. > HDCP2 encryption status is tracked. > HW state check is moved into WARN_ON [Daniel] > v5: > Redefined the mei service functions as per comp redesign. > Merged patches related to hdcp2.2 enabling and disabling [Sean Paul]. > Required shim functionality is defined [Sean Paul] > v6: > Return values are handles [Uma] > Realigned the code. > Check for comp_master is removed. > v7: > HDCP2.2 is attempted only if mei interface is up. > Adjust to the new interface > Avoid bool usage in struct [Tomas] > v8: > mei_binded status check is removed. > %s/hdcp2_in_use/hdcp2_encrypted > > Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx> lgtm now. Reviewed-by: Daniel Vetter <daniel.vetter@xxxxxxxx> > --- > drivers/gpu/drm/i915/intel_drv.h | 7 ++ > drivers/gpu/drm/i915/intel_hdcp.c | 202 +++++++++++++++++++++++++++++++++++--- > 2 files changed, 195 insertions(+), 14 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index decd0346c6a7..6d5361616ca3 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -383,6 +383,10 @@ struct intel_hdcp_shim { > > /* HDCP adaptation(DP/HDMI) required on the port */ > enum hdcp_wired_protocol protocol; > + > + /* Detects whether Panel is HDCP2.2 capable */ > + int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port, > + bool *capable); > }; > > struct intel_hdcp { > @@ -400,6 +404,9 @@ struct intel_hdcp { > /* Flag indicates whether this connector supports HDCP2.2 or not. */ > u8 hdcp2_supported; > > + /* HDCP2.2 Encryption status */ > + u8 hdcp2_encrypted; > + > /* > * Content Stream Type defined by content owner. TYPE0(0x0) content can > * flow in the link protected by HDCP2.2 or HDCP1.4, where as TYPE1(0x1) > diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c > index 2b7814a6f12b..f0ee448e6546 100644 > --- a/drivers/gpu/drm/i915/intel_hdcp.c > +++ b/drivers/gpu/drm/i915/intel_hdcp.c > @@ -75,6 +75,23 @@ bool intel_hdcp_capable(struct intel_connector *connector) > return capable; > } > > +/* Is HDCP2.2 capable on Platform and Sink */ > +static bool intel_hdcp2_capable(struct intel_connector *connector) > +{ > + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); > + struct intel_hdcp *hdcp = &connector->hdcp; > + bool capable = false; > + > + /* I915 support for HDCP2.2 */ > + if (!hdcp->hdcp2_supported) > + return false; > + > + /* Sink's capability for HDCP2.2 */ > + hdcp->shim->hdcp_2_2_capable(intel_dig_port, &capable); > + > + return capable; > +} > + > static inline bool intel_hdcp_in_use(struct intel_connector *connector) > { > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); > @@ -1014,8 +1031,7 @@ int hdcp2_authenticate_port(struct intel_connector *connector) > return ret; > } > > -static __attribute__((unused)) > -int hdcp2_close_mei_session(struct intel_connector *connector) > +static int hdcp2_close_mei_session(struct intel_connector *connector) > { > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); > struct i915_component_master *comp = dev_priv->comp_master; > @@ -1024,12 +1040,157 @@ int hdcp2_close_mei_session(struct intel_connector *connector) > &connector->hdcp.port_data); > } > > -static __attribute__((unused)) > -int hdcp2_deauthenticate_port(struct intel_connector *connector) > +static int hdcp2_deauthenticate_port(struct intel_connector *connector) > { > return hdcp2_close_mei_session(connector); > } > > +static int hdcp2_authenticate_sink(struct intel_connector *connector) > +{ > + DRM_ERROR("Sink authentication is done in subsequent patches\n"); > + > + return -EINVAL; > +} > + > +static int hdcp2_enable_encryption(struct intel_connector *connector) > +{ > + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); > + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); > + struct intel_hdcp *hdcp = &connector->hdcp; > + enum port port = connector->encoder->port; > + int ret; > + > + WARN_ON(I915_READ(HDCP2_STATUS_DDI(port)) & LINK_ENCRYPTION_STATUS); > + > + if (hdcp->shim->toggle_signalling) { > + ret = hdcp->shim->toggle_signalling(intel_dig_port, true); > + if (ret) { > + DRM_ERROR("Failed to enable HDCP signalling. %d\n", > + ret); > + return ret; > + } > + } > + > + if (I915_READ(HDCP2_STATUS_DDI(port)) & LINK_AUTH_STATUS) { > + /* Link is Authenticated. Now set for Encryption */ > + I915_WRITE(HDCP2_CTL_DDI(port), > + I915_READ(HDCP2_CTL_DDI(port)) | > + CTL_LINK_ENCRYPTION_REQ); > + } > + > + ret = intel_wait_for_register(dev_priv, HDCP2_STATUS_DDI(port), > + LINK_ENCRYPTION_STATUS, > + LINK_ENCRYPTION_STATUS, > + ENCRYPT_STATUS_CHANGE_TIMEOUT_MS); > + > + return ret; > +} > + > +static int hdcp2_disable_encryption(struct intel_connector *connector) > +{ > + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); > + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); > + struct intel_hdcp *hdcp = &connector->hdcp; > + enum port port = connector->encoder->port; > + int ret; > + > + WARN_ON(!(I915_READ(HDCP2_STATUS_DDI(port)) & LINK_ENCRYPTION_STATUS)); > + > + I915_WRITE(HDCP2_CTL_DDI(port), > + I915_READ(HDCP2_CTL_DDI(port)) & ~CTL_LINK_ENCRYPTION_REQ); > + > + ret = intel_wait_for_register(dev_priv, HDCP2_STATUS_DDI(port), > + LINK_ENCRYPTION_STATUS, 0x0, > + ENCRYPT_STATUS_CHANGE_TIMEOUT_MS); > + if (ret == -ETIMEDOUT) > + DRM_DEBUG_KMS("Disable Encryption Timedout"); > + > + if (hdcp->shim->toggle_signalling) { > + ret = hdcp->shim->toggle_signalling(intel_dig_port, false); > + if (ret) { > + DRM_ERROR("Failed to disable HDCP signalling. %d\n", > + ret); > + return ret; > + } > + } > + > + return ret; > +} > + > +static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector) > +{ > + int ret, i, tries = 3; > + > + for (i = 0; i < tries; i++) { > + ret = hdcp2_authenticate_sink(connector); > + if (!ret) > + break; > + > + /* Clearing the mei hdcp session */ > + DRM_DEBUG_KMS("HDCP2.2 Auth %d of %d Failed.(%d)\n", > + i + 1, tries, ret); > + if (hdcp2_deauthenticate_port(connector) < 0) > + DRM_DEBUG_KMS("Port deauth failed.\n"); > + } > + > + if (i != tries) { > + /* > + * Ensuring the required 200mSec min time interval between > + * Session Key Exchange and encryption. > + */ > + msleep(HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN); > + ret = hdcp2_enable_encryption(connector); > + if (ret < 0) { > + DRM_DEBUG_KMS("Encryption Enable Failed.(%d)\n", ret); > + if (hdcp2_deauthenticate_port(connector) < 0) > + DRM_DEBUG_KMS("Port deauth failed.\n"); > + } > + } > + > + return ret; > +} > + > +static int _intel_hdcp2_enable(struct intel_connector *connector) > +{ > + struct intel_hdcp *hdcp = &connector->hdcp; > + int ret; > + > + DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being enabled. Type: %d\n", > + connector->base.name, connector->base.base.id, > + hdcp->content_type); > + > + ret = hdcp2_authenticate_and_encrypt(connector); > + if (ret) { > + DRM_DEBUG_KMS("HDCP2 Type%d Enabling Failed. (%d)\n", > + hdcp->content_type, ret); > + return ret; > + } > + > + DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is enabled. Type %d\n", > + connector->base.name, connector->base.base.id, > + hdcp->content_type); > + > + hdcp->hdcp2_encrypted = 1; > + return 0; > +} > + > +static int _intel_hdcp2_disable(struct intel_connector *connector) > +{ > + int ret; > + > + DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being Disabled\n", > + connector->base.name, connector->base.base.id); > + > + ret = hdcp2_disable_encryption(connector); > + > + if (hdcp2_deauthenticate_port(connector) < 0) > + DRM_DEBUG_KMS("Port deauth failed.\n"); > + > + connector->hdcp.hdcp2_encrypted = 0; > + > + return ret; > +} > + > static inline void _intel_hdcp_check_work(struct intel_connector *connector) > { > struct intel_hdcp *hdcp = &connector->hdcp; > @@ -1145,22 +1306,33 @@ int intel_hdcp_init(struct intel_connector *connector, > int intel_hdcp_enable(struct intel_connector *connector) > { > struct intel_hdcp *hdcp = &connector->hdcp; > - int ret; > + int ret = -EINVAL; > > if (!hdcp->shim) > return -ENOENT; > > mutex_lock(&hdcp->mutex); > > - ret = _intel_hdcp_enable(connector); > - if (ret) > - goto out; > + /* > + * Considering that HDCP2.2 is more secure than HDCP1.4, If the setup > + * is capable of HDCP2.2, it is preferred to use HDCP2.2. > + */ > + if (intel_hdcp2_capable(connector)) > + ret = _intel_hdcp2_enable(connector); > + > + /* When HDCP2.2 fails, HDCP1.4 will be attempted */ > + if (ret && intel_hdcp_capable(connector)) { > + ret = _intel_hdcp_enable(connector); > + if (!ret) > + schedule_delayed_work(&hdcp->check_work, > + DRM_HDCP_CHECK_PERIOD_MS); > + } > + > + if (!ret) { > + hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED; > + schedule_work(&hdcp->prop_work); > + } > > - hdcp->value = DRM_MODE_CONTENT_PROTECTION_ENABLED; > - schedule_work(&hdcp->prop_work); > - schedule_delayed_work(&hdcp->check_work, > - DRM_HDCP_CHECK_PERIOD_MS); > -out: > mutex_unlock(&hdcp->mutex); > return ret; > } > @@ -1177,7 +1349,9 @@ int intel_hdcp_disable(struct intel_connector *connector) > > if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { > hdcp->value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; > - if (hdcp->hdcp_encrypted) > + if (hdcp->hdcp2_encrypted) > + ret = _intel_hdcp2_disable(connector); > + else if (hdcp->hdcp_encrypted) > ret = _intel_hdcp_disable(connector); > } > > -- > 2.7.4 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel