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

Commit 95a147ec authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Merge remote-tracking branch 'quic/dev/msm-4.14-display' into msm-4.14.c2"

parents eb05d2a4 54cc350d
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -127,7 +127,6 @@ Optional properties:
					turns off PHY pmic power supply, phy ldo and DSI Lane ldo during
					idle screen (footswitch control off) when this property is enabled.
- qcom,dsi-phy-regulator-min-datarate-bps:  Minimum per lane data rate (bps) to turn on PHY regulator.
- qcom,panel-force-clock-lane-hs:	A boolean property indicates that panel needs clock lanes in HS mode only

[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/graph.txt
@@ -238,5 +237,4 @@ Example:
		qcom,dsi-phy-regulator-ldo-mode;
		qcom,panel-allow-phy-poweroff;
		qcom,dsi-phy-regulator-min-datarate-bps = <1200000000>;
		qcom,panel-force-clock-lane-hs;
	};
+13 −23
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ struct dp_hdcp2p2_ctrl {
	u8 rx_status;
	char abort_mask;

	bool cp_irq_done;
	bool polling;
};

@@ -191,6 +190,8 @@ static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
	if (dp_hdcp2p2_copy_buf(ctrl, data))
		goto exit;

	ctrl->polling = false;

	pr_debug("%s\n", hdcp_transport_cmd_to_str(ctrl->wakeup_cmd));

	switch (ctrl->wakeup_cmd) {
@@ -198,6 +199,9 @@ static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
		kthread_queue_work(&ctrl->worker, &ctrl->send_msg);
		break;
	case HDCP_TRANSPORT_CMD_RECV_MESSAGE:
		if (ctrl->rx_status)
			ctrl->polling = true;
		else
			kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
		break;
	case HDCP_TRANSPORT_CMD_STATUS_SUCCESS:
@@ -212,9 +216,6 @@ static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
		dp_hdcp2p2_send_auth_status(ctrl);
		break;
	case HDCP_TRANSPORT_CMD_LINK_POLL:
		if (ctrl->cp_irq_done)
			kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
		else
		ctrl->polling = true;
		break;
	case HDCP_TRANSPORT_CMD_AUTHENTICATE:
@@ -533,26 +534,12 @@ static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work)
		return;
	}

	if (ctrl->rx_status) {
		if (!ctrl->cp_irq_done) {
			pr_debug("waiting for CP_IRQ\n");
			ctrl->polling = true;
			return;
		}

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

static void dp_hdcp2p2_link_work(struct kthread_work *work)
{
	int rc = 0;
	int rc = 0, retries = 10;
	struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
		struct dp_hdcp2p2_ctrl, link);
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};
@@ -587,6 +574,11 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)
		goto exit;
	}

	/* wait for polling to start till spec allowed timeout */
	while (!ctrl->polling && retries--)
		msleep(20);

	/* check if sink has made a message available */
	if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) {
		ctrl->sink_rx_status = 0;
		ctrl->rx_status = 0;
@@ -594,8 +586,6 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)
		dp_hdcp2p2_get_msg_from_sink(ctrl);

		ctrl->polling = false;
	} else {
		ctrl->cp_irq_done = true;
	}
exit:
	if (rc)
