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

Commit 2cc1946a authored by Narender Ankam's avatar Narender Ankam Committed by Gerrit - the friendly Code Review server
Browse files

msm: mdss: hdmi: add SRM support for HDCP1.4



Extend HDCP1.4 SRM support for fb based hdmi driver as well.

Change-Id: I3d6597503d95b066d1fcfa71218cdda70965fbd0
Signed-off-by: default avatarNarender Ankam <nankam@codeaurora.org>
parent 1a51baa6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include <video/msm_hdmi_modes.h>
#include <soc/qcom/scm.h>

#define HDCP_SRM_CHECK_FAIL 29

enum hdcp_client_id {
	HDCP_CLIENT_HDMI,
	HDCP_CLIENT_DP,
+163 −2
Original line number Diff line number Diff line
@@ -789,6 +789,107 @@ error:
	return rc;
}

static u8 *hdcp_1x_swap_byte_order(u8 *bksv_in, int num_dev)
{
	u8 *bksv_out;
	u8 *tmp_out;
	u8 *tmp_in;
	int i, j;

	/* Dont exceed max downstream devices */
	if (num_dev > MAX_DEVICES_SUPPORTED) {
		pr_err("invalid params\n");
		return NULL;
	}

	bksv_out = kzalloc(RECV_ID_SIZE * num_dev, GFP_KERNEL);

	if (!bksv_out)
		return NULL;

	pr_debug("num_dev = %d\n", num_dev);

	/* Store temporarily for return */
	tmp_out = bksv_out;
	tmp_in = bksv_in;

	for (i = 0; i < num_dev; i++) {
		for (j = 0; j < RECV_ID_SIZE; j++)
			bksv_out[j] = tmp_in[RECV_ID_SIZE - j - 1];

		/* Each KSV is 5 bytes long */
		bksv_out += RECV_ID_SIZE;
		tmp_in += RECV_ID_SIZE;
	}

	return tmp_out;
}

static int hdcp_1x_revoked_rcv_chk(struct hdcp_1x *hdcp)
{
	int rc = 0;
	u8 *bksv = hdcp->current_tp.bksv;
	u8 *bksv_out;
	struct hdcp_srm_device_id_t *bksv_srm;

	bksv_out = hdcp_1x_swap_byte_order(bksv, 1);

	if (!bksv_out) {
		rc = -ENOMEM;
		goto exit;
	}

	pr_debug("bksv_out : 0x%2x%2x%2x%2x%2x\n",
		bksv_out[4], bksv_out[3], bksv_out[2],
		bksv_out[1], bksv_out[0]);

	bksv_srm = (struct hdcp_srm_device_id_t *)bksv_out;
	/* Here we are checking only receiver ID
	 * hence the device count is one
	 */
	rc = hdcp1_validate_receiver_ids(bksv_srm, 1);

	kfree(bksv_out);

exit:
	return rc;
}

static int hdcp_1x_revoked_rpt_chk(struct hdcp_1x *hdcp)
{
	int rc = 0;
	int i;
	u8 *bksv = hdcp->current_tp.ksv_list;
	u8 *bksv_out;
	struct hdcp_srm_device_id_t *bksv_srm;

	for (i = 0; i < hdcp->sink_addr.ksv_fifo.len;
		 i += RECV_ID_SIZE) {
		pr_debug("bksv : 0x%2x%2x%2x%2x%2x\n",
		bksv[i + 4],
		bksv[i + 3], bksv[i + 2],
		bksv[i + 1], bksv[i]);
	}

	bksv_out = hdcp_1x_swap_byte_order(bksv,
		hdcp->current_tp.dev_count);

	if (!bksv_out) {
		rc = -ENOMEM;
		goto exit;
	}

	bksv_srm = (struct hdcp_srm_device_id_t *)bksv_out;
	/* Here we are checking repeater ksv list */
	rc = hdcp1_validate_receiver_ids(bksv_srm,
			hdcp->current_tp.dev_count);

	kfree(bksv_out);

exit:
	return rc;
}

static void hdcp_1x_enable_sink_irq_hpd(struct hdcp_1x *hdcp)
{
	int rc;
@@ -906,6 +1007,12 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x *hdcp)
	if (rc)
		goto error;

	rc = hdcp_1x_revoked_rcv_chk(hdcp);
	if (rc) {
		rc = -HDCP_SRM_CHECK_FAIL;
		goto error;
	}

	rc = hdcp_1x_send_an_aksv_to_sink(hdcp);
	if (rc)
		goto error;
@@ -1230,6 +1337,12 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x *hdcp)
	if (rc)
		goto error;

	rc = hdcp_1x_revoked_rpt_chk(hdcp);
	if (rc) {
		rc = -HDCP_SRM_CHECK_FAIL;
		goto error;
	}

	do {
		rc = hdcp_1x_transfer_v_h(hdcp);
		if (rc)
@@ -1361,9 +1474,11 @@ static void hdcp_1x_auth_work(struct work_struct *work)
		DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io,
				HDMI_DDC_ARBITRATION) | (BIT(4)));
end:
	if (rc && !hdcp_1x_state(HDCP_STATE_INACTIVE))
	if (rc && !hdcp_1x_state(HDCP_STATE_INACTIVE)) {
		hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;

		if (rc == -HDCP_SRM_CHECK_FAIL)
			hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL_NOREAUTH;
	}

	hdcp_1x_update_auth_status(hdcp);

@@ -1751,6 +1866,7 @@ void hdcp_1x_deinit(void *input)
	sysfs_remove_group(hdcp->init_data.sysfs_kobj,
				&hdcp_1x_fs_attr_group);

	hdcp1_client_unregister();
	kfree(hdcp);
} /* hdcp_1x_deinit */

@@ -1853,6 +1969,44 @@ irq_not_handled:
	return -EINVAL;
}

static void hdcp_1x_srm_cb(void *input)
{

	struct hdcp_1x *hdcp = (struct hdcp_1x *)input;
	int rc = 0;

	if (!hdcp) {
		pr_err("invalid input\n");
		return;
	}

	rc = hdcp_1x_revoked_rcv_chk(hdcp);

	if (rc) {
		pr_err("receiver failed SRM check\n");
		goto fail_noreauth;
	}

	/* If its not a repeater we are done */
	if (hdcp->current_tp.ds_type != DS_REPEATER)
		return;


	/* Check the repeater KSV against SRM */
	rc = hdcp_1x_revoked_rpt_chk(hdcp);
	if (rc) {
		pr_err("repeater failed SRM check\n");
		goto fail_noreauth;
	}

	return;

 fail_noreauth:
	/* No reauth in case of SRM failure */
	hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL_NOREAUTH;
	hdcp_1x_update_auth_status(hdcp);
}

void *hdcp_1x_init(struct hdcp_init_data *init_data)
{
	struct hdcp_1x *hdcp = NULL;
@@ -1865,6 +2019,10 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
		.off = hdcp_1x_off
	};

	static struct hdcp_client_ops client_ops = {
		.srm_cb = hdcp_1x_srm_cb,
	};

	if (!init_data || !init_data->core_io || !init_data->qfprom_io ||
		!init_data->mutex || !init_data->notify_status ||
		!init_data->workq || !init_data->cb_data) {
@@ -1907,6 +2065,9 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
	init_completion(&hdcp->r0_checked);
	init_completion(&hdcp->sink_r0_available);

	/* Register client ctx and the srm_cb with hdcp lib */
	hdcp1_client_register((void *)hdcp, &client_ops);

	pr_debug("HDCP module initialized. HDCP_STATE=%s\n",
		HDCP_STATE_NAME);