summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbhishek Kharbanda <akharban@codeaurora.org>2013-07-02 14:22:47 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:19:11 -0700
commitbe44c0b29da82dc26e16865bd4320ec393524674 (patch)
tree0c74fe50f9cef24004900e85c3dd52831d393526
parent07dbf677509ee30be403fee3cad21bc272f5aa3c (diff)
mdss: hdmi: Clear pending h/w DDC data before HDCP disable
Poll for HW DDC status to ensure no pending H/W DDC transactions before disabling HDCP engine. This is required to avoid corruption of internal state machine of HDCP hardware, which if happens, will lead to continous Ri's failures in Part 3 Authentication(when h/w DDC transaction take control again). Change-Id: Iab01599a40ff75d4021b426c723a759fb3230c81 CRs-Fixed: 484366 Signed-off-by: Abhishek Kharbanda <akharban@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_hdcp.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
index 1f0efd3c9fa3..1666b6643cd5 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
@@ -140,6 +140,48 @@ static void reset_hdcp_ddc_failures(struct hdmi_hdcp_ctrl *hdcp_ctrl)
__func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
} /* reset_hdcp_ddc_failures */
+static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ struct dss_io_data *io = NULL;
+ u32 hdcp_ddc_status, ddc_hw_status;
+ u32 ddc_xfer_done, ddc_xfer_req, ddc_hw_done;
+ u32 ddc_hw_not_ready;
+ u32 timeout_count;
+
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = hdcp_ctrl->init_data.core_io;
+ if (!io->base) {
+ DEV_ERR("%s: core io not inititalized\n", __func__);
+ return;
+ }
+
+ if (DSS_REG_R(io, HDMI_DDC_HW_STATUS) != 0) {
+ /* Wait to be clean on DDC HW engine */
+ timeout_count = 100;
+ do {
+ hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
+ ddc_hw_status = DSS_REG_R(io, HDMI_DDC_HW_STATUS);
+ ddc_xfer_done = (hdcp_ddc_status & BIT(10)) ;
+ ddc_xfer_req = (hdcp_ddc_status & BIT(4)) ;
+ ddc_hw_done = (ddc_hw_status & BIT(3)) ;
+ ddc_hw_not_ready = ((ddc_xfer_done != 1) ||
+ (ddc_xfer_req != 0) || (ddc_hw_done != 1));
+
+ DEV_DBG("%s: %s: timeout count(%d):ddc hw%sready\n",
+ __func__, HDCP_STATE_NAME, timeout_count,
+ ddc_hw_not_ready ? " not " : " ");
+ DEV_DBG("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n",
+ hdcp_ddc_status, ddc_hw_status);
+ if (ddc_hw_not_ready)
+ msleep(20);
+ } while (ddc_hw_not_ready && --timeout_count);
+ }
+} /* hdmi_hdcp_hw_ddc_clean */
+
static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
{
int rc;
@@ -969,6 +1011,9 @@ int hdmi_hdcp_reauthenticate(void *input)
DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+ /* Wait to be clean on DDC HW engine */
+ hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
+
/* Disable encryption and disable the HDCP block */
DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
@@ -1036,6 +1081,9 @@ void hdmi_hdcp_off(void *input)
DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
+ /* Wait to be clean on DDC HW engine */
+ hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
+
/* Disable encryption and disable the HDCP block */
DSS_REG_W(io, HDMI_HDCP_CTRL, 0);