diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index fa111d581529..0f77e35ef287 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -665,6 +665,15 @@ static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work) __func__); } + break; + case HDCP_STATE_AUTH_FAIL_NOREAUTH: + if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) { + if (hdmi_ctrl->auth_state && !hdmi_ctrl->hdcp22_present) + hdcp1_set_enc(false); + } + + hdmi_ctrl->auth_state = false; + break; case HDCP_STATE_AUTH_ENC_NONE: hdmi_ctrl->enc_lvl = HDCP_STATE_AUTH_ENC_NONE; diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c index 1e673440f399..51f5c8d8dde6 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_hdcp2p2.c @@ -338,6 +338,41 @@ static void sde_hdmi_hdcp2p2_auth_failed(struct sde_hdmi_hdcp2p2_ctrl *ctrl) HDCP_STATE_AUTH_FAIL); } +static void sde_hdmi_hdcp2p2_fail_noreauth(struct sde_hdmi_hdcp2p2_ctrl *ctrl) +{ + if (!ctrl) { + SDE_ERROR("invalid input\n"); + return; + } + + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); + + sde_hdmi_hdcp2p2_ddc_disable(ctrl->init_data.cb_data); + + /* notify hdmi tx about HDCP failure */ + ctrl->init_data.notify_status(ctrl->init_data.cb_data, + HDCP_STATE_AUTH_FAIL_NOREAUTH); +} + +static void sde_hdmi_hdcp2p2_srm_cb(void *client_ctx) +{ + struct sde_hdmi_hdcp2p2_ctrl *ctrl = + (struct sde_hdmi_hdcp2p2_ctrl *)client_ctx; + struct hdcp_lib_wakeup_data cdata = { + HDCP_LIB_WKUP_CMD_INVALID}; + + if (!ctrl) { + SDE_ERROR("invalid input\n"); + return; + } + + cdata.context = ctrl->lib_ctx; + cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; + sde_hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); + + sde_hdmi_hdcp2p2_fail_noreauth(ctrl); +} + static int sde_hdmi_hdcp2p2_ddc_rd_message(struct sde_hdmi_hdcp2p2_ctrl *ctrl, u8 *buf, int size, u32 timeout) { @@ -888,6 +923,7 @@ void *sde_hdmi_hdcp2p2_init(struct sde_hdcp_init_data *init_data) static struct hdcp_client_ops client_ops = { .wakeup = sde_hdmi_hdcp2p2_wakeup, .notify_lvl_change = sde_hdmi_hdcp2p2_min_level_change, + .srm_cb = sde_hdmi_hdcp2p2_srm_cb, }; static struct hdcp_txmtr_ops txmtr_ops; diff --git a/drivers/gpu/drm/msm/sde_hdcp.h b/drivers/gpu/drm/msm/sde_hdcp.h index 49cca9399cb0..c414f68a8e0d 100644 --- a/drivers/gpu/drm/msm/sde_hdcp.h +++ b/drivers/gpu/drm/msm/sde_hdcp.h @@ -43,6 +43,7 @@ enum sde_hdcp_states { HDCP_STATE_AUTHENTICATING, HDCP_STATE_AUTHENTICATED, HDCP_STATE_AUTH_FAIL, + HDCP_STATE_AUTH_FAIL_NOREAUTH, HDCP_STATE_AUTH_ENC_NONE, HDCP_STATE_AUTH_ENC_1X, HDCP_STATE_AUTH_ENC_2P2 diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 687f55bd5afd..87daee7cf1c6 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -38,6 +38,7 @@ #include "qseecom_kernel.h" +#define SRMAPP_NAME "hdcpsrm" #define TZAPP_NAME "hdcp2p2" #define HDCP1_APP_NAME "hdcp1" #define QSEECOM_SBUFF_SIZE 0x1000 @@ -138,6 +139,7 @@ #define HDCP_SESSION_INIT SERVICE_CREATE_CMD(16) #define HDCP_SESSION_DEINIT SERVICE_CREATE_CMD(17) #define HDCP_TXMTR_START_AUTHENTICATE SERVICE_CREATE_CMD(18) +#define HDCP_TXMTR_VALIDATE_RECEIVER_ID_LIST SERVICE_CREATE_CMD(19) #define HCDP_TXMTR_GET_MAJOR_VERSION(v) (((v) >> 16) & 0xFF) #define HCDP_TXMTR_GET_MINOR_VERSION(v) (((v) >> 8) & 0xFF) @@ -485,6 +487,15 @@ struct __attribute__ ((__packed__)) hdcp_start_auth_rsp { uint8_t message[MAX_TX_MESSAGE_SIZE]; }; +struct __attribute__ ((__packed__)) hdcp_rcv_id_list_req { + uint32_t commandid; + uint32_t ctxHandle; +}; +struct __attribute__ ((__packed__)) hdcp_rcv_id_list_rsp { + uint32_t status; + uint32_t commandid; +}; + /* * struct hdcp_lib_handle - handle for hdcp client * @qseecom_handle - for sending commands to qseecom @@ -575,6 +586,8 @@ static int hdcp_lib_txmtr_init(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 bool hdcp1_supported = true; static bool hdcp1_enc_enabled; static struct mutex hdcp1_ta_cmd_lock; @@ -1044,6 +1057,15 @@ static int hdcp_lib_library_load(struct hdcp_lib_handle *handle) goto exit; } + if (!hdcpsrm_handle) { + rc = qseecom_start_app(&hdcpsrm_handle, + SRMAPP_NAME, QSEECOM_SBUFF_SIZE); + if (rc) { + pr_err("qseecom_start_app failed for SRM TA %d\n", rc); + goto exit; + } + } + handle->hdcp_state |= HDCP_STATE_APP_LOADED; pr_debug("qseecom_start_app success\n"); @@ -1113,10 +1135,17 @@ static int hdcp_lib_library_unload(struct hdcp_lib_handle *handle) goto exit; } - /* deallocate the resources for qseecom handle */ + /* deallocate the resources for qseecom hdcp2p2 handle */ rc = qseecom_shutdown_app(&handle->qseecom_handle); if (rc) { - pr_err("qseecom_shutdown_app failed err: %d\n", rc); + pr_err("hdcp2p2 qseecom_shutdown_app failed err: %d\n", rc); + goto exit; + } + + /* deallocate the resources for qseecom hdcpsrm handle */ + rc = qseecom_shutdown_app(&hdcpsrm_handle); + if (rc) { + pr_err("hdcpsrm qseecom_shutdown_app failed err: %d\n", rc); goto exit; } @@ -2322,6 +2351,48 @@ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb) return 0; } +static int hdcp_validate_recv_id(struct hdcp_lib_handle *handle) +{ + int rc = 0; + struct hdcp_rcv_id_list_req *recv_id_req; + struct hdcp_rcv_id_list_rsp *recv_id_rsp; + + if (!handle || !handle->qseecom_handle || + !handle->qseecom_handle->sbuf) { + pr_err("invalid handle\n"); + return -EINVAL; + } + + /* validate the receiver ID list against the new SRM blob */ + recv_id_req = (struct hdcp_rcv_id_list_req *) + handle->qseecom_handle->sbuf; + recv_id_req->commandid = HDCP_TXMTR_VALIDATE_RECEIVER_ID_LIST; + recv_id_req->ctxHandle = handle->tz_ctxhandle; + + recv_id_rsp = (struct hdcp_rcv_id_list_rsp *) + (handle->qseecom_handle->sbuf + + QSEECOM_ALIGN(sizeof(struct hdcp_rcv_id_list_req))); + + rc = qseecom_send_command(handle->qseecom_handle, + recv_id_req, + QSEECOM_ALIGN(sizeof(struct hdcp_rcv_id_list_req)), + recv_id_rsp, + QSEECOM_ALIGN(sizeof(struct hdcp_rcv_id_list_rsp))); + + + if ((rc < 0) || (recv_id_rsp->status != HDCP_SUCCESS) || + (recv_id_rsp->commandid != + HDCP_TXMTR_VALIDATE_RECEIVER_ID_LIST)) { + pr_err("qseecom cmd failed with err = %d status = %d\n", + rc, recv_id_rsp->status); + rc = -EINVAL; + goto exit; + } + +exit: + return rc; +} + int hdcp1_set_enc(bool enable) { int rc = 0; @@ -2601,12 +2672,44 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev, return ret; } +static ssize_t hdmi_hdcp_srm_updated(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + int srm_updated; + struct hdcp_lib_handle *handle; + ssize_t ret = count; + + handle = hdcp_drv_mgr->handle; + + rc = kstrtoint(buf, 10, &srm_updated); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return -EINVAL; + } + + if (srm_updated) { + if (hdcp_validate_recv_id(handle)) { + pr_debug("SRM check FAILED\n"); + if (handle && handle->client_ops->srm_cb) + handle->client_ops->srm_cb(handle->client_ctx); + } else { + pr_debug("SRM check PASSED\n"); + } + } + + return ret; +} + static DEVICE_ATTR(tp, S_IRUGO | S_IWUSR, msm_hdcp_1x_sysfs_rda_tp, msm_hdcp_1x_sysfs_wta_tp); static DEVICE_ATTR(min_level_change, S_IWUSR, NULL, hdmi_hdcp2p2_sysfs_wta_min_level_change); +static DEVICE_ATTR(srm_updated, S_IWUSR, NULL, +hdmi_hdcp_srm_updated); + void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp) { memcpy((void *)&hdcp_drv_mgr->cached_tp, @@ -2617,6 +2720,7 @@ void hdcp1_cache_repeater_topology(void *hdcp1_cached_tp) static struct attribute *msm_hdcp_fs_attrs[] = { &dev_attr_tp.attr, &dev_attr_min_level_change.attr, + &dev_attr_srm_updated.attr, NULL }; diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h index dc513fbab580..8e1b853e738e 100644 --- a/include/linux/hdcp_qseecom.h +++ b/include/linux/hdcp_qseecom.h @@ -126,6 +126,7 @@ struct hdcp_txmtr_ops { struct hdcp_client_ops { int (*wakeup)(struct hdmi_hdcp_wakeup_data *data); void (*notify_lvl_change)(void *client_ctx, int min_lvl); + void (*srm_cb)(void *client_ctx); }; enum hdcp_device_type {