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

Commit 3c35a41e authored by Christopher Braga's avatar Christopher Braga
Browse files

drm/msm/hdcp: Update HDCP QSEECOM to start auth on user command



Split HDCP QSEECOM interface to separate authentication start
from library initialization. Update DP and SDE driver code to
conform to this new interface.

Change-Id: I4780f41cba6b08e6b4a139c0fbe324ec8be803f7
Signed-off-by: default avatarShivaprasad Hongal <shongal@codeaurora.org>
Signed-off-by: default avatarChristopher Braga <cbraga@codeaurora.org>
parent 70f35db1
Loading
Loading
Loading
Loading
+35 −6
Original line number Diff line number Diff line
@@ -241,10 +241,15 @@ static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp)
		struct sde_hdcp_ops *ops = dev->ops;
		void *fd = dev->fd;

		if (!fd || !ops || (dp->hdcp.source_cap & dev->ver))
		if (!fd || !ops)
			continue;

		if (ops->feature_supported(fd))
		if (ops->set_mode && ops->set_mode(fd, dp->mst.mst_active))
			continue;

		if (!(dp->hdcp.source_cap & dev->ver) &&
				ops->feature_supported &&
				ops->feature_supported(fd))
			dp->hdcp.source_cap |= dev->ver;
	}

@@ -273,6 +278,11 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
		dp_display_update_hdcp_info(dp);

		if (dp_display_is_hdcp_enabled(dp)) {
			if (dp->hdcp.ops && dp->hdcp.ops->on &&
					dp->hdcp.ops->on(dp->hdcp.data)) {
				dp_display_update_hdcp_status(dp, true);
				return;
			}
			status->hdcp_state = HDCP_STATE_AUTHENTICATING;
		} else {
			dp_display_update_hdcp_status(dp, true);
@@ -304,6 +314,11 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
		break;
	case HDCP_STATE_AUTH_FAIL:
		if (dp_display_is_ready(dp) && dp->power_on) {
			if (ops && ops->on && ops->on(data)) {
				dp_display_update_hdcp_status(dp, true);
				return;
			}
			status->hdcp_state = HDCP_STATE_AUTHENTICATING;
			if (ops && ops->reauthenticate) {
				rc = ops->reauthenticate(data);
				if (rc)
@@ -721,15 +736,23 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp)
{
	int rc = 0, idx;
	struct dp_panel *dp_panel;
	struct dp_link_hdcp_status *status;

	mutex_lock(&dp->session_lock);

	status = &dp->link->hdcp_status;
	dp->is_connected = false;
	dp->process_hpd_connect = false;

	if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off)
	if (dp_display_is_hdcp_enabled(dp) &&
			status->hdcp_state != HDCP_STATE_INACTIVE) {
		cancel_delayed_work_sync(&dp->hdcp_cb_work);
		if (dp->hdcp.ops->off)
			dp->hdcp.ops->off(dp->hdcp.data);

		dp_display_update_hdcp_status(dp, true);
	}

	for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
		if (!dp->active_panels[idx])
			continue;
@@ -823,8 +846,10 @@ static void dp_display_clean(struct dp_display_private *dp)
{
	int idx;
	struct dp_panel *dp_panel;
	struct dp_link_hdcp_status *status = &dp->link->hdcp_status;

	if (dp_display_is_hdcp_enabled(dp)) {
	if (dp_display_is_hdcp_enabled(dp) &&
			status->hdcp_state != HDCP_STATE_INACTIVE) {
		cancel_delayed_work_sync(&dp->hdcp_cb_work);
		if (dp->hdcp.ops->off)
			dp->hdcp.ops->off(dp->hdcp.data);
@@ -1583,6 +1608,7 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
{
	struct dp_display_private *dp;
	struct dp_panel *dp_panel = panel;
	struct dp_link_hdcp_status *status;
	int rc = 0;

	if (!dp_display || !panel) {
@@ -1594,12 +1620,15 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)

	mutex_lock(&dp->session_lock);

	status = &dp->link->hdcp_status;

	if (!dp->power_on) {
		pr_debug("stream already powered off, return\n");
		goto end;
	}

	if (dp_display_is_hdcp_enabled(dp)) {
	if (dp_display_is_hdcp_enabled(dp) &&
			status->hdcp_state != HDCP_STATE_INACTIVE) {
		cancel_delayed_work_sync(&dp->hdcp_cb_work);
		if (dp->hdcp.ops->off)
			dp->hdcp.ops->off(dp->hdcp.data);
+100 −54
Original line number Diff line number Diff line
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -76,6 +76,25 @@ struct dp_hdcp2p2_interrupts {
	struct dp_hdcp2p2_int_set *int_set;
};

static inline int dp_hdcp2p2_valid_handle(struct dp_hdcp2p2_ctrl *ctrl)
{
	if (!ctrl) {
		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;
	}
	return 0;
}

static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl)
{
	if (ctrl->wakeup_cmd == HDCP_TRANSPORT_CMD_AUTHENTICATE)
@@ -255,20 +274,57 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
	atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
}

static void dp_hdcp2p2_off(void *input)
static int dp_hdcp2p2_register(void *input, bool mst_enabled)
{
	int rc;
	enum sde_hdcp_2x_device_type device_type;
	struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
	struct hdcp_transport_wakeup_data cdata = {
					HDCP_TRANSPORT_CMD_AUTHENTICATE};

	if (!ctrl) {
		pr_err("invalid input\n");
		return;
	rc = dp_hdcp2p2_valid_handle(ctrl);
	if (rc)
		return rc;

	if (mst_enabled)
		device_type = HDCP_TXMTR_DP_MST;
	else
		device_type = HDCP_TXMTR_DP;

	return sde_hdcp_2x_enable(ctrl->lib_ctx, device_type);
}

	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
		pr_err("hdcp is off\n");
static int dp_hdcp2p2_on(void *input)
{
	int rc = 0;
	struct dp_hdcp2p2_ctrl *ctrl = input;
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};

	rc = dp_hdcp2p2_valid_handle(ctrl);
	if (rc)
		return rc;

	cdata.cmd = HDCP_2X_CMD_START;
	cdata.context = ctrl->lib_ctx;
	rc = ctrl->lib->wakeup(&cdata);
	if (rc)
		pr_err("Unable to start the HDCP 2.2 library. Error - %d", rc);

	return rc;
}

static void dp_hdcp2p2_off(void *input)
{
	int rc;
	struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};

	rc = dp_hdcp2p2_valid_handle(ctrl);
	if (rc)
		return;

	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_AUTH_FAIL) {
		cdata.cmd = HDCP_2X_CMD_STOP;
		cdata.context = ctrl->lib_ctx;
		dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
	}

	dp_hdcp2p2_set_interrupts(ctrl, false);
@@ -277,16 +333,18 @@ static void dp_hdcp2p2_off(void *input)

	kthread_flush_worker(&ctrl->worker);

	cdata.context = input;
	dp_hdcp2p2_wakeup(&cdata);
	sde_hdcp_2x_disable(ctrl->lib_ctx);
}

static int dp_hdcp2p2_authenticate(void *input)
{
	int rc;
	struct dp_hdcp2p2_ctrl *ctrl = input;
	struct hdcp_transport_wakeup_data cdata = {
					HDCP_TRANSPORT_CMD_AUTHENTICATE};
	int rc = 0;
	rc = dp_hdcp2p2_valid_handle(ctrl);
	if (rc)
		return rc;

	kthread_flush_worker(&ctrl->worker);

@@ -407,44 +465,34 @@ static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl,

static bool dp_hdcp2p2_feature_supported(void *input)
{
	int rc;
	struct dp_hdcp2p2_ctrl *ctrl = input;
	struct sde_hdcp_2x_ops *lib = NULL;
	bool supported = false;

	if (!ctrl) {
		pr_err("invalid input\n");
		goto end;
	}
	rc = dp_hdcp2p2_valid_handle(ctrl);
	if (rc)
		return supported;

	lib = ctrl->lib;
	if (!lib) {
		pr_err("invalid lib ops data\n");
		goto end;
	}

	if (lib->feature_supported)
		supported = lib->feature_supported(
			ctrl->lib_ctx);
end:

	return supported;
}

static void dp_hdcp2p2_force_encryption(void *data, bool enable)
{
	int rc;
	struct dp_hdcp2p2_ctrl *ctrl = data;
	struct sde_hdcp_2x_ops *lib = NULL;

	if (!ctrl) {
		pr_err("invalid input\n");
	rc = dp_hdcp2p2_valid_handle(ctrl);
	if (rc)
		return;
	}

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

	if (lib->force_encryption)
		lib->force_encryption(ctrl->lib_ctx, enable);
}
@@ -594,19 +642,17 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)

static void dp_hdcp2p2_auth_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};
	struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
		struct dp_hdcp2p2_ctrl, auth);

	cdata.context = ctrl->lib_ctx;

	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING)
		cdata.cmd = HDCP_2X_CMD_START;
	else
		cdata.cmd = HDCP_2X_CMD_STOP;
	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING) {
		struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};

		cdata.context = ctrl->lib_ctx;
		cdata.cmd = HDCP_2X_CMD_START_AUTH;
		dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
	}
}

