Merge "drm/msm: add SRM support for HDCP 1.4"
This commit is contained in:
commit
92c49e0199
4 changed files with 362 additions and 20 deletions
|
@ -33,6 +33,8 @@
|
||||||
#define SDE_HDCP_DEBUG(fmt, args...) SDE_DEBUG(fmt, ##args)
|
#define SDE_HDCP_DEBUG(fmt, args...) SDE_DEBUG(fmt, ##args)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDE_HDCP_SRM_FAIL 29
|
||||||
|
|
||||||
enum sde_hdcp_client_id {
|
enum sde_hdcp_client_id {
|
||||||
HDCP_CLIENT_HDMI,
|
HDCP_CLIENT_HDMI,
|
||||||
HDCP_CLIENT_DP,
|
HDCP_CLIENT_DP,
|
||||||
|
|
|
@ -748,6 +748,107 @@ error:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 *sde_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;
|
||||||
|
|
||||||
|
SDE_HDCP_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 sde_hdcp_1x_revoked_rcv_chk(struct sde_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 = sde_hdcp_1x_swap_byte_order(bksv, 1);
|
||||||
|
|
||||||
|
if (!bksv_out) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDE_HDCP_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 sde_hdcp_1x_revoked_rpt_chk(struct sde_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) {
|
||||||
|
SDE_HDCP_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 = sde_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 sde_hdcp_1x_enable_sink_irq_hpd(struct sde_hdcp_1x *hdcp)
|
static void sde_hdcp_1x_enable_sink_irq_hpd(struct sde_hdcp_1x *hdcp)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -872,6 +973,12 @@ static int sde_hdcp_1x_authentication_part1(struct sde_hdcp_1x *hdcp)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
rc = sde_hdcp_1x_revoked_rcv_chk(hdcp);
|
||||||
|
if (rc) {
|
||||||
|
rc = -SDE_HDCP_SRM_FAIL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
rc = sde_hdcp_1x_send_an_aksv_to_sink(hdcp);
|
rc = sde_hdcp_1x_send_an_aksv_to_sink(hdcp);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1196,6 +1303,12 @@ static int sde_hdcp_1x_authentication_part2(struct sde_hdcp_1x *hdcp)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
rc = sde_hdcp_1x_revoked_rpt_chk(hdcp);
|
||||||
|
if (rc) {
|
||||||
|
rc = -SDE_HDCP_SRM_FAIL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
rc = sde_hdcp_1x_transfer_v_h(hdcp);
|
rc = sde_hdcp_1x_transfer_v_h(hdcp);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -1317,8 +1430,11 @@ static void sde_hdcp_1x_auth_work(struct work_struct *work)
|
||||||
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (rc && !sde_hdcp_1x_state(HDCP_STATE_INACTIVE))
|
if (rc && !sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) {
|
||||||
hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
|
hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
|
||||||
|
if (rc == -SDE_HDCP_SRM_FAIL)
|
||||||
|
hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL_NOREAUTH;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disabling software DDC before going into part3 to make sure
|
* Disabling software DDC before going into part3 to make sure
|
||||||
|
@ -1581,6 +1697,7 @@ void sde_hdcp_1x_deinit(void *input)
|
||||||
if (hdcp->workq)
|
if (hdcp->workq)
|
||||||
destroy_workqueue(hdcp->workq);
|
destroy_workqueue(hdcp->workq);
|
||||||
|
|
||||||
|
hdcp1_client_unregister();
|
||||||
kfree(hdcp);
|
kfree(hdcp);
|
||||||
} /* hdcp_1x_deinit */
|
} /* hdcp_1x_deinit */
|
||||||
|
|
||||||
|
@ -1680,6 +1797,44 @@ irq_not_handled:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sde_hdcp_1x_srm_cb(void *input)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!hdcp) {
|
||||||
|
pr_err("invalid input\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sde_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 = sde_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;
|
||||||
|
sde_hdcp_1x_update_auth_status(hdcp);
|
||||||
|
}
|
||||||
|
|
||||||
void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
|
void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
|
||||||
{
|
{
|
||||||
struct sde_hdcp_1x *hdcp = NULL;
|
struct sde_hdcp_1x *hdcp = NULL;
|
||||||
|
@ -1692,6 +1847,10 @@ void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
|
||||||
.off = sde_hdcp_1x_off
|
.off = sde_hdcp_1x_off
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct hdcp_client_ops client_ops = {
|
||||||
|
.srm_cb = sde_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) {
|
||||||
|
@ -1729,6 +1888,8 @@ void *sde_hdcp_1x_init(struct sde_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);
|
||||||
SDE_HDCP_DEBUG("HDCP module initialized. HDCP_STATE=%s\n",
|
SDE_HDCP_DEBUG("HDCP module initialized. HDCP_STATE=%s\n",
|
||||||
SDE_HDCP_STATE_NAME);
|
SDE_HDCP_STATE_NAME);
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,8 @@
|
||||||
#define RXINFO_SIZE 2
|
#define RXINFO_SIZE 2
|
||||||
#define SEQ_NUM_V_SIZE 3
|
#define SEQ_NUM_V_SIZE 3
|
||||||
|
|
||||||
|
#define HDCP_SRM_CMD_CHECK_DEVICE_ID 2
|
||||||
|
|
||||||
#define RCVR_ID_SIZE BITS_40_IN_BYTES
|
#define RCVR_ID_SIZE BITS_40_IN_BYTES
|
||||||
#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
|
#define MAX_RCVR_IDS_ALLOWED_IN_LIST 31
|
||||||
#define MAX_RCVR_ID_LIST_SIZE \
|
#define MAX_RCVR_ID_LIST_SIZE \
|
||||||
|
@ -437,6 +439,17 @@ struct __attribute__ ((__packed__)) hdcp_update_srm_rsp {
|
||||||
uint32_t commandid;
|
uint32_t commandid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct __attribute__ ((__packed__)) hdcp_srm_check_device_ids_req {
|
||||||
|
uint32_t commandid;
|
||||||
|
uint32_t num_device_ids;
|
||||||
|
uint8_t device_ids[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __attribute__ ((__packed__)) hdcp_srm_check_device_ids_rsp {
|
||||||
|
uint32_t commandid;
|
||||||
|
int32_t retval;
|
||||||
|
};
|
||||||
|
|
||||||
struct __attribute__ ((__packed__)) hdcp_get_topology_req {
|
struct __attribute__ ((__packed__)) hdcp_get_topology_req {
|
||||||
uint32_t commandid;
|
uint32_t commandid;
|
||||||
uint32_t ctxhandle;
|
uint32_t ctxhandle;
|
||||||
|
@ -496,6 +509,20 @@ struct __attribute__ ((__packed__)) hdcp_rcv_id_list_rsp {
|
||||||
uint32_t commandid;
|
uint32_t commandid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct hdcp1_lib_handle - handle for hdcp1 client
|
||||||
|
* @qseecom_handle - for sending commands to hdcp1 TA
|
||||||
|
* @srm_handle - for sending commands to SRM TA
|
||||||
|
* @client_ops - handle to call APIs exposed by hdcp1 client
|
||||||
|
* @client_ctx - client context maintained by hdmi
|
||||||
|
*/
|
||||||
|
struct hdcp1_lib_handle {
|
||||||
|
struct qseecom_handle *qsee_handle;
|
||||||
|
struct qseecom_handle *srm_handle;
|
||||||
|
struct hdcp_client_ops *client_ops;
|
||||||
|
void *client_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct hdcp_lib_handle - handle for hdcp client
|
* struct hdcp_lib_handle - handle for hdcp client
|
||||||
* @qseecom_handle - for sending commands to qseecom
|
* @qseecom_handle - for sending commands to qseecom
|
||||||
|
@ -585,9 +612,10 @@ static void hdcp_lib_stream(struct hdcp_lib_handle *handle);
|
||||||
static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle);
|
static int hdcp_lib_txmtr_init(struct hdcp_lib_handle *handle);
|
||||||
static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle);
|
static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle);
|
||||||
|
|
||||||
static struct qseecom_handle *hdcp1_handle;
|
|
||||||
static struct qseecom_handle *hdcpsrm_handle;
|
static struct qseecom_handle *hdcpsrm_handle;
|
||||||
|
|
||||||
|
static struct hdcp1_lib_handle *hdcp1_handle;
|
||||||
|
|
||||||
static bool hdcp1_supported = true;
|
static bool hdcp1_supported = true;
|
||||||
static bool hdcp1_enc_enabled;
|
static bool hdcp1_enc_enabled;
|
||||||
static struct mutex hdcp1_ta_cmd_lock;
|
static struct mutex hdcp1_ta_cmd_lock;
|
||||||
|
@ -2283,31 +2311,69 @@ static void hdcp_lib_wait_work(struct kthread_work *work)
|
||||||
bool hdcp1_check_if_supported_load_app(void)
|
bool hdcp1_check_if_supported_load_app(void)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
bool hdcp1_srm_supported = true;
|
||||||
|
|
||||||
/* start hdcp1 app */
|
/* start hdcp1 app */
|
||||||
if (hdcp1_supported && !hdcp1_handle) {
|
if (hdcp1_supported && !hdcp1_handle->qsee_handle) {
|
||||||
rc = qseecom_start_app(&hdcp1_handle, HDCP1_APP_NAME,
|
rc = qseecom_start_app(&hdcp1_handle->qsee_handle,
|
||||||
QSEECOM_SBUFF_SIZE);
|
HDCP1_APP_NAME,
|
||||||
|
QSEECOM_SBUFF_SIZE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("qseecom_start_app failed %d\n", rc);
|
pr_err("hdcp1 qseecom_start_app failed %d\n", rc);
|
||||||
hdcp1_supported = false;
|
hdcp1_supported = false;
|
||||||
} else {
|
kfree(hdcp1_handle);
|
||||||
mutex_init(&hdcp1_ta_cmd_lock);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if hdcp1 app succeeds load SRM TA as well */
|
||||||
|
if (hdcp1_supported && !hdcp1_handle->srm_handle) {
|
||||||
|
mutex_init(&hdcp1_ta_cmd_lock);
|
||||||
|
rc = qseecom_start_app(&hdcp1_handle->srm_handle,
|
||||||
|
SRMAPP_NAME,
|
||||||
|
QSEECOM_SBUFF_SIZE);
|
||||||
|
if (rc) {
|
||||||
|
hdcp1_srm_supported = false;
|
||||||
|
pr_err("hdcp1_srm qseecom_start_app failed %d\n", rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("hdcp1 app %s loaded\n",
|
pr_debug("hdcp1 app %s loaded\n",
|
||||||
hdcp1_supported ? "successfully" : "not");
|
hdcp1_supported ? "successfully" : "not");
|
||||||
|
pr_debug("hdcp1 srm app %s loaded\n",
|
||||||
|
hdcp1_srm_supported ? "successfully" : "not");
|
||||||
|
|
||||||
return hdcp1_supported;
|
return hdcp1_supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hdcp1_client_register(void *client_ctx, struct hdcp_client_ops *ops)
|
||||||
|
{
|
||||||
|
/* initialize the hdcp1 handle */
|
||||||
|
hdcp1_handle = kzalloc(sizeof(*hdcp1_handle), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (hdcp1_handle) {
|
||||||
|
hdcp1_handle->client_ops = ops;
|
||||||
|
hdcp1_handle->client_ctx = client_ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hdcp1_client_unregister(void)
|
||||||
|
{
|
||||||
|
if (hdcp1_handle && hdcp1_handle->qsee_handle)
|
||||||
|
qseecom_shutdown_app(&hdcp1_handle->qsee_handle);
|
||||||
|
|
||||||
|
if (hdcp1_handle && hdcp1_handle->srm_handle)
|
||||||
|
qseecom_shutdown_app(&hdcp1_handle->srm_handle);
|
||||||
|
|
||||||
|
kfree(hdcp1_handle);
|
||||||
|
}
|
||||||
|
|
||||||
/* APIs exposed to all clients */
|
/* APIs exposed to all clients */
|
||||||
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct hdcp1_key_set_req *key_set_req;
|
struct hdcp1_key_set_req *key_set_req;
|
||||||
struct hdcp1_key_set_rsp *key_set_rsp;
|
struct hdcp1_key_set_rsp *key_set_rsp;
|
||||||
|
struct qseecom_handle *hdcp1_qsee_handle;
|
||||||
|
|
||||||
if (aksv_msb == NULL || aksv_lsb == NULL)
|
if (aksv_msb == NULL || aksv_lsb == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2315,12 +2381,17 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
||||||
if (!hdcp1_supported || !hdcp1_handle)
|
if (!hdcp1_supported || !hdcp1_handle)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
hdcp1_qsee_handle = hdcp1_handle->qsee_handle;
|
||||||
|
|
||||||
|
if (!hdcp1_qsee_handle)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* set keys and request aksv */
|
/* set keys and request aksv */
|
||||||
key_set_req = (struct hdcp1_key_set_req *)hdcp1_handle->sbuf;
|
key_set_req = (struct hdcp1_key_set_req *)hdcp1_qsee_handle->sbuf;
|
||||||
key_set_req->commandid = HDCP1_SET_KEY_MESSAGE_ID;
|
key_set_req->commandid = HDCP1_SET_KEY_MESSAGE_ID;
|
||||||
key_set_rsp = (struct hdcp1_key_set_rsp *)(hdcp1_handle->sbuf +
|
key_set_rsp = (struct hdcp1_key_set_rsp *)(hdcp1_qsee_handle->sbuf +
|
||||||
QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)));
|
QSEECOM_ALIGN(sizeof(struct hdcp1_key_set_req)));
|
||||||
rc = qseecom_send_command(hdcp1_handle, key_set_req,
|
rc = qseecom_send_command(hdcp1_qsee_handle, key_set_req,
|
||||||
QSEECOM_ALIGN(sizeof
|
QSEECOM_ALIGN(sizeof
|
||||||
(struct hdcp1_key_set_req)),
|
(struct hdcp1_key_set_req)),
|
||||||
key_set_rsp,
|
key_set_rsp,
|
||||||
|
@ -2351,6 +2422,85 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hdcp1_validate_receiver_ids(struct hdcp_srm_device_id_t *device_ids,
|
||||||
|
uint32_t device_id_cnt)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct hdcp_srm_check_device_ids_req *recv_id_req;
|
||||||
|
struct hdcp_srm_check_device_ids_rsp *recv_id_rsp;
|
||||||
|
uint32_t sbuf_len;
|
||||||
|
uint32_t rbuf_len;
|
||||||
|
int i = 0;
|
||||||
|
struct qseecom_handle *hdcp1_srmhandle;
|
||||||
|
|
||||||
|
/* If client has not been registered return */
|
||||||
|
if (!hdcp1_supported || !hdcp1_handle)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Start the hdcp srm app if not already started */
|
||||||
|
if (hdcp1_handle && !hdcp1_handle->srm_handle) {
|
||||||
|
rc = qseecom_start_app(&hdcp1_handle->srm_handle,
|
||||||
|
SRMAPP_NAME, QSEECOM_SBUFF_SIZE);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("qseecom_start_app failed for SRM TA %d\n", rc);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("device_id_cnt = %d\n", device_id_cnt);
|
||||||
|
|
||||||
|
hdcp1_srmhandle = hdcp1_handle->srm_handle;
|
||||||
|
|
||||||
|
sbuf_len = sizeof(struct hdcp_srm_check_device_ids_req)
|
||||||
|
+ sizeof(struct hdcp_srm_device_id_t) * device_id_cnt
|
||||||
|
- 1;
|
||||||
|
|
||||||
|
rbuf_len = sizeof(struct hdcp_srm_check_device_ids_rsp);
|
||||||
|
|
||||||
|
/* Create a SRM validate receiver ID request */
|
||||||
|
recv_id_req = (struct hdcp_srm_check_device_ids_req *)
|
||||||
|
hdcp1_srmhandle->sbuf;
|
||||||
|
recv_id_req->commandid = HDCP_SRM_CMD_CHECK_DEVICE_ID;
|
||||||
|
recv_id_req->num_device_ids = device_id_cnt;
|
||||||
|
memcpy(recv_id_req->device_ids, device_ids,
|
||||||
|
device_id_cnt * sizeof(struct hdcp_srm_device_id_t));
|
||||||
|
|
||||||
|
for (i = 0; i < device_id_cnt * sizeof(struct hdcp_srm_device_id_t);
|
||||||
|
i++) {
|
||||||
|
pr_debug("recv_id_req->device_ids[%d] = 0x%x\n", i,
|
||||||
|
recv_id_req->device_ids[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
recv_id_rsp = (struct hdcp_srm_check_device_ids_rsp *)
|
||||||
|
(hdcp1_srmhandle->sbuf +
|
||||||
|
QSEECOM_ALIGN(sbuf_len));
|
||||||
|
|
||||||
|
rc = qseecom_send_command(hdcp1_srmhandle,
|
||||||
|
recv_id_req,
|
||||||
|
QSEECOM_ALIGN(sbuf_len),
|
||||||
|
recv_id_rsp,
|
||||||
|
QSEECOM_ALIGN(rbuf_len));
|
||||||
|
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_err("qseecom cmd failed err=%d\n", rc);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = recv_id_rsp->retval;
|
||||||
|
if (rc) {
|
||||||
|
pr_err("enc cmd failed, rsp=%d\n", recv_id_rsp->retval);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("rsp=%d\n", recv_id_rsp->retval);
|
||||||
|
pr_debug("commandid=%d\n", recv_id_rsp->commandid);
|
||||||
|
|
||||||
|
end:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hdcp_validate_recv_id(struct hdcp_lib_handle *handle)
|
static int hdcp_validate_recv_id(struct hdcp_lib_handle *handle)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@ -2398,6 +2548,7 @@ int hdcp1_set_enc(bool enable)
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct hdcp1_set_enc_req *set_enc_req;
|
struct hdcp1_set_enc_req *set_enc_req;
|
||||||
struct hdcp1_set_enc_rsp *set_enc_rsp;
|
struct hdcp1_set_enc_rsp *set_enc_rsp;
|
||||||
|
struct qseecom_handle *hdcp1_qsee_handle;
|
||||||
|
|
||||||
mutex_lock(&hdcp1_ta_cmd_lock);
|
mutex_lock(&hdcp1_ta_cmd_lock);
|
||||||
|
|
||||||
|
@ -2406,18 +2557,23 @@ int hdcp1_set_enc(bool enable)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hdcp1_qsee_handle = hdcp1_handle->qsee_handle;
|
||||||
|
|
||||||
|
if (!hdcp1_qsee_handle)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (hdcp1_enc_enabled == enable) {
|
if (hdcp1_enc_enabled == enable) {
|
||||||
pr_info("already %s\n", enable ? "enabled" : "disabled");
|
pr_info("already %s\n", enable ? "enabled" : "disabled");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set keys and request aksv */
|
/* set keys and request aksv */
|
||||||
set_enc_req = (struct hdcp1_set_enc_req *)hdcp1_handle->sbuf;
|
set_enc_req = (struct hdcp1_set_enc_req *)hdcp1_qsee_handle->sbuf;
|
||||||
set_enc_req->commandid = HDCP1_SET_ENC_MESSAGE_ID;
|
set_enc_req->commandid = HDCP1_SET_ENC_MESSAGE_ID;
|
||||||
set_enc_req->enable = enable;
|
set_enc_req->enable = enable;
|
||||||
set_enc_rsp = (struct hdcp1_set_enc_rsp *)(hdcp1_handle->sbuf +
|
set_enc_rsp = (struct hdcp1_set_enc_rsp *)(hdcp1_qsee_handle->sbuf +
|
||||||
QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)));
|
QSEECOM_ALIGN(sizeof(struct hdcp1_set_enc_req)));
|
||||||
rc = qseecom_send_command(hdcp1_handle, set_enc_req,
|
rc = qseecom_send_command(hdcp1_qsee_handle, set_enc_req,
|
||||||
QSEECOM_ALIGN(sizeof
|
QSEECOM_ALIGN(sizeof
|
||||||
(struct hdcp1_set_enc_req)),
|
(struct hdcp1_set_enc_req)),
|
||||||
set_enc_rsp,
|
set_enc_rsp,
|
||||||
|
@ -2679,6 +2835,8 @@ static ssize_t hdmi_hdcp_srm_updated(struct device *dev,
|
||||||
int srm_updated;
|
int srm_updated;
|
||||||
struct hdcp_lib_handle *handle;
|
struct hdcp_lib_handle *handle;
|
||||||
ssize_t ret = count;
|
ssize_t ret = count;
|
||||||
|
struct hdcp_client_ops *client_ops;
|
||||||
|
void *hdcp_client_ctx;
|
||||||
|
|
||||||
handle = hdcp_drv_mgr->handle;
|
handle = hdcp_drv_mgr->handle;
|
||||||
|
|
||||||
|
@ -2689,12 +2847,21 @@ static ssize_t hdmi_hdcp_srm_updated(struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srm_updated) {
|
if (srm_updated) {
|
||||||
if (hdcp_validate_recv_id(handle)) {
|
if (handle && handle->qseecom_handle) {
|
||||||
pr_debug("SRM check FAILED\n");
|
client_ops = handle->client_ops;
|
||||||
if (handle && handle->client_ops->srm_cb)
|
hdcp_client_ctx = handle->client_ctx;
|
||||||
handle->client_ops->srm_cb(handle->client_ctx);
|
if (hdcp_validate_recv_id(handle)) {
|
||||||
} else {
|
pr_debug("HDCP 2.2 SRM check FAILED\n");
|
||||||
pr_debug("SRM check PASSED\n");
|
if (handle && client_ops->srm_cb)
|
||||||
|
client_ops->srm_cb(hdcp_client_ctx);
|
||||||
|
} else
|
||||||
|
pr_debug("HDCP 2.2 SRM check PASSED\n");
|
||||||
|
} else if (hdcp1_handle && hdcp1_handle->qsee_handle) {
|
||||||
|
pr_debug("HDCP 1.4 SRM check\n");
|
||||||
|
hdcp_client_ctx = hdcp1_handle->client_ctx;
|
||||||
|
client_ops = hdcp1_handle->client_ops;
|
||||||
|
if (client_ops->srm_cb)
|
||||||
|
client_ops->srm_cb(hdcp_client_ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#define HDCP_MAX_MESSAGE_PARTS 4
|
#define HDCP_MAX_MESSAGE_PARTS 4
|
||||||
|
#define RECV_ID_SIZE 5
|
||||||
|
#define MAX_DEVICES_SUPPORTED 127
|
||||||
|
|
||||||
enum hdcp_lib_wakeup_cmd {
|
enum hdcp_lib_wakeup_cmd {
|
||||||
HDCP_LIB_WKUP_CMD_INVALID,
|
HDCP_LIB_WKUP_CMD_INVALID,
|
||||||
|
@ -115,6 +117,10 @@ static inline char *hdcp_lib_cmd_to_str(uint32_t cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct hdcp_srm_device_id_t {
|
||||||
|
uint8_t data[RECV_ID_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
struct hdcp_txmtr_ops {
|
struct hdcp_txmtr_ops {
|
||||||
int (*wakeup)(struct hdcp_lib_wakeup_data *data);
|
int (*wakeup)(struct hdcp_lib_wakeup_data *data);
|
||||||
bool (*feature_supported)(void *phdcpcontext);
|
bool (*feature_supported)(void *phdcpcontext);
|
||||||
|
@ -148,6 +154,12 @@ void hdcp_library_deregister(void *phdcpcontext);
|
||||||
bool hdcp1_check_if_supported_load_app(void);
|
bool hdcp1_check_if_supported_load_app(void);
|
||||||
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
|
int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb);
|
||||||
int hdcp1_set_enc(bool enable);
|
int hdcp1_set_enc(bool enable);
|
||||||
|
int hdcp1_validate_receiver_ids(struct hdcp_srm_device_id_t *device_ids,
|
||||||
|
uint32_t device_id_cnt);
|
||||||
void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp);
|
void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp);
|
||||||
void hdcp1_notify_topology(void);
|
void hdcp1_notify_topology(void);
|
||||||
|
void hdcp1_client_register(void *client_ctx,
|
||||||
|
struct hdcp_client_ops *ops);
|
||||||
|
void hdcp1_client_unregister(void);
|
||||||
|
|
||||||
#endif /* __HDCP_QSEECOM_H */
|
#endif /* __HDCP_QSEECOM_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue