@@ -7,10 +7,12 @@
*/
#include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_hdcp.h>
#include <drm/drm_print.h>
#include "intel_display_types.h"
+#include "intel_ddi.h"
#include "intel_dp.h"
#include "intel_hdcp.h"
@@ -589,6 +591,104 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = {
.protocol = HDCP_PROTOCOL_DP,
};
+static int
+intel_dp_mst_hdcp_toggle_signalling(struct intel_digital_port *intel_dig_port,
+ enum transcoder cpu_transcoder,
+ bool enable)
+{
+ int ret;
+
+ if (!enable)
+ usleep_range(6, 60); /* Bspec says >= 6us */
+
+ ret = intel_ddi_toggle_hdcp_signalling(&intel_dig_port->base,
+ cpu_transcoder, enable);
+ if (ret)
+ DRM_DEBUG_KMS("%s HDCP signalling failed (%d)\n",
+ enable ? "Enable" : "Disable", ret);
+ return ret;
+}
+
+static
+int intel_dp_mst_hdcp2_write_msg(struct intel_digital_port *intel_dig_port,
+ void *buf, size_t size)
+{
+ return -EOPNOTSUPP;
+}
+
+static
+int intel_dp_mst_hdcp2_read_msg(struct intel_digital_port *intel_dig_port,
+ u8 msg_id, void *buf, size_t size)
+{
+ return -EOPNOTSUPP;
+}
+
+static int
+intel_dp_mst_hdcp2_config_stream_type(struct intel_digital_port *intel_dig_port,
+ bool is_repeater, u8 content_type)
+{
+ return -EOPNOTSUPP;
+}
+
+static
+int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *intel_dig_port)
+{
+ return -EOPNOTSUPP;
+}
+
+static
+int intel_dp_mst_hdcp2_capable(struct intel_digital_port *intel_dig_port,
+ bool *capable)
+{
+ *capable = false;
+ return 0;
+}
+
+static
+bool intel_dp_mst_hdcp_check_link(struct intel_digital_port *intel_dig_port,
+ struct intel_connector *connector)
+{
+ struct intel_dp *intel_dp = &intel_dig_port->dp;
+ struct drm_dp_query_stream_enc_status_ack_reply reply;
+ int ret;
+
+ if (!intel_dp_hdcp_check_link(intel_dig_port, connector))
+ return false;
+
+ ret = drm_dp_send_query_stream_enc_status(&intel_dp->mst_mgr,
+ connector->port, &reply);
+ if (ret) {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] failed QSES ret=%d\n",
+ connector->base.base.id, connector->base.name,
+ ret);
+ return false;
+ }
+
+ return reply.auth_completed && reply.encryption_enabled;
+}
+
+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_mst_hdcp_toggle_signalling,
+ .check_link = intel_dp_mst_hdcp_check_link,
+ .hdcp_capable = intel_dp_hdcp_capable,
+
+ .write_2_2_msg = intel_dp_mst_hdcp2_write_msg,
+ .read_2_2_msg = intel_dp_mst_hdcp2_read_msg,
+ .config_stream_type = intel_dp_mst_hdcp2_config_stream_type,
+ .check_2_2_link = intel_dp_mst_hdcp2_check_link,
+ .hdcp_2_2_capable = intel_dp_mst_hdcp2_capable,
+
+ .protocol = HDCP_PROTOCOL_DP,
+};
+
int intel_dp_init_hdcp(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector)
{
@@ -601,7 +701,10 @@ int intel_dp_init_hdcp(struct intel_digital_port *intel_dig_port,
if (!is_hdcp_supported(dev_priv, port))
return 0;
- if (!intel_dp_is_edp(intel_dp))
+ if (intel_connector->mst_port)
+ return intel_hdcp_init(intel_connector, port,
+ &intel_dp_mst_hdcp_shim);
+ else if (!intel_dp_is_edp(intel_dp))
return intel_hdcp_init(intel_connector, port,
&intel_dp_hdcp_shim);
@@ -36,6 +36,7 @@
#include "intel_dp.h"
#include "intel_dp_mst.h"
#include "intel_dpio_phy.h"
+#include "intel_hdcp.h"
static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
@@ -326,6 +327,8 @@ static void intel_mst_disable_dp(struct intel_encoder *encoder,
DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links);
+ intel_hdcp_disable(intel_mst->connector);
+
drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
@@ -510,6 +513,13 @@ static void intel_mst_enable_dp(struct intel_encoder *encoder,
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
if (pipe_config->has_audio)
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->cpu_transcoder,
+ (u8)conn_state->hdcp_content_type);
}
static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
@@ -703,6 +713,10 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
intel_attach_force_audio_property(connector);
intel_attach_broadcast_rgb_property(connector);
+ ret = intel_dp_init_hdcp(intel_dig_port, intel_connector);
+ if (ret)
+ DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
+
/*
* Reuse the prop from the SST connector because we're
* not allowed to create new props after device registration.