static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,
		u8 *rx_status)
@@ -651,41 +697,36 @@ static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,

static int dp_hdcp2p2_cp_irq(void *input)
{
	int rc = 0;
	int rc;
	struct dp_hdcp2p2_ctrl *ctrl = input;

	if (!ctrl) {
		pr_err("invalid input\n");
		return -EINVAL;
	}
	rc = dp_hdcp2p2_valid_handle(ctrl);
	if (rc)
		return rc;

	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL ||
		atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
		pr_err("invalid hdcp state\n");
		rc = -EINVAL;
		goto error;
		return -EINVAL;
	}

	ctrl->sink_rx_status = 0;
	rc = dp_hdcp2p2_read_rx_status(ctrl, &ctrl->sink_rx_status);
	if (rc) {
		pr_err("failed to read rx status\n");
		goto error;
		return rc;
	}

	pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status);

	if (!ctrl->sink_rx_status) {
		pr_debug("not a hdcp 2.2 irq\n");
		rc = -EINVAL;
		goto error;
		return -EINVAL;
	}

	kthread_queue_work(&ctrl->worker, &ctrl->link);

	return 0;
error:
	return rc;
}

static int dp_hdcp2p2_isr(void *input)
@@ -763,9 +804,13 @@ void sde_dp_hdcp2p2_deinit(void *input)
		return;
	}

	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_AUTH_FAIL) {
		cdata.cmd = HDCP_2X_CMD_STOP;
		cdata.context = ctrl->lib_ctx;
		dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
	}

	sde_hdcp_2x_deregister(ctrl->lib_ctx);

	kthread_stop(ctrl->thread);

