linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Archit Taneja <architt@codeaurora.org>
To: dri-devel@lists.freedesktop.org
Cc: robdclark@gmail.com, linux-arm-msm@vger.kernel.org,
	hali@codeaurora.org, wentaox@codeaurora.org,
	sviau@codeaurora.org, jilaiw@codeaurora.org,
	Archit Taneja <architt@codeaurora.org>
Subject: [PATCH v2 4/5] drm/msm/dsi: Allow dsi to connect to an external bridge
Date: Sun,  2 Aug 2015 21:50:36 +0530	[thread overview]
Message-ID: <1438532437-24646-5-git-send-email-architt@codeaurora.org> (raw)
In-Reply-To: <1438532437-24646-1-git-send-email-architt@codeaurora.org>

There are platforms where the DSI output can be connected to another
encoder bridge chip (DSI to HDMI, DSI to LVDS etc).

Add support for external bridge support to the dsi driver. We assume that
the external bridge chip would be of the type drm_bridge. The dsi driver's
internal drm_bridge (msm_dsi->bridge) is linked to the external bridge's
drm_bridge struct.

In the case we're connected to an external bridge, we don't need to create
and manage a connector within our driver, it's the bridge driver's
responsibility to create one.

v2:
- Move the external bridge attaching stuff to dsi manager to make things
  cleaner.
- Force the bridge to connect to a video mode encoder for now (the dsi
  mode flags may have not been populated by modeset_init)

Signed-off-by: Archit Taneja <architt@codeaurora.org>
---
 drivers/gpu/drm/msm/dsi/dsi.c         | 28 ++++++++++++++++----
 drivers/gpu/drm/msm/dsi/dsi.h         | 12 ++++++++-
 drivers/gpu/drm/msm/dsi/dsi_host.c    |  9 ++++++-
 drivers/gpu/drm/msm/dsi/dsi_manager.c | 49 ++++++++++++++++++++++++++++++++++-
 4 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index e991270..f036060 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -196,6 +196,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 		struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
 {
 	struct msm_drm_private *priv = dev->dev_private;
+	struct drm_bridge *ext_bridge;
 	int ret, i;
 
 	if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
@@ -223,10 +224,25 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 		msm_dsi->encoders[i] = encoders[i];
 	}
 
-	msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
+	/*
+	 * check if the dsi encoder output is connected to a panel or an
+	 * external bridge. We create a connector only if we're connected to a
+	 * drm_panel device. When we're connected to an external bridge, we
+	 * assume that the drm_bridge driver will create the connector itself.
+	 */
+	ext_bridge = msm_dsi_host_get_bridge(msm_dsi->host);
+
+	if (ext_bridge)
+		msm_dsi->connector =
+			msm_dsi_manager_ext_bridge_init(msm_dsi->id);
+	else
+		msm_dsi->connector =
+			msm_dsi_manager_connector_init(msm_dsi->id);
+
 	if (IS_ERR(msm_dsi->connector)) {
 		ret = PTR_ERR(msm_dsi->connector);
-		dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
+		dev_err(dev->dev,
+			"failed to create dsi connector: %d\n", ret);
 		msm_dsi->connector = NULL;
 		goto fail;
 	}
@@ -242,10 +258,12 @@ fail:
 			msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
 			msm_dsi->bridge = NULL;
 		}
-		if (msm_dsi->connector) {
+
+		/* don't destroy connector if we didn't make it */
+		if (msm_dsi->connector && !msm_dsi->external_bridge)
 			msm_dsi->connector->funcs->destroy(msm_dsi->connector);
-			msm_dsi->connector = NULL;
-		}
+
+		msm_dsi->connector = NULL;
 	}
 
 	return ret;
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 918b0c6..2a5e02c 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -65,12 +65,20 @@ struct msm_dsi {
 	struct drm_device *dev;
 	struct platform_device *pdev;
 
+	/* connector managed by us when we're connected to a drm_panel */
 	struct drm_connector *connector;
+	/* internal dsi bridge attached to MDP interface */
 	struct drm_bridge *bridge;
 
 	struct mipi_dsi_host *host;
 	struct msm_dsi_phy *phy;
+
+	/*
+	 * panel/external_bridge connected to dsi bridge output, only one of the
+	 * two can be valid at a time
+	 */
 	struct drm_panel *panel;
+	struct drm_bridge *external_bridge;
 	unsigned long device_flags;
 
 	struct device *phy_dev;
@@ -86,6 +94,7 @@ struct msm_dsi {
 struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
 void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
 struct drm_connector *msm_dsi_manager_connector_init(u8 id);
+struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id);
 int msm_dsi_manager_phy_enable(int id,
 		const unsigned long bit_rate, const unsigned long esc_rate,
 		u32 *clk_pre, u32 *clk_post);
@@ -98,7 +107,7 @@ void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
 /* msm dsi */
 static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
 {
-	return msm_dsi->panel;
+	return msm_dsi->panel || msm_dsi->external_bridge;
 }
 
 struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
@@ -145,6 +154,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
 					struct drm_display_mode *mode);
 struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
 					unsigned long *panel_flags);
+struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
 int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
 void msm_dsi_host_unregister(struct mipi_dsi_host *host);
 int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 06f2975..8134a17 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -1623,7 +1623,8 @@ int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer)
 		 */
 		if (check_defer && msm_host->device_node) {
 			if (!of_drm_find_panel(msm_host->device_node))
-				return -EPROBE_DEFER;
+				if (!of_drm_find_bridge(msm_host->device_node))
+					return -EPROBE_DEFER;
 		}
 	}
 
@@ -2039,3 +2040,9 @@ struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
 	return panel;
 }
 
+struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host)
+{
+	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+	return of_drm_find_bridge(msm_host->device_node);
+}
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index e252d9d..620aca0 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -505,7 +505,7 @@ static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
 	.mode_set = dsi_mgr_bridge_mode_set,
 };
 
-/* initialize connector */
+/* initialize connector when we're connected to a drm_panel */
 struct drm_connector *msm_dsi_manager_connector_init(u8 id)
 {
 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
@@ -590,6 +590,53 @@ fail:
 	return ERR_PTR(ret);
 }
 
+struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
+{
+	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
+	struct drm_device *dev = msm_dsi->dev;
+	struct drm_encoder *encoder;
+	struct drm_bridge *int_bridge, *ext_bridge;
+	struct drm_connector *connector;
+	struct list_head *connector_list;
+
+	int_bridge = msm_dsi->bridge;
+	ext_bridge = msm_dsi->external_bridge =
+			msm_dsi_host_get_bridge(msm_dsi->host);
+
+	/*
+	 * HACK: we may not know the external DSI bridge device's mode
+	 * flags here. We'll get to know them only when the device
+	 * attaches to the dsi host. For now, assume the bridge supports
+	 * DSI video mode
+	 */
+	encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
+
+	/* link the internal dsi bridge to the external bridge */
+	int_bridge->next = ext_bridge;
+	/* set the external bridge's encoder as dsi's encoder */
+	ext_bridge->encoder = encoder;
+
+	drm_bridge_attach(dev, ext_bridge);
+
+	/*
+	 * we need the drm_connector created by the external bridge
+	 * driver (or someone else) to feed it to our driver's
+	 * priv->connector[] list, mainly for msm_fbdev_init()
+	 */
+	connector_list = &dev->mode_config.connector_list;
+
+	list_for_each_entry(connector, connector_list, head) {
+		int i;
+
+		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+			if (connector->encoder_ids[i] == encoder->base.id)
+				return connector;
+		}
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
 void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
 {
 }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

  parent reply	other threads:[~2015-08-02 16:20 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-26  7:45 [PATCH 0/5] drm/msm/dsi: Add support for external bridge chips Archit Taneja
2015-06-26  7:45 ` [PATCH 1/5] drm/msm/dsi: Make TE gpio optional Archit Taneja
2015-06-26  7:45 ` [PATCH 2/5] drm/msm/dsi: Refer to connected device as 'device' instead of 'panel' Archit Taneja
2015-06-26  7:45 ` [PATCH 3/5] drm/msm/dsi: Create a helper to check if there is a connected device Archit Taneja
2015-06-26  7:45 ` [PATCH 4/5] drm/msm/dsi: Allow dsi to connect to an external bridge Archit Taneja
2015-06-26  7:45 ` [PATCH 5/5] drm/msm/dsi: Modify dsi manager bridge ops to work with external bridges Archit Taneja
2015-08-02 16:20 ` [PATCH v2 0/5] drm/msm/dsi: Add support for external bridge chips Archit Taneja
2015-08-02 16:20   ` [PATCH v2 1/5] drm/msm/dsi: Make TE gpio optional Archit Taneja
2015-08-02 16:20   ` [PATCH v2 2/5] drm/msm/dsi: Refer to connected device as 'device' instead of 'panel' Archit Taneja
2015-08-02 16:20   ` [PATCH v2 3/5] drm/msm/dsi: Create a helper to check if there is a connected device Archit Taneja
2015-08-02 16:20   ` Archit Taneja [this message]
2015-08-02 16:20   ` [PATCH v2 5/5] drm/msm/dsi: Modify dsi manager bridge ops to work with external bridges Archit Taneja

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1438532437-24646-5-git-send-email-architt@codeaurora.org \
    --to=architt@codeaurora.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hali@codeaurora.org \
    --cc=jilaiw@codeaurora.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=robdclark@gmail.com \
    --cc=sviau@codeaurora.org \
    --cc=wentaox@codeaurora.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).