diff options
| author | Ajay Singh Parmar <aparmar@codeaurora.org> | 2015-11-13 18:22:20 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:14:08 -0700 |
| commit | d27317a651a8c16402cbbdfebe4dee33b786afb5 (patch) | |
| tree | 77a9190e2329d2606c8956b80ccd2440853873f5 /drivers/video/fbdev | |
| parent | 58ee64bfb78183841604c2b7d95d158543fc51bd (diff) | |
msm: mdss: hdmi: clear ddc line before starting hdcp
Clear DDC line if scrambling and Rx status polling is still
going on. Check for all scrambling and Rx status errors and
stop polling in error cases. This needs to be done before
new hdcp authentication session is started to avoid any
authentication failures because of ddc line being busy.
Change-Id: I90957410172ca206d435a5549d689ada222f84db
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_hdcp.c | 9 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.c | 938 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.h | 7 |
5 files changed, 416 insertions, 547 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c index 2a09dcc612ef..8ac193cfed1f 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c @@ -372,7 +372,6 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) ddc_data.request_len = 1; ddc_data.retry = 5; ddc_data.what = "Bcaps"; - ddc_data.no_align = true; hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; @@ -574,7 +573,6 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) ddc_data.request_len = 5; ddc_data.retry = 5; ddc_data.what = "Bksv"; - ddc_data.no_align = true; hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; @@ -649,7 +647,6 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) ddc_data.request_len = 2; ddc_data.retry = 5; ddc_data.what = "R0'"; - ddc_data.no_align = true; hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; @@ -758,7 +755,6 @@ static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl) ddc_data.request_len = 4; ddc_data.retry = 5; ddc_data.what = what; - ddc_data.no_align = true; if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); @@ -888,7 +884,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) ddc_data.request_len = 1; ddc_data.retry = 5; ddc_data.what = "Bcaps"; - ddc_data.no_align = false; + ddc_data.retry_align = true; hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; @@ -910,7 +906,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) ddc_data.request_len = 2; ddc_data.retry = 5; ddc_data.what = "Bstatuss"; - ddc_data.no_align = false; + ddc_data.retry_align = true; hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; @@ -1005,7 +1001,6 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) ddc_data.request_len = ksv_bytes; ddc_data.retry = 5; ddc_data.what = "KSV FIFO"; - ddc_data.no_align = true; hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c index 4ec9c788efc7..8607d95c2fa6 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c @@ -233,6 +233,10 @@ static int hdmi_hdcp2p2_authenticate(void *input) ctrl->sink_status = SINK_CONNECTED; atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING); + /* make sure ddc is idle before starting hdcp 2.2 authentication */ + hdmi_scrambler_ddc_disable(ctrl->init_data.ddc_ctrl); + hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl); + cdata.context = input; hdmi_hdcp2p2_wakeup(&cdata); @@ -431,7 +435,6 @@ static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl, ddc_data.offset = HDCP_SINK_DDC_HDCP2_WRITE_MESSAGE; ddc_data.data_buf = buf; ddc_data.data_len = size; - ddc_data.retry = 1; ddc_data.hard_timeout = ctrl->timeout; ddc_data.what = "HDCP2WriteMessage"; @@ -800,7 +803,7 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) goto exit; } - rc = hdmi_ddc_check_status(ddc_ctrl); + rc = hdmi_hdcp2p2_ddc_check_status(ddc_ctrl); if (rc) { cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; goto exit; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index e0e4035baeb6..a88648bad161 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -1435,7 +1435,7 @@ static u32 hdmi_tx_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl, ddc_data.request_len = block_size; ddc_data.retry = 1; ddc_data.what = "EDID"; - ddc_data.no_align = false; + ddc_data.retry_align = true; ddc_ctrl->ddc_data = ddc_data; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index 41311784932b..d957f75e9609 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -28,6 +28,11 @@ static char res_buf[RESOLUTION_NAME_STR_LEN]; +enum trigger_mode { + TRIGGER_WRITE, + TRIGGER_READ +}; + int hdmi_utils_get_timeout_in_hysnc(struct msm_hdmi_mode_timing_info *timing, u32 timeout_ms) { @@ -96,15 +101,98 @@ static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl, return 0; } -static void hdmi_scrambler_status_timer_setup(struct hdmi_tx_ddc_ctrl *ctrl, +static void hdmi_scrambler_ddc_reset(struct hdmi_tx_ddc_ctrl *ctrl) +{ + u32 reg_val; + + if (!ctrl) { + pr_err("Invalid parameters\n"); + return; + } + + /* clear ack and disable interrupts */ + reg_val = BIT(14) | BIT(9) | BIT(5) | BIT(1); + DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL2, reg_val); + + /* Reset DDC timers */ + reg_val = BIT(0) | DSS_REG_R(ctrl->io, HDMI_SCRAMBLER_STATUS_DDC_CTRL); + DSS_REG_W(ctrl->io, HDMI_SCRAMBLER_STATUS_DDC_CTRL, reg_val); + + reg_val = DSS_REG_R(ctrl->io, HDMI_SCRAMBLER_STATUS_DDC_CTRL); + reg_val &= ~BIT(0); + DSS_REG_W(ctrl->io, HDMI_SCRAMBLER_STATUS_DDC_CTRL, reg_val); +} + +void hdmi_scrambler_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl) +{ + u32 reg_val; + + if (!ctrl) { + pr_err("Invalid parameters\n"); + return; + } + + hdmi_scrambler_ddc_reset(ctrl); + + /* Disable HW DDC access to RxStatus register */ + reg_val = DSS_REG_R(ctrl->io, HDMI_HW_DDC_CTRL); + reg_val &= ~(BIT(8) | BIT(9)); + + DSS_REG_W(ctrl->io, HDMI_HW_DDC_CTRL, reg_val); +} + +static int hdmi_scrambler_ddc_check_status(struct hdmi_tx_ddc_ctrl *ctrl) +{ + int rc = 0; + u32 reg_val; + + if (!ctrl) { + pr_err("invalid ddc ctrl\n"); + return -EINVAL; + } + + /* check for errors and clear status */ + reg_val = DSS_REG_R(ctrl->io, HDMI_SCRAMBLER_STATUS_DDC_STATUS); + + if (reg_val & BIT(4)) { + pr_err("ddc aborted\n"); + reg_val |= BIT(5); + rc = -ECONNABORTED; + } + + if (reg_val & BIT(8)) { + pr_err("timed out\n"); + reg_val |= BIT(9); + rc = -ETIMEDOUT; + } + + if (reg_val & BIT(12)) { + pr_err("NACK0\n"); + reg_val |= BIT(13); + rc = -EIO; + } + + if (reg_val & BIT(14)) { + pr_err("NACK1\n"); + reg_val |= BIT(15); + rc = -EIO; + } + + DSS_REG_W(ctrl->io, HDMI_SCRAMBLER_STATUS_DDC_STATUS, reg_val); + + return rc; +} + +static int hdmi_scrambler_status_timer_setup(struct hdmi_tx_ddc_ctrl *ctrl, u32 timeout_hsync) { u32 reg_val; + int rc; struct dss_io_data *io = NULL; if (!ctrl || !ctrl->io) { pr_err("invalid input\n"); - return; + return -EINVAL; } io = ctrl->io; @@ -131,6 +219,18 @@ static void hdmi_scrambler_status_timer_setup(struct hdmi_tx_ddc_ctrl *ctrl, reg_val &= ~(BIT(8) | BIT(9)); reg_val |= BIT(8); DSS_REG_W(io, HDMI_HW_DDC_CTRL, reg_val); + + /* WAIT for 200ms as per HDMI 2.0 standard for sink to respond */ + msleep(200); + + /* clear the scrambler status */ + rc = hdmi_scrambler_ddc_check_status(ctrl); + if (rc) + pr_err("scrambling ddc error %d\n", rc); + + hdmi_scrambler_ddc_disable(ctrl); + + return rc; } static inline char *hdmi_scdc_reg2string(u32 type) @@ -565,27 +665,98 @@ ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size) return len; } /* hdmi_get_video_3d_fmt_2string */ -static void hdmi_ddc_print_data(struct hdmi_tx_ddc_data *ddc_data) +static void hdmi_ddc_trigger(struct hdmi_tx_ddc_ctrl *ddc_ctrl, + enum trigger_mode mode, bool seg) { - if (!ddc_data) { - pr_err("invalid input\n"); - return; + struct hdmi_tx_ddc_data *ddc_data = &ddc_ctrl->ddc_data; + struct dss_io_data *io = ddc_ctrl->io; + u32 const seg_addr = 0x60, seg_num = 0x01; + u32 ddc_ctrl_reg_val; + + ddc_data->dev_addr &= 0xFE; + + if (mode == TRIGGER_READ && seg) { + DSS_REG_W_ND(io, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8)); + DSS_REG_W_ND(io, HDMI_DDC_DATA, seg_num << 8); + } + + /* handle portion #1 */ + DSS_REG_W_ND(io, HDMI_DDC_DATA, BIT(31) | (ddc_data->dev_addr << 8)); + + /* handle portion #2 */ + DSS_REG_W_ND(io, HDMI_DDC_DATA, ddc_data->offset << 8); + + if (mode == TRIGGER_READ) { + /* handle portion #3 */ + DSS_REG_W_ND(io, HDMI_DDC_DATA, + (ddc_data->dev_addr | BIT(0)) << 8); + + /* HDMI_I2C_TRANSACTION0 */ + DSS_REG_W_ND(io, HDMI_DDC_TRANS0, BIT(12) | BIT(16)); + + /* Write to HDMI_I2C_TRANSACTION1 */ + if (seg) { + DSS_REG_W_ND(io, HDMI_DDC_TRANS1, BIT(12) | BIT(16)); + DSS_REG_W_ND(io, HDMI_DDC_TRANS2, + BIT(0) | BIT(12) | BIT(13) | + (ddc_data->request_len << 16)); + + ddc_ctrl_reg_val = BIT(0) | BIT(21); + } else { + DSS_REG_W_ND(io, HDMI_DDC_TRANS1, + BIT(0) | BIT(12) | BIT(13) | + (ddc_data->request_len << 16)); + + ddc_ctrl_reg_val = BIT(0) | BIT(20); + } + } else { + int ndx; + + /* write buffer */ + for (ndx = 0; ndx < ddc_data->data_len; ++ndx) + DSS_REG_W_ND(io, HDMI_DDC_DATA, + ((u32)ddc_data->data_buf[ndx]) << 8); + + DSS_REG_W_ND(io, HDMI_DDC_TRANS0, + (ddc_data->data_len + 1) << 16 | BIT(12) | BIT(13)); + + ddc_ctrl_reg_val = BIT(0); } - pr_debug("what: %s, buf=%p, d_len=0x%x, d_addr=0x%x, no_align=%d\n", - ddc_data->what, ddc_data->data_buf, ddc_data->data_len, - ddc_data->dev_addr, ddc_data->no_align); - pr_debug("what: %s, offset=0x%x, req_len=0x%x, retry=%d, what=%s\n", - ddc_data->what, ddc_data->offset, ddc_data->request_len, - ddc_data->retry, ddc_data->what); -} /* hdmi_ddc_print_data */ + /* Trigger the I2C transfer */ + DSS_REG_W_ND(io, HDMI_DDC_CTRL, ddc_ctrl_reg_val); +} + +static int hdmi_ddc_check_status(struct hdmi_tx_ddc_ctrl *ddc_ctrl) +{ + u32 reg_val; + int rc = 0; + + /* Read DDC status */ + reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS); + reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15); + + /* Check if any NACK occurred */ + if (reg_val) { + pr_debug("%s: NACK: HDMI_DDC_SW_STATUS 0x%x\n", + ddc_ctrl->ddc_data.what, reg_val); + + /* SW_STATUS_RESET, SOFT_RESET */ + reg_val = BIT(3) | BIT(1); + + DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, reg_val); + + rc = -ECOMM; + } + + return rc; +} static int hdmi_ddc_read_retry(struct hdmi_tx_ddc_ctrl *ddc_ctrl) { u32 reg_val, ndx, time_out_count, wait_time; struct hdmi_tx_ddc_data *ddc_data; - int status = 0; - int log_retry_fail; + int status, rc; int busy_wait_us; if (!ddc_ctrl || !ddc_ctrl->io) { @@ -601,175 +772,69 @@ static int hdmi_ddc_read_retry(struct hdmi_tx_ddc_ctrl *ddc_ctrl) goto error; } - hdmi_ddc_print_data(ddc_data); - - log_retry_fail = ddc_data->retry != 1; -again: - status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what); - if (status) + if (ddc_data->retry < 0) { + pr_err("invalid no. of retries %d\n", ddc_data->retry); + status = -EINVAL; goto error; + } - /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */ - ddc_data->dev_addr &= 0xFE; - - /* - * 1. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #1 - * DATA_RW = 0x0 (write) - * DATA = linkAddress (primary link address and writing) - * INDEX = 0x0 (initial offset into buffer) - * INDEX_WRITE = 0x1 (setting initial offset) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, - BIT(31) | (ddc_data->dev_addr << 8)); - - /* - * 2. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #2 - * DATA_RW = 0x0 (write) - * DATA = offsetAddress - * INDEX = 0x0 - * INDEX_WRITE = 0x0 (auto-increment by hardware) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8); - - /* - * 3. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #3 - * DATA_RW = 0x0 (write) - * DATA = linkAddress + 1 (primary link address 0x74 and reading) - * INDEX = 0x0 - * INDEX_WRITE = 0x0 (auto-increment by hardware) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, - (ddc_data->dev_addr | BIT(0)) << 8); - - /* Data setup is complete, now setup the transaction characteristics */ - - /* - * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in - * order to handle characteristics of portion #1 and portion #2 - * RW0 = 0x0 (write) - * START0 = 0x1 (insert START bit) - * STOP0 = 0x0 (do NOT insert STOP bit) - * CNT0 = 0x1 (single byte transaction excluding address) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16)); - - /* - * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in - * order to handle characteristics of portion #3 - * RW1 = 0x1 (read) - * START1 = 0x1 (insert START bit) - * STOP1 = 0x1 (insert STOP bit) - * CNT1 = data_len (it's 128 (0x80) for a blk read) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1, - BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16)); + do { + status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what); + if (status) + continue; - if (ddc_data->hard_timeout) { - pr_debug("using hard_timeout %dms\n", ddc_data->hard_timeout); + if (ddc_data->hard_timeout) { + pr_debug("using hard_timeout %dms\n", + ddc_data->hard_timeout); - busy_wait_us = ddc_data->hard_timeout * HDMI_MS_TO_US; - atomic_set(&ddc_ctrl->read_busy_wait_done, 0); - } else { - reinit_completion(&ddc_ctrl->ddc_sw_done); - wait_time = HZ / 2; - } + busy_wait_us = ddc_data->hard_timeout * HDMI_MS_TO_US; + atomic_set(&ddc_ctrl->read_busy_wait_done, 0); + } else { + reinit_completion(&ddc_ctrl->ddc_sw_done); + wait_time = HZ / 2; + } - /* Trigger the I2C transfer */ + hdmi_ddc_trigger(ddc_ctrl, TRIGGER_READ, false); - /* - * 6. Write to HDMI_I2C_CONTROL to kick off the hardware. - * Note that NOTHING has been transmitted on the DDC lines up to this - * point. - * TRANSACTION_CNT = 0x1 (execute transaction0 followed by - * transaction1) - * SEND_RESET = Set to 1 to send reset sequence - * GO = 0x1 (kicks off hardware) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20)); + if (ddc_data->hard_timeout) { + while (busy_wait_us > 0 && + !atomic_read(&ddc_ctrl->read_busy_wait_done)) { + udelay(HDMI_BUSY_WAIT_DELAY_US); + busy_wait_us -= HDMI_BUSY_WAIT_DELAY_US; + }; - if (ddc_data->hard_timeout) { - while (busy_wait_us > 0 && - !atomic_read(&ddc_ctrl->read_busy_wait_done)) { - udelay(HDMI_BUSY_WAIT_DELAY_US); - busy_wait_us -= HDMI_BUSY_WAIT_DELAY_US; - }; + if (busy_wait_us < 0) + busy_wait_us = 0; - if (busy_wait_us < 0) - busy_wait_us = 0; + time_out_count = busy_wait_us / HDMI_MS_TO_US; - time_out_count = busy_wait_us / HDMI_MS_TO_US; - - ddc_data->timeout_left = time_out_count; - } else { - time_out_count = wait_for_completion_timeout( - &ddc_ctrl->ddc_sw_done, wait_time); + ddc_data->timeout_left = time_out_count; + } else { + time_out_count = wait_for_completion_timeout( + &ddc_ctrl->ddc_sw_done, wait_time); - ddc_data->timeout_left = jiffies_to_msecs(time_out_count); - } + ddc_data->timeout_left = + jiffies_to_msecs(time_out_count); + } - pr_debug("ddc read done at %dms\n", jiffies_to_msecs(jiffies)); + pr_debug("ddc read done at %dms\n", jiffies_to_msecs(jiffies)); - if (!time_out_count) { - if (ddc_data->retry-- > 0) { - pr_debug("failed timout, retry=%d\n", ddc_data->retry); + if (!time_out_count) { + pr_debug("%s: timedout\n", ddc_data->what); - if (!ddc_data->hard_timeout) - goto again; + status = -ETIMEDOUT; } - status = -ETIMEDOUT; - pr_err("timedout(7), Int Ctrl=%08x\n", - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL)); - pr_err("DDC SW Status=%08x, HW Status=%08x\n", - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS), - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS)); - goto error; - } - /* Read DDC status */ - reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS); - reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15); + rc = hdmi_ddc_check_status(ddc_ctrl); - /* Check if any NACK occurred */ - if (reg_val) { - /* SW_STATUS_RESET */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3)); - - if (ddc_data->retry == 1) - /* SOFT_RESET */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1)); - - if (ddc_data->retry-- > 0) { - pr_debug("%s: failed NACK=0x%08x, retry=%d\n", - ddc_data->what, reg_val, - ddc_data->retry); - pr_debug("daddr=0x%02x,off=0x%02x,len=%d\n", - ddc_data->dev_addr, - ddc_data->offset, ddc_data->data_len); - goto again; - } - status = -EIO; - if (log_retry_fail) { - pr_err("%s: failed NACK=0x%08x\n", - ddc_data->what, reg_val); - pr_err("daddr=0x%02x,off=0x%02x,len=%d\n", - ddc_data->dev_addr, - ddc_data->offset, ddc_data->data_len); - } + if (!status) + status = rc; + } while (status && ddc_data->retry--); + + if (status) goto error; - } - /* - * 8. ALL data is now available and waiting in the DDC buffer. - * Read HDMI_I2C_DATA with the following fields set - * RW = 0x1 (read) - * DATA = BCAPS (this is field where data is pulled from) - * INDEX = 0x3 (where the data has been placed in buffer by hardware) - * INDEX_WRITE = 0x1 (explicitly define offset) - */ - /* Write this data to DDC buffer */ + /* Write data to DDC buffer */ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, BIT(0) | (3 << 16) | BIT(31)); @@ -806,7 +871,7 @@ void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *ddc_ctrl) DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_REF, (1 << 16) | (19 << 0)); } /* hdmi_ddc_config */ -int hdmi_ddc_check_status(struct hdmi_tx_ddc_ctrl *ctrl) +int hdmi_hdcp2p2_ddc_check_status(struct hdmi_tx_ddc_ctrl *ctrl) { int rc = 0; u32 reg_val; @@ -852,7 +917,8 @@ static int hdmi_ddc_hdcp2p2_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl) { struct dss_io_data *io = NULL; struct hdmi_tx_hdcp2p2_ddc_data *data; - u32 intr0, intr2; + u32 intr0, intr2, intr5; + u32 msg_size; if (!ddc_ctrl || !ddc_ctrl->io) { pr_err("invalid input\n"); @@ -863,112 +929,118 @@ static int hdmi_ddc_hdcp2p2_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl) data = &ddc_ctrl->hdcp2p2_ddc_data; - intr2 = DSS_REG_R(io, HDMI_HDCP_INT_CTRL2); intr0 = DSS_REG_R(io, HDMI_DDC_INT_CTRL0); + intr2 = DSS_REG_R(io, HDMI_HDCP_INT_CTRL2); + intr5 = DSS_REG_R_ND(io, HDMI_DDC_INT_CTRL5); - pr_debug("intr0: 0x%x, intr2: 0x%x\n", intr0, intr2); - - /* check for encryption ready interrupt */ - if (intr2 & BIT(2)) { - /* check if encryption is enabled */ - if (intr2 & BIT(0)) { - /* - * ack encryption ready interrupt. - * disable encryption ready interrupt. - * enable encryption not ready interrupt. - */ - intr2 &= ~BIT(2); - intr2 |= BIT(1) | BIT(6); - - pr_debug("HDCP 2.2 Encryption enabled\n"); - data->encryption_ready = true; - } + pr_debug("intr0: 0x%x, intr2: 0x%x, intr5: 0x%x\n", + intr0, intr2, intr5); + + /* check if encryption is enabled */ + if (intr2 & BIT(0)) { + /* + * ack encryption ready interrupt. + * disable encryption ready interrupt. + * enable encryption not ready interrupt. + */ + intr2 &= ~BIT(2); + intr2 |= BIT(1) | BIT(6); + + pr_debug("HDCP 2.2 Encryption enabled\n"); + data->encryption_ready = true; } - /* check for encryption not ready interrupt */ - if (intr2 & BIT(6)) { - /* check if encryption is disabled */ - if (intr2 & BIT(4)) { - /* - * ack encryption not ready interrupt. - * disable encryption not ready interrupt. - * enable encryption ready interrupt. - */ - intr2 |= BIT(5) | BIT(2); - intr2 &= ~BIT(6); - - pr_debug("HDCP 2.2 Encryption disabled\n"); - data->encryption_ready = false; - } + /* check if encryption is disabled */ + if (intr2 & BIT(4)) { + /* + * ack encryption not ready interrupt. + * disable encryption not ready interrupt. + * enable encryption ready interrupt. + */ + intr2 &= ~BIT(6); + intr2 |= BIT(5) | BIT(2); + + pr_debug("HDCP 2.2 Encryption disabled\n"); + data->encryption_ready = false; } DSS_REG_W_ND(io, HDMI_HDCP_INT_CTRL2, intr2); - /* check for message size interrupt */ - if (intr0 & BIT(31)) { - /* get the message size bits 29:20 */ - data->message_size = (intr0 & (0x3FF << 20)) >> 20; + /* get the message size bits 29:20 */ + msg_size = (intr0 & (0x3FF << 20)) >> 20; - if (data->message_size) { - /* ack and disable message size interrupt */ - intr0 |= BIT(30); - intr0 &= ~BIT(31); - } + if (msg_size) { + /* ack and disable message size interrupt */ + intr0 |= BIT(30); + intr0 &= ~BIT(31); + + data->message_size = msg_size; } - /* check for ready/not ready interrupt */ - if (intr0 & (BIT(18) | BIT(19))) { - /* check and disable ready interrupt */ - if (intr0 & BIT(16)) { - intr0 &= ~BIT(18); - data->ready = true; - } + /* check and disable ready interrupt */ + if (intr0 & BIT(16)) { + /* ack ready/not ready interrupt */ + intr0 |= BIT(17); - /* check and disable not ready interrupt */ - if (intr0 & BIT(15)) { - intr0 &= ~BIT(19); - data->ready = false; - } + intr0 &= ~BIT(18); + data->ready = true; + } + /* check and disable not ready interrupt */ + if (intr0 & BIT(15)) { /* ack ready/not ready interrupt */ intr0 |= BIT(17); + + intr0 &= ~BIT(19); + data->ready = false; } /* check for reauth req interrupt */ - if (intr0 & BIT(14)) { + if (intr0 & BIT(12)) { /* ack and disable reauth req interrupt */ intr0 |= BIT(13); intr0 &= ~BIT(14); - data->reauth_req = (intr0 & BIT(12)) ? true : false; + data->reauth_req = true; } /* check for ddc fail interrupt */ - if (intr0 & BIT(10)) { + if (intr0 & BIT(8)) { /* ack ddc fail interrupt */ intr0 |= BIT(9); - data->ddc_max_retries_fail = (intr0 & BIT(8)) ? true : false; + data->ddc_max_retries_fail = true; } /* check for ddc done interrupt */ - if (intr0 & BIT(6)) { + if (intr0 & BIT(4)) { /* ack ddc done interrupt */ intr0 |= BIT(5); - data->ddc_done = (intr0 & BIT(4)) ? true : false; + data->ddc_done = true; } /* check for ddc read req interrupt */ - if (intr0 & BIT(2)) { + if (intr0 & BIT(0)) { /* ack read req interrupt */ intr0 |= BIT(1); - data->ddc_read_req = (intr0 & BIT(0)) ? true : false; + data->ddc_read_req = true; } DSS_REG_W_ND(io, HDMI_DDC_INT_CTRL0, intr0); + if (intr5 & BIT(0)) { + pr_err("RXSTATUS_DDC_REQ_TIMEOUT\n"); + + /* ack and disable timeout interrupt */ + intr5 |= BIT(1); + intr5 &= ~BIT(2); + + data->ddc_timeout = true; + } + DSS_REG_W_ND(io, HDMI_DDC_INT_CTRL5, intr5); + if (data->message_size || data->ready || data->reauth_req) atomic_set(&ddc_ctrl->rxstatus_busy_wait_done, 1); @@ -988,8 +1060,10 @@ static int hdmi_ddc_scrambling_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl) io = ddc_ctrl->io; - intr2 = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL2); - pr_debug("ddc_int_ctrl2=0x%x\n", intr2); + intr2 = DSS_REG_R_ND(io, HDMI_DDC_INT_CTRL2); + intr5 = DSS_REG_R_ND(io, HDMI_DDC_INT_CTRL5); + + pr_debug("intr2: 0x%x, intr5: 0x%x\n", intr2, intr5); if (intr2 & BIT(12)) { pr_err("SCRAMBLER_STATUS_NOT\n"); @@ -1008,24 +1082,18 @@ static int hdmi_ddc_scrambling_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl) } DSS_REG_W_ND(io, HDMI_DDC_INT_CTRL2, intr2); - intr5 = DSS_REG_R_ND(io, HDMI_DDC_INT_CTRL5); - pr_debug("ddc_int_ctrl5=0x%x\n", intr5); - if (intr5 & BIT(8)) { pr_err("SCRAMBLER_STATUS_DDC_REQ_TIMEOUT\n"); intr5 |= BIT(9); + intr5 &= ~BIT(10); scrambler_timer_off = true; } DSS_REG_W_ND(io, HDMI_DDC_INT_CTRL5, intr5); - if (scrambler_timer_off) { - u32 reg_val = DSS_REG_R_ND(io, HDMI_HW_DDC_CTRL); - - reg_val &= ~(BIT(8) | BIT(9)); - DSS_REG_W_ND(io, HDMI_HW_DDC_CTRL, reg_val); - } + if (scrambler_timer_off) + hdmi_scrambler_ddc_disable(ddc_ctrl); return 0; } @@ -1040,22 +1108,25 @@ 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); - pr_debug("ddc_int_ctrl=0x%x\n", ddc_int_ctrl); + pr_debug("intr: 0x%x\n", ddc_int_ctrl); - if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) { - pr_debug("ddc sw done\n"); + if (ddc_int_ctrl & BIT(0)) { + pr_debug("sw done\n"); ddc_int_ctrl |= BIT(1); - complete(&ddc_ctrl->ddc_sw_done); - - atomic_set(&ddc_ctrl->read_busy_wait_done, 1); - atomic_set(&ddc_ctrl->write_busy_wait_done, 1); + if (ddc_ctrl->ddc_data.hard_timeout) { + atomic_set(&ddc_ctrl->read_busy_wait_done, 1); + atomic_set(&ddc_ctrl->write_busy_wait_done, 1); + } else { + complete(&ddc_ctrl->ddc_sw_done); + } } - if ((ddc_int_ctrl & BIT(6)) && (ddc_int_ctrl & BIT(4))) { - pr_debug("ddc hw done\n"); + if (ddc_int_ctrl & BIT(4)) { + pr_debug("hw done\n"); ddc_int_ctrl |= BIT(5); } + DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, ddc_int_ctrl); if (version >= HDMI_TX_SCRAMBLER_MIN_TX_VERSION) { @@ -1074,6 +1145,7 @@ int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl, u32 version) int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl) { int rc = 0; + int retry; struct hdmi_tx_ddc_data *ddc_data; if (!ddc_ctrl) { @@ -1082,14 +1154,15 @@ int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl) } ddc_data = &ddc_ctrl->ddc_data; + retry = ddc_data->retry; rc = hdmi_ddc_read_retry(ddc_ctrl); if (!rc) return rc; - if (ddc_data->no_align) { - rc = hdmi_ddc_read_retry(ddc_ctrl); - } else { + if (ddc_data->retry_align) { + ddc_data->retry = retry; + ddc_data->request_len = 32 * ((ddc_data->data_len + 31) / 32); rc = hdmi_ddc_read_retry(ddc_ctrl); } @@ -1099,10 +1172,8 @@ int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl) int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *ddc_ctrl) { - int status = 0; + int status, rc; u32 reg_val, ndx, time_out_count; - int log_retry_fail; - int seg_addr = 0x60, seg_num = 0x01; struct hdmi_tx_ddc_data *ddc_data; if (!ddc_ctrl || !ddc_ctrl->io) { @@ -1118,152 +1189,40 @@ int hdmi_ddc_read_seg(struct hdmi_tx_ddc_ctrl *ddc_ctrl) goto error; } - log_retry_fail = ddc_data->retry != 1; - -again: - status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what); - if (status) + if (ddc_data->retry < 0) { + pr_err("invalid no. of retries %d\n", ddc_data->retry); + status = -EINVAL; goto error; + } - /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */ - ddc_data->dev_addr &= 0xFE; - - /* - * 1. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #1 - * DATA_RW = 0x0 (write) - * DATA = linkAddress (primary link address and writing) - * INDEX = 0x0 (initial offset into buffer) - * INDEX_WRITE = 0x1 (setting initial offset) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8)); - - /* - * 2. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #2 - * DATA_RW = 0x0 (write) - * DATA = offsetAddress - * INDEX = 0x0 - * INDEX_WRITE = 0x0 (auto-increment by hardware) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, seg_num << 8); - - /* - * 3. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #3 - * DATA_RW = 0x0 (write) - * DATA = linkAddress + 1 (primary link address 0x74 and reading) - * INDEX = 0x0 - * INDEX_WRITE = 0x0 (auto-increment by hardware) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->dev_addr << 8); - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8); - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, - (ddc_data->dev_addr | BIT(0)) << 8); - - /* Data setup is complete, now setup the transaction characteristics */ - - /* - * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in - * order to handle characteristics of portion #1 and portion #2 - * RW0 = 0x0 (write) - * START0 = 0x1 (insert START bit) - * STOP0 = 0x0 (do NOT insert STOP bit) - * CNT0 = 0x1 (single byte transaction excluding address) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16)); - - /* - * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in - * order to handle characteristics of portion #3 - * RW1 = 0x1 (read) - * START1 = 0x1 (insert START bit) - * STOP1 = 0x1 (insert STOP bit) - * CNT1 = data_len (it's 128 (0x80) for a blk read) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1, BIT(12) | BIT(16)); + do { + status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what); + if (status) + continue; - /* - * 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in - * order to handle characteristics of portion #3 - * RW1 = 0x1 (read) - * START1 = 0x1 (insert START bit) - * STOP1 = 0x1 (insert STOP bit) - * CNT1 = data_len (it's 128 (0x80) for a blk read) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS2, - BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16)); + reinit_completion(&ddc_ctrl->ddc_sw_done); - /* Trigger the I2C transfer */ + hdmi_ddc_trigger(ddc_ctrl, TRIGGER_READ, true); - /* - * 6. Write to HDMI_I2C_CONTROL to kick off the hardware. - * Note that NOTHING has been transmitted on the DDC lines up to this - * point. - * TRANSACTION_CNT = 0x2 (execute transaction0 followed by - * transaction1) - * GO = 0x1 (kicks off hardware) - */ - reinit_completion(&ddc_ctrl->ddc_sw_done); - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(21)); + time_out_count = wait_for_completion_timeout( + &ddc_ctrl->ddc_sw_done, HZ / 2); - time_out_count = wait_for_completion_timeout( - &ddc_ctrl->ddc_sw_done, HZ/2); + if (!time_out_count) { + pr_debug("%s: timedout\n", ddc_data->what); - if (!time_out_count) { - if (ddc_data->retry-- > 0) { - pr_debug("failed timout, retry=%d\n", ddc_data->retry); - goto again; + status = -ETIMEDOUT; } - status = -ETIMEDOUT; - pr_err("timedout(7), Int Ctrl=%08x\n", - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL)); - pr_err("DDC SW Status=%08x, HW Status=%08x\n", - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS), - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS)); - goto error; - } - /* Read DDC status */ - reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS); - reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15); + rc = hdmi_ddc_check_status(ddc_ctrl); - /* Check if any NACK occurred */ - if (reg_val) { - /* SW_STATUS_RESET */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3)); - if (ddc_data->retry == 1) - /* SOFT_RESET */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1)); - if (ddc_data->retry-- > 0) { - pr_debug("%s: failed NACK=0x%08x, retry=%d\n", - ddc_data->what, reg_val, - ddc_data->retry); - pr_debug("daddr=0x%02x,off=0x%02x,len=%d\n", - ddc_data->dev_addr, - ddc_data->offset, ddc_data->data_len); - goto again; - } - status = -EIO; - if (log_retry_fail) { - pr_err("%s: failed NACK=0x%08x\n", - ddc_data->what, reg_val); - pr_err("daddr=0x%02x,off=0x%02x,len=%d\n", - ddc_data->dev_addr, - ddc_data->offset, ddc_data->data_len); - } + if (!status) + status = rc; + } while (status && ddc_data->retry--); + + if (status) goto error; - } - /* - * 8. ALL data is now available and waiting in the DDC buffer. - * Read HDMI_I2C_DATA with the following fields set - * RW = 0x1 (read) - * DATA = BCAPS (this is field where data is pulled from) - * INDEX = 0x5 (where the data has been placed in buffer by hardware) - * INDEX_WRITE = 0x1 (explicitly define offset) - */ - /* Write this data to DDC buffer */ + /* Write data to DDC buffer */ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, BIT(0) | (5 << 16) | BIT(31)); @@ -1283,8 +1242,7 @@ error: int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl) { - u32 reg_val, ndx; - int status = 0, retry = 10; + int status, rc; u32 time_out_count; struct hdmi_tx_ddc_data *ddc_data; u32 wait_time; @@ -1303,149 +1261,69 @@ int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl) goto error; } -again: - status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what); - if (status) + if (ddc_data->retry < 0) { + pr_err("invalid no. of retries %d\n", ddc_data->retry); + status = -EINVAL; goto error; + } - /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */ - ddc_data->dev_addr &= 0xFE; - - /* - * 1. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #1 - * DATA_RW = 0x1 (write) - * DATA = linkAddress (primary link address and writing) - * INDEX = 0x0 (initial offset into buffer) - * INDEX_WRITE = 0x1 (setting initial offset) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, - BIT(31) | (ddc_data->dev_addr << 8)); - - /* - * 2. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #2 - * DATA_RW = 0x0 (write) - * DATA = offsetAddress - * INDEX = 0x0 - * INDEX_WRITE = 0x0 (auto-increment by hardware) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8); - - /* - * 3. Write to HDMI_I2C_DATA with the following fields set in order to - * handle portion #3 - * DATA_RW = 0x0 (write) - * DATA = data_buf[ndx] - * INDEX = 0x0 - * INDEX_WRITE = 0x0 (auto-increment by hardware) - */ - for (ndx = 0; ndx < ddc_data->data_len; ++ndx) - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, - ((u32)ddc_data->data_buf[ndx]) << 8); - - /* Data setup is complete, now setup the transaction characteristics */ - - /* - * 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in - * order to handle characteristics of portion #1 and portion #2 - * RW0 = 0x0 (write) - * START0 = 0x1 (insert START bit) - * STOP0 = 0x0 (do NOT insert STOP bit) - * CNT0 = 0x1 (single byte transaction excluding address) - */ - reg_val = (ddc_data->data_len + 1) << 16; - reg_val |= BIT(12); - reg_val |= BIT(13); - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, reg_val); + do { + status = hdmi_ddc_clear_irq(ddc_ctrl, ddc_data->what); + if (status) + continue; - if (ddc_data->hard_timeout) { - pr_debug("using hard_timeout %dms\n", ddc_data->hard_timeout); + if (ddc_data->hard_timeout) { + pr_debug("using hard_timeout %dms\n", + ddc_data->hard_timeout); - busy_wait_us = ddc_data->hard_timeout * HDMI_MS_TO_US; - atomic_set(&ddc_ctrl->write_busy_wait_done, 0); - } else { - reinit_completion(&ddc_ctrl->ddc_sw_done); - wait_time = HZ / 2; - } + busy_wait_us = ddc_data->hard_timeout * HDMI_MS_TO_US; + atomic_set(&ddc_ctrl->write_busy_wait_done, 0); + } else { + reinit_completion(&ddc_ctrl->ddc_sw_done); + wait_time = HZ / 2; + } - /* Trigger the I2C transfer */ - /* - * 6. Write to HDMI_I2C_CONTROL to kick off the hardware. - * Note that NOTHING has been transmitted on the DDC lines up to this - * point. - * TRANSACTION_CNT = 0x1 (execute transaction0 followed by - * transaction1) - * GO = 0x1 (kicks off hardware) - */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0)); + hdmi_ddc_trigger(ddc_ctrl, TRIGGER_WRITE, false); - if (ddc_data->hard_timeout) { - while (busy_wait_us > 0 && - !atomic_read(&ddc_ctrl->write_busy_wait_done)) { - udelay(HDMI_BUSY_WAIT_DELAY_US); - busy_wait_us -= HDMI_BUSY_WAIT_DELAY_US; - }; + if (ddc_data->hard_timeout) { + while (busy_wait_us > 0 && + !atomic_read(&ddc_ctrl->write_busy_wait_done)) { + udelay(HDMI_BUSY_WAIT_DELAY_US); + busy_wait_us -= HDMI_BUSY_WAIT_DELAY_US; + }; - if (busy_wait_us < 0) - busy_wait_us = 0; + if (busy_wait_us < 0) + busy_wait_us = 0; - time_out_count = busy_wait_us / HDMI_MS_TO_US; + time_out_count = busy_wait_us / HDMI_MS_TO_US; - ddc_data->timeout_left = time_out_count; - } else { - time_out_count = wait_for_completion_timeout( - &ddc_ctrl->ddc_sw_done, wait_time); + ddc_data->timeout_left = time_out_count; + } else { + time_out_count = wait_for_completion_timeout( + &ddc_ctrl->ddc_sw_done, wait_time); - ddc_data->timeout_left = jiffies_to_msecs(time_out_count); - } + ddc_data->timeout_left = + jiffies_to_msecs(time_out_count); + } - pr_debug("DDC write done at %dms\n", jiffies_to_msecs(jiffies)); + pr_debug("DDC write done at %dms\n", jiffies_to_msecs(jiffies)); - if (!time_out_count) { - if (retry-- > 0) { - pr_debug("%s: failed timout, retry=%d\n", - ddc_data->what, retry); + if (!time_out_count) { + pr_debug("%s timout\n", ddc_data->what); - if (!ddc_data->hard_timeout) - goto again; + status = -ETIMEDOUT; } - status = -ETIMEDOUT; - pr_err("%s: timedout, Int Ctrl=%08x\n", - ddc_data->what, - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL)); - pr_err("DDC SW Status=%08x, HW Status=%08x\n", - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS), - DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS)); - goto error; - } - /* Read DDC status */ - reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_SW_STATUS); - reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000; + rc = hdmi_ddc_check_status(ddc_ctrl); - /* Check if any NACK occurred */ - if (reg_val) { - if (retry > 1) - /* SW_STATUS_RESET */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3)); - else - /* SOFT_RESET */ - DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1)); - - if (retry-- > 0) { - pr_debug("%s: failed NACK=%08x, retry=%d\n", - ddc_data->what, reg_val, retry); - msleep(100); - goto again; - } - status = -EIO; - pr_err("%s: failed NACK: %08x\n", ddc_data->what, reg_val); + if (!status) + status = rc; + } while (status && ddc_data->retry--); + + if (status) goto error; - } pr_debug("%s: success\n", ddc_data->what); - error: return status; } /* hdmi_ddc_write */ @@ -1492,7 +1370,6 @@ int hdmi_scdc_read(struct hdmi_tx_ddc_ctrl *ctrl, u32 data_type, u32 *val) data.what = hdmi_scdc_reg2string(data_type); data.dev_addr = 0xA8; - data.no_align = true; data.retry = 1; data.data_buf = data_buf; @@ -1608,7 +1485,6 @@ int hdmi_scdc_write(struct hdmi_tx_ddc_ctrl *ctrl, u32 data_type, u32 val) data.what = hdmi_scdc_reg2string(data_type); data.dev_addr = 0xA8; - data.no_align = true; data.retry = 1; data.data_buf = data_buf; @@ -1617,7 +1493,6 @@ int hdmi_scdc_write(struct hdmi_tx_ddc_ctrl *ctrl, u32 data_type, u32 val) case HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE: rdata.what = "TMDS CONFIG"; rdata.dev_addr = 0xA8; - rdata.no_align = true; rdata.retry = 2; rdata.data_buf = &read_val; rdata.data_len = 1; @@ -1688,7 +1563,7 @@ int hdmi_setup_ddc_timers(struct hdmi_tx_ddc_ctrl *ctrl, return 0; } -void hdmi_hdcp2p2_ddc_reset(struct hdmi_tx_ddc_ctrl *ctrl) +static void hdmi_hdcp2p2_ddc_reset(struct hdmi_tx_ddc_ctrl *ctrl) { u32 reg_val; @@ -1715,29 +1590,18 @@ void hdmi_hdcp2p2_ddc_reset(struct hdmi_tx_ddc_ctrl *ctrl) void hdmi_hdcp2p2_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl) { u32 reg_val; - u32 retry_read = 100; - bool ddc_hw_not_ready; if (!ctrl) { pr_err("Invalid parameters\n"); return; } - /* Clear RXSTATUS_DDC_DONE interrupt */ - DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, BIT(5)); - ddc_hw_not_ready = true; - - /* Make sure the interrupt is clear */ - do { - reg_val = DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL0); - ddc_hw_not_ready = reg_val & BIT(5); - if (ddc_hw_not_ready) - msleep(20); - } while (ddc_hw_not_ready && --retry_read); + hdmi_hdcp2p2_ddc_reset(ctrl); /* Disable HW DDC access to RxStatus register */ reg_val = DSS_REG_R(ctrl->io, HDMI_HW_DDC_CTRL); reg_val &= ~(BIT(1) | BIT(0)); + DSS_REG_W(ctrl->io, HDMI_HW_DDC_CTRL, reg_val); } @@ -1805,6 +1669,12 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait) pr_debug("writng HDMI_DDC_INT_CTRL0 0x%x\n", reg_val); DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, reg_val); + reg_val = DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL5); + /* clear and enable RxStatus read timeout */ + reg_val |= BIT(2) | BIT(1); + + DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL5, reg_val); + /* * Enable hardware DDC access to RxStatus register * @@ -1851,7 +1721,7 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait) rc = -ETIMEDOUT; } - rc = hdmi_ddc_check_status(ctrl); + rc = hdmi_hdcp2p2_ddc_check_status(ctrl); hdmi_hdcp2p2_ddc_disable(ctrl); } diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index 4c5f8bc09bec..c919865ccf41 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -406,7 +406,7 @@ struct hdmi_tx_ddc_data { u32 dev_addr; u32 offset; u32 request_len; - u32 no_align; + u32 retry_align; u32 hard_timeout; u32 timeout_left; int retry; @@ -432,6 +432,7 @@ struct hdmi_tx_hdcp2p2_ddc_data { bool ddc_max_retries_fail; bool ddc_done; bool ddc_read_req; + bool ddc_timeout; int irq_wait_count; }; @@ -497,10 +498,10 @@ int hdmi_scdc_read(struct hdmi_tx_ddc_ctrl *ctrl, u32 data_type, u32 *val); int hdmi_scdc_write(struct hdmi_tx_ddc_ctrl *ctrl, u32 data_type, u32 val); int hdmi_setup_ddc_timers(struct hdmi_tx_ddc_ctrl *ctrl, u32 type, u32 to_in_num_lines); -void hdmi_hdcp2p2_ddc_reset(struct hdmi_tx_ddc_ctrl *ctrl); +void hdmi_scrambler_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl); void hdmi_hdcp2p2_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait); -int hdmi_ddc_check_status(struct hdmi_tx_ddc_ctrl *ctrl); +int hdmi_hdcp2p2_ddc_check_status(struct hdmi_tx_ddc_ctrl *ctrl); int hdmi_utils_get_timeout_in_hysnc(struct msm_hdmi_mode_timing_info *timing, u32 timeout_ms); |