+60 −38
Original line number Diff line number Diff line
/*
 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -30,6 +30,7 @@
#include "dp_drm.h"

#define DP_MST_DEBUG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__)
#define DP_MST_INFO_LOG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__)

#define MAX_DP_MST_STREAMS		2
#define MAX_DP_MST_DRM_ENCODERS		2
@@ -102,7 +103,9 @@ struct dp_mst_bridge {
	struct drm_display_mode drm_mode;
	struct dp_display_mode dp_mode;
	struct drm_connector *connector;
	struct drm_connector *old_connector;
	void *dp_panel;
	void *old_dp_panel;

	int vcpi;
	int pbn;
@@ -120,6 +123,7 @@ struct dp_mst_private {
	struct dp_mst_sim_mode simulator;
	struct mutex mst_lock;
	enum dp_drv_state state;
	bool mst_session_state;
};

struct dp_mst_encoder_info_cache {
@@ -681,8 +685,6 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge)
	struct dp_display *dp;
	struct dp_mst_private *mst;

	DP_MST_DEBUG("enter\n");

	if (!drm_bridge) {
		pr_err("Invalid params\n");
		return;
@@ -691,6 +693,9 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge)
	bridge = to_dp_mst_bridge(drm_bridge);
	dp = bridge->display;

	bridge->old_connector = NULL;
	bridge->old_dp_panel = NULL;

	if (!bridge->connector) {
		pr_err("Invalid connector\n");
		return;
@@ -727,7 +732,14 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge)
		_dp_mst_bridge_pre_enable_part2(bridge);
	}

	DP_MST_DEBUG("mst bridge [%d] pre enable complete\n", bridge->id);
	DP_MST_INFO_LOG("mode: id(%d) mode(%s), refresh(%d)\n",
			bridge->id, bridge->drm_mode.name,
			bridge->drm_mode.vrefresh);
	DP_MST_INFO_LOG("dsc: id(%d) dsc(%d)\n", bridge->id,
			bridge->dp_mode.timing.comp_info.comp_ratio);
	DP_MST_INFO_LOG("channel: id(%d) vcpi(%d) start(%d) tot(%d)\n",
			bridge->id, bridge->vcpi, bridge->start_slot,
			bridge->num_slots);
end:
	mutex_unlock(&mst->mst_lock);
}
@@ -738,8 +750,6 @@ static void dp_mst_bridge_enable(struct drm_bridge *drm_bridge)
	struct dp_mst_bridge *bridge;
	struct dp_display *dp;

	DP_MST_DEBUG("enter\n");

	if (!drm_bridge) {
		pr_err("Invalid params\n");
		return;
@@ -760,7 +770,8 @@ static void dp_mst_bridge_enable(struct drm_bridge *drm_bridge)
		return;
	}

	DP_MST_DEBUG("mst bridge [%d] post enable complete\n", bridge->id);
	DP_MST_INFO_LOG("mst bridge [%d] post enable complete\n",
			bridge->id);
}

static void dp_mst_bridge_disable(struct drm_bridge *drm_bridge)
@@ -770,8 +781,6 @@ static void dp_mst_bridge_disable(struct drm_bridge *drm_bridge)
	struct dp_display *dp;
	struct dp_mst_private *mst;

	DP_MST_DEBUG("enter\n");

	if (!drm_bridge) {
		pr_err("Invalid params\n");
		return;
@@ -800,7 +809,7 @@ static void dp_mst_bridge_disable(struct drm_bridge *drm_bridge)

	_dp_mst_bridge_pre_disable_part2(bridge);

	DP_MST_DEBUG("mst bridge [%d] disable complete\n", bridge->id);
	DP_MST_INFO_LOG("mst bridge [%d] disable complete\n", bridge->id);

	mutex_unlock(&mst->mst_lock);
}
@@ -812,8 +821,6 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge)
	struct dp_display *dp;
	struct dp_mst_private *mst;

	DP_MST_DEBUG("enter\n");

	if (!drm_bridge) {
		pr_err("Invalid params\n");
		return;
@@ -841,12 +848,17 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge)
	/* maintain the connector to encoder link during suspend/resume */
	if (mst->state != PM_SUSPEND) {
		/* Disconnect the connector and panel info from bridge */
		mst->mst_bridge[bridge->id].old_connector =
				mst->mst_bridge[bridge->id].connector;
		mst->mst_bridge[bridge->id].old_dp_panel =
				mst->mst_bridge[bridge->id].dp_panel;
		mst->mst_bridge[bridge->id].connector = NULL;
		mst->mst_bridge[bridge->id].dp_panel = NULL;
		mst->mst_bridge[bridge->id].encoder_active_sts = false;
	}

	DP_MST_DEBUG("mst bridge [%d] post disable complete\n", bridge->id);
	DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n",
			bridge->id);
}

