diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 0a32d11f6161..0df388a841d6 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -332,6 +332,7 @@ struct hdcp_lib_handle { uint32_t msglen; uint32_t tz_ctxhandle; uint32_t hdcp_timeout; + uint32_t timeout_left; bool no_stored_km_flag; bool feature_supported; void *client_ctx; @@ -842,7 +843,11 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) mutex_lock(&handle->wakeup_mutex); handle->wakeup_cmd = data->cmd; - pr_debug("%s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd)); + handle->timeout_left = data->timeout; + + pr_debug("%s, timeout left: %dms\n", + hdcp_lib_cmd_to_str(handle->wakeup_cmd), + handle->timeout_left); rc = hdcp_lib_check_valid_state(handle); if (rc) @@ -874,6 +879,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) handle->no_stored_km_flag = 0; handle->repeater_flag = 0; handle->last_msg_sent = 0; + handle->hdcp_timeout = 0; + handle->timeout_left = 0; atomic_set(&handle->hdcp_off, 0); handle->hdcp_state = HDCP_STATE_INIT; @@ -949,7 +956,7 @@ static void hdcp_lib_msg_sent_work(struct kthread_work *work) break; default: cdata.cmd = HDMI_HDCP_WKUP_CMD_RECV_MESSAGE; - cdata.timeout = handle->hdcp_timeout; + cdata.timeout = handle->timeout_left; } mutex_unlock(&handle->hdcp_lock); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c index 421ab07ca930..0673609ad5bd 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c @@ -34,11 +34,12 @@ #define HDCP_SINK_DDC_HDCP2_RXSTATUS 0x70 /* RxStatus, 2 bytes */ #define HDCP_SINK_DDC_HDCP2_READ_MESSAGE 0x80 /* HDCP Tx reads here */ -#define HDCP2P2_LINK_CHECK_TIME_MS 500 /* link check within 1 sec */ +#define HDCP2P2_LINK_CHECK_TIME_MS 900 /* link check within 1 sec */ #define HDCP2P2_SEC_TO_US 1000000 #define HDCP2P2_MS_TO_US 1000 #define HDCP2P2_KHZ_TO_HZ 1000 +#define HDCP2P2_DEFAULT_TIMEOUT 500 /* * HDCP 2.2 encryption requires the data encryption block that is present in @@ -66,6 +67,7 @@ struct hdmi_hdcp2p2_ctrl { char *send_msg_buf; uint32_t send_msg_len; uint32_t timeout; + uint32_t timeout_left; struct task_struct *thread; struct kthread_worker worker; @@ -78,6 +80,45 @@ struct hdmi_hdcp2p2_ctrl { struct delayed_work link_check_work; }; +static inline bool hdmi_hdcp2p2_is_valid_state(struct hdmi_hdcp2p2_ctrl *ctrl) +{ + if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE) + return true; + + if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE) + return true; + + return false; +} + +static int hdmi_hdcp2p2_copy_buf(struct hdmi_hdcp2p2_ctrl *ctrl, + struct hdmi_hdcp_wakeup_data *data) +{ + mutex_lock(&ctrl->msg_lock); + + if (!data->send_msg_len) { + mutex_unlock(&ctrl->msg_lock); + return 0; + } + + ctrl->send_msg_len = data->send_msg_len; + + kzfree(ctrl->send_msg_buf); + + ctrl->send_msg_buf = kzalloc(data->send_msg_len, GFP_KERNEL); + + if (!ctrl->send_msg_buf) { + mutex_unlock(&ctrl->msg_lock); + return -ENOMEM; + } + + memcpy(ctrl->send_msg_buf, data->send_msg_buf, ctrl->send_msg_len); + + mutex_unlock(&ctrl->msg_lock); + + return 0; +} + static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) { struct hdmi_hdcp2p2_ctrl *ctrl; @@ -95,43 +136,35 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) mutex_lock(&ctrl->wakeup_mutex); - pr_debug("cmd: %s\n", hdmi_hdcp_cmd_to_str(data->cmd)); + pr_debug("cmd: %s, timeout %dms\n", + hdmi_hdcp_cmd_to_str(data->cmd), + data->timeout); ctrl->wakeup_cmd = data->cmd; - ctrl->timeout = data->timeout; - mutex_lock(&ctrl->msg_lock); - if (data->send_msg_len) { - ctrl->send_msg_len = data->send_msg_len; + if (data->timeout) + ctrl->timeout = data->timeout; + else + ctrl->timeout = HDCP2P2_DEFAULT_TIMEOUT; - kzfree(ctrl->send_msg_buf); - - ctrl->send_msg_buf = kzalloc( - data->send_msg_len, GFP_KERNEL); - - if (!ctrl->send_msg_buf) { - mutex_unlock(&ctrl->msg_lock); - goto exit; - } - - memcpy(ctrl->send_msg_buf, data->send_msg_buf, - ctrl->send_msg_len); + if (!hdmi_hdcp2p2_is_valid_state(ctrl)) { + pr_err("invalid state\n"); + goto exit; } - mutex_unlock(&ctrl->msg_lock); + + if (hdmi_hdcp2p2_copy_buf(ctrl, data)) + goto exit; switch (ctrl->wakeup_cmd) { case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE: - if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE) - queue_kthread_work(&ctrl->worker, &ctrl->send_msg); + queue_kthread_work(&ctrl->worker, &ctrl->send_msg); break; case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE: - if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE) - queue_kthread_work(&ctrl->worker, &ctrl->recv_msg); + queue_kthread_work(&ctrl->worker, &ctrl->recv_msg); break; case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS: case HDMI_HDCP_WKUP_CMD_STATUS_FAILED: - if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE) - queue_kthread_work(&ctrl->worker, &ctrl->status); + queue_kthread_work(&ctrl->worker, &ctrl->status); break; case HDMI_HDCP_WKUP_CMD_AUTHENTICATE: queue_kthread_work(&ctrl->worker, &ctrl->auth); @@ -366,6 +399,7 @@ static int hdmi_hdcp2p2_ddc_read_message(struct hdmi_hdcp2p2_ctrl *ctrl, pr_err("hdcp is off\n"); return -EINVAL; } + memset(&ddc_data, 0, sizeof(ddc_data)); ddc_data.dev_addr = HDCP_SINK_DDC_SLAVE_ADDR; ddc_data.offset = HDCP_SINK_DDC_HDCP2_READ_MESSAGE; @@ -378,9 +412,14 @@ static int hdmi_hdcp2p2_ddc_read_message(struct hdmi_hdcp2p2_ctrl *ctrl, ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; + pr_debug("read msg timeout %dms\n", timeout); + rc = hdmi_ddc_read(ctrl->init_data.ddc_ctrl); if (rc) pr_err("Cannot read HDCP message register\n"); + + ctrl->timeout_left = ctrl->init_data.ddc_ctrl->ddc_data.timeout_left; + return rc; } @@ -396,6 +435,7 @@ static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl, ddc_data.data_buf = buf; ddc_data.data_len = size; ddc_data.retry = 1; + ddc_data.hard_timeout = ctrl->timeout; ddc_data.what = "HDCP2WriteMessage"; ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; @@ -403,6 +443,9 @@ static int hdmi_hdcp2p2_ddc_write_message(struct hdmi_hdcp2p2_ctrl *ctrl, rc = hdmi_ddc_write(ctrl->init_data.ddc_ctrl); if (rc) pr_err("Cannot write HDCP message register\n"); + + ctrl->timeout_left = ctrl->init_data.ddc_ctrl->ddc_data.timeout_left; + return rc; } @@ -545,6 +588,7 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED; } else { cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS; + cdata.timeout = ctrl->timeout_left; } exit: kzfree(msg); @@ -605,10 +649,13 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) lines_needed_for_given_time = (ctrl->timeout * HDCP2P2_MS_TO_US) / time_taken_by_one_line_us; - pr_debug("timeout for rxstatus %d\n", lines_needed_for_given_time); + pr_debug("timeout for rxstatus %dms, %d hsyncs\n", + ctrl->timeout, lines_needed_for_given_time); ddc_data->intr_mask = RXSTATUS_MESSAGE_SIZE; - ddc_data->timer_delay_lines = lines_needed_for_given_time; + ddc_data->timeout_ms = ctrl->timeout; + ddc_data->timeout_hsync = lines_needed_for_given_time; + ddc_data->periodic_timer_hsync = lines_needed_for_given_time / 20; ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, true); @@ -617,26 +664,30 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) goto exit; } + ctrl->timeout_left = ddc_data->timeout_left; + + pr_debug("timeout left after rxstatus %dms, msg size %d\n", + ctrl->timeout_left, ddc_data->message_size); + if (!ddc_data->message_size) { pr_err("recvd invalid message size\n"); rc = -EINVAL; goto exit; } - pr_debug("rxstatus msg size %d\n", ddc_data->message_size); - recvd_msg_buf = kzalloc(ddc_data->message_size, GFP_KERNEL); if (!recvd_msg_buf) goto exit; rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf, - ddc_data->message_size, ctrl->timeout); + ddc_data->message_size, ctrl->timeout_left); if (rc) pr_err("error reading message %d\n", rc); cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS; cdata.recvd_msg_buf = recvd_msg_buf; cdata.recvd_msg_len = ddc_data->message_size; + cdata.timeout = ctrl->timeout_left; exit: if (rc == -ETIMEDOUT) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT; @@ -672,14 +723,16 @@ static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl) fps = timing->refresh_rate / HDCP2P2_KHZ_TO_HZ; v_total = hdmi_tx_get_v_total(timing); time_taken_by_one_line_us = HDCP2P2_SEC_TO_US / (v_total * fps); - lines_needed_for_given_time = (jiffies_to_msecs(HZ / 2) * + lines_needed_for_given_time = (jiffies_to_msecs((HZ / 2) + (HZ / 4)) * HDCP2P2_MS_TO_US) / time_taken_by_one_line_us; - pr_debug("timeout for rxstatus %d\n", lines_needed_for_given_time); + pr_debug("timeout for rxstatus %d hsyncs\n", + lines_needed_for_given_time); ddc_data->intr_mask = RXSTATUS_READY | RXSTATUS_MESSAGE_SIZE | RXSTATUS_REAUTH_REQ; - ddc_data->timer_delay_lines = lines_needed_for_given_time; + ddc_data->timeout_hsync = lines_needed_for_given_time; + ddc_data->periodic_timer_hsync = lines_needed_for_given_time; ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false); @@ -788,7 +841,7 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) } rc = hdmi_hdcp2p2_ddc_read_message(ctrl, recvd_msg_buf, - ddc_data->message_size, ctrl->timeout); + ddc_data->message_size, HDCP2P2_DEFAULT_TIMEOUT); if (rc) { cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; pr_err("error reading message %d\n", rc); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c index df8d72ee7cdf..09138eb9056d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c @@ -515,23 +515,22 @@ static int hdmi_ddc_clear_irq(struct hdmi_tx_ddc_ctrl *ddc_ctrl, return -EINVAL; } + /* 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); + /* wait until DDC HW is free */ timeout = 100; do { - --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); + udelay(100); } - } while (in_use && timeout); - - /* 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); + } while (in_use && --timeout); if (!timeout) { pr_err("%s: timedout\n", what); @@ -652,11 +651,15 @@ again: &ddc_ctrl->ddc_sw_done, wait_time); pr_debug("ddc read done at %dms\n", jiffies_to_msecs(jiffies)); + ddc_data->timeout_left = jiffies_to_msecs(time_out_count); + DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, BIT(1)); if (!time_out_count) { if (ddc_data->retry-- > 0) { pr_debug("failed timout, retry=%d\n", ddc_data->retry); - goto again; + + if (!ddc_data->hard_timeout) + goto again; } status = -ETIMEDOUT; pr_err("timedout(7), Int Ctrl=%08x\n", @@ -809,8 +812,7 @@ static int hdmi_ddc_hdcp2p2_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl) intr2 = DSS_REG_R(io, HDMI_HDCP_INT_CTRL2); intr0 = DSS_REG_R(io, HDMI_DDC_INT_CTRL0); - pr_debug("INT_CTRL0 :0x%x\n", intr0); - pr_debug("INT_CTRL2 :0x%x\n", intr2); + pr_debug("ctl0: 0x%x, ctl1: 0x%x\n", intr0, intr2); /* check for encryption ready interrupt */ if (intr2 & BIT(2)) { @@ -1204,6 +1206,7 @@ int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl) int status = 0, retry = 10; u32 time_out_count; struct hdmi_tx_ddc_data *ddc_data; + u32 wait_time; if (!ddc_ctrl || !ddc_ctrl->io) { pr_err("invalid input\n"); @@ -1286,8 +1289,19 @@ again: reinit_completion(&ddc_ctrl->ddc_sw_done); DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0)); + if (ddc_data->hard_timeout) { + pr_debug("using hard_timeout %dms\n", ddc_data->hard_timeout); + wait_time = msecs_to_jiffies(ddc_data->hard_timeout); + } else { + wait_time = HZ/2; + } + + pr_debug("timeout for ddc write %d jiffies\n", wait_time); + time_out_count = wait_for_completion_timeout( - &ddc_ctrl->ddc_sw_done, HZ/2); + &ddc_ctrl->ddc_sw_done, wait_time); + + ddc_data->timeout_left = jiffies_to_msecs(time_out_count); pr_debug("DDC write done at %dms\n", jiffies_to_msecs(jiffies)); @@ -1297,7 +1311,9 @@ again: if (retry-- > 0) { pr_debug("%s: failed timout, retry=%d\n", ddc_data->what, retry); - goto again; + + if (!ddc_data->hard_timeout) + goto again; } status = -ETIMEDOUT; pr_err("%s: timedout, Int Ctrl=%08x\n", @@ -1635,6 +1651,7 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait) u32 reg_val; u32 intr_en_mask; u32 timeout; + u32 timer; int rc = 0; struct hdmi_tx_hdcp2p2_ddc_data *data; @@ -1674,9 +1691,11 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait) * 3. DDC_TIMEOUT_TIMER: Timeout in hsyncs which starts counting when * a request is made and stops when it is accepted by DDC arbiter */ - timeout = data->timer_delay_lines; - pr_debug("timeout: %d\n", timeout); - DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL, timeout); + timeout = data->timeout_hsync; + timer = data->periodic_timer_hsync; + pr_debug("timeout: %d hsyncs, timer %d hsync\n", timeout, timer); + + DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL, timer); /* Set both urgent and hw-timeout fields to the same value */ DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL2, @@ -1711,8 +1730,6 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait) reg_val = DSS_REG_R(ctrl->io, HDMI_HW_DDC_CTRL); reg_val &= ~(BIT(1) | BIT(0)); - pr_debug("data->read_method %d\n", data->read_method); - if (data->read_method == HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER) reg_val |= BIT(1) | BIT(0); else @@ -1725,16 +1742,20 @@ int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl, bool wait) DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_SW_TRIGGER, 1); if (wait) { + u32 wait_timeout; + reinit_completion(&ctrl->rxstatus_completion); - /* max timeout as per hdcp 2.2 std is 1 sec */ - timeout = wait_for_completion_timeout( + + wait_timeout = wait_for_completion_timeout( &ctrl->rxstatus_completion, - msecs_to_jiffies(HDMI_SEC_TO_MS)); - if (!timeout) { + msecs_to_jiffies(data->timeout_ms)); + if (!wait_timeout) { pr_err("sw ddc rxstatus timeout\n"); rc = -ETIMEDOUT; } + data->timeout_left = jiffies_to_msecs(wait_timeout); + rc = hdmi_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 4530fd414b12..439a1c408eae 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -405,6 +405,7 @@ struct hdmi_tx_ddc_data { u32 request_len; u32 no_align; u32 hard_timeout; + u32 timeout_left; int retry; }; @@ -416,7 +417,10 @@ enum hdmi_tx_hdcp2p2_rxstatus_intr_mask { struct hdmi_tx_hdcp2p2_ddc_data { enum hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask; - u32 timer_delay_lines; + u32 timeout_ms; + u32 timeout_hsync; + u32 periodic_timer_hsync; + u32 timeout_left; u32 read_method; u32 message_size; bool encryption_ready;