@@ -28,6 +28,7 @@
#include <linux/string_helpers.h>
#include <drm/display/drm_scdc_helper.h>
+#include <drm/display/drm_hdcp_helper.h>
#include <drm/drm_privacy_screen_consumer.h>
#include "i915_drv.h"
@@ -2941,6 +2942,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
+ struct intel_connector *connector =
+ to_intel_connector(conn_state->connector);
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
drm_WARN_ON(state->base.dev, crtc_state->has_pch_encoder);
if (!intel_crtc_is_bigjoiner_slave(crtc_state))
@@ -2957,12 +2962,10 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
else
intel_enable_ddi_dp(state, encoder, crtc_state, conn_state);
- /* Enable hdcp if it's desired */
- if (conn_state->content_protection ==
- DRM_MODE_CONTENT_PROTECTION_DESIRED)
- intel_hdcp_enable(to_intel_connector(conn_state->connector),
- crtc_state,
- (u8)conn_state->hdcp_content_type);
+ if (connector->hdcp_helper_data)
+ drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+ &state->base,
+ &dig_port->hdcp_mutex);
}
static void intel_disable_ddi_dp(struct intel_atomic_state *state,
@@ -3008,7 +3011,14 @@ static void intel_disable_ddi(struct intel_atomic_state *state,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
{
- intel_hdcp_disable(to_intel_connector(old_conn_state->connector));
+ struct intel_connector *connector =
+ to_intel_connector(old_conn_state->connector);
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
+
+ if (connector->hdcp_helper_data)
+ drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+ &state->base,
+ &dig_port->hdcp_mutex);
if (intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_HDMI))
intel_disable_ddi_hdmi(state, encoder, old_crtc_state,
@@ -3036,13 +3046,19 @@ void intel_ddi_update_pipe(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
+ struct intel_connector *connector =
+ to_intel_connector(conn_state->connector);
+ struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) &&
!intel_encoder_is_mst(encoder))
intel_ddi_update_pipe_dp(state, encoder, crtc_state,
conn_state);
- intel_hdcp_update_pipe(state, encoder, crtc_state, conn_state);
+ if (connector->hdcp_helper_data)
+ drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+ &state->base,
+ &dig_port->hdcp_mutex);
}
static void
@@ -7,6 +7,7 @@
#include <drm/drm_debugfs.h>
#include <drm/drm_fourcc.h>
+#include <drm/display/drm_hdcp_helper.h>
#include "i915_debugfs.h"
#include "i915_irq.h"
@@ -502,10 +503,11 @@ static void intel_hdcp_info(struct seq_file *m,
goto out;
}
- ret = intel_hdcp_capable(intel_connector, &hdcp_cap);
+ ret = intel_connector->hdcp_helper_data->funcs->hdcp1_capable(
+ intel_connector->hdcp_helper_data, &hdcp_cap);
if (ret)
hdcp_cap = false;
- ret = intel_hdcp2_capable(intel_connector, &hdcp2_cap);
+ ret = intel_hdcp2_capable(&intel_connector->base, &hdcp2_cap);
if (ret)
hdcp2_cap = false;
@@ -430,64 +430,14 @@ enum check_link_response {
* to send it over DP AUX vs DDC
*/
struct intel_hdcp_shim {
- /* Outputs the transmitter's An and Aksv values to the receiver. */
- int (*write_an_aksv)(struct intel_digital_port *dig_port, u8 *an);
-
- /* Reads the receiver's key selection vector */
- int (*read_bksv)(struct intel_digital_port *dig_port, u8 *bksv);
-
- /*
- * Reads BINFO from DP receivers and BSTATUS from HDMI receivers. The
- * definitions are the same in the respective specs, but the names are
- * different. Call it BSTATUS since that's the name the HDMI spec
- * uses and it was there first.
- */
- int (*read_bstatus)(struct intel_digital_port *dig_port,
- u8 *bstatus);
-
- /* Determines whether a repeater is present downstream */
- int (*repeater_present)(struct intel_digital_port *dig_port,
- bool *repeater_present);
-
- /* Reads the receiver's Ri' value */
- int (*read_ri_prime)(struct intel_digital_port *dig_port, u8 *ri);
-
- /* Determines if the receiver's KSV FIFO is ready for consumption */
- int (*read_ksv_ready)(struct intel_digital_port *dig_port,
- bool *ksv_ready);
-
- /* Reads the ksv fifo for num_downstream devices */
- int (*read_ksv_fifo)(struct intel_digital_port *dig_port,
- int num_downstream, u8 *ksv_fifo);
-
- /* Reads a 32-bit part of V' from the receiver */
- int (*read_v_prime_part)(struct intel_digital_port *dig_port,
- int i, u32 *part);
-
/* Enables HDCP signalling on the port */
int (*toggle_signalling)(struct intel_digital_port *dig_port,
enum transcoder cpu_transcoder,
bool enable);
- /* Enable/Disable stream encryption on DP MST Transport Link */
- int (*stream_encryption)(struct intel_connector *connector,
- bool enable);
-
- /* Ensures the link is still protected */
- bool (*check_link)(struct intel_digital_port *dig_port,
- struct intel_connector *connector);
-
- /* Detects panel's hdcp capability. This is optional for HDMI. */
- int (*hdcp_capable)(struct intel_digital_port *dig_port,
- bool *hdcp_capable);
-
/* HDCP adaptation(DP/HDMI) required on the port */
enum hdcp_wired_protocol protocol;
- /* Detects whether sink is HDCP2.2 capable */
- int (*hdcp_2_2_capable)(struct intel_digital_port *dig_port,
- bool *capable);
-
/* Write HDCP2.2 messages */
int (*write_2_2_msg)(struct intel_digital_port *dig_port,
void *buf, size_t size);
@@ -610,6 +560,7 @@ struct intel_connector {
struct work_struct modeset_retry_work;
struct intel_hdcp hdcp;
+ struct drm_hdcp_helper_data *hdcp_helper_data;
};
struct intel_digital_connector_state {
@@ -48,17 +48,24 @@ static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout)
DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n");
}
-static
-int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
- u8 *an)
+static int intel_dp_hdcp_send_an_aksv(struct drm_connector *drm_connector,
+ void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+ struct drm_hdcp_an an;
u8 aksv[DRM_HDCP_KSV_LEN] = {};
ssize_t dpcd_ret;
+ int ret;
+
+ ret = intel_hdcp1_read_an(drm_connector, &an);
+ if (ret)
+ return ret;
- /* Output An first, that's easy */
dpcd_ret = drm_dp_dpcd_write(&dig_port->dp.aux, DP_AUX_HDCP_AN,
- an, DRM_HDCP_AN_LEN);
+ an.bytes, DRM_HDCP_AN_LEN);
if (dpcd_ret != DRM_HDCP_AN_LEN) {
drm_dbg_kms(&i915->drm,
"Failed to write An over DP/AUX (%zd)\n",
@@ -84,158 +91,6 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
return 0;
}
-static int intel_dp_hdcp_read_bksv(struct intel_digital_port *dig_port,
- u8 *bksv)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
-
- ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BKSV, bksv,
- DRM_HDCP_KSV_LEN);
- if (ret != DRM_HDCP_KSV_LEN) {
- drm_dbg_kms(&i915->drm,
- "Read Bksv from DP/AUX failed (%zd)\n", ret);
- return ret >= 0 ? -EIO : ret;
- }
- return 0;
-}
-
-static int intel_dp_hdcp_read_bstatus(struct intel_digital_port *dig_port,
- u8 *bstatus)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
-
- /*
- * For some reason the HDMI and DP HDCP specs call this register
- * definition by different names. In the HDMI spec, it's called BSTATUS,
- * but in DP it's called BINFO.
- */
- ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BINFO,
- bstatus, DRM_HDCP_BSTATUS_LEN);
- if (ret != DRM_HDCP_BSTATUS_LEN) {
- drm_dbg_kms(&i915->drm,
- "Read bstatus from DP/AUX failed (%zd)\n", ret);
- return ret >= 0 ? -EIO : ret;
- }
- return 0;
-}
-
-static
-int intel_dp_hdcp_read_bcaps(struct intel_digital_port *dig_port,
- u8 *bcaps)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
-
- ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BCAPS,
- bcaps, 1);
- if (ret != 1) {
- drm_dbg_kms(&i915->drm,
- "Read bcaps from DP/AUX failed (%zd)\n", ret);
- return ret >= 0 ? -EIO : ret;
- }
-
- return 0;
-}
-
-static
-int intel_dp_hdcp_repeater_present(struct intel_digital_port *dig_port,
- bool *repeater_present)
-{
- ssize_t ret;
- u8 bcaps;
-
- ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
- if (ret)
- return ret;
-
- *repeater_present = bcaps & DP_BCAPS_REPEATER_PRESENT;
- return 0;
-}
-
-static
-int intel_dp_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
- u8 *ri_prime)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
-
- ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_RI_PRIME,
- ri_prime, DRM_HDCP_RI_LEN);
- if (ret != DRM_HDCP_RI_LEN) {
- drm_dbg_kms(&i915->drm, "Read Ri' from DP/AUX failed (%zd)\n",
- ret);
- return ret >= 0 ? -EIO : ret;
- }
- return 0;
-}
-
-static
-int intel_dp_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
- bool *ksv_ready)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
- u8 bstatus;
-
- ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
- &bstatus, 1);
- if (ret != 1) {
- drm_dbg_kms(&i915->drm,
- "Read bstatus from DP/AUX failed (%zd)\n", ret);
- return ret >= 0 ? -EIO : ret;
- }
- *ksv_ready = bstatus & DP_BSTATUS_READY;
- return 0;
-}
-
-static
-int intel_dp_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
- int num_downstream, u8 *ksv_fifo)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
- int i;
-
- /* KSV list is read via 15 byte window (3 entries @ 5 bytes each) */
- for (i = 0; i < num_downstream; i += 3) {
- size_t len = min(num_downstream - i, 3) * DRM_HDCP_KSV_LEN;
- ret = drm_dp_dpcd_read(&dig_port->dp.aux,
- DP_AUX_HDCP_KSV_FIFO,
- ksv_fifo + i * DRM_HDCP_KSV_LEN,
- len);
- if (ret != len) {
- drm_dbg_kms(&i915->drm,
- "Read ksv[%d] from DP/AUX failed (%zd)\n",
- i, ret);
- return ret >= 0 ? -EIO : ret;
- }
- }
- return 0;
-}
-
-static
-int intel_dp_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
- int i, u32 *part)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
-
- if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
- return -EINVAL;
-
- ret = drm_dp_dpcd_read(&dig_port->dp.aux,
- DP_AUX_HDCP_V_PRIME(i), part,
- DRM_HDCP_V_PRIME_PART_LEN);
- if (ret != DRM_HDCP_V_PRIME_PART_LEN) {
- drm_dbg_kms(&i915->drm,
- "Read v'[%d] from DP/AUX failed (%zd)\n", i, ret);
- return ret >= 0 ? -EIO : ret;
- }
- return 0;
-}
-
static
int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
enum transcoder cpu_transcoder,
@@ -245,40 +100,6 @@ int intel_dp_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
return 0;
}
-static
-bool intel_dp_hdcp_check_link(struct intel_digital_port *dig_port,
- struct intel_connector *connector)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- ssize_t ret;
- u8 bstatus;
-
- ret = drm_dp_dpcd_read(&dig_port->dp.aux, DP_AUX_HDCP_BSTATUS,
- &bstatus, 1);
- if (ret != 1) {
- drm_dbg_kms(&i915->drm,
- "Read bstatus from DP/AUX failed (%zd)\n", ret);
- return false;
- }
-
- return !(bstatus & (DP_BSTATUS_LINK_FAILURE | DP_BSTATUS_REAUTH_REQ));
-}
-
-static
-int intel_dp_hdcp_capable(struct intel_digital_port *dig_port,
- bool *hdcp_capable)
-{
- ssize_t ret;
- u8 bcaps;
-
- ret = intel_dp_hdcp_read_bcaps(dig_port, &bcaps);
- if (ret)
- return ret;
-
- *hdcp_capable = bcaps & DP_BCAPS_HDCP_CAPABLE;
- return 0;
-}
-
struct hdcp2_dp_errata_stream_type {
u8 msg_id;
u8 stream_type;
@@ -621,13 +442,19 @@ int intel_dp_hdcp2_check_link(struct intel_digital_port *dig_port,
return ret;
}
-static
-int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
- bool *capable)
+static int intel_dp_hdcp2_capable(struct drm_connector *drm_connector,
+ bool *capable, void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
u8 rx_caps[3];
int ret;
+ ret = intel_hdcp2_capable(drm_connector, capable);
+ if (ret || !capable)
+ return ret;
+
*capable = false;
ret = drm_dp_dpcd_read(&dig_port->dp.aux,
DP_HDCP_2_2_REG_RX_CAPS_OFFSET,
@@ -643,22 +470,11 @@ int intel_dp_hdcp2_capable(struct intel_digital_port *dig_port,
}
static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
- .write_an_aksv = intel_dp_hdcp_write_an_aksv,
- .read_bksv = intel_dp_hdcp_read_bksv,
- .read_bstatus = intel_dp_hdcp_read_bstatus,
- .repeater_present = intel_dp_hdcp_repeater_present,
- .read_ri_prime = intel_dp_hdcp_read_ri_prime,
- .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
- .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
- .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
- .check_link = intel_dp_hdcp_check_link,
- .hdcp_capable = intel_dp_hdcp_capable,
.write_2_2_msg = intel_dp_hdcp2_write_msg,
.read_2_2_msg = intel_dp_hdcp2_read_msg,
.config_stream_type = intel_dp_hdcp2_config_stream_type,
.check_2_2_link = intel_dp_hdcp2_check_link,
- .hdcp_2_2_capable = intel_dp_hdcp2_capable,
.protocol = HDCP_PROTOCOL_DP,
};
@@ -714,6 +530,48 @@ intel_dp_mst_hdcp_stream_encryption(struct intel_connector *connector,
return 0;
}
+static int
+intel_dp_mst_hdcp1_post_encryption(struct drm_connector *drm_connector,
+ void *driver_data)
+{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ int ret;
+
+ ret = intel_hdcp1_post_encryption(drm_connector, driver_data);
+ if (ret)
+ return ret;
+
+ return intel_dp_mst_hdcp_stream_encryption(connector, true);
+}
+
+static int intel_dp_mst_hdcp1_disable(struct drm_connector *drm_connector,
+ void *driver_data)
+{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ int ret;
+
+ ret = intel_dp_mst_hdcp_stream_encryption(connector, true);
+ if (ret) {
+ drm_err(&i915->drm,
+ "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
+ connector->base.name, connector->base.base.id);
+ return ret;
+ }
+
+ /*
+ * If there are other connectors on this port using HDCP,
+ * don't disable it until it disabled HDCP encryption for
+ * all connectors in MST topology.
+ */
+ if (dig_port->num_hdcp_streams > 0)
+ return 0;
+
+ return intel_hdcp1_disable(drm_connector, driver_data);
+}
+
static int
intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector,
bool enable)
@@ -772,45 +630,101 @@ int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *dig_port,
}
static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = {
- .write_an_aksv = intel_dp_hdcp_write_an_aksv,
- .read_bksv = intel_dp_hdcp_read_bksv,
- .read_bstatus = intel_dp_hdcp_read_bstatus,
- .repeater_present = intel_dp_hdcp_repeater_present,
- .read_ri_prime = intel_dp_hdcp_read_ri_prime,
- .read_ksv_ready = intel_dp_hdcp_read_ksv_ready,
- .read_ksv_fifo = intel_dp_hdcp_read_ksv_fifo,
- .read_v_prime_part = intel_dp_hdcp_read_v_prime_part,
.toggle_signalling = intel_dp_hdcp_toggle_signalling,
- .stream_encryption = intel_dp_mst_hdcp_stream_encryption,
- .check_link = intel_dp_hdcp_check_link,
- .hdcp_capable = intel_dp_hdcp_capable,
.write_2_2_msg = intel_dp_hdcp2_write_msg,
.read_2_2_msg = intel_dp_hdcp2_read_msg,
.config_stream_type = intel_dp_hdcp2_config_stream_type,
.stream_2_2_encryption = intel_dp_mst_hdcp2_stream_encryption,
.check_2_2_link = intel_dp_mst_hdcp2_check_link,
- .hdcp_2_2_capable = intel_dp_hdcp2_capable,
.protocol = HDCP_PROTOCOL_DP,
};
+static const struct drm_hdcp_helper_funcs intel_dp_hdcp_helper_funcs = {
+ .setup = intel_hdcp_setup,
+ .load_keys = intel_hdcp_load_keys,
+ .hdcp2_capable = intel_dp_hdcp2_capable,
+ .hdcp2_enable = intel_hdcp2_enable,
+ .hdcp2_check_link = intel_hdcp2_check_link,
+ .hdcp2_disable = intel_hdcp2_disable,
+ .hdcp1_send_an_aksv = intel_dp_hdcp_send_an_aksv,
+ .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
+ .hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
+ .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
+ .hdcp1_match_ri = intel_hdcp1_match_ri,
+ .hdcp1_post_encryption = intel_hdcp1_post_encryption,
+ .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
+ .hdcp1_disable = intel_hdcp1_disable,
+ /* Common DRM functions that are different between DP vs HDMI*/
+ .remote_read = drm_hdcp_remote_dpcd_read,
+ .remote_write = drm_hdcp_remote_dpcd_write,
+ .hdcp1_capable = drm_hdcp_helper_hdcp1_capable_dp,
+ .hdcp1_ksv_fifo_ready = drm_hdcp_helper_hdcp1_ksv_fifo_ready_dp,
+ .wait_r0 = drm_hdcp_helper_wait_r0_dp,
+ .hdcp1_check_link_registers = drm_hdcp_hdcp1_check_link_registers_dp,
+ .hdcp1_read_ksv_fifo = drm_hdcp_helper_hdcp1_read_ksv_fifo_dp
+};
+
+static const struct drm_hdcp_helper_funcs intel_dp_mst_hdcp_helper_funcs = {
+ .setup = intel_hdcp_setup,
+ .load_keys = intel_hdcp_load_keys,
+ .hdcp2_capable = intel_dp_hdcp2_capable,
+ .hdcp2_enable = intel_hdcp2_enable,
+ .hdcp2_check_link = intel_hdcp2_check_link,
+ .hdcp2_disable = intel_hdcp2_disable,
+ .hdcp1_send_an_aksv = intel_dp_hdcp_send_an_aksv,
+ .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
+ .hdcp1_enable_encryption = intel_hdcp1_enable_encryption,
+ .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
+ .hdcp1_match_ri = intel_hdcp1_match_ri,
+ .hdcp1_post_encryption = intel_dp_mst_hdcp1_post_encryption,
+ .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
+ .hdcp1_disable = intel_dp_mst_hdcp1_disable,
+ /* Common DRM functions that are different between DP vs HDMI*/
+ .remote_read = drm_hdcp_remote_dpcd_read,
+ .remote_write = drm_hdcp_remote_dpcd_write,
+ .hdcp1_capable = drm_hdcp_helper_hdcp1_capable_dp,
+ .hdcp1_ksv_fifo_ready = drm_hdcp_helper_hdcp1_ksv_fifo_ready_dp,
+ .wait_r0 = drm_hdcp_helper_wait_r0_dp,
+ .hdcp1_check_link_registers = drm_hdcp_hdcp1_check_link_registers_dp,
+ .hdcp1_read_ksv_fifo = drm_hdcp_helper_hdcp1_read_ksv_fifo_dp
+};
+
int intel_dp_hdcp_init(struct intel_digital_port *dig_port,
- struct intel_connector *intel_connector)
+ struct intel_connector *connector)
{
- struct drm_device *dev = intel_connector->base.dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_encoder *intel_encoder = &dig_port->base;
enum port port = intel_encoder->port;
struct intel_dp *intel_dp = &dig_port->dp;
+ struct drm_hdcp_helper_data *data;
+ const struct drm_hdcp_helper_funcs *helper_funcs;
+ const struct intel_hdcp_shim *intel_shim;
+ int ret;
- if (!is_hdcp_supported(dev_priv, port))
+ if (!is_hdcp_supported(dev_priv, port) || intel_dp_is_edp(intel_dp))
return 0;
- if (intel_connector->mst_port)
- return intel_hdcp_init(intel_connector, dig_port,
- &intel_dp_mst_hdcp_shim);
- else if (!intel_dp_is_edp(intel_dp))
- return intel_hdcp_init(intel_connector, dig_port,
- &intel_dp_hdcp_shim);
+ if (connector->mst_port) {
+ helper_funcs = &intel_dp_mst_hdcp_helper_funcs;
+ intel_shim = &intel_dp_mst_hdcp_shim;
+ } else {
+ helper_funcs = &intel_dp_hdcp_helper_funcs;
+ intel_shim = &intel_dp_hdcp_shim;
+ }
+
+ data = drm_hdcp_helper_initialize_dp(&connector->base, &dig_port->dp.aux,
+ helper_funcs, true);
+ if (IS_ERR(data)) {
+ drm_dbg_kms(&dev_priv->drm, "HDCP init failed, skipping.\n");
+ return PTR_ERR(data);
+ }
+
+ ret = intel_hdcp_init(connector, dig_port, intel_shim);
+ if (ret) {
+ drm_hdcp_helper_destroy(data);
+ return ret;
+ }
+ connector->hdcp_helper_data = data;
return 0;
}
@@ -23,6 +23,7 @@
*
*/
+#include <drm/display/drm_hdcp_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
@@ -41,7 +42,6 @@
#include "intel_dp_hdcp.h"
#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
-#include "intel_hdcp.h"
#include "intel_hotplug.h"
#include "skl_scaler.h"
@@ -372,7 +372,10 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,
drm_dbg_kms(&i915->drm, "active links %d\n",
intel_dp->active_mst_links);
- intel_hdcp_disable(intel_mst->connector);
+ if (connector->hdcp_helper_data)
+ drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+ &state->base,
+ &dig_port->hdcp_mutex);
drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state,
drm_atomic_get_mst_payload_state(mst_state, connector->port));
@@ -580,11 +583,10 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
intel_audio_codec_enable(encoder, pipe_config, conn_state);
/* Enable hdcp if it's desired */
- if (conn_state->content_protection ==
- DRM_MODE_CONTENT_PROTECTION_DESIRED)
- intel_hdcp_enable(to_intel_connector(conn_state->connector),
- pipe_config,
- (u8)conn_state->hdcp_content_type);
+ if (connector->hdcp_helper_data)
+ drm_hdcp_helper_atomic_commit(connector->hdcp_helper_data,
+ &state->base,
+ &dig_port->hdcp_mutex);
}
static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
@@ -140,67 +140,10 @@ static int intel_hdcp_prepare_streams(struct intel_connector *connector)
return 0;
}
-static
-bool intel_hdcp_is_ksv_valid(u8 *ksv)
-{
- int i, ones = 0;
- /* KSV has 20 1's and 20 0's */
- for (i = 0; i < DRM_HDCP_KSV_LEN; i++)
- ones += hweight8(ksv[i]);
- if (ones != 20)
- return false;
-
- return true;
-}
-
-static
-int intel_hdcp_read_valid_bksv(struct intel_digital_port *dig_port,
- const struct intel_hdcp_shim *shim, u8 *bksv)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- int ret, i, tries = 2;
-
- /* HDCP spec states that we must retry the bksv if it is invalid */
- for (i = 0; i < tries; i++) {
- ret = shim->read_bksv(dig_port, bksv);
- if (ret)
- return ret;
- if (intel_hdcp_is_ksv_valid(bksv))
- break;
- }
- if (i == tries) {
- drm_dbg_kms(&i915->drm, "Bksv is invalid\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-/* Is HDCP1.4 capable on Platform and Sink */
-int intel_hdcp_capable(struct intel_connector *connector, bool *capable)
-{
- struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
- const struct intel_hdcp_shim *shim = connector->hdcp.shim;
- u8 bksv[5];
-
- *capable = false;
-
- if (!shim)
- return 0;
-
- if (shim->hdcp_capable)
- return shim->hdcp_capable(dig_port, capable);
-
- if (!intel_hdcp_read_valid_bksv(dig_port, shim, bksv))
- *capable = true;
-
- return 0;
-}
-
/* Is HDCP2.2 capable on Platform and Sink */
-int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
+int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable)
{
- struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
+ struct intel_connector *connector = to_intel_connector(drm_connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
@@ -218,16 +161,26 @@ int intel_hdcp2_capable(struct intel_connector *connector, bool *capable)
}
mutex_unlock(&dev_priv->display.hdcp.comp_mutex);
- /* Sink's capability for HDCP2.2 */
- return hdcp->shim->hdcp_2_2_capable(dig_port, capable);
+ return 0;
}
-static bool intel_hdcp_in_use(struct drm_i915_private *dev_priv,
- enum transcoder cpu_transcoder, enum port port)
+int intel_hdcp1_check_link(struct drm_connector *drm_connector)
{
- return intel_de_read(dev_priv,
- HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
- HDCP_STATUS_ENC;
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+ enum port port = dig_port->base.port;
+ u32 val;
+
+ val = intel_de_read(dev_priv,
+ HDCP_STATUS(dev_priv, cpu_transcoder, port));
+
+ if (val & HDCP_STATUS_ENC)
+ return 0;
+
+ return -EINVAL;
}
static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
@@ -238,27 +191,6 @@ static bool intel_hdcp2_in_use(struct drm_i915_private *dev_priv,
LINK_ENCRYPTION_STATUS;
}
-static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *dig_port,
- const struct intel_hdcp_shim *shim)
-{
- int ret, read_ret;
- bool ksv_ready;
-
- /* Poll for ksv list ready (spec says max time allowed is 5s) */
- ret = __wait_for(read_ret = shim->read_ksv_ready(dig_port,
- &ksv_ready),
- read_ret || ksv_ready, 5 * 1000 * 1000, 1000,
- 100 * 1000);
- if (ret)
- return ret;
- if (read_ret)
- return read_ret;
- if (!ksv_ready)
- return -ETIMEDOUT;
-
- return 0;
-}
-
static bool hdcp_key_loadable(struct drm_i915_private *dev_priv)
{
enum i915_power_well_id id;
@@ -294,11 +226,18 @@ static void intel_hdcp_clear_keys(struct drm_i915_private *dev_priv)
HDCP_KEY_LOAD_DONE | HDCP_KEY_LOAD_STATUS | HDCP_FUSE_IN_PROGRESS | HDCP_FUSE_ERROR | HDCP_FUSE_DONE);
}
-static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
+int intel_hdcp_load_keys(struct drm_connector *drm_connector, void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
int ret;
u32 val;
+ if (!hdcp_key_loadable(dev_priv)) {
+ drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
+ return -ENXIO;
+ }
+
val = intel_de_read(dev_priv, HDCP_KEY_STATUS);
if ((val & HDCP_KEY_LOAD_DONE) && (val & HDCP_KEY_LOAD_STATUS))
return 0;
@@ -308,8 +247,11 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
* out of reset. So if Key is not already loaded, its an error state.
*/
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
- if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) & HDCP_KEY_LOAD_DONE))
- return -ENXIO;
+ if (!(intel_de_read(dev_priv, HDCP_KEY_STATUS) &
+ HDCP_KEY_LOAD_DONE)) {
+ ret = -ENXIO;
+ goto err;
+ }
/*
* Initiate loading the HDCP key from fuses.
@@ -325,7 +267,7 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
drm_err(&dev_priv->drm,
"Failed to initiate HDCP key load (%d)\n",
ret);
- return ret;
+ goto err;
}
} else {
intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_KEY_LOAD_TRIGGER);
@@ -335,15 +277,21 @@ static int intel_hdcp_load_keys(struct drm_i915_private *dev_priv)
ret = __intel_wait_for_register(&dev_priv->uncore, HDCP_KEY_STATUS,
HDCP_KEY_LOAD_DONE, HDCP_KEY_LOAD_DONE,
10, 1, &val);
- if (ret)
- return ret;
- else if (!(val & HDCP_KEY_LOAD_STATUS))
- return -ENXIO;
+ if (ret) {
+ goto err;
+ } else if (!(val & HDCP_KEY_LOAD_STATUS)) {
+ ret = -ENXIO;
+ goto err;
+ }
/* Send Aksv over to PCH display for use in authentication */
intel_de_write(dev_priv, HDCP_KEY_CONF, HDCP_AKSV_SEND_TRIGGER);
return 0;
+
+err:
+ intel_hdcp_clear_keys(dev_priv);
+ return ret;
}
/* Returns updated SHA-1 index */
@@ -399,25 +347,21 @@ u32 intel_hdcp_get_repeater_ctl(struct drm_i915_private *dev_priv,
}
}
-static
-int intel_hdcp_validate_v_prime(struct intel_connector *connector,
- const struct intel_hdcp_shim *shim,
- u8 *ksv_fifo, u8 num_downstream, u8 *bstatus)
+int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
+ u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
+ u32 *v_prime, void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
enum port port = dig_port->base.port;
- u32 vprime, sha_text, sha_leftovers, rep_ctl;
+ u32 sha_text, sha_leftovers, rep_ctl;
int ret, i, j, sha_idx;
/* Process V' values from the receiver */
- for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) {
- ret = shim->read_v_prime_part(dig_port, i, &vprime);
- if (ret)
- return ret;
- intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), vprime);
- }
+ for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++)
+ intel_de_write(dev_priv, HDCP_SHA_V_PRIME(i), v_prime[i]);
/*
* We need to write the concatenation of all device KSVs, BINFO (DP) ||
@@ -642,131 +586,38 @@ int intel_hdcp_validate_v_prime(struct intel_connector *connector,
return 0;
}
-/* Implements Part 2 of the HDCP authorization procedure */
-static
-int intel_hdcp_auth_downstream(struct intel_connector *connector)
+int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
+ u32 *ksv, u32 status, u8 caps,
+ bool repeater_present, void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- const struct intel_hdcp_shim *shim = connector->hdcp.shim;
- u8 bstatus[2], num_downstream, *ksv_fifo;
- int ret, i, tries = 3;
-
- ret = intel_hdcp_poll_ksv_fifo(dig_port, shim);
- if (ret) {
- drm_dbg_kms(&dev_priv->drm,
- "KSV list failed to become ready (%d)\n", ret);
- return ret;
- }
-
- ret = shim->read_bstatus(dig_port, bstatus);
- if (ret)
- return ret;
-
- if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
- DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
- drm_dbg_kms(&dev_priv->drm, "Max Topology Limit Exceeded\n");
- return -EPERM;
- }
-
- /*
- * When repeater reports 0 device count, HDCP1.4 spec allows disabling
- * the HDCP encryption. That implies that repeater can't have its own
- * display. As there is no consumption of encrypted content in the
- * repeater with 0 downstream devices, we are failing the
- * authentication.
- */
- num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
- if (num_downstream == 0) {
- drm_dbg_kms(&dev_priv->drm,
- "Repeater with zero downstream devices\n");
- return -EINVAL;
- }
-
- ksv_fifo = kcalloc(DRM_HDCP_KSV_LEN, num_downstream, GFP_KERNEL);
- if (!ksv_fifo) {
- drm_dbg_kms(&dev_priv->drm, "Out of mem: ksv_fifo\n");
- return -ENOMEM;
- }
-
- ret = shim->read_ksv_fifo(dig_port, num_downstream, ksv_fifo);
- if (ret)
- goto err;
-
- if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, ksv_fifo,
- num_downstream) > 0) {
- drm_err(&dev_priv->drm, "Revoked Ksv(s) in ksv_fifo\n");
- ret = -EPERM;
- goto err;
- }
+ enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+ enum port port = dig_port->base.port;
- /*
- * When V prime mismatches, DP Spec mandates re-read of
- * V prime atleast twice.
- */
- for (i = 0; i < tries; i++) {
- ret = intel_hdcp_validate_v_prime(connector, shim,
- ksv_fifo, num_downstream,
- bstatus);
- if (!ret)
- break;
- }
+ intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
+ ksv[0]);
+ intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
+ ksv[1]);
- if (i == tries) {
- drm_dbg_kms(&dev_priv->drm,
- "V Prime validation failed.(%d)\n", ret);
- goto err;
- }
+ if (repeater_present)
+ intel_de_write(dev_priv, HDCP_REP_CTL,
+ intel_hdcp_get_repeater_ctl(
+ dev_priv, cpu_transcoder, port));
- drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (%d downstream devices)\n",
- num_downstream);
- ret = 0;
-err:
- kfree(ksv_fifo);
- return ret;
+ return 0;
}
-/* Implements Part 1 of the HDCP authorization procedure */
-static int intel_hdcp_auth(struct intel_connector *connector)
+int intel_hdcp1_read_an(struct drm_connector *drm_connector,
+ struct drm_hdcp_an *an)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct intel_hdcp *hdcp = &connector->hdcp;
- const struct intel_hdcp_shim *shim = hdcp->shim;
enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
enum port port = dig_port->base.port;
- unsigned long r0_prime_gen_start;
- int ret, i, tries = 2;
- union {
- u32 reg[2];
- u8 shim[DRM_HDCP_AN_LEN];
- } an;
- union {
- u32 reg[2];
- u8 shim[DRM_HDCP_KSV_LEN];
- } bksv;
- union {
- u32 reg;
- u8 shim[DRM_HDCP_RI_LEN];
- } ri;
- bool repeater_present, hdcp_capable;
-
- /*
- * Detects whether the display is HDCP capable. Although we check for
- * valid Bksv below, the HDCP over DP spec requires that we check
- * whether the display supports HDCP before we write An. For HDMI
- * displays, this is not necessary.
- */
- if (shim->hdcp_capable) {
- ret = shim->hdcp_capable(dig_port, &hdcp_capable);
- if (ret)
- return ret;
- if (!hdcp_capable) {
- drm_dbg_kms(&dev_priv->drm,
- "Panel is not HDCP capable\n");
- return -EINVAL;
- }
- }
+ int i;
/* Initialize An with 2 random values and acquire it */
for (i = 0; i < 2; i++)
@@ -784,92 +635,83 @@ static int intel_hdcp_auth(struct intel_connector *connector)
return -ETIMEDOUT;
}
- an.reg[0] = intel_de_read(dev_priv,
- HDCP_ANLO(dev_priv, cpu_transcoder, port));
- an.reg[1] = intel_de_read(dev_priv,
- HDCP_ANHI(dev_priv, cpu_transcoder, port));
- ret = shim->write_an_aksv(dig_port, an.shim);
- if (ret)
- return ret;
+ an->words[0] = intel_de_read(dev_priv,
+ HDCP_ANLO(dev_priv, cpu_transcoder, port));
+ an->words[1] = intel_de_read(dev_priv,
+ HDCP_ANHI(dev_priv, cpu_transcoder, port));
- r0_prime_gen_start = jiffies;
-
- memset(&bksv, 0, sizeof(bksv));
-
- ret = intel_hdcp_read_valid_bksv(dig_port, shim, bksv.shim);
- if (ret < 0)
- return ret;
-
- if (drm_hdcp_check_ksvs_revoked(&dev_priv->drm, bksv.shim, 1) > 0) {
- drm_err(&dev_priv->drm, "BKSV is revoked\n");
- return -EPERM;
- }
-
- intel_de_write(dev_priv, HDCP_BKSVLO(dev_priv, cpu_transcoder, port),
- bksv.reg[0]);
- intel_de_write(dev_priv, HDCP_BKSVHI(dev_priv, cpu_transcoder, port),
- bksv.reg[1]);
-
- ret = shim->repeater_present(dig_port, &repeater_present);
- if (ret)
- return ret;
- if (repeater_present)
- intel_de_write(dev_priv, HDCP_REP_CTL,
- intel_hdcp_get_repeater_ctl(dev_priv, cpu_transcoder, port));
+ return 0;
+}
- ret = shim->toggle_signalling(dig_port, cpu_transcoder, true);
- if (ret)
- return ret;
+int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector,
+ void *driver_data)
+{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+ enum port port = dig_port->base.port;
intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port),
HDCP_CONF_AUTH_AND_ENC);
+ return 0;
+}
+
+int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector,
+ void *driver_data)
+{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+ enum port port = dig_port->base.port;
+
/* Wait for R0 ready */
- if (wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
- (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
+ if (wait_for((intel_de_read(dev_priv,
+ HDCP_STATUS(dev_priv, cpu_transcoder, port))) &
+ (HDCP_STATUS_R0_READY | HDCP_STATUS_ENC), 1)) {
drm_err(&dev_priv->drm, "Timed out waiting for R0 ready\n");
return -ETIMEDOUT;
}
- /*
- * Wait for R0' to become available. The spec says 100ms from Aksv, but
- * some monitors can take longer than this. We'll set the timeout at
- * 300ms just to be sure.
- *
- * On DP, there's an R0_READY bit available but no such bit
- * exists on HDMI. Since the upper-bound is the same, we'll just do
- * the stupid thing instead of polling on one and not the other.
- */
- wait_remaining_ms_from_jiffies(r0_prime_gen_start, 300);
-
- tries = 3;
+ return 0;
+}
- /*
- * DP HDCP Spec mandates the two more reattempt to read R0, incase
- * of R0 mismatch.
- */
- for (i = 0; i < tries; i++) {
- ri.reg = 0;
- ret = shim->read_ri_prime(dig_port, ri.shim);
- if (ret)
- return ret;
- intel_de_write(dev_priv,
- HDCP_RPRIME(dev_priv, cpu_transcoder, port),
- ri.reg);
+int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime,
+ void *driver_data)
+{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+ enum port port = dig_port->base.port;
- /* Wait for Ri prime match */
- if (!wait_for(intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
- (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1))
- break;
- }
+ intel_de_write(dev_priv, HDCP_RPRIME(dev_priv, cpu_transcoder, port),
+ ri_prime);
- if (i == tries) {
- drm_dbg_kms(&dev_priv->drm,
- "Timed out waiting for Ri prime match (%x)\n",
- intel_de_read(dev_priv, HDCP_STATUS(dev_priv,
- cpu_transcoder, port)));
+ /* Wait for Ri prime match */
+ if (wait_for(intel_de_read(dev_priv,
+ HDCP_STATUS(dev_priv, cpu_transcoder, port)) &
+ (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC),
+ 1))
return -ETIMEDOUT;
- }
+
+ return 0;
+}
+
+int intel_hdcp1_post_encryption(struct drm_connector *drm_connector,
+ void *driver_data)
+{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+ enum port port = dig_port->base.port;
/* Wait for encryption confirmation */
if (intel_de_wait_for_set(dev_priv,
@@ -880,56 +722,22 @@ static int intel_hdcp_auth(struct intel_connector *connector)
return -ETIMEDOUT;
}
- /* DP MST Auth Part 1 Step 2.a and Step 2.b */
- if (shim->stream_encryption) {
- ret = shim->stream_encryption(connector, true);
- if (ret) {
- drm_err(&dev_priv->drm, "[%s:%d] Failed to enable HDCP 1.4 stream enc\n",
- connector->base.name, connector->base.base.id);
- return ret;
- }
- drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encrypted\n",
- transcoder_name(hdcp->stream_transcoder));
- }
-
- if (repeater_present)
- return intel_hdcp_auth_downstream(connector);
-
- drm_dbg_kms(&dev_priv->drm, "HDCP is enabled (no repeater present)\n");
return 0;
}
-static int _intel_hdcp_disable(struct intel_connector *connector)
+int intel_hdcp1_disable(struct drm_connector *drm_connector, void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
enum port port = dig_port->base.port;
enum transcoder cpu_transcoder = hdcp->cpu_transcoder;
u32 repeater_ctl;
- int ret;
drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being disabled...\n",
connector->base.name, connector->base.base.id);
- if (hdcp->shim->stream_encryption) {
- ret = hdcp->shim->stream_encryption(connector, false);
- if (ret) {
- drm_err(&dev_priv->drm, "[%s:%d] Failed to disable HDCP 1.4 stream enc\n",
- connector->base.name, connector->base.base.id);
- return ret;
- }
- drm_dbg_kms(&dev_priv->drm, "HDCP 1.4 transcoder: %s stream encryption disabled\n",
- transcoder_name(hdcp->stream_transcoder));
- /*
- * If there are other connectors on this port using HDCP,
- * don't disable it until it disabled HDCP encryption for
- * all connectors in MST topology.
- */
- if (dig_port->num_hdcp_streams > 0)
- return 0;
- }
-
hdcp->hdcp_encrypted = false;
intel_de_write(dev_priv, HDCP_CONF(dev_priv, cpu_transcoder, port), 0);
if (intel_de_wait_for_clear(dev_priv,
@@ -945,190 +753,9 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
intel_de_write(dev_priv, HDCP_REP_CTL,
intel_de_read(dev_priv, HDCP_REP_CTL) & ~repeater_ctl);
- ret = hdcp->shim->toggle_signalling(dig_port, cpu_transcoder, false);
- if (ret) {
- drm_err(&dev_priv->drm, "Failed to disable HDCP signalling\n");
- return ret;
- }
-
- drm_dbg_kms(&dev_priv->drm, "HDCP is disabled\n");
return 0;
}
-static int _intel_hdcp_enable(struct intel_connector *connector)
-{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct intel_hdcp *hdcp = &connector->hdcp;
- int i, ret, tries = 3;
-
- drm_dbg_kms(&dev_priv->drm, "[%s:%d] HDCP is being enabled...\n",
- connector->base.name, connector->base.base.id);
-
- if (!hdcp_key_loadable(dev_priv)) {
- drm_err(&dev_priv->drm, "HDCP key Load is not possible\n");
- return -ENXIO;
- }
-
- for (i = 0; i < KEY_LOAD_TRIES; i++) {
- ret = intel_hdcp_load_keys(dev_priv);
- if (!ret)
- break;
- intel_hdcp_clear_keys(dev_priv);
- }
- if (ret) {
- drm_err(&dev_priv->drm, "Could not load HDCP keys, (%d)\n",
- ret);
- return ret;
- }
-
- /* Incase of authentication failures, HDCP spec expects reauth. */
- for (i = 0; i < tries; i++) {
- ret = intel_hdcp_auth(connector);
- if (!ret) {
- hdcp->hdcp_encrypted = true;
- return 0;
- }
-
- drm_dbg_kms(&dev_priv->drm, "HDCP Auth failure (%d)\n", ret);
-
- /* Ensuring HDCP encryption and signalling are stopped. */
- _intel_hdcp_disable(connector);
- }
-
- drm_dbg_kms(&dev_priv->drm,
- "HDCP authentication failed (%d tries/%d)\n", tries, ret);
- return ret;
-}
-
-static struct intel_connector *intel_hdcp_to_connector(struct intel_hdcp *hdcp)
-{
- return container_of(hdcp, struct intel_connector, hdcp);
-}
-
-static void intel_hdcp_update_value(struct intel_connector *connector,
- u64 value, bool update_property)
-{
- struct drm_device *dev = connector->base.dev;
- struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
-
- drm_WARN_ON(connector->base.dev, !mutex_is_locked(&hdcp->mutex));
-
- if (hdcp->value == value)
- return;
-
- drm_WARN_ON(dev, !mutex_is_locked(&dig_port->hdcp_mutex));
-
- if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
- if (!drm_WARN_ON(dev, dig_port->num_hdcp_streams == 0))
- dig_port->num_hdcp_streams--;
- } else if (value == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
- dig_port->num_hdcp_streams++;
- }
-
- hdcp->value = value;
- if (update_property) {
- drm_connector_get(&connector->base);
- schedule_work(&hdcp->prop_work);
- }
-}
-
-/* Implements Part 3 of the HDCP authorization procedure */
-static int intel_hdcp_check_link(struct intel_connector *connector)
-{
- struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct intel_hdcp *hdcp = &connector->hdcp;
- enum port port = dig_port->base.port;
- enum transcoder cpu_transcoder;
- int ret = 0;
-
- mutex_lock(&hdcp->mutex);
- mutex_lock(&dig_port->hdcp_mutex);
-
- cpu_transcoder = hdcp->cpu_transcoder;
-
- /* Check_link valid only when HDCP1.4 is enabled */
- if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
- !hdcp->hdcp_encrypted) {
- ret = -EINVAL;
- goto out;
- }
-
- if (drm_WARN_ON(&dev_priv->drm,
- !intel_hdcp_in_use(dev_priv, cpu_transcoder, port))) {
- drm_err(&dev_priv->drm,
- "%s:%d HDCP link stopped encryption,%x\n",
- connector->base.name, connector->base.base.id,
- intel_de_read(dev_priv, HDCP_STATUS(dev_priv, cpu_transcoder, port)));
- ret = -ENXIO;
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED,
- true);
- goto out;
- }
-
- if (hdcp->shim->check_link(dig_port, connector)) {
- if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_ENABLED, true);
- }
- goto out;
- }
-
- drm_dbg_kms(&dev_priv->drm,
- "[%s:%d] HDCP link failed, retrying authentication\n",
- connector->base.name, connector->base.base.id);
-
- ret = _intel_hdcp_disable(connector);
- if (ret) {
- drm_err(&dev_priv->drm, "Failed to disable hdcp (%d)\n", ret);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED,
- true);
- goto out;
- }
-
- ret = _intel_hdcp_enable(connector);
- if (ret) {
- drm_err(&dev_priv->drm, "Failed to enable hdcp (%d)\n", ret);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED,
- true);
- goto out;
- }
-
-out:
- mutex_unlock(&dig_port->hdcp_mutex);
- mutex_unlock(&hdcp->mutex);
- return ret;
-}
-
-static void intel_hdcp_prop_work(struct work_struct *work)
-{
- struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
- prop_work);
- struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
- drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, NULL);
- mutex_lock(&hdcp->mutex);
-
- /*
- * This worker is only used to flip between ENABLED/DESIRED. Either of
- * those to UNDESIRED is handled by core. If value == UNDESIRED,
- * we're running just after hdcp has been disabled, so just exit
- */
- if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
- drm_hdcp_update_content_protection(&connector->base,
- hdcp->value);
-
- mutex_unlock(&hdcp->mutex);
- drm_modeset_unlock(&dev_priv->drm.mode_config.connection_mutex);
-
- drm_connector_put(&connector->base);
-}
-
bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port)
{
return RUNTIME_INFO(dev_priv)->has_hdcp &&
@@ -1961,8 +1588,9 @@ static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
return ret;
}
-static int _intel_hdcp2_enable(struct intel_connector *connector)
+int intel_hdcp2_enable(struct drm_connector *drm_connector, void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
int ret;
@@ -1986,8 +1614,8 @@ static int _intel_hdcp2_enable(struct intel_connector *connector)
return 0;
}
-static int
-_intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery)
+static int _intel_hdcp2_disable(struct intel_connector *connector,
+ bool hdcp2_link_recovery, void *driver_data)
{
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *i915 = to_i915(connector->base.dev);
@@ -2024,9 +1652,17 @@ _intel_hdcp2_disable(struct intel_connector *connector, bool hdcp2_link_recovery
return ret;
}
+int intel_hdcp2_disable(struct drm_connector *drm_connector, void *driver_data)
+{
+ return _intel_hdcp2_disable(to_intel_connector(drm_connector), false,
+ driver_data);
+}
+
/* Implements the Link Integrity Check for HDCP2.2 */
-static int intel_hdcp2_check_link(struct intel_connector *connector)
+int intel_hdcp2_check_link(struct drm_connector *drm_connector,
+ void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
struct intel_hdcp *hdcp = &connector->hdcp;
@@ -2034,109 +1670,39 @@ static int intel_hdcp2_check_link(struct intel_connector *connector)
enum transcoder cpu_transcoder;
int ret = 0;
- mutex_lock(&hdcp->mutex);
- mutex_lock(&dig_port->hdcp_mutex);
cpu_transcoder = hdcp->cpu_transcoder;
/* hdcp2_check_link is expected only when HDCP2.2 is Enabled */
- if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED ||
- !hdcp->hdcp2_encrypted) {
- ret = -EINVAL;
- goto out;
- }
+ if (!hdcp->hdcp2_encrypted)
+ return -EINVAL;
if (drm_WARN_ON(&dev_priv->drm,
!intel_hdcp2_in_use(dev_priv, cpu_transcoder, port))) {
drm_err(&dev_priv->drm,
"HDCP2.2 link stopped the encryption, %x\n",
intel_de_read(dev_priv, HDCP2_STATUS(dev_priv, cpu_transcoder, port)));
- ret = -ENXIO;
- _intel_hdcp2_disable(connector, true);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED,
- true);
- goto out;
+ return -ENXIO;
}
ret = hdcp->shim->check_2_2_link(dig_port, connector);
- if (ret == HDCP_LINK_PROTECTED) {
- if (hdcp->value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_ENABLED,
- true);
- }
- goto out;
- }
+ if (ret == HDCP_LINK_PROTECTED)
+ return 0;
if (ret == HDCP_TOPOLOGY_CHANGE) {
- if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
- goto out;
-
drm_dbg_kms(&dev_priv->drm,
"HDCP2.2 Downstream topology change\n");
ret = hdcp2_authenticate_repeater_topology(connector);
- if (!ret) {
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_ENABLED,
- true);
- goto out;
- }
- drm_dbg_kms(&dev_priv->drm,
- "[%s:%d] Repeater topology auth failed.(%d)\n",
- connector->base.name, connector->base.base.id,
- ret);
- } else {
- drm_dbg_kms(&dev_priv->drm,
- "[%s:%d] HDCP2.2 link failed, retrying auth\n",
- connector->base.name, connector->base.base.id);
- }
-
- ret = _intel_hdcp2_disable(connector, true);
- if (ret) {
- drm_err(&dev_priv->drm,
- "[%s:%d] Failed to disable hdcp2.2 (%d)\n",
- connector->base.name, connector->base.base.id, ret);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED, true);
- goto out;
- }
+ if (!ret)
+ return 0;
- ret = _intel_hdcp2_enable(connector);
- if (ret) {
drm_dbg_kms(&dev_priv->drm,
- "[%s:%d] Failed to enable hdcp2.2 (%d)\n",
- connector->base.name, connector->base.base.id,
- ret);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_DESIRED,
- true);
- goto out;
+ "[%s:%d] Repeater topology auth failed.(%d)\n",
+ connector->base.name, connector->base.base.id, ret);
}
-out:
- mutex_unlock(&dig_port->hdcp_mutex);
- mutex_unlock(&hdcp->mutex);
return ret;
}
-static void intel_hdcp_check_work(struct work_struct *work)
-{
- struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
- struct intel_hdcp,
- check_work);
- struct intel_connector *connector = intel_hdcp_to_connector(hdcp);
-
- if (drm_connector_is_unregistered(&connector->base))
- return;
-
- if (!intel_hdcp2_check_link(connector))
- schedule_delayed_work(&hdcp->check_work,
- DRM_HDCP2_CHECK_PERIOD_MS);
- else if (!intel_hdcp_check_link(connector))
- schedule_delayed_work(&hdcp->check_work,
- DRM_HDCP_CHECK_PERIOD_MS);
-}
-
static int i915_hdcp_component_bind(struct device *i915_kdev,
struct device *mei_kdev, void *data)
{
@@ -2189,22 +1755,28 @@ static enum mei_fw_tc intel_get_mei_fw_tc(enum transcoder cpu_transcoder)
}
}
-static int
-_intel_hdcp_setup(struct intel_connector *connector,
- const struct intel_crtc_state *pipe_config, u8 content_type)
+int intel_hdcp_setup(struct drm_connector *connector,
+ struct drm_atomic_state *state, void *driver_data)
{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
+ struct drm_i915_private *dev_priv = to_i915(connector->dev);
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(intel_connector);
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct intel_crtc_state *pipe_config;
+ struct intel_hdcp *hdcp = &intel_connector->hdcp;
int ret = 0;
- if (!connector->encoder) {
+ if (!intel_connector->encoder) {
drm_err(&dev_priv->drm, "[%s:%d] encoder is not initialized\n",
- connector->base.name, connector->base.base.id);
+ connector->name, connector->base.id);
return -ENODEV;
}
- hdcp->content_type = content_type;
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ pipe_config = to_intel_crtc_state(crtc_state);
if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) {
hdcp->cpu_transcoder = pipe_config->mst_master_transcoder;
@@ -2321,7 +1893,6 @@ int intel_hdcp_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 (!shim)
return -EINVAL;
@@ -2329,174 +1900,12 @@ int intel_hdcp_init(struct intel_connector *connector,
if (is_hdcp2_supported(dev_priv))
intel_hdcp2_init(connector, dig_port, shim);
- ret =
- drm_connector_attach_content_protection_property(&connector->base,
- hdcp->hdcp2_supported);
- if (ret) {
- hdcp->hdcp2_supported = false;
- kfree(dig_port->hdcp_port_data.streams);
- return ret;
- }
-
hdcp->shim = shim;
- mutex_init(&hdcp->mutex);
- INIT_DELAYED_WORK(&hdcp->check_work, intel_hdcp_check_work);
- INIT_WORK(&hdcp->prop_work, intel_hdcp_prop_work);
init_waitqueue_head(&hdcp->cp_irq_queue);
return 0;
}
-int intel_hdcp_enable(struct intel_connector *connector,
- const struct intel_crtc_state *pipe_config, u8 content_type)
-{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
- bool capable;
- int ret = -EINVAL;
-
- if (!hdcp->shim)
- return -ENOENT;
-
- mutex_lock(&hdcp->mutex);
- mutex_lock(&dig_port->hdcp_mutex);
- drm_WARN_ON(&dev_priv->drm,
- hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
-
- ret = _intel_hdcp_setup(connector, pipe_config, content_type);
- 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.
- */
- ret = intel_hdcp2_capable(connector, &capable);
- if (capable) {
- ret = _intel_hdcp2_enable(connector);
- if (!ret) {
- check_link_interval = DRM_HDCP2_CHECK_PERIOD_MS;
- goto out;
- }
- }
-
- /*
- * When HDCP2.2 fails and Content Type is not Type1, HDCP1.4 will
- * be attempted.
- */
- ret = intel_hdcp_capable(connector, &capable);
- if (ret)
- goto out;
-
- if (capable && hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1)
- ret = _intel_hdcp_enable(connector);
-
-out:
- if (!ret) {
- schedule_delayed_work(&hdcp->check_work, check_link_interval);
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_ENABLED,
- true);
- }
-
- mutex_unlock(&dig_port->hdcp_mutex);
- mutex_unlock(&hdcp->mutex);
- return ret;
-}
-
-int intel_hdcp_disable(struct intel_connector *connector)
-{
- struct intel_digital_port *dig_port = intel_attached_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- int ret = 0;
-
- if (!hdcp->shim)
- return -ENOENT;
-
- mutex_lock(&hdcp->mutex);
- mutex_lock(&dig_port->hdcp_mutex);
-
- if (hdcp->value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
- goto out;
-
- intel_hdcp_update_value(connector,
- DRM_MODE_CONTENT_PROTECTION_UNDESIRED, false);
- if (hdcp->hdcp2_encrypted)
- ret = _intel_hdcp2_disable(connector, false);
- else if (hdcp->hdcp_encrypted)
- ret = _intel_hdcp_disable(connector);
-
-out:
- mutex_unlock(&dig_port->hdcp_mutex);
- mutex_unlock(&hdcp->mutex);
- cancel_delayed_work_sync(&hdcp->check_work);
- return ret;
-}
-
-void intel_hdcp_update_pipe(struct intel_atomic_state *state,
- struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state)
-{
- struct intel_connector *connector =
- to_intel_connector(conn_state->connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- bool content_protection_type_changed, desired_and_not_enabled = false;
-
- if (!connector->hdcp.shim)
- return;
-
- content_protection_type_changed =
- (conn_state->hdcp_content_type != hdcp->content_type &&
- conn_state->content_protection !=
- DRM_MODE_CONTENT_PROTECTION_UNDESIRED);
-
- /*
- * During the HDCP encryption session if Type change is requested,
- * disable the HDCP and reenable it with new TYPE value.
- */
- if (conn_state->content_protection ==
- DRM_MODE_CONTENT_PROTECTION_UNDESIRED ||
- content_protection_type_changed)
- intel_hdcp_disable(connector);
-
- /*
- * Mark the hdcp state as DESIRED after the hdcp disable of type
- * change procedure.
- */
- if (content_protection_type_changed) {
- mutex_lock(&hdcp->mutex);
- hdcp->value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
- drm_connector_get(&connector->base);
- schedule_work(&hdcp->prop_work);
- mutex_unlock(&hdcp->mutex);
- }
-
- if (conn_state->content_protection ==
- DRM_MODE_CONTENT_PROTECTION_DESIRED) {
- mutex_lock(&hdcp->mutex);
- /* Avoid enabling hdcp, if it already ENABLED */
- desired_and_not_enabled =
- hdcp->value != DRM_MODE_CONTENT_PROTECTION_ENABLED;
- mutex_unlock(&hdcp->mutex);
- /*
- * If HDCP already ENABLED and CP property is DESIRED, schedule
- * prop_work to update correct CP property to user space.
- */
- if (!desired_and_not_enabled && !content_protection_type_changed) {
- drm_connector_get(&connector->base);
- schedule_work(&hdcp->prop_work);
- }
- }
-
- if (desired_and_not_enabled || content_protection_type_changed)
- intel_hdcp_enable(connector,
- crtc_state,
- (u8)conn_state->hdcp_content_type);
-}
-
void intel_hdcp_component_fini(struct drm_i915_private *dev_priv)
{
mutex_lock(&dev_priv->display.hdcp.comp_mutex);
@@ -2518,33 +1927,8 @@ void intel_hdcp_cleanup(struct intel_connector *connector)
if (!hdcp->shim)
return;
- /*
- * If the connector is registered, it's possible userspace could kick
- * off another HDCP enable, which would re-spawn the workers.
- */
- drm_WARN_ON(connector->base.dev,
- connector->base.registration_state == DRM_CONNECTOR_REGISTERED);
-
- /*
- * Now that the connector is not registered, check_work won't be run,
- * but cancel any outstanding instances of it
- */
- cancel_delayed_work_sync(&hdcp->check_work);
-
- /*
- * We don't cancel prop_work in the same way as check_work since it
- * requires connection_mutex which could be held while calling this
- * function. Instead, we rely on the connector references grabbed before
- * scheduling prop_work to ensure the connector is alive when prop_work
- * is run. So if we're in the destroy path (which is where this
- * function should be called), we're "guaranteed" that prop_work is not
- * active (tl;dr This Should Never Happen).
- */
- drm_WARN_ON(connector->base.dev, work_pending(&hdcp->prop_work));
-
- mutex_lock(&hdcp->mutex);
+ drm_hdcp_helper_destroy(connector->hdcp_helper_data);
hdcp->shim = NULL;
- mutex_unlock(&hdcp->mutex);
}
/* Handles the CP_IRQ raised from the DP HDCP sink */
@@ -2558,5 +1942,5 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector)
atomic_inc(&connector->hdcp.cp_irq_count);
wake_up_all(&connector->hdcp.cp_irq_queue);
- schedule_delayed_work(&hdcp->check_work, 0);
+ drm_hdcp_helper_schedule_hdcp_check(connector->hdcp_helper_data);
}
@@ -10,8 +10,10 @@
#define HDCP_ENCRYPT_STATUS_CHANGE_TIMEOUT_MS 50
+struct drm_atomic_state;
struct drm_connector;
struct drm_connector_state;
+struct drm_hdcp_an;
struct drm_i915_private;
struct intel_atomic_state;
struct intel_connector;
@@ -25,16 +27,35 @@ enum transcoder;
int intel_hdcp_init(struct intel_connector *connector,
struct intel_digital_port *dig_port,
const struct intel_hdcp_shim *hdcp_shim);
-int intel_hdcp_enable(struct intel_connector *connector,
- const struct intel_crtc_state *pipe_config, u8 content_type);
-int intel_hdcp_disable(struct intel_connector *connector);
-void intel_hdcp_update_pipe(struct intel_atomic_state *state,
- struct intel_encoder *encoder,
- const struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state);
+int intel_hdcp_setup(struct drm_connector *drm_connector,
+ struct drm_atomic_state *state, void *driver_data);
+int intel_hdcp_load_keys(struct drm_connector *drm_connector,
+ void *driver_data);
bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
int intel_hdcp_capable(struct intel_connector *connector, bool *capable);
-int intel_hdcp2_capable(struct intel_connector *connector, bool *capable);
+int intel_hdcp2_capable(struct drm_connector *drm_connector, bool *capable);
+int intel_hdcp2_enable(struct drm_connector *drm_connector, void *driver_data);
+int intel_hdcp2_disable(struct drm_connector *drm_connector, void *driver_data);
+int intel_hdcp2_check_link(struct drm_connector *drm_connector,
+ void *driver_data);
+int intel_hdcp1_store_receiver_info(struct drm_connector *drm_connector,
+ u32 *ksv, u32 status, u8 caps,
+ bool repeater_present, void *driver_data);
+int intel_hdcp1_read_an(struct drm_connector *drm_connector,
+ struct drm_hdcp_an *an);
+int intel_hdcp1_enable_encryption(struct drm_connector *drm_connector,
+ void *driver_data);
+int intel_hdcp1_wait_for_r0(struct drm_connector *drm_connector,
+ void *driver_data);
+int intel_hdcp1_match_ri(struct drm_connector *drm_connector, u32 ri_prime,
+ void *driver_data);
+int intel_hdcp1_post_encryption(struct drm_connector *drm_connector,
+ void *driver_data);
+int intel_hdcp1_store_ksv_fifo(struct drm_connector *drm_connector,
+ u8 *ksv_fifo, u8 num_downstream, u8 *bstatus,
+ u32 *v_prime, void *driver_data);
+int intel_hdcp1_check_link(struct drm_connector *drm_connector);
+int intel_hdcp1_disable(struct drm_connector *drm_connector, void *driver_data);
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);
@@ -1325,17 +1325,25 @@ static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port,
return ret;
}
-static
-int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
- u8 *an)
+static int intel_hdmi_hdcp1_send_an_aksv(struct drm_connector *drm_connector,
+ void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
struct intel_hdmi *hdmi = &dig_port->hdmi;
struct i2c_adapter *adapter = intel_gmbus_get_adapter(i915,
hdmi->ddc_bus);
+ struct drm_hdcp_an an;
int ret;
- ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an,
+ /* Output An first, that's easy */
+ ret = intel_hdcp1_read_an(drm_connector, &an);
+ if (ret)
+ return ret;
+
+ ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an.bytes,
DRM_HDCP_AN_LEN);
if (ret) {
drm_dbg_kms(&i915->drm, "Write An over DDC failed (%d)\n",
@@ -1351,120 +1359,6 @@ int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port,
return 0;
}
-static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port,
- u8 *bksv)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-
- int ret;
- ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv,
- DRM_HDCP_KSV_LEN);
- if (ret)
- drm_dbg_kms(&i915->drm, "Read Bksv over DDC failed (%d)\n",
- ret);
- return ret;
-}
-
-static
-int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port,
- u8 *bstatus)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-
- int ret;
- ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS,
- bstatus, DRM_HDCP_BSTATUS_LEN);
- if (ret)
- drm_dbg_kms(&i915->drm, "Read bstatus over DDC failed (%d)\n",
- ret);
- return ret;
-}
-
-static
-int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *dig_port,
- bool *repeater_present)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- int ret;
- u8 val;
-
- ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
- if (ret) {
- drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
- ret);
- return ret;
- }
- *repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT;
- return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port,
- u8 *ri_prime)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
-
- int ret;
- ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME,
- ri_prime, DRM_HDCP_RI_LEN);
- if (ret)
- drm_dbg_kms(&i915->drm, "Read Ri' over DDC failed (%d)\n",
- ret);
- return ret;
-}
-
-static
-int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port,
- bool *ksv_ready)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- int ret;
- u8 val;
-
- ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1);
- if (ret) {
- drm_dbg_kms(&i915->drm, "Read bcaps over DDC failed (%d)\n",
- ret);
- return ret;
- }
- *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY;
- return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port,
- int num_downstream, u8 *ksv_fifo)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- int ret;
- ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO,
- ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN);
- if (ret) {
- drm_dbg_kms(&i915->drm,
- "Read ksv fifo over DDC failed (%d)\n", ret);
- return ret;
- }
- return 0;
-}
-
-static
-int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port,
- int i, u32 *part)
-{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- int ret;
-
- if (i >= DRM_HDCP_V_PRIME_NUM_PARTS)
- return -EINVAL;
-
- ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_V_PRIME(i),
- part, DRM_HDCP_V_PRIME_PART_LEN);
- if (ret)
- drm_dbg_kms(&i915->drm, "Read V'[%d] over DDC failed (%d)\n",
- i, ret);
- return ret;
-}
-
static int kbl_repositioning_enc_en_signal(struct intel_connector *connector,
enum transcoder cpu_transcoder)
{
@@ -1533,50 +1427,42 @@ int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port,
return 0;
}
-static
-bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port,
- struct intel_connector *connector)
+static int
+intel_hdmi_hdcp1_enable_encryption(struct drm_connector *drm_connector,
+ void *driver_data)
{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- enum port port = dig_port->base.port;
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
int ret;
- union {
- u32 reg;
- u8 shim[DRM_HDCP_RI_LEN];
- } ri;
- ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim);
+ ret = intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder, true);
if (ret)
- return false;
-
- intel_de_write(i915, HDCP_RPRIME(i915, cpu_transcoder, port), ri.reg);
+ return ret;
- /* Wait for Ri prime match */
- if (wait_for((intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder, port)) &
- (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) ==
- (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) {
- drm_dbg_kms(&i915->drm, "Ri' mismatch detected (%x)\n",
- intel_de_read(i915, HDCP_STATUS(i915, cpu_transcoder,
- port)));
- return false;
- }
- return true;
+ return intel_hdcp1_enable_encryption(drm_connector, driver_data);
}
-static
-bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port,
- struct intel_connector *connector)
+static int intel_hdmi_hdcp1_disable(struct drm_connector *drm_connector,
+ void *driver_data)
{
- struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
- int retry;
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
+ enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder;
+ struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ int ret;
- for (retry = 0; retry < 3; retry++)
- if (intel_hdmi_hdcp_check_link_once(dig_port, connector))
- return true;
+ ret = intel_hdcp1_disable(drm_connector, driver_data);
+ if (ret) {
+ drm_err(&i915->drm, "[%s:%d] Failed to disable HDCP 1.4\n",
+ connector->base.name, connector->base.base.id);
+ return ret;
+ }
- drm_err(&i915->drm, "Link check failed\n");
- return false;
+ return intel_hdmi_hdcp_toggle_signalling(dig_port, cpu_transcoder,
+ false);
}
struct hdcp2_hdmi_msg_timeout {
@@ -1742,13 +1628,19 @@ int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port,
return ret;
}
-static
-int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
- bool *capable)
+static int intel_hdmi_hdcp2_capable(struct drm_connector *drm_connector,
+ bool *capable, void *driver_data)
{
+ struct intel_connector *connector = to_intel_connector(drm_connector);
+ struct intel_digital_port *dig_port =
+ intel_attached_dig_port(connector);
u8 hdcp2_version;
int ret;
+ ret = intel_hdcp2_capable(drm_connector, capable);
+ if (ret || !capable)
+ return ret;
+
*capable = false;
ret = intel_hdmi_hdcp_read(dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET,
&hdcp2_version, sizeof(hdcp2_version));
@@ -1759,23 +1651,38 @@ int intel_hdmi_hdcp2_capable(struct intel_digital_port *dig_port,
}
static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = {
- .write_an_aksv = intel_hdmi_hdcp_write_an_aksv,
- .read_bksv = intel_hdmi_hdcp_read_bksv,
- .read_bstatus = intel_hdmi_hdcp_read_bstatus,
- .repeater_present = intel_hdmi_hdcp_repeater_present,
- .read_ri_prime = intel_hdmi_hdcp_read_ri_prime,
- .read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready,
- .read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo,
- .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part,
.toggle_signalling = intel_hdmi_hdcp_toggle_signalling,
- .check_link = intel_hdmi_hdcp_check_link,
.write_2_2_msg = intel_hdmi_hdcp2_write_msg,
.read_2_2_msg = intel_hdmi_hdcp2_read_msg,
- .check_2_2_link = intel_hdmi_hdcp2_check_link,
- .hdcp_2_2_capable = intel_hdmi_hdcp2_capable,
+ .check_2_2_link = intel_hdmi_hdcp2_check_link,
.protocol = HDCP_PROTOCOL_HDMI,
};
+static const struct drm_hdcp_helper_funcs intel_hdmi_hdcp_helper_funcs = {
+ .setup = intel_hdcp_setup,
+ .load_keys = intel_hdcp_load_keys,
+ .hdcp2_capable = intel_hdmi_hdcp2_capable,
+ .hdcp2_enable = intel_hdcp2_enable,
+ .hdcp2_check_link = intel_hdcp2_check_link,
+ .hdcp2_disable = intel_hdcp2_disable,
+ .hdcp1_send_an_aksv = intel_hdmi_hdcp1_send_an_aksv,
+ .hdcp1_store_receiver_info = intel_hdcp1_store_receiver_info,
+ .hdcp1_enable_encryption = intel_hdmi_hdcp1_enable_encryption,
+ .hdcp1_wait_for_r0 = intel_hdcp1_wait_for_r0,
+ .hdcp1_match_ri = intel_hdcp1_match_ri,
+ .hdcp1_post_encryption = intel_hdcp1_post_encryption,
+ .hdcp1_store_ksv_fifo = intel_hdcp1_store_ksv_fifo,
+ .hdcp1_disable = intel_hdmi_hdcp1_disable,
+ /* Common DRM functions that are different between HDMI vs DP*/
+ .remote_read = drm_hdcp_remote_ddc_read,
+ .remote_write = drm_hdcp_remote_ddc_write,
+ .hdcp1_capable = drm_hdcp_helper_hdcp1_capable_hdmi,
+ .hdcp1_ksv_fifo_ready = drm_hdcp_helper_hdcp1_ksv_fifo_ready_hdmi,
+ .wait_r0 = drm_hdcp_helper_wait_r0_hdmi,
+ .hdcp1_check_link_registers = drm_hdcp_hdcp1_check_link_registers_hdmi,
+ .hdcp1_read_ksv_fifo = drm_hdcp_helper_hdcp1_read_ksv_fifo_hdmi,
+};
+
static int intel_hdmi_source_max_tmds_clock(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -2919,6 +2826,37 @@ void intel_infoframe_init(struct intel_digital_port *dig_port)
}
}
+static void intel_hdmi_hdcp_init(struct intel_digital_port *dig_port,
+ struct intel_connector *connector)
+{
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ struct intel_encoder *intel_encoder = &dig_port->base;
+ enum port port = intel_encoder->port;
+ struct drm_hdcp_helper_data *data;
+ int ret;
+
+ if (!is_hdcp_supported(dev_priv, port))
+ return;
+
+ data = drm_hdcp_helper_initialize_hdmi(
+ &connector->base, &intel_hdmi_hdcp_helper_funcs, true);
+ if (IS_ERR(data)) {
+ drm_dbg_kms(&dev_priv->drm, "HDCP init failed ret=%ld\n",
+ PTR_ERR(data));
+ return;
+ }
+
+ ret = intel_hdcp_init(connector, dig_port, &intel_hdmi_hdcp_shim);
+ if (ret) {
+ drm_hdcp_helper_destroy(data);
+ drm_dbg_kms(&dev_priv->drm, "Intel HDCP init failed ret=%d\n",
+ ret);
+ return;
+ }
+
+ connector->hdcp_helper_data = data;
+}
+
void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
struct intel_connector *intel_connector)
{
@@ -2971,13 +2909,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port,
intel_connector_attach_encoder(intel_connector, intel_encoder);
intel_hdmi->attached_connector = intel_connector;
- if (is_hdcp_supported(dev_priv, port)) {
- int ret = intel_hdcp_init(intel_connector, dig_port,
- &intel_hdmi_hdcp_shim);
- if (ret)
- drm_dbg_kms(&dev_priv->drm,
- "HDCP init failed, skipping.\n");
- }
+ intel_hdmi_hdcp_init(dig_port, intel_connector);
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
* 0xd. Failure to do so will result in spurious interrupts being