diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 7054e74654fe..e42d4fb5587e 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -863,6 +863,27 @@ exit: return rc; } +static bool hdcp2p2_client_feature_supported(void *phdcpcontext) +{ + int rc = 0; + bool supported = false; + struct hdcp2p2_handle *handle = phdcpcontext; + + if (!handle) { + pr_err("invalid input\n"); + goto end; + } + + rc = hdcp2p2_library_load(handle); + if (!rc) { + pr_debug("HDCP2p2 supported\n"); + hdcp2p2_library_unload(handle); + supported = true; + } +end: + return supported; +} + static int hdcp2p2_client_start(void *phdcpcontext) { int rc = 0; @@ -1135,6 +1156,7 @@ int hdcp_library_register(void **pphdcpcontext, /* populate ops to be called by client */ txmtr_ops->start = hdcp2p2_client_start; txmtr_ops->stop = hdcp2p2_client_stop; + txmtr_ops->feature_supported = hdcp2p2_client_feature_supported; txmtr_ops->process_message = hdcp2p2_txmtr_process_message; txmtr_ops->hdcp_txmtr_query_stream_type = hdcp2p2_txmtr_query_stream_type; @@ -1166,7 +1188,8 @@ int hdcp_library_register(void **pphdcpcontext, } *((struct hdcp2p2_handle **)pphdcpcontext) = handle; - pr_debug("hdcp lib successfully initialized\n"); + + pr_debug("hdcp lib successfully registered\n"); return 0; error: @@ -1196,6 +1219,8 @@ void hdcp_library_deregister(void *phdcpcontext) if (handle->hdcp_workqueue) destroy_workqueue(handle->hdcp_workqueue); + mutex_destroy(&handle->hdcp_lock); + kzfree(handle->listener_buf); kzfree(handle); } diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h index 901aaefac387..c6e151812a4c 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h @@ -43,6 +43,7 @@ struct hdmi_hdcp_ops { int (*hdmi_hdcp_isr)(void *ptr); int (*hdmi_hdcp_reauthenticate)(void *input); int (*hdmi_hdcp_authenticate)(void *hdcp_ctrl); + bool (*feature_supported)(void *input); void (*hdmi_hdcp_off)(void *hdcp_ctrl); }; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c index ca7f7c082da9..060adcf5d319 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c @@ -554,6 +554,29 @@ static int hdcp2p2_isr(void *input) return 0; } +static bool hdcp2p2_feature_supported(void *input) +{ + struct hdcp2p2_ctrl *hdcp2p2_ctrl = input; + struct hdcp_txmtr_ops *lib = NULL; + bool supported = false; + + if (!hdcp2p2_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + goto end; + } + + lib = hdcp2p2_ctrl->txmtr_ops; + if (!lib) { + DEV_ERR("%s: invalid lib ops data\n", __func__); + goto end; + } + + if (lib->feature_supported) + supported = lib->feature_supported( + hdcp2p2_ctrl->hdcp_lib_handle); +end: + return supported; +} static void hdcp2p2_reset(struct hdcp2p2_ctrl *hdcp2p2_ctrl) { @@ -781,6 +804,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) .hdmi_hdcp_isr = hdcp2p2_isr, .hdmi_hdcp_reauthenticate = hdcp2p2_reauthenticate, .hdmi_hdcp_authenticate = hdcp2p2_authenticate, + .feature_supported = hdcp2p2_feature_supported, .hdmi_hdcp_off = hdcp2p2_off }; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index ae004c5042bb..c6dced49ef04 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -1600,6 +1600,36 @@ error: return status; } /* hdmi_tx_read_sink_info */ +static void hdmi_tx_update_hdcp_info(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + void *fd = NULL; + struct hdmi_hdcp_ops *ops = NULL; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + /* check first if hdcp2p2 is supported */ + fd = hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]; + if (fd) + ops = hdmi_hdcp2p2_start(fd); + + if (ops && ops->feature_supported) + hdmi_ctrl->hdcp22_present = ops->feature_supported(fd); + else + hdmi_ctrl->hdcp22_present = false; + + if (!hdmi_ctrl->hdcp22_present && hdmi_ctrl->hdcp14_present) { + fd = hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]; + ops = hdmi_hdcp_start(fd); + } + + /* update internal data about hdcp */ + hdmi_ctrl->hdcp_feature_data = fd; + hdmi_ctrl->hdcp_ops = ops; +} + static void hdmi_tx_hpd_int_work(struct work_struct *work) { struct hdmi_tx_ctrl *hdmi_ctrl = NULL; @@ -1629,26 +1659,7 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false)) DEV_ERR("%s: Failed to disable ddc power\n", __func__); - /* Figure out HDCP capabilities of sink */ - hdmi_ctrl->hdcp_ops = NULL; - hdmi_ctrl->hdcp_feature_data = - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP2P2]; - if (hdmi_ctrl->hdcp_feature_data) - hdmi_ctrl->hdcp_ops = - hdmi_hdcp2p2_start( - hdmi_ctrl->hdcp_feature_data); - - if (hdmi_ctrl->hdcp_ops) - hdmi_ctrl->hdcp22_present = true; - else - hdmi_ctrl->hdcp22_present = false; - - if (!hdmi_ctrl->hdcp22_present && hdmi_ctrl->hdcp14_present) { - hdmi_ctrl->hdcp_feature_data = - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]; - hdmi_ctrl->hdcp_ops = - hdmi_hdcp_start(hdmi_ctrl->hdcp_feature_data); - } + hdmi_tx_update_hdcp_info(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, true); } else { diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h index a8f50dc1d90c..0a31b66e6a72 100644 --- a/include/linux/hdcp_qseecom.h +++ b/include/linux/hdcp_qseecom.h @@ -17,6 +17,7 @@ struct hdcp_txmtr_ops { int (*start)(void *phdcpcontext); int (*stop)(void *phdcpcontext); + bool (*feature_supported)(void *phdcpcontext); int (*process_message)(void *phdcpcontext, unsigned char *msg, uint32_t msg_size);