diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 76add503b6b8..69ec7127102c 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -160,43 +160,46 @@ static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = { [AKE_INIT_MESSAGE_ID] = { 2, - { {0x69000, 8}, {0x69008, 3} }, + { {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} }, 0 }, [AKE_SEND_CERT_MESSAGE_ID] = { 3, - { {0x6900B, 522}, {0x69215, 8}, {0x6921D, 3} }, + { {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8}, + {"RxCaps", 0x6921D, 3} }, 0 }, [AKE_NO_STORED_KM_MESSAGE_ID] = { 1, - { {0x69220, 128} }, + { {"Ekpub_km", 0x69220, 128} }, 0 }, [AKE_STORED_KM_MESSAGE_ID] = { 2, - { {0x692A0, 16}, {0x692B0, 16} }, + { {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} }, 0 }, [AKE_SEND_H_PRIME_MESSAGE_ID] = { 1, - { {0x692C0, 32} }, + { {"H'", 0x692C0, 32} }, (1 << 1) }, [AKE_SEND_PAIRING_INFO_MESSAGE_ID] = { 1, - { {0x692E0, 16} }, + { {"Ekh_km", 0x692E0, 16} }, (1 << 2) }, [LC_INIT_MESSAGE_ID] = { 1, - { {0x692F0, 8} }, + { {"rn", 0x692F0, 8} }, 0 }, [LC_SEND_L_PRIME_MESSAGE_ID] = { 1, - { {0x692F8, 32} }, + { {"L'", 0x692F8, 32} }, 0 }, [SKE_SEND_EKS_MESSAGE_ID] = { 2, - { {0x69318, 16}, {0x69328, 8} }, + { {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} }, 0 }, [REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4, - { {0x69330, 2}, {0x69332, 3}, {0x69335, 16}, {0x69345, 155} }, + { {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3}, + {"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} }, (1 << 0) }, [REPEATER_AUTH_SEND_ACK_MESSAGE_ID] = { 1, - { {0x693E0, 16} }, + { {"V", 0x693E0, 16} }, 0 }, [REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID] = { 3, - { {0x693F0, 3}, {0x693F3, 2}, {0x693F5, 126} }, + { {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2}, + {"streamID_Type", 0x693F5, 126} }, 0 }, [REPEATER_AUTH_STREAM_READY_MESSAGE_ID] = { 1, - { {0x69473, 32} }, + { {"M'", 0x69473, 32} }, 0 } }; @@ -616,36 +619,59 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle, } } -static inline void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle, - struct hdmi_hdcp_wakeup_data *data) +static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle, + struct hdmi_hdcp_wakeup_data *data) { - int rc = 0; + int rc = 0, i; - if (handle && handle->client_ops && handle->client_ops->wakeup && - data && (data->cmd != HDMI_HDCP_WKUP_CMD_INVALID)) { - data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE; + if (!handle || !handle->client_ops || !handle->client_ops->wakeup || + !data || (data->cmd == HDMI_HDCP_WKUP_CMD_INVALID)) + return; - if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE || - data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE || - data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) { - handle->last_msg = - hdcp_lib_get_next_message(handle, data); + data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE; - if (handle->last_msg > INVALID_MESSAGE_ID && - handle->last_msg < HDCP2P2_MAX_MESSAGES) - data->message_data = - &hdcp_msg_lookup[handle->last_msg]; + if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE || + data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE || + data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) { + handle->last_msg = hdcp_lib_get_next_message(handle, data); + + pr_debug("lib->client: %s (%s)\n", + hdmi_hdcp_cmd_to_str(data->cmd), + hdcp_lib_message_name(handle->last_msg)); + + if (handle->last_msg > INVALID_MESSAGE_ID && + handle->last_msg < HDCP2P2_MAX_MESSAGES) { + u32 msg_num, rx_status; + const struct hdcp_msg_part *msg; + + data->message_data = &hdcp_msg_lookup[handle->last_msg]; + + msg_num = data->message_data->num_messages; + msg = data->message_data->messages; + rx_status = data->message_data->rx_status; + + pr_debug("rxstatus 0x%x\n", rx_status); + pr_debug("%10s | %6s | %4s\n", "name", "offset", "len"); + + for (i = 0; i < msg_num; i++) + pr_debug("%10s | %6x | %4d\n", + msg[i].name, msg[i].offset, + msg[i].length); } - - rc = handle->client_ops->wakeup(data); - if (rc) - pr_err("error sending %s to client\n", - hdmi_hdcp_cmd_to_str(data->cmd)); + } else { + pr_debug("lib->client: %s\n", + hdmi_hdcp_cmd_to_str(data->cmd)); } + + rc = handle->client_ops->wakeup(data); + if (rc) + pr_err("error sending %s to client\n", + hdmi_hdcp_cmd_to_str(data->cmd)); } static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle) { + char msg_name[50]; struct hdmi_hdcp_wakeup_data cdata = { HDMI_HDCP_WKUP_CMD_SEND_MESSAGE }; @@ -655,6 +681,13 @@ static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle) cdata.send_msg_len = handle->msglen; cdata.timeout = handle->hdcp_timeout; + snprintf(msg_name, sizeof(msg_name), "%s: ", + hdcp_lib_message_name((int)cdata.send_msg_buf[0])); + + print_hex_dump(KERN_DEBUG, msg_name, + DUMP_PREFIX_NONE, 16, 1, cdata.send_msg_buf, + cdata.send_msg_len, false); + hdcp_lib_wakeup_client(handle, &cdata); } @@ -1486,6 +1519,7 @@ static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle) if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) { if (!list_empty(&handle->worker.work_list)) { + pr_debug("error: queue not empty\n"); rc = -EBUSY; goto exit; } @@ -1543,9 +1577,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) handle->wakeup_cmd = data->cmd; handle->timeout_left = data->timeout; - pr_debug("%s, timeout left: %dms, tethered %d\n", - hdcp_lib_cmd_to_str(handle->wakeup_cmd), - handle->timeout_left, handle->tethered); + pr_debug("client->lib: %s\n", + hdcp_lib_cmd_to_str(handle->wakeup_cmd)); rc = hdcp_lib_check_valid_state(handle); if (rc) @@ -1599,6 +1632,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) break; case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: + case HDCP_LIB_WKUP_CMD_LINK_FAILED: + handle->hdcp_state |= HDCP_STATE_ERROR; HDCP_LIB_EXECUTE(clean); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: @@ -1825,7 +1860,7 @@ static void hdcp_lib_clean(struct hdcp_lib_handle *handle) if (!handle) { pr_err("invalid input\n"); return; - }; + } hdcp_lib_txmtr_deinit(handle); if (!handle->legacy_app) @@ -1859,6 +1894,7 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) struct hdcp_rcvd_msg_rsp *rsp_buf; uint32_t msglen; char *msg = NULL; + char msg_name[50]; uint32_t message_id_bytes = 0; if (!handle || !handle->qseecom_handle || @@ -1907,8 +1943,11 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) mutex_unlock(&handle->msg_lock); - pr_debug("msg received: %s from sink\n", - hdcp_lib_message_name((int)msg[0])); + snprintf(msg_name, sizeof(msg_name), "%s: ", + hdcp_lib_message_name((int)msg[0])); + + print_hex_dump(KERN_DEBUG, msg_name, + DUMP_PREFIX_NONE, 16, 1, msg, msglen, false); /* send the message to QSEECOM */ req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf); @@ -1989,13 +2028,8 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle) handle->hdcp_timeout = rsp_buf->timeout; handle->msglen = rsp_buf->msglen; - if (!atomic_read(&handle->hdcp_off)) { - cdata.cmd = HDMI_HDCP_WKUP_CMD_SEND_MESSAGE; - cdata.send_msg_buf = handle->listener_buf; - cdata.send_msg_len = handle->msglen; - cdata.timeout = handle->hdcp_timeout; - } - + if (!atomic_read(&handle->hdcp_off)) + hdcp_lib_send_message(handle); exit: kzfree(msg); @@ -2026,6 +2060,16 @@ static void hdcp_lib_topology_work(struct kthread_work *work) return; } + if (atomic_read(&handle->hdcp_off)) { + pr_debug("invalid state: hdcp off\n"); + return; + } + + if (handle->hdcp_state & HDCP_STATE_ERROR) { + pr_debug("invalid state: hdcp error\n"); + return; + } + reinit_completion(&handle->topo_wait); timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3); if (!timeout) { diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index fa2e47e06503..75e42ca8cd88 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -57,6 +57,10 @@ static u32 supported_modes[] = { HDMI_VFRMT_4096x2160p60_256_135, HDMI_EVFRMT_4096x2160p24_16_9 }; +static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv); +static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata); +static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp); + static void mdss_dp_put_dt_clk_data(struct device *dev, struct dss_module_power *module_power) { @@ -902,8 +906,6 @@ static int dp_audio_info_setup(struct platform_device *pdev, mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt); mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true); - dp_ctrl->wait_for_audio_comp = true; - return rc; } /* dp_audio_info_setup */ @@ -926,17 +928,6 @@ static int dp_get_audio_edid_blk(struct platform_device *pdev, return rc; } /* dp_get_audio_edid_blk */ -static void dp_audio_codec_teardown_done(struct platform_device *pdev) -{ - struct mdss_dp_drv_pdata *dp = platform_get_drvdata(pdev); - - if (!dp) - pr_err("invalid input\n"); - - pr_debug("audio codec teardown done\n"); - complete_all(&dp->audio_comp); -} - static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp) { int ret = 0; @@ -958,8 +949,6 @@ static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp) dp_get_audio_edid_blk; dp->ext_audio_data.codec_ops.cable_status = dp_get_cable_status; - dp->ext_audio_data.codec_ops.teardown_done = - dp_audio_codec_teardown_done; if (!dp->pdev->dev.of_node) { pr_err("%s cannot find dp dev.of_node\n", __func__); @@ -1040,12 +1029,10 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) return 0; } /* dp_init_panel_info */ -static inline void mdss_dp_set_audio_switch_node( - struct mdss_dp_drv_pdata *dp, int val) +static inline void mdss_dp_ack_state(struct mdss_dp_drv_pdata *dp, int val) { if (dp && dp->ext_audio_data.intf_ops.notify) - dp->ext_audio_data.intf_ops.notify(dp->ext_pdev, - val); + dp->ext_audio_data.intf_ops.notify(dp->ext_pdev, val); } /** @@ -1156,19 +1143,27 @@ static void mdss_dp_configure_source_params(struct mdss_dp_drv_pdata *dp, * * Initiates training of the DP main link and checks the state of the main * link after the training is complete. + * + * Return: error code. -EINVAL if any invalid data or -EAGAIN if retraining + * is required. */ -static void mdss_dp_train_main_link(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_train_main_link(struct mdss_dp_drv_pdata *dp) { + int ret = 0; int ready = 0; pr_debug("enter\n"); + ret = mdss_dp_link_train(dp); + if (ret) + goto end; - mdss_dp_link_train(dp); mdss_dp_wait4train(dp); ready = mdss_dp_mainlink_ready(dp, BIT(0)); pr_debug("main link %s\n", ready ? "READY" : "NOT READY"); +end: + return ret; } static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv) @@ -1178,33 +1173,43 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv) struct lane_mapping ln_map; /* wait until link training is completed */ - mutex_lock(&dp_drv->train_mutex); - pr_debug("enter\n"); - orientation = usbpd_get_plug_orientation(dp_drv->pd); - pr_debug("plug orientation = %d\n", orientation); + do { + if (ret == -EAGAIN) { + mdss_dp_mainlink_push_idle(&dp_drv->panel_data); + mdss_dp_off_irq(dp_drv); + } - ret = mdss_dp_get_lane_mapping(dp_drv, orientation, &ln_map); - if (ret) - goto exit; + mutex_lock(&dp_drv->train_mutex); - mdss_dp_phy_share_lane_config(&dp_drv->phy_io, - orientation, dp_drv->dpcd.max_lane_count); + orientation = usbpd_get_plug_orientation(dp_drv->pd); + pr_debug("plug orientation = %d\n", orientation); - ret = mdss_dp_enable_mainlink_clocks(dp_drv); - if (ret) - goto exit; + ret = mdss_dp_get_lane_mapping(dp_drv, orientation, &ln_map); + if (ret) + goto exit; - mdss_dp_mainlink_reset(&dp_drv->ctrl_io); + mdss_dp_phy_share_lane_config(&dp_drv->phy_io, + orientation, dp_drv->dpcd.max_lane_count); - reinit_completion(&dp_drv->idle_comp); + ret = mdss_dp_enable_mainlink_clocks(dp_drv); + if (ret) + goto exit; - mdss_dp_configure_source_params(dp_drv, &ln_map); + mdss_dp_mainlink_reset(&dp_drv->ctrl_io); - mdss_dp_train_main_link(dp_drv); + reinit_completion(&dp_drv->idle_comp); + + mdss_dp_configure_source_params(dp_drv, &ln_map); + + dp_drv->power_on = true; + + ret = mdss_dp_train_main_link(dp_drv); + + mutex_unlock(&dp_drv->train_mutex); + } while (ret == -EAGAIN); - dp_drv->power_on = true; pr_debug("end\n"); exit: @@ -1273,12 +1278,19 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) mdss_dp_configure_source_params(dp_drv, &ln_map); link_training: - mdss_dp_train_main_link(dp_drv); + dp_drv->power_on = true; + + if (-EAGAIN == mdss_dp_train_main_link(dp_drv)) { + mutex_unlock(&dp_drv->train_mutex); + + mdss_dp_link_retraining(dp_drv); + return 0; + } dp_drv->cont_splash = 0; dp_drv->power_on = true; - mdss_dp_set_audio_switch_node(dp_drv, true); + mdss_dp_ack_state(dp_drv, true); pr_debug("End-\n"); exit: @@ -1311,6 +1323,12 @@ static inline bool mdss_dp_is_link_status_updated(struct mdss_dp_drv_pdata *dp) return dp->link_status.link_status_updated; } +static inline bool mdss_dp_is_downstream_port_status_changed( + struct mdss_dp_drv_pdata *dp) +{ + return dp->link_status.downstream_port_status_changed; +} + static inline bool mdss_dp_is_link_training_requested( struct mdss_dp_drv_pdata *dp) { @@ -1390,6 +1408,7 @@ static int mdss_dp_off_hpd(struct mdss_dp_drv_pdata *dp_drv) dp_drv->dp_initialized = false; dp_drv->power_on = false; + mdss_dp_ack_state(dp_drv, false); mutex_unlock(&dp_drv->train_mutex); pr_debug("DP off done\n"); @@ -1413,52 +1432,30 @@ int mdss_dp_off(struct mdss_panel_data *pdata) return mdss_dp_off_hpd(dp); } -static void mdss_dp_send_cable_notification( +static int mdss_dp_send_cable_notification( struct mdss_dp_drv_pdata *dp, int val) { + int ret = 0; if (!dp) { DEV_ERR("%s: invalid input\n", __func__); - return; + ret = -EINVAL; + goto end; } if (dp && dp->ext_audio_data.intf_ops.hpd) - dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, + ret = dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, dp->ext_audio_data.type, val); + +end: + return ret; } -static void mdss_dp_audio_codec_wait(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable) { - const int audio_completion_timeout_ms = HZ * 3; - int ret = 0; - - if (!dp->wait_for_audio_comp) - return; - - reinit_completion(&dp->audio_comp); - ret = wait_for_completion_timeout(&dp->audio_comp, - audio_completion_timeout_ms); - if (ret <= 0) - pr_warn("audio codec teardown timed out\n"); - - dp->wait_for_audio_comp = false; + return mdss_dp_send_cable_notification(dp, enable); } -static void mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable) -{ - if (enable) { - mdss_dp_send_cable_notification(dp, enable); - } else { - mdss_dp_set_audio_switch_node(dp, enable); - mdss_dp_audio_codec_wait(dp); - mdss_dp_send_cable_notification(dp, enable); - } - - pr_debug("notify state %s done\n", - enable ? "ENABLE" : "DISABLE"); -} - - static int mdss_dp_edid_init(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; @@ -1614,22 +1611,18 @@ end: return rc; } -static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status) +static void mdss_dp_hdcp_cb_work(struct work_struct *work) { - struct mdss_dp_drv_pdata *dp = ptr; + struct mdss_dp_drv_pdata *dp; + struct delayed_work *dw = to_delayed_work(work); struct hdcp_ops *ops; int rc = 0; - if (!dp) { - pr_debug("invalid input\n"); - return; - } + dp = container_of(dw, struct mdss_dp_drv_pdata, hdcp_cb_work); ops = dp->hdcp.ops; - mutex_lock(&dp->train_mutex); - - switch (status) { + switch (dp->hdcp_status) { case HDCP_STATE_AUTHENTICATED: pr_debug("hdcp authenticated\n"); dp->hdcp.auth_state = true; @@ -1652,8 +1645,20 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status) default: break; } +} - mutex_unlock(&dp->train_mutex); +static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status) +{ + struct mdss_dp_drv_pdata *dp = ptr; + + if (!dp) { + pr_err("invalid input\n"); + return; + } + + dp->hdcp_status = status; + + queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4); } static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata) @@ -1691,19 +1696,19 @@ static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata) hdcp_init_data.sec_access = true; hdcp_init_data.client_id = HDCP_CLIENT_DP; - dp_drv->hdcp.data = hdcp_1x_init(&hdcp_init_data); - if (IS_ERR_OR_NULL(dp_drv->hdcp.data)) { + dp_drv->hdcp.hdcp1 = hdcp_1x_init(&hdcp_init_data); + if (IS_ERR_OR_NULL(dp_drv->hdcp.hdcp1)) { pr_err("Error hdcp init\n"); rc = -EINVAL; goto error; } - dp_drv->panel_data.panel_info.hdcp_1x_data = dp_drv->hdcp.data; + dp_drv->panel_data.panel_info.hdcp_1x_data = dp_drv->hdcp.hdcp1; pr_debug("HDCP 1.3 initialized\n"); dp_drv->hdcp.hdcp2 = dp_hdcp2p2_init(&hdcp_init_data); - if (!IS_ERR_OR_NULL(dp_drv->hdcp.data)) + if (!IS_ERR_OR_NULL(dp_drv->hdcp.hdcp2)) pr_debug("HDCP 2.2 initialized\n"); dp_drv->hdcp.feature_enabled = true; @@ -1882,6 +1887,13 @@ static void mdss_dp_update_hdcp_info(struct mdss_dp_drv_pdata *dp) dp->hdcp.ops = ops; } +static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv) +{ + return dp_drv->hdcp.feature_enabled && + (dp_drv->hdcp.hdcp1_present || dp_drv->hdcp.hdcp2_present) && + dp_drv->hdcp.ops; +} + static int mdss_dp_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -1913,8 +1925,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, rc = mdss_dp_off(pdata); break; case MDSS_EVENT_BLANK: - if (dp->hdcp.ops && dp->hdcp.ops->off) + if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) { + flush_delayed_work(&dp->hdcp_cb_work); dp->hdcp.ops->off(dp->hdcp.data); + } mdss_dp_mainlink_push_idle(pdata); break; @@ -2191,6 +2205,11 @@ irqreturn_t dp_isr(int irq, void *ptr) dp_aux_native_handler(dp, isr1); } + if (dp->hdcp.ops && dp->hdcp.ops->isr) { + if (dp->hdcp.ops->isr(dp->hdcp.data)) + pr_err("dp_hdcp_isr failed\n"); + } + return IRQ_HANDLED; } @@ -2205,6 +2224,7 @@ static int mdss_dp_event_setup(struct mdss_dp_drv_pdata *dp) } INIT_WORK(&dp->work, mdss_dp_event_work); + INIT_DELAYED_WORK(&dp->hdcp_cb_work, mdss_dp_hdcp_cb_work); return 0; } @@ -2307,14 +2327,20 @@ static int mdss_dp_hpd_irq_notify_clients(struct mdss_dp_drv_pdata *dp) int ret = 0; if (dp->hpd_irq_toggled) { - mdss_dp_notify_clients(dp, false); + dp->hpd_irq_clients_notified = true; - reinit_completion(&dp->irq_comp); - ret = wait_for_completion_timeout(&dp->irq_comp, - irq_comp_timeout); - if (ret <= 0) { - pr_warn("irq_comp timed out\n"); - return -EINVAL; + ret = mdss_dp_notify_clients(dp, false); + + if (!IS_ERR_VALUE(ret) && ret) { + reinit_completion(&dp->irq_comp); + ret = wait_for_completion_timeout(&dp->irq_comp, + irq_comp_timeout); + if (ret <= 0) { + pr_warn("irq_comp timed out\n"); + ret = -EINVAL; + } else { + ret = 0; + } } } @@ -2344,19 +2370,24 @@ static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp) * This function will check for changes in the link status, e.g. clock * recovery done on all lanes, and trigger link training if there is a * failure/error on the link. + * + * The function will return 0 if the a link status update has been processed, + * otherwise it will return -EINVAL. */ -static void mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp) { if (!mdss_dp_is_link_status_updated(dp) || (mdss_dp_aux_channel_eq_done(dp) && mdss_dp_aux_clock_recovery_done(dp))) - return; + return -EINVAL; pr_info("channel_eq_done = %d, clock_recovery_done = %d\n", mdss_dp_aux_channel_eq_done(dp), mdss_dp_aux_clock_recovery_done(dp)); mdss_dp_link_retraining(dp); + + return 0; } /** @@ -2366,11 +2397,14 @@ static void mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp) * This function will handle new link training requests that are initiated by * the sink. In particular, it will update the requested lane count and link * link rate, and then trigger the link retraining procedure. + * + * The function will return 0 if a link training request has been processed, + * otherwise it will return -EINVAL. */ -static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp) { if (!mdss_dp_is_link_training_requested(dp)) - return; + return -EINVAL; mdss_dp_send_test_response(dp); @@ -2383,6 +2417,28 @@ static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp) dp->link_rate = dp->test_data.test_link_rate; mdss_dp_link_retraining(dp); + + return 0; +} + +/** + * mdss_dp_process_downstream_port_status_change() - process port status changes + * @dp: Display Port Driver data + * + * This function will handle downstream port updates that are initiated by + * the sink. If the downstream port status has changed, the EDID is read via + * AUX. + * + * The function will return 0 if a downstream port update has been + * processed, otherwise it will return -EINVAL. + */ +static int mdss_dp_process_downstream_port_status_change( + struct mdss_dp_drv_pdata *dp) +{ + if (!mdss_dp_is_downstream_port_status_changed(dp)) + return -EINVAL; + + return mdss_dp_edid_read(dp); } /** @@ -2393,21 +2449,31 @@ static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp) * (including cases when there are back to back HPD IRQ HIGH) indicating * the start of a new link training request or sink status update. */ -static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) { - pr_debug("enter: HPD IRQ High\n"); + int ret = 0; dp->hpd_irq_on = true; mdss_dp_aux_parse_sink_status_field(dp); - mdss_dp_process_link_training_request(dp); + ret = mdss_dp_process_link_training_request(dp); + if (!ret) + goto exit; - mdss_dp_process_link_status_update(dp); + ret = mdss_dp_process_link_status_update(dp); + if (!ret) + goto exit; - mdss_dp_reset_test_data(dp); + ret = mdss_dp_process_downstream_port_status_change(dp); + if (!ret) + goto exit; pr_debug("done\n"); +exit: + mdss_dp_reset_test_data(dp); + + return ret; } /** @@ -2417,11 +2483,15 @@ static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp) * This function will handle the HPD IRQ state transitions from HIGH to LOW, * indicating the end of a test request. */ -static void mdss_dp_process_hpd_irq_low(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_process_hpd_irq_low(struct mdss_dp_drv_pdata *dp) { + if (!dp->hpd_irq_clients_notified) + return -EINVAL; + pr_debug("enter: HPD IRQ low\n"); dp->hpd_irq_on = false; + dp->hpd_irq_clients_notified = false; mdss_dp_update_cable_status(dp, false); mdss_dp_mainlink_push_idle(&dp->panel_data); @@ -2430,6 +2500,7 @@ static void mdss_dp_process_hpd_irq_low(struct mdss_dp_drv_pdata *dp) mdss_dp_reset_test_data(dp); pr_debug("done\n"); + return 0; } static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, @@ -2471,14 +2542,17 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, dp_drv->alt_mode.dp_status.hpd_irq; if (dp_drv->alt_mode.dp_status.hpd_irq) { - mdss_dp_process_hpd_irq_high(dp_drv); - break; - } + pr_debug("Attention: hpd_irq high\n"); - if (dp_drv->hpd_irq_toggled - && !dp_drv->alt_mode.dp_status.hpd_irq) { - mdss_dp_process_hpd_irq_low(dp_drv); - break; + if (dp_drv->power_on && dp_drv->hdcp.ops && + dp_drv->hdcp.ops->cp_irq) + dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data); + + if (!mdss_dp_process_hpd_irq_high(dp_drv)) + break; + } else if (dp_drv->hpd_irq_toggled) { + if (!mdss_dp_process_hpd_irq_low(dp_drv)) + break; } if (!dp_drv->alt_mode.dp_status.hpd_high) { @@ -2500,9 +2574,6 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, else dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE); - if (dp_drv->alt_mode.dp_status.hpd_irq && dp_drv->power_on && - dp_drv->hdcp.ops && dp_drv->hdcp.ops->isr) - dp_drv->hdcp.ops->isr(dp_drv->hdcp.data); break; case DP_VDM_STATUS: dp_drv->alt_mode.dp_status.response = *vdos; @@ -2677,10 +2748,8 @@ static int mdss_dp_probe(struct platform_device *pdev) mdss_dp_device_register(dp_drv); dp_drv->inited = true; - dp_drv->wait_for_audio_comp = false; dp_drv->hpd_irq_on = false; mdss_dp_reset_test_data(dp_drv); - init_completion(&dp_drv->audio_comp); init_completion(&dp_drv->irq_comp); pr_debug("done\n"); @@ -2718,13 +2787,6 @@ void *mdss_dp_get_hdcp_data(struct device *dev) return dp_drv->hdcp.data; } -static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv) -{ - return dp_drv->hdcp.feature_enabled && - (dp_drv->hdcp.hdcp1_present || dp_drv->hdcp.hdcp2_present) && - dp_drv->hdcp.ops; -} - static inline bool dp_is_stream_shareable(struct mdss_dp_drv_pdata *dp_drv) { bool ret = 0; diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index 4ba2d20d4261..e801eceeef1b 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -228,6 +228,18 @@ struct dp_alt_mode { #define DP_LINK_RATE_MULTIPLIER 27000000 #define DP_MAX_PIXEL_CLK_KHZ 675000 +struct downstream_port_config { + /* Byte 02205h */ + bool dfp_present; + u32 dfp_type; + bool format_conversion; + bool detailed_cap_info_available; + /* Byte 02207h */ + u32 dfp_count; + bool msa_timing_par_ignored; + bool oui_support; +}; + struct dpcd_cap { char major; char minor; @@ -240,6 +252,7 @@ struct dpcd_cap { u32 flags; u32 rx_port0_buf_size; u32 training_read_interval;/* us */ + struct downstream_port_config downstream_port; }; struct dpcd_link_status { @@ -437,7 +450,6 @@ struct mdss_dp_drv_pdata { struct completion train_comp; struct completion idle_comp; struct completion video_comp; - struct completion audio_comp; struct completion irq_comp; struct mutex aux_mutex; struct mutex train_mutex; @@ -463,13 +475,14 @@ struct mdss_dp_drv_pdata { char delay_start; u32 bpp; struct dp_statistic dp_stat; - bool wait_for_audio_comp; bool hpd_irq_on; bool hpd_irq_toggled; + bool hpd_irq_clients_notified; /* event */ struct workqueue_struct *workq; struct work_struct work; + struct delayed_work hdcp_cb_work; u32 current_event; spinlock_t event_lock; spinlock_t lock; @@ -480,6 +493,7 @@ struct mdss_dp_drv_pdata { u32 vic; u32 new_vic; int fb_node; + int hdcp_status; struct dpcd_test_request test_data; struct dpcd_sink_count sink_count; diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index 91066662e793..9014e3a02d21 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -801,6 +801,8 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, cap = &ep->dpcd; bp = rp->data; + memset(cap, 0, sizeof(*cap)); + data = *bp++; /* byte 0 */ cap->major = (data >> 4) & 0x0f; cap->minor = data & 0x0f; @@ -819,8 +821,13 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, if (data & BIT(7)) cap->enhanced_frame++; - if (data & 0x40) + if (data & 0x40) { cap->flags |= DPCD_TPS3; + pr_debug("pattern 3 supported\n"); + } else { + pr_debug("pattern 3 not supported\n"); + } + data &= 0x0f; cap->max_lane_count = data; if (--rlen <= 0) @@ -846,11 +853,36 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, if (--rlen <= 0) return; - bp += 3; /* skip 5, 6 and 7 */ - rlen -= 3; + data = *bp++; /* Byte 5: DOWN_STREAM_PORT_PRESENT */ + cap->downstream_port.dfp_present = data & BIT(0); + cap->downstream_port.dfp_type = data & 0x6; + cap->downstream_port.format_conversion = data & BIT(3); + cap->downstream_port.detailed_cap_info_available = data & BIT(4); + pr_debug("dfp_present = %d, dfp_type = %d\n", + cap->downstream_port.dfp_present, + cap->downstream_port.dfp_type); + pr_debug("format_conversion = %d, detailed_cap_info_available = %d\n", + cap->downstream_port.format_conversion, + cap->downstream_port.detailed_cap_info_available); + if (--rlen <= 0) + return; + + bp += 1; /* Skip Byte 6 */ + rlen -= 1; if (rlen <= 0) return; + data = *bp++; /* Byte 7: DOWN_STREAM_PORT_COUNT */ + cap->downstream_port.dfp_count = data & 0x7; + cap->downstream_port.msa_timing_par_ignored = data & BIT(6); + cap->downstream_port.oui_support = data & BIT(7); + pr_debug("dfp_count = %d, msa_timing_par_ignored = %d\n", + cap->downstream_port.dfp_count, + cap->downstream_port.msa_timing_par_ignored); + pr_debug("oui_support = %d\n", cap->downstream_port.oui_support); + if (--rlen <= 0) + return; + data = *bp++; /* byte 8 */ if (data & BIT(1)) { cap->flags |= DPCD_PORT_0_EDID_PRESENTED; @@ -861,7 +893,7 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, data = *bp++; /* byte 9 */ cap->rx_port0_buf_size = (data + 1) * 32; - pr_debug("lane_buf_size=%d", cap->rx_port0_buf_size); + pr_debug("lane_buf_size=%d\n", cap->rx_port0_buf_size); if (--rlen <= 0) return; @@ -1431,6 +1463,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep) int tries, old_v_level; int ret = 0; int usleep_time; + int const maximum_retries = 5; pr_debug("Entered++"); @@ -1458,7 +1491,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep) if (old_v_level == ep->v_level) { tries++; - if (tries >= 5) { + if (tries >= maximum_retries) { ret = -1; break; /* quit */ } @@ -1480,6 +1513,7 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) int ret = 0; int usleep_time; char pattern; + int const maximum_retries = 5; pr_debug("Entered++"); @@ -1505,7 +1539,7 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) } tries++; - if (tries > 4) { + if (tries > maximum_retries) { ret = -1; break; } @@ -1518,47 +1552,27 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) static int dp_link_rate_down_shift(struct mdss_dp_drv_pdata *ep) { - u32 prate, lrate; - int rate, lane, max_lane; - int changed = 0; + int ret = 0; - rate = ep->link_rate; - lane = ep->lane_cnt; - max_lane = ep->dpcd.max_lane_count; + if (!ep) + return -EINVAL; - prate = ep->pixel_rate; - prate /= 1000; /* avoid using 64 biits */ - prate *= ep->bpp; - prate /= 8; /* byte */ + switch (ep->link_rate) { + case DP_LINK_RATE_540: + ep->link_rate = DP_LINK_RATE_270; + break; + case DP_LINK_RATE_270: + ep->link_rate = DP_LINK_RATE_162; + break; + case DP_LINK_RATE_162: + default: + ret = -EINVAL; + break; + }; - if (rate > DP_LINK_RATE_162 && rate <= DP_LINK_RATE_MAX) { - rate -= 4; /* reduce rate */ - changed++; - } + pr_debug("new rate=%d\n", ep->link_rate); - if (changed) { - if (lane >= 1 && lane < max_lane) - lane <<= 1; /* increase lane */ - - lrate = 270000000; /* 270M */ - lrate /= 1000; /* avoid using 64 bits */ - lrate *= rate; - lrate /= 10; /* byte, 10 bits --> 8 bits */ - lrate *= lane; - - pr_debug("new lrate=%u prate=%u rate=%d lane=%d p=%d b=%d\n", - lrate, prate, rate, lane, ep->pixel_rate, ep->bpp); - - if (lrate > prate) { - ep->link_rate = rate; - ep->lane_cnt = lane; - pr_debug("new rate=%d %d\n", rate, lane); - return 0; - } - } - - /* add calculation later */ - return -EINVAL; + return ret; } int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state) @@ -1595,7 +1609,6 @@ int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp) mdss_dp_aux_set_sink_power_state(dp, SINK_POWER_ON); -train_start: dp->v_level = 0; /* start from default level */ dp->p_level = 0; mdss_dp_config_ctrl(dp); @@ -1605,11 +1618,12 @@ train_start: ret = dp_start_link_train_1(dp); if (ret < 0) { - if (dp_link_rate_down_shift(dp) == 0) { - goto train_start; + if (!dp_link_rate_down_shift(dp)) { + pr_debug("retry with lower rate\n"); + return -EAGAIN; } else { pr_err("Training 1 failed\n"); - ret = -1; + ret = -EINVAL; goto clear; } } @@ -1618,21 +1632,21 @@ train_start: ret = dp_start_link_train_2(dp); if (ret < 0) { - if (dp_link_rate_down_shift(dp) == 0) { - goto train_start; + if (!dp_link_rate_down_shift(dp)) { + pr_debug("retry with lower rate\n"); + return -EAGAIN; } else { pr_err("Training 2 failed\n"); - ret = -1; + ret = -EINVAL; goto clear; } } pr_debug("Training 2 completed successfully\n"); - clear: dp_clear_training_pattern(dp); - if (ret != -1) { + if (ret != -EINVAL) { mdss_dp_setup_tr_unit(&dp->ctrl_io, dp->link_rate, dp->lane_cnt, dp->vic); mdss_dp_state_ctrl(&dp->ctrl_io, ST_SEND_VIDEO); diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c index 3891806b09bb..79cd94cfbe88 100644 --- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c @@ -53,7 +53,6 @@ struct dp_hdcp2p2_ctrl { struct kthread_work send_msg; struct kthread_work recv_msg; struct kthread_work link; - struct kthread_work poll; char *msg_buf; uint32_t send_msg_len; /* length of all parameters in msg */ uint32_t timeout; @@ -67,26 +66,6 @@ struct dp_hdcp2p2_ctrl { bool polling; }; -static inline char *dp_hdcp_cmd_to_str(uint32_t cmd) -{ - switch (cmd) { - case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE: - return "HDMI_HDCP_WKUP_CMD_SEND_MESSAGE"; - case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE: - return "HDMI_HDCP_WKUP_CMD_RECV_MESSAGE"; - case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS: - return "HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS"; - case HDMI_HDCP_WKUP_CMD_STATUS_FAILED: - return "DP_HDCP_WKUP_CMD_STATUS_FAIL"; - case HDMI_HDCP_WKUP_CMD_LINK_POLL: - return "HDMI_HDCP_WKUP_CMD_LINK_POLL"; - case HDMI_HDCP_WKUP_CMD_AUTHENTICATE: - return "HDMI_HDCP_WKUP_CMD_AUTHENTICATE"; - default: - return "???"; - } -} - static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl) { if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE) @@ -193,7 +172,7 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) queue_kthread_work(&ctrl->worker, &ctrl->status); break; case HDMI_HDCP_WKUP_CMD_LINK_POLL: - queue_kthread_work(&ctrl->worker, &ctrl->poll); + ctrl->polling = true; break; case HDMI_HDCP_WKUP_CMD_AUTHENTICATE: queue_kthread_work(&ctrl->worker, &ctrl->auth); @@ -203,10 +182,11 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) } exit: mutex_unlock(&ctrl->wakeup_mutex); + return 0; } -static inline int dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl, +static inline void dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl, struct hdcp_lib_wakeup_data *data) { int rc = 0; @@ -218,8 +198,6 @@ static inline int dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl, pr_err("error sending %s to lib\n", hdcp_lib_cmd_to_str(data->cmd)); } - - return rc; } static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) @@ -339,8 +317,6 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl) return; } - atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); - /* notify DP about HDCP failure */ ctrl->init_data.notify_status(ctrl->init_data.cb_data, HDCP_STATE_AUTH_FAIL); @@ -349,8 +325,7 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl) static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl, u8 *buf, int size, int offset, u32 timeout) { - int rc, max_size = 16, read_size, len = size; - u8 *buf_start = buf; + int rc, max_size = 16, read_size; if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { pr_err("hdcp is off\n"); @@ -378,8 +353,6 @@ static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl, size -= read_size; } while (size > 0); - print_hex_dump(KERN_DEBUG, "hdcp2p2: ", DUMP_PREFIX_NONE, - 16, 1, buf_start, len, false); return rc; } @@ -452,12 +425,9 @@ end: static void dp_hdcp2p2_send_msg_work(struct kthread_work *work) { int rc = 0; - int i; - int sent_bytes = 0; struct dp_hdcp2p2_ctrl *ctrl = container_of(work, struct dp_hdcp2p2_ctrl, send_msg); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; - char *buf = NULL; if (!ctrl) { pr_err("invalid input\n"); @@ -474,20 +444,13 @@ static void dp_hdcp2p2_send_msg_work(struct kthread_work *work) mutex_lock(&ctrl->msg_lock); - /* Loop through number of parameters in the messages. */ - for (i = 0; i < ctrl->num_messages; i++) { - buf = ctrl->msg_buf + sent_bytes; - - /* Forward the message to the sink */ - rc = dp_hdcp2p2_aux_write_message(ctrl, buf, - (size_t)ctrl->msg_part[i].length, - ctrl->msg_part[i].offset, ctrl->timeout); - if (rc) { - pr_err("Error sending msg to sink %d\n", rc); - mutex_unlock(&ctrl->msg_lock); - goto exit; - } - sent_bytes += ctrl->msg_part[i].length; + rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->msg_buf, + ctrl->send_msg_len, ctrl->msg_part->offset, + ctrl->timeout); + if (rc) { + pr_err("Error sending msg to sink %d\n", rc); + mutex_unlock(&ctrl->msg_lock); + goto exit; } cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS; @@ -505,10 +468,9 @@ exit: static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl) { - int i, rc = 0; + int rc = 0; char *recvd_msg_buf = NULL; struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID }; - int bytes_read = 0; cdata.context = ctrl->lib_ctx; @@ -518,17 +480,12 @@ static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl) goto exit; } - for (i = 0; i < ctrl->num_messages; i++) { - rc = dp_hdcp2p2_aux_read_message( - ctrl, recvd_msg_buf + bytes_read, - ctrl->msg_part[i].length, - ctrl->msg_part[i].offset, - ctrl->timeout); - if (rc) { - pr_err("error reading message %d\n", rc); - goto exit; - } - bytes_read += ctrl->msg_part[i].length; + rc = dp_hdcp2p2_aux_read_message(ctrl, recvd_msg_buf, + ctrl->send_msg_len, ctrl->msg_part->offset, + ctrl->timeout); + if (rc) { + pr_err("error reading message %d\n", rc); + goto exit; } cdata.recvd_msg_buf = recvd_msg_buf; @@ -550,7 +507,6 @@ exit: static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work) { - int rc = 0; struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID }; struct dp_hdcp2p2_ctrl *ctrl = container_of(work, struct dp_hdcp2p2_ctrl, recv_msg); @@ -559,44 +515,24 @@ static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work) if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { pr_err("hdcp is off\n"); - goto exit; + return; } - if (ctrl->sink_rx_status & ctrl->abort_mask) { - pr_err("reauth or Link fail triggered by sink\n"); + if (ctrl->rx_status) { + if (!ctrl->cp_irq_done) { + pr_debug("waiting for CP_IRQ\n"); + ctrl->polling = true; + return; + } - ctrl->sink_rx_status = 0; - rc = -ENOLINK; - cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; - - goto exit; - } - - if (ctrl->rx_status && !ctrl->sink_rx_status) { - pr_debug("Recv msg for RxStatus, but no CP_IRQ yet\n"); - ctrl->polling = true; - goto exit; + if (ctrl->rx_status & ctrl->sink_rx_status) { + ctrl->cp_irq_done = false; + ctrl->sink_rx_status = 0; + ctrl->rx_status = 0; + } } dp_hdcp2p2_get_msg_from_sink(ctrl); - - return; -exit: - if (rc) - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); -} - -static void dp_hdcp2p2_poll_work(struct kthread_work *work) -{ - struct dp_hdcp2p2_ctrl *ctrl = container_of(work, - struct dp_hdcp2p2_ctrl, poll); - - if (ctrl->cp_irq_done) { - ctrl->cp_irq_done = false; - dp_hdcp2p2_get_msg_from_sink(ctrl); - } else { - ctrl->polling = true; - } } static void dp_hdcp2p2_auth_status_work(struct kthread_work *work) @@ -645,44 +581,45 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work) if (rc) { pr_err("failed to read rx status\n"); - cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; + cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED; + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); goto exit; } if (ctrl->sink_rx_status & ctrl->abort_mask) { - pr_err("reauth or Link fail triggered by sink\n"); + if (ctrl->sink_rx_status & BIT(3)) + pr_err("reauth_req set by sink\n"); + + if (ctrl->sink_rx_status & BIT(4)) + pr_err("link failure reported by sink\n"); ctrl->sink_rx_status = 0; ctrl->rx_status = 0; rc = -ENOLINK; - cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; + + cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED; + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); goto exit; } - /* if polling, get message from sink else let polling start */ if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) { ctrl->sink_rx_status = 0; ctrl->rx_status = 0; - rc = dp_hdcp2p2_get_msg_from_sink(ctrl); + dp_hdcp2p2_get_msg_from_sink(ctrl); ctrl->polling = false; } else { ctrl->cp_irq_done = true; } exit: - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); - - if (rc) { - dp_hdcp2p2_auth_failed(ctrl); - return; - } + if (rc) + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); } static void dp_hdcp2p2_auth_work(struct kthread_work *work) { - int rc = 0; struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; struct dp_hdcp2p2_ctrl *ctrl = container_of(work, struct dp_hdcp2p2_ctrl, auth); @@ -694,12 +631,10 @@ static void dp_hdcp2p2_auth_work(struct kthread_work *work) else cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; - rc = dp_hdcp2p2_wakeup_lib(ctrl, &cdata); - if (rc) - dp_hdcp2p2_auth_failed(ctrl); + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); } -static int dp_hdcp2p2_isr(void *input) +static int dp_hdcp2p2_cp_irq(void *input) { struct dp_hdcp2p2_ctrl *ctrl = input; @@ -748,7 +683,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) .authenticate = dp_hdcp2p2_authenticate, .feature_supported = dp_hdcp2p2_feature_supported, .off = dp_hdcp2p2_off, - .isr = dp_hdcp2p2_isr + .cp_irq = dp_hdcp2p2_cp_irq, }; static struct hdcp_client_ops client_ops = { @@ -806,7 +741,6 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data) init_kthread_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work); init_kthread_work(&ctrl->status, dp_hdcp2p2_auth_status_work); init_kthread_work(&ctrl->link, dp_hdcp2p2_link_work); - init_kthread_work(&ctrl->poll, dp_hdcp2p2_poll_work); ctrl->thread = kthread_run(kthread_worker_fn, &ctrl->worker, "dp_hdcp2p2"); diff --git a/drivers/video/fbdev/msm/mdss_hdcp.h b/drivers/video/fbdev/msm/mdss_hdcp.h index d373d22384e8..6e347a867366 100644 --- a/drivers/video/fbdev/msm/mdss_hdcp.h +++ b/drivers/video/fbdev/msm/mdss_hdcp.h @@ -55,6 +55,7 @@ struct hdcp_init_data { struct hdcp_ops { int (*isr)(void *ptr); + int (*cp_irq)(void *ptr); int (*reauthenticate)(void *input); int (*authenticate)(void *hdcp_ctrl); bool (*feature_supported)(void *input); diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c index 1e502cf750a6..a8182c2f0e76 100644 --- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c +++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c @@ -153,6 +153,7 @@ struct hdcp_reg_set { u32 sec_data12; u32 reset; + u32 reset_bit; }; #define HDCP_REG_SET_CLIENT_HDMI \ @@ -175,7 +176,7 @@ struct hdcp_reg_set { HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \ HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \ - HDMI_HDCP_RESET} + HDMI_HDCP_RESET, BIT(0)} #define HDCP_REG_SET_CLIENT_DP \ {DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \ @@ -193,7 +194,8 @@ struct hdcp_reg_set { HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \ - HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, 0} + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \ + DP_SW_RESET, BIT(1)} #define HDCP_HDMI_SINK_ADDR_MAP \ {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \ @@ -1295,6 +1297,9 @@ static void hdcp_1x_int_work(struct work_struct *work) return; } + if (hdcp_ctrl->hdcp_state == HDCP_STATE_AUTHENTICATED) + hdcp1_set_enc(false); + mutex_lock(hdcp_ctrl->init_data.mutex); hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAIL; mutex_unlock(hdcp_ctrl->init_data.mutex); @@ -1383,6 +1388,8 @@ error: hdcp_ctrl->init_data.cb_data, hdcp_ctrl->hdcp_state); } + + hdcp1_set_enc(true); } else { DEV_DBG("%s: %s: HDCP state changed during authentication\n", __func__, HDCP_STATE_NAME); @@ -1431,7 +1438,7 @@ int hdcp_1x_reauthenticate(void *input) struct hdcp_reg_set *reg_set; struct hdcp_int_set *isr; u32 hdmi_hw_version; - u32 ret = 0; + u32 ret = 0, reg; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { DEV_ERR("%s: invalid input\n", __func__); @@ -1462,15 +1469,17 @@ int hdcp_1x_reauthenticate(void *input) /* Disable HDCP interrupts */ DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN); - if (reg_set->reset) - DSS_REG_W(io, reg_set->reset, BIT(0)); + reg = DSS_REG_R(io, reg_set->reset); + DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit); /* Disable encryption and disable the HDCP block */ DSS_REG_W(io, reg_set->ctrl, 0); + DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); + if (!hdcp_1x_load_keys(input)) queue_delayed_work(hdcp_ctrl->init_data.workq, - &hdcp_ctrl->hdcp_auth_work, HZ/2); + &hdcp_ctrl->hdcp_auth_work, HZ); else queue_work(hdcp_ctrl->init_data.workq, &hdcp_ctrl->hdcp_int_work); @@ -1485,6 +1494,7 @@ void hdcp_1x_off(void *input) struct hdcp_reg_set *reg_set; struct hdcp_int_set *isr; int rc = 0; + u32 reg; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { DEV_ERR("%s: invalid input\n", __func__); @@ -1501,6 +1511,9 @@ void hdcp_1x_off(void *input) return; } + if (hdcp_ctrl->hdcp_state == HDCP_STATE_AUTHENTICATED) + hdcp1_set_enc(false); + /* * Disable HDCP interrupts. * Also, need to set the state to inactive here so that any ongoing @@ -1527,12 +1540,15 @@ void hdcp_1x_off(void *input) DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__, HDCP_STATE_NAME); - if (reg_set->reset) - DSS_REG_W(io, reg_set->reset, BIT(0)); + + reg = DSS_REG_R(io, reg_set->reset); + DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit); /* Disable encryption and disable the HDCP block */ DSS_REG_W(io, reg_set->ctrl, 0); + DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); + DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME); } /* hdcp_1x_off */ diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c index f6c6548bdaa5..ca01ee6345d2 100644 --- a/drivers/video/fbdev/msm/msm_ext_display.c +++ b/drivers/video/fbdev/msm/msm_ext_display.c @@ -38,15 +38,18 @@ struct msm_ext_disp { struct switch_dev hdmi_sdev; struct switch_dev audio_sdev; bool ack_enabled; - atomic_t ack_pending; + bool audio_session_on; struct list_head display_list; struct mutex lock; + struct completion hpd_comp; }; static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp, enum msm_ext_disp_type type, struct msm_ext_disp_init_data **data); static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack); +static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp, + enum msm_ext_disp_cable_state state); static int msm_ext_disp_switch_dev_register(struct msm_ext_disp *ext_disp) { @@ -313,14 +316,14 @@ static void msm_ext_disp_remove_intf_data(struct msm_ext_disp *ext_disp, } } -static void msm_ext_disp_send_cable_notification(struct msm_ext_disp *ext_disp, +static int msm_ext_disp_send_cable_notification(struct msm_ext_disp *ext_disp, enum msm_ext_disp_cable_state new_state) { int state = EXT_DISPLAY_CABLE_STATE_MAX; if (!ext_disp) { pr_err("Invalid params\n"); - return; + return -EINVAL; } state = ext_disp->hdmi_sdev.state; @@ -330,6 +333,77 @@ static void msm_ext_disp_send_cable_notification(struct msm_ext_disp *ext_disp, ext_disp->hdmi_sdev.state == state ? "is same" : "switched to", ext_disp->hdmi_sdev.state); + + return ext_disp->hdmi_sdev.state == state ? 0 : 1; +} + +static int msm_ext_disp_send_audio_notification(struct msm_ext_disp *ext_disp, + enum msm_ext_disp_cable_state new_state) +{ + int state = EXT_DISPLAY_CABLE_STATE_MAX; + + if (!ext_disp) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + state = ext_disp->audio_sdev.state; + switch_set_state(&ext_disp->audio_sdev, !!new_state); + + pr_debug("Audio state %s %d\n", + ext_disp->audio_sdev.state == state ? + "is same" : "switched to", + ext_disp->audio_sdev.state); + + return ext_disp->audio_sdev.state == state ? 0 : 1; +} + +static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp, + enum msm_ext_disp_cable_state state) +{ + int ret = msm_ext_disp_send_cable_notification(ext_disp, state); + + /* positive ret value means audio node was switched */ + if (IS_ERR_VALUE(ret) || !ret) { + pr_debug("not waiting for display\n"); + goto end; + } + + reinit_completion(&ext_disp->hpd_comp); + ret = wait_for_completion_timeout(&ext_disp->hpd_comp, HZ * 2); + if (!ret) { + pr_err("display timeout\n"); + ret = -EINVAL; + goto end; + } + + ret = 0; +end: + return ret; +} + +static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp, + enum msm_ext_disp_cable_state state) +{ + int ret = msm_ext_disp_send_audio_notification(ext_disp, state); + + /* positive ret value means audio node was switched */ + if (IS_ERR_VALUE(ret) || !ret || !ext_disp->ack_enabled) { + pr_debug("not waiting for audio\n"); + goto end; + } + + reinit_completion(&ext_disp->hpd_comp); + ret = wait_for_completion_timeout(&ext_disp->hpd_comp, HZ * 2); + if (!ret) { + pr_err("audio timeout\n"); + ret = -EINVAL; + goto end; + } + + ret = 0; +end: + return ret; } static int msm_ext_disp_hpd(struct platform_device *pdev, @@ -337,7 +411,6 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, enum msm_ext_disp_cable_state state) { int ret = 0; - struct msm_ext_disp_init_data *data = NULL; struct msm_ext_disp *ext_disp = NULL; if (!pdev) { @@ -379,27 +452,28 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, goto end; } - ret = msm_ext_disp_get_intf_data(ext_disp, type, &data); - if (ret) - goto end; - if (state == EXT_DISPLAY_CABLE_CONNECT) { - ext_disp->current_disp = data->type; - } else if ((state == EXT_DISPLAY_CABLE_DISCONNECT) && - !ext_disp->ack_enabled) { - if (ext_disp->ops) { - ext_disp->ops->audio_info_setup = NULL; - ext_disp->ops->get_audio_edid_blk = NULL; - ext_disp->ops->cable_status = NULL; - ext_disp->ops->get_intf_id = NULL; - ext_disp->ops->teardown_done = NULL; - } + ext_disp->current_disp = type; + + ret = msm_ext_disp_process_display(ext_disp, state); + if (ret) + goto end; + + msm_ext_disp_update_audio_ops(ext_disp, state); + if (ret) + goto end; + + ret = msm_ext_disp_process_audio(ext_disp, state); + if (ret) + goto end; + } else { + msm_ext_disp_process_audio(ext_disp, state); + msm_ext_disp_update_audio_ops(ext_disp, state); + msm_ext_disp_process_display(ext_disp, state); ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; } - msm_ext_disp_send_cable_notification(ext_disp, state); - pr_debug("Hpd (%d) for display (%s)\n", state, msm_ext_disp_name(type)); @@ -427,23 +501,18 @@ static int msm_ext_disp_get_intf_data_helper(struct platform_device *pdev, goto end; } - mutex_lock(&ext_disp->lock); - if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX) { ret = -EINVAL; pr_err("No display connected\n"); - goto error; + goto end; } ret = msm_ext_disp_get_intf_data(ext_disp, ext_disp->current_disp, data); - if (ret) - goto error; -error: - mutex_unlock(&ext_disp->lock); end: return ret; } + static int msm_ext_disp_cable_status(struct platform_device *pdev, u32 vote) { int ret = 0; @@ -480,11 +549,21 @@ static int msm_ext_disp_audio_info_setup(struct platform_device *pdev, { int ret = 0; struct msm_ext_disp_init_data *data = NULL; + struct msm_ext_disp *ext_disp = NULL; ret = msm_ext_disp_get_intf_data_helper(pdev, &data); if (ret || !data) goto end; + ext_disp = platform_get_drvdata(pdev); + if (!ext_disp) { + pr_err("No drvdata found\n"); + ret = -EINVAL; + goto end; + } + + ext_disp->audio_session_on = true; + ret = data->codec_ops.audio_info_setup(data->pdev, params); end: @@ -495,6 +574,7 @@ static void msm_ext_disp_teardown_done(struct platform_device *pdev) { int ret = 0; struct msm_ext_disp_init_data *data = NULL; + struct msm_ext_disp *ext_disp = NULL; ret = msm_ext_disp_get_intf_data_helper(pdev, &data); if (ret || !data) { @@ -502,7 +582,21 @@ static void msm_ext_disp_teardown_done(struct platform_device *pdev) return; } - data->codec_ops.teardown_done(data->pdev); + ext_disp = platform_get_drvdata(pdev); + if (!ext_disp) { + pr_err("No drvdata found\n"); + return; + } + + if (data->codec_ops.teardown_done) + data->codec_ops.teardown_done(data->pdev); + + ext_disp->audio_session_on = false; + + pr_debug("%s tearing down audio\n", + msm_ext_disp_name(ext_disp->current_disp)); + + complete_all(&ext_disp->hpd_comp); } static int msm_ext_disp_get_intf_id(struct platform_device *pdev) @@ -523,93 +617,78 @@ static int msm_ext_disp_get_intf_id(struct platform_device *pdev) goto end; } - mutex_lock(&ext_disp->lock); ret = ext_disp->current_disp; - mutex_unlock(&ext_disp->lock); end: return ret; } -static int msm_ext_disp_notify(struct platform_device *pdev, - enum msm_ext_disp_cable_state new_state) +static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp, + enum msm_ext_disp_cable_state state) +{ + int ret = 0; + struct msm_ext_disp_audio_codec_ops *ops = ext_disp->ops; + + if (!ops) { + pr_err("Invalid audio ops\n"); + ret = -EINVAL; + goto end; + } + + if (state == EXT_DISPLAY_CABLE_CONNECT) { + ops->audio_info_setup = msm_ext_disp_audio_info_setup; + ops->get_audio_edid_blk = msm_ext_disp_get_audio_edid_blk; + ops->cable_status = msm_ext_disp_cable_status; + ops->get_intf_id = msm_ext_disp_get_intf_id; + ops->teardown_done = msm_ext_disp_teardown_done; + } else { + ops->audio_info_setup = NULL; + ops->get_audio_edid_blk = NULL; + ops->cable_status = NULL; + ops->get_intf_id = NULL; + ops->teardown_done = NULL; + } +end: + return ret; +} + +static int msm_ext_disp_notify(struct platform_device *pdev, + enum msm_ext_disp_cable_state state) { int ret = 0; - int state = 0; - bool switched; - struct msm_ext_disp_init_data *data = NULL; struct msm_ext_disp *ext_disp = NULL; if (!pdev) { pr_err("Invalid platform device\n"); - return -EINVAL; + ret = -EINVAL; + goto end; } ext_disp = platform_get_drvdata(pdev); if (!ext_disp) { pr_err("Invalid drvdata\n"); - return -EINVAL; + ret = -EINVAL; + goto end; } - mutex_lock(&ext_disp->lock); - if (state < EXT_DISPLAY_CABLE_DISCONNECT || - state >= EXT_DISPLAY_CABLE_STATE_MAX) { + state >= EXT_DISPLAY_CABLE_STATE_MAX) { pr_err("Invalid state (%d)\n", state); ret = -EINVAL; goto end; } - state = ext_disp->audio_sdev.state; - if (state == new_state) - goto end; - - if (ext_disp->ack_enabled && - atomic_read(&ext_disp->ack_pending)) { - ret = -EINVAL; - pr_err("%s ack pending, not notifying %s\n", - state ? "connect" : "disconnect", - new_state ? "connect" : "disconnect"); - goto end; - } - - ret = msm_ext_disp_get_intf_data(ext_disp, ext_disp->current_disp, - &data); - if (ret) - goto end; - - if (new_state == EXT_DISPLAY_CABLE_CONNECT && ext_disp->ops) { - ext_disp->ops->audio_info_setup = - msm_ext_disp_audio_info_setup; - ext_disp->ops->get_audio_edid_blk = - msm_ext_disp_get_audio_edid_blk; - ext_disp->ops->cable_status = - msm_ext_disp_cable_status; - ext_disp->ops->get_intf_id = - msm_ext_disp_get_intf_id; - ext_disp->ops->teardown_done = - msm_ext_disp_teardown_done; - } - - switch_set_state(&ext_disp->audio_sdev, (int)new_state); - switched = ext_disp->audio_sdev.state != state; - - if (ext_disp->ack_enabled && switched) - atomic_set(&ext_disp->ack_pending, 1); - - pr_debug("audio %s %s\n", switched ? "switched to" : "same as", - ext_disp->audio_sdev.state ? "HDMI" : "SPKR"); + pr_debug("%s notifying hpd (%d)\n", + msm_ext_disp_name(ext_disp->current_disp), state); + complete_all(&ext_disp->hpd_comp); end: - mutex_unlock(&ext_disp->lock); - return ret; } static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack) { u32 ack_hpd; - u32 hpd; int ret = 0; struct msm_ext_disp *ext_disp = NULL; @@ -624,10 +703,6 @@ static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack) return -EINVAL; } - mutex_lock(&ext_disp->lock); - - hpd = ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX; - if (ack & AUDIO_ACK_SET_ENABLE) { ext_disp->ack_enabled = ack & AUDIO_ACK_ENABLE ? true : false; @@ -640,44 +715,14 @@ static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack) if (!ext_disp->ack_enabled) goto end; - atomic_set(&ext_disp->ack_pending, 0); - ack_hpd = ack & AUDIO_ACK_CONNECT; - pr_debug("acknowledging %s\n", - ack_hpd ? "connect" : "disconnect"); - - /** - * If the ack feature is enabled and we receive an ack for - * disconnect then we reset the current display state to - * empty. - */ - if (!ack_hpd) { - if (ext_disp->ops) { - ext_disp->ops->audio_info_setup = NULL; - ext_disp->ops->get_audio_edid_blk = NULL; - ext_disp->ops->cable_status = NULL; - ext_disp->ops->get_intf_id = NULL; - ext_disp->ops->teardown_done = NULL; - } - - ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; - } - - if (ack_hpd != hpd) { - pr_err("unbalanced audio state, ack %d, hpd %d\n", - ack_hpd, hpd); - - mutex_unlock(&ext_disp->lock); - - ret = msm_ext_disp_notify(pdev, hpd); - - return ret; - } + pr_debug("%s acknowledging audio (%d)\n", + msm_ext_disp_name(ext_disp->current_disp), ack_hpd); + if (!ext_disp->audio_session_on) + complete_all(&ext_disp->hpd_comp); end: - mutex_unlock(&ext_disp->lock); - return ret; } @@ -850,6 +895,7 @@ static int msm_ext_disp_probe(struct platform_device *pdev) mutex_init(&ext_disp->lock); INIT_LIST_HEAD(&ext_disp->display_list); + init_completion(&ext_disp->hpd_comp); ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; return ret; diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h index f66264bc935a..68f2dd993170 100644 --- a/include/linux/hdcp_qseecom.h +++ b/include/linux/hdcp_qseecom.h @@ -26,6 +26,7 @@ enum hdcp_lib_wakeup_cmd { HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED, HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT, HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE, + HDCP_LIB_WKUP_CMD_LINK_FAILED, }; enum hdmi_hdcp_wakeup_cmd { @@ -47,6 +48,7 @@ struct hdcp_lib_wakeup_data { }; struct hdcp_msg_part { + char *name; uint32_t offset; uint32_t length; }; @@ -106,6 +108,8 @@ static inline char *hdcp_lib_cmd_to_str(uint32_t cmd) return "HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT"; case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: return "HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE"; + case HDCP_LIB_WKUP_CMD_LINK_FAILED: + return "HDCP_LIB_WKUP_CMD_LINK_FAILED"; default: return "???"; }