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:
parent
1a51baa68a
commit
2cc1946a7a
2 changed files with 165 additions and 2 deletions
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue