Loading drivers/misc/hdcp.c +107 −19 Original line number Diff line number Diff line Loading @@ -337,6 +337,7 @@ struct hdcp_lib_handle { void *client_ctx; struct hdcp_client_ops *client_ops; struct mutex hdcp_lock; struct mutex msg_lock; struct mutex wakeup_mutex; enum hdcp_state hdcp_state; enum hdcp_lib_wakeup_cmd wakeup_cmd; Loading Loading @@ -755,6 +756,77 @@ exit: return supported; } static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle) { if (!list_empty(&handle->init.node)) pr_debug("init work queued\n"); if (handle->worker.current_work == &handle->init) pr_debug("init work executing\n"); if (!list_empty(&handle->msg_sent.node)) pr_debug("msg_sent work queued\n"); if (handle->worker.current_work == &handle->msg_sent) pr_debug("msg_sent work executing\n"); if (!list_empty(&handle->msg_recvd.node)) pr_debug("msg_recvd work queued\n"); if (handle->worker.current_work == &handle->msg_recvd) pr_debug("msg_recvd work executing\n"); if (!list_empty(&handle->timeout.node)) pr_debug("timeout work queued\n"); if (handle->worker.current_work == &handle->timeout) pr_debug("timeout work executing\n"); if (!list_empty(&handle->clean.node)) pr_debug("clean work queued\n"); if (handle->worker.current_work == &handle->clean) pr_debug("clean work executing\n"); if (!list_empty(&handle->topology.node)) pr_debug("topology work queued\n"); if (handle->worker.current_work == &handle->topology) pr_debug("topology work executing\n"); if (!list_empty(&handle->stream.node)) pr_debug("stream work queued\n"); if (handle->worker.current_work == &handle->stream) pr_debug("stream work executing\n"); } static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle) { int rc = 0; if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) { if (!list_empty(&handle->worker.work_list)) { hdcp_lib_check_worker_status(handle); rc = -EBUSY; goto exit; } } else { if (atomic_read(&handle->hdcp_off)) { pr_warn("hdcp2.2 session tearing down\n"); goto exit; } if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("hdcp 2.2 app not loaded\n"); rc = -EINVAL; goto exit; } } exit: return rc; } static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) { struct hdcp_lib_handle *handle; Loading @@ -770,22 +842,29 @@ 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)); pr_debug("cmd: %s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd)); rc = hdcp_lib_check_valid_state(handle); if (rc) goto exit; mutex_lock(&handle->msg_lock); if (data->recvd_msg_len) { handle->last_msg_recvd_len = data->recvd_msg_len; kzfree(handle->last_msg_recvd_buf); handle->last_msg_recvd_len = data->recvd_msg_len; handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len, GFP_KERNEL); if (!handle->last_msg_recvd_buf) { rc = -ENOMEM; mutex_unlock(&handle->msg_lock); goto exit; } memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf, data->recvd_msg_len); } mutex_unlock(&handle->msg_lock); if (!completion_done(&handle->topo_wait)) complete_all(&handle->topo_wait); Loading @@ -807,24 +886,19 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS: handle->last_msg_sent = handle->listener_buf[0]; if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->msg_sent); break; case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->clean); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->msg_recvd); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->timeout); break; case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->stream); break; default: Loading @@ -832,7 +906,7 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) } exit: mutex_unlock(&handle->wakeup_mutex); return 0; return rc; } static void hdcp_lib_msg_sent_work(struct kthread_work *work) Loading Loading @@ -926,7 +1000,6 @@ exit: if (rc && !atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->clean); return; } static void hdcp_lib_manage_timeout_work(struct kthread_work *work) Loading Loading @@ -1044,18 +1117,29 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) } mutex_lock(&handle->hdcp_lock); cdata.context = handle->client_ctx; msg = handle->last_msg_recvd_buf; mutex_lock(&handle->msg_lock); msglen = handle->last_msg_recvd_len; cdata.context = handle->client_ctx; if (msglen <= 0) { pr_err("invalid msg len\n"); mutex_unlock(&handle->msg_lock); rc = -EINVAL; goto exit; } msg = kzalloc(msglen, GFP_KERNEL); if (!msg) { mutex_unlock(&handle->msg_lock); rc = -ENOMEM; goto exit; } memcpy(msg, handle->last_msg_recvd_buf, msglen); mutex_unlock(&handle->msg_lock); pr_debug("msg received: %s from sink\n", hdcp_lib_message_name((int)msg[0])); Loading Loading @@ -1140,7 +1224,7 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) } exit: kzfree(handle->last_msg_recvd_buf); kzfree(msg); mutex_unlock(&handle->hdcp_lock); hdcp_lib_wakeup_client(handle, &cdata); Loading @@ -1160,7 +1244,6 @@ static void hdcp_lib_topology_work(struct kthread_work *work) return; } reinit_completion(&handle->topo_wait); timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3); if (!timeout) { Loading @@ -1185,6 +1268,9 @@ bool hdcp1_check_if_supported_load_app(void) } } pr_debug("hdcp1 app %s loaded\n", hdcp1_supported ? "successfully" : "not"); return hdcp1_supported; } Loading Loading @@ -1274,6 +1360,7 @@ int hdcp_library_register(void **pphdcpcontext, atomic_set(&handle->hdcp_off, 0); mutex_init(&handle->hdcp_lock); mutex_init(&handle->msg_lock); mutex_init(&handle->wakeup_mutex); init_kthread_worker(&handle->worker); Loading Loading @@ -1326,6 +1413,7 @@ void hdcp_library_deregister(void *phdcpcontext) kthread_stop(handle->thread); kzfree(handle->qseecom_handle); kzfree(handle->last_msg_recvd_buf); mutex_destroy(&handle->hdcp_lock); mutex_destroy(&handle->wakeup_mutex); Loading drivers/video/msm/mdss/mdss_hdmi_edid.c +10 −10 Original line number Diff line number Diff line Loading @@ -1208,9 +1208,9 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl, u32 pulse_width_v = 0; u32 active_low_h = 0; u32 active_low_v = 0; const u32 khz_to_hz = 1000; u32 frame_data; struct msm_hdmi_mode_timing_info timing = {0}; u64 rr_tmp, frame_data; int rc; /* Loading Loading @@ -1326,15 +1326,10 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl, active_low_h = ((data_buf[0x11] & BIT(1)) && (data_buf[0x11] & BIT(4))) ? 0 : 1; DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__, active_h, active_v, blank_h, blank_v, img_size_h, img_size_v, interlaced ? "i" : "p"); rr_tmp = pixel_clk * 1000 * 1000; frame_data = (blank_h + active_h) * (blank_v + active_v); frame_data = (active_h + blank_h) * (active_v + blank_v); if (frame_data) { do_div(rr_tmp, frame_data); int refresh_rate_khz = (pixel_clk * khz_to_hz) / frame_data; timing.active_h = active_h; timing.front_porch_h = front_porch_h; Loading @@ -1349,13 +1344,18 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl, (front_porch_v + pulse_width_v); timing.active_low_v = active_low_v; timing.pixel_freq = pixel_clk; timing.refresh_rate = (u32) rr_tmp; timing.refresh_rate = refresh_rate_khz * khz_to_hz; timing.interlaced = interlaced; timing.supported = true; timing.ar = aspect_ratio_4_3 ? HDMI_RES_AR_4_3 : (aspect_ratio_5_4 ? HDMI_RES_AR_5_4 : HDMI_RES_AR_16_9); DEV_DBG("%s: new res: %dx%d%s@%dHz\n", __func__, timing.active_h, timing.active_v, interlaced ? "i" : "p", timing.refresh_rate / khz_to_hz); rc = hdmi_set_resv_timing_info(&timing); } else { DEV_ERR("%s: Invalid frame data\n", __func__); Loading drivers/video/msm/mdss/mdss_hdmi_hdcp.c +29 −22 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -182,17 +183,24 @@ 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; ddc_xfer_done = hdcp_ddc_status & BIT(10); 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, Loading @@ -202,7 +210,6 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl) 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) Loading drivers/video/msm/mdss/mdss_hdmi_hdcp.h +4 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,10 @@ enum hdmi_hdcp_state { HDCP_STATE_INACTIVE, HDCP_STATE_AUTHENTICATING, HDCP_STATE_AUTHENTICATED, HDCP_STATE_AUTH_FAIL HDCP_STATE_AUTH_FAIL, HDCP_STATE_AUTH_ENC_NONE, HDCP_STATE_AUTH_ENC_1X, HDCP_STATE_AUTH_ENC_2P2 }; struct hdmi_hdcp_init_data { Loading drivers/video/msm/mdss/mdss_hdmi_hdcp2p2.c +145 −36 Original line number Diff line number Diff line Loading @@ -36,6 +36,10 @@ #define HDCP2P2_LINK_CHECK_TIME_MS 500 /* link check within 1 sec */ #define HDCP2P2_SEC_TO_US 1000000 #define HDCP2P2_MS_TO_US 1000 #define HDCP2P2_KHZ_TO_HZ 1000 /* * HDCP 2.2 encryption requires the data encryption block that is present in * HDMI controller version 4.0.0 and above Loading @@ -52,6 +56,7 @@ struct hdmi_hdcp2p2_ctrl { enum hdmi_hdcp2p2_sink_status sink_status; /* Is sink connected */ struct hdmi_hdcp_init_data init_data; /* Feature data from HDMI drv */ struct mutex mutex; /* mutex to protect access to ctrl */ struct mutex msg_lock; /* mutex to protect access to msg buffer */ struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/ struct hdmi_hdcp_ops *ops; void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */ Loading Loading @@ -95,18 +100,24 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) 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; kzfree(ctrl->send_msg_buf); ctrl->send_msg_buf = kzalloc( data->send_msg_len, GFP_KERNEL); if (!ctrl->send_msg_buf) 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); } mutex_unlock(&ctrl->msg_lock); switch (ctrl->wakeup_cmd) { case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE: Loading @@ -133,7 +144,7 @@ exit: return 0; } static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, struct hdcp_lib_wakeup_data *data) { int rc = 0; Loading @@ -145,6 +156,8 @@ static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, pr_err("error sending %s to lib\n", hdcp_lib_cmd_to_str(data->cmd)); } return rc; } static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl) Loading Loading @@ -172,6 +185,8 @@ static void hdmi_hdcp2p2_off(void *input) flush_kthread_worker(&ctrl->worker); hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl); cdata.context = input; hdmi_hdcp2p2_wakeup(&cdata); Loading Loading @@ -281,18 +296,48 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev, hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2); struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE}; bool enc_notify = true; enum hdmi_hdcp_state enc_lvl; int min_enc_lvl; int rc; if (!ctrl) { pr_err("invalid input\n"); return -EINVAL; rc = -EINVAL; goto exit; } pr_debug("notification of minimum level change received\n"); rc = kstrtoint(buf, 10, &min_enc_lvl); if (rc) { DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc); goto exit; } switch (min_enc_lvl) { case 0: enc_lvl = HDCP_STATE_AUTH_ENC_NONE; break; case 1: enc_lvl = HDCP_STATE_AUTH_ENC_1X; break; case 2: enc_lvl = HDCP_STATE_AUTH_ENC_2P2; break; default: enc_notify = false; } pr_debug("enc level changed %d\n", min_enc_lvl); cdata.context = ctrl->lib_ctx; hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); return count; if (enc_notify && ctrl->init_data.notify_status) ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl); rc = count; exit: return rc; } static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl) Loading @@ -304,6 +349,8 @@ static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl) atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl); /* notify hdmi tx about HDCP failure */ ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTH_FAIL); Loading Loading @@ -457,6 +504,8 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, struct hdmi_hdcp2p2_ctrl, send_msg); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; char *msg; uint32_t msglen; if (!ctrl) { pr_err("invalid input\n"); Loading @@ -472,9 +521,25 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) goto exit; } mutex_lock(&ctrl->msg_lock); msglen = ctrl->send_msg_len; if (!msglen) { mutex_unlock(&ctrl->msg_lock); goto exit; } msg = kzalloc(msglen, GFP_KERNEL); if (!msg) { mutex_unlock(&ctrl->msg_lock); goto exit; } memcpy(msg, ctrl->send_msg_buf, msglen); mutex_unlock(&ctrl->msg_lock); /* Forward the message to the sink */ rc = hdmi_hdcp2p2_ddc_write_message(ctrl, ctrl->send_msg_buf, (size_t)ctrl->send_msg_len); rc = hdmi_hdcp2p2_ddc_write_message(ctrl, msg, (size_t)msglen); if (rc) { pr_err("Error sending msg to sink %d\n", rc); cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED; Loading @@ -482,7 +547,7 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS; } exit: kzfree(ctrl->send_msg_buf); kzfree(msg); mutex_unlock(&ctrl->mutex); hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); Loading @@ -491,7 +556,9 @@ exit: static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) { int rc = 0; u64 mult; u32 fps, v_total; u32 time_taken_by_one_line_us; u32 lines_needed_for_given_time; char *recvd_msg_buf = NULL; struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, struct hdmi_hdcp2p2_ctrl, recv_msg); Loading Loading @@ -525,12 +592,26 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) memset(ddc_data, 0, sizeof(*ddc_data)); timing = ctrl->init_data.timing; mult = hdmi_tx_get_v_total(timing) / 20; fps = timing->refresh_rate / HDCP2P2_KHZ_TO_HZ; v_total = hdmi_tx_get_v_total(timing); /* * pixel clock = h_total * v_total * fps * 1 sec = pixel clock number of pixels are transmitted. * time taken by one line (h_total) = 1 / (v_total * fps). */ time_taken_by_one_line_us = HDCP2P2_SEC_TO_US / (v_total * fps); 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); ddc_data->intr_mask = RXSTATUS_MESSAGE_SIZE; ddc_data->timer_delay_lines = (u32)mult; ddc_data->timer_delay_lines = lines_needed_for_given_time; ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl); rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, true); if (rc) { pr_err("error reading rxstatus %d\n", rc); goto exit; Loading Loading @@ -568,6 +649,42 @@ exit: kfree(recvd_msg_buf); } static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl) { struct hdmi_tx_ddc_ctrl *ddc_ctrl; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; struct msm_hdmi_mode_timing_info *timing; u32 fps, v_total; u32 time_taken_by_one_line_us; u32 lines_needed_for_given_time; ddc_ctrl = ctrl->init_data.ddc_ctrl; if (!ddc_ctrl) return -EINVAL; hdmi_ddc_config(ddc_ctrl); ddc_data = &ddc_ctrl->hdcp2p2_ddc_data; memset(ddc_data, 0, sizeof(*ddc_data)); timing = ctrl->init_data.timing; 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) * HDCP2P2_MS_TO_US) / time_taken_by_one_line_us; pr_debug("timeout for rxstatus %d\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->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false); } static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work) { struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, Loading Loading @@ -602,7 +719,7 @@ static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work) ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTHENTICATED); /* recheck within 1sec as per hdcp 2.2 standard */ if (!hdmi_hdcp2p2_link_check(ctrl)) schedule_delayed_work(&ctrl->link_check_work, msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS)); } Loading @@ -625,11 +742,9 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, struct hdmi_hdcp2p2_ctrl, link); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; struct hdmi_tx_ddc_ctrl *ddc_ctrl; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; u64 mult; struct msm_hdmi_mode_timing_info *timing; char *recvd_msg_buf = NULL; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; struct hdmi_tx_ddc_ctrl *ddc_ctrl; if (!ctrl) { pr_err("invalid input\n"); Loading @@ -647,26 +762,14 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) goto exit; } hdmi_ddc_config(ddc_ctrl); ddc_data = &ddc_ctrl->hdcp2p2_ddc_data; memset(ddc_data, 0, sizeof(*ddc_data)); timing = ctrl->init_data.timing; mult = hdmi_tx_get_v_total(timing) / 20; ddc_data->intr_mask = RXSTATUS_READY | RXSTATUS_MESSAGE_SIZE | RXSTATUS_REAUTH_REQ; ddc_data->timer_delay_lines = (u32)mult; ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl); rc = hdmi_ddc_check_status(ddc_ctrl); if (rc) { pr_err("error reading rxstatus %d\n", rc); cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; goto exit; } ddc_data = &ddc_ctrl->hdcp2p2_ddc_data; if (ddc_data->reauth_req) { pr_debug("sync reported loss of synchronization, reauth\n"); rc = -ENOLINK; Loading @@ -693,6 +796,8 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS; cdata.recvd_msg_buf = recvd_msg_buf; cdata.recvd_msg_len = ddc_data->message_size; hdmi_hdcp2p2_link_check(ctrl); } } exit: Loading Loading @@ -735,7 +840,8 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work) mutex_unlock(&ctrl->mutex); hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); if (hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata)) hdmi_hdcp2p2_auth_failed(ctrl); } void hdmi_hdcp2p2_deinit(void *input) Loading @@ -758,6 +864,8 @@ void hdmi_hdcp2p2_deinit(void *input) &hdmi_hdcp2p2_fs_attr_group); mutex_destroy(&ctrl->mutex); mutex_destroy(&ctrl->msg_lock); mutex_destroy(&ctrl->wakeup_mutex); kfree(ctrl); } Loading Loading @@ -812,6 +920,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) ctrl->ops = &ops; mutex_init(&ctrl->mutex); mutex_init(&ctrl->msg_lock); mutex_init(&ctrl->wakeup_mutex); rc = hdcp_library_register(&ctrl->lib_ctx, Loading Loading
drivers/misc/hdcp.c +107 −19 Original line number Diff line number Diff line Loading @@ -337,6 +337,7 @@ struct hdcp_lib_handle { void *client_ctx; struct hdcp_client_ops *client_ops; struct mutex hdcp_lock; struct mutex msg_lock; struct mutex wakeup_mutex; enum hdcp_state hdcp_state; enum hdcp_lib_wakeup_cmd wakeup_cmd; Loading Loading @@ -755,6 +756,77 @@ exit: return supported; } static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle) { if (!list_empty(&handle->init.node)) pr_debug("init work queued\n"); if (handle->worker.current_work == &handle->init) pr_debug("init work executing\n"); if (!list_empty(&handle->msg_sent.node)) pr_debug("msg_sent work queued\n"); if (handle->worker.current_work == &handle->msg_sent) pr_debug("msg_sent work executing\n"); if (!list_empty(&handle->msg_recvd.node)) pr_debug("msg_recvd work queued\n"); if (handle->worker.current_work == &handle->msg_recvd) pr_debug("msg_recvd work executing\n"); if (!list_empty(&handle->timeout.node)) pr_debug("timeout work queued\n"); if (handle->worker.current_work == &handle->timeout) pr_debug("timeout work executing\n"); if (!list_empty(&handle->clean.node)) pr_debug("clean work queued\n"); if (handle->worker.current_work == &handle->clean) pr_debug("clean work executing\n"); if (!list_empty(&handle->topology.node)) pr_debug("topology work queued\n"); if (handle->worker.current_work == &handle->topology) pr_debug("topology work executing\n"); if (!list_empty(&handle->stream.node)) pr_debug("stream work queued\n"); if (handle->worker.current_work == &handle->stream) pr_debug("stream work executing\n"); } static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle) { int rc = 0; if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) { if (!list_empty(&handle->worker.work_list)) { hdcp_lib_check_worker_status(handle); rc = -EBUSY; goto exit; } } else { if (atomic_read(&handle->hdcp_off)) { pr_warn("hdcp2.2 session tearing down\n"); goto exit; } if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { pr_err("hdcp 2.2 app not loaded\n"); rc = -EINVAL; goto exit; } } exit: return rc; } static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) { struct hdcp_lib_handle *handle; Loading @@ -770,22 +842,29 @@ 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)); pr_debug("cmd: %s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd)); rc = hdcp_lib_check_valid_state(handle); if (rc) goto exit; mutex_lock(&handle->msg_lock); if (data->recvd_msg_len) { handle->last_msg_recvd_len = data->recvd_msg_len; kzfree(handle->last_msg_recvd_buf); handle->last_msg_recvd_len = data->recvd_msg_len; handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len, GFP_KERNEL); if (!handle->last_msg_recvd_buf) { rc = -ENOMEM; mutex_unlock(&handle->msg_lock); goto exit; } memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf, data->recvd_msg_len); } mutex_unlock(&handle->msg_lock); if (!completion_done(&handle->topo_wait)) complete_all(&handle->topo_wait); Loading @@ -807,24 +886,19 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS: handle->last_msg_sent = handle->listener_buf[0]; if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->msg_sent); break; case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->clean); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->msg_recvd); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->timeout); break; case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: if (!atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->stream); break; default: Loading @@ -832,7 +906,7 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) } exit: mutex_unlock(&handle->wakeup_mutex); return 0; return rc; } static void hdcp_lib_msg_sent_work(struct kthread_work *work) Loading Loading @@ -926,7 +1000,6 @@ exit: if (rc && !atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->clean); return; } static void hdcp_lib_manage_timeout_work(struct kthread_work *work) Loading Loading @@ -1044,18 +1117,29 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) } mutex_lock(&handle->hdcp_lock); cdata.context = handle->client_ctx; msg = handle->last_msg_recvd_buf; mutex_lock(&handle->msg_lock); msglen = handle->last_msg_recvd_len; cdata.context = handle->client_ctx; if (msglen <= 0) { pr_err("invalid msg len\n"); mutex_unlock(&handle->msg_lock); rc = -EINVAL; goto exit; } msg = kzalloc(msglen, GFP_KERNEL); if (!msg) { mutex_unlock(&handle->msg_lock); rc = -ENOMEM; goto exit; } memcpy(msg, handle->last_msg_recvd_buf, msglen); mutex_unlock(&handle->msg_lock); pr_debug("msg received: %s from sink\n", hdcp_lib_message_name((int)msg[0])); Loading Loading @@ -1140,7 +1224,7 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) } exit: kzfree(handle->last_msg_recvd_buf); kzfree(msg); mutex_unlock(&handle->hdcp_lock); hdcp_lib_wakeup_client(handle, &cdata); Loading @@ -1160,7 +1244,6 @@ static void hdcp_lib_topology_work(struct kthread_work *work) return; } reinit_completion(&handle->topo_wait); timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3); if (!timeout) { Loading @@ -1185,6 +1268,9 @@ bool hdcp1_check_if_supported_load_app(void) } } pr_debug("hdcp1 app %s loaded\n", hdcp1_supported ? "successfully" : "not"); return hdcp1_supported; } Loading Loading @@ -1274,6 +1360,7 @@ int hdcp_library_register(void **pphdcpcontext, atomic_set(&handle->hdcp_off, 0); mutex_init(&handle->hdcp_lock); mutex_init(&handle->msg_lock); mutex_init(&handle->wakeup_mutex); init_kthread_worker(&handle->worker); Loading Loading @@ -1326,6 +1413,7 @@ void hdcp_library_deregister(void *phdcpcontext) kthread_stop(handle->thread); kzfree(handle->qseecom_handle); kzfree(handle->last_msg_recvd_buf); mutex_destroy(&handle->hdcp_lock); mutex_destroy(&handle->wakeup_mutex); Loading
drivers/video/msm/mdss/mdss_hdmi_edid.c +10 −10 Original line number Diff line number Diff line Loading @@ -1208,9 +1208,9 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl, u32 pulse_width_v = 0; u32 active_low_h = 0; u32 active_low_v = 0; const u32 khz_to_hz = 1000; u32 frame_data; struct msm_hdmi_mode_timing_info timing = {0}; u64 rr_tmp, frame_data; int rc; /* Loading Loading @@ -1326,15 +1326,10 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl, active_low_h = ((data_buf[0x11] & BIT(1)) && (data_buf[0x11] & BIT(4))) ? 0 : 1; DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__, active_h, active_v, blank_h, blank_v, img_size_h, img_size_v, interlaced ? "i" : "p"); rr_tmp = pixel_clk * 1000 * 1000; frame_data = (blank_h + active_h) * (blank_v + active_v); frame_data = (active_h + blank_h) * (active_v + blank_v); if (frame_data) { do_div(rr_tmp, frame_data); int refresh_rate_khz = (pixel_clk * khz_to_hz) / frame_data; timing.active_h = active_h; timing.front_porch_h = front_porch_h; Loading @@ -1349,13 +1344,18 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl, (front_porch_v + pulse_width_v); timing.active_low_v = active_low_v; timing.pixel_freq = pixel_clk; timing.refresh_rate = (u32) rr_tmp; timing.refresh_rate = refresh_rate_khz * khz_to_hz; timing.interlaced = interlaced; timing.supported = true; timing.ar = aspect_ratio_4_3 ? HDMI_RES_AR_4_3 : (aspect_ratio_5_4 ? HDMI_RES_AR_5_4 : HDMI_RES_AR_16_9); DEV_DBG("%s: new res: %dx%d%s@%dHz\n", __func__, timing.active_h, timing.active_v, interlaced ? "i" : "p", timing.refresh_rate / khz_to_hz); rc = hdmi_set_resv_timing_info(&timing); } else { DEV_ERR("%s: Invalid frame data\n", __func__); Loading
drivers/video/msm/mdss/mdss_hdmi_hdcp.c +29 −22 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -182,17 +183,24 @@ 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; ddc_xfer_done = hdcp_ddc_status & BIT(10); 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, Loading @@ -202,7 +210,6 @@ static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl) 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) Loading
drivers/video/msm/mdss/mdss_hdmi_hdcp.h +4 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,10 @@ enum hdmi_hdcp_state { HDCP_STATE_INACTIVE, HDCP_STATE_AUTHENTICATING, HDCP_STATE_AUTHENTICATED, HDCP_STATE_AUTH_FAIL HDCP_STATE_AUTH_FAIL, HDCP_STATE_AUTH_ENC_NONE, HDCP_STATE_AUTH_ENC_1X, HDCP_STATE_AUTH_ENC_2P2 }; struct hdmi_hdcp_init_data { Loading
drivers/video/msm/mdss/mdss_hdmi_hdcp2p2.c +145 −36 Original line number Diff line number Diff line Loading @@ -36,6 +36,10 @@ #define HDCP2P2_LINK_CHECK_TIME_MS 500 /* link check within 1 sec */ #define HDCP2P2_SEC_TO_US 1000000 #define HDCP2P2_MS_TO_US 1000 #define HDCP2P2_KHZ_TO_HZ 1000 /* * HDCP 2.2 encryption requires the data encryption block that is present in * HDMI controller version 4.0.0 and above Loading @@ -52,6 +56,7 @@ struct hdmi_hdcp2p2_ctrl { enum hdmi_hdcp2p2_sink_status sink_status; /* Is sink connected */ struct hdmi_hdcp_init_data init_data; /* Feature data from HDMI drv */ struct mutex mutex; /* mutex to protect access to ctrl */ struct mutex msg_lock; /* mutex to protect access to msg buffer */ struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/ struct hdmi_hdcp_ops *ops; void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */ Loading Loading @@ -95,18 +100,24 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) 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; kzfree(ctrl->send_msg_buf); ctrl->send_msg_buf = kzalloc( data->send_msg_len, GFP_KERNEL); if (!ctrl->send_msg_buf) 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); } mutex_unlock(&ctrl->msg_lock); switch (ctrl->wakeup_cmd) { case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE: Loading @@ -133,7 +144,7 @@ exit: return 0; } static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, struct hdcp_lib_wakeup_data *data) { int rc = 0; Loading @@ -145,6 +156,8 @@ static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, pr_err("error sending %s to lib\n", hdcp_lib_cmd_to_str(data->cmd)); } return rc; } static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl) Loading Loading @@ -172,6 +185,8 @@ static void hdmi_hdcp2p2_off(void *input) flush_kthread_worker(&ctrl->worker); hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl); cdata.context = input; hdmi_hdcp2p2_wakeup(&cdata); Loading Loading @@ -281,18 +296,48 @@ static ssize_t hdmi_hdcp2p2_sysfs_wta_min_level_change(struct device *dev, hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP2P2); struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE}; bool enc_notify = true; enum hdmi_hdcp_state enc_lvl; int min_enc_lvl; int rc; if (!ctrl) { pr_err("invalid input\n"); return -EINVAL; rc = -EINVAL; goto exit; } pr_debug("notification of minimum level change received\n"); rc = kstrtoint(buf, 10, &min_enc_lvl); if (rc) { DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc); goto exit; } switch (min_enc_lvl) { case 0: enc_lvl = HDCP_STATE_AUTH_ENC_NONE; break; case 1: enc_lvl = HDCP_STATE_AUTH_ENC_1X; break; case 2: enc_lvl = HDCP_STATE_AUTH_ENC_2P2; break; default: enc_notify = false; } pr_debug("enc level changed %d\n", min_enc_lvl); cdata.context = ctrl->lib_ctx; hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); return count; if (enc_notify && ctrl->init_data.notify_status) ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl); rc = count; exit: return rc; } static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl) Loading @@ -304,6 +349,8 @@ static void hdmi_hdcp2p2_auth_failed(struct hdmi_hdcp2p2_ctrl *ctrl) atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl); /* notify hdmi tx about HDCP failure */ ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTH_FAIL); Loading Loading @@ -457,6 +504,8 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, struct hdmi_hdcp2p2_ctrl, send_msg); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; char *msg; uint32_t msglen; if (!ctrl) { pr_err("invalid input\n"); Loading @@ -472,9 +521,25 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) goto exit; } mutex_lock(&ctrl->msg_lock); msglen = ctrl->send_msg_len; if (!msglen) { mutex_unlock(&ctrl->msg_lock); goto exit; } msg = kzalloc(msglen, GFP_KERNEL); if (!msg) { mutex_unlock(&ctrl->msg_lock); goto exit; } memcpy(msg, ctrl->send_msg_buf, msglen); mutex_unlock(&ctrl->msg_lock); /* Forward the message to the sink */ rc = hdmi_hdcp2p2_ddc_write_message(ctrl, ctrl->send_msg_buf, (size_t)ctrl->send_msg_len); rc = hdmi_hdcp2p2_ddc_write_message(ctrl, msg, (size_t)msglen); if (rc) { pr_err("Error sending msg to sink %d\n", rc); cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED; Loading @@ -482,7 +547,7 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS; } exit: kzfree(ctrl->send_msg_buf); kzfree(msg); mutex_unlock(&ctrl->mutex); hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); Loading @@ -491,7 +556,9 @@ exit: static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) { int rc = 0; u64 mult; u32 fps, v_total; u32 time_taken_by_one_line_us; u32 lines_needed_for_given_time; char *recvd_msg_buf = NULL; struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, struct hdmi_hdcp2p2_ctrl, recv_msg); Loading Loading @@ -525,12 +592,26 @@ static void hdmi_hdcp2p2_recv_msg_work(struct kthread_work *work) memset(ddc_data, 0, sizeof(*ddc_data)); timing = ctrl->init_data.timing; mult = hdmi_tx_get_v_total(timing) / 20; fps = timing->refresh_rate / HDCP2P2_KHZ_TO_HZ; v_total = hdmi_tx_get_v_total(timing); /* * pixel clock = h_total * v_total * fps * 1 sec = pixel clock number of pixels are transmitted. * time taken by one line (h_total) = 1 / (v_total * fps). */ time_taken_by_one_line_us = HDCP2P2_SEC_TO_US / (v_total * fps); 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); ddc_data->intr_mask = RXSTATUS_MESSAGE_SIZE; ddc_data->timer_delay_lines = (u32)mult; ddc_data->timer_delay_lines = lines_needed_for_given_time; ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl); rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, true); if (rc) { pr_err("error reading rxstatus %d\n", rc); goto exit; Loading Loading @@ -568,6 +649,42 @@ exit: kfree(recvd_msg_buf); } static int hdmi_hdcp2p2_link_check(struct hdmi_hdcp2p2_ctrl *ctrl) { struct hdmi_tx_ddc_ctrl *ddc_ctrl; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; struct msm_hdmi_mode_timing_info *timing; u32 fps, v_total; u32 time_taken_by_one_line_us; u32 lines_needed_for_given_time; ddc_ctrl = ctrl->init_data.ddc_ctrl; if (!ddc_ctrl) return -EINVAL; hdmi_ddc_config(ddc_ctrl); ddc_data = &ddc_ctrl->hdcp2p2_ddc_data; memset(ddc_data, 0, sizeof(*ddc_data)); timing = ctrl->init_data.timing; 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) * HDCP2P2_MS_TO_US) / time_taken_by_one_line_us; pr_debug("timeout for rxstatus %d\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->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; return hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl, false); } static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work) { struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, Loading Loading @@ -602,7 +719,7 @@ static void hdmi_hdcp2p2_auth_status_work(struct kthread_work *work) ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTHENTICATED); /* recheck within 1sec as per hdcp 2.2 standard */ if (!hdmi_hdcp2p2_link_check(ctrl)) schedule_delayed_work(&ctrl->link_check_work, msecs_to_jiffies(HDCP2P2_LINK_CHECK_TIME_MS)); } Loading @@ -625,11 +742,9 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, struct hdmi_hdcp2p2_ctrl, link); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; struct hdmi_tx_ddc_ctrl *ddc_ctrl; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; u64 mult; struct msm_hdmi_mode_timing_info *timing; char *recvd_msg_buf = NULL; struct hdmi_tx_hdcp2p2_ddc_data *ddc_data; struct hdmi_tx_ddc_ctrl *ddc_ctrl; if (!ctrl) { pr_err("invalid input\n"); Loading @@ -647,26 +762,14 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) goto exit; } hdmi_ddc_config(ddc_ctrl); ddc_data = &ddc_ctrl->hdcp2p2_ddc_data; memset(ddc_data, 0, sizeof(*ddc_data)); timing = ctrl->init_data.timing; mult = hdmi_tx_get_v_total(timing) / 20; ddc_data->intr_mask = RXSTATUS_READY | RXSTATUS_MESSAGE_SIZE | RXSTATUS_REAUTH_REQ; ddc_data->timer_delay_lines = (u32)mult; ddc_data->read_method = HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER; rc = hdmi_hdcp2p2_ddc_read_rxstatus(ddc_ctrl); rc = hdmi_ddc_check_status(ddc_ctrl); if (rc) { pr_err("error reading rxstatus %d\n", rc); cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; goto exit; } ddc_data = &ddc_ctrl->hdcp2p2_ddc_data; if (ddc_data->reauth_req) { pr_debug("sync reported loss of synchronization, reauth\n"); rc = -ENOLINK; Loading @@ -693,6 +796,8 @@ static void hdmi_hdcp2p2_link_work(struct kthread_work *work) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS; cdata.recvd_msg_buf = recvd_msg_buf; cdata.recvd_msg_len = ddc_data->message_size; hdmi_hdcp2p2_link_check(ctrl); } } exit: Loading Loading @@ -735,7 +840,8 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work) mutex_unlock(&ctrl->mutex); hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); if (hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata)) hdmi_hdcp2p2_auth_failed(ctrl); } void hdmi_hdcp2p2_deinit(void *input) Loading @@ -758,6 +864,8 @@ void hdmi_hdcp2p2_deinit(void *input) &hdmi_hdcp2p2_fs_attr_group); mutex_destroy(&ctrl->mutex); mutex_destroy(&ctrl->msg_lock); mutex_destroy(&ctrl->wakeup_mutex); kfree(ctrl); } Loading Loading @@ -812,6 +920,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) ctrl->ops = &ops; mutex_init(&ctrl->mutex); mutex_init(&ctrl->msg_lock); mutex_init(&ctrl->wakeup_mutex); rc = hdcp_library_register(&ctrl->lib_ctx, Loading