summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAjay Singh Parmar <aparmar@codeaurora.org>2015-10-06 00:00:15 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:46:28 -0700
commitc5cda87b7686647b10e94c4e7dd1509f739a8031 (patch)
treec45365d1e8ec43c2f1124dde1894e7ae1ec9043b
parent005782911808488b436b05d8dac1b9bcdf2f4643 (diff)
msm: mdss: hdmi: link integrity check
Add support to check link status within every second as per hdcp 2.2 standard. Check for re-authentication required bit in rxstatus. In case sink has indicated authentication needs to be teared down and restart, close HDCP lib authentication session and inform hdmi tx driver to re-authenticate. Change-Id: I61023d069c88e8ef060683ab369af6bf44bb2972 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c94
1 files changed, 90 insertions, 4 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
index 5566185c1908..c2d6f8fd85df 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
@@ -34,6 +34,8 @@
#define HDCP_SINK_DDC_HDCP2_RXSTATUS 0x70 /* RxStatus, 2 bytes */
#define HDCP_SINK_DDC_HDCP2_READ_MESSAGE 0x80 /* HDCP Tx reads here */
+#define HDCP2P2_LINK_CHECK_TIME_MS 500 /* link check within 1 sec */
+
/*
* HDCP 2.2 encryption requires the data encryption block that is present in
* HDMI controller version 4.0.0 and above
@@ -67,6 +69,9 @@ struct hdmi_hdcp2p2_ctrl {
struct kthread_work auth;
struct kthread_work send_msg;
struct kthread_work recv_msg;
+ struct kthread_work link;
+
+ struct delayed_work link_check_work;
};
static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
@@ -301,8 +306,7 @@ static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl)
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
/* notify hdmi tx about HDCP failure */
- ctrl->init_data.notify_status(
- ctrl->init_data.cb_data,
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data,
HDCP_STATE_AUTH_FAIL);
}
@@ -596,12 +600,90 @@ static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work)
DSS_REG_W(ctrl->init_data.core_io,
HDMI_HDCP_INT_CTRL2, regval);
- ctrl->init_data.notify_status(
- ctrl->init_data.cb_data,
+ ctrl->init_data.notify_status(ctrl->init_data.cb_data,
HDCP_STATE_AUTHENTICATED);
+
+ /* recheck within 1sec as per hdcp 2.2 standard */
+ schedule_delayed_work(&ctrl->link_check_work,
+ msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS));
+ }
+exit:
+ mutex_unlock(&ctrl->mutex);
+}
+
+static void hdmi_hdcp2p2_link_schedule_work(struct work_struct *work)
+{
+ struct hdmi_hdcp2p2_ctrl *ctrl = container_of(to_delayed_work(work),
+ struct hdmi_hdcp2p2_ctrl, link_check_work);
+
+ if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
+ queue_kthread_work(&ctrl->worker, &ctrl->link);
+}
+
+static void hdmi_hdcp2p2_link_work(struct kthread_work *work)
+{
+ int rc = 0;
+ struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work,
+ struct hdmi_hdcp2p2_ctrl, link);
+ struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_STOP};
+ struct hdmi_tx_ddc_ctrl *ddc_ctrl;
+ struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
+ u64 mult;
+ struct msm_hdmi_mode_timing_info *timing;
+
+ if (!ctrl) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ mutex_lock(&ctrl->mutex);
+
+ cdata.context = ctrl->lib_ctx;
+
+ ddc_ctrl = ctrl->init_data.ddc_ctrl;
+ if (!ddc_ctrl) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ hdmi_ddc_config(ddc_ctrl);
+
+ ddc_data = &ddc_ctrl->hdcp2p2_ddc_data;
+
+ memset(ddc_data, 0, sizeof(*ddc_data));
+
+ timing = ctrl->init_data.timing;
+ mult = hdmi_tx_get_v_total(timing) / 20;
+ ddc_data->intr_mask = RXSTATUS_REAUTH_REQ;
+ ddc_data->timer_delay_lines = (u32)mult;
+ ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;
+
+ rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl);
+ if (rc) {
+ pr_err("error reading rxstatus %d\n", rc);
+ goto exit;
+ }
+
+ if (ddc_data->reauth_req) {
+ pr_debug("sync reported loss of synchronization, reauth\n");
+ rc = -ENOLINK;
}
exit:
mutex_unlock(&ctrl->mutex);
+
+ if (rc) {
+ /* notify hdcp lib to stop auth */
+ hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata);
+
+ /* notify hdmi tx about auth failure */
+ hdmi_hdcp2p2_auth_failed(ctrl);
+
+ return;
+ }
+
+ /* recheck within 1sec as per hdcp 2.2 standard */
+ schedule_delayed_work(&ctrl->link_check_work,
+ msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS));
}
static void hdmi_hdcp2p2_auth_work(struct kthread_work *work)
@@ -720,10 +802,14 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
init_kthread_work(&ctrl->send_msg, hdmi_hdcp2p2_send_msg_work);
init_kthread_work(&ctrl->recv_msg, hdmi_hdcp2p2_recv_msg_work);
init_kthread_work(&ctrl->status, hdmi_hdcp2p2_auth_status_work);
+ init_kthread_work(&ctrl->link, hdmi_hdcp2p2_link_work);
ctrl->thread = kthread_run(kthread_worker_fn,
&ctrl->worker, "hdmi_hdcp2p2");
+ INIT_DELAYED_WORK(&ctrl->link_check_work,
+ hdmi_hdcp2p2_link_schedule_work);
+
if (IS_ERR(ctrl->thread)) {
pr_err("unable to start hdcp2p2 thread\n");
rc = PTR_ERR(ctrl->thread);