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: Narender Ankam <nankam@codeaurora.org>
This commit is contained in:
Narender Ankam 2017-11-14 18:21:49 +05:30 committed by Gerrit - the friendly Code Review server
parent 1a51baa68a
commit 2cc1946a7a
2 changed files with 165 additions and 2 deletions

View file

@ -18,6 +18,8 @@
#include <video/msm_hdmi_modes.h> #include <video/msm_hdmi_modes.h>
#include <soc/qcom/scm.h> #include <soc/qcom/scm.h>
#define HDCP_SRM_CHECK_FAIL 29
enum hdcp_client_id { enum hdcp_client_id {
HDCP_CLIENT_HDMI, HDCP_CLIENT_HDMI,
HDCP_CLIENT_DP, HDCP_CLIENT_DP,

View file

@ -789,6 +789,107 @@ error:
return rc; 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) static void hdcp_1x_enable_sink_irq_hpd(struct hdcp_1x *hdcp)
{ {
int rc; int rc;
@ -906,6 +1007,12 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x *hdcp)
if (rc) if (rc)
goto error; 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); rc = hdcp_1x_send_an_aksv_to_sink(hdcp);
if (rc) if (rc)
goto error; goto error;
@ -1230,6 +1337,12 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x *hdcp)
if (rc) if (rc)
goto error; goto error;
rc = hdcp_1x_revoked_rpt_chk(hdcp);
if (rc) {
rc = -HDCP_SRM_CHECK_FAIL;
goto error;
}
do { do {
rc = hdcp_1x_transfer_v_h(hdcp); rc = hdcp_1x_transfer_v_h(hdcp);
if (rc) 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, DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io,
HDMI_DDC_ARBITRATION) | (BIT(4))); HDMI_DDC_ARBITRATION) | (BIT(4)));
end: end:
if (rc && !hdcp_1x_state(HDCP_STATE_INACTIVE)) if (rc && !hdcp_1x_state(HDCP_STATE_INACTIVE)) {
hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL; 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); hdcp_1x_update_auth_status(hdcp);
@ -1751,6 +1866,7 @@ void hdcp_1x_deinit(void *input)
sysfs_remove_group(hdcp->init_data.sysfs_kobj, sysfs_remove_group(hdcp->init_data.sysfs_kobj,
&hdcp_1x_fs_attr_group); &hdcp_1x_fs_attr_group);
hdcp1_client_unregister();
kfree(hdcp); kfree(hdcp);
} /* hdcp_1x_deinit */ } /* hdcp_1x_deinit */
@ -1853,6 +1969,44 @@ irq_not_handled:
return -EINVAL; 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) void *hdcp_1x_init(struct hdcp_init_data *init_data)
{ {
struct hdcp_1x *hdcp = NULL; struct hdcp_1x *hdcp = NULL;
@ -1865,6 +2019,10 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
.off = hdcp_1x_off .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 || if (!init_data || !init_data->core_io || !init_data->qfprom_io ||
!init_data->mutex || !init_data->notify_status || !init_data->mutex || !init_data->notify_status ||
!init_data->workq || !init_data->cb_data) { !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->r0_checked);
init_completion(&hdcp->sink_r0_available); 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", pr_debug("HDCP module initialized. HDCP_STATE=%s\n",
HDCP_STATE_NAME); HDCP_STATE_NAME);