Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 764c1ad3 authored by Christopher Braga's avatar Christopher Braga
Browse files

drm/msm/dp: Add MST support for HDCP 2.2



Add MST support for HDCP 2.2 by initializing the HDCP library
in MST mode, and adding the support to dynamically add and
remove streams.

Change-Id: I46ed13f4bc56dca5c2ef08745f435b541265be98
Signed-off-by: default avatarChristopher Braga <cbraga@codeaurora.org>
parent 451f0282
Loading
Loading
Loading
Loading
+59 −1
Original line number Diff line number Diff line
@@ -256,6 +256,47 @@ static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp)
	dp_display_update_hdcp_status(dp, false);
}

static void dp_display_hdcp_register_streams(struct dp_display_private *dp)
{
	int rc;
	struct sde_hdcp_ops *ops = dp->hdcp.ops;
	void *data = dp->hdcp.data;

	if (dp_display_is_ready(dp) && dp->mst.mst_active && ops &&
			ops->register_streams){
		struct stream_info streams[DP_STREAM_MAX];
		int index = 0;

		pr_debug("Registering all active panel streams with HDCP\n");
		for (size_t i = DP_STREAM_0; i < DP_STREAM_MAX; i++) {
			if (!dp->active_panels[i])
				continue;
			streams[index].stream_id = i;
			streams[index].virtual_channel =
				dp->active_panels[i]->vcpi;
			index++;
		}

		if (index > 0) {
			rc = ops->register_streams(data, index, streams);
			if (rc)
				pr_err("failed to register streams. rc = %d\n",
					rc);
		}
	}
}

static void dp_display_hdcp_deregister_stream(struct dp_display_private *dp,
		enum dp_stream_id stream_id)
{
	if (dp->hdcp.ops->deregister_streams) {
		struct stream_info stream = {stream_id, 0};

		pr_debug("Deregistering stream within HDCP library");
		dp->hdcp.ops->deregister_streams(dp->hdcp.data, 1, &stream);
	}
}

static void dp_display_hdcp_cb_work(struct work_struct *work)
{
	struct dp_display_private *dp;
@@ -309,6 +350,7 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)

	switch (status->hdcp_state) {
	case HDCP_STATE_AUTHENTICATING:
		dp_display_hdcp_register_streams(dp);
		if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
			rc = dp->hdcp.ops->authenticate(data);
		break;
@@ -318,6 +360,7 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
				dp_display_update_hdcp_status(dp, true);
				return;
			}
			dp_display_hdcp_register_streams(dp);
			status->hdcp_state = HDCP_STATE_AUTHENTICATING;
			if (ops && ops->reauthenticate) {
				rc = ops->reauthenticate(data);
@@ -329,6 +372,7 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
		}
		break;
	default:
		dp_display_hdcp_register_streams(dp);
		break;
	}
}
@@ -1629,13 +1673,27 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)

	if (dp_display_is_hdcp_enabled(dp) &&
			status->hdcp_state != HDCP_STATE_INACTIVE) {
		cancel_delayed_work_sync(&dp->hdcp_cb_work);
		flush_delayed_work(&dp->hdcp_cb_work);
		if (dp->mst.mst_active) {
			dp_display_hdcp_deregister_stream(dp,
				dp_panel->stream_id);
			for (int i = DP_STREAM_0; i < DP_STREAM_MAX; i++) {
				if (i != dp_panel->stream_id)
					continue;
				if (dp->active_panels[i]) {
					pr_debug("Streams are still active. Skip disabling HDCP\n");
					goto stream;
				}
			}
		}

		if (dp->hdcp.ops->off)
			dp->hdcp.ops->off(dp->hdcp.data);

		dp_display_update_hdcp_status(dp, true);
	}

stream:
	if (dp_panel->audio_supported)
		dp_panel->audio->off(dp_panel->audio);

+47 −0
Original line number Diff line number Diff line
@@ -794,6 +794,51 @@ static bool dp_hdcp2p2_supported(void *input)
	return false;
}

static int dp_hdcp2p2_change_streams(struct dp_hdcp2p2_ctrl *ctrl,
		struct sde_hdcp_2x_wakeup_data *cdata)
{
	if (!ctrl || cdata->num_streams == 0 || !cdata->streams) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	if (!ctrl->lib_ctx) {
		pr_err("HDCP library needs to be acquired\n");
		return -EINVAL;
	}

	if (!ctrl->lib) {
		pr_err("invalid lib ops data\n");
		return -EINVAL;
	}

	cdata->context = ctrl->lib_ctx;
	return ctrl->lib->wakeup(cdata);
}


static int dp_hdcp2p2_register_streams(void *input, u8 num_streams,
			struct stream_info *streams)
{
	struct dp_hdcp2p2_ctrl *ctrl = input;
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_OPEN_STREAMS};

	cdata.streams = streams;
	cdata.num_streams = num_streams;
	return dp_hdcp2p2_change_streams(ctrl, &cdata);
}

static int dp_hdcp2p2_deregister_streams(void *input, u8 num_streams,
			struct stream_info *streams)
{
	struct dp_hdcp2p2_ctrl *ctrl = input;
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_CLOSE_STREAMS};

	cdata.streams = streams;
	cdata.num_streams = num_streams;
	return dp_hdcp2p2_change_streams(ctrl, &cdata);
}

void sde_dp_hdcp2p2_deinit(void *input)
{
	struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
@@ -835,6 +880,8 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
		.on = dp_hdcp2p2_on,
		.off = dp_hdcp2p2_off,
		.cp_irq = dp_hdcp2p2_cp_irq,
		.register_streams = dp_hdcp2p2_register_streams,
		.deregister_streams = dp_hdcp2p2_deregister_streams,
	};

	static struct hdcp_transport_ops client_ops = {