summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAjay Singh Parmar <aparmar@codeaurora.org>2015-10-23 23:30:44 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:47:23 -0700
commit10ab09906bc032199d03783bab6b8997689effc6 (patch)
treea2886e7459b05d16cd8bb6a526c7ff8d632498f9
parenta5d905591a3de595fce17bf5845c2411c8ba3fc2 (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.c51
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.c44
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);