@@ -786,6 +831,8 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
		.feature_supported = dp_hdcp2p2_feature_supported,
		.force_encryption = dp_hdcp2p2_force_encryption,
		.sink_support = dp_hdcp2p2_supported,
		.set_mode = dp_hdcp2p2_register,
		.on = dp_hdcp2p2_on,
		.off = dp_hdcp2p2_off,
		.cp_irq = dp_hdcp2p2_cp_irq,
	};
@@ -840,7 +887,6 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
	register_data.hdcp_data = &ctrl->lib_ctx;
	register_data.client_ops = &client_ops;
	register_data.ops = &hdcp2x_ops;
	register_data.device_type = HDCP_TXMTR_DP;
	register_data.client_data = ctrl;

	rc = sde_hdcp_2x_register(&register_data);
+3 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012, 2014-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012, 2014-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -74,6 +74,8 @@ struct sde_hdcp_ops {
	bool (*feature_supported)(void *input);
	void (*force_encryption)(void *input, bool enable);
	bool (*sink_support)(void *input);
	int (*set_mode)(void *input, bool mst_enabled);
	int (*on)(void *input);
	void (*off)(void *hdcp_ctrl);
};

+71 −22
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -80,6 +80,7 @@ struct sde_hdcp_2x_ctrl {

	struct kthread_worker worker;
	struct kthread_work wk_init;
	struct kthread_work wk_start_auth;
	struct kthread_work wk_msg_sent;
	struct kthread_work wk_msg_recvd;
	struct kthread_work wk_timeout;
@@ -384,11 +385,9 @@ static void sde_hdcp_2x_clean(struct sde_hdcp_2x_ctrl *hdcp)
	cdata.context = hdcp->client_data;
	cdata.cmd = HDCP_TRANSPORT_CMD_STATUS_FAILED;

	if (!atomic_read(&hdcp->hdcp_off))
	if (!atomic_xchg(&hdcp->hdcp_off, 1))
		sde_hdcp_2x_wakeup_client(hdcp, &cdata);

	atomic_set(&hdcp->hdcp_off, 1);

	hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_STOP, &hdcp->app_data);
}

