diff options
| author | Ajay Singh Parmar <aparmar@codeaurora.org> | 2015-10-23 23:30:44 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:47:23 -0700 |
| commit | 10ab09906bc032199d03783bab6b8997689effc6 (patch) | |
| tree | a2886e7459b05d16cd8bb6a526c7ff8d632498f9 | |
| parent | a5d905591a3de595fce17bf5845c2411c8ba3fc2 (diff) | |
msm: mdss: hdmi: proper ddc interrupt handling
Enable both software and hardware interrupts for DDC to
properly check for DDC engine being idle before any new
DDC transaction.
Change-Id: Iaab95483954e76397620a9f708982de060318d8a
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_hdcp.c | 51 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.c | 44 |
2 files changed, 61 insertions, 34 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c index c9bc0fee2bf5..2a09dcc612ef 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c @@ -167,8 +167,9 @@ 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 ddc_xfer_done, ddc_xfer_req; + u32 ddc_hw_req, ddc_hw_not_idle; + bool ddc_hw_not_ready, xfer_not_done, hw_not_done; u32 timeout_count; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { @@ -182,27 +183,33 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl) 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 || - ddc_xfer_req || !ddc_hw_done; + /* Wait to be clean on DDC HW engine */ + timeout_count = 100; + do { + hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS); + ddc_xfer_req = hdcp_ddc_status & BIT(4); + ddc_xfer_done = hdcp_ddc_status & BIT(10); - 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); - } + ddc_hw_status = DSS_REG_R(io, HDMI_DDC_HW_STATUS); + ddc_hw_req = ddc_hw_status & BIT(16); + ddc_hw_not_idle = ddc_hw_status & (BIT(0) | BIT(1)); + + /* ddc transfer was requested but not completed */ + xfer_not_done = ddc_xfer_req && !ddc_xfer_done; + + /* ddc status is not idle or a hw request pending */ + hw_not_done = ddc_hw_not_idle || ddc_hw_req; + + ddc_hw_not_ready = xfer_not_done || hw_not_done; + + 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 hdcp_scm_call(struct scm_hdcp_req *req, u32 *resp) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index 6012a0740f24..a799cd84b39c 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -502,24 +502,38 @@ static void hdmi_ddc_print_data(struct hdmi_tx_ddc_data *ddc_data) static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl, char *what) { - u32 reg_val, time_out_count; + u32 ddc_int_ctrl, ddc_status, in_use, timeout; + u32 sw_done_mask = BIT(2); + u32 sw_done_ack = BIT(1); + u32 hw_done_mask = BIT(6); + u32 hw_done_ack = BIT(5); + u32 in_use_by_sw = BIT(0); + u32 in_use_by_hw = BIT(1); if (!ddc_ctrl || !ddc_ctrl->io) { pr_err("invalid input\n"); return -EINVAL; } - /* clear pending and enable interrupt */ - time_out_count = 0xFFFF; + /* wait until DDC HW is free */ + timeout = 100; do { - --time_out_count; - /* Clear and Enable DDC interrupt */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, - BIT(2) | BIT(1)); - reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL); - } while ((reg_val & BIT(0)) && time_out_count); + --timeout; + ddc_status = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_HW_STATUS); + in_use = ddc_status & (in_use_by_sw | in_use_by_hw); + if (in_use) { + pr_debug("ddc is in use by %s\n", + ddc_status & in_use_by_sw ? "sw" : "hw"); + msleep(20); + } + } while (in_use && timeout); - if (!time_out_count) { + /* clear and enable interrutps */ + ddc_int_ctrl = sw_done_mask | sw_done_ack | hw_done_mask | hw_done_ack; + + DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, ddc_int_ctrl); + + if (!timeout) { pr_err("%s: timedout\n", what); return -ETIMEDOUT; } @@ -877,12 +891,18 @@ int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl, u32 version) ddc_int_ctrl = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL); if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) { - /* SW_DONE INT occured, clr it */ + /* SW_DONE INT occurred, clr it */ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, ddc_int_ctrl | BIT(1)); complete(&ddc_ctrl->ddc_sw_done); } + if ((ddc_int_ctrl & BIT(6)) && (ddc_int_ctrl & BIT(4))) { + /* HW_DONE INT occurred, clr it */ + DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, + ddc_int_ctrl | BIT(5)); + } + pr_debug("ddc_int_ctrl=%04x\n", ddc_int_ctrl); if (version < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) goto end; @@ -1699,7 +1719,7 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl) rc = -EIO; } - DSS_REG_W(ctrl->io, HDMI_HW_DDC_CTRL, reg_val); + DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_STATUS, reg_val); /* Disable hardware access to RxStatus register */ hdmi_hdcp2p2_ddc_disable(ctrl); |
