-----Original Message----- From: C, Ramalingam Sent: Saturday, July 14, 2018 8:45 AM To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; seanpaul@chromium.org; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Cc: Sharma, Shashank shashank.sharma@intel.com; C, Ramalingam ramalingam.c@intel.com Subject: [PATCH v6 11/35] drm/i915: Enable and Disable of HDCP2.2
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: No changes. v4: Extra comment added and Style issue fixed [Uma] v5: Rebased as part of patch reordering. HDCP2 encryption status is tracked. HW state check is moved into WARN_ON [Daniel] v6: 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]
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_drv.h | 5 + drivers/gpu/drm/i915/intel_hdcp.c | 226 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 221 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 38262792813a..21683702bcdc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -380,6 +380,10 @@ struct intel_hdcp_shim {
/* Detects the HDCP protocol(DP/HDMI) required on the port */ enum hdcp_protocol (*hdcp_protocol)(void);
- /* Detects whether Panel is HDCP2.2 capable */
- int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port,
bool *capable);
};
struct intel_hdcp { @@ -393,6 +397,7 @@ struct intel_hdcp { /* HDCP2.2 related definitions */ /* Flag indicates whether this connector supports HDCP2.2 or not. */ bool hdcp2_supported;
bool hdcp2_in_use;
/*
- Content Stream Type defined by content owner. TYPE0(0x0) content
can diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 18509c3bae08..4ace64315baa 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -17,10 +17,51 @@ #include "i915_reg.h"
#define KEY_LOAD_TRIES 5 +#define TIME_FOR_ENCRYPT_STATUS_CHANGE 32 #define GET_MEI_DDI_INDEX(port) (((port) == PORT_A) ? DDI_A : \ (enum hdcp_physical_port)(port))
static int intel_hdcp2_init(struct intel_connector *connector); +static int _intel_hdcp2_enable(struct intel_connector *connector); +static int _intel_hdcp2_disable(struct intel_connector *connector); +static int intel_hdcp_read_valid_bksv(struct intel_digital_port +*intel_dig_port,
const struct intel_hdcp_shim *shim, u8 *bksv); static
struct +intel_digital_port *conn_to_dig_port(struct intel_connector +*connector);
+/* Is HDCP1.4 capable on Platform and Panel */ static bool
Instead of Panel, call it as sink.
+intel_hdcp_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;
- u8 bksv[5];
- if (hdcp->shim->hdcp_capable) {
hdcp->shim->hdcp_capable(intel_dig_port, &capable);
- } else {
if (!intel_hdcp_read_valid_bksv(intel_dig_port,
hdcp->shim, bksv))
capable = true;
- }
- return capable;
+}
+/* Is HDCP2.2 capable on Platform and Panel */ static bool
Same as above.
+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;
- /* Check the panel's hdcp2.2 compliance if platform supports it. */
Here too.
- if (hdcp->hdcp2_supported)
hdcp->shim->hdcp_2_2_capable(intel_dig_port, &capable);
- return capable;
+}
static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) @@ - 791,22 +832,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);
- }
x>- 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; } @@ -823,7 +875,10 @@ int intel_hdcp_disable(struct intel_connector *connector)
if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { hdcp->value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
ret = _intel_hdcp_disable(connector);
if (hdcp->hdcp2_in_use)
ret = _intel_hdcp2_disable(connector);
else
ret = _intel_hdcp_disable(connector);
}
mutex_unlock(&hdcp->mutex);
@@ -923,6 +978,157 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int hdcp2_close_mei_session(struct intel_connector *connector) {
The return value is not handled in the call chain. Please check for return value in the calling functions.
- struct mei_hdcp_data *data = &connector->hdcp.mei_data;
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct i915_component_master *comp = dev_priv->comp_master;
- if (!comp)
return -EINVAL;
- if (!comp->hdcp_ops || !comp->mei_cldev || data->port ==
INVALID_PORT)
return -EINVAL;
- return comp->hdcp_ops->close_hdcp_session(comp->mei_cldev, data); }
+static int hdcp2_deauthenticate_port(struct intel_connector *connector)
As Described above.
+{
- return hdcp2_close_mei_session(connector);
+}
+static int hdcp2_authenticate_sink(struct intel_connector *connector) {
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- 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)
hdcp->shim->toggle_signalling(intel_dig_port, true);
Handle the error returned.
- 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,
TIME_FOR_ENCRYPT_STATUS_CHANGE);
- 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,
TIME_FOR_ENCRYPT_STATUS_CHANGE);
- if (ret == -ETIMEDOUT)
DRM_DEBUG_KMS("Disable Encryption Timedout");
- if (hdcp->shim->toggle_signalling)
hdcp->shim->toggle_signalling(intel_dig_port, false);
- 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 */
hdcp2_deauthenticate_port(connector);
DRM_DEBUG_KMS("HDCP2.2 Auth %d of %d Failed.(%d)\n",
i + 1, tries, ret);
- }
- 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);
hdcp2_deauthenticate_port(connector);
}
- }
- 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_ERROR("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_in_use = true;
- 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);
- hdcp2_deauthenticate_port(connector);
- connector->hdcp.hdcp2_in_use = false;
- return ret;
+}
static int i915_hdcp_component_match(struct device *dev, void *data) { return !strcmp(dev->driver->name, "mei_hdcp"); -- 2.7.4