@@ -569,11 +568,6 @@ static void sde_hdcp_2x_msg_sent_work(struct kthread_work *work)
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_msg_sent);

	if (hdcp->wakeup_cmd != HDCP_2X_CMD_MSG_SEND_SUCCESS) {
		pr_err("invalid wakeup command %d\n", hdcp->wakeup_cmd);
		return;
	}

	sde_hdcp_2x_msg_sent(hdcp);
}

@@ -581,12 +575,29 @@ static void sde_hdcp_2x_init(struct sde_hdcp_2x_ctrl *hdcp)
{
	int rc = 0;

	if (hdcp->wakeup_cmd != HDCP_2X_CMD_START) {
		pr_err("invalid wakeup command %d\n", hdcp->wakeup_cmd);
	rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_START, &hdcp->app_data);
	if (rc)
		goto exit;

	return;
exit:
	HDCP_2X_EXECUTE(clean);
}

	rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_START, &hdcp->app_data);
static void sde_hdcp_2x_init_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_init);

	sde_hdcp_2x_init(hdcp);
}

static void sde_hdcp_2x_start_auth(struct sde_hdcp_2x_ctrl *hdcp)
{
	int rc = 0;

	rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_START_AUTH,
		&hdcp->app_data);
	if (rc)
		goto exit;

@@ -600,14 +611,16 @@ static void sde_hdcp_2x_init(struct sde_hdcp_2x_ctrl *hdcp)
	HDCP_2X_EXECUTE(clean);
}

static void sde_hdcp_2x_init_work(struct kthread_work *work)

static void sde_hdcp_2x_start_auth_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_init);
		container_of(work, struct sde_hdcp_2x_ctrl, wk_start_auth);

	sde_hdcp_2x_init(hdcp);
	sde_hdcp_2x_start_auth(hdcp);
}


static void sde_hdcp_2x_timeout(struct sde_hdcp_2x_ctrl *hdcp)
{
	int rc = 0;
@@ -837,6 +850,9 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)

		HDCP_2X_EXECUTE(init);
		break;
	case HDCP_2X_CMD_START_AUTH:
		HDCP_2X_EXECUTE(start_auth);
		break;
	case HDCP_2X_CMD_STOP:
		atomic_set(&hdcp->hdcp_off, 1);
		HDCP_2X_EXECUTE(clean);
@@ -914,17 +930,15 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data)

	hdcp->client_data = data->client_data;
	hdcp->client_ops = data->client_ops;
	hdcp->device_type = data->device_type;

	hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type);

	atomic_set(&hdcp->hdcp_off, 0);
	atomic_set(&hdcp->hdcp_off, 1);

	mutex_init(&hdcp->wakeup_mutex);

	kthread_init_worker(&hdcp->worker);

	kthread_init_work(&hdcp->wk_init,      sde_hdcp_2x_init_work);
	kthread_init_work(&hdcp->wk_start_auth, sde_hdcp_2x_start_auth_work);
	kthread_init_work(&hdcp->wk_msg_sent,  sde_hdcp_2x_msg_sent_work);
	kthread_init_work(&hdcp->wk_msg_recvd, sde_hdcp_2x_msg_recvd_work);
	kthread_init_work(&hdcp->wk_timeout,   sde_hdcp_2x_timeout_work);
