diff options
| author | Abhishek Kharbanda <akharban@codeaurora.org> | 2013-07-02 14:22:47 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:19:11 -0700 |
| commit | be44c0b29da82dc26e16865bd4320ec393524674 (patch) | |
| tree | 0c74fe50f9cef24004900e85c3dd52831d393526 | |
| parent | 07dbf677509ee30be403fee3cad21bc272f5aa3c (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.c | 48 |
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); |