static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,
@@ -865,14 +877,22 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,

	bridge = to_dp_mst_bridge(drm_bridge);
	if (!bridge->connector) {
		if (!bridge->old_connector) {
			pr_err("Invalid connector\n");
			return;
		}
		bridge->connector = bridge->old_connector;
		bridge->old_connector = NULL;
	}

	if (!bridge->dp_panel) {
		if (!bridge->old_dp_panel) {
			pr_err("Invalid dp_panel\n");
			return;
		}
		bridge->dp_panel = bridge->old_dp_panel;
		bridge->old_dp_panel = NULL;
	}

	dp = bridge->display;

@@ -1381,7 +1401,7 @@ dp_mst_add_connector(struct drm_dp_mst_topology_mgr *mgr,
	/* unlock connector and make it accessible */
	drm_modeset_unlock_all(dev);

	DP_MST_DEBUG("add mst connector:%d\n", connector->base.id);
	DP_MST_INFO_LOG("add mst connector id:%d\n", connector->base.id);

	return connector;
}
@@ -1392,7 +1412,8 @@ static void dp_mst_register_connector(struct drm_connector *connector)

	connector->status = connector->funcs->detect(connector, false);

	DP_MST_DEBUG("register mst connector:%d\n", connector->base.id);
	DP_MST_INFO_LOG("register mst connector id:%d\n",
			connector->base.id);
	drm_connector_register(connector);
}

@@ -1401,7 +1422,7 @@ static void dp_mst_destroy_connector(struct drm_dp_mst_topology_mgr *mgr,
{
	DP_MST_DEBUG("enter\n");

	DP_MST_DEBUG("destroy mst connector:%d\n", connector->base.id);
	DP_MST_INFO_LOG("destroy mst connector id:%d\n", connector->base.id);

	drm_connector_unregister(connector);
	drm_connector_unreference(connector);
@@ -1420,7 +1441,7 @@ static void dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)

	kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);

	DP_MST_DEBUG("mst hot plug event\n");
	DP_MST_INFO_LOG("mst hot plug event\n");
}

static void dp_mst_hpd_event_notify(struct dp_mst_private *mst, bool hpd_status)
@@ -1441,7 +1462,7 @@ static void dp_mst_hpd_event_notify(struct dp_mst_private *mst, bool hpd_status)

	kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);

	DP_MST_DEBUG("%s finished\n", __func__);
	DP_MST_INFO_LOG("%s finished\n", __func__);
}

/* DP Driver Callback OPs */
@@ -1453,7 +1474,9 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status,
	struct dp_display *dp = dp_display;
	struct dp_mst_private *mst = dp->dp_mst_prv_info;

	DP_MST_DEBUG("enter:\n");
	mutex_lock(&mst->mst_lock);
	mst->mst_session_state = hpd_status;
	mutex_unlock(&mst->mst_lock);

	if (!hpd_status)
		rc = mst->mst_fw_cbs->topology_mgr_set_mst(&mst->mst_mgr,
@@ -1475,9 +1498,7 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status,

	dp_mst_hpd_event_notify(mst, hpd_status);

	DP_MST_DEBUG("mst display hpd:%d, rc:%d\n", hpd_status, rc);

	DP_MST_DEBUG("exit:\n");
	DP_MST_INFO_LOG("mst display hpd:%d, rc:%d\n", hpd_status, rc);
}