@@ -957,6 +971,41 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data)
	return rc;
}

int sde_hdcp_2x_enable(void *data, enum sde_hdcp_2x_device_type device_type)
{
	int rc =  0;
	struct sde_hdcp_2x_ctrl *hdcp = data;

	if (!hdcp)
		return  -EINVAL;

	if (hdcp->hdcp2_ctx) {
		pr_debug("HDCP library context already acquired\n");
		return 0;
	}

	hdcp->device_type = device_type;
	hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type);
	if (!hdcp->hdcp2_ctx) {
		pr_err("Unable to acquire HDCP library handle\n");
		return -ENOMEM;
	}

	return rc;
}

void sde_hdcp_2x_disable(void *data)
{
	struct sde_hdcp_2x_ctrl *hdcp = data;

	if (!hdcp->hdcp2_ctx)
		return;

	kthread_flush_worker(&hdcp->worker);
	hdcp2_deinit(hdcp->hdcp2_ctx);
	hdcp->hdcp2_ctx = NULL;
}

void sde_hdcp_2x_deregister(void *data)
{
	struct sde_hdcp_2x_ctrl *hdcp = data;
@@ -964,8 +1013,8 @@ void sde_hdcp_2x_deregister(void *data)
	if (!hdcp)
		return;

	sde_hdcp_2x_disable(data);
	kthread_stop(hdcp->thread);
	mutex_destroy(&hdcp->wakeup_mutex);
	hdcp2_deinit(hdcp->hdcp2_ctx);
	kzfree(hdcp);
}
+9 −5
Original line number Diff line number Diff line
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -22,8 +22,9 @@
/**
 * enum sde_hdcp_2x_wakeup_cmd - commands for interacting with HDCP driver
 * @HDCP_2X_CMD_INVALID:           initialization value
 * @HDCP_2X_CMD_START:             start authentication
 * @HDCP_2X_CMD_STOP:              stop authentication
 * @HDCP_2X_CMD_START:             start HDCP driver
 * @HDCP_2X_CMD_START_AUTH:        start authentication
 * @HDCP_2X_CMD_STOP:              stop HDCP driver
 * @HDCP_2X_CMD_MSG_SEND_SUCCESS:  sending message to sink succeeded
 * @HDCP_2X_CMD_MSG_SEND_FAILED:   sending message to sink failed
 * @HDCP_2X_CMD_MSG_SEND_TIMEOUT:  sending message to sink timed out
@@ -37,6 +38,7 @@
enum sde_hdcp_2x_wakeup_cmd {
	HDCP_2X_CMD_INVALID,
	HDCP_2X_CMD_START,
	HDCP_2X_CMD_START_AUTH,
	HDCP_2X_CMD_STOP,
	HDCP_2X_CMD_MSG_SEND_SUCCESS,
	HDCP_2X_CMD_MSG_SEND_FAILED,
@@ -71,7 +73,8 @@ enum hdcp_transport_wakeup_cmd {

enum sde_hdcp_2x_device_type {
	HDCP_TXMTR_HDMI = 0x8001,
	HDCP_TXMTR_DP = 0x8002
	HDCP_TXMTR_DP = 0x8002,
	HDCP_TXMTR_DP_MST = 0x8003
};

/**
@@ -195,12 +198,13 @@ struct hdcp_transport_ops {
struct sde_hdcp_2x_register_data {
	struct hdcp_transport_ops *client_ops;
	struct sde_hdcp_2x_ops *ops;
	enum sde_hdcp_2x_device_type device_type;
	void *client_data;
	void **hdcp_data;
};

/* functions for the HDCP 2.2 state machine module */
int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data);
int sde_hdcp_2x_enable(void *data, enum sde_hdcp_2x_device_type device_type);
void sde_hdcp_2x_disable(void *data);
void sde_hdcp_2x_deregister(void *data);
#endif
Loading