Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9454b9f3 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ext_display: update hpd and notify logic"

parents 68afff6f 0659e585
Loading
Loading
Loading
Loading
+90 −46
Original line number Diff line number Diff line
@@ -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,25 +619,48 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
	}
}

static inline void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
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))
		return;

	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 (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);
		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)
				data->message_data =
					&hdcp_msg_lookup[handle->last_msg];
		    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);
		}
	} else {
		pr_debug("lib->client: %s\n",
			hdmi_hdcp_cmd_to_str(data->cmd));
	}

	rc = handle->client_ops->wakeup(data);
@@ -642,10 +668,10 @@ static inline void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
		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,9 +1943,12 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)

	mutex_unlock(&handle->msg_lock);

	pr_debug("msg received: %s from sink\n",
	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);
	req_buf->commandid = HDCP_TXMTR_PROCESS_RECEIVED_MESSAGE;
@@ -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) {
+185 −123
Original line number Diff line number Diff line
@@ -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,10 +1173,16 @@ 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");

	do {
		if (ret == -EAGAIN) {
			mdss_dp_mainlink_push_idle(&dp_drv->panel_data);
			mdss_dp_off_irq(dp_drv);
		}

		mutex_lock(&dp_drv->train_mutex);

		orientation = usbpd_get_plug_orientation(dp_drv->pd);
		pr_debug("plug orientation = %d\n", orientation);

@@ -1202,9 +1203,13 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv)

		mdss_dp_configure_source_params(dp_drv, &ln_map);

	mdss_dp_train_main_link(dp_drv);

		dp_drv->power_on = true;

		ret = mdss_dp_train_main_link(dp_drv);

		mutex_unlock(&dp_drv->train_mutex);
	} while (ret == -EAGAIN);

	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);
}

static void mdss_dp_audio_codec_wait(struct mdss_dp_drv_pdata *dp)
{
	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;
end:
	return ret;
}

static void mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable)
static int 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");
	return mdss_dp_send_cable_notification(dp, enable);
}


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;

		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");
			return -EINVAL;
				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,13 +2542,16 @@ 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->power_on && dp_drv->hdcp.ops &&
			    dp_drv->hdcp.ops->cp_irq)
				dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data);

		if (dp_drv->hpd_irq_toggled
				&& !dp_drv->alt_mode.dp_status.hpd_irq) {
			mdss_dp_process_hpd_irq_low(dp_drv);
			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;
		}

@@ -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;
+16 −2
Original line number Diff line number Diff line
@@ -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;
+66 −52

File changed.

Preview size limit exceeded, changes collapsed.

+46 −112

File changed.

Preview size limit exceeded, changes collapsed.

Loading