static void dp_mst_display_hpd_irq(void *dp_display,
@@ -1486,26 +1507,29 @@ static void dp_mst_display_hpd_irq(void *dp_display,
	int rc;
	struct dp_display *dp = dp_display;
	struct dp_mst_private *mst = dp->dp_mst_prv_info;
	u8 esi[14], idx;
	u8 esi[14];
	unsigned int esi_res = DP_SINK_COUNT_ESI + 1;
	bool handled;

	DP_MST_DEBUG("enter:\n");

	if (info->mst_hpd_sim) {
		dp_mst_hotplug(&mst->mst_mgr);
		return;
	}

	if (!mst->mst_session_state) {
		pr_err("mst_hpd_irq received before mst session start\n");
		return;
	}

	rc = drm_dp_dpcd_read(mst->caps.drm_aux, DP_SINK_COUNT_ESI,
		esi, 14);
	if (rc != 14) {
		pr_err("dpcd sync status read failed, rlen=%d\n", rc);
		goto end;
		pr_err("dpcd sink status read failed, rlen=%d\n", rc);
		return;
	}

	for (idx = 0; idx < 14; idx++)
		DP_MST_DEBUG("mst irq: esi[%d]: 0x%x\n", idx, esi[idx]);
	DP_MST_DEBUG("mst irq: esi1[0x%x] esi2[0x%x] esi3[%x]\n",
			esi[1], esi[2], esi[3]);

	rc = drm_dp_mst_hpd_irq(&mst->mst_mgr, esi, &handled);

@@ -1518,9 +1542,6 @@ static void dp_mst_display_hpd_irq(void *dp_display,
	}

	DP_MST_DEBUG("mst display hpd_irq handled:%d rc:%d\n", handled, rc);

end:
	DP_MST_DEBUG("exit:\n");
}

static void dp_mst_set_state(void *dp_display, enum dp_drv_state mst_state)
@@ -1534,6 +1555,7 @@ static void dp_mst_set_state(void *dp_display, enum dp_drv_state mst_state)
	}

	mst->state = mst_state;
	DP_MST_INFO_LOG("mst power state:%d\n", mst_state);
}

/* DP MST APIs */
@@ -1615,7 +1637,7 @@ int dp_mst_init(struct dp_display *dp_display)
	}
	memset(&dp_mst_enc_cache, 0, sizeof(dp_mst_enc_cache));

	DP_MST_DEBUG("dp drm mst topology manager init completed\n");
	DP_MST_INFO_LOG("dp drm mst topology manager init completed\n");

	return ret;

@@ -1646,6 +1668,6 @@ void dp_mst_deinit(struct dp_display *dp_display)

	mutex_destroy(&mst->mst_lock);

	DP_MST_DEBUG("dp drm mst topology manager deinit completed\n");
	DP_MST_INFO_LOG("dp drm mst topology manager deinit completed\n");
}
+0 −1
Original line number Diff line number Diff line
@@ -475,7 +475,6 @@ struct dsi_video_engine_cfg {
	bool hsa_lp11_en;
	bool eof_bllp_lp11_en;
	bool bllp_lp11_en;
	bool force_clk_lane_hs;
	enum dsi_video_traffic_mode traffic_mode;
	u32 vc_id;
	u32 dma_sched_line;
+195 −59
Original line number Diff line number Diff line
@@ -3504,8 +3504,15 @@ static int dsi_display_parse_dt(struct dsi_display *display)
	/* Parse TE data */
	dsi_display_parse_te_data(display);

	/* Parse external bridge from port 0, reg 0 */
	display->ext_bridge_of = of_graph_get_remote_node(of_node, 0, 0);
	/* Parse all external bridges from port 0 */
	display_for_each_ctrl(i, display) {
		display->ext_bridge[i].node_of =
			of_graph_get_remote_node(of_node, 0, i);
		if (display->ext_bridge[i].node_of)
			display->ext_bridge_cnt++;
		else
			break;
	}

	pr_debug("success\n");
error:
@@ -3543,6 +3550,14 @@ static int dsi_display_res_init(struct dsi_display *display)
				display->parser_node,
				display->display_type,
				display->cmdline_topology);

	display_for_each_ctrl(i, display) {
		struct msm_dsi_phy *phy = display->ctrl[i].phy;

		phy->cfg.force_clk_lane_hs =
			display->panel->host_config.force_hs_clk_lane;
	}

	if (IS_ERR_OR_NULL(display->panel)) {
		rc = PTR_ERR(display->panel);
		pr_err("failed to get panel, rc=%d\n", rc);
@@ -5118,6 +5133,102 @@ static int dsi_display_ext_get_mode_info(struct drm_connector *connector,
	return 0;
}

static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge(
		struct drm_bridge *bridge)
{
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;
	struct list_head *connector_list;
	struct drm_connector *conn_iter;
	struct sde_connector *sde_conn;
	struct dsi_display *display;
	int i;

	if (!bridge || !bridge->encoder) {
		SDE_ERROR("invalid argument\n");
		return NULL;
	}

	priv = bridge->dev->dev_private;
	sde_kms = to_sde_kms(priv->kms);
	connector_list = &sde_kms->dev->mode_config.connector_list;

	list_for_each_entry(conn_iter, connector_list, head) {
		sde_conn = to_sde_connector(conn_iter);
		if (sde_conn->encoder == bridge->encoder) {
			display = sde_conn->display;
			for (i = 0; i < display->ctrl_count; i++) {
				if (display->ext_bridge[i].bridge == bridge)
					return &display->ext_bridge[i];
			}
		}
	}

	return NULL;
}

static void dsi_display_drm_ext_adjust_timing(
		const struct dsi_display *display,
		struct drm_display_mode *mode)
{
	mode->hdisplay /= display->ctrl_count;
	mode->hsync_start /= display->ctrl_count;
	mode->hsync_end /= display->ctrl_count;
	mode->htotal /= display->ctrl_count;
	mode->hskew /= display->ctrl_count;
	mode->clock /= display->ctrl_count;
}

static enum drm_mode_status dsi_display_drm_ext_bridge_mode_valid(
		struct drm_bridge *bridge,
		const struct drm_display_mode *mode)
{
	struct dsi_display_ext_bridge *ext_bridge;
	struct drm_display_mode tmp;

	ext_bridge = dsi_display_ext_get_bridge(bridge);
	if (!ext_bridge)
		return MODE_ERROR;

	tmp = *mode;
	dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp);
	return ext_bridge->orig_funcs->mode_valid(bridge, &tmp);
}

static bool dsi_display_drm_ext_bridge_mode_fixup(
		struct drm_bridge *bridge,
		const struct drm_display_mode *mode,
		struct drm_display_mode *adjusted_mode)
{
	struct dsi_display_ext_bridge *ext_bridge;
	struct drm_display_mode tmp;

	ext_bridge = dsi_display_ext_get_bridge(bridge);
	if (!ext_bridge)
		return false;

	tmp = *mode;
	dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp);
	return ext_bridge->orig_funcs->mode_fixup(bridge, &tmp, &tmp);
}

static void dsi_display_drm_ext_bridge_mode_set(
		struct drm_bridge *bridge,
		struct drm_display_mode *mode,
		struct drm_display_mode *adjusted_mode)
{
	struct dsi_display_ext_bridge *ext_bridge;
	struct drm_display_mode tmp;

	ext_bridge = dsi_display_ext_get_bridge(bridge);
	if (!ext_bridge)
		return;

	tmp = *mode;
	dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp);
	ext_bridge->orig_funcs->mode_set(bridge, &tmp, &tmp);
}

static int dsi_host_ext_attach(struct mipi_dsi_host *host,
			   struct mipi_dsi_device *dsi)
{
@@ -5210,31 +5321,50 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
	struct drm_bridge *ext_bridge;
	struct drm_connector *ext_conn;
	struct sde_connector *sde_conn = to_sde_connector(connector);
	int rc;
	struct drm_bridge *prev_bridge = bridge;
	int rc = 0, i;

	/* check if ext_bridge is already attached */
	if (display->ext_bridge)
		return 0;
	for (i = 0; i < display->ext_bridge_cnt; i++) {
		struct dsi_display_ext_bridge *ext_bridge_info =
				&display->ext_bridge[i];

	/* check if there is no external bridge defined */
	if (!display->ext_bridge_of)
		/* return if ext bridge is already initialized */
		if (ext_bridge_info->bridge)
			return 0;

	ext_bridge = of_drm_find_bridge(display->ext_bridge_of);
		ext_bridge = of_drm_find_bridge(ext_bridge_info->node_of);
		if (IS_ERR_OR_NULL(ext_bridge)) {
			rc = PTR_ERR(ext_bridge);
			pr_err("failed to find ext bridge\n");
			goto error;
		}

	rc = drm_bridge_attach(bridge->encoder, ext_bridge, bridge);
		/* override functions for mode adjustment */
		if (display->ext_bridge_cnt > 1) {
			ext_bridge_info->bridge_funcs = *ext_bridge->funcs;
			if (ext_bridge->funcs->mode_fixup)
				ext_bridge_info->bridge_funcs.mode_fixup =
					dsi_display_drm_ext_bridge_mode_fixup;
			if (ext_bridge->funcs->mode_valid)
				ext_bridge_info->bridge_funcs.mode_valid =
					dsi_display_drm_ext_bridge_mode_valid;
			if (ext_bridge->funcs->mode_set)
				ext_bridge_info->bridge_funcs.mode_set =
					dsi_display_drm_ext_bridge_mode_set;
			ext_bridge_info->orig_funcs = ext_bridge->funcs;
			ext_bridge->funcs = &ext_bridge_info->bridge_funcs;
		}

		rc = drm_bridge_attach(encoder, ext_bridge, prev_bridge);
		if (rc) {
			pr_err("[%s] ext brige attach failed, %d\n",
				display->name, rc);
			goto error;
		}

	display->ext_bridge = ext_bridge;
		ext_bridge_info->display = display;
		ext_bridge_info->bridge = ext_bridge;
		prev_bridge = ext_bridge;

		/* ext bridge will init its own connector during attach,
		 * we need to extract it out of the connector list
@@ -5249,14 +5379,15 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
		}
		spin_unlock_irq(&drm->mode_config.connector_list_lock);

	/* if there is no valid external connector created, we'll use default
	 * setting from panel defined in DT file.
		/* if there is no valid external connector created, or in split
		 * mode, default setting is used from panel defined in DT file.
		 */
		if (!display->ext_conn ||
		    !display->ext_conn->funcs ||
	    !display->ext_conn->helper_private) {
		    !display->ext_conn->helper_private ||
		    display->ext_bridge_cnt > 1) {
			display->ext_conn = NULL;
		return 0;
			continue;
		}

		/* otherwise, hook up the functions to use external connector */
@@ -5264,13 +5395,16 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
			sde_conn->ops.detect = dsi_display_drm_ext_detect;

		if (display->ext_conn->helper_private->get_modes)
		sde_conn->ops.get_modes = dsi_display_drm_ext_get_modes;
			sde_conn->ops.get_modes =
				dsi_display_drm_ext_get_modes;

		if (display->ext_conn->helper_private->mode_valid)
		sde_conn->ops.mode_valid = dsi_display_drm_ext_mode_valid;
			sde_conn->ops.mode_valid =
				dsi_display_drm_ext_mode_valid;

		if (display->ext_conn->helper_private->atomic_check)
		sde_conn->ops.atomic_check = dsi_display_drm_ext_atomic_check;
			sde_conn->ops.atomic_check =
				dsi_display_drm_ext_atomic_check;

		sde_conn->ops.get_info =
				dsi_display_ext_get_info;
@@ -5279,6 +5413,8 @@ int dsi_display_drm_ext_bridge_init(struct dsi_display *display,

		/* add support to attach/detach */
		display->host.ops = &dsi_host_ext_ops;
	}

	return 0;
error:
	return rc;
Loading