dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] drm/msm/dsi: stop using drm_panel directly
@ 2022-07-11  9:43 Dmitry Baryshkov
  2022-07-11  9:43 ` [PATCH v2 1/4] drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device Dmitry Baryshkov
                   ` (3 more replies)
  0 siblings, 4 replies; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-11  9:43 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Thierry Reding, Sam Ravnborg, David Airlie, Daniel Vetter,
	Rob Clark, Sean Paul, Abhinav Kumar
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd

This series superseeds two existing patch series ([1] and [2]) and
merges them together in a single patchset to demonstrate necessity for
the first three patches.

The drm/msm/dsi driver has two separate code paths, one utilizing a
chain of drm_bridges and another one for directly interfacing the
drm_panel. We would have dropped the second path completely but for the
DSI DSC pps data.

To properly support DSI DSC the DSI sink driver (panel) has to pass DSC
pps data to the source (DSI host). The commit 0f40ba48de3b
("drm/msm/dsi: Pass DSC params to drm_panel") added a pointer to the DSC
data to the struct drm_panel. However this is not ideal.

First, this keeps DSC-supporting DSI sink bridges out of the picture
(like ANX7625 which support DSC decoding on the MIPI DSI inputs).

Second, this does not play well with the panel_bridge. Drivers depending
solely on the bridge chains will still have to lookup panel and fetch
data from it.

Last, but not least, the DSC data is not relevant for the wide variety
of panels including DPI and LVDS panels.

To solve all these problems, move struct drm_dsc_config pointer from
struct drm_panel to struct mipi_host_device. This way MIPI DSI host
driver receives DSC data during attach callback without additional
lookups.

The last commit drops the drm_panel code from msm/dsi driver, providing
code simplification.

Changes since v1 (of both patchsets):
 - Minor cleanups in the msm/dsi driver, dropping more now-unused code.

[1] https://patchwork.freedesktop.org/series/103411/
[2] https://patchwork.freedesktop.org/series/105995/

Dmitry Baryshkov (4):
  drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device
  drm/msm/dsi: fetch DSC pps payload from struct mipi_dsi_device
  drm/panel: drop DSC pps pointer
  drm/msm/dsi: switch to DRM_PANEL_BRIDGE

 drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
 drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c    |  50 ++---
 drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
 include/drm/drm_mipi_dsi.h            |   2 +
 include/drm/drm_panel.h               |   7 -
 6 files changed, 39 insertions(+), 336 deletions(-)

-- 
2.35.1


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2 1/4] drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device
  2022-07-11  9:43 [PATCH v2 0/4] drm/msm/dsi: stop using drm_panel directly Dmitry Baryshkov
@ 2022-07-11  9:43 ` Dmitry Baryshkov
  2022-07-11 17:41   ` Abhinav Kumar
  2022-07-11  9:43 ` [PATCH v2 2/4] drm/msm/dsi: fetch DSC pps payload from " Dmitry Baryshkov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-11  9:43 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Thierry Reding, Sam Ravnborg, David Airlie, Daniel Vetter,
	Rob Clark, Sean Paul, Abhinav Kumar
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd

The commit 0f40ba48de3b ("drm/msm/dsi: Pass DSC params to drm_panel")
added a pointer to the DSC data to the struct drm_panel. However DSC
support is not limited to the DSI panels. MIPI DSI bridges can also
consume DSC command streams. Thus add struct drm_dsc_config pointer to
the struct mipi_dsi_device.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 include/drm/drm_mipi_dsi.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 91a164bdd8f3..bb20bc27ce87 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -179,6 +179,7 @@ struct mipi_dsi_device_info {
  * @lp_rate: maximum lane frequency for low power mode in hertz, this should
  * be set to the real limits of the hardware, zero is only accepted for
  * legacy drivers
+ * @dsc: panel/bridge DSC pps payload to be sent
  */
 struct mipi_dsi_device {
 	struct mipi_dsi_host *host;
@@ -191,6 +192,7 @@ struct mipi_dsi_device {
 	unsigned long mode_flags;
 	unsigned long hs_rate;
 	unsigned long lp_rate;
+	struct drm_dsc_config *dsc;
 };
 
 #define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 2/4] drm/msm/dsi: fetch DSC pps payload from struct mipi_dsi_device
  2022-07-11  9:43 [PATCH v2 0/4] drm/msm/dsi: stop using drm_panel directly Dmitry Baryshkov
  2022-07-11  9:43 ` [PATCH v2 1/4] drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device Dmitry Baryshkov
@ 2022-07-11  9:43 ` Dmitry Baryshkov
  2022-07-11 17:42   ` Abhinav Kumar
  2022-07-11  9:43 ` [PATCH v2 3/4] drm/panel: drop DSC pps pointer Dmitry Baryshkov
  2022-07-11  9:43 ` [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
  3 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-11  9:43 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Thierry Reding, Sam Ravnborg, David Airlie, Daniel Vetter,
	Rob Clark, Sean Paul, Abhinav Kumar
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd

Now that struct mipi_dsi_device provides DSC data, fetch it from the
mentioned struct rather than from the struct drm_panel itself. This
would allow supporting MIPI DSI bridges handling DSC on their input
side.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/dsi/dsi_host.c | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index a34078497af1..fb5ab6c718c8 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -1686,6 +1686,17 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
 	msm_host->lanes = dsi->lanes;
 	msm_host->format = dsi->format;
 	msm_host->mode_flags = dsi->mode_flags;
+	if (dsi->dsc) {
+		struct msm_display_dsc_config *dsc = msm_host->dsc;
+
+		if (!dsc) {
+			dsc = devm_kzalloc(&msm_host->pdev->dev, sizeof(*dsc), GFP_KERNEL);
+			if (!dsc)
+				return -ENOMEM;
+			dsc->drm = dsi->dsc;
+			msm_host->dsc = dsc;
+		}
+	}
 
 	/* Some gpios defined in panel DT need to be controlled by host */
 	ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev);
@@ -2159,23 +2170,9 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
 {
 	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
 	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
-	struct drm_panel *panel;
 	int ret;
 
 	msm_host->dev = dev;
-	panel = msm_dsi_host_get_panel(&msm_host->base);
-
-	if (!IS_ERR(panel) && panel->dsc) {
-		struct msm_display_dsc_config *dsc = msm_host->dsc;
-
-		if (!dsc) {
-			dsc = devm_kzalloc(&msm_host->pdev->dev, sizeof(*dsc), GFP_KERNEL);
-			if (!dsc)
-				return -ENOMEM;
-			dsc->drm = panel->dsc;
-			msm_host->dsc = dsc;
-		}
-	}
 
 	ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K);
 	if (ret) {
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 3/4] drm/panel: drop DSC pps pointer
  2022-07-11  9:43 [PATCH v2 0/4] drm/msm/dsi: stop using drm_panel directly Dmitry Baryshkov
  2022-07-11  9:43 ` [PATCH v2 1/4] drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device Dmitry Baryshkov
  2022-07-11  9:43 ` [PATCH v2 2/4] drm/msm/dsi: fetch DSC pps payload from " Dmitry Baryshkov
@ 2022-07-11  9:43 ` Dmitry Baryshkov
  2022-07-11 17:52   ` Abhinav Kumar
  2022-07-11  9:43 ` [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
  3 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-11  9:43 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Thierry Reding, Sam Ravnborg, David Airlie, Daniel Vetter,
	Rob Clark, Sean Paul, Abhinav Kumar
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd

Complete the move of DSC data pointer from struct drm_panel to struct
mipi_dsi_device.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 include/drm/drm_panel.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 3a271128c078..994bfcdd84c5 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -188,13 +188,6 @@ struct drm_panel {
 	 * Panel entry in registry.
 	 */
 	struct list_head list;
-
-	/**
-	 * @dsc:
-	 *
-	 * Panel DSC pps payload to be sent
-	 */
-	struct drm_dsc_config *dsc;
 };
 
 void drm_panel_init(struct drm_panel *panel, struct device *dev,
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-11  9:43 [PATCH v2 0/4] drm/msm/dsi: stop using drm_panel directly Dmitry Baryshkov
                   ` (2 preceding siblings ...)
  2022-07-11  9:43 ` [PATCH v2 3/4] drm/panel: drop DSC pps pointer Dmitry Baryshkov
@ 2022-07-11  9:43 ` Dmitry Baryshkov
  2022-07-11 22:39   ` Abhinav Kumar
  3 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-11  9:43 UTC (permalink / raw)
  To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Thierry Reding, Sam Ravnborg, David Airlie, Daniel Vetter,
	Rob Clark, Sean Paul, Abhinav Kumar
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd

Currently the DSI driver has two separate paths: one if the next device
in a chain is a bridge and another one if the panel is connected
directly to the DSI host. Simplify the code path by using panel-bridge
driver (already selected in Kconfig) and dropping support for
handling the panel directly.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
 drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
 drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
 4 files changed, 26 insertions(+), 315 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 1625328fa430..3c53e28092db 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -6,14 +6,6 @@
 #include "dsi.h"
 #include "dsi_cfg.h"
 
-struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
-{
-	if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
-		return NULL;
-
-	return msm_dsi->encoder;
-}
-
 bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
 {
 	unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
@@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 			 struct drm_encoder *encoder)
 {
 	struct msm_drm_private *priv;
-	struct drm_bridge *ext_bridge;
+	struct drm_connector *connector;
 	int ret;
 
 	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
@@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 		goto fail;
 	}
 
-	/*
-	 * 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);
+	connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
+
+	if (IS_ERR(connector)) {
+		ret = PTR_ERR(connector);
 		DRM_DEV_ERROR(dev->dev,
 			"failed to create dsi connector: %d\n", ret);
-		msm_dsi->connector = NULL;
 		goto fail;
 	}
 
@@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 		msm_dsi->bridge = NULL;
 	}
 
-	/* 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;
-
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 580a1e6358bf..41630b8f5358 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -12,7 +12,6 @@
 #include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_mipi_dsi.h>
-#include <drm/drm_panel.h>
 
 #include "msm_drv.h"
 #include "disp/msm_disp_snapshot.h"
@@ -49,8 +48,6 @@ 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;
 
@@ -58,10 +55,8 @@ struct msm_dsi {
 	struct msm_dsi_phy *phy;
 
 	/*
-	 * panel/external_bridge connected to dsi bridge output, only one of the
-	 * two can be valid at a time
+	 * external_bridge connected to dsi bridge output
 	 */
-	struct drm_panel *panel;
 	struct drm_bridge *external_bridge;
 
 	struct device *phy_dev;
@@ -76,7 +71,6 @@ struct msm_dsi {
 /* dsi manager */
 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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
 bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
@@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
 /* msm dsi */
 static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
 {
-	return msm_dsi->panel || msm_dsi->external_bridge;
+	return msm_dsi->external_bridge;
 }
 
-struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
-
 /* dsi host */
 struct msm_dsi_host;
 int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
@@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
 				  const struct drm_display_mode *mode);
 enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
 					    const struct drm_display_mode *mode);
-struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
 unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
-struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
 int msm_dsi_host_register(struct mipi_dsi_host *host);
 void msm_dsi_host_unregister(struct mipi_dsi_host *host);
 void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -164,7 +164,6 @@ struct msm_dsi_host {
 	struct msm_display_dsc_config *dsc;
 
 	/* connected device info */
-	struct device_node *device_node;
 	unsigned int channel;
 	unsigned int lanes;
 	enum mipi_dsi_pixel_format format;
@@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
 
 	dsi_dev_detach(msm_host->pdev);
 
-	msm_host->device_node = NULL;
-
 	DBG("id=%d", msm_host->id);
 	if (msm_host->dev)
 		queue_work(msm_host->workqueue, &msm_host->hpd_work);
@@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
 		goto err;
 	}
 
-	/* Get panel node from the output port's endpoint data */
-	device_node = of_graph_get_remote_node(np, 1, 0);
-	if (!device_node) {
-		DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
-		ret = -ENODEV;
-		goto err;
-	}
-
-	msm_host->device_node = device_node;
-
 	if (of_property_read_bool(np, "syscon-sfpb")) {
 		msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
 					"syscon-sfpb");
@@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
 	return MODE_OK;
 }
 
-struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
-{
-	return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
-}
-
 unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
 {
 	return to_msm_dsi_host(host)->mode_flags;
 }
 
-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);
-}
-
 void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
 {
 	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index cb84d185d73a..3970368e07d5 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
 	}
 }
 
-struct dsi_connector {
-	struct drm_connector base;
-	int id;
-};
-
 struct dsi_bridge {
 	struct drm_bridge base;
 	int id;
 };
 
-#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
 #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
 
-static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
-{
-	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
-	return dsi_connector->id;
-}
-
 static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
 {
 	struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
 	return dsi_bridge->id;
 }
 
-static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
+static void msm_dsi_manager_set_split_display(u8 id)
 {
-	struct msm_drm_private *priv = conn->dev->dev_private;
-	struct msm_kms *kms = priv->kms;
 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
 	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+	struct msm_drm_private *priv = msm_dsi->dev->dev_private;
+	struct msm_kms *kms = priv->kms;
 	struct msm_dsi *master_dsi, *slave_dsi;
-	struct drm_panel *panel;
 
 	if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
 		master_dsi = other_dsi;
@@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
 		slave_dsi = other_dsi;
 	}
 
-	/*
-	 * There is only 1 panel in the global panel list for bonded DSI mode.
-	 * Therefore slave dsi should get the drm_panel instance from master
-	 * dsi.
-	 */
-	panel = msm_dsi_host_get_panel(master_dsi->host);
-	if (IS_ERR(panel)) {
-		DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
-			  PTR_ERR(panel));
-		return PTR_ERR(panel);
-	}
-
-	if (!panel || !IS_BONDED_DSI())
-		goto out;
-
-	drm_object_attach_property(&conn->base,
-				   conn->dev->mode_config.tile_property, 0);
+	if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
+		return;
 
 	/*
 	 * Set split display info to kms once bonded DSI panel is connected to
 	 * both hosts.
 	 */
-	if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
+	if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
 		kms->funcs->set_split_display(kms, master_dsi->encoder,
 					      slave_dsi->encoder,
 					      msm_dsi_is_cmd_mode(msm_dsi));
 	}
-
-out:
-	msm_dsi->panel = panel;
-	return 0;
-}
-
-static enum drm_connector_status dsi_mgr_connector_detect(
-		struct drm_connector *connector, bool force)
-{
-	int id = dsi_mgr_connector_get_id(connector);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-
-	return msm_dsi->panel ? connector_status_connected :
-		connector_status_disconnected;
-}
-
-static void dsi_mgr_connector_destroy(struct drm_connector *connector)
-{
-	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
-
-	DBG("");
-
-	drm_connector_cleanup(connector);
-
-	kfree(dsi_connector);
-}
-
-static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
-{
-	int id = dsi_mgr_connector_get_id(connector);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-	struct drm_panel *panel = msm_dsi->panel;
-	int num;
-
-	if (!panel)
-		return 0;
-
-	/*
-	 * In bonded DSI mode, we have one connector that can be
-	 * attached to the drm_panel.
-	 */
-	num = drm_panel_get_modes(panel, connector);
-	if (!num)
-		return 0;
-
-	return num;
-}
-
-static struct drm_encoder *
-dsi_mgr_connector_best_encoder(struct drm_connector *connector)
-{
-	int id = dsi_mgr_connector_get_id(connector);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-
-	DBG("");
-	return msm_dsi_get_encoder(msm_dsi);
 }
 
 static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
@@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
 	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
 	struct mipi_dsi_host *host = msm_dsi->host;
-	struct drm_panel *panel = msm_dsi->panel;
 	bool is_bonded_dsi = IS_BONDED_DSI();
 	int ret;
 
@@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
 	if (!dsi_mgr_power_on_early(bridge))
 		dsi_mgr_bridge_power_on(bridge);
 
-	/* Always call panel functions once, because even for dual panels,
-	 * there is only one drm_panel instance.
-	 */
-	if (panel) {
-		ret = drm_panel_prepare(panel);
-		if (ret) {
-			pr_err("%s: prepare panel %d failed, %d\n", __func__,
-								id, ret);
-			goto panel_prep_fail;
-		}
-	}
-
 	ret = msm_dsi_host_enable(host);
 	if (ret) {
 		pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
@@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
 host1_en_fail:
 	msm_dsi_host_disable(host);
 host_en_fail:
-	if (panel)
-		drm_panel_unprepare(panel);
-panel_prep_fail:
 
 	return;
 }
@@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
 	}
 }
 
-static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
-{
-	int id = dsi_mgr_bridge_get_id(bridge);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-	struct drm_panel *panel = msm_dsi->panel;
-	bool is_bonded_dsi = IS_BONDED_DSI();
-	int ret;
-
-	DBG("id=%d", id);
-	if (!msm_dsi_device_connected(msm_dsi))
-		return;
-
-	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
-	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
-		return;
-
-	if (panel) {
-		ret = drm_panel_enable(panel);
-		if (ret) {
-			pr_err("%s: enable panel %d failed, %d\n", __func__, id,
-									ret);
-		}
-	}
-}
-
-static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
-{
-	int id = dsi_mgr_bridge_get_id(bridge);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-	struct drm_panel *panel = msm_dsi->panel;
-	bool is_bonded_dsi = IS_BONDED_DSI();
-	int ret;
-
-	DBG("id=%d", id);
-	if (!msm_dsi_device_connected(msm_dsi))
-		return;
-
-	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
-	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
-		return;
-
-	if (panel) {
-		ret = drm_panel_disable(panel);
-		if (ret)
-			pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
-									ret);
-	}
-}
-
 static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
 {
 	int id = dsi_mgr_bridge_get_id(bridge);
 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
 	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
 	struct mipi_dsi_host *host = msm_dsi->host;
-	struct drm_panel *panel = msm_dsi->panel;
 	bool is_bonded_dsi = IS_BONDED_DSI();
 	int ret;
 
@@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
 			pr_err("%s: host1 disable failed, %d\n", __func__, ret);
 	}
 
-	if (panel) {
-		ret = drm_panel_unprepare(panel);
-		if (ret)
-			pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
-								id, ret);
-	}
-
 	msm_dsi_host_disable_irq(host);
 	if (is_bonded_dsi && msm_dsi1)
 		msm_dsi_host_disable_irq(msm_dsi1->host);
@@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
 	return msm_dsi_host_check_dsc(host, mode);
 }
 
-static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
-	.detect = dsi_mgr_connector_detect,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = dsi_mgr_connector_destroy,
-	.reset = drm_atomic_helper_connector_reset,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
-	.get_modes = dsi_mgr_connector_get_modes,
-	.best_encoder = dsi_mgr_connector_best_encoder,
-};
-
 static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
 	.pre_enable = dsi_mgr_bridge_pre_enable,
-	.enable = dsi_mgr_bridge_enable,
-	.disable = dsi_mgr_bridge_disable,
 	.post_disable = dsi_mgr_bridge_post_disable,
 	.mode_set = dsi_mgr_bridge_mode_set,
 	.mode_valid = dsi_mgr_bridge_mode_valid,
 };
 
-/* 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);
-	struct drm_connector *connector = NULL;
-	struct dsi_connector *dsi_connector;
-	int ret;
-
-	dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
-	if (!dsi_connector)
-		return ERR_PTR(-ENOMEM);
-
-	dsi_connector->id = id;
-
-	connector = &dsi_connector->base;
-
-	ret = drm_connector_init(msm_dsi->dev, connector,
-			&dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
-	if (ret)
-		return ERR_PTR(ret);
-
-	drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
-
-	/* Enable HPD to let hpd event is handled
-	 * when panel is attached to the host.
-	 */
-	connector->polled = DRM_CONNECTOR_POLL_HPD;
-
-	/* Display driver doesn't support interlace now. */
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-
-	drm_connector_attach_encoder(connector, msm_dsi->encoder);
-
-	ret = msm_dsi_manager_panel_init(connector, id);
-	if (ret) {
-		DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
-		goto fail;
-	}
-
-	return connector;
-
-fail:
-	connector->funcs->destroy(connector);
-	return ERR_PTR(ret);
-}
-
 /* initialize bridge */
 struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
 {
@@ -732,8 +512,11 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
 	int ret;
 
 	int_bridge = msm_dsi->bridge;
-	ext_bridge = msm_dsi->external_bridge =
-			msm_dsi_host_get_bridge(msm_dsi->host);
+	ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, msm_dsi->pdev->dev.of_node, 1, 0);
+	if (IS_ERR(ext_bridge))
+		return ERR_CAST(ext_bridge);
+
+	msm_dsi->external_bridge = ext_bridge;
 
 	encoder = msm_dsi->encoder;
 
@@ -745,25 +528,12 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
 	ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
 			DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret == -EINVAL) {
-		struct drm_connector *connector;
-		struct list_head *connector_list;
-
 		/* link the internal dsi bridge to the external bridge */
-		drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
+		ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
+		if (ret < 0)
+			return ERR_PTR(ret);
 
-		/*
-		 * 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) {
-			if (drm_connector_has_possible_encoder(connector, encoder))
-				return connector;
-		}
-
-		return ERR_PTR(-ENODEV);
+		goto out;
 	}
 
 	connector = drm_bridge_connector_init(dev, encoder);
@@ -774,6 +544,10 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
 
 	drm_connector_attach_encoder(connector, encoder);
 
+out:
+	/* The pipeline is ready, ping encoders if necessary */
+	msm_dsi_manager_set_split_display(id);
+
 	return connector;
 }
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 1/4] drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device
  2022-07-11  9:43 ` [PATCH v2 1/4] drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device Dmitry Baryshkov
@ 2022-07-11 17:41   ` Abhinav Kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-11 17:41 UTC (permalink / raw)
  To: Dmitry Baryshkov, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Thierry Reding, Sam Ravnborg, David Airlie,
	Daniel Vetter, Rob Clark, Sean Paul
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd



On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
> The commit 0f40ba48de3b ("drm/msm/dsi: Pass DSC params to drm_panel")
> added a pointer to the DSC data to the struct drm_panel. However DSC
> support is not limited to the DSI panels. MIPI DSI bridges can also
> consume DSC command streams. Thus add struct drm_dsc_config pointer to
> the struct mipi_dsi_device.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

Agreed, DSC params are not limited to a drm_panel. From that standpoint, 
this change seems logical to me, hence

Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>

> ---
>   include/drm/drm_mipi_dsi.h | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
> index 91a164bdd8f3..bb20bc27ce87 100644
> --- a/include/drm/drm_mipi_dsi.h
> +++ b/include/drm/drm_mipi_dsi.h
> @@ -179,6 +179,7 @@ struct mipi_dsi_device_info {
>    * @lp_rate: maximum lane frequency for low power mode in hertz, this should
>    * be set to the real limits of the hardware, zero is only accepted for
>    * legacy drivers
> + * @dsc: panel/bridge DSC pps payload to be sent
>    */
>   struct mipi_dsi_device {
>   	struct mipi_dsi_host *host;
> @@ -191,6 +192,7 @@ struct mipi_dsi_device {
>   	unsigned long mode_flags;
>   	unsigned long hs_rate;
>   	unsigned long lp_rate;
> +	struct drm_dsc_config *dsc;
>   };
>   
>   #define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 2/4] drm/msm/dsi: fetch DSC pps payload from struct mipi_dsi_device
  2022-07-11  9:43 ` [PATCH v2 2/4] drm/msm/dsi: fetch DSC pps payload from " Dmitry Baryshkov
@ 2022-07-11 17:42   ` Abhinav Kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-11 17:42 UTC (permalink / raw)
  To: Dmitry Baryshkov, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Thierry Reding, Sam Ravnborg, David Airlie,
	Daniel Vetter, Rob Clark, Sean Paul
  Cc: linux-arm-msm, dri-devel, Bjorn Andersson, Vinod Koul,
	Stephen Boyd, freedreno



On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
> Now that struct mipi_dsi_device provides DSC data, fetch it from the
> mentioned struct rather than from the struct drm_panel itself. This
> would allow supporting MIPI DSI bridges handling DSC on their input
> side.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

Would prefer to have Vinod's Tested-by on this series once we get all 
the R-bs but other than this change is,

Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>

> ---
>   drivers/gpu/drm/msm/dsi/dsi_host.c | 25 +++++++++++--------------
>   1 file changed, 11 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
> index a34078497af1..fb5ab6c718c8 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -1686,6 +1686,17 @@ static int dsi_host_attach(struct mipi_dsi_host *host,
>   	msm_host->lanes = dsi->lanes;
>   	msm_host->format = dsi->format;
>   	msm_host->mode_flags = dsi->mode_flags;
> +	if (dsi->dsc) {
> +		struct msm_display_dsc_config *dsc = msm_host->dsc;
> +
> +		if (!dsc) {
> +			dsc = devm_kzalloc(&msm_host->pdev->dev, sizeof(*dsc), GFP_KERNEL);
> +			if (!dsc)
> +				return -ENOMEM;
> +			dsc->drm = dsi->dsc;
> +			msm_host->dsc = dsc;
> +		}
> +	}
>   
>   	/* Some gpios defined in panel DT need to be controlled by host */
>   	ret = dsi_host_init_panel_gpios(msm_host, &dsi->dev);
> @@ -2159,23 +2170,9 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
>   {
>   	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
>   	const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
> -	struct drm_panel *panel;
>   	int ret;
>   
>   	msm_host->dev = dev;
> -	panel = msm_dsi_host_get_panel(&msm_host->base);
> -
> -	if (!IS_ERR(panel) && panel->dsc) {
> -		struct msm_display_dsc_config *dsc = msm_host->dsc;
> -
> -		if (!dsc) {
> -			dsc = devm_kzalloc(&msm_host->pdev->dev, sizeof(*dsc), GFP_KERNEL);
> -			if (!dsc)
> -				return -ENOMEM;
> -			dsc->drm = panel->dsc;
> -			msm_host->dsc = dsc;
> -		}
> -	}
>   
>   	ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K);
>   	if (ret) {

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 3/4] drm/panel: drop DSC pps pointer
  2022-07-11  9:43 ` [PATCH v2 3/4] drm/panel: drop DSC pps pointer Dmitry Baryshkov
@ 2022-07-11 17:52   ` Abhinav Kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-11 17:52 UTC (permalink / raw)
  To: Dmitry Baryshkov, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Thierry Reding, Sam Ravnborg, David Airlie,
	Daniel Vetter, Rob Clark, Sean Paul
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd



On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
> Complete the move of DSC data pointer from struct drm_panel to struct
> mipi_dsi_device.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
> ---
>   include/drm/drm_panel.h | 7 -------
>   1 file changed, 7 deletions(-)
> 
> diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> index 3a271128c078..994bfcdd84c5 100644
> --- a/include/drm/drm_panel.h
> +++ b/include/drm/drm_panel.h
> @@ -188,13 +188,6 @@ struct drm_panel {
>   	 * Panel entry in registry.
>   	 */
>   	struct list_head list;
> -
> -	/**
> -	 * @dsc:
> -	 *
> -	 * Panel DSC pps payload to be sent
> -	 */
> -	struct drm_dsc_config *dsc;
>   };
>   
>   void drm_panel_init(struct drm_panel *panel, struct device *dev,

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-11  9:43 ` [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
@ 2022-07-11 22:39   ` Abhinav Kumar
  2022-07-11 22:54     ` [Freedreno] " Abhinav Kumar
                       ` (2 more replies)
  0 siblings, 3 replies; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-11 22:39 UTC (permalink / raw)
  To: Dmitry Baryshkov, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Thierry Reding, Sam Ravnborg, David Airlie,
	Daniel Vetter, Rob Clark, Sean Paul
  Cc: linux-arm-msm, Bjorn Andersson, freedreno, dri-devel, Stephen Boyd



On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
> Currently the DSI driver has two separate paths: one if the next device
> in a chain is a bridge and another one if the panel is connected
> directly to the DSI host. Simplify the code path by using panel-bridge
> driver (already selected in Kconfig) and dropping support for
> handling the panel directly.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>   drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
>   drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
>   4 files changed, 26 insertions(+), 315 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
> index 1625328fa430..3c53e28092db 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> @@ -6,14 +6,6 @@
>   #include "dsi.h"
>   #include "dsi_cfg.h"
>   
> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
> -{
> -	if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
> -		return NULL;
> -
> -	return msm_dsi->encoder;
> -}

panel_bridge doesnt have the best_encoder method today.
Today, this does not break anything for us.
But, for future if we do need it, panel_bridge needs to be expanded to 
add that method?

> -
>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>   {
>   	unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
> @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   			 struct drm_encoder *encoder)
>   {
>   	struct msm_drm_private *priv;
> -	struct drm_bridge *ext_bridge;
> +	struct drm_connector *connector;
>   	int ret;
>   
>   	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
> @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   		goto fail;
>   	}
>   
> -	/*
> -	 * 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);
> +	connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
> +
> +	if (IS_ERR(connector)) {
> +		ret = PTR_ERR(connector);
>   		DRM_DEV_ERROR(dev->dev,
>   			"failed to create dsi connector: %d\n", ret);
> -		msm_dsi->connector = NULL;
>   		goto fail;
>   	}
>   
> @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   		msm_dsi->bridge = NULL;
>   	}
>   
> -	/* 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;
> -
>   	return ret;
>   }
>   
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> index 580a1e6358bf..41630b8f5358 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> @@ -12,7 +12,6 @@
>   #include <drm/drm_bridge.h>
>   #include <drm/drm_crtc.h>
>   #include <drm/drm_mipi_dsi.h>
> -#include <drm/drm_panel.h>
>   
>   #include "msm_drv.h"
>   #include "disp/msm_disp_snapshot.h"
> @@ -49,8 +48,6 @@ 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;
>   
> @@ -58,10 +55,8 @@ struct msm_dsi {
>   	struct msm_dsi_phy *phy;
>   
>   	/*
> -	 * panel/external_bridge connected to dsi bridge output, only one of the
> -	 * two can be valid at a time
> +	 * external_bridge connected to dsi bridge output
>   	 */
> -	struct drm_panel *panel;
>   	struct drm_bridge *external_bridge;
>   
>   	struct device *phy_dev;
> @@ -76,7 +71,6 @@ struct msm_dsi {
>   /* dsi manager */
>   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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>   bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>   /* msm dsi */
>   static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>   {
> -	return msm_dsi->panel || msm_dsi->external_bridge;
> +	return msm_dsi->external_bridge;
>   }
>   
> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
> -
>   /* dsi host */
>   struct msm_dsi_host;
>   int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
>   				  const struct drm_display_mode *mode);
>   enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>   					    const struct drm_display_mode *mode);
> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>   int msm_dsi_host_register(struct mipi_dsi_host *host);
>   void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>   void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>   	struct msm_display_dsc_config *dsc;
>   
>   	/* connected device info */
> -	struct device_node *device_node;
>   	unsigned int channel;
>   	unsigned int lanes;
>   	enum mipi_dsi_pixel_format format;
> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
>   
>   	dsi_dev_detach(msm_host->pdev);
>   
> -	msm_host->device_node = NULL;
> -
>   	DBG("id=%d", msm_host->id);
>   	if (msm_host->dev)
>   		queue_work(msm_host->workqueue, &msm_host->hpd_work);
> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
>   		goto err;
>   	}
>   
> -	/* Get panel node from the output port's endpoint data */
> -	device_node = of_graph_get_remote_node(np, 1, 0);
> -	if (!device_node) {
> -		DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
> -		ret = -ENODEV;
> -		goto err;
> -	}
> -
> -	msm_host->device_node = device_node;
> -
>   	if (of_property_read_bool(np, "syscon-sfpb")) {
>   		msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>   					"syscon-sfpb");
> @@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>   	return MODE_OK;
>   }
>   
> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
> -{
> -	return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
> -}
> -
>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>   {
>   	return to_msm_dsi_host(host)->mode_flags;
>   }
>   
> -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);
> -}
> -
>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
>   {
>   	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index cb84d185d73a..3970368e07d5 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>   	}
>   }
>   
> -struct dsi_connector {
> -	struct drm_connector base;
> -	int id;
> -};
> -
>   struct dsi_bridge {
>   	struct drm_bridge base;
>   	int id;
>   };
>   
> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>   #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
>   
> -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
> -{
> -	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> -	return dsi_connector->id;
> -}
> -
>   static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>   {
>   	struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>   	return dsi_bridge->id;
>   }
>   
> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> +static void msm_dsi_manager_set_split_display(u8 id)
>   {
> -	struct msm_drm_private *priv = conn->dev->dev_private;
> -	struct msm_kms *kms = priv->kms;
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
> +	struct msm_drm_private *priv = msm_dsi->dev->dev_private;
> +	struct msm_kms *kms = priv->kms;
>   	struct msm_dsi *master_dsi, *slave_dsi;
> -	struct drm_panel *panel;
>   
>   	if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>   		master_dsi = other_dsi;
> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>   		slave_dsi = other_dsi;
>   	}
>   
> -	/*
> -	 * There is only 1 panel in the global panel list for bonded DSI mode.
> -	 * Therefore slave dsi should get the drm_panel instance from master
> -	 * dsi.
> -	 */
> -	panel = msm_dsi_host_get_panel(master_dsi->host);
> -	if (IS_ERR(panel)) {
> -		DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
> -			  PTR_ERR(panel));
> -		return PTR_ERR(panel);
> -	}
> -
> -	if (!panel || !IS_BONDED_DSI())
> -		goto out;
> -
> -	drm_object_attach_property(&conn->base,
> -				   conn->dev->mode_config.tile_property, 0);
> +	if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
> +		return;
>   
>   	/*
>   	 * Set split display info to kms once bonded DSI panel is connected to
>   	 * both hosts.
>   	 */
> -	if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
> +	if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
>   		kms->funcs->set_split_display(kms, master_dsi->encoder,
>   					      slave_dsi->encoder,
>   					      msm_dsi_is_cmd_mode(msm_dsi));
>   	}
> -
> -out:
> -	msm_dsi->panel = panel;
> -	return 0;
> -}
> -
> -static enum drm_connector_status dsi_mgr_connector_detect(
> -		struct drm_connector *connector, bool force)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -
> -	return msm_dsi->panel ? connector_status_connected :
> -		connector_status_disconnected;
> -}
> -
> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
> -{
> -	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> -
> -	DBG("");
> -
> -	drm_connector_cleanup(connector);
> -
> -	kfree(dsi_connector);
> -}
> -
> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	int num;
> -
> -	if (!panel)
> -		return 0;
> -
> -	/*
> -	 * In bonded DSI mode, we have one connector that can be
> -	 * attached to the drm_panel.
> -	 */
> -	num = drm_panel_get_modes(panel, connector);
> -	if (!num)
> -		return 0;
> -
> -	return num;
> -}
> -
> -static struct drm_encoder *
> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -
> -	DBG("");
> -	return msm_dsi_get_encoder(msm_dsi);
>   }
>   
>   static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>   	struct mipi_dsi_host *host = msm_dsi->host;
> -	struct drm_panel *panel = msm_dsi->panel;
>   	bool is_bonded_dsi = IS_BONDED_DSI();
>   	int ret;
>   
> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   	if (!dsi_mgr_power_on_early(bridge))
>   		dsi_mgr_bridge_power_on(bridge);
>   
> -	/* Always call panel functions once, because even for dual panels,
> -	 * there is only one drm_panel instance.
> -	 */
> -	if (panel) {
> -		ret = drm_panel_prepare(panel);
> -		if (ret) {
> -			pr_err("%s: prepare panel %d failed, %d\n", __func__,
> -								id, ret);
> -			goto panel_prep_fail;
> -		}
> -	}
> -
>   	ret = msm_dsi_host_enable(host);
>   	if (ret) {
>   		pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   host1_en_fail:
>   	msm_dsi_host_disable(host);
>   host_en_fail:
> -	if (panel)
> -		drm_panel_unprepare(panel);
> -panel_prep_fail:
>   
>   	return;
>   }
> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>   	}
>   }
>   
> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
> -{
> -	int id = dsi_mgr_bridge_get_id(bridge);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	bool is_bonded_dsi = IS_BONDED_DSI();
> -	int ret;
> -
> -	DBG("id=%d", id);
> -	if (!msm_dsi_device_connected(msm_dsi))
> -		return;
> -
> -	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> -	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> -		return;
> -
> -	if (panel) {
> -		ret = drm_panel_enable(panel);
> -		if (ret) {
> -			pr_err("%s: enable panel %d failed, %d\n", __func__, id,
> -									ret);
> -		}
> -	}
> -}
> -
> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
> -{
> -	int id = dsi_mgr_bridge_get_id(bridge);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	bool is_bonded_dsi = IS_BONDED_DSI();
> -	int ret;
> -
> -	DBG("id=%d", id);
> -	if (!msm_dsi_device_connected(msm_dsi))
> -		return;
> -
> -	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> -	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> -		return;
> -
> -	if (panel) {
> -		ret = drm_panel_disable(panel);
> -		if (ret)
> -			pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
> -									ret);
> -	}
> -}
> -
>   static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>   {
>   	int id = dsi_mgr_bridge_get_id(bridge);
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>   	struct mipi_dsi_host *host = msm_dsi->host;
> -	struct drm_panel *panel = msm_dsi->panel;
>   	bool is_bonded_dsi = IS_BONDED_DSI();
>   	int ret;
>   
> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>   			pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>   	}
>   
> -	if (panel) {
> -		ret = drm_panel_unprepare(panel);
> -		if (ret)
> -			pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
> -								id, ret);
> -	}
> -
>   	msm_dsi_host_disable_irq(host);
>   	if (is_bonded_dsi && msm_dsi1)
>   		msm_dsi_host_disable_irq(msm_dsi1->host);
> @@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>   	return msm_dsi_host_check_dsc(host, mode);
>   }
>   
> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
> -	.detect = dsi_mgr_connector_detect,
> -	.fill_modes = drm_helper_probe_single_connector_modes,
> -	.destroy = dsi_mgr_connector_destroy,
> -	.reset = drm_atomic_helper_connector_reset,
> -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> -	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> -};
> -
> -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
> -	.get_modes = dsi_mgr_connector_get_modes,
> -	.best_encoder = dsi_mgr_connector_best_encoder,
> -};
> -
>   static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>   	.pre_enable = dsi_mgr_bridge_pre_enable,
> -	.enable = dsi_mgr_bridge_enable,
> -	.disable = dsi_mgr_bridge_disable,
>   	.post_disable = dsi_mgr_bridge_post_disable,
>   	.mode_set = dsi_mgr_bridge_mode_set,
>   	.mode_valid = dsi_mgr_bridge_mode_valid,
>   };
>   
> -/* 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);
> -	struct drm_connector *connector = NULL;
> -	struct dsi_connector *dsi_connector;
> -	int ret;
> -
> -	dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
> -	if (!dsi_connector)
> -		return ERR_PTR(-ENOMEM);
> -
> -	dsi_connector->id = id;
> -
> -	connector = &dsi_connector->base;
> -
> -	ret = drm_connector_init(msm_dsi->dev, connector,
> -			&dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
> -	if (ret)
> -		return ERR_PTR(ret);
> -
> -	drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
> -
> -	/* Enable HPD to let hpd event is handled
> -	 * when panel is attached to the host.
> -	 */
> -	connector->polled = DRM_CONNECTOR_POLL_HPD;

I see that this part gets removed with this migration.

For fixed/built-in displays, it should not matter i think but i am not 
sure if some usermodes might expect this even for DSI?

So, once again does panel_bridge needs to account for this?


> -
> -	/* Display driver doesn't support interlace now. */
> -	connector->interlace_allowed = 0;
> -	connector->doublescan_allowed = 0;
> -
> -	drm_connector_attach_encoder(connector, msm_dsi->encoder);
> -
> -	ret = msm_dsi_manager_panel_init(connector, id);
> -	if (ret) {
> -		DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
> -		goto fail;
> -	}
> -
> -	return connector;
> -
> -fail:
> -	connector->funcs->destroy(connector);
> -	return ERR_PTR(ret);
> -}
> -
>   /* initialize bridge */
>   struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>   {
> @@ -732,8 +512,11 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>   	int ret;
>   
>   	int_bridge = msm_dsi->bridge;
> -	ext_bridge = msm_dsi->external_bridge =
> -			msm_dsi_host_get_bridge(msm_dsi->host);
> +	ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, msm_dsi->pdev->dev.of_node, 1, 0);
> +	if (IS_ERR(ext_bridge))
> +		return ERR_CAST(ext_bridge);
> +
> +	msm_dsi->external_bridge = ext_bridge;
>   
>   	encoder = msm_dsi->encoder;
>   
> @@ -745,25 +528,12 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>   	ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>   			DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>   	if (ret == -EINVAL) {
> -		struct drm_connector *connector;
> -		struct list_head *connector_list;
> -
>   		/* link the internal dsi bridge to the external bridge */
> -		drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> +		ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> +		if (ret < 0)
> +			return ERR_PTR(ret);
>   
> -		/*
> -		 * 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) {
> -			if (drm_connector_has_possible_encoder(connector, encoder))
> -				return connector;
> -		}
> -
> -		return ERR_PTR(-ENODEV);
> +		goto out;
>   	}
>   
>   	connector = drm_bridge_connector_init(dev, encoder);
> @@ -774,6 +544,10 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>   
>   	drm_connector_attach_encoder(connector, encoder);
>   
> +out:
> +	/* The pipeline is ready, ping encoders if necessary */
> +	msm_dsi_manager_set_split_display(id);
Do you still want to execute msm_dsi_manager_set_split_display even for 
the error case? Like in the above lines you have replaced the return 
ERR_PTR() with the goto out. But do you want to then move the 
set_split_display() call above the out label?

Also, now for the cases where there was an error where the connector was 
not found, we will return a NULL ptr instead of the ERR_PTR(-ENODEV).
Is that expected?

> +
>   	return connector;
>   }
>   

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-11 22:39   ` Abhinav Kumar
@ 2022-07-11 22:54     ` Abhinav Kumar
  2022-07-12 10:13       ` Dmitry Baryshkov
  2022-07-12 10:00     ` Dmitry Baryshkov
  2022-07-12 13:22     ` [PATCH v2.5] " Dmitry Baryshkov
  2 siblings, 1 reply; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-11 22:54 UTC (permalink / raw)
  To: Dmitry Baryshkov, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Thierry Reding, Sam Ravnborg, David Airlie,
	Daniel Vetter, Rob Clark, Sean Paul
  Cc: linux-arm-msm, Stephen Boyd, freedreno, dri-devel, Bjorn Andersson

<missed one comment>


On 7/11/2022 3:39 PM, Abhinav Kumar wrote:
> 
> 
> On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
>> Currently the DSI driver has two separate paths: one if the next device
>> in a chain is a bridge and another one if the panel is connected
>> directly to the DSI host. Simplify the code path by using panel-bridge
>> driver (already selected in Kconfig) and dropping support for
>> handling the panel directly.
>>
>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>>   drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
>>   drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
>>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
>>   4 files changed, 26 insertions(+), 315 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c 
>> b/drivers/gpu/drm/msm/dsi/dsi.c
>> index 1625328fa430..3c53e28092db 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
>> @@ -6,14 +6,6 @@
>>   #include "dsi.h"
>>   #include "dsi_cfg.h"
>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
>> -{
>> -    if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
>> -        return NULL;
>> -
>> -    return msm_dsi->encoder;
>> -}
> 
> panel_bridge doesnt have the best_encoder method today.
> Today, this does not break anything for us.
> But, for future if we do need it, panel_bridge needs to be expanded to 
> add that method?
> 
>> -
>>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>>   {
>>       unsigned long host_flags = 
>> msm_dsi_host_get_mode_flags(msm_dsi->host);
>> @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, 
>> struct drm_device *dev,
>>                struct drm_encoder *encoder)
>>   {
>>       struct msm_drm_private *priv;
>> -    struct drm_bridge *ext_bridge;
>> +    struct drm_connector *connector;
>>       int ret;
>>       if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
>> @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi 
>> *msm_dsi, struct drm_device *dev,
>>           goto fail;
>>       }
>> -    /*
>> -     * 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);
>> +    connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
>> +
>> +    if (IS_ERR(connector)) {
>> +        ret = PTR_ERR(connector);
>>           DRM_DEV_ERROR(dev->dev,
>>               "failed to create dsi connector: %d\n", ret);
>> -        msm_dsi->connector = NULL;
>>           goto fail;
>>       }
>> @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, 
>> struct drm_device *dev,
>>           msm_dsi->bridge = NULL;
>>       }
>> -    /* 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;
>> -
>>       return ret;
>>   }
>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h 
>> b/drivers/gpu/drm/msm/dsi/dsi.h
>> index 580a1e6358bf..41630b8f5358 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi.h
>> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
>> @@ -12,7 +12,6 @@
>>   #include <drm/drm_bridge.h>
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drm_mipi_dsi.h>
>> -#include <drm/drm_panel.h>
>>   #include "msm_drv.h"
>>   #include "disp/msm_disp_snapshot.h"
>> @@ -49,8 +48,6 @@ 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;
>> @@ -58,10 +55,8 @@ struct msm_dsi {
>>       struct msm_dsi_phy *phy;
>>       /*
>> -     * panel/external_bridge connected to dsi bridge output, only one 
>> of the
>> -     * two can be valid at a time
>> +     * external_bridge connected to dsi bridge output
>>        */
>> -    struct drm_panel *panel;
>>       struct drm_bridge *external_bridge;
>>       struct device *phy_dev;
>> @@ -76,7 +71,6 @@ struct msm_dsi {
>>   /* dsi manager */
>>   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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>>   bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
>> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>>   /* msm dsi */
>>   static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>>   {
>> -    return msm_dsi->panel || msm_dsi->external_bridge;
>> +    return msm_dsi->external_bridge;
>>   }
>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
>> -
>>   /* dsi host */
>>   struct msm_dsi_host;
>>   int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
>> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct 
>> mipi_dsi_host *host,
>>                     const struct drm_display_mode *mode);
>>   enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>                           const struct drm_display_mode *mode);
>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
>> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>>   int msm_dsi_host_register(struct mipi_dsi_host *host);
>>   void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>>   void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
>> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
>> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>>       struct msm_display_dsc_config *dsc;
>>       /* connected device info */
>> -    struct device_node *device_node;
>>       unsigned int channel;
>>       unsigned int lanes;
>>       enum mipi_dsi_pixel_format format;
>> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host 
>> *host,
>>       dsi_dev_detach(msm_host->pdev);
>> -    msm_host->device_node = NULL;
>> -
>>       DBG("id=%d", msm_host->id);
>>       if (msm_host->dev)
>>           queue_work(msm_host->workqueue, &msm_host->hpd_work);
>> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct 
>> msm_dsi_host *msm_host)
>>           goto err;
>>       }
>> -    /* Get panel node from the output port's endpoint data */
>> -    device_node = of_graph_get_remote_node(np, 1, 0);
>> -    if (!device_node) {
>> -        DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
>> -        ret = -ENODEV;
>> -        goto err;
>> -    }
>> -
>> -    msm_host->device_node = device_node;
>> -
>>       if (of_property_read_bool(np, "syscon-sfpb")) {
>>           msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>>                       "syscon-sfpb");
>> @@ -2678,23 +2665,11 @@ enum drm_mode_status 
>> msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>       return MODE_OK;
>>   }
>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
>> -{
>> -    return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
>> -}
>> -
>>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>>   {
>>       return to_msm_dsi_host(host)->mode_flags;
>>   }
>> -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);
>> -}
>> -
>>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct 
>> mipi_dsi_host *host)
>>   {
>>       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
>> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c 
>> b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>> index cb84d185d73a..3970368e07d5 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
>> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>>       }
>>   }
>> -struct dsi_connector {
>> -    struct drm_connector base;
>> -    int id;
>> -};
>> -
>>   struct dsi_bridge {
>>       struct drm_bridge base;
>>       int id;
>>   };
>> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>>   #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
>> -static inline int dsi_mgr_connector_get_id(struct drm_connector 
>> *connector)
>> -{
>> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>> -    return dsi_connector->id;
>> -}
>> -
>>   static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>>   {
>>       struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>>       return dsi_bridge->id;
>>   }
>> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>> +static void msm_dsi_manager_set_split_display(u8 id)
>>   {
>> -    struct msm_drm_private *priv = conn->dev->dev_private;
>> -    struct msm_kms *kms = priv->kms;
>>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
>> +    struct msm_drm_private *priv = msm_dsi->dev->dev_private;
>> +    struct msm_kms *kms = priv->kms;
>>       struct msm_dsi *master_dsi, *slave_dsi;
>> -    struct drm_panel *panel;
>>       if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>>           master_dsi = other_dsi;
>> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct 
>> drm_connector *conn, u8 id)
>>           slave_dsi = other_dsi;
>>       }
>> -    /*
>> -     * There is only 1 panel in the global panel list for bonded DSI 
>> mode.
>> -     * Therefore slave dsi should get the drm_panel instance from master
>> -     * dsi.
>> -     */
>> -    panel = msm_dsi_host_get_panel(master_dsi->host);
>> -    if (IS_ERR(panel)) {
>> -        DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
>> -              PTR_ERR(panel));
>> -        return PTR_ERR(panel);
>> -    }
>> -
>> -    if (!panel || !IS_BONDED_DSI())
>> -        goto out;
>> -
>> -    drm_object_attach_property(&conn->base,
>> -                   conn->dev->mode_config.tile_property, 0);
>> +    if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
>> +        return;
>>       /*
>>        * Set split display info to kms once bonded DSI panel is 
>> connected to
>>        * both hosts.
>>        */
>> -    if (other_dsi && other_dsi->panel && 
>> kms->funcs->set_split_display) {
>> +    if (other_dsi && other_dsi->external_bridge && 
>> kms->funcs->set_split_display) {
>>           kms->funcs->set_split_display(kms, master_dsi->encoder,
>>                             slave_dsi->encoder,
>>                             msm_dsi_is_cmd_mode(msm_dsi));
>>       }
>> -
>> -out:
>> -    msm_dsi->panel = panel;
>> -    return 0;
>> -}
>> -
>> -static enum drm_connector_status dsi_mgr_connector_detect(
>> -        struct drm_connector *connector, bool force)
>> -{
>> -    int id = dsi_mgr_connector_get_id(connector);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -
>> -    return msm_dsi->panel ? connector_status_connected :
>> -        connector_status_disconnected;
>> -}
>> -
>> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
>> -{
>> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>> -
>> -    DBG("");
>> -
>> -    drm_connector_cleanup(connector);
>> -
>> -    kfree(dsi_connector);
>> -}
>> -
>> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
>> -{
>> -    int id = dsi_mgr_connector_get_id(connector);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -    struct drm_panel *panel = msm_dsi->panel;
>> -    int num;
>> -
>> -    if (!panel)
>> -        return 0;
>> -
>> -    /*
>> -     * In bonded DSI mode, we have one connector that can be
>> -     * attached to the drm_panel.
>> -     */
>> -    num = drm_panel_get_modes(panel, connector);
>> -    if (!num)
>> -        return 0;
>> -
>> -    return num;
>> -}
>> -
>> -static struct drm_encoder *
>> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
>> -{
>> -    int id = dsi_mgr_connector_get_id(connector);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -
>> -    DBG("");
>> -    return msm_dsi_get_encoder(msm_dsi);
>>   }
>>   static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
>> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct 
>> drm_bridge *bridge)
>>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>       struct mipi_dsi_host *host = msm_dsi->host;
>> -    struct drm_panel *panel = msm_dsi->panel;
>>       bool is_bonded_dsi = IS_BONDED_DSI();
>>       int ret;
>> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct 
>> drm_bridge *bridge)
>>       if (!dsi_mgr_power_on_early(bridge))
>>           dsi_mgr_bridge_power_on(bridge);
>> -    /* Always call panel functions once, because even for dual panels,
>> -     * there is only one drm_panel instance.
>> -     */
>> -    if (panel) {
>> -        ret = drm_panel_prepare(panel);
>> -        if (ret) {
>> -            pr_err("%s: prepare panel %d failed, %d\n", __func__,
>> -                                id, ret);
>> -            goto panel_prep_fail;
>> -        }
>> -    }
>> -
>>       ret = msm_dsi_host_enable(host);
>>       if (ret) {
>>           pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
>> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct 
>> drm_bridge *bridge)
>>   host1_en_fail:
>>       msm_dsi_host_disable(host);
>>   host_en_fail:
>> -    if (panel)
>> -        drm_panel_unprepare(panel);
>> -panel_prep_fail:
>>       return;
>>   }
>> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>>       }
>>   }
>> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
>> -{
>> -    int id = dsi_mgr_bridge_get_id(bridge);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -    struct drm_panel *panel = msm_dsi->panel;
>> -    bool is_bonded_dsi = IS_BONDED_DSI();
>> -    int ret;
>> -
>> -    DBG("id=%d", id);
>> -    if (!msm_dsi_device_connected(msm_dsi))
>> -        return;
>> -
>> -    /* Do nothing with the host if it is slave-DSI in case of bonded 
>> DSI */
>> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>> -        return;
>> -
>> -    if (panel) {
>> -        ret = drm_panel_enable(panel);
>> -        if (ret) {
>> -            pr_err("%s: enable panel %d failed, %d\n", __func__, id,
>> -                                    ret);
>> -        }
>> -    }
>> -}
>> -
>> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
>> -{
>> -    int id = dsi_mgr_bridge_get_id(bridge);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -    struct drm_panel *panel = msm_dsi->panel;
>> -    bool is_bonded_dsi = IS_BONDED_DSI();
>> -    int ret;
>> -
>> -    DBG("id=%d", id);
>> -    if (!msm_dsi_device_connected(msm_dsi))
>> -        return;
>> -
>> -    /* Do nothing with the host if it is slave-DSI in case of bonded 
>> DSI */
>> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>> -        return;
>> -
>> -    if (panel) {
>> -        ret = drm_panel_disable(panel);
>> -        if (ret)
>> -            pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
>> -                                    ret);
>> -    }
>> -}
>> -
>>   static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>>   {
>>       int id = dsi_mgr_bridge_get_id(bridge);
>>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>       struct mipi_dsi_host *host = msm_dsi->host;
>> -    struct drm_panel *panel = msm_dsi->panel;
>>       bool is_bonded_dsi = IS_BONDED_DSI();
>>       int ret;
>> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct 
>> drm_bridge *bridge)
>>               pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>>       }
>> -    if (panel) {
>> -        ret = drm_panel_unprepare(panel);
>> -        if (ret)
>> -            pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
>> -                                id, ret);
>> -    }
>> -
>>       msm_dsi_host_disable_irq(host);
>>       if (is_bonded_dsi && msm_dsi1)
>>           msm_dsi_host_disable_irq(msm_dsi1->host);
>> @@ -614,76 +457,13 @@ static enum drm_mode_status 
>> dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>>       return msm_dsi_host_check_dsc(host, mode);
>>   }
>> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
>> -    .detect = dsi_mgr_connector_detect,
>> -    .fill_modes = drm_helper_probe_single_connector_modes,
>> -    .destroy = dsi_mgr_connector_destroy,
>> -    .reset = drm_atomic_helper_connector_reset,
>> -    .atomic_duplicate_state = 
>> drm_atomic_helper_connector_duplicate_state,
>> -    .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> -};
>> -
>> -static const struct drm_connector_helper_funcs 
>> dsi_mgr_conn_helper_funcs = {
>> -    .get_modes = dsi_mgr_connector_get_modes,
>> -    .best_encoder = dsi_mgr_connector_best_encoder,
>> -};
>> -
>>   static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>>       .pre_enable = dsi_mgr_bridge_pre_enable,
>> -    .enable = dsi_mgr_bridge_enable,
>> -    .disable = dsi_mgr_bridge_disable,

With dsi_mgr_bridge_enable/dsi_mgr_bridge_disable() removed, how will we 
handle conditions like below:

     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
         return;

Have you verified bonded_dsi with this change?

>>       .post_disable = dsi_mgr_bridge_post_disable,
>>       .mode_set = dsi_mgr_bridge_mode_set,
>>       .mode_valid = dsi_mgr_bridge_mode_valid,
>>   };
>> -/* 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);
>> -    struct drm_connector *connector = NULL;
>> -    struct dsi_connector *dsi_connector;
>> -    int ret;
>> -
>> -    dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
>> -    if (!dsi_connector)
>> -        return ERR_PTR(-ENOMEM);
>> -
>> -    dsi_connector->id = id;
>> -
>> -    connector = &dsi_connector->base;
>> -
>> -    ret = drm_connector_init(msm_dsi->dev, connector,
>> -            &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
>> -    if (ret)
>> -        return ERR_PTR(ret);
>> -
>> -    drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
>> -
>> -    /* Enable HPD to let hpd event is handled
>> -     * when panel is attached to the host.
>> -     */
>> -    connector->polled = DRM_CONNECTOR_POLL_HPD;
> 
> I see that this part gets removed with this migration.
> 
> For fixed/built-in displays, it should not matter i think but i am not 
> sure if some usermodes might expect this even for DSI?
> 
> So, once again does panel_bridge needs to account for this?
> 
> 
>> -
>> -    /* Display driver doesn't support interlace now. */
>> -    connector->interlace_allowed = 0;
>> -    connector->doublescan_allowed = 0;
>> -
>> -    drm_connector_attach_encoder(connector, msm_dsi->encoder);
>> -
>> -    ret = msm_dsi_manager_panel_init(connector, id);
>> -    if (ret) {
>> -        DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
>> -        goto fail;
>> -    }
>> -
>> -    return connector;
>> -
>> -fail:
>> -    connector->funcs->destroy(connector);
>> -    return ERR_PTR(ret);
>> -}
>> -
>>   /* initialize bridge */
>>   struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>>   {
>> @@ -732,8 +512,11 @@ struct drm_connector 
>> *msm_dsi_manager_ext_bridge_init(u8 id)
>>       int ret;
>>       int_bridge = msm_dsi->bridge;
>> -    ext_bridge = msm_dsi->external_bridge =
>> -            msm_dsi_host_get_bridge(msm_dsi->host);
>> +    ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, 
>> msm_dsi->pdev->dev.of_node, 1, 0);
>> +    if (IS_ERR(ext_bridge))
>> +        return ERR_CAST(ext_bridge);
>> +
>> +    msm_dsi->external_bridge = ext_bridge;
>>       encoder = msm_dsi->encoder;
>> @@ -745,25 +528,12 @@ struct drm_connector 
>> *msm_dsi_manager_ext_bridge_init(u8 id)
>>       ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>>               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>       if (ret == -EINVAL) {
>> -        struct drm_connector *connector;
>> -        struct list_head *connector_list;
>> -
>>           /* link the internal dsi bridge to the external bridge */
>> -        drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>> +        ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>> +        if (ret < 0)
>> +            return ERR_PTR(ret);
>> -        /*
>> -         * 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) {
>> -            if (drm_connector_has_possible_encoder(connector, encoder))
>> -                return connector;
>> -        }
>> -
>> -        return ERR_PTR(-ENODEV);
>> +        goto out;
>>       }
>>       connector = drm_bridge_connector_init(dev, encoder);
>> @@ -774,6 +544,10 @@ struct drm_connector 
>> *msm_dsi_manager_ext_bridge_init(u8 id)
>>       drm_connector_attach_encoder(connector, encoder);
>> +out:
>> +    /* The pipeline is ready, ping encoders if necessary */
>> +    msm_dsi_manager_set_split_display(id);
> Do you still want to execute msm_dsi_manager_set_split_display even for 
> the error case? Like in the above lines you have replaced the return 
> ERR_PTR() with the goto out. But do you want to then move the 
> set_split_display() call above the out label?
> 
> Also, now for the cases where there was an error where the connector was 
> not found, we will return a NULL ptr instead of the ERR_PTR(-ENODEV).
> Is that expected?
> 
>> +
>>       return connector;
>>   }

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-11 22:39   ` Abhinav Kumar
  2022-07-11 22:54     ` [Freedreno] " Abhinav Kumar
@ 2022-07-12 10:00     ` Dmitry Baryshkov
  2022-07-12 19:15       ` [Freedreno] " Abhinav Kumar
  2022-07-12 13:22     ` [PATCH v2.5] " Dmitry Baryshkov
  2 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-12 10:00 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: freedreno, David Airlie, Sean Paul, Stephen Boyd, Thierry Reding,
	dri-devel, Thomas Zimmermann, linux-arm-msm, Bjorn Andersson,
	Sam Ravnborg

On Tue, 12 Jul 2022 at 01:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
> > Currently the DSI driver has two separate paths: one if the next device
> > in a chain is a bridge and another one if the panel is connected
> > directly to the DSI host. Simplify the code path by using panel-bridge
> > driver (already selected in Kconfig) and dropping support for
> > handling the panel directly.
> >
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> >   drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
> >   drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
> >   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
> >   drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
> >   4 files changed, 26 insertions(+), 315 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
> > index 1625328fa430..3c53e28092db 100644
> > --- a/drivers/gpu/drm/msm/dsi/dsi.c
> > +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> > @@ -6,14 +6,6 @@
> >   #include "dsi.h"
> >   #include "dsi_cfg.h"
> >
> > -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
> > -{
> > -     if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
> > -             return NULL;
> > -
> > -     return msm_dsi->encoder;
> > -}
>
> panel_bridge doesnt have the best_encoder method today.
> Today, this does not break anything for us.
> But, for future if we do need it, panel_bridge needs to be expanded to
> add that method?

We have a 1:1 between encoder and connector, so
drm_connector_get_single_encoder() works well in our case.

>
> > -
> >   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
> >   {
> >       unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
> > @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
> >                        struct drm_encoder *encoder)
> >   {
> >       struct msm_drm_private *priv;
> > -     struct drm_bridge *ext_bridge;
> > +     struct drm_connector *connector;
> >       int ret;
> >
> >       if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
> > @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
> >               goto fail;
> >       }
> >
> > -     /*
> > -      * 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);
> > +     connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
> > +
> > +     if (IS_ERR(connector)) {
> > +             ret = PTR_ERR(connector);
> >               DRM_DEV_ERROR(dev->dev,
> >                       "failed to create dsi connector: %d\n", ret);
> > -             msm_dsi->connector = NULL;
> >               goto fail;
> >       }
> >
> > @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
> >               msm_dsi->bridge = NULL;
> >       }
> >
> > -     /* 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;
> > -
> >       return ret;
> >   }
> >
> > diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> > index 580a1e6358bf..41630b8f5358 100644
> > --- a/drivers/gpu/drm/msm/dsi/dsi.h
> > +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> > @@ -12,7 +12,6 @@
> >   #include <drm/drm_bridge.h>
> >   #include <drm/drm_crtc.h>
> >   #include <drm/drm_mipi_dsi.h>
> > -#include <drm/drm_panel.h>
> >
> >   #include "msm_drv.h"
> >   #include "disp/msm_disp_snapshot.h"
> > @@ -49,8 +48,6 @@ 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;
> >
> > @@ -58,10 +55,8 @@ struct msm_dsi {
> >       struct msm_dsi_phy *phy;
> >
> >       /*
> > -      * panel/external_bridge connected to dsi bridge output, only one of the
> > -      * two can be valid at a time
> > +      * external_bridge connected to dsi bridge output
> >        */
> > -     struct drm_panel *panel;
> >       struct drm_bridge *external_bridge;
> >
> >       struct device *phy_dev;
> > @@ -76,7 +71,6 @@ struct msm_dsi {
> >   /* dsi manager */
> >   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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
> >   bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
> > @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
> >   /* msm dsi */
> >   static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
> >   {
> > -     return msm_dsi->panel || msm_dsi->external_bridge;
> > +     return msm_dsi->external_bridge;
> >   }
> >
> > -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
> > -
> >   /* dsi host */
> >   struct msm_dsi_host;
> >   int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
> > @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
> >                                 const struct drm_display_mode *mode);
> >   enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
> >                                           const struct drm_display_mode *mode);
> > -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
> >   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
> > -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
> >   int msm_dsi_host_register(struct mipi_dsi_host *host);
> >   void msm_dsi_host_unregister(struct mipi_dsi_host *host);
> >   void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
> > --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> > +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> > @@ -164,7 +164,6 @@ struct msm_dsi_host {
> >       struct msm_display_dsc_config *dsc;
> >
> >       /* connected device info */
> > -     struct device_node *device_node;
> >       unsigned int channel;
> >       unsigned int lanes;
> >       enum mipi_dsi_pixel_format format;
> > @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
> >
> >       dsi_dev_detach(msm_host->pdev);
> >
> > -     msm_host->device_node = NULL;
> > -
> >       DBG("id=%d", msm_host->id);
> >       if (msm_host->dev)
> >               queue_work(msm_host->workqueue, &msm_host->hpd_work);
> > @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
> >               goto err;
> >       }
> >
> > -     /* Get panel node from the output port's endpoint data */
> > -     device_node = of_graph_get_remote_node(np, 1, 0);
> > -     if (!device_node) {
> > -             DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
> > -             ret = -ENODEV;
> > -             goto err;
> > -     }
> > -
> > -     msm_host->device_node = device_node;
> > -
> >       if (of_property_read_bool(np, "syscon-sfpb")) {
> >               msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
> >                                       "syscon-sfpb");
> > @@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
> >       return MODE_OK;
> >   }
> >
> > -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
> > -{
> > -     return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
> > -}
> > -
> >   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
> >   {
> >       return to_msm_dsi_host(host)->mode_flags;
> >   }
> >
> > -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);
> > -}
> > -
> >   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
> >   {
> >       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> > diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> > index cb84d185d73a..3970368e07d5 100644
> > --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> > +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> > @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
> >       }
> >   }
> >
> > -struct dsi_connector {
> > -     struct drm_connector base;
> > -     int id;
> > -};
> > -
> >   struct dsi_bridge {
> >       struct drm_bridge base;
> >       int id;
> >   };
> >
> > -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
> >   #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
> >
> > -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
> > -{
> > -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> > -     return dsi_connector->id;
> > -}
> > -
> >   static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
> >   {
> >       struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
> >       return dsi_bridge->id;
> >   }
> >
> > -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> > +static void msm_dsi_manager_set_split_display(u8 id)
> >   {
> > -     struct msm_drm_private *priv = conn->dev->dev_private;
> > -     struct msm_kms *kms = priv->kms;
> >       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
> > +     struct msm_drm_private *priv = msm_dsi->dev->dev_private;
> > +     struct msm_kms *kms = priv->kms;
> >       struct msm_dsi *master_dsi, *slave_dsi;
> > -     struct drm_panel *panel;
> >
> >       if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
> >               master_dsi = other_dsi;
> > @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> >               slave_dsi = other_dsi;
> >       }
> >
> > -     /*
> > -      * There is only 1 panel in the global panel list for bonded DSI mode.
> > -      * Therefore slave dsi should get the drm_panel instance from master
> > -      * dsi.
> > -      */
> > -     panel = msm_dsi_host_get_panel(master_dsi->host);
> > -     if (IS_ERR(panel)) {
> > -             DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
> > -                       PTR_ERR(panel));
> > -             return PTR_ERR(panel);
> > -     }
> > -
> > -     if (!panel || !IS_BONDED_DSI())
> > -             goto out;
> > -
> > -     drm_object_attach_property(&conn->base,
> > -                                conn->dev->mode_config.tile_property, 0);
> > +     if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
> > +             return;
> >
> >       /*
> >        * Set split display info to kms once bonded DSI panel is connected to
> >        * both hosts.
> >        */
> > -     if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
> > +     if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
> >               kms->funcs->set_split_display(kms, master_dsi->encoder,
> >                                             slave_dsi->encoder,
> >                                             msm_dsi_is_cmd_mode(msm_dsi));
> >       }
> > -
> > -out:
> > -     msm_dsi->panel = panel;
> > -     return 0;
> > -}
> > -
> > -static enum drm_connector_status dsi_mgr_connector_detect(
> > -             struct drm_connector *connector, bool force)
> > -{
> > -     int id = dsi_mgr_connector_get_id(connector);
> > -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> > -
> > -     return msm_dsi->panel ? connector_status_connected :
> > -             connector_status_disconnected;
> > -}
> > -
> > -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
> > -{
> > -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> > -
> > -     DBG("");
> > -
> > -     drm_connector_cleanup(connector);
> > -
> > -     kfree(dsi_connector);
> > -}
> > -
> > -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
> > -{
> > -     int id = dsi_mgr_connector_get_id(connector);
> > -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> > -     struct drm_panel *panel = msm_dsi->panel;
> > -     int num;
> > -
> > -     if (!panel)
> > -             return 0;
> > -
> > -     /*
> > -      * In bonded DSI mode, we have one connector that can be
> > -      * attached to the drm_panel.
> > -      */
> > -     num = drm_panel_get_modes(panel, connector);
> > -     if (!num)
> > -             return 0;
> > -
> > -     return num;
> > -}
> > -
> > -static struct drm_encoder *
> > -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
> > -{
> > -     int id = dsi_mgr_connector_get_id(connector);
> > -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> > -
> > -     DBG("");
> > -     return msm_dsi_get_encoder(msm_dsi);
> >   }
> >
> >   static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
> > @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
> >       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
> >       struct mipi_dsi_host *host = msm_dsi->host;
> > -     struct drm_panel *panel = msm_dsi->panel;
> >       bool is_bonded_dsi = IS_BONDED_DSI();
> >       int ret;
> >
> > @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
> >       if (!dsi_mgr_power_on_early(bridge))
> >               dsi_mgr_bridge_power_on(bridge);
> >
> > -     /* Always call panel functions once, because even for dual panels,
> > -      * there is only one drm_panel instance.
> > -      */
> > -     if (panel) {
> > -             ret = drm_panel_prepare(panel);
> > -             if (ret) {
> > -                     pr_err("%s: prepare panel %d failed, %d\n", __func__,
> > -                                                             id, ret);
> > -                     goto panel_prep_fail;
> > -             }
> > -     }
> > -
> >       ret = msm_dsi_host_enable(host);
> >       if (ret) {
> >               pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
> > @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
> >   host1_en_fail:
> >       msm_dsi_host_disable(host);
> >   host_en_fail:
> > -     if (panel)
> > -             drm_panel_unprepare(panel);
> > -panel_prep_fail:
> >
> >       return;
> >   }
> > @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
> >       }
> >   }
> >
> > -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
> > -{
> > -     int id = dsi_mgr_bridge_get_id(bridge);
> > -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> > -     struct drm_panel *panel = msm_dsi->panel;
> > -     bool is_bonded_dsi = IS_BONDED_DSI();
> > -     int ret;
> > -
> > -     DBG("id=%d", id);
> > -     if (!msm_dsi_device_connected(msm_dsi))
> > -             return;
> > -
> > -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> > -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> > -             return;
> > -
> > -     if (panel) {
> > -             ret = drm_panel_enable(panel);
> > -             if (ret) {
> > -                     pr_err("%s: enable panel %d failed, %d\n", __func__, id,
> > -                                                                     ret);
> > -             }
> > -     }
> > -}
> > -
> > -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
> > -{
> > -     int id = dsi_mgr_bridge_get_id(bridge);
> > -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> > -     struct drm_panel *panel = msm_dsi->panel;
> > -     bool is_bonded_dsi = IS_BONDED_DSI();
> > -     int ret;
> > -
> > -     DBG("id=%d", id);
> > -     if (!msm_dsi_device_connected(msm_dsi))
> > -             return;
> > -
> > -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> > -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> > -             return;
> > -
> > -     if (panel) {
> > -             ret = drm_panel_disable(panel);
> > -             if (ret)
> > -                     pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
> > -                                                                     ret);
> > -     }
> > -}
> > -
> >   static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
> >   {
> >       int id = dsi_mgr_bridge_get_id(bridge);
> >       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
> >       struct mipi_dsi_host *host = msm_dsi->host;
> > -     struct drm_panel *panel = msm_dsi->panel;
> >       bool is_bonded_dsi = IS_BONDED_DSI();
> >       int ret;
> >
> > @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
> >                       pr_err("%s: host1 disable failed, %d\n", __func__, ret);
> >       }
> >
> > -     if (panel) {
> > -             ret = drm_panel_unprepare(panel);
> > -             if (ret)
> > -                     pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
> > -                                                             id, ret);
> > -     }
> > -
> >       msm_dsi_host_disable_irq(host);
> >       if (is_bonded_dsi && msm_dsi1)
> >               msm_dsi_host_disable_irq(msm_dsi1->host);
> > @@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
> >       return msm_dsi_host_check_dsc(host, mode);
> >   }
> >
> > -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
> > -     .detect = dsi_mgr_connector_detect,
> > -     .fill_modes = drm_helper_probe_single_connector_modes,
> > -     .destroy = dsi_mgr_connector_destroy,
> > -     .reset = drm_atomic_helper_connector_reset,
> > -     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > -     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > -};
> > -
> > -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
> > -     .get_modes = dsi_mgr_connector_get_modes,
> > -     .best_encoder = dsi_mgr_connector_best_encoder,
> > -};
> > -
> >   static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
> >       .pre_enable = dsi_mgr_bridge_pre_enable,
> > -     .enable = dsi_mgr_bridge_enable,
> > -     .disable = dsi_mgr_bridge_disable,
> >       .post_disable = dsi_mgr_bridge_post_disable,
> >       .mode_set = dsi_mgr_bridge_mode_set,
> >       .mode_valid = dsi_mgr_bridge_mode_valid,
> >   };
> >
> > -/* 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);
> > -     struct drm_connector *connector = NULL;
> > -     struct dsi_connector *dsi_connector;
> > -     int ret;
> > -
> > -     dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
> > -     if (!dsi_connector)
> > -             return ERR_PTR(-ENOMEM);
> > -
> > -     dsi_connector->id = id;
> > -
> > -     connector = &dsi_connector->base;
> > -
> > -     ret = drm_connector_init(msm_dsi->dev, connector,
> > -                     &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
> > -     if (ret)
> > -             return ERR_PTR(ret);
> > -
> > -     drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
> > -
> > -     /* Enable HPD to let hpd event is handled
> > -      * when panel is attached to the host.
> > -      */
> > -     connector->polled = DRM_CONNECTOR_POLL_HPD;
>
> I see that this part gets removed with this migration.
>
> For fixed/built-in displays, it should not matter i think but i am not
> sure if some usermodes might expect this even for DSI?
>
> So, once again does panel_bridge needs to account for this?

Panel bridge sets only DRM_BRIDGE_OP_MODES. If you check the existing
code, the dsi_mgr_connector also does not provide HPD support. It only
can return panel status depending on whether the drm_panel was fetched
or not. No events are generated ever.
Thus said I think we should stop hijacking the usual mechanisms. If we
do not do the HPD, let's not declare it. If there is a case of panel
being hotplugged or switched, it will be handled by the next bridge in
the chain, not by the MSM DSI code.

>
>
> > -
> > -     /* Display driver doesn't support interlace now. */
> > -     connector->interlace_allowed = 0;
> > -     connector->doublescan_allowed = 0;
> > -
> > -     drm_connector_attach_encoder(connector, msm_dsi->encoder);
> > -
> > -     ret = msm_dsi_manager_panel_init(connector, id);
> > -     if (ret) {
> > -             DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
> > -             goto fail;
> > -     }
> > -
> > -     return connector;
> > -
> > -fail:
> > -     connector->funcs->destroy(connector);
> > -     return ERR_PTR(ret);
> > -}
> > -
> >   /* initialize bridge */
> >   struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> >   {
> > @@ -732,8 +512,11 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> >       int ret;
> >
> >       int_bridge = msm_dsi->bridge;
> > -     ext_bridge = msm_dsi->external_bridge =
> > -                     msm_dsi_host_get_bridge(msm_dsi->host);
> > +     ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, msm_dsi->pdev->dev.of_node, 1, 0);
> > +     if (IS_ERR(ext_bridge))
> > +             return ERR_CAST(ext_bridge);
> > +
> > +     msm_dsi->external_bridge = ext_bridge;
> >
> >       encoder = msm_dsi->encoder;
> >
> > @@ -745,25 +528,12 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> >       ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
> >                       DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> >       if (ret == -EINVAL) {
> > -             struct drm_connector *connector;
> > -             struct list_head *connector_list;
> > -
> >               /* link the internal dsi bridge to the external bridge */
> > -             drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> > +             ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> > +             if (ret < 0)
> > +                     return ERR_PTR(ret);
> >
> > -             /*
> > -              * 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) {
> > -                     if (drm_connector_has_possible_encoder(connector, encoder))
> > -                             return connector;
> > -             }
> > -
> > -             return ERR_PTR(-ENODEV);
> > +             goto out;
> >       }
> >
> >       connector = drm_bridge_connector_init(dev, encoder);
> > @@ -774,6 +544,10 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> >
> >       drm_connector_attach_encoder(connector, encoder);
> >
> > +out:
> > +     /* The pipeline is ready, ping encoders if necessary */
> > +     msm_dsi_manager_set_split_display(id);
> Do you still want to execute msm_dsi_manager_set_split_display even for
> the error case? Like in the above lines you have replaced the return
> ERR_PTR() with the goto out. But do you want to then move the
> set_split_display() call above the out label?

You see, the return ERR_PTR was the error case, where we could not
find the connector corresponding to the encoder.
We just don't need it anymore. Let's change the function to return int
rather than the unused connector.

>
> Also, now for the cases where there was an error where the connector was
> not found, we will return a NULL ptr instead of the ERR_PTR(-ENODEV).
> Is that expected?

Yes. We just do not care anymore about this connector.

>
> > +
> >       return connector;
> >   }
> >



-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-11 22:54     ` [Freedreno] " Abhinav Kumar
@ 2022-07-12 10:13       ` Dmitry Baryshkov
  2022-07-12 19:53         ` Abhinav Kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-12 10:13 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: freedreno, David Airlie, Sean Paul, Bjorn Andersson,
	Thierry Reding, dri-devel, Thomas Zimmermann, linux-arm-msm,
	Stephen Boyd, Sam Ravnborg

On Tue, 12 Jul 2022 at 01:54, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
> <missed one comment>
>
>
> On 7/11/2022 3:39 PM, Abhinav Kumar wrote:
> >
> >
> > On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
> >> Currently the DSI driver has two separate paths: one if the next device
> >> in a chain is a bridge and another one if the panel is connected
> >> directly to the DSI host. Simplify the code path by using panel-bridge
> >> driver (already selected in Kconfig) and dropping support for
> >> handling the panel directly.
> >>
> >> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >> ---
> >>   drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
> >>   drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
> >>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
> >>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
> >>   4 files changed, 26 insertions(+), 315 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c
> >> b/drivers/gpu/drm/msm/dsi/dsi.c
> >> index 1625328fa430..3c53e28092db 100644
> >> --- a/drivers/gpu/drm/msm/dsi/dsi.c
> >> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> >> @@ -6,14 +6,6 @@
> >>   #include "dsi.h"
> >>   #include "dsi_cfg.h"
> >> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
> >> -{
> >> -    if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
> >> -        return NULL;
> >> -
> >> -    return msm_dsi->encoder;
> >> -}
> >
> > panel_bridge doesnt have the best_encoder method today.
> > Today, this does not break anything for us.
> > But, for future if we do need it, panel_bridge needs to be expanded to
> > add that method?
> >
> >> -
> >>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
> >>   {
> >>       unsigned long host_flags =
> >> msm_dsi_host_get_mode_flags(msm_dsi->host);
> >> @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
> >> struct drm_device *dev,
> >>                struct drm_encoder *encoder)
> >>   {
> >>       struct msm_drm_private *priv;
> >> -    struct drm_bridge *ext_bridge;
> >> +    struct drm_connector *connector;
> >>       int ret;
> >>       if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
> >> @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi
> >> *msm_dsi, struct drm_device *dev,
> >>           goto fail;
> >>       }
> >> -    /*
> >> -     * 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);
> >> +    connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
> >> +
> >> +    if (IS_ERR(connector)) {
> >> +        ret = PTR_ERR(connector);
> >>           DRM_DEV_ERROR(dev->dev,
> >>               "failed to create dsi connector: %d\n", ret);
> >> -        msm_dsi->connector = NULL;
> >>           goto fail;
> >>       }
> >> @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
> >> struct drm_device *dev,
> >>           msm_dsi->bridge = NULL;
> >>       }
> >> -    /* 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;
> >> -
> >>       return ret;
> >>   }
> >> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h
> >> b/drivers/gpu/drm/msm/dsi/dsi.h
> >> index 580a1e6358bf..41630b8f5358 100644
> >> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> >> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> >> @@ -12,7 +12,6 @@
> >>   #include <drm/drm_bridge.h>
> >>   #include <drm/drm_crtc.h>
> >>   #include <drm/drm_mipi_dsi.h>
> >> -#include <drm/drm_panel.h>
> >>   #include "msm_drv.h"
> >>   #include "disp/msm_disp_snapshot.h"
> >> @@ -49,8 +48,6 @@ 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;
> >> @@ -58,10 +55,8 @@ struct msm_dsi {
> >>       struct msm_dsi_phy *phy;
> >>       /*
> >> -     * panel/external_bridge connected to dsi bridge output, only one
> >> of the
> >> -     * two can be valid at a time
> >> +     * external_bridge connected to dsi bridge output
> >>        */
> >> -    struct drm_panel *panel;
> >>       struct drm_bridge *external_bridge;
> >>       struct device *phy_dev;
> >> @@ -76,7 +71,6 @@ struct msm_dsi {
> >>   /* dsi manager */
> >>   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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
> >>   bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
> >> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
> >>   /* msm dsi */
> >>   static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
> >>   {
> >> -    return msm_dsi->panel || msm_dsi->external_bridge;
> >> +    return msm_dsi->external_bridge;
> >>   }
> >> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
> >> -
> >>   /* dsi host */
> >>   struct msm_dsi_host;
> >>   int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
> >> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct
> >> mipi_dsi_host *host,
> >>                     const struct drm_display_mode *mode);
> >>   enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
> >>                           const struct drm_display_mode *mode);
> >> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
> >>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
> >> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
> >>   int msm_dsi_host_register(struct mipi_dsi_host *host);
> >>   void msm_dsi_host_unregister(struct mipi_dsi_host *host);
> >>   void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
> >> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> >> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> >> @@ -164,7 +164,6 @@ struct msm_dsi_host {
> >>       struct msm_display_dsc_config *dsc;
> >>       /* connected device info */
> >> -    struct device_node *device_node;
> >>       unsigned int channel;
> >>       unsigned int lanes;
> >>       enum mipi_dsi_pixel_format format;
> >> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host
> >> *host,
> >>       dsi_dev_detach(msm_host->pdev);
> >> -    msm_host->device_node = NULL;
> >> -
> >>       DBG("id=%d", msm_host->id);
> >>       if (msm_host->dev)
> >>           queue_work(msm_host->workqueue, &msm_host->hpd_work);
> >> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct
> >> msm_dsi_host *msm_host)
> >>           goto err;
> >>       }
> >> -    /* Get panel node from the output port's endpoint data */
> >> -    device_node = of_graph_get_remote_node(np, 1, 0);
> >> -    if (!device_node) {
> >> -        DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
> >> -        ret = -ENODEV;
> >> -        goto err;
> >> -    }
> >> -
> >> -    msm_host->device_node = device_node;
> >> -
> >>       if (of_property_read_bool(np, "syscon-sfpb")) {
> >>           msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
> >>                       "syscon-sfpb");
> >> @@ -2678,23 +2665,11 @@ enum drm_mode_status
> >> msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
> >>       return MODE_OK;
> >>   }
> >> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
> >> -{
> >> -    return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
> >> -}
> >> -
> >>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
> >>   {
> >>       return to_msm_dsi_host(host)->mode_flags;
> >>   }
> >> -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);
> >> -}
> >> -
> >>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct
> >> mipi_dsi_host *host)
> >>   {
> >>       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> >> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> >> b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> >> index cb84d185d73a..3970368e07d5 100644
> >> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> >> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> >> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
> >>       }
> >>   }
> >> -struct dsi_connector {
> >> -    struct drm_connector base;
> >> -    int id;
> >> -};
> >> -
> >>   struct dsi_bridge {
> >>       struct drm_bridge base;
> >>       int id;
> >>   };
> >> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
> >>   #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
> >> -static inline int dsi_mgr_connector_get_id(struct drm_connector
> >> *connector)
> >> -{
> >> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> >> -    return dsi_connector->id;
> >> -}
> >> -
> >>   static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
> >>   {
> >>       struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
> >>       return dsi_bridge->id;
> >>   }
> >> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> >> +static void msm_dsi_manager_set_split_display(u8 id)
> >>   {
> >> -    struct msm_drm_private *priv = conn->dev->dev_private;
> >> -    struct msm_kms *kms = priv->kms;
> >>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
> >> +    struct msm_drm_private *priv = msm_dsi->dev->dev_private;
> >> +    struct msm_kms *kms = priv->kms;
> >>       struct msm_dsi *master_dsi, *slave_dsi;
> >> -    struct drm_panel *panel;
> >>       if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
> >>           master_dsi = other_dsi;
> >> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct
> >> drm_connector *conn, u8 id)
> >>           slave_dsi = other_dsi;
> >>       }
> >> -    /*
> >> -     * There is only 1 panel in the global panel list for bonded DSI
> >> mode.
> >> -     * Therefore slave dsi should get the drm_panel instance from master
> >> -     * dsi.
> >> -     */
> >> -    panel = msm_dsi_host_get_panel(master_dsi->host);
> >> -    if (IS_ERR(panel)) {
> >> -        DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
> >> -              PTR_ERR(panel));
> >> -        return PTR_ERR(panel);
> >> -    }
> >> -
> >> -    if (!panel || !IS_BONDED_DSI())
> >> -        goto out;
> >> -
> >> -    drm_object_attach_property(&conn->base,
> >> -                   conn->dev->mode_config.tile_property, 0);
> >> +    if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
> >> +        return;
> >>       /*
> >>        * Set split display info to kms once bonded DSI panel is
> >> connected to
> >>        * both hosts.
> >>        */
> >> -    if (other_dsi && other_dsi->panel &&
> >> kms->funcs->set_split_display) {
> >> +    if (other_dsi && other_dsi->external_bridge &&
> >> kms->funcs->set_split_display) {
> >>           kms->funcs->set_split_display(kms, master_dsi->encoder,
> >>                             slave_dsi->encoder,
> >>                             msm_dsi_is_cmd_mode(msm_dsi));
> >>       }
> >> -
> >> -out:
> >> -    msm_dsi->panel = panel;
> >> -    return 0;
> >> -}
> >> -
> >> -static enum drm_connector_status dsi_mgr_connector_detect(
> >> -        struct drm_connector *connector, bool force)
> >> -{
> >> -    int id = dsi_mgr_connector_get_id(connector);
> >> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >> -
> >> -    return msm_dsi->panel ? connector_status_connected :
> >> -        connector_status_disconnected;
> >> -}
> >> -
> >> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
> >> -{
> >> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> >> -
> >> -    DBG("");
> >> -
> >> -    drm_connector_cleanup(connector);
> >> -
> >> -    kfree(dsi_connector);
> >> -}
> >> -
> >> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
> >> -{
> >> -    int id = dsi_mgr_connector_get_id(connector);
> >> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >> -    struct drm_panel *panel = msm_dsi->panel;
> >> -    int num;
> >> -
> >> -    if (!panel)
> >> -        return 0;
> >> -
> >> -    /*
> >> -     * In bonded DSI mode, we have one connector that can be
> >> -     * attached to the drm_panel.
> >> -     */
> >> -    num = drm_panel_get_modes(panel, connector);
> >> -    if (!num)
> >> -        return 0;
> >> -
> >> -    return num;
> >> -}
> >> -
> >> -static struct drm_encoder *
> >> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
> >> -{
> >> -    int id = dsi_mgr_connector_get_id(connector);
> >> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >> -
> >> -    DBG("");
> >> -    return msm_dsi_get_encoder(msm_dsi);
> >>   }
> >>   static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
> >> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct
> >> drm_bridge *bridge)
> >>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
> >>       struct mipi_dsi_host *host = msm_dsi->host;
> >> -    struct drm_panel *panel = msm_dsi->panel;
> >>       bool is_bonded_dsi = IS_BONDED_DSI();
> >>       int ret;
> >> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct
> >> drm_bridge *bridge)
> >>       if (!dsi_mgr_power_on_early(bridge))
> >>           dsi_mgr_bridge_power_on(bridge);
> >> -    /* Always call panel functions once, because even for dual panels,
> >> -     * there is only one drm_panel instance.
> >> -     */
> >> -    if (panel) {
> >> -        ret = drm_panel_prepare(panel);
> >> -        if (ret) {
> >> -            pr_err("%s: prepare panel %d failed, %d\n", __func__,
> >> -                                id, ret);
> >> -            goto panel_prep_fail;
> >> -        }
> >> -    }
> >> -
> >>       ret = msm_dsi_host_enable(host);
> >>       if (ret) {
> >>           pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
> >> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct
> >> drm_bridge *bridge)
> >>   host1_en_fail:
> >>       msm_dsi_host_disable(host);
> >>   host_en_fail:
> >> -    if (panel)
> >> -        drm_panel_unprepare(panel);
> >> -panel_prep_fail:
> >>       return;
> >>   }
> >> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
> >>       }
> >>   }
> >> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
> >> -{
> >> -    int id = dsi_mgr_bridge_get_id(bridge);
> >> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >> -    struct drm_panel *panel = msm_dsi->panel;
> >> -    bool is_bonded_dsi = IS_BONDED_DSI();
> >> -    int ret;
> >> -
> >> -    DBG("id=%d", id);
> >> -    if (!msm_dsi_device_connected(msm_dsi))
> >> -        return;
> >> -
> >> -    /* Do nothing with the host if it is slave-DSI in case of bonded
> >> DSI */
> >> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> >> -        return;
> >> -
> >> -    if (panel) {
> >> -        ret = drm_panel_enable(panel);
> >> -        if (ret) {
> >> -            pr_err("%s: enable panel %d failed, %d\n", __func__, id,
> >> -                                    ret);
> >> -        }
> >> -    }
> >> -}
> >> -
> >> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
> >> -{
> >> -    int id = dsi_mgr_bridge_get_id(bridge);
> >> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >> -    struct drm_panel *panel = msm_dsi->panel;
> >> -    bool is_bonded_dsi = IS_BONDED_DSI();
> >> -    int ret;
> >> -
> >> -    DBG("id=%d", id);
> >> -    if (!msm_dsi_device_connected(msm_dsi))
> >> -        return;
> >> -
> >> -    /* Do nothing with the host if it is slave-DSI in case of bonded
> >> DSI */
> >> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> >> -        return;
> >> -
> >> -    if (panel) {
> >> -        ret = drm_panel_disable(panel);
> >> -        if (ret)
> >> -            pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
> >> -                                    ret);
> >> -    }
> >> -}
> >> -
> >>   static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
> >>   {
> >>       int id = dsi_mgr_bridge_get_id(bridge);
> >>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
> >>       struct mipi_dsi_host *host = msm_dsi->host;
> >> -    struct drm_panel *panel = msm_dsi->panel;
> >>       bool is_bonded_dsi = IS_BONDED_DSI();
> >>       int ret;
> >> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct
> >> drm_bridge *bridge)
> >>               pr_err("%s: host1 disable failed, %d\n", __func__, ret);
> >>       }
> >> -    if (panel) {
> >> -        ret = drm_panel_unprepare(panel);
> >> -        if (ret)
> >> -            pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
> >> -                                id, ret);
> >> -    }
> >> -
> >>       msm_dsi_host_disable_irq(host);
> >>       if (is_bonded_dsi && msm_dsi1)
> >>           msm_dsi_host_disable_irq(msm_dsi1->host);
> >> @@ -614,76 +457,13 @@ static enum drm_mode_status
> >> dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
> >>       return msm_dsi_host_check_dsc(host, mode);
> >>   }
> >> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
> >> -    .detect = dsi_mgr_connector_detect,
> >> -    .fill_modes = drm_helper_probe_single_connector_modes,
> >> -    .destroy = dsi_mgr_connector_destroy,
> >> -    .reset = drm_atomic_helper_connector_reset,
> >> -    .atomic_duplicate_state =
> >> drm_atomic_helper_connector_duplicate_state,
> >> -    .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >> -};
> >> -
> >> -static const struct drm_connector_helper_funcs
> >> dsi_mgr_conn_helper_funcs = {
> >> -    .get_modes = dsi_mgr_connector_get_modes,
> >> -    .best_encoder = dsi_mgr_connector_best_encoder,
> >> -};
> >> -
> >>   static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
> >>       .pre_enable = dsi_mgr_bridge_pre_enable,
> >> -    .enable = dsi_mgr_bridge_enable,
> >> -    .disable = dsi_mgr_bridge_disable,
>
> With dsi_mgr_bridge_enable/dsi_mgr_bridge_disable() removed, how will we
> handle conditions like below:
>
>      /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
>      if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>          return;
>
> Have you verified bonded_dsi with this change?

Yes, with the DPU. I don't have a bonded panel setup for the mdp5 case.

For the DPU it doesn't matter since we have just one encoder ->
bridges(+panel) -> connector chain. Thus the panel
I think it is not the case for MDP5, where there are two encoders, two
connectors, but the single panel.

Frankly speaking I'm not sure how/if this worked and whether it was
tested at all since 2015. Maybe we should step back and check this. Do
you know any available MDP5 device which uses bonded DSI?

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-11 22:39   ` Abhinav Kumar
  2022-07-11 22:54     ` [Freedreno] " Abhinav Kumar
  2022-07-12 10:00     ` Dmitry Baryshkov
@ 2022-07-12 13:22     ` Dmitry Baryshkov
  2022-07-14 21:54       ` [Freedreno] " Abhinav Kumar
  2022-11-11 15:30       ` Caleb Connolly
  2 siblings, 2 replies; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-12 13:22 UTC (permalink / raw)
  To: Rob Clark, Sean Paul, Abhinav Kumar
  Cc: David Airlie, linux-arm-msm, dri-devel, Bjorn Andersson,
	Stephen Boyd, freedreno

Currently the DSI driver has two separate paths: one if the next device
in a chain is a bridge and another one if the panel is connected
directly to the DSI host. Simplify the code path by using panel-bridge
driver (already selected in Kconfig) and dropping support for
handling the panel directly.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---

I'm not sending this as a separate patchset (I'd like to sort out mdp5
first), but more of a preview of changes related to
msm_dsi_manager_ext_bridge_init().

---
 drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
 drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
 drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
 4 files changed, 36 insertions(+), 323 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 1625328fa430..4edb9167e600 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -6,14 +6,6 @@
 #include "dsi.h"
 #include "dsi_cfg.h"
 
-struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
-{
-	if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
-		return NULL;
-
-	return msm_dsi->encoder;
-}
-
 bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
 {
 	unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
@@ -220,7 +212,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 			 struct drm_encoder *encoder)
 {
 	struct msm_drm_private *priv;
-	struct drm_bridge *ext_bridge;
 	int ret;
 
 	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
@@ -254,26 +245,10 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 		goto fail;
 	}
 
-	/*
-	 * 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);
+	ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
+	if (ret) {
 		DRM_DEV_ERROR(dev->dev,
 			"failed to create dsi connector: %d\n", ret);
-		msm_dsi->connector = NULL;
 		goto fail;
 	}
 
@@ -287,12 +262,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
 		msm_dsi->bridge = NULL;
 	}
 
-	/* 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;
-
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index 580a1e6358bf..703e4c88d7fb 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -12,7 +12,6 @@
 #include <drm/drm_bridge.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_mipi_dsi.h>
-#include <drm/drm_panel.h>
 
 #include "msm_drv.h"
 #include "disp/msm_disp_snapshot.h"
@@ -49,8 +48,6 @@ 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;
 
@@ -58,10 +55,8 @@ struct msm_dsi {
 	struct msm_dsi_phy *phy;
 
 	/*
-	 * panel/external_bridge connected to dsi bridge output, only one of the
-	 * two can be valid at a time
+	 * external_bridge connected to dsi bridge output
 	 */
-	struct drm_panel *panel;
 	struct drm_bridge *external_bridge;
 
 	struct device *phy_dev;
@@ -76,8 +71,7 @@ struct msm_dsi {
 /* dsi manager */
 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_ext_bridge_init(u8 id);
 int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
 bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
 int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
@@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
 /* msm dsi */
 static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
 {
-	return msm_dsi->panel || msm_dsi->external_bridge;
+	return msm_dsi->external_bridge;
 }
 
-struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
-
 /* dsi host */
 struct msm_dsi_host;
 int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
@@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
 				  const struct drm_display_mode *mode);
 enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
 					    const struct drm_display_mode *mode);
-struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
 unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
-struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
 int msm_dsi_host_register(struct mipi_dsi_host *host);
 void msm_dsi_host_unregister(struct mipi_dsi_host *host);
 void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -164,7 +164,6 @@ struct msm_dsi_host {
 	struct msm_display_dsc_config *dsc;
 
 	/* connected device info */
-	struct device_node *device_node;
 	unsigned int channel;
 	unsigned int lanes;
 	enum mipi_dsi_pixel_format format;
@@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
 
 	dsi_dev_detach(msm_host->pdev);
 
-	msm_host->device_node = NULL;
-
 	DBG("id=%d", msm_host->id);
 	if (msm_host->dev)
 		queue_work(msm_host->workqueue, &msm_host->hpd_work);
@@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
 		goto err;
 	}
 
-	/* Get panel node from the output port's endpoint data */
-	device_node = of_graph_get_remote_node(np, 1, 0);
-	if (!device_node) {
-		DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
-		ret = -ENODEV;
-		goto err;
-	}
-
-	msm_host->device_node = device_node;
-
 	if (of_property_read_bool(np, "syscon-sfpb")) {
 		msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
 					"syscon-sfpb");
@@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
 	return MODE_OK;
 }
 
-struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
-{
-	return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
-}
-
 unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
 {
 	return to_msm_dsi_host(host)->mode_flags;
 }
 
-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);
-}
-
 void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
 {
 	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index cb84d185d73a..546e0b873558 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
 	}
 }
 
-struct dsi_connector {
-	struct drm_connector base;
-	int id;
-};
-
 struct dsi_bridge {
 	struct drm_bridge base;
 	int id;
 };
 
-#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
 #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
 
-static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
-{
-	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
-	return dsi_connector->id;
-}
-
 static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
 {
 	struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
 	return dsi_bridge->id;
 }
 
-static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
+static void msm_dsi_manager_set_split_display(u8 id)
 {
-	struct msm_drm_private *priv = conn->dev->dev_private;
-	struct msm_kms *kms = priv->kms;
 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
 	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
+	struct msm_drm_private *priv = msm_dsi->dev->dev_private;
+	struct msm_kms *kms = priv->kms;
 	struct msm_dsi *master_dsi, *slave_dsi;
-	struct drm_panel *panel;
 
 	if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
 		master_dsi = other_dsi;
@@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
 		slave_dsi = other_dsi;
 	}
 
-	/*
-	 * There is only 1 panel in the global panel list for bonded DSI mode.
-	 * Therefore slave dsi should get the drm_panel instance from master
-	 * dsi.
-	 */
-	panel = msm_dsi_host_get_panel(master_dsi->host);
-	if (IS_ERR(panel)) {
-		DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
-			  PTR_ERR(panel));
-		return PTR_ERR(panel);
-	}
-
-	if (!panel || !IS_BONDED_DSI())
-		goto out;
-
-	drm_object_attach_property(&conn->base,
-				   conn->dev->mode_config.tile_property, 0);
+	if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
+		return;
 
 	/*
 	 * Set split display info to kms once bonded DSI panel is connected to
 	 * both hosts.
 	 */
-	if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
+	if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
 		kms->funcs->set_split_display(kms, master_dsi->encoder,
 					      slave_dsi->encoder,
 					      msm_dsi_is_cmd_mode(msm_dsi));
 	}
-
-out:
-	msm_dsi->panel = panel;
-	return 0;
-}
-
-static enum drm_connector_status dsi_mgr_connector_detect(
-		struct drm_connector *connector, bool force)
-{
-	int id = dsi_mgr_connector_get_id(connector);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-
-	return msm_dsi->panel ? connector_status_connected :
-		connector_status_disconnected;
-}
-
-static void dsi_mgr_connector_destroy(struct drm_connector *connector)
-{
-	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
-
-	DBG("");
-
-	drm_connector_cleanup(connector);
-
-	kfree(dsi_connector);
-}
-
-static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
-{
-	int id = dsi_mgr_connector_get_id(connector);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-	struct drm_panel *panel = msm_dsi->panel;
-	int num;
-
-	if (!panel)
-		return 0;
-
-	/*
-	 * In bonded DSI mode, we have one connector that can be
-	 * attached to the drm_panel.
-	 */
-	num = drm_panel_get_modes(panel, connector);
-	if (!num)
-		return 0;
-
-	return num;
-}
-
-static struct drm_encoder *
-dsi_mgr_connector_best_encoder(struct drm_connector *connector)
-{
-	int id = dsi_mgr_connector_get_id(connector);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-
-	DBG("");
-	return msm_dsi_get_encoder(msm_dsi);
 }
 
 static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
@@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
 	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
 	struct mipi_dsi_host *host = msm_dsi->host;
-	struct drm_panel *panel = msm_dsi->panel;
 	bool is_bonded_dsi = IS_BONDED_DSI();
 	int ret;
 
@@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
 	if (!dsi_mgr_power_on_early(bridge))
 		dsi_mgr_bridge_power_on(bridge);
 
-	/* Always call panel functions once, because even for dual panels,
-	 * there is only one drm_panel instance.
-	 */
-	if (panel) {
-		ret = drm_panel_prepare(panel);
-		if (ret) {
-			pr_err("%s: prepare panel %d failed, %d\n", __func__,
-								id, ret);
-			goto panel_prep_fail;
-		}
-	}
-
 	ret = msm_dsi_host_enable(host);
 	if (ret) {
 		pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
@@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
 host1_en_fail:
 	msm_dsi_host_disable(host);
 host_en_fail:
-	if (panel)
-		drm_panel_unprepare(panel);
-panel_prep_fail:
 
 	return;
 }
@@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
 	}
 }
 
-static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
-{
-	int id = dsi_mgr_bridge_get_id(bridge);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-	struct drm_panel *panel = msm_dsi->panel;
-	bool is_bonded_dsi = IS_BONDED_DSI();
-	int ret;
-
-	DBG("id=%d", id);
-	if (!msm_dsi_device_connected(msm_dsi))
-		return;
-
-	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
-	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
-		return;
-
-	if (panel) {
-		ret = drm_panel_enable(panel);
-		if (ret) {
-			pr_err("%s: enable panel %d failed, %d\n", __func__, id,
-									ret);
-		}
-	}
-}
-
-static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
-{
-	int id = dsi_mgr_bridge_get_id(bridge);
-	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
-	struct drm_panel *panel = msm_dsi->panel;
-	bool is_bonded_dsi = IS_BONDED_DSI();
-	int ret;
-
-	DBG("id=%d", id);
-	if (!msm_dsi_device_connected(msm_dsi))
-		return;
-
-	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
-	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
-		return;
-
-	if (panel) {
-		ret = drm_panel_disable(panel);
-		if (ret)
-			pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
-									ret);
-	}
-}
-
 static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
 {
 	int id = dsi_mgr_bridge_get_id(bridge);
 	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
 	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
 	struct mipi_dsi_host *host = msm_dsi->host;
-	struct drm_panel *panel = msm_dsi->panel;
 	bool is_bonded_dsi = IS_BONDED_DSI();
 	int ret;
 
@@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
 			pr_err("%s: host1 disable failed, %d\n", __func__, ret);
 	}
 
-	if (panel) {
-		ret = drm_panel_unprepare(panel);
-		if (ret)
-			pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
-								id, ret);
-	}
-
 	msm_dsi_host_disable_irq(host);
 	if (is_bonded_dsi && msm_dsi1)
 		msm_dsi_host_disable_irq(msm_dsi1->host);
@@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
 	return msm_dsi_host_check_dsc(host, mode);
 }
 
-static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
-	.detect = dsi_mgr_connector_detect,
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = dsi_mgr_connector_destroy,
-	.reset = drm_atomic_helper_connector_reset,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
-	.get_modes = dsi_mgr_connector_get_modes,
-	.best_encoder = dsi_mgr_connector_best_encoder,
-};
-
 static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
 	.pre_enable = dsi_mgr_bridge_pre_enable,
-	.enable = dsi_mgr_bridge_enable,
-	.disable = dsi_mgr_bridge_disable,
 	.post_disable = dsi_mgr_bridge_post_disable,
 	.mode_set = dsi_mgr_bridge_mode_set,
 	.mode_valid = dsi_mgr_bridge_mode_valid,
 };
 
-/* 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);
-	struct drm_connector *connector = NULL;
-	struct dsi_connector *dsi_connector;
-	int ret;
-
-	dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
-	if (!dsi_connector)
-		return ERR_PTR(-ENOMEM);
-
-	dsi_connector->id = id;
-
-	connector = &dsi_connector->base;
-
-	ret = drm_connector_init(msm_dsi->dev, connector,
-			&dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
-	if (ret)
-		return ERR_PTR(ret);
-
-	drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
-
-	/* Enable HPD to let hpd event is handled
-	 * when panel is attached to the host.
-	 */
-	connector->polled = DRM_CONNECTOR_POLL_HPD;
-
-	/* Display driver doesn't support interlace now. */
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-
-	drm_connector_attach_encoder(connector, msm_dsi->encoder);
-
-	ret = msm_dsi_manager_panel_init(connector, id);
-	if (ret) {
-		DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
-		goto fail;
-	}
-
-	return connector;
-
-fail:
-	connector->funcs->destroy(connector);
-	return ERR_PTR(ret);
-}
-
 /* initialize bridge */
 struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
 {
@@ -722,18 +502,21 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
 	return ERR_PTR(ret);
 }
 
-struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
+int 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_connector *connector;
 	struct drm_encoder *encoder;
 	struct drm_bridge *int_bridge, *ext_bridge;
 	int ret;
 
 	int_bridge = msm_dsi->bridge;
-	ext_bridge = msm_dsi->external_bridge =
-			msm_dsi_host_get_bridge(msm_dsi->host);
+	ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev,
+					    msm_dsi->pdev->dev.of_node, 1, 0);
+	if (IS_ERR(ext_bridge))
+		return PTR_ERR(ext_bridge);
+
+	msm_dsi->external_bridge = ext_bridge;
 
 	encoder = msm_dsi->encoder;
 
@@ -745,36 +528,32 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
 	ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
 			DRM_BRIDGE_ATTACH_NO_CONNECTOR);
 	if (ret == -EINVAL) {
-		struct drm_connector *connector;
-		struct list_head *connector_list;
-
-		/* link the internal dsi bridge to the external bridge */
-		drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
-
 		/*
-		 * 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()
+		 * link the internal dsi bridge to the external bridge,
+		 * connector is created by the next bridge.
 		 */
-		connector_list = &dev->mode_config.connector_list;
+		ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
+		if (ret < 0)
+			return ret;
+	} else {
+		struct drm_connector *connector;
 
-		list_for_each_entry(connector, connector_list, head) {
-			if (drm_connector_has_possible_encoder(connector, encoder))
-				return connector;
+		/* We are in charge of the connector, create one now. */
+		connector = drm_bridge_connector_init(dev, encoder);
+		if (IS_ERR(connector)) {
+			DRM_ERROR("Unable to create bridge connector\n");
+			return PTR_ERR(connector);
 		}
 
-		return ERR_PTR(-ENODEV);
-	}
-
-	connector = drm_bridge_connector_init(dev, encoder);
-	if (IS_ERR(connector)) {
-		DRM_ERROR("Unable to create bridge connector\n");
-		return ERR_CAST(connector);
+		ret = drm_connector_attach_encoder(connector, encoder);
+		if (ret < 0)
+			return ret;
 	}
 
-	drm_connector_attach_encoder(connector, encoder);
+	/* The pipeline is ready, ping encoders if necessary */
+	msm_dsi_manager_set_split_display(id);
 
-	return connector;
+	return 0;
 }
 
 void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-12 10:00     ` Dmitry Baryshkov
@ 2022-07-12 19:15       ` Abhinav Kumar
  2022-07-12 20:10         ` Dmitry Baryshkov
  0 siblings, 1 reply; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-12 19:15 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Thomas Zimmermann, Sam Ravnborg, David Airlie, freedreno,
	Stephen Boyd, Thierry Reding, dri-devel, linux-arm-msm,
	Bjorn Andersson, Sean Paul



On 7/12/2022 3:00 AM, Dmitry Baryshkov wrote:
> On Tue, 12 Jul 2022 at 01:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
>>> Currently the DSI driver has two separate paths: one if the next device
>>> in a chain is a bridge and another one if the panel is connected
>>> directly to the DSI host. Simplify the code path by using panel-bridge
>>> driver (already selected in Kconfig) and dropping support for
>>> handling the panel directly.
>>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>>    drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
>>>    drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
>>>    drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>>    drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
>>>    4 files changed, 26 insertions(+), 315 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
>>> index 1625328fa430..3c53e28092db 100644
>>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
>>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
>>> @@ -6,14 +6,6 @@
>>>    #include "dsi.h"
>>>    #include "dsi_cfg.h"
>>>
>>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
>>> -{
>>> -     if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
>>> -             return NULL;
>>> -
>>> -     return msm_dsi->encoder;
>>> -}
>>
>> panel_bridge doesnt have the best_encoder method today.
>> Today, this does not break anything for us.
>> But, for future if we do need it, panel_bridge needs to be expanded to
>> add that method?
> 
> We have a 1:1 between encoder and connector, so
> drm_connector_get_single_encoder() works well in our case.
> 
like I said before, today this should be fine.
If we do come up with a use-case in future to have the best_encoder() 
panel_bridge will need to be expanded. So this is more of a comment to 
keep in mind but no change needed for this.

>>
>>> -
>>>    bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>>>    {
>>>        unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
>>> @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>>>                         struct drm_encoder *encoder)
>>>    {
>>>        struct msm_drm_private *priv;
>>> -     struct drm_bridge *ext_bridge;
>>> +     struct drm_connector *connector;
>>>        int ret;
>>>
>>>        if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
>>> @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>>>                goto fail;
>>>        }
>>>
>>> -     /*
>>> -      * 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);
>>> +     connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
>>> +
>>> +     if (IS_ERR(connector)) {
>>> +             ret = PTR_ERR(connector);
>>>                DRM_DEV_ERROR(dev->dev,
>>>                        "failed to create dsi connector: %d\n", ret);
>>> -             msm_dsi->connector = NULL;
>>>                goto fail;
>>>        }
>>>
>>> @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>>>                msm_dsi->bridge = NULL;
>>>        }
>>>
>>> -     /* 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;
>>> -
>>>        return ret;
>>>    }
>>>
>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
>>> index 580a1e6358bf..41630b8f5358 100644
>>> --- a/drivers/gpu/drm/msm/dsi/dsi.h
>>> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
>>> @@ -12,7 +12,6 @@
>>>    #include <drm/drm_bridge.h>
>>>    #include <drm/drm_crtc.h>
>>>    #include <drm/drm_mipi_dsi.h>
>>> -#include <drm/drm_panel.h>
>>>
>>>    #include "msm_drv.h"
>>>    #include "disp/msm_disp_snapshot.h"
>>> @@ -49,8 +48,6 @@ 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;
>>>
>>> @@ -58,10 +55,8 @@ struct msm_dsi {
>>>        struct msm_dsi_phy *phy;
>>>
>>>        /*
>>> -      * panel/external_bridge connected to dsi bridge output, only one of the
>>> -      * two can be valid at a time
>>> +      * external_bridge connected to dsi bridge output
>>>         */
>>> -     struct drm_panel *panel;
>>>        struct drm_bridge *external_bridge;
>>>
>>>        struct device *phy_dev;
>>> @@ -76,7 +71,6 @@ struct msm_dsi {
>>>    /* dsi manager */
>>>    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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>>>    bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
>>> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>>>    /* msm dsi */
>>>    static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>>>    {
>>> -     return msm_dsi->panel || msm_dsi->external_bridge;
>>> +     return msm_dsi->external_bridge;
>>>    }
>>>
>>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
>>> -
>>>    /* dsi host */
>>>    struct msm_dsi_host;
>>>    int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
>>> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
>>>                                  const struct drm_display_mode *mode);
>>>    enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>>                                            const struct drm_display_mode *mode);
>>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>>>    unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
>>> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>>>    int msm_dsi_host_register(struct mipi_dsi_host *host);
>>>    void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>>>    void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
>>> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
>>> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
>>> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>>>        struct msm_display_dsc_config *dsc;
>>>
>>>        /* connected device info */
>>> -     struct device_node *device_node;
>>>        unsigned int channel;
>>>        unsigned int lanes;
>>>        enum mipi_dsi_pixel_format format;
>>> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
>>>
>>>        dsi_dev_detach(msm_host->pdev);
>>>
>>> -     msm_host->device_node = NULL;
>>> -
>>>        DBG("id=%d", msm_host->id);
>>>        if (msm_host->dev)
>>>                queue_work(msm_host->workqueue, &msm_host->hpd_work);
>>> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
>>>                goto err;
>>>        }
>>>
>>> -     /* Get panel node from the output port's endpoint data */
>>> -     device_node = of_graph_get_remote_node(np, 1, 0);
>>> -     if (!device_node) {
>>> -             DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
>>> -             ret = -ENODEV;
>>> -             goto err;
>>> -     }
>>> -
>>> -     msm_host->device_node = device_node;
>>> -
>>>        if (of_property_read_bool(np, "syscon-sfpb")) {
>>>                msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>>>                                        "syscon-sfpb");
>>> @@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>>        return MODE_OK;
>>>    }
>>>
>>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
>>> -{
>>> -     return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
>>> -}
>>> -
>>>    unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>>>    {
>>>        return to_msm_dsi_host(host)->mode_flags;
>>>    }
>>>
>>> -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);
>>> -}
>>> -
>>>    void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
>>>    {
>>>        struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>> index cb84d185d73a..3970368e07d5 100644
>>> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>>>        }
>>>    }
>>>
>>> -struct dsi_connector {
>>> -     struct drm_connector base;
>>> -     int id;
>>> -};
>>> -
>>>    struct dsi_bridge {
>>>        struct drm_bridge base;
>>>        int id;
>>>    };
>>>
>>> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>>>    #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
>>>
>>> -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
>>> -{
>>> -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>>> -     return dsi_connector->id;
>>> -}
>>> -
>>>    static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>>>    {
>>>        struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>>>        return dsi_bridge->id;
>>>    }
>>>
>>> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>>> +static void msm_dsi_manager_set_split_display(u8 id)
>>>    {
>>> -     struct msm_drm_private *priv = conn->dev->dev_private;
>>> -     struct msm_kms *kms = priv->kms;
>>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>        struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
>>> +     struct msm_drm_private *priv = msm_dsi->dev->dev_private;
>>> +     struct msm_kms *kms = priv->kms;
>>>        struct msm_dsi *master_dsi, *slave_dsi;
>>> -     struct drm_panel *panel;
>>>
>>>        if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>>>                master_dsi = other_dsi;
>>> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>>>                slave_dsi = other_dsi;
>>>        }
>>>
>>> -     /*
>>> -      * There is only 1 panel in the global panel list for bonded DSI mode.
>>> -      * Therefore slave dsi should get the drm_panel instance from master
>>> -      * dsi.
>>> -      */
>>> -     panel = msm_dsi_host_get_panel(master_dsi->host);
>>> -     if (IS_ERR(panel)) {
>>> -             DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
>>> -                       PTR_ERR(panel));
>>> -             return PTR_ERR(panel);
>>> -     }
>>> -
>>> -     if (!panel || !IS_BONDED_DSI())
>>> -             goto out;
>>> -
>>> -     drm_object_attach_property(&conn->base,
>>> -                                conn->dev->mode_config.tile_property, 0);
>>> +     if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
>>> +             return;
>>>
>>>        /*
>>>         * Set split display info to kms once bonded DSI panel is connected to
>>>         * both hosts.
>>>         */
>>> -     if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
>>> +     if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
>>>                kms->funcs->set_split_display(kms, master_dsi->encoder,
>>>                                              slave_dsi->encoder,
>>>                                              msm_dsi_is_cmd_mode(msm_dsi));
>>>        }
>>> -
>>> -out:
>>> -     msm_dsi->panel = panel;
>>> -     return 0;
>>> -}
>>> -
>>> -static enum drm_connector_status dsi_mgr_connector_detect(
>>> -             struct drm_connector *connector, bool force)
>>> -{
>>> -     int id = dsi_mgr_connector_get_id(connector);
>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>> -
>>> -     return msm_dsi->panel ? connector_status_connected :
>>> -             connector_status_disconnected;
>>> -}
>>> -
>>> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
>>> -{
>>> -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>>> -
>>> -     DBG("");
>>> -
>>> -     drm_connector_cleanup(connector);
>>> -
>>> -     kfree(dsi_connector);
>>> -}
>>> -
>>> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
>>> -{
>>> -     int id = dsi_mgr_connector_get_id(connector);
>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>> -     struct drm_panel *panel = msm_dsi->panel;
>>> -     int num;
>>> -
>>> -     if (!panel)
>>> -             return 0;
>>> -
>>> -     /*
>>> -      * In bonded DSI mode, we have one connector that can be
>>> -      * attached to the drm_panel.
>>> -      */
>>> -     num = drm_panel_get_modes(panel, connector);
>>> -     if (!num)
>>> -             return 0;
>>> -
>>> -     return num;
>>> -}
>>> -
>>> -static struct drm_encoder *
>>> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
>>> -{
>>> -     int id = dsi_mgr_connector_get_id(connector);
>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>> -
>>> -     DBG("");
>>> -     return msm_dsi_get_encoder(msm_dsi);
>>>    }
>>>
>>>    static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
>>> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>        struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>>        struct mipi_dsi_host *host = msm_dsi->host;
>>> -     struct drm_panel *panel = msm_dsi->panel;
>>>        bool is_bonded_dsi = IS_BONDED_DSI();
>>>        int ret;
>>>
>>> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>>>        if (!dsi_mgr_power_on_early(bridge))
>>>                dsi_mgr_bridge_power_on(bridge);
>>>
>>> -     /* Always call panel functions once, because even for dual panels,
>>> -      * there is only one drm_panel instance.
>>> -      */
>>> -     if (panel) {
>>> -             ret = drm_panel_prepare(panel);
>>> -             if (ret) {
>>> -                     pr_err("%s: prepare panel %d failed, %d\n", __func__,
>>> -                                                             id, ret);
>>> -                     goto panel_prep_fail;
>>> -             }
>>> -     }
>>> -
>>>        ret = msm_dsi_host_enable(host);
>>>        if (ret) {
>>>                pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
>>> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>>>    host1_en_fail:
>>>        msm_dsi_host_disable(host);
>>>    host_en_fail:
>>> -     if (panel)
>>> -             drm_panel_unprepare(panel);
>>> -panel_prep_fail:
>>>
>>>        return;
>>>    }
>>> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>>>        }
>>>    }
>>>
>>> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
>>> -{
>>> -     int id = dsi_mgr_bridge_get_id(bridge);
>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>> -     struct drm_panel *panel = msm_dsi->panel;
>>> -     bool is_bonded_dsi = IS_BONDED_DSI();
>>> -     int ret;
>>> -
>>> -     DBG("id=%d", id);
>>> -     if (!msm_dsi_device_connected(msm_dsi))
>>> -             return;
>>> -
>>> -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
>>> -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>>> -             return;
>>> -
>>> -     if (panel) {
>>> -             ret = drm_panel_enable(panel);
>>> -             if (ret) {
>>> -                     pr_err("%s: enable panel %d failed, %d\n", __func__, id,
>>> -                                                                     ret);
>>> -             }
>>> -     }
>>> -}
>>> -
>>> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
>>> -{
>>> -     int id = dsi_mgr_bridge_get_id(bridge);
>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>> -     struct drm_panel *panel = msm_dsi->panel;
>>> -     bool is_bonded_dsi = IS_BONDED_DSI();
>>> -     int ret;
>>> -
>>> -     DBG("id=%d", id);
>>> -     if (!msm_dsi_device_connected(msm_dsi))
>>> -             return;
>>> -
>>> -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
>>> -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>>> -             return;
>>> -
>>> -     if (panel) {
>>> -             ret = drm_panel_disable(panel);
>>> -             if (ret)
>>> -                     pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
>>> -                                                                     ret);
>>> -     }
>>> -}
>>> -
>>>    static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>>>    {
>>>        int id = dsi_mgr_bridge_get_id(bridge);
>>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>        struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>>        struct mipi_dsi_host *host = msm_dsi->host;
>>> -     struct drm_panel *panel = msm_dsi->panel;
>>>        bool is_bonded_dsi = IS_BONDED_DSI();
>>>        int ret;
>>>
>>> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>>>                        pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>>>        }
>>>
>>> -     if (panel) {
>>> -             ret = drm_panel_unprepare(panel);
>>> -             if (ret)
>>> -                     pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
>>> -                                                             id, ret);
>>> -     }
>>> -
>>>        msm_dsi_host_disable_irq(host);
>>>        if (is_bonded_dsi && msm_dsi1)
>>>                msm_dsi_host_disable_irq(msm_dsi1->host);
>>> @@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>>>        return msm_dsi_host_check_dsc(host, mode);
>>>    }
>>>
>>> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
>>> -     .detect = dsi_mgr_connector_detect,
>>> -     .fill_modes = drm_helper_probe_single_connector_modes,
>>> -     .destroy = dsi_mgr_connector_destroy,
>>> -     .reset = drm_atomic_helper_connector_reset,
>>> -     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>>> -     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>>> -};
>>> -
>>> -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
>>> -     .get_modes = dsi_mgr_connector_get_modes,
>>> -     .best_encoder = dsi_mgr_connector_best_encoder,
>>> -};
>>> -
>>>    static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>>>        .pre_enable = dsi_mgr_bridge_pre_enable,
>>> -     .enable = dsi_mgr_bridge_enable,
>>> -     .disable = dsi_mgr_bridge_disable,
>>>        .post_disable = dsi_mgr_bridge_post_disable,
>>>        .mode_set = dsi_mgr_bridge_mode_set,
>>>        .mode_valid = dsi_mgr_bridge_mode_valid,
>>>    };
>>>
>>> -/* 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);
>>> -     struct drm_connector *connector = NULL;
>>> -     struct dsi_connector *dsi_connector;
>>> -     int ret;
>>> -
>>> -     dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
>>> -     if (!dsi_connector)
>>> -             return ERR_PTR(-ENOMEM);
>>> -
>>> -     dsi_connector->id = id;
>>> -
>>> -     connector = &dsi_connector->base;
>>> -
>>> -     ret = drm_connector_init(msm_dsi->dev, connector,
>>> -                     &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
>>> -     if (ret)
>>> -             return ERR_PTR(ret);
>>> -
>>> -     drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
>>> -
>>> -     /* Enable HPD to let hpd event is handled
>>> -      * when panel is attached to the host.
>>> -      */
>>> -     connector->polled = DRM_CONNECTOR_POLL_HPD;
>>
>> I see that this part gets removed with this migration.
>>
>> For fixed/built-in displays, it should not matter i think but i am not
>> sure if some usermodes might expect this even for DSI?
>>
>> So, once again does panel_bridge needs to account for this?
> 
> Panel bridge sets only DRM_BRIDGE_OP_MODES. If you check the existing
> code, the dsi_mgr_connector also does not provide HPD support. It only
> can return panel status depending on whether the drm_panel was fetched
> or not. No events are generated ever.
> Thus said I think we should stop hijacking the usual mechanisms. If we
> do not do the HPD, let's not declare it. If there is a case of panel
> being hotplugged or switched, it will be handled by the next bridge in
> the chain, not by the MSM DSI code.
> 
hot plug events are sent today.


static void dsi_hpd_worker(struct work_struct *work)
{
     struct msm_dsi_host *msm_host =
         container_of(work, struct msm_dsi_host, hpd_work);

     drm_helper_hpd_irq_event(msm_host->dev);
}

If you are planning to drop DRM_CONNECTOR_POLL_HPD, then you should 
remove all this code as well because its just dead code otherwise.

I agree, the hot plug handling can be done by the next bridge in the chain.

Then lets cleanup this code too.

>>
>>
>>> -
>>> -     /* Display driver doesn't support interlace now. */
>>> -     connector->interlace_allowed = 0;
>>> -     connector->doublescan_allowed = 0;
>>> -
>>> -     drm_connector_attach_encoder(connector, msm_dsi->encoder);
>>> -
>>> -     ret = msm_dsi_manager_panel_init(connector, id);
>>> -     if (ret) {
>>> -             DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
>>> -             goto fail;
>>> -     }
>>> -
>>> -     return connector;
>>> -
>>> -fail:
>>> -     connector->funcs->destroy(connector);
>>> -     return ERR_PTR(ret);
>>> -}
>>> -
>>>    /* initialize bridge */
>>>    struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>>>    {
>>> @@ -732,8 +512,11 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>>>        int ret;
>>>
>>>        int_bridge = msm_dsi->bridge;
>>> -     ext_bridge = msm_dsi->external_bridge =
>>> -                     msm_dsi_host_get_bridge(msm_dsi->host);
>>> +     ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, msm_dsi->pdev->dev.of_node, 1, 0);
>>> +     if (IS_ERR(ext_bridge))
>>> +             return ERR_CAST(ext_bridge);
>>> +
>>> +     msm_dsi->external_bridge = ext_bridge;
>>>
>>>        encoder = msm_dsi->encoder;
>>>
>>> @@ -745,25 +528,12 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>>>        ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>>>                        DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>>        if (ret == -EINVAL) {
>>> -             struct drm_connector *connector;
>>> -             struct list_head *connector_list;
>>> -
>>>                /* link the internal dsi bridge to the external bridge */
>>> -             drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>>> +             ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>>> +             if (ret < 0)
>>> +                     return ERR_PTR(ret);
>>>
>>> -             /*
>>> -              * 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) {
>>> -                     if (drm_connector_has_possible_encoder(connector, encoder))
>>> -                             return connector;
>>> -             }
>>> -
>>> -             return ERR_PTR(-ENODEV);
>>> +             goto out;
>>>        }
>>>
>>>        connector = drm_bridge_connector_init(dev, encoder);
>>> @@ -774,6 +544,10 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>>>
>>>        drm_connector_attach_encoder(connector, encoder);
>>>
>>> +out:
>>> +     /* The pipeline is ready, ping encoders if necessary */
>>> +     msm_dsi_manager_set_split_display(id);
>> Do you still want to execute msm_dsi_manager_set_split_display even for
>> the error case? Like in the above lines you have replaced the return
>> ERR_PTR() with the goto out. But do you want to then move the
>> set_split_display() call above the out label?
> 
> You see, the return ERR_PTR was the error case, where we could not
> find the connector corresponding to the encoder.
> We just don't need it anymore. Let's change the function to return int
> rather than the unused connector.
> 
>>
>> Also, now for the cases where there was an error where the connector was
>> not found, we will return a NULL ptr instead of the ERR_PTR(-ENODEV).
>> Is that expected?
> 
> Yes. We just do not care anymore about this connector.
> 

My question was do you want to skip even 
msm_dsi_manager_set_split_display(id) by moving it above the out label.

>>
>>> +
>>>        return connector;
>>>    }
>>>
> 
> 
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-12 10:13       ` Dmitry Baryshkov
@ 2022-07-12 19:53         ` Abhinav Kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-12 19:53 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: freedreno, David Airlie, Sean Paul, Bjorn Andersson,
	Thierry Reding, dri-devel, Thomas Zimmermann, linux-arm-msm,
	Stephen Boyd, Sam Ravnborg



On 7/12/2022 3:13 AM, Dmitry Baryshkov wrote:
> On Tue, 12 Jul 2022 at 01:54, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>> <missed one comment>
>>
>>
>> On 7/11/2022 3:39 PM, Abhinav Kumar wrote:
>>>
>>>
>>> On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
>>>> Currently the DSI driver has two separate paths: one if the next device
>>>> in a chain is a bridge and another one if the panel is connected
>>>> directly to the DSI host. Simplify the code path by using panel-bridge
>>>> driver (already selected in Kconfig) and dropping support for
>>>> handling the panel directly.
>>>>
>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>> ---
>>>>    drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
>>>>    drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
>>>>    drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>>>    drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
>>>>    4 files changed, 26 insertions(+), 315 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c
>>>> b/drivers/gpu/drm/msm/dsi/dsi.c
>>>> index 1625328fa430..3c53e28092db 100644
>>>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
>>>> @@ -6,14 +6,6 @@
>>>>    #include "dsi.h"
>>>>    #include "dsi_cfg.h"
>>>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
>>>> -{
>>>> -    if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
>>>> -        return NULL;
>>>> -
>>>> -    return msm_dsi->encoder;
>>>> -}
>>>
>>> panel_bridge doesnt have the best_encoder method today.
>>> Today, this does not break anything for us.
>>> But, for future if we do need it, panel_bridge needs to be expanded to
>>> add that method?
>>>
>>>> -
>>>>    bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>>>>    {
>>>>        unsigned long host_flags =
>>>> msm_dsi_host_get_mode_flags(msm_dsi->host);
>>>> @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
>>>> struct drm_device *dev,
>>>>                 struct drm_encoder *encoder)
>>>>    {
>>>>        struct msm_drm_private *priv;
>>>> -    struct drm_bridge *ext_bridge;
>>>> +    struct drm_connector *connector;
>>>>        int ret;
>>>>        if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
>>>> @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi
>>>> *msm_dsi, struct drm_device *dev,
>>>>            goto fail;
>>>>        }
>>>> -    /*
>>>> -     * 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);
>>>> +    connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
>>>> +
>>>> +    if (IS_ERR(connector)) {
>>>> +        ret = PTR_ERR(connector);
>>>>            DRM_DEV_ERROR(dev->dev,
>>>>                "failed to create dsi connector: %d\n", ret);
>>>> -        msm_dsi->connector = NULL;
>>>>            goto fail;
>>>>        }
>>>> @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
>>>> struct drm_device *dev,
>>>>            msm_dsi->bridge = NULL;
>>>>        }
>>>> -    /* 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;
>>>> -
>>>>        return ret;
>>>>    }
>>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h
>>>> b/drivers/gpu/drm/msm/dsi/dsi.h
>>>> index 580a1e6358bf..41630b8f5358 100644
>>>> --- a/drivers/gpu/drm/msm/dsi/dsi.h
>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
>>>> @@ -12,7 +12,6 @@
>>>>    #include <drm/drm_bridge.h>
>>>>    #include <drm/drm_crtc.h>
>>>>    #include <drm/drm_mipi_dsi.h>
>>>> -#include <drm/drm_panel.h>
>>>>    #include "msm_drv.h"
>>>>    #include "disp/msm_disp_snapshot.h"
>>>> @@ -49,8 +48,6 @@ 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;
>>>> @@ -58,10 +55,8 @@ struct msm_dsi {
>>>>        struct msm_dsi_phy *phy;
>>>>        /*
>>>> -     * panel/external_bridge connected to dsi bridge output, only one
>>>> of the
>>>> -     * two can be valid at a time
>>>> +     * external_bridge connected to dsi bridge output
>>>>         */
>>>> -    struct drm_panel *panel;
>>>>        struct drm_bridge *external_bridge;
>>>>        struct device *phy_dev;
>>>> @@ -76,7 +71,6 @@ struct msm_dsi {
>>>>    /* dsi manager */
>>>>    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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>>>>    bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
>>>> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>>>>    /* msm dsi */
>>>>    static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>>>>    {
>>>> -    return msm_dsi->panel || msm_dsi->external_bridge;
>>>> +    return msm_dsi->external_bridge;
>>>>    }
>>>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
>>>> -
>>>>    /* dsi host */
>>>>    struct msm_dsi_host;
>>>>    int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
>>>> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct
>>>> mipi_dsi_host *host,
>>>>                      const struct drm_display_mode *mode);
>>>>    enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>>>                            const struct drm_display_mode *mode);
>>>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>>>>    unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
>>>> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>>>>    int msm_dsi_host_register(struct mipi_dsi_host *host);
>>>>    void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>>>>    void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
>>>> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
>>>> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>>>>        struct msm_display_dsc_config *dsc;
>>>>        /* connected device info */
>>>> -    struct device_node *device_node;
>>>>        unsigned int channel;
>>>>        unsigned int lanes;
>>>>        enum mipi_dsi_pixel_format format;
>>>> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host
>>>> *host,
>>>>        dsi_dev_detach(msm_host->pdev);
>>>> -    msm_host->device_node = NULL;
>>>> -
>>>>        DBG("id=%d", msm_host->id);
>>>>        if (msm_host->dev)
>>>>            queue_work(msm_host->workqueue, &msm_host->hpd_work);
>>>> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct
>>>> msm_dsi_host *msm_host)
>>>>            goto err;
>>>>        }
>>>> -    /* Get panel node from the output port's endpoint data */
>>>> -    device_node = of_graph_get_remote_node(np, 1, 0);
>>>> -    if (!device_node) {
>>>> -        DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
>>>> -        ret = -ENODEV;
>>>> -        goto err;
>>>> -    }
>>>> -
>>>> -    msm_host->device_node = device_node;
>>>> -
>>>>        if (of_property_read_bool(np, "syscon-sfpb")) {
>>>>            msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>>>>                        "syscon-sfpb");
>>>> @@ -2678,23 +2665,11 @@ enum drm_mode_status
>>>> msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>>>        return MODE_OK;
>>>>    }
>>>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
>>>> -{
>>>> -    return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
>>>> -}
>>>> -
>>>>    unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>>>>    {
>>>>        return to_msm_dsi_host(host)->mode_flags;
>>>>    }
>>>> -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);
>>>> -}
>>>> -
>>>>    void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct
>>>> mipi_dsi_host *host)
>>>>    {
>>>>        struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
>>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>>> b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>>> index cb84d185d73a..3970368e07d5 100644
>>>> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>>> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>>>>        }
>>>>    }
>>>> -struct dsi_connector {
>>>> -    struct drm_connector base;
>>>> -    int id;
>>>> -};
>>>> -
>>>>    struct dsi_bridge {
>>>>        struct drm_bridge base;
>>>>        int id;
>>>>    };
>>>> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>>>>    #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
>>>> -static inline int dsi_mgr_connector_get_id(struct drm_connector
>>>> *connector)
>>>> -{
>>>> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>>>> -    return dsi_connector->id;
>>>> -}
>>>> -
>>>>    static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>>>>    {
>>>>        struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>>>>        return dsi_bridge->id;
>>>>    }
>>>> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>>>> +static void msm_dsi_manager_set_split_display(u8 id)
>>>>    {
>>>> -    struct msm_drm_private *priv = conn->dev->dev_private;
>>>> -    struct msm_kms *kms = priv->kms;
>>>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>        struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
>>>> +    struct msm_drm_private *priv = msm_dsi->dev->dev_private;
>>>> +    struct msm_kms *kms = priv->kms;
>>>>        struct msm_dsi *master_dsi, *slave_dsi;
>>>> -    struct drm_panel *panel;
>>>>        if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>>>>            master_dsi = other_dsi;
>>>> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct
>>>> drm_connector *conn, u8 id)
>>>>            slave_dsi = other_dsi;
>>>>        }
>>>> -    /*
>>>> -     * There is only 1 panel in the global panel list for bonded DSI
>>>> mode.
>>>> -     * Therefore slave dsi should get the drm_panel instance from master
>>>> -     * dsi.
>>>> -     */
>>>> -    panel = msm_dsi_host_get_panel(master_dsi->host);
>>>> -    if (IS_ERR(panel)) {
>>>> -        DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
>>>> -              PTR_ERR(panel));
>>>> -        return PTR_ERR(panel);
>>>> -    }
>>>> -
>>>> -    if (!panel || !IS_BONDED_DSI())
>>>> -        goto out;
>>>> -
>>>> -    drm_object_attach_property(&conn->base,
>>>> -                   conn->dev->mode_config.tile_property, 0);
>>>> +    if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
>>>> +        return;
>>>>        /*
>>>>         * Set split display info to kms once bonded DSI panel is
>>>> connected to
>>>>         * both hosts.
>>>>         */
>>>> -    if (other_dsi && other_dsi->panel &&
>>>> kms->funcs->set_split_display) {
>>>> +    if (other_dsi && other_dsi->external_bridge &&
>>>> kms->funcs->set_split_display) {
>>>>            kms->funcs->set_split_display(kms, master_dsi->encoder,
>>>>                              slave_dsi->encoder,
>>>>                              msm_dsi_is_cmd_mode(msm_dsi));
>>>>        }
>>>> -
>>>> -out:
>>>> -    msm_dsi->panel = panel;
>>>> -    return 0;
>>>> -}
>>>> -
>>>> -static enum drm_connector_status dsi_mgr_connector_detect(
>>>> -        struct drm_connector *connector, bool force)
>>>> -{
>>>> -    int id = dsi_mgr_connector_get_id(connector);
>>>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>> -
>>>> -    return msm_dsi->panel ? connector_status_connected :
>>>> -        connector_status_disconnected;
>>>> -}
>>>> -
>>>> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
>>>> -{
>>>> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>>>> -
>>>> -    DBG("");
>>>> -
>>>> -    drm_connector_cleanup(connector);
>>>> -
>>>> -    kfree(dsi_connector);
>>>> -}
>>>> -
>>>> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
>>>> -{
>>>> -    int id = dsi_mgr_connector_get_id(connector);
>>>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>> -    struct drm_panel *panel = msm_dsi->panel;
>>>> -    int num;
>>>> -
>>>> -    if (!panel)
>>>> -        return 0;
>>>> -
>>>> -    /*
>>>> -     * In bonded DSI mode, we have one connector that can be
>>>> -     * attached to the drm_panel.
>>>> -     */
>>>> -    num = drm_panel_get_modes(panel, connector);
>>>> -    if (!num)
>>>> -        return 0;
>>>> -
>>>> -    return num;
>>>> -}
>>>> -
>>>> -static struct drm_encoder *
>>>> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
>>>> -{
>>>> -    int id = dsi_mgr_connector_get_id(connector);
>>>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>> -
>>>> -    DBG("");
>>>> -    return msm_dsi_get_encoder(msm_dsi);
>>>>    }
>>>>    static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
>>>> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct
>>>> drm_bridge *bridge)
>>>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>        struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>>>        struct mipi_dsi_host *host = msm_dsi->host;
>>>> -    struct drm_panel *panel = msm_dsi->panel;
>>>>        bool is_bonded_dsi = IS_BONDED_DSI();
>>>>        int ret;
>>>> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct
>>>> drm_bridge *bridge)
>>>>        if (!dsi_mgr_power_on_early(bridge))
>>>>            dsi_mgr_bridge_power_on(bridge);
>>>> -    /* Always call panel functions once, because even for dual panels,
>>>> -     * there is only one drm_panel instance.
>>>> -     */
>>>> -    if (panel) {
>>>> -        ret = drm_panel_prepare(panel);
>>>> -        if (ret) {
>>>> -            pr_err("%s: prepare panel %d failed, %d\n", __func__,
>>>> -                                id, ret);
>>>> -            goto panel_prep_fail;
>>>> -        }
>>>> -    }
>>>> -
>>>>        ret = msm_dsi_host_enable(host);
>>>>        if (ret) {
>>>>            pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
>>>> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct
>>>> drm_bridge *bridge)
>>>>    host1_en_fail:
>>>>        msm_dsi_host_disable(host);
>>>>    host_en_fail:
>>>> -    if (panel)
>>>> -        drm_panel_unprepare(panel);
>>>> -panel_prep_fail:
>>>>        return;
>>>>    }
>>>> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>>>>        }
>>>>    }
>>>> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
>>>> -{
>>>> -    int id = dsi_mgr_bridge_get_id(bridge);
>>>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>> -    struct drm_panel *panel = msm_dsi->panel;
>>>> -    bool is_bonded_dsi = IS_BONDED_DSI();
>>>> -    int ret;
>>>> -
>>>> -    DBG("id=%d", id);
>>>> -    if (!msm_dsi_device_connected(msm_dsi))
>>>> -        return;
>>>> -
>>>> -    /* Do nothing with the host if it is slave-DSI in case of bonded
>>>> DSI */
>>>> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>>>> -        return;
>>>> -
>>>> -    if (panel) {
>>>> -        ret = drm_panel_enable(panel);
>>>> -        if (ret) {
>>>> -            pr_err("%s: enable panel %d failed, %d\n", __func__, id,
>>>> -                                    ret);
>>>> -        }
>>>> -    }
>>>> -}
>>>> -
>>>> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
>>>> -{
>>>> -    int id = dsi_mgr_bridge_get_id(bridge);
>>>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>> -    struct drm_panel *panel = msm_dsi->panel;
>>>> -    bool is_bonded_dsi = IS_BONDED_DSI();
>>>> -    int ret;
>>>> -
>>>> -    DBG("id=%d", id);
>>>> -    if (!msm_dsi_device_connected(msm_dsi))
>>>> -        return;
>>>> -
>>>> -    /* Do nothing with the host if it is slave-DSI in case of bonded
>>>> DSI */
>>>> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>>>> -        return;
>>>> -
>>>> -    if (panel) {
>>>> -        ret = drm_panel_disable(panel);
>>>> -        if (ret)
>>>> -            pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
>>>> -                                    ret);
>>>> -    }
>>>> -}
>>>> -
>>>>    static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>>>>    {
>>>>        int id = dsi_mgr_bridge_get_id(bridge);
>>>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>        struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>>>        struct mipi_dsi_host *host = msm_dsi->host;
>>>> -    struct drm_panel *panel = msm_dsi->panel;
>>>>        bool is_bonded_dsi = IS_BONDED_DSI();
>>>>        int ret;
>>>> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct
>>>> drm_bridge *bridge)
>>>>                pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>>>>        }
>>>> -    if (panel) {
>>>> -        ret = drm_panel_unprepare(panel);
>>>> -        if (ret)
>>>> -            pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
>>>> -                                id, ret);
>>>> -    }
>>>> -
>>>>        msm_dsi_host_disable_irq(host);
>>>>        if (is_bonded_dsi && msm_dsi1)
>>>>            msm_dsi_host_disable_irq(msm_dsi1->host);
>>>> @@ -614,76 +457,13 @@ static enum drm_mode_status
>>>> dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>>>>        return msm_dsi_host_check_dsc(host, mode);
>>>>    }
>>>> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
>>>> -    .detect = dsi_mgr_connector_detect,
>>>> -    .fill_modes = drm_helper_probe_single_connector_modes,
>>>> -    .destroy = dsi_mgr_connector_destroy,
>>>> -    .reset = drm_atomic_helper_connector_reset,
>>>> -    .atomic_duplicate_state =
>>>> drm_atomic_helper_connector_duplicate_state,
>>>> -    .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>>>> -};
>>>> -
>>>> -static const struct drm_connector_helper_funcs
>>>> dsi_mgr_conn_helper_funcs = {
>>>> -    .get_modes = dsi_mgr_connector_get_modes,
>>>> -    .best_encoder = dsi_mgr_connector_best_encoder,
>>>> -};
>>>> -
>>>>    static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>>>>        .pre_enable = dsi_mgr_bridge_pre_enable,
>>>> -    .enable = dsi_mgr_bridge_enable,
>>>> -    .disable = dsi_mgr_bridge_disable,
>>
>> With dsi_mgr_bridge_enable/dsi_mgr_bridge_disable() removed, how will we
>> handle conditions like below:
>>
>>       /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
>>       if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>>           return;
>>
>> Have you verified bonded_dsi with this change?
> 
> Yes, with the DPU. I don't have a bonded panel setup for the mdp5 case.
> 
> For the DPU it doesn't matter since we have just one encoder ->
> bridges(+panel) -> connector chain. Thus the panel
> I think it is not the case for MDP5, where there are two encoders, two
> connectors, but the single panel.
> 

You are right.

For DPU, it works today because we have protection in 
_dpu_kms_initialize_dsi() to not call msm_dsi_modeset_init() so only one 
bridge gets created. So the bridge's pre_enable/enable/disable calls 
should happen only once for the master.


560 	for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) {
561 		int other = (i + 1) % 2;
562
563 		if (!priv->dsi[i])
564 			continue;
565
566 		if (msm_dsi_is_bonded_dsi(priv->dsi[i]) &&
567 		    !msm_dsi_is_master_dsi(priv->dsi[i]))
568 			continue;


Actually, looking closely at msm_dsi_modeset_init() it already has 
protection to skip the msm_dsi_manager_bridge_init(msm_dsi->id); for 
slave dsi.

238 	if (msm_dsi_is_bonded_dsi(msm_dsi) &&
239 	    !msm_dsi_is_master_dsi(msm_dsi)) {
240 		/*
241 		 * Do not return an eror here,
242 		 * Just skip creating encoder/connector for the slave-DSI.
243 		 */
244 		return 0;
245 	}

So we can actually get rid of the above duplicated code in 
_dpu_kms_initialize_dsi().

Based on this, i do think that because of this protection it should 
still work even on mdp5.

But we can just cleanup the above code.

> Frankly speaking I'm not sure how/if this worked and whether it was
> tested at all since 2015. Maybe we should step back and check this. Do
> you know any available MDP5 device which uses bonded DSI?

Unfortunately no, i am not aware of which mdp5 device you can test this on.

But based on above analysis, i think it should still work.
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-12 19:15       ` [Freedreno] " Abhinav Kumar
@ 2022-07-12 20:10         ` Dmitry Baryshkov
  2022-07-12 21:21           ` Abhinav Kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-07-12 20:10 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Thomas Zimmermann, Sam Ravnborg, David Airlie, freedreno,
	Stephen Boyd, Thierry Reding, dri-devel, linux-arm-msm,
	Bjorn Andersson, Sean Paul

On Tue, 12 Jul 2022 at 22:15, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>
>
>
> On 7/12/2022 3:00 AM, Dmitry Baryshkov wrote:
> > On Tue, 12 Jul 2022 at 01:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
> >>
> >>
> >>
> >> On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
> >>> Currently the DSI driver has two separate paths: one if the next device
> >>> in a chain is a bridge and another one if the panel is connected
> >>> directly to the DSI host. Simplify the code path by using panel-bridge
> >>> driver (already selected in Kconfig) and dropping support for
> >>> handling the panel directly.
> >>>
> >>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >>> ---
> >>>    drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
> >>>    drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
> >>>    drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
> >>>    drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
> >>>    4 files changed, 26 insertions(+), 315 deletions(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
> >>> index 1625328fa430..3c53e28092db 100644
> >>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
> >>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> >>> @@ -6,14 +6,6 @@
> >>>    #include "dsi.h"
> >>>    #include "dsi_cfg.h"
> >>>
> >>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
> >>> -{
> >>> -     if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
> >>> -             return NULL;
> >>> -
> >>> -     return msm_dsi->encoder;
> >>> -}
> >>
> >> panel_bridge doesnt have the best_encoder method today.
> >> Today, this does not break anything for us.
> >> But, for future if we do need it, panel_bridge needs to be expanded to
> >> add that method?
> >
> > We have a 1:1 between encoder and connector, so
> > drm_connector_get_single_encoder() works well in our case.
> >
> like I said before, today this should be fine.
> If we do come up with a use-case in future to have the best_encoder()
> panel_bridge will need to be expanded. So this is more of a comment to
> keep in mind but no change needed for this.

Do you think we can end up with a DSI encoder being handled by
multiple connectors?

>
> >>
> >>> -
> >>>    bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
> >>>    {
> >>>        unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
> >>> @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
> >>>                         struct drm_encoder *encoder)
> >>>    {
> >>>        struct msm_drm_private *priv;
> >>> -     struct drm_bridge *ext_bridge;
> >>> +     struct drm_connector *connector;
> >>>        int ret;
> >>>
> >>>        if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
> >>> @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
> >>>                goto fail;
> >>>        }
> >>>
> >>> -     /*
> >>> -      * 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);
> >>> +     connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
> >>> +
> >>> +     if (IS_ERR(connector)) {
> >>> +             ret = PTR_ERR(connector);
> >>>                DRM_DEV_ERROR(dev->dev,
> >>>                        "failed to create dsi connector: %d\n", ret);
> >>> -             msm_dsi->connector = NULL;
> >>>                goto fail;
> >>>        }
> >>>
> >>> @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
> >>>                msm_dsi->bridge = NULL;
> >>>        }
> >>>
> >>> -     /* 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;
> >>> -
> >>>        return ret;
> >>>    }
> >>>
> >>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> >>> index 580a1e6358bf..41630b8f5358 100644
> >>> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> >>> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> >>> @@ -12,7 +12,6 @@
> >>>    #include <drm/drm_bridge.h>
> >>>    #include <drm/drm_crtc.h>
> >>>    #include <drm/drm_mipi_dsi.h>
> >>> -#include <drm/drm_panel.h>
> >>>
> >>>    #include "msm_drv.h"
> >>>    #include "disp/msm_disp_snapshot.h"
> >>> @@ -49,8 +48,6 @@ 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;
> >>>
> >>> @@ -58,10 +55,8 @@ struct msm_dsi {
> >>>        struct msm_dsi_phy *phy;
> >>>
> >>>        /*
> >>> -      * panel/external_bridge connected to dsi bridge output, only one of the
> >>> -      * two can be valid at a time
> >>> +      * external_bridge connected to dsi bridge output
> >>>         */
> >>> -     struct drm_panel *panel;
> >>>        struct drm_bridge *external_bridge;
> >>>
> >>>        struct device *phy_dev;
> >>> @@ -76,7 +71,6 @@ struct msm_dsi {
> >>>    /* dsi manager */
> >>>    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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
> >>>    bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
> >>> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
> >>>    /* msm dsi */
> >>>    static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
> >>>    {
> >>> -     return msm_dsi->panel || msm_dsi->external_bridge;
> >>> +     return msm_dsi->external_bridge;
> >>>    }
> >>>
> >>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
> >>> -
> >>>    /* dsi host */
> >>>    struct msm_dsi_host;
> >>>    int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
> >>> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
> >>>                                  const struct drm_display_mode *mode);
> >>>    enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
> >>>                                            const struct drm_display_mode *mode);
> >>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
> >>>    unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
> >>> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
> >>>    int msm_dsi_host_register(struct mipi_dsi_host *host);
> >>>    void msm_dsi_host_unregister(struct mipi_dsi_host *host);
> >>>    void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
> >>> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> >>> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> >>> @@ -164,7 +164,6 @@ struct msm_dsi_host {
> >>>        struct msm_display_dsc_config *dsc;
> >>>
> >>>        /* connected device info */
> >>> -     struct device_node *device_node;
> >>>        unsigned int channel;
> >>>        unsigned int lanes;
> >>>        enum mipi_dsi_pixel_format format;
> >>> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
> >>>
> >>>        dsi_dev_detach(msm_host->pdev);
> >>>
> >>> -     msm_host->device_node = NULL;
> >>> -
> >>>        DBG("id=%d", msm_host->id);
> >>>        if (msm_host->dev)
> >>>                queue_work(msm_host->workqueue, &msm_host->hpd_work);
> >>> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
> >>>                goto err;
> >>>        }
> >>>
> >>> -     /* Get panel node from the output port's endpoint data */
> >>> -     device_node = of_graph_get_remote_node(np, 1, 0);
> >>> -     if (!device_node) {
> >>> -             DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
> >>> -             ret = -ENODEV;
> >>> -             goto err;
> >>> -     }
> >>> -
> >>> -     msm_host->device_node = device_node;
> >>> -
> >>>        if (of_property_read_bool(np, "syscon-sfpb")) {
> >>>                msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
> >>>                                        "syscon-sfpb");
> >>> @@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
> >>>        return MODE_OK;
> >>>    }
> >>>
> >>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
> >>> -{
> >>> -     return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
> >>> -}
> >>> -
> >>>    unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
> >>>    {
> >>>        return to_msm_dsi_host(host)->mode_flags;
> >>>    }
> >>>
> >>> -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);
> >>> -}
> >>> -
> >>>    void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
> >>>    {
> >>>        struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> >>> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> >>> index cb84d185d73a..3970368e07d5 100644
> >>> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> >>> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> >>> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
> >>>        }
> >>>    }
> >>>
> >>> -struct dsi_connector {
> >>> -     struct drm_connector base;
> >>> -     int id;
> >>> -};
> >>> -
> >>>    struct dsi_bridge {
> >>>        struct drm_bridge base;
> >>>        int id;
> >>>    };
> >>>
> >>> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
> >>>    #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
> >>>
> >>> -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
> >>> -{
> >>> -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> >>> -     return dsi_connector->id;
> >>> -}
> >>> -
> >>>    static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
> >>>    {
> >>>        struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
> >>>        return dsi_bridge->id;
> >>>    }
> >>>
> >>> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> >>> +static void msm_dsi_manager_set_split_display(u8 id)
> >>>    {
> >>> -     struct msm_drm_private *priv = conn->dev->dev_private;
> >>> -     struct msm_kms *kms = priv->kms;
> >>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>>        struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
> >>> +     struct msm_drm_private *priv = msm_dsi->dev->dev_private;
> >>> +     struct msm_kms *kms = priv->kms;
> >>>        struct msm_dsi *master_dsi, *slave_dsi;
> >>> -     struct drm_panel *panel;
> >>>
> >>>        if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
> >>>                master_dsi = other_dsi;
> >>> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> >>>                slave_dsi = other_dsi;
> >>>        }
> >>>
> >>> -     /*
> >>> -      * There is only 1 panel in the global panel list for bonded DSI mode.
> >>> -      * Therefore slave dsi should get the drm_panel instance from master
> >>> -      * dsi.
> >>> -      */
> >>> -     panel = msm_dsi_host_get_panel(master_dsi->host);
> >>> -     if (IS_ERR(panel)) {
> >>> -             DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
> >>> -                       PTR_ERR(panel));
> >>> -             return PTR_ERR(panel);
> >>> -     }
> >>> -
> >>> -     if (!panel || !IS_BONDED_DSI())
> >>> -             goto out;
> >>> -
> >>> -     drm_object_attach_property(&conn->base,
> >>> -                                conn->dev->mode_config.tile_property, 0);
> >>> +     if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
> >>> +             return;
> >>>
> >>>        /*
> >>>         * Set split display info to kms once bonded DSI panel is connected to
> >>>         * both hosts.
> >>>         */
> >>> -     if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
> >>> +     if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
> >>>                kms->funcs->set_split_display(kms, master_dsi->encoder,
> >>>                                              slave_dsi->encoder,
> >>>                                              msm_dsi_is_cmd_mode(msm_dsi));
> >>>        }
> >>> -
> >>> -out:
> >>> -     msm_dsi->panel = panel;
> >>> -     return 0;
> >>> -}
> >>> -
> >>> -static enum drm_connector_status dsi_mgr_connector_detect(
> >>> -             struct drm_connector *connector, bool force)
> >>> -{
> >>> -     int id = dsi_mgr_connector_get_id(connector);
> >>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>> -
> >>> -     return msm_dsi->panel ? connector_status_connected :
> >>> -             connector_status_disconnected;
> >>> -}
> >>> -
> >>> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
> >>> -{
> >>> -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> >>> -
> >>> -     DBG("");
> >>> -
> >>> -     drm_connector_cleanup(connector);
> >>> -
> >>> -     kfree(dsi_connector);
> >>> -}
> >>> -
> >>> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
> >>> -{
> >>> -     int id = dsi_mgr_connector_get_id(connector);
> >>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>> -     struct drm_panel *panel = msm_dsi->panel;
> >>> -     int num;
> >>> -
> >>> -     if (!panel)
> >>> -             return 0;
> >>> -
> >>> -     /*
> >>> -      * In bonded DSI mode, we have one connector that can be
> >>> -      * attached to the drm_panel.
> >>> -      */
> >>> -     num = drm_panel_get_modes(panel, connector);
> >>> -     if (!num)
> >>> -             return 0;
> >>> -
> >>> -     return num;
> >>> -}
> >>> -
> >>> -static struct drm_encoder *
> >>> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
> >>> -{
> >>> -     int id = dsi_mgr_connector_get_id(connector);
> >>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>> -
> >>> -     DBG("");
> >>> -     return msm_dsi_get_encoder(msm_dsi);
> >>>    }
> >>>
> >>>    static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
> >>> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
> >>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>>        struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
> >>>        struct mipi_dsi_host *host = msm_dsi->host;
> >>> -     struct drm_panel *panel = msm_dsi->panel;
> >>>        bool is_bonded_dsi = IS_BONDED_DSI();
> >>>        int ret;
> >>>
> >>> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
> >>>        if (!dsi_mgr_power_on_early(bridge))
> >>>                dsi_mgr_bridge_power_on(bridge);
> >>>
> >>> -     /* Always call panel functions once, because even for dual panels,
> >>> -      * there is only one drm_panel instance.
> >>> -      */
> >>> -     if (panel) {
> >>> -             ret = drm_panel_prepare(panel);
> >>> -             if (ret) {
> >>> -                     pr_err("%s: prepare panel %d failed, %d\n", __func__,
> >>> -                                                             id, ret);
> >>> -                     goto panel_prep_fail;
> >>> -             }
> >>> -     }
> >>> -
> >>>        ret = msm_dsi_host_enable(host);
> >>>        if (ret) {
> >>>                pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
> >>> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
> >>>    host1_en_fail:
> >>>        msm_dsi_host_disable(host);
> >>>    host_en_fail:
> >>> -     if (panel)
> >>> -             drm_panel_unprepare(panel);
> >>> -panel_prep_fail:
> >>>
> >>>        return;
> >>>    }
> >>> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
> >>>        }
> >>>    }
> >>>
> >>> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
> >>> -{
> >>> -     int id = dsi_mgr_bridge_get_id(bridge);
> >>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>> -     struct drm_panel *panel = msm_dsi->panel;
> >>> -     bool is_bonded_dsi = IS_BONDED_DSI();
> >>> -     int ret;
> >>> -
> >>> -     DBG("id=%d", id);
> >>> -     if (!msm_dsi_device_connected(msm_dsi))
> >>> -             return;
> >>> -
> >>> -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> >>> -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> >>> -             return;
> >>> -
> >>> -     if (panel) {
> >>> -             ret = drm_panel_enable(panel);
> >>> -             if (ret) {
> >>> -                     pr_err("%s: enable panel %d failed, %d\n", __func__, id,
> >>> -                                                                     ret);
> >>> -             }
> >>> -     }
> >>> -}
> >>> -
> >>> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
> >>> -{
> >>> -     int id = dsi_mgr_bridge_get_id(bridge);
> >>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>> -     struct drm_panel *panel = msm_dsi->panel;
> >>> -     bool is_bonded_dsi = IS_BONDED_DSI();
> >>> -     int ret;
> >>> -
> >>> -     DBG("id=%d", id);
> >>> -     if (!msm_dsi_device_connected(msm_dsi))
> >>> -             return;
> >>> -
> >>> -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> >>> -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> >>> -             return;
> >>> -
> >>> -     if (panel) {
> >>> -             ret = drm_panel_disable(panel);
> >>> -             if (ret)
> >>> -                     pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
> >>> -                                                                     ret);
> >>> -     }
> >>> -}
> >>> -
> >>>    static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
> >>>    {
> >>>        int id = dsi_mgr_bridge_get_id(bridge);
> >>>        struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> >>>        struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
> >>>        struct mipi_dsi_host *host = msm_dsi->host;
> >>> -     struct drm_panel *panel = msm_dsi->panel;
> >>>        bool is_bonded_dsi = IS_BONDED_DSI();
> >>>        int ret;
> >>>
> >>> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
> >>>                        pr_err("%s: host1 disable failed, %d\n", __func__, ret);
> >>>        }
> >>>
> >>> -     if (panel) {
> >>> -             ret = drm_panel_unprepare(panel);
> >>> -             if (ret)
> >>> -                     pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
> >>> -                                                             id, ret);
> >>> -     }
> >>> -
> >>>        msm_dsi_host_disable_irq(host);
> >>>        if (is_bonded_dsi && msm_dsi1)
> >>>                msm_dsi_host_disable_irq(msm_dsi1->host);
> >>> @@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
> >>>        return msm_dsi_host_check_dsc(host, mode);
> >>>    }
> >>>
> >>> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
> >>> -     .detect = dsi_mgr_connector_detect,
> >>> -     .fill_modes = drm_helper_probe_single_connector_modes,
> >>> -     .destroy = dsi_mgr_connector_destroy,
> >>> -     .reset = drm_atomic_helper_connector_reset,
> >>> -     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> >>> -     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >>> -};
> >>> -
> >>> -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
> >>> -     .get_modes = dsi_mgr_connector_get_modes,
> >>> -     .best_encoder = dsi_mgr_connector_best_encoder,
> >>> -};
> >>> -
> >>>    static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
> >>>        .pre_enable = dsi_mgr_bridge_pre_enable,
> >>> -     .enable = dsi_mgr_bridge_enable,
> >>> -     .disable = dsi_mgr_bridge_disable,
> >>>        .post_disable = dsi_mgr_bridge_post_disable,
> >>>        .mode_set = dsi_mgr_bridge_mode_set,
> >>>        .mode_valid = dsi_mgr_bridge_mode_valid,
> >>>    };
> >>>
> >>> -/* 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);
> >>> -     struct drm_connector *connector = NULL;
> >>> -     struct dsi_connector *dsi_connector;
> >>> -     int ret;
> >>> -
> >>> -     dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
> >>> -     if (!dsi_connector)
> >>> -             return ERR_PTR(-ENOMEM);
> >>> -
> >>> -     dsi_connector->id = id;
> >>> -
> >>> -     connector = &dsi_connector->base;
> >>> -
> >>> -     ret = drm_connector_init(msm_dsi->dev, connector,
> >>> -                     &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
> >>> -     if (ret)
> >>> -             return ERR_PTR(ret);
> >>> -
> >>> -     drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
> >>> -
> >>> -     /* Enable HPD to let hpd event is handled
> >>> -      * when panel is attached to the host.
> >>> -      */
> >>> -     connector->polled = DRM_CONNECTOR_POLL_HPD;
> >>
> >> I see that this part gets removed with this migration.
> >>
> >> For fixed/built-in displays, it should not matter i think but i am not
> >> sure if some usermodes might expect this even for DSI?
> >>
> >> So, once again does panel_bridge needs to account for this?
> >
> > Panel bridge sets only DRM_BRIDGE_OP_MODES. If you check the existing
> > code, the dsi_mgr_connector also does not provide HPD support. It only
> > can return panel status depending on whether the drm_panel was fetched
> > or not. No events are generated ever.
> > Thus said I think we should stop hijacking the usual mechanisms. If we
> > do not do the HPD, let's not declare it. If there is a case of panel
> > being hotplugged or switched, it will be handled by the next bridge in
> > the chain, not by the MSM DSI code.
> >
> hot plug events are sent today.
>
>
> static void dsi_hpd_worker(struct work_struct *work)
> {
>      struct msm_dsi_host *msm_host =
>          container_of(work, struct msm_dsi_host, hpd_work);
>
>      drm_helper_hpd_irq_event(msm_host->dev);
> }
>
> If you are planning to drop DRM_CONNECTOR_POLL_HPD, then you should
> remove all this code as well because its just dead code otherwise.

This is scheduled at dsi_host_attach() / dsi_host_detach(), so it's
not a dead code.

We can probably inline the dsi_hpd_worker, but it's a separate change.

> I agree, the hot plug handling can be done by the next bridge in the chain.
>
> Then lets cleanup this code too.
>
> >>
> >>
> >>> -
> >>> -     /* Display driver doesn't support interlace now. */
> >>> -     connector->interlace_allowed = 0;
> >>> -     connector->doublescan_allowed = 0;
> >>> -
> >>> -     drm_connector_attach_encoder(connector, msm_dsi->encoder);
> >>> -
> >>> -     ret = msm_dsi_manager_panel_init(connector, id);
> >>> -     if (ret) {
> >>> -             DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
> >>> -             goto fail;
> >>> -     }
> >>> -
> >>> -     return connector;
> >>> -
> >>> -fail:
> >>> -     connector->funcs->destroy(connector);
> >>> -     return ERR_PTR(ret);
> >>> -}
> >>> -
> >>>    /* initialize bridge */
> >>>    struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> >>>    {
> >>> @@ -732,8 +512,11 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> >>>        int ret;
> >>>
> >>>        int_bridge = msm_dsi->bridge;
> >>> -     ext_bridge = msm_dsi->external_bridge =
> >>> -                     msm_dsi_host_get_bridge(msm_dsi->host);
> >>> +     ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, msm_dsi->pdev->dev.of_node, 1, 0);
> >>> +     if (IS_ERR(ext_bridge))
> >>> +             return ERR_CAST(ext_bridge);
> >>> +
> >>> +     msm_dsi->external_bridge = ext_bridge;
> >>>
> >>>        encoder = msm_dsi->encoder;
> >>>
> >>> @@ -745,25 +528,12 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> >>>        ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
> >>>                        DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> >>>        if (ret == -EINVAL) {
> >>> -             struct drm_connector *connector;
> >>> -             struct list_head *connector_list;
> >>> -
> >>>                /* link the internal dsi bridge to the external bridge */
> >>> -             drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> >>> +             ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> >>> +             if (ret < 0)
> >>> +                     return ERR_PTR(ret);
> >>>
> >>> -             /*
> >>> -              * 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) {
> >>> -                     if (drm_connector_has_possible_encoder(connector, encoder))
> >>> -                             return connector;
> >>> -             }
> >>> -
> >>> -             return ERR_PTR(-ENODEV);
> >>> +             goto out;
> >>>        }
> >>>
> >>>        connector = drm_bridge_connector_init(dev, encoder);
> >>> @@ -774,6 +544,10 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> >>>
> >>>        drm_connector_attach_encoder(connector, encoder);
> >>>
> >>> +out:
> >>> +     /* The pipeline is ready, ping encoders if necessary */
> >>> +     msm_dsi_manager_set_split_display(id);
> >> Do you still want to execute msm_dsi_manager_set_split_display even for
> >> the error case? Like in the above lines you have replaced the return
> >> ERR_PTR() with the goto out. But do you want to then move the
> >> set_split_display() call above the out label?
> >
> > You see, the return ERR_PTR was the error case, where we could not
> > find the connector corresponding to the encoder.
> > We just don't need it anymore. Let's change the function to return int
> > rather than the unused connector.
> >
> >>
> >> Also, now for the cases where there was an error where the connector was
> >> not found, we will return a NULL ptr instead of the ERR_PTR(-ENODEV).
> >> Is that expected?
> >
> > Yes. We just do not care anymore about this connector.
> >
>
> My question was do you want to skip even
> msm_dsi_manager_set_split_display(id) by moving it above the out label.

No. The 'out' was a path around creating our own DSI connector. I've
refactored this piece of code in v2.5. Maybe it would be more obvious
now.


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-12 20:10         ` Dmitry Baryshkov
@ 2022-07-12 21:21           ` Abhinav Kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-12 21:21 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Sean Paul, David Airlie, Sam Ravnborg, dri-devel, Stephen Boyd,
	Thierry Reding, Thomas Zimmermann, linux-arm-msm,
	Bjorn Andersson, freedreno



On 7/12/2022 1:10 PM, Dmitry Baryshkov wrote:
> On Tue, 12 Jul 2022 at 22:15, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>
>>
>>
>> On 7/12/2022 3:00 AM, Dmitry Baryshkov wrote:
>>> On Tue, 12 Jul 2022 at 01:39, Abhinav Kumar <quic_abhinavk@quicinc.com> wrote:
>>>>
>>>>
>>>>
>>>> On 7/11/2022 2:43 AM, Dmitry Baryshkov wrote:
>>>>> Currently the DSI driver has two separate paths: one if the next device
>>>>> in a chain is a bridge and another one if the panel is connected
>>>>> directly to the DSI host. Simplify the code path by using panel-bridge
>>>>> driver (already selected in Kconfig) and dropping support for
>>>>> handling the panel directly.
>>>>>
>>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>>> ---
>>>>>     drivers/gpu/drm/msm/dsi/dsi.c         |  38 +---
>>>>>     drivers/gpu/drm/msm/dsi/dsi.h         |  14 +-
>>>>>     drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>>>>     drivers/gpu/drm/msm/dsi/dsi_manager.c | 264 ++------------------------
>>>>>     4 files changed, 26 insertions(+), 315 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
>>>>> index 1625328fa430..3c53e28092db 100644
>>>>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
>>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
>>>>> @@ -6,14 +6,6 @@
>>>>>     #include "dsi.h"
>>>>>     #include "dsi_cfg.h"
>>>>>
>>>>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
>>>>> -{
>>>>> -     if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
>>>>> -             return NULL;
>>>>> -
>>>>> -     return msm_dsi->encoder;
>>>>> -}
>>>>
>>>> panel_bridge doesnt have the best_encoder method today.
>>>> Today, this does not break anything for us.
>>>> But, for future if we do need it, panel_bridge needs to be expanded to
>>>> add that method?
>>>
>>> We have a 1:1 between encoder and connector, so
>>> drm_connector_get_single_encoder() works well in our case.
>>>
>> like I said before, today this should be fine.
>> If we do come up with a use-case in future to have the best_encoder()
>> panel_bridge will need to be expanded. So this is more of a comment to
>> keep in mind but no change needed for this.
> 
> Do you think we can end up with a DSI encoder being handled by
> multiple connectors?

No, i dont foresee such a case.

Even if we enable ping-pong split in the future that will still have 
only one connector.

> 
>>
>>>>
>>>>> -
>>>>>     bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>>>>>     {
>>>>>         unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
>>>>> @@ -220,7 +212,7 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>>>>>                          struct drm_encoder *encoder)
>>>>>     {
>>>>>         struct msm_drm_private *priv;
>>>>> -     struct drm_bridge *ext_bridge;
>>>>> +     struct drm_connector *connector;
>>>>>         int ret;
>>>>>
>>>>>         if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
>>>>> @@ -254,26 +246,12 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>>>>>                 goto fail;
>>>>>         }
>>>>>
>>>>> -     /*
>>>>> -      * 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);
>>>>> +     connector = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
>>>>> +
>>>>> +     if (IS_ERR(connector)) {
>>>>> +             ret = PTR_ERR(connector);
>>>>>                 DRM_DEV_ERROR(dev->dev,
>>>>>                         "failed to create dsi connector: %d\n", ret);
>>>>> -             msm_dsi->connector = NULL;
>>>>>                 goto fail;
>>>>>         }
>>>>>
>>>>> @@ -287,12 +265,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>>>>>                 msm_dsi->bridge = NULL;
>>>>>         }
>>>>>
>>>>> -     /* 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;
>>>>> -
>>>>>         return ret;
>>>>>     }
>>>>>
>>>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
>>>>> index 580a1e6358bf..41630b8f5358 100644
>>>>> --- a/drivers/gpu/drm/msm/dsi/dsi.h
>>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
>>>>> @@ -12,7 +12,6 @@
>>>>>     #include <drm/drm_bridge.h>
>>>>>     #include <drm/drm_crtc.h>
>>>>>     #include <drm/drm_mipi_dsi.h>
>>>>> -#include <drm/drm_panel.h>
>>>>>
>>>>>     #include "msm_drv.h"
>>>>>     #include "disp/msm_disp_snapshot.h"
>>>>> @@ -49,8 +48,6 @@ 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;
>>>>>
>>>>> @@ -58,10 +55,8 @@ struct msm_dsi {
>>>>>         struct msm_dsi_phy *phy;
>>>>>
>>>>>         /*
>>>>> -      * panel/external_bridge connected to dsi bridge output, only one of the
>>>>> -      * two can be valid at a time
>>>>> +      * external_bridge connected to dsi bridge output
>>>>>          */
>>>>> -     struct drm_panel *panel;
>>>>>         struct drm_bridge *external_bridge;
>>>>>
>>>>>         struct device *phy_dev;
>>>>> @@ -76,7 +71,6 @@ struct msm_dsi {
>>>>>     /* dsi manager */
>>>>>     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_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>>>>>     bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
>>>>> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>>>>>     /* msm dsi */
>>>>>     static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>>>>>     {
>>>>> -     return msm_dsi->panel || msm_dsi->external_bridge;
>>>>> +     return msm_dsi->external_bridge;
>>>>>     }
>>>>>
>>>>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
>>>>> -
>>>>>     /* dsi host */
>>>>>     struct msm_dsi_host;
>>>>>     int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
>>>>> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
>>>>>                                   const struct drm_display_mode *mode);
>>>>>     enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>>>>                                             const struct drm_display_mode *mode);
>>>>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>>>>>     unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
>>>>> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>>>>>     int msm_dsi_host_register(struct mipi_dsi_host *host);
>>>>>     void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>>>>>     void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
>>>>> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
>>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
>>>>> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>>>>>         struct msm_display_dsc_config *dsc;
>>>>>
>>>>>         /* connected device info */
>>>>> -     struct device_node *device_node;
>>>>>         unsigned int channel;
>>>>>         unsigned int lanes;
>>>>>         enum mipi_dsi_pixel_format format;
>>>>> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
>>>>>
>>>>>         dsi_dev_detach(msm_host->pdev);
>>>>>
>>>>> -     msm_host->device_node = NULL;
>>>>> -
>>>>>         DBG("id=%d", msm_host->id);
>>>>>         if (msm_host->dev)
>>>>>                 queue_work(msm_host->workqueue, &msm_host->hpd_work);
>>>>> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
>>>>>                 goto err;
>>>>>         }
>>>>>
>>>>> -     /* Get panel node from the output port's endpoint data */
>>>>> -     device_node = of_graph_get_remote_node(np, 1, 0);
>>>>> -     if (!device_node) {
>>>>> -             DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
>>>>> -             ret = -ENODEV;
>>>>> -             goto err;
>>>>> -     }
>>>>> -
>>>>> -     msm_host->device_node = device_node;
>>>>> -
>>>>>         if (of_property_read_bool(np, "syscon-sfpb")) {
>>>>>                 msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>>>>>                                         "syscon-sfpb");
>>>>> @@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>>>>         return MODE_OK;
>>>>>     }
>>>>>
>>>>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
>>>>> -{
>>>>> -     return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
>>>>> -}
>>>>> -
>>>>>     unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>>>>>     {
>>>>>         return to_msm_dsi_host(host)->mode_flags;
>>>>>     }
>>>>>
>>>>> -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);
>>>>> -}
>>>>> -
>>>>>     void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
>>>>>     {
>>>>>         struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
>>>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>>>> index cb84d185d73a..3970368e07d5 100644
>>>>> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>>>> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>>>>> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>>>>>         }
>>>>>     }
>>>>>
>>>>> -struct dsi_connector {
>>>>> -     struct drm_connector base;
>>>>> -     int id;
>>>>> -};
>>>>> -
>>>>>     struct dsi_bridge {
>>>>>         struct drm_bridge base;
>>>>>         int id;
>>>>>     };
>>>>>
>>>>> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>>>>>     #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
>>>>>
>>>>> -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
>>>>> -{
>>>>> -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>>>>> -     return dsi_connector->id;
>>>>> -}
>>>>> -
>>>>>     static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>>>>>     {
>>>>>         struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>>>>>         return dsi_bridge->id;
>>>>>     }
>>>>>
>>>>> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>>>>> +static void msm_dsi_manager_set_split_display(u8 id)
>>>>>     {
>>>>> -     struct msm_drm_private *priv = conn->dev->dev_private;
>>>>> -     struct msm_kms *kms = priv->kms;
>>>>>         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>>         struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
>>>>> +     struct msm_drm_private *priv = msm_dsi->dev->dev_private;
>>>>> +     struct msm_kms *kms = priv->kms;
>>>>>         struct msm_dsi *master_dsi, *slave_dsi;
>>>>> -     struct drm_panel *panel;
>>>>>
>>>>>         if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>>>>>                 master_dsi = other_dsi;
>>>>> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>>>>>                 slave_dsi = other_dsi;
>>>>>         }
>>>>>
>>>>> -     /*
>>>>> -      * There is only 1 panel in the global panel list for bonded DSI mode.
>>>>> -      * Therefore slave dsi should get the drm_panel instance from master
>>>>> -      * dsi.
>>>>> -      */
>>>>> -     panel = msm_dsi_host_get_panel(master_dsi->host);
>>>>> -     if (IS_ERR(panel)) {
>>>>> -             DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
>>>>> -                       PTR_ERR(panel));
>>>>> -             return PTR_ERR(panel);
>>>>> -     }
>>>>> -
>>>>> -     if (!panel || !IS_BONDED_DSI())
>>>>> -             goto out;
>>>>> -
>>>>> -     drm_object_attach_property(&conn->base,
>>>>> -                                conn->dev->mode_config.tile_property, 0);
>>>>> +     if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
>>>>> +             return;
>>>>>
>>>>>         /*
>>>>>          * Set split display info to kms once bonded DSI panel is connected to
>>>>>          * both hosts.
>>>>>          */
>>>>> -     if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
>>>>> +     if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
>>>>>                 kms->funcs->set_split_display(kms, master_dsi->encoder,
>>>>>                                               slave_dsi->encoder,
>>>>>                                               msm_dsi_is_cmd_mode(msm_dsi));
>>>>>         }
>>>>> -
>>>>> -out:
>>>>> -     msm_dsi->panel = panel;
>>>>> -     return 0;
>>>>> -}
>>>>> -
>>>>> -static enum drm_connector_status dsi_mgr_connector_detect(
>>>>> -             struct drm_connector *connector, bool force)
>>>>> -{
>>>>> -     int id = dsi_mgr_connector_get_id(connector);
>>>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>> -
>>>>> -     return msm_dsi->panel ? connector_status_connected :
>>>>> -             connector_status_disconnected;
>>>>> -}
>>>>> -
>>>>> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
>>>>> -{
>>>>> -     struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>>>>> -
>>>>> -     DBG("");
>>>>> -
>>>>> -     drm_connector_cleanup(connector);
>>>>> -
>>>>> -     kfree(dsi_connector);
>>>>> -}
>>>>> -
>>>>> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
>>>>> -{
>>>>> -     int id = dsi_mgr_connector_get_id(connector);
>>>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>> -     struct drm_panel *panel = msm_dsi->panel;
>>>>> -     int num;
>>>>> -
>>>>> -     if (!panel)
>>>>> -             return 0;
>>>>> -
>>>>> -     /*
>>>>> -      * In bonded DSI mode, we have one connector that can be
>>>>> -      * attached to the drm_panel.
>>>>> -      */
>>>>> -     num = drm_panel_get_modes(panel, connector);
>>>>> -     if (!num)
>>>>> -             return 0;
>>>>> -
>>>>> -     return num;
>>>>> -}
>>>>> -
>>>>> -static struct drm_encoder *
>>>>> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
>>>>> -{
>>>>> -     int id = dsi_mgr_connector_get_id(connector);
>>>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>> -
>>>>> -     DBG("");
>>>>> -     return msm_dsi_get_encoder(msm_dsi);
>>>>>     }
>>>>>
>>>>>     static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
>>>>> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>>>>>         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>>         struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>>>>         struct mipi_dsi_host *host = msm_dsi->host;
>>>>> -     struct drm_panel *panel = msm_dsi->panel;
>>>>>         bool is_bonded_dsi = IS_BONDED_DSI();
>>>>>         int ret;
>>>>>
>>>>> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>>>>>         if (!dsi_mgr_power_on_early(bridge))
>>>>>                 dsi_mgr_bridge_power_on(bridge);
>>>>>
>>>>> -     /* Always call panel functions once, because even for dual panels,
>>>>> -      * there is only one drm_panel instance.
>>>>> -      */
>>>>> -     if (panel) {
>>>>> -             ret = drm_panel_prepare(panel);
>>>>> -             if (ret) {
>>>>> -                     pr_err("%s: prepare panel %d failed, %d\n", __func__,
>>>>> -                                                             id, ret);
>>>>> -                     goto panel_prep_fail;
>>>>> -             }
>>>>> -     }
>>>>> -
>>>>>         ret = msm_dsi_host_enable(host);
>>>>>         if (ret) {
>>>>>                 pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
>>>>> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>>>>>     host1_en_fail:
>>>>>         msm_dsi_host_disable(host);
>>>>>     host_en_fail:
>>>>> -     if (panel)
>>>>> -             drm_panel_unprepare(panel);
>>>>> -panel_prep_fail:
>>>>>
>>>>>         return;
>>>>>     }
>>>>> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>>>>>         }
>>>>>     }
>>>>>
>>>>> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
>>>>> -{
>>>>> -     int id = dsi_mgr_bridge_get_id(bridge);
>>>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>> -     struct drm_panel *panel = msm_dsi->panel;
>>>>> -     bool is_bonded_dsi = IS_BONDED_DSI();
>>>>> -     int ret;
>>>>> -
>>>>> -     DBG("id=%d", id);
>>>>> -     if (!msm_dsi_device_connected(msm_dsi))
>>>>> -             return;
>>>>> -
>>>>> -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
>>>>> -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>>>>> -             return;
>>>>> -
>>>>> -     if (panel) {
>>>>> -             ret = drm_panel_enable(panel);
>>>>> -             if (ret) {
>>>>> -                     pr_err("%s: enable panel %d failed, %d\n", __func__, id,
>>>>> -                                                                     ret);
>>>>> -             }
>>>>> -     }
>>>>> -}
>>>>> -
>>>>> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
>>>>> -{
>>>>> -     int id = dsi_mgr_bridge_get_id(bridge);
>>>>> -     struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>> -     struct drm_panel *panel = msm_dsi->panel;
>>>>> -     bool is_bonded_dsi = IS_BONDED_DSI();
>>>>> -     int ret;
>>>>> -
>>>>> -     DBG("id=%d", id);
>>>>> -     if (!msm_dsi_device_connected(msm_dsi))
>>>>> -             return;
>>>>> -
>>>>> -     /* Do nothing with the host if it is slave-DSI in case of bonded DSI */
>>>>> -     if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>>>>> -             return;
>>>>> -
>>>>> -     if (panel) {
>>>>> -             ret = drm_panel_disable(panel);
>>>>> -             if (ret)
>>>>> -                     pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
>>>>> -                                                                     ret);
>>>>> -     }
>>>>> -}
>>>>> -
>>>>>     static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>>>>>     {
>>>>>         int id = dsi_mgr_bridge_get_id(bridge);
>>>>>         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>>>>         struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>>>>         struct mipi_dsi_host *host = msm_dsi->host;
>>>>> -     struct drm_panel *panel = msm_dsi->panel;
>>>>>         bool is_bonded_dsi = IS_BONDED_DSI();
>>>>>         int ret;
>>>>>
>>>>> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>>>>>                         pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>>>>>         }
>>>>>
>>>>> -     if (panel) {
>>>>> -             ret = drm_panel_unprepare(panel);
>>>>> -             if (ret)
>>>>> -                     pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
>>>>> -                                                             id, ret);
>>>>> -     }
>>>>> -
>>>>>         msm_dsi_host_disable_irq(host);
>>>>>         if (is_bonded_dsi && msm_dsi1)
>>>>>                 msm_dsi_host_disable_irq(msm_dsi1->host);
>>>>> @@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>>>>>         return msm_dsi_host_check_dsc(host, mode);
>>>>>     }
>>>>>
>>>>> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
>>>>> -     .detect = dsi_mgr_connector_detect,
>>>>> -     .fill_modes = drm_helper_probe_single_connector_modes,
>>>>> -     .destroy = dsi_mgr_connector_destroy,
>>>>> -     .reset = drm_atomic_helper_connector_reset,
>>>>> -     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>>>>> -     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>>>>> -};
>>>>> -
>>>>> -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
>>>>> -     .get_modes = dsi_mgr_connector_get_modes,
>>>>> -     .best_encoder = dsi_mgr_connector_best_encoder,
>>>>> -};
>>>>> -
>>>>>     static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>>>>>         .pre_enable = dsi_mgr_bridge_pre_enable,
>>>>> -     .enable = dsi_mgr_bridge_enable,
>>>>> -     .disable = dsi_mgr_bridge_disable,
>>>>>         .post_disable = dsi_mgr_bridge_post_disable,
>>>>>         .mode_set = dsi_mgr_bridge_mode_set,
>>>>>         .mode_valid = dsi_mgr_bridge_mode_valid,
>>>>>     };
>>>>>
>>>>> -/* 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);
>>>>> -     struct drm_connector *connector = NULL;
>>>>> -     struct dsi_connector *dsi_connector;
>>>>> -     int ret;
>>>>> -
>>>>> -     dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
>>>>> -     if (!dsi_connector)
>>>>> -             return ERR_PTR(-ENOMEM);
>>>>> -
>>>>> -     dsi_connector->id = id;
>>>>> -
>>>>> -     connector = &dsi_connector->base;
>>>>> -
>>>>> -     ret = drm_connector_init(msm_dsi->dev, connector,
>>>>> -                     &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
>>>>> -     if (ret)
>>>>> -             return ERR_PTR(ret);
>>>>> -
>>>>> -     drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
>>>>> -
>>>>> -     /* Enable HPD to let hpd event is handled
>>>>> -      * when panel is attached to the host.
>>>>> -      */
>>>>> -     connector->polled = DRM_CONNECTOR_POLL_HPD;
>>>>
>>>> I see that this part gets removed with this migration.
>>>>
>>>> For fixed/built-in displays, it should not matter i think but i am not
>>>> sure if some usermodes might expect this even for DSI?
>>>>
>>>> So, once again does panel_bridge needs to account for this?
>>>
>>> Panel bridge sets only DRM_BRIDGE_OP_MODES. If you check the existing
>>> code, the dsi_mgr_connector also does not provide HPD support. It only
>>> can return panel status depending on whether the drm_panel was fetched
>>> or not. No events are generated ever.
>>> Thus said I think we should stop hijacking the usual mechanisms. If we
>>> do not do the HPD, let's not declare it. If there is a case of panel
>>> being hotplugged or switched, it will be handled by the next bridge in
>>> the chain, not by the MSM DSI code.
>>>
>> hot plug events are sent today.
>>
>>
>> static void dsi_hpd_worker(struct work_struct *work)
>> {
>>       struct msm_dsi_host *msm_host =
>>           container_of(work, struct msm_dsi_host, hpd_work);
>>
>>       drm_helper_hpd_irq_event(msm_host->dev);
>> }
>>
>> If you are planning to drop DRM_CONNECTOR_POLL_HPD, then you should
>> remove all this code as well because its just dead code otherwise.
> 
> This is scheduled at dsi_host_attach() / dsi_host_detach(), so it's
> not a dead code.
> 

What I mean by dead code is that if you do not set 
DRM_CONNECTOR_POLL_HPD, then no hotplug event is sent today.

https://gitlab.freedesktop.org/drm/msm/-/blob/msm-next/drivers/gpu/drm/drm_probe_helper.c#L941

And if we are not sending hotplug event, why keep this wq and call
drm_helper_hpd_irq_event()?

> We can probably inline the dsi_hpd_worker, but it's a separate change.
> 

>> I agree, the hot plug handling can be done by the next bridge in the chain.
>>
>> Then lets cleanup this code too.
>>
>>>>
>>>>
>>>>> -
>>>>> -     /* Display driver doesn't support interlace now. */
>>>>> -     connector->interlace_allowed = 0;
>>>>> -     connector->doublescan_allowed = 0;
>>>>> -
>>>>> -     drm_connector_attach_encoder(connector, msm_dsi->encoder);
>>>>> -
>>>>> -     ret = msm_dsi_manager_panel_init(connector, id);
>>>>> -     if (ret) {
>>>>> -             DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
>>>>> -             goto fail;
>>>>> -     }
>>>>> -
>>>>> -     return connector;
>>>>> -
>>>>> -fail:
>>>>> -     connector->funcs->destroy(connector);
>>>>> -     return ERR_PTR(ret);
>>>>> -}
>>>>> -
>>>>>     /* initialize bridge */
>>>>>     struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>>>>>     {
>>>>> @@ -732,8 +512,11 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>>>>>         int ret;
>>>>>
>>>>>         int_bridge = msm_dsi->bridge;
>>>>> -     ext_bridge = msm_dsi->external_bridge =
>>>>> -                     msm_dsi_host_get_bridge(msm_dsi->host);
>>>>> +     ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev, msm_dsi->pdev->dev.of_node, 1, 0);
>>>>> +     if (IS_ERR(ext_bridge))
>>>>> +             return ERR_CAST(ext_bridge);
>>>>> +
>>>>> +     msm_dsi->external_bridge = ext_bridge;
>>>>>
>>>>>         encoder = msm_dsi->encoder;
>>>>>
>>>>> @@ -745,25 +528,12 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>>>>>         ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>>>>>                         DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>>>>         if (ret == -EINVAL) {
>>>>> -             struct drm_connector *connector;
>>>>> -             struct list_head *connector_list;
>>>>> -
>>>>>                 /* link the internal dsi bridge to the external bridge */
>>>>> -             drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>>>>> +             ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>>>>> +             if (ret < 0)
>>>>> +                     return ERR_PTR(ret);
>>>>>
>>>>> -             /*
>>>>> -              * 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) {
>>>>> -                     if (drm_connector_has_possible_encoder(connector, encoder))
>>>>> -                             return connector;
>>>>> -             }
>>>>> -
>>>>> -             return ERR_PTR(-ENODEV);
>>>>> +             goto out;
>>>>>         }
>>>>>
>>>>>         connector = drm_bridge_connector_init(dev, encoder);
>>>>> @@ -774,6 +544,10 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>>>>>
>>>>>         drm_connector_attach_encoder(connector, encoder);
>>>>>
>>>>> +out:
>>>>> +     /* The pipeline is ready, ping encoders if necessary */
>>>>> +     msm_dsi_manager_set_split_display(id);
>>>> Do you still want to execute msm_dsi_manager_set_split_display even for
>>>> the error case? Like in the above lines you have replaced the return
>>>> ERR_PTR() with the goto out. But do you want to then move the
>>>> set_split_display() call above the out label?
>>>
>>> You see, the return ERR_PTR was the error case, where we could not
>>> find the connector corresponding to the encoder.
>>> We just don't need it anymore. Let's change the function to return int
>>> rather than the unused connector.
>>>
>>>>
>>>> Also, now for the cases where there was an error where the connector was
>>>> not found, we will return a NULL ptr instead of the ERR_PTR(-ENODEV).
>>>> Is that expected?
>>>
>>> Yes. We just do not care anymore about this connector.
>>>
>>
>> My question was do you want to skip even
>> msm_dsi_manager_set_split_display(id) by moving it above the out label.
> 
> No. The 'out' was a path around creating our own DSI connector. I've
> refactored this piece of code in v2.5. Maybe it would be more obvious
> now.

Ok, let me review v2.5 for this part.

> 
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-12 13:22     ` [PATCH v2.5] " Dmitry Baryshkov
@ 2022-07-14 21:54       ` Abhinav Kumar
  2022-08-22 17:53         ` Dmitry Baryshkov
  2022-11-11 15:30       ` Caleb Connolly
  1 sibling, 1 reply; 25+ messages in thread
From: Abhinav Kumar @ 2022-07-14 21:54 UTC (permalink / raw)
  To: Dmitry Baryshkov, Rob Clark, Sean Paul
  Cc: David Airlie, linux-arm-msm, dri-devel, Stephen Boyd,
	Bjorn Andersson, freedreno



On 7/12/2022 6:22 AM, Dmitry Baryshkov wrote:
> Currently the DSI driver has two separate paths: one if the next device
> in a chain is a bridge and another one if the panel is connected
> directly to the DSI host. Simplify the code path by using panel-bridge
> driver (already selected in Kconfig) and dropping support for
> handling the panel directly.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> 
> I'm not sending this as a separate patchset (I'd like to sort out mdp5
> first), but more of a preview of changes related to
> msm_dsi_manager_ext_bridge_init().
> 
> ---
>   drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
>   drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
>   4 files changed, 36 insertions(+), 323 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
> index 1625328fa430..4edb9167e600 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> @@ -6,14 +6,6 @@
>   #include "dsi.h"
>   #include "dsi_cfg.h"
>   
> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
> -{
> -	if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
> -		return NULL;
> -
> -	return msm_dsi->encoder;
> -}
> -
>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>   {
>   	unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
> @@ -220,7 +212,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   			 struct drm_encoder *encoder)
>   {
>   	struct msm_drm_private *priv;
> -	struct drm_bridge *ext_bridge;
>   	int ret;
>   
>   	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
> @@ -254,26 +245,10 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   		goto fail;
>   	}
>   
> -	/*
> -	 * 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);
> +	ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
> +	if (ret) {
>   		DRM_DEV_ERROR(dev->dev,
>   			"failed to create dsi connector: %d\n", ret);
> -		msm_dsi->connector = NULL;
>   		goto fail;
>   	}
>   
> @@ -287,12 +262,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   		msm_dsi->bridge = NULL;
>   	}
>   
> -	/* 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;

 From what i can see all the usages of msm_dsi->connector are removed 
after this change. So can we drop that?

> -
>   	return ret;
>   }
>   
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> index 580a1e6358bf..703e4c88d7fb 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> @@ -12,7 +12,6 @@
>   #include <drm/drm_bridge.h>
>   #include <drm/drm_crtc.h>
>   #include <drm/drm_mipi_dsi.h>
> -#include <drm/drm_panel.h>
>   
>   #include "msm_drv.h"
>   #include "disp/msm_disp_snapshot.h"
> @@ -49,8 +48,6 @@ 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;
>   
> @@ -58,10 +55,8 @@ struct msm_dsi {
>   	struct msm_dsi_phy *phy;
>   
>   	/*
> -	 * panel/external_bridge connected to dsi bridge output, only one of the
> -	 * two can be valid at a time
> +	 * external_bridge connected to dsi bridge output
>   	 */
> -	struct drm_panel *panel;
>   	struct drm_bridge *external_bridge;
>   
>   	struct device *phy_dev;
> @@ -76,8 +71,7 @@ struct msm_dsi {
>   /* dsi manager */
>   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_ext_bridge_init(u8 id);
>   int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>   bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
>   int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>   /* msm dsi */
>   static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>   {
> -	return msm_dsi->panel || msm_dsi->external_bridge;
> +	return msm_dsi->external_bridge;
>   }
>   
> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
> -
>   /* dsi host */
>   struct msm_dsi_host;
>   int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
>   				  const struct drm_display_mode *mode);
>   enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>   					    const struct drm_display_mode *mode);
> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>   int msm_dsi_host_register(struct mipi_dsi_host *host);
>   void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>   void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>   	struct msm_display_dsc_config *dsc;
>   
>   	/* connected device info */
> -	struct device_node *device_node;
>   	unsigned int channel;
>   	unsigned int lanes;
>   	enum mipi_dsi_pixel_format format;
> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
>   
>   	dsi_dev_detach(msm_host->pdev);
>   
> -	msm_host->device_node = NULL;
> -
>   	DBG("id=%d", msm_host->id);
>   	if (msm_host->dev)
>   		queue_work(msm_host->workqueue, &msm_host->hpd_work);
> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
>   		goto err;
>   	}
>   
> -	/* Get panel node from the output port's endpoint data */
> -	device_node = of_graph_get_remote_node(np, 1, 0);
> -	if (!device_node) {
> -		DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
> -		ret = -ENODEV;
> -		goto err;
> -	}
> -
> -	msm_host->device_node = device_node;
> -
>   	if (of_property_read_bool(np, "syscon-sfpb")) {
>   		msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>   					"syscon-sfpb");
> @@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>   	return MODE_OK;
>   }
>   
> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
> -{
> -	return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
> -}
> -
>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>   {
>   	return to_msm_dsi_host(host)->mode_flags;
>   }
>   
> -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);
> -}
> -
>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
>   {
>   	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index cb84d185d73a..546e0b873558 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>   	}
>   }
>   
> -struct dsi_connector {
> -	struct drm_connector base;
> -	int id;
> -};
> -
>   struct dsi_bridge {
>   	struct drm_bridge base;
>   	int id;
>   };
>   
> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>   #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
>   
> -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
> -{
> -	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> -	return dsi_connector->id;
> -}
> -
>   static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>   {
>   	struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>   	return dsi_bridge->id;
>   }
>   
> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> +static void msm_dsi_manager_set_split_display(u8 id)
>   {
> -	struct msm_drm_private *priv = conn->dev->dev_private;
> -	struct msm_kms *kms = priv->kms;
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
> +	struct msm_drm_private *priv = msm_dsi->dev->dev_private;
> +	struct msm_kms *kms = priv->kms;
>   	struct msm_dsi *master_dsi, *slave_dsi;
> -	struct drm_panel *panel;
>   
>   	if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>   		master_dsi = other_dsi;
> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>   		slave_dsi = other_dsi;
>   	}
>   
> -	/*
> -	 * There is only 1 panel in the global panel list for bonded DSI mode.
> -	 * Therefore slave dsi should get the drm_panel instance from master
> -	 * dsi.
> -	 */
> -	panel = msm_dsi_host_get_panel(master_dsi->host);
> -	if (IS_ERR(panel)) {
> -		DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
> -			  PTR_ERR(panel));
> -		return PTR_ERR(panel);
> -	}
> -
> -	if (!panel || !IS_BONDED_DSI())
> -		goto out;
> -
> -	drm_object_attach_property(&conn->base,
> -				   conn->dev->mode_config.tile_property, 0);
> +	if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
> +		return;
>   
>   	/*
>   	 * Set split display info to kms once bonded DSI panel is connected to
>   	 * both hosts.
>   	 */
> -	if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
> +	if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
>   		kms->funcs->set_split_display(kms, master_dsi->encoder,
>   					      slave_dsi->encoder,
>   					      msm_dsi_is_cmd_mode(msm_dsi));
>   	}
> -
> -out:
> -	msm_dsi->panel = panel;
> -	return 0;
> -}
> -
> -static enum drm_connector_status dsi_mgr_connector_detect(
> -		struct drm_connector *connector, bool force)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -
> -	return msm_dsi->panel ? connector_status_connected :
> -		connector_status_disconnected;
> -}
> -
> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
> -{
> -	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> -
> -	DBG("");
> -
> -	drm_connector_cleanup(connector);
> -
> -	kfree(dsi_connector);
> -}
> -
> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	int num;
> -
> -	if (!panel)
> -		return 0;
> -
> -	/*
> -	 * In bonded DSI mode, we have one connector that can be
> -	 * attached to the drm_panel.
> -	 */
> -	num = drm_panel_get_modes(panel, connector);
> -	if (!num)
> -		return 0;
> -
> -	return num;
> -}
> -
> -static struct drm_encoder *
> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -
> -	DBG("");
> -	return msm_dsi_get_encoder(msm_dsi);
>   }
>   
>   static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>   	struct mipi_dsi_host *host = msm_dsi->host;
> -	struct drm_panel *panel = msm_dsi->panel;
>   	bool is_bonded_dsi = IS_BONDED_DSI();
>   	int ret;
>   
> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   	if (!dsi_mgr_power_on_early(bridge))
>   		dsi_mgr_bridge_power_on(bridge);
>   
> -	/* Always call panel functions once, because even for dual panels,
> -	 * there is only one drm_panel instance.
> -	 */
> -	if (panel) {
> -		ret = drm_panel_prepare(panel);
> -		if (ret) {
> -			pr_err("%s: prepare panel %d failed, %d\n", __func__,
> -								id, ret);
> -			goto panel_prep_fail;
> -		}
> -	}
> -
>   	ret = msm_dsi_host_enable(host);
>   	if (ret) {
>   		pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   host1_en_fail:
>   	msm_dsi_host_disable(host);
>   host_en_fail:
> -	if (panel)
> -		drm_panel_unprepare(panel);
> -panel_prep_fail:
>   
>   	return;
>   }
> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>   	}
>   }
>   
> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
> -{
> -	int id = dsi_mgr_bridge_get_id(bridge);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	bool is_bonded_dsi = IS_BONDED_DSI();
> -	int ret;
> -
> -	DBG("id=%d", id);
> -	if (!msm_dsi_device_connected(msm_dsi))
> -		return;
> -
> -	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> -	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> -		return;
> -
> -	if (panel) {
> -		ret = drm_panel_enable(panel);
> -		if (ret) {
> -			pr_err("%s: enable panel %d failed, %d\n", __func__, id,
> -									ret);
> -		}
> -	}
> -}
> -
> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
> -{
> -	int id = dsi_mgr_bridge_get_id(bridge);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	bool is_bonded_dsi = IS_BONDED_DSI();
> -	int ret;
> -
> -	DBG("id=%d", id);
> -	if (!msm_dsi_device_connected(msm_dsi))
> -		return;
> -
> -	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> -	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> -		return;
> -
> -	if (panel) {
> -		ret = drm_panel_disable(panel);
> -		if (ret)
> -			pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
> -									ret);
> -	}
> -}
> -
>   static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>   {
>   	int id = dsi_mgr_bridge_get_id(bridge);
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>   	struct mipi_dsi_host *host = msm_dsi->host;
> -	struct drm_panel *panel = msm_dsi->panel;
>   	bool is_bonded_dsi = IS_BONDED_DSI();
>   	int ret;
>   
> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>   			pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>   	}
>   
> -	if (panel) {
> -		ret = drm_panel_unprepare(panel);
> -		if (ret)
> -			pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
> -								id, ret);
> -	}
> -
>   	msm_dsi_host_disable_irq(host);
>   	if (is_bonded_dsi && msm_dsi1)
>   		msm_dsi_host_disable_irq(msm_dsi1->host);
> @@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>   	return msm_dsi_host_check_dsc(host, mode);
>   }
>   
> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
> -	.detect = dsi_mgr_connector_detect,
> -	.fill_modes = drm_helper_probe_single_connector_modes,
> -	.destroy = dsi_mgr_connector_destroy,
> -	.reset = drm_atomic_helper_connector_reset,
> -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> -	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> -};
> -
> -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
> -	.get_modes = dsi_mgr_connector_get_modes,
> -	.best_encoder = dsi_mgr_connector_best_encoder,
> -};
> -
>   static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>   	.pre_enable = dsi_mgr_bridge_pre_enable,
> -	.enable = dsi_mgr_bridge_enable,
> -	.disable = dsi_mgr_bridge_disable,
>   	.post_disable = dsi_mgr_bridge_post_disable,
>   	.mode_set = dsi_mgr_bridge_mode_set,
>   	.mode_valid = dsi_mgr_bridge_mode_valid,
>   };
>   
> -/* 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);
> -	struct drm_connector *connector = NULL;
> -	struct dsi_connector *dsi_connector;
> -	int ret;
> -
> -	dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
> -	if (!dsi_connector)
> -		return ERR_PTR(-ENOMEM);
> -
> -	dsi_connector->id = id;
> -
> -	connector = &dsi_connector->base;
> -
> -	ret = drm_connector_init(msm_dsi->dev, connector,
> -			&dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
> -	if (ret)
> -		return ERR_PTR(ret);
> -
> -	drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
> -
> -	/* Enable HPD to let hpd event is handled
> -	 * when panel is attached to the host.
> -	 */
> -	connector->polled = DRM_CONNECTOR_POLL_HPD;
> -
> -	/* Display driver doesn't support interlace now. */
> -	connector->interlace_allowed = 0;
> -	connector->doublescan_allowed = 0;
> -
> -	drm_connector_attach_encoder(connector, msm_dsi->encoder);
> -
> -	ret = msm_dsi_manager_panel_init(connector, id);
> -	if (ret) {
> -		DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
> -		goto fail;
> -	}
> -
> -	return connector;
> -
> -fail:
> -	connector->funcs->destroy(connector);
> -	return ERR_PTR(ret);
> -}
> -
>   /* initialize bridge */
>   struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>   {
> @@ -722,18 +502,21 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>   	return ERR_PTR(ret);
>   }
>   
> -struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> +int 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_connector *connector;
>   	struct drm_encoder *encoder;
>   	struct drm_bridge *int_bridge, *ext_bridge;
>   	int ret;
>   
>   	int_bridge = msm_dsi->bridge;
> -	ext_bridge = msm_dsi->external_bridge =
> -			msm_dsi_host_get_bridge(msm_dsi->host);
> +	ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev,
> +					    msm_dsi->pdev->dev.of_node, 1, 0);
> +	if (IS_ERR(ext_bridge))
> +		return PTR_ERR(ext_bridge);
> +
> +	msm_dsi->external_bridge = ext_bridge;
>   
>   	encoder = msm_dsi->encoder;
>   
> @@ -745,36 +528,32 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>   	ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>   			DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>   	if (ret == -EINVAL) {
> -		struct drm_connector *connector;
> -		struct list_head *connector_list;
> -
> -		/* link the internal dsi bridge to the external bridge */
> -		drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> -
>   		/*
> -		 * 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()
> +		 * link the internal dsi bridge to the external bridge,
> +		 * connector is created by the next bridge.
>   		 */
> -		connector_list = &dev->mode_config.connector_list;
> +		ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		struct drm_connector *connector;
>   
> -		list_for_each_entry(connector, connector_list, head) {
> -			if (drm_connector_has_possible_encoder(connector, encoder))
> -				return connector;
> +		/* We are in charge of the connector, create one now. */
> +		connector = drm_bridge_connector_init(dev, encoder);
> +		if (IS_ERR(connector)) {
> +			DRM_ERROR("Unable to create bridge connector\n");
> +			return PTR_ERR(connector);
>   		}

Ok, I understood now. We create the connector using 
drm_bridge_connector_init() only when the brige doesnt create one already.

In both cases since now we are leaving the hpd handling to the next 
bridge, like I was suggesting, the dsi_hpd_worker() etc can be dropped 
now. Because anyway without setting the DRM_CONNECTOR_POLL_HPD, event 
will not be sent to usermode.

>   
> -		return ERR_PTR(-ENODEV);
> -	}
> -
> -	connector = drm_bridge_connector_init(dev, encoder);
> -	if (IS_ERR(connector)) {
> -		DRM_ERROR("Unable to create bridge connector\n");
> -		return ERR_CAST(connector);
> +		ret = drm_connector_attach_encoder(connector, encoder);
> +		if (ret < 0)
> +			return ret;
>   	}
>   
> -	drm_connector_attach_encoder(connector, encoder);
> +	/* The pipeline is ready, ping encoders if necessary */
> +	msm_dsi_manager_set_split_display(id);
>   
> -	return connector;
> +	return 0;
>   }
>   
>   void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-14 21:54       ` [Freedreno] " Abhinav Kumar
@ 2022-08-22 17:53         ` Dmitry Baryshkov
  2022-08-27 21:34           ` Abhinav Kumar
  0 siblings, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-08-22 17:53 UTC (permalink / raw)
  To: Abhinav Kumar, Rob Clark, Sean Paul
  Cc: David Airlie, linux-arm-msm, dri-devel, Stephen Boyd,
	Bjorn Andersson, freedreno

On 15/07/2022 00:54, Abhinav Kumar wrote:
> 
> 
> On 7/12/2022 6:22 AM, Dmitry Baryshkov wrote:
>> Currently the DSI driver has two separate paths: one if the next device
>> in a chain is a bridge and another one if the panel is connected
>> directly to the DSI host. Simplify the code path by using panel-bridge
>> driver (already selected in Kconfig) and dropping support for
>> handling the panel directly.
>>
>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>>
>> I'm not sending this as a separate patchset (I'd like to sort out mdp5
>> first), but more of a preview of changes related to
>> msm_dsi_manager_ext_bridge_init().
>>
>> ---
>>   drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
>>   drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
>>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
>>   4 files changed, 36 insertions(+), 323 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c 
>> b/drivers/gpu/drm/msm/dsi/dsi.c
>> index 1625328fa430..4edb9167e600 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
>> @@ -6,14 +6,6 @@
>>   #include "dsi.h"
>>   #include "dsi_cfg.h"
>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
>> -{
>> -    if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
>> -        return NULL;
>> -
>> -    return msm_dsi->encoder;
>> -}
>> -
>>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>>   {
>>       unsigned long host_flags = 
>> msm_dsi_host_get_mode_flags(msm_dsi->host);
>> @@ -220,7 +212,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, 
>> struct drm_device *dev,
>>                struct drm_encoder *encoder)
>>   {
>>       struct msm_drm_private *priv;
>> -    struct drm_bridge *ext_bridge;
>>       int ret;
>>       if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
>> @@ -254,26 +245,10 @@ int msm_dsi_modeset_init(struct msm_dsi 
>> *msm_dsi, struct drm_device *dev,
>>           goto fail;
>>       }
>> -    /*
>> -     * 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);
>> +    ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
>> +    if (ret) {
>>           DRM_DEV_ERROR(dev->dev,
>>               "failed to create dsi connector: %d\n", ret);
>> -        msm_dsi->connector = NULL;
>>           goto fail;
>>       }
>> @@ -287,12 +262,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, 
>> struct drm_device *dev,
>>           msm_dsi->bridge = NULL;
>>       }
>> -    /* 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;
> 
>  From what i can see all the usages of msm_dsi->connector are removed 
> after this change. So can we drop that?

The connector field is dropped from the msm_dsi struct. If you are 
asking about the msm_dsi_modeset_init(), we can not drop it since we 
require the DRM device with GEM being initialized in order to allocate 
DSI DMA buffer. We can think about moving DMA buffer allocation towards 
the usage point, however this is definitely a separate commit.

[skipped]

>> *msm_dsi_manager_ext_bridge_init(u8 id)
>>       ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>>               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>       if (ret == -EINVAL) {
>> -        struct drm_connector *connector;
>> -        struct list_head *connector_list;
>> -
>> -        /* link the internal dsi bridge to the external bridge */
>> -        drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>> -
>>           /*
>> -         * 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()
>> +         * link the internal dsi bridge to the external bridge,
>> +         * connector is created by the next bridge.
>>            */
>> -        connector_list = &dev->mode_config.connector_list;
>> +        ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>> +        if (ret < 0)
>> +            return ret;
>> +    } else {
>> +        struct drm_connector *connector;
>> -        list_for_each_entry(connector, connector_list, head) {
>> -            if (drm_connector_has_possible_encoder(connector, encoder))
>> -                return connector;
>> +        /* We are in charge of the connector, create one now. */
>> +        connector = drm_bridge_connector_init(dev, encoder);
>> +        if (IS_ERR(connector)) {
>> +            DRM_ERROR("Unable to create bridge connector\n");
>> +            return PTR_ERR(connector);
>>           }
> 
> Ok, I understood now. We create the connector using 
> drm_bridge_connector_init() only when the brige doesnt create one already.
> 
> In both cases since now we are leaving the hpd handling to the next 
> bridge, like I was suggesting, the dsi_hpd_worker() etc can be dropped 
> now. Because anyway without setting the DRM_CONNECTOR_POLL_HPD, event 
> will not be sent to usermode.

I've submitted https://patchwork.freedesktop.org/series/107564/ as a 
separate change.

> 
>> -        return ERR_PTR(-ENODEV);
>> -    }
>> -
>> -    connector = drm_bridge_connector_init(dev, encoder);
>> -    if (IS_ERR(connector)) {
>> -        DRM_ERROR("Unable to create bridge connector\n");
>> -        return ERR_CAST(connector);
>> +        ret = drm_connector_attach_encoder(connector, encoder);
>> +        if (ret < 0)
>> +            return ret;
>>       }
>> -    drm_connector_attach_encoder(connector, encoder);
>> +    /* The pipeline is ready, ping encoders if necessary */
>> +    msm_dsi_manager_set_split_display(id);
>> -    return connector;
>> +    return 0;
>>   }
>>   void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Freedreno] [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-08-22 17:53         ` Dmitry Baryshkov
@ 2022-08-27 21:34           ` Abhinav Kumar
  0 siblings, 0 replies; 25+ messages in thread
From: Abhinav Kumar @ 2022-08-27 21:34 UTC (permalink / raw)
  To: Dmitry Baryshkov, Rob Clark, Sean Paul
  Cc: David Airlie, linux-arm-msm, dri-devel, Stephen Boyd,
	Bjorn Andersson, freedreno



On 8/22/2022 10:53 AM, Dmitry Baryshkov wrote:
> On 15/07/2022 00:54, Abhinav Kumar wrote:
>>
>>
>> On 7/12/2022 6:22 AM, Dmitry Baryshkov wrote:
>>> Currently the DSI driver has two separate paths: one if the next device
>>> in a chain is a bridge and another one if the panel is connected
>>> directly to the DSI host. Simplify the code path by using panel-bridge
>>> driver (already selected in Kconfig) and dropping support for
>>> handling the panel directly.
>>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>>
>>> I'm not sending this as a separate patchset (I'd like to sort out mdp5
>>> first), but more of a preview of changes related to
>>> msm_dsi_manager_ext_bridge_init().
>>>
>>> ---
>>>   drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
>>>   drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
>>>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
>>>   4 files changed, 36 insertions(+), 323 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c 
>>> b/drivers/gpu/drm/msm/dsi/dsi.c
>>> index 1625328fa430..4edb9167e600 100644
>>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
>>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
>>> @@ -6,14 +6,6 @@
>>>   #include "dsi.h"
>>>   #include "dsi_cfg.h"
>>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
>>> -{
>>> -    if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
>>> -        return NULL;
>>> -
>>> -    return msm_dsi->encoder;
>>> -}
>>> -
>>>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>>>   {
>>>       unsigned long host_flags = 
>>> msm_dsi_host_get_mode_flags(msm_dsi->host);
>>> @@ -220,7 +212,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, 
>>> struct drm_device *dev,
>>>                struct drm_encoder *encoder)
>>>   {
>>>       struct msm_drm_private *priv;
>>> -    struct drm_bridge *ext_bridge;
>>>       int ret;
>>>       if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
>>> @@ -254,26 +245,10 @@ int msm_dsi_modeset_init(struct msm_dsi 
>>> *msm_dsi, struct drm_device *dev,
>>>           goto fail;
>>>       }
>>> -    /*
>>> -     * 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);
>>> +    ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
>>> +    if (ret) {
>>>           DRM_DEV_ERROR(dev->dev,
>>>               "failed to create dsi connector: %d\n", ret);
>>> -        msm_dsi->connector = NULL;
>>>           goto fail;
>>>       }
>>> @@ -287,12 +262,6 @@ int msm_dsi_modeset_init(struct msm_dsi 
>>> *msm_dsi, struct drm_device *dev,
>>>           msm_dsi->bridge = NULL;
>>>       }
>>> -    /* 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;
>>
>>  From what i can see all the usages of msm_dsi->connector are removed 
>> after this change. So can we drop that?
> 
> The connector field is dropped from the msm_dsi struct. If you are 
> asking about the msm_dsi_modeset_init(), we can not drop it since we 
> require the DRM device with GEM being initialized in order to allocate 
> DSI DMA buffer. We can think about moving DMA buffer allocation towards 
> the usage point, however this is definitely a separate commit.
> 
> [skipped]

Yes, got it.
> 
>>> *msm_dsi_manager_ext_bridge_init(u8 id)
>>>       ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>>>               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>>       if (ret == -EINVAL) {
>>> -        struct drm_connector *connector;
>>> -        struct list_head *connector_list;
>>> -
>>> -        /* link the internal dsi bridge to the external bridge */
>>> -        drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>>> -
>>>           /*
>>> -         * 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()
>>> +         * link the internal dsi bridge to the external bridge,
>>> +         * connector is created by the next bridge.
>>>            */
>>> -        connector_list = &dev->mode_config.connector_list;
>>> +        ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>>> +        if (ret < 0)
>>> +            return ret;
>>> +    } else {
>>> +        struct drm_connector *connector;
>>> -        list_for_each_entry(connector, connector_list, head) {
>>> -            if (drm_connector_has_possible_encoder(connector, encoder))
>>> -                return connector;
>>> +        /* We are in charge of the connector, create one now. */
>>> +        connector = drm_bridge_connector_init(dev, encoder);
>>> +        if (IS_ERR(connector)) {
>>> +            DRM_ERROR("Unable to create bridge connector\n");
>>> +            return PTR_ERR(connector);
>>>           }
>>
>> Ok, I understood now. We create the connector using 
>> drm_bridge_connector_init() only when the brige doesnt create one 
>> already.
>>
>> In both cases since now we are leaving the hpd handling to the next 
>> bridge, like I was suggesting, the dsi_hpd_worker() etc can be dropped 
>> now. Because anyway without setting the DRM_CONNECTOR_POLL_HPD, event 
>> will not be sent to usermode.
> 
> I've submitted https://patchwork.freedesktop.org/series/107564/ as a 
> separate change.
> 
Thanks for pushing this change, I have R-bed that too.

For this one, now I can

Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>

>>
>>> -        return ERR_PTR(-ENODEV);
>>> -    }
>>> -
>>> -    connector = drm_bridge_connector_init(dev, encoder);
>>> -    if (IS_ERR(connector)) {
>>> -        DRM_ERROR("Unable to create bridge connector\n");
>>> -        return ERR_CAST(connector);
>>> +        ret = drm_connector_attach_encoder(connector, encoder);
>>> +        if (ret < 0)
>>> +            return ret;
>>>       }
>>> -    drm_connector_attach_encoder(connector, encoder);
>>> +    /* The pipeline is ready, ping encoders if necessary */
>>> +    msm_dsi_manager_set_split_display(id);
>>> -    return connector;
>>> +    return 0;
>>>   }
>>>   void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-07-12 13:22     ` [PATCH v2.5] " Dmitry Baryshkov
  2022-07-14 21:54       ` [Freedreno] " Abhinav Kumar
@ 2022-11-11 15:30       ` Caleb Connolly
  2022-11-13 10:23         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE #forregzbot Thorsten Leemhuis
  2022-11-13 13:28         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
  1 sibling, 2 replies; 25+ messages in thread
From: Caleb Connolly @ 2022-11-11 15:30 UTC (permalink / raw)
  To: Dmitry Baryshkov, Rob Clark, Sean Paul, Abhinav Kumar
  Cc: David Airlie, linux-arm-msm, dri-devel, Bjorn Andersson,
	Stephen Boyd, freedreno

Hi,

This patch has caused a regression on 6.1-rc for some devices that use 
DSI panels. The new behaviour results in the DSI controller being 
switched off before the panel unprepare hook is called. As a result, 
panel drivers which call mipi_dsi_dcs_write() or similar in 
unprepare() fail.

I've noticed it specifically on the OnePlus 6 (with upstream Samsung 
s0fef00 panel driver) and the SHIFT6mq with an out of tree driver.

On 12/07/2022 14:22, Dmitry Baryshkov wrote:
> Currently the DSI driver has two separate paths: one if the next device
> in a chain is a bridge and another one if the panel is connected
> directly to the DSI host. Simplify the code path by using panel-bridge
> driver (already selected in Kconfig) and dropping support for
> handling the panel directly.
> 
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> 
> I'm not sending this as a separate patchset (I'd like to sort out mdp5
> first), but more of a preview of changes related to
> msm_dsi_manager_ext_bridge_init().
> 
> ---
>   drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
>   drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
>   4 files changed, 36 insertions(+), 323 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
> index 1625328fa430..4edb9167e600 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> @@ -6,14 +6,6 @@
>   #include "dsi.h"
>   #include "dsi_cfg.h"
> 
> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
> -{
> -	if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
> -		return NULL;
> -
> -	return msm_dsi->encoder;
> -}
> -
>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>   {
>   	unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
> @@ -220,7 +212,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   			 struct drm_encoder *encoder)
>   {
>   	struct msm_drm_private *priv;
> -	struct drm_bridge *ext_bridge;
>   	int ret;
> 
>   	if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
> @@ -254,26 +245,10 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   		goto fail;
>   	}
> 
> -	/*
> -	 * 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);
> +	ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
> +	if (ret) {
>   		DRM_DEV_ERROR(dev->dev,
>   			"failed to create dsi connector: %d\n", ret);
> -		msm_dsi->connector = NULL;
>   		goto fail;
>   	}
> 
> @@ -287,12 +262,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
>   		msm_dsi->bridge = NULL;
>   	}
> 
> -	/* 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;
> -
>   	return ret;
>   }
> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> index 580a1e6358bf..703e4c88d7fb 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> @@ -12,7 +12,6 @@
>   #include <drm/drm_bridge.h>
>   #include <drm/drm_crtc.h>
>   #include <drm/drm_mipi_dsi.h>
> -#include <drm/drm_panel.h>
> 
>   #include "msm_drv.h"
>   #include "disp/msm_disp_snapshot.h"
> @@ -49,8 +48,6 @@ 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;
> 
> @@ -58,10 +55,8 @@ struct msm_dsi {
>   	struct msm_dsi_phy *phy;
> 
>   	/*
> -	 * panel/external_bridge connected to dsi bridge output, only one of the
> -	 * two can be valid at a time
> +	 * external_bridge connected to dsi bridge output
>   	 */
> -	struct drm_panel *panel;
>   	struct drm_bridge *external_bridge;
> 
>   	struct device *phy_dev;
> @@ -76,8 +71,7 @@ struct msm_dsi {
>   /* dsi manager */
>   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_ext_bridge_init(u8 id);
>   int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>   bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
>   int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>   /* msm dsi */
>   static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>   {
> -	return msm_dsi->panel || msm_dsi->external_bridge;
> +	return msm_dsi->external_bridge;
>   }
> 
> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
> -
>   /* dsi host */
>   struct msm_dsi_host;
>   int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
>   				  const struct drm_display_mode *mode);
>   enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>   					    const struct drm_display_mode *mode);
> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>   int msm_dsi_host_register(struct mipi_dsi_host *host);
>   void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>   void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>   	struct msm_display_dsc_config *dsc;
> 
>   	/* connected device info */
> -	struct device_node *device_node;
>   	unsigned int channel;
>   	unsigned int lanes;
>   	enum mipi_dsi_pixel_format format;
> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
> 
>   	dsi_dev_detach(msm_host->pdev);
> 
> -	msm_host->device_node = NULL;
> -
>   	DBG("id=%d", msm_host->id);
>   	if (msm_host->dev)
>   		queue_work(msm_host->workqueue, &msm_host->hpd_work);
> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
>   		goto err;
>   	}
> 
> -	/* Get panel node from the output port's endpoint data */
> -	device_node = of_graph_get_remote_node(np, 1, 0);
> -	if (!device_node) {
> -		DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
> -		ret = -ENODEV;
> -		goto err;
> -	}
> -
> -	msm_host->device_node = device_node;
> -
>   	if (of_property_read_bool(np, "syscon-sfpb")) {
>   		msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>   					"syscon-sfpb");
> @@ -2678,23 +2665,11 @@ enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>   	return MODE_OK;
>   }
> 
> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
> -{
> -	return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
> -}
> -
>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>   {
>   	return to_msm_dsi_host(host)->mode_flags;
>   }
> 
> -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);
> -}
> -
>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host)
>   {
>   	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index cb84d185d73a..546e0b873558 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>   	}
>   }
> 
> -struct dsi_connector {
> -	struct drm_connector base;
> -	int id;
> -};
> -
>   struct dsi_bridge {
>   	struct drm_bridge base;
>   	int id;
>   };
> 
> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>   #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
> 
> -static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
> -{
> -	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> -	return dsi_connector->id;
> -}
> -
>   static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>   {
>   	struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>   	return dsi_bridge->id;
>   }
> 
> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
> +static void msm_dsi_manager_set_split_display(u8 id)
>   {
> -	struct msm_drm_private *priv = conn->dev->dev_private;
> -	struct msm_kms *kms = priv->kms;
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
> +	struct msm_drm_private *priv = msm_dsi->dev->dev_private;
> +	struct msm_kms *kms = priv->kms;
>   	struct msm_dsi *master_dsi, *slave_dsi;
> -	struct drm_panel *panel;
> 
>   	if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>   		master_dsi = other_dsi;
> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>   		slave_dsi = other_dsi;
>   	}
> 
> -	/*
> -	 * There is only 1 panel in the global panel list for bonded DSI mode.
> -	 * Therefore slave dsi should get the drm_panel instance from master
> -	 * dsi.
> -	 */
> -	panel = msm_dsi_host_get_panel(master_dsi->host);
> -	if (IS_ERR(panel)) {
> -		DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
> -			  PTR_ERR(panel));
> -		return PTR_ERR(panel);
> -	}
> -
> -	if (!panel || !IS_BONDED_DSI())
> -		goto out;
> -
> -	drm_object_attach_property(&conn->base,
> -				   conn->dev->mode_config.tile_property, 0);
> +	if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
> +		return;
> 
>   	/*
>   	 * Set split display info to kms once bonded DSI panel is connected to
>   	 * both hosts.
>   	 */
> -	if (other_dsi && other_dsi->panel && kms->funcs->set_split_display) {
> +	if (other_dsi && other_dsi->external_bridge && kms->funcs->set_split_display) {
>   		kms->funcs->set_split_display(kms, master_dsi->encoder,
>   					      slave_dsi->encoder,
>   					      msm_dsi_is_cmd_mode(msm_dsi));
>   	}
> -
> -out:
> -	msm_dsi->panel = panel;
> -	return 0;
> -}
> -
> -static enum drm_connector_status dsi_mgr_connector_detect(
> -		struct drm_connector *connector, bool force)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -
> -	return msm_dsi->panel ? connector_status_connected :
> -		connector_status_disconnected;
> -}
> -
> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
> -{
> -	struct dsi_connector *dsi_connector = to_dsi_connector(connector);
> -
> -	DBG("");
> -
> -	drm_connector_cleanup(connector);
> -
> -	kfree(dsi_connector);
> -}
> -
> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	int num;
> -
> -	if (!panel)
> -		return 0;
> -
> -	/*
> -	 * In bonded DSI mode, we have one connector that can be
> -	 * attached to the drm_panel.
> -	 */
> -	num = drm_panel_get_modes(panel, connector);
> -	if (!num)
> -		return 0;
> -
> -	return num;
> -}
> -
> -static struct drm_encoder *
> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
> -{
> -	int id = dsi_mgr_connector_get_id(connector);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -
> -	DBG("");
> -	return msm_dsi_get_encoder(msm_dsi);
>   }
> 
>   static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>   	struct mipi_dsi_host *host = msm_dsi->host;
> -	struct drm_panel *panel = msm_dsi->panel;
>   	bool is_bonded_dsi = IS_BONDED_DSI();
>   	int ret;
> 
> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   	if (!dsi_mgr_power_on_early(bridge))
>   		dsi_mgr_bridge_power_on(bridge);
> 
> -	/* Always call panel functions once, because even for dual panels,
> -	 * there is only one drm_panel instance.
> -	 */
> -	if (panel) {
> -		ret = drm_panel_prepare(panel);
> -		if (ret) {
> -			pr_err("%s: prepare panel %d failed, %d\n", __func__,
> -								id, ret);
> -			goto panel_prep_fail;
> -		}
> -	}
> -
>   	ret = msm_dsi_host_enable(host);
>   	if (ret) {
>   		pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
>   host1_en_fail:
>   	msm_dsi_host_disable(host);
>   host_en_fail:
> -	if (panel)
> -		drm_panel_unprepare(panel);
> -panel_prep_fail:
> 
>   	return;
>   }
> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>   	}
>   }
> 
> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
> -{
> -	int id = dsi_mgr_bridge_get_id(bridge);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	bool is_bonded_dsi = IS_BONDED_DSI();
> -	int ret;
> -
> -	DBG("id=%d", id);
> -	if (!msm_dsi_device_connected(msm_dsi))
> -		return;
> -
> -	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> -	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> -		return;
> -
> -	if (panel) {
> -		ret = drm_panel_enable(panel);
> -		if (ret) {
> -			pr_err("%s: enable panel %d failed, %d\n", __func__, id,
> -									ret);
> -		}
> -	}
> -}
> -
> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
> -{
> -	int id = dsi_mgr_bridge_get_id(bridge);
> -	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> -	struct drm_panel *panel = msm_dsi->panel;
> -	bool is_bonded_dsi = IS_BONDED_DSI();
> -	int ret;
> -
> -	DBG("id=%d", id);
> -	if (!msm_dsi_device_connected(msm_dsi))
> -		return;
> -
> -	/* Do nothing with the host if it is slave-DSI in case of bonded DSI */
> -	if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
> -		return;
> -
> -	if (panel) {
> -		ret = drm_panel_disable(panel);
> -		if (ret)
> -			pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
> -									ret);
> -	}
> -}
> -
>   static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>   {
>   	int id = dsi_mgr_bridge_get_id(bridge);
>   	struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>   	struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>   	struct mipi_dsi_host *host = msm_dsi->host;
> -	struct drm_panel *panel = msm_dsi->panel;
>   	bool is_bonded_dsi = IS_BONDED_DSI();
>   	int ret;
> 
> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>   			pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>   	}
> 
> -	if (panel) {
> -		ret = drm_panel_unprepare(panel);
> -		if (ret)
> -			pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
> -								id, ret);
> -	}
> -
>   	msm_dsi_host_disable_irq(host);
>   	if (is_bonded_dsi && msm_dsi1)
>   		msm_dsi_host_disable_irq(msm_dsi1->host);
> @@ -614,76 +457,13 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>   	return msm_dsi_host_check_dsc(host, mode);
>   }
> 
> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
> -	.detect = dsi_mgr_connector_detect,
> -	.fill_modes = drm_helper_probe_single_connector_modes,
> -	.destroy = dsi_mgr_connector_destroy,
> -	.reset = drm_atomic_helper_connector_reset,
> -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> -	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> -};
> -
> -static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
> -	.get_modes = dsi_mgr_connector_get_modes,
> -	.best_encoder = dsi_mgr_connector_best_encoder,
> -};
> -
>   static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>   	.pre_enable = dsi_mgr_bridge_pre_enable,
> -	.enable = dsi_mgr_bridge_enable,
> -	.disable = dsi_mgr_bridge_disable,
>   	.post_disable = dsi_mgr_bridge_post_disable,
>   	.mode_set = dsi_mgr_bridge_mode_set,
>   	.mode_valid = dsi_mgr_bridge_mode_valid,
>   };
> 
> -/* 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);
> -	struct drm_connector *connector = NULL;
> -	struct dsi_connector *dsi_connector;
> -	int ret;
> -
> -	dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
> -	if (!dsi_connector)
> -		return ERR_PTR(-ENOMEM);
> -
> -	dsi_connector->id = id;
> -
> -	connector = &dsi_connector->base;
> -
> -	ret = drm_connector_init(msm_dsi->dev, connector,
> -			&dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
> -	if (ret)
> -		return ERR_PTR(ret);
> -
> -	drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
> -
> -	/* Enable HPD to let hpd event is handled
> -	 * when panel is attached to the host.
> -	 */
> -	connector->polled = DRM_CONNECTOR_POLL_HPD;
> -
> -	/* Display driver doesn't support interlace now. */
> -	connector->interlace_allowed = 0;
> -	connector->doublescan_allowed = 0;
> -
> -	drm_connector_attach_encoder(connector, msm_dsi->encoder);
> -
> -	ret = msm_dsi_manager_panel_init(connector, id);
> -	if (ret) {
> -		DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
> -		goto fail;
> -	}
> -
> -	return connector;
> -
> -fail:
> -	connector->funcs->destroy(connector);
> -	return ERR_PTR(ret);
> -}
> -
>   /* initialize bridge */
>   struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>   {
> @@ -722,18 +502,21 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>   	return ERR_PTR(ret);
>   }
> 
> -struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> +int 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_connector *connector;
>   	struct drm_encoder *encoder;
>   	struct drm_bridge *int_bridge, *ext_bridge;
>   	int ret;
> 
>   	int_bridge = msm_dsi->bridge;
> -	ext_bridge = msm_dsi->external_bridge =
> -			msm_dsi_host_get_bridge(msm_dsi->host);
> +	ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev,
> +					    msm_dsi->pdev->dev.of_node, 1, 0);
> +	if (IS_ERR(ext_bridge))
> +		return PTR_ERR(ext_bridge);
> +
> +	msm_dsi->external_bridge = ext_bridge;
> 
>   	encoder = msm_dsi->encoder;
> 
> @@ -745,36 +528,32 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>   	ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>   			DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>   	if (ret == -EINVAL) {
> -		struct drm_connector *connector;
> -		struct list_head *connector_list;
> -
> -		/* link the internal dsi bridge to the external bridge */
> -		drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> -
>   		/*
> -		 * 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()
> +		 * link the internal dsi bridge to the external bridge,
> +		 * connector is created by the next bridge.
>   		 */
> -		connector_list = &dev->mode_config.connector_list;
> +		ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		struct drm_connector *connector;
> 
> -		list_for_each_entry(connector, connector_list, head) {
> -			if (drm_connector_has_possible_encoder(connector, encoder))
> -				return connector;
> +		/* We are in charge of the connector, create one now. */
> +		connector = drm_bridge_connector_init(dev, encoder);
> +		if (IS_ERR(connector)) {
> +			DRM_ERROR("Unable to create bridge connector\n");
> +			return PTR_ERR(connector);
>   		}
> 
> -		return ERR_PTR(-ENODEV);
> -	}
> -
> -	connector = drm_bridge_connector_init(dev, encoder);
> -	if (IS_ERR(connector)) {
> -		DRM_ERROR("Unable to create bridge connector\n");
> -		return ERR_CAST(connector);
> +		ret = drm_connector_attach_encoder(connector, encoder);
> +		if (ret < 0)
> +			return ret;
>   	}
> 
> -	drm_connector_attach_encoder(connector, encoder);
> +	/* The pipeline is ready, ping encoders if necessary */
> +	msm_dsi_manager_set_split_display(id);
> 
> -	return connector;
> +	return 0;
>   }
> 
>   void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
> --
> 2.35.1
> 

-- 
Kind Regards,
Caleb (they/them)

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE #forregzbot
  2022-11-11 15:30       ` Caleb Connolly
@ 2022-11-13 10:23         ` Thorsten Leemhuis
  2022-12-08 15:26           ` Thorsten Leemhuis
  2022-11-13 13:28         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
  1 sibling, 1 reply; 25+ messages in thread
From: Thorsten Leemhuis @ 2022-11-13 10:23 UTC (permalink / raw)
  To: regressions; +Cc: linux-arm-msm, freedreno, dri-devel

[Note: this mail is primarily send for documentation purposes and/or for
regzbot, my Linux kernel regression tracking bot. That's why I removed
most or all folks from the list of recipients, but left any that looked
like a mailing lists. These mails usually contain '#forregzbot' in the
subject, to make them easy to spot and filter out.]

[TLDR: I'm adding this regression report to the list of tracked
regressions; all text from me you find below is based on a few templates
paragraphs you might have encountered already already in similar form.]

Hi, this is your Linux kernel regression tracker.

On 11.11.22 16:30, Caleb Connolly wrote:
> 
> This patch has caused a regression on 6.1-rc for some devices that use
> DSI panels. The new behaviour results in the DSI controller being
> switched off before the panel unprepare hook is called. As a result,
> panel drivers which call mipi_dsi_dcs_write() or similar in unprepare()
> fail.
> 
> I've noticed it specifically on the OnePlus 6 (with upstream Samsung
> s0fef00 panel driver) and the SHIFT6mq with an out of tree driver.

Thanks for the report. To be sure below issue doesn't fall through the
cracks unnoticed, I'm adding it to regzbot, my Linux kernel regression
tracking bot:

#regzbot ^introduced 007ac0262b0d
#regzbot title drm: msm: DSI controller being switched off before the
panel unprepare hook is called
#regzbot ignore-activity

This isn't a regression? This issue or a fix for it are already
discussed somewhere else? It was fixed already? You want to clarify when
the regression started to happen? Or point out I got the title or
something else totally wrong? Then just reply -- ideally with also
telling regzbot about it, as explained here:
https://linux-regtracking.leemhuis.info/tracked-regression/

Reminder for developers: When fixing the issue, add 'Link:' tags
pointing to the report (the mail this one replies to), as explained for
in the Linux kernel's documentation; above webpage explains why this is
important for tracked regressions.

Ciao, Thorsten (wearing his 'the Linux kernel's regression tracker' hat)

P.S.: As the Linux kernel's regression tracker I deal with a lot of
reports and sometimes miss something important when writing mails like
this. If that's the case here, don't hesitate to tell me in a public
reply, it's in everyone's interest to set the public record straight.

> On 12/07/2022 14:22, Dmitry Baryshkov wrote:
>> Currently the DSI driver has two separate paths: one if the next device
>> in a chain is a bridge and another one if the panel is connected
>> directly to the DSI host. Simplify the code path by using panel-bridge
>> driver (already selected in Kconfig) and dropping support for
>> handling the panel directly.
>>
>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>>
>> I'm not sending this as a separate patchset (I'd like to sort out mdp5
>> first), but more of a preview of changes related to
>> msm_dsi_manager_ext_bridge_init().
>>
>> ---
>>   drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
>>   drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
>>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
>>   4 files changed, 36 insertions(+), 323 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c
>> b/drivers/gpu/drm/msm/dsi/dsi.c
>> index 1625328fa430..4edb9167e600 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi.c
>> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
>> @@ -6,14 +6,6 @@
>>   #include "dsi.h"
>>   #include "dsi_cfg.h"
>>
>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
>> -{
>> -    if (!msm_dsi || !msm_dsi_device_connected(msm_dsi))
>> -        return NULL;
>> -
>> -    return msm_dsi->encoder;
>> -}
>> -
>>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>>   {
>>       unsigned long host_flags =
>> msm_dsi_host_get_mode_flags(msm_dsi->host);
>> @@ -220,7 +212,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
>> struct drm_device *dev,
>>                struct drm_encoder *encoder)
>>   {
>>       struct msm_drm_private *priv;
>> -    struct drm_bridge *ext_bridge;
>>       int ret;
>>
>>       if (WARN_ON(!encoder) || WARN_ON(!msm_dsi) || WARN_ON(!dev))
>> @@ -254,26 +245,10 @@ int msm_dsi_modeset_init(struct msm_dsi
>> *msm_dsi, struct drm_device *dev,
>>           goto fail;
>>       }
>>
>> -    /*
>> -     * 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);
>> +    ret = msm_dsi_manager_ext_bridge_init(msm_dsi->id);
>> +    if (ret) {
>>           DRM_DEV_ERROR(dev->dev,
>>               "failed to create dsi connector: %d\n", ret);
>> -        msm_dsi->connector = NULL;
>>           goto fail;
>>       }
>>
>> @@ -287,12 +262,6 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
>> struct drm_device *dev,
>>           msm_dsi->bridge = NULL;
>>       }
>>
>> -    /* 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;
>> -
>>       return ret;
>>   }
>>
>> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h
>> b/drivers/gpu/drm/msm/dsi/dsi.h
>> index 580a1e6358bf..703e4c88d7fb 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi.h
>> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
>> @@ -12,7 +12,6 @@
>>   #include <drm/drm_bridge.h>
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drm_mipi_dsi.h>
>> -#include <drm/drm_panel.h>
>>
>>   #include "msm_drv.h"
>>   #include "disp/msm_disp_snapshot.h"
>> @@ -49,8 +48,6 @@ 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;
>>
>> @@ -58,10 +55,8 @@ struct msm_dsi {
>>       struct msm_dsi_phy *phy;
>>
>>       /*
>> -     * panel/external_bridge connected to dsi bridge output, only one
>> of the
>> -     * two can be valid at a time
>> +     * external_bridge connected to dsi bridge output
>>        */
>> -    struct drm_panel *panel;
>>       struct drm_bridge *external_bridge;
>>
>>       struct device *phy_dev;
>> @@ -76,8 +71,7 @@ struct msm_dsi {
>>   /* dsi manager */
>>   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_ext_bridge_init(u8 id);
>>   int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
>>   bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
>>   int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
>> @@ -87,11 +81,9 @@ void msm_dsi_manager_tpg_enable(void);
>>   /* msm dsi */
>>   static inline bool msm_dsi_device_connected(struct msm_dsi *msm_dsi)
>>   {
>> -    return msm_dsi->panel || msm_dsi->external_bridge;
>> +    return msm_dsi->external_bridge;
>>   }
>>
>> -struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
>> -
>>   /* dsi host */
>>   struct msm_dsi_host;
>>   int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
>> @@ -116,9 +108,7 @@ int msm_dsi_host_set_display_mode(struct
>> mipi_dsi_host *host,
>>                     const struct drm_display_mode *mode);
>>   enum drm_mode_status msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>                           const struct drm_display_mode *mode);
>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host);
>>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host);
>> -struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host);
>>   int msm_dsi_host_register(struct mipi_dsi_host *host);
>>   void msm_dsi_host_unregister(struct mipi_dsi_host *host);
>>   void msm_dsi_host_set_phy_mode(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 fb5ab6c718c8..5a18aa710d00 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
>> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
>> @@ -164,7 +164,6 @@ struct msm_dsi_host {
>>       struct msm_display_dsc_config *dsc;
>>
>>       /* connected device info */
>> -    struct device_node *device_node;
>>       unsigned int channel;
>>       unsigned int lanes;
>>       enum mipi_dsi_pixel_format format;
>> @@ -1721,8 +1720,6 @@ static int dsi_host_detach(struct mipi_dsi_host
>> *host,
>>
>>       dsi_dev_detach(msm_host->pdev);
>>
>> -    msm_host->device_node = NULL;
>> -
>>       DBG("id=%d", msm_host->id);
>>       if (msm_host->dev)
>>           queue_work(msm_host->workqueue, &msm_host->hpd_work);
>> @@ -1988,16 +1985,6 @@ static int dsi_host_parse_dt(struct
>> msm_dsi_host *msm_host)
>>           goto err;
>>       }
>>
>> -    /* Get panel node from the output port's endpoint data */
>> -    device_node = of_graph_get_remote_node(np, 1, 0);
>> -    if (!device_node) {
>> -        DRM_DEV_DEBUG(dev, "%s: no valid device\n", __func__);
>> -        ret = -ENODEV;
>> -        goto err;
>> -    }
>> -
>> -    msm_host->device_node = device_node;
>> -
>>       if (of_property_read_bool(np, "syscon-sfpb")) {
>>           msm_host->sfpb = syscon_regmap_lookup_by_phandle(np,
>>                       "syscon-sfpb");
>> @@ -2678,23 +2665,11 @@ enum drm_mode_status
>> msm_dsi_host_check_dsc(struct mipi_dsi_host *host,
>>       return MODE_OK;
>>   }
>>
>> -struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host)
>> -{
>> -    return of_drm_find_panel(to_msm_dsi_host(host)->device_node);
>> -}
>> -
>>   unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host)
>>   {
>>       return to_msm_dsi_host(host)->mode_flags;
>>   }
>>
>> -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);
>> -}
>> -
>>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct
>> mipi_dsi_host *host)
>>   {
>>       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
>> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c
>> b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>> index cb84d185d73a..546e0b873558 100644
>> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
>> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
>> @@ -214,39 +214,26 @@ static void dsi_mgr_phy_disable(int id)
>>       }
>>   }
>>
>> -struct dsi_connector {
>> -    struct drm_connector base;
>> -    int id;
>> -};
>> -
>>   struct dsi_bridge {
>>       struct drm_bridge base;
>>       int id;
>>   };
>>
>> -#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
>>   #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
>>
>> -static inline int dsi_mgr_connector_get_id(struct drm_connector
>> *connector)
>> -{
>> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>> -    return dsi_connector->id;
>> -}
>> -
>>   static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
>>   {
>>       struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
>>       return dsi_bridge->id;
>>   }
>>
>> -static int msm_dsi_manager_panel_init(struct drm_connector *conn, u8 id)
>> +static void msm_dsi_manager_set_split_display(u8 id)
>>   {
>> -    struct msm_drm_private *priv = conn->dev->dev_private;
>> -    struct msm_kms *kms = priv->kms;
>>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>       struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
>> +    struct msm_drm_private *priv = msm_dsi->dev->dev_private;
>> +    struct msm_kms *kms = priv->kms;
>>       struct msm_dsi *master_dsi, *slave_dsi;
>> -    struct drm_panel *panel;
>>
>>       if (IS_BONDED_DSI() && !IS_MASTER_DSI_LINK(id)) {
>>           master_dsi = other_dsi;
>> @@ -256,89 +243,18 @@ static int msm_dsi_manager_panel_init(struct
>> drm_connector *conn, u8 id)
>>           slave_dsi = other_dsi;
>>       }
>>
>> -    /*
>> -     * There is only 1 panel in the global panel list for bonded DSI
>> mode.
>> -     * Therefore slave dsi should get the drm_panel instance from master
>> -     * dsi.
>> -     */
>> -    panel = msm_dsi_host_get_panel(master_dsi->host);
>> -    if (IS_ERR(panel)) {
>> -        DRM_ERROR("Could not find panel for %u (%ld)\n", msm_dsi->id,
>> -              PTR_ERR(panel));
>> -        return PTR_ERR(panel);
>> -    }
>> -
>> -    if (!panel || !IS_BONDED_DSI())
>> -        goto out;
>> -
>> -    drm_object_attach_property(&conn->base,
>> -                   conn->dev->mode_config.tile_property, 0);
>> +    if (!msm_dsi->external_bridge || !IS_BONDED_DSI())
>> +        return;
>>
>>       /*
>>        * Set split display info to kms once bonded DSI panel is
>> connected to
>>        * both hosts.
>>        */
>> -    if (other_dsi && other_dsi->panel &&
>> kms->funcs->set_split_display) {
>> +    if (other_dsi && other_dsi->external_bridge &&
>> kms->funcs->set_split_display) {
>>           kms->funcs->set_split_display(kms, master_dsi->encoder,
>>                             slave_dsi->encoder,
>>                             msm_dsi_is_cmd_mode(msm_dsi));
>>       }
>> -
>> -out:
>> -    msm_dsi->panel = panel;
>> -    return 0;
>> -}
>> -
>> -static enum drm_connector_status dsi_mgr_connector_detect(
>> -        struct drm_connector *connector, bool force)
>> -{
>> -    int id = dsi_mgr_connector_get_id(connector);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -
>> -    return msm_dsi->panel ? connector_status_connected :
>> -        connector_status_disconnected;
>> -}
>> -
>> -static void dsi_mgr_connector_destroy(struct drm_connector *connector)
>> -{
>> -    struct dsi_connector *dsi_connector = to_dsi_connector(connector);
>> -
>> -    DBG("");
>> -
>> -    drm_connector_cleanup(connector);
>> -
>> -    kfree(dsi_connector);
>> -}
>> -
>> -static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
>> -{
>> -    int id = dsi_mgr_connector_get_id(connector);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -    struct drm_panel *panel = msm_dsi->panel;
>> -    int num;
>> -
>> -    if (!panel)
>> -        return 0;
>> -
>> -    /*
>> -     * In bonded DSI mode, we have one connector that can be
>> -     * attached to the drm_panel.
>> -     */
>> -    num = drm_panel_get_modes(panel, connector);
>> -    if (!num)
>> -        return 0;
>> -
>> -    return num;
>> -}
>> -
>> -static struct drm_encoder *
>> -dsi_mgr_connector_best_encoder(struct drm_connector *connector)
>> -{
>> -    int id = dsi_mgr_connector_get_id(connector);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -
>> -    DBG("");
>> -    return msm_dsi_get_encoder(msm_dsi);
>>   }
>>
>>   static void dsi_mgr_bridge_power_on(struct drm_bridge *bridge)
>> @@ -403,7 +319,6 @@ static void dsi_mgr_bridge_pre_enable(struct
>> drm_bridge *bridge)
>>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>       struct mipi_dsi_host *host = msm_dsi->host;
>> -    struct drm_panel *panel = msm_dsi->panel;
>>       bool is_bonded_dsi = IS_BONDED_DSI();
>>       int ret;
>>
>> @@ -418,18 +333,6 @@ static void dsi_mgr_bridge_pre_enable(struct
>> drm_bridge *bridge)
>>       if (!dsi_mgr_power_on_early(bridge))
>>           dsi_mgr_bridge_power_on(bridge);
>>
>> -    /* Always call panel functions once, because even for dual panels,
>> -     * there is only one drm_panel instance.
>> -     */
>> -    if (panel) {
>> -        ret = drm_panel_prepare(panel);
>> -        if (ret) {
>> -            pr_err("%s: prepare panel %d failed, %d\n", __func__,
>> -                                id, ret);
>> -            goto panel_prep_fail;
>> -        }
>> -    }
>> -
>>       ret = msm_dsi_host_enable(host);
>>       if (ret) {
>>           pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
>> @@ -449,9 +352,6 @@ static void dsi_mgr_bridge_pre_enable(struct
>> drm_bridge *bridge)
>>   host1_en_fail:
>>       msm_dsi_host_disable(host);
>>   host_en_fail:
>> -    if (panel)
>> -        drm_panel_unprepare(panel);
>> -panel_prep_fail:
>>
>>       return;
>>   }
>> @@ -469,62 +369,12 @@ void msm_dsi_manager_tpg_enable(void)
>>       }
>>   }
>>
>> -static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
>> -{
>> -    int id = dsi_mgr_bridge_get_id(bridge);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -    struct drm_panel *panel = msm_dsi->panel;
>> -    bool is_bonded_dsi = IS_BONDED_DSI();
>> -    int ret;
>> -
>> -    DBG("id=%d", id);
>> -    if (!msm_dsi_device_connected(msm_dsi))
>> -        return;
>> -
>> -    /* Do nothing with the host if it is slave-DSI in case of bonded
>> DSI */
>> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>> -        return;
>> -
>> -    if (panel) {
>> -        ret = drm_panel_enable(panel);
>> -        if (ret) {
>> -            pr_err("%s: enable panel %d failed, %d\n", __func__, id,
>> -                                    ret);
>> -        }
>> -    }
>> -}
>> -
>> -static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
>> -{
>> -    int id = dsi_mgr_bridge_get_id(bridge);
>> -    struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>> -    struct drm_panel *panel = msm_dsi->panel;
>> -    bool is_bonded_dsi = IS_BONDED_DSI();
>> -    int ret;
>> -
>> -    DBG("id=%d", id);
>> -    if (!msm_dsi_device_connected(msm_dsi))
>> -        return;
>> -
>> -    /* Do nothing with the host if it is slave-DSI in case of bonded
>> DSI */
>> -    if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id))
>> -        return;
>> -
>> -    if (panel) {
>> -        ret = drm_panel_disable(panel);
>> -        if (ret)
>> -            pr_err("%s: Panel %d OFF failed, %d\n", __func__, id,
>> -                                    ret);
>> -    }
>> -}
>> -
>>   static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
>>   {
>>       int id = dsi_mgr_bridge_get_id(bridge);
>>       struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
>>       struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
>>       struct mipi_dsi_host *host = msm_dsi->host;
>> -    struct drm_panel *panel = msm_dsi->panel;
>>       bool is_bonded_dsi = IS_BONDED_DSI();
>>       int ret;
>>
>> @@ -551,13 +401,6 @@ static void dsi_mgr_bridge_post_disable(struct
>> drm_bridge *bridge)
>>               pr_err("%s: host1 disable failed, %d\n", __func__, ret);
>>       }
>>
>> -    if (panel) {
>> -        ret = drm_panel_unprepare(panel);
>> -        if (ret)
>> -            pr_err("%s: Panel %d unprepare failed,%d\n", __func__,
>> -                                id, ret);
>> -    }
>> -
>>       msm_dsi_host_disable_irq(host);
>>       if (is_bonded_dsi && msm_dsi1)
>>           msm_dsi_host_disable_irq(msm_dsi1->host);
>> @@ -614,76 +457,13 @@ static enum drm_mode_status
>> dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
>>       return msm_dsi_host_check_dsc(host, mode);
>>   }
>>
>> -static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
>> -    .detect = dsi_mgr_connector_detect,
>> -    .fill_modes = drm_helper_probe_single_connector_modes,
>> -    .destroy = dsi_mgr_connector_destroy,
>> -    .reset = drm_atomic_helper_connector_reset,
>> -    .atomic_duplicate_state =
>> drm_atomic_helper_connector_duplicate_state,
>> -    .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> -};
>> -
>> -static const struct drm_connector_helper_funcs
>> dsi_mgr_conn_helper_funcs = {
>> -    .get_modes = dsi_mgr_connector_get_modes,
>> -    .best_encoder = dsi_mgr_connector_best_encoder,
>> -};
>> -
>>   static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
>>       .pre_enable = dsi_mgr_bridge_pre_enable,
>> -    .enable = dsi_mgr_bridge_enable,
>> -    .disable = dsi_mgr_bridge_disable,
>>       .post_disable = dsi_mgr_bridge_post_disable,
>>       .mode_set = dsi_mgr_bridge_mode_set,
>>       .mode_valid = dsi_mgr_bridge_mode_valid,
>>   };
>>
>> -/* 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);
>> -    struct drm_connector *connector = NULL;
>> -    struct dsi_connector *dsi_connector;
>> -    int ret;
>> -
>> -    dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL);
>> -    if (!dsi_connector)
>> -        return ERR_PTR(-ENOMEM);
>> -
>> -    dsi_connector->id = id;
>> -
>> -    connector = &dsi_connector->base;
>> -
>> -    ret = drm_connector_init(msm_dsi->dev, connector,
>> -            &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
>> -    if (ret)
>> -        return ERR_PTR(ret);
>> -
>> -    drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
>> -
>> -    /* Enable HPD to let hpd event is handled
>> -     * when panel is attached to the host.
>> -     */
>> -    connector->polled = DRM_CONNECTOR_POLL_HPD;
>> -
>> -    /* Display driver doesn't support interlace now. */
>> -    connector->interlace_allowed = 0;
>> -    connector->doublescan_allowed = 0;
>> -
>> -    drm_connector_attach_encoder(connector, msm_dsi->encoder);
>> -
>> -    ret = msm_dsi_manager_panel_init(connector, id);
>> -    if (ret) {
>> -        DRM_DEV_ERROR(msm_dsi->dev->dev, "init panel failed %d\n", ret);
>> -        goto fail;
>> -    }
>> -
>> -    return connector;
>> -
>> -fail:
>> -    connector->funcs->destroy(connector);
>> -    return ERR_PTR(ret);
>> -}
>> -
>>   /* initialize bridge */
>>   struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>>   {
>> @@ -722,18 +502,21 @@ struct drm_bridge
>> *msm_dsi_manager_bridge_init(u8 id)
>>       return ERR_PTR(ret);
>>   }
>>
>> -struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
>> +int 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_connector *connector;
>>       struct drm_encoder *encoder;
>>       struct drm_bridge *int_bridge, *ext_bridge;
>>       int ret;
>>
>>       int_bridge = msm_dsi->bridge;
>> -    ext_bridge = msm_dsi->external_bridge =
>> -            msm_dsi_host_get_bridge(msm_dsi->host);
>> +    ext_bridge = devm_drm_of_get_bridge(&msm_dsi->pdev->dev,
>> +                        msm_dsi->pdev->dev.of_node, 1, 0);
>> +    if (IS_ERR(ext_bridge))
>> +        return PTR_ERR(ext_bridge);
>> +
>> +    msm_dsi->external_bridge = ext_bridge;
>>
>>       encoder = msm_dsi->encoder;
>>
>> @@ -745,36 +528,32 @@ struct drm_connector
>> *msm_dsi_manager_ext_bridge_init(u8 id)
>>       ret = drm_bridge_attach(encoder, ext_bridge, int_bridge,
>>               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>>       if (ret == -EINVAL) {
>> -        struct drm_connector *connector;
>> -        struct list_head *connector_list;
>> -
>> -        /* link the internal dsi bridge to the external bridge */
>> -        drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>> -
>>           /*
>> -         * 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()
>> +         * link the internal dsi bridge to the external bridge,
>> +         * connector is created by the next bridge.
>>            */
>> -        connector_list = &dev->mode_config.connector_list;
>> +        ret = drm_bridge_attach(encoder, ext_bridge, int_bridge, 0);
>> +        if (ret < 0)
>> +            return ret;
>> +    } else {
>> +        struct drm_connector *connector;
>>
>> -        list_for_each_entry(connector, connector_list, head) {
>> -            if (drm_connector_has_possible_encoder(connector, encoder))
>> -                return connector;
>> +        /* We are in charge of the connector, create one now. */
>> +        connector = drm_bridge_connector_init(dev, encoder);
>> +        if (IS_ERR(connector)) {
>> +            DRM_ERROR("Unable to create bridge connector\n");
>> +            return PTR_ERR(connector);
>>           }
>>
>> -        return ERR_PTR(-ENODEV);
>> -    }
>> -
>> -    connector = drm_bridge_connector_init(dev, encoder);
>> -    if (IS_ERR(connector)) {
>> -        DRM_ERROR("Unable to create bridge connector\n");
>> -        return ERR_CAST(connector);
>> +        ret = drm_connector_attach_encoder(connector, encoder);
>> +        if (ret < 0)
>> +            return ret;
>>       }
>>
>> -    drm_connector_attach_encoder(connector, encoder);
>> +    /* The pipeline is ready, ping encoders if necessary */
>> +    msm_dsi_manager_set_split_display(id);
>>
>> -    return connector;
>> +    return 0;
>>   }
>>
>>   void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
>> -- 
>> 2.35.1
>>
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-11-11 15:30       ` Caleb Connolly
  2022-11-13 10:23         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE #forregzbot Thorsten Leemhuis
@ 2022-11-13 13:28         ` Dmitry Baryshkov
  2022-11-23 10:12           ` Thorsten Leemhuis
  1 sibling, 1 reply; 25+ messages in thread
From: Dmitry Baryshkov @ 2022-11-13 13:28 UTC (permalink / raw)
  To: Caleb Connolly
  Cc: freedreno, David Airlie, linux-arm-msm, Abhinav Kumar, dri-devel,
	Stephen Boyd, Bjorn Andersson, Sean Paul

Hi Caleb,

On Fri, 11 Nov 2022 at 18:30, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
> Hi,
>
> This patch has caused a regression on 6.1-rc for some devices that use
> DSI panels. The new behaviour results in the DSI controller being
> switched off before the panel unprepare hook is called. As a result,
> panel drivers which call mipi_dsi_dcs_write() or similar in
> unprepare() fail.

Thanks for the notice. Can you move your command stream to
panel_disable() hook? (even if it's just as a temporary workaround)

From what I see from other panels, some of them call
mipi_dsi_dcs_set_display_off() in the unprepare() hook, while others
do it in disable().

Yes, this is (again) the DSI host vs device order here. Short story:
the DRM has a notion of 'the display pipe (i.e. clocks and timing
signals) feeding the bridge being running'. That's the difference
between enable/pre_enable and disable/post_disable. For the DSI we
have a third state, when the DSI clock and ln0 allow transferring
commands to the panel, but the image is not enabled.

There was a somewhat promising patchset at [1], but it seems it went
out of the radar. I can try working on an alternative (explicit)
approach if I have time.

With respect to your panel. Let me quote the docs: 'Before stopping
video transmission from the display controller it can be necessary to
turn off the panel to avoid visual glitches. This is done in the
.disable() function. Analogously to .enable() this typically involves
turning off the backlight and waiting for some time to make sure no
image is visible on the panel. It is then safe for the display
controller to cease transmission of video data.'

So, if we stop the call chain after switching the DSI host off but
before calling the panel's unprepare() hook, will we see any
artifacts/image leftover/etc. on the panel? Generally I have the
feeling that all panels should call mipi_dsi_dcs_set_display_off() in
the .disable() hook, not in the .unprepare() one.

[1] https://lore.kernel.org/dri-devel/cover.1646406653.git.dave.stevenson@raspberrypi.com/

>
> I've noticed it specifically on the OnePlus 6 (with upstream Samsung
> s0fef00 panel driver) and the SHIFT6mq with an out of tree driver.
>
> On 12/07/2022 14:22, Dmitry Baryshkov wrote:
> > Currently the DSI driver has two separate paths: one if the next device
> > in a chain is a bridge and another one if the panel is connected
> > directly to the DSI host. Simplify the code path by using panel-bridge
> > driver (already selected in Kconfig) and dropping support for
> > handling the panel directly.
> >
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> >
> > I'm not sending this as a separate patchset (I'd like to sort out mdp5
> > first), but more of a preview of changes related to
> > msm_dsi_manager_ext_bridge_init().
> >
> > ---
> >   drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
> >   drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
> >   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
> >   drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
> >   4 files changed, 36 insertions(+), 323 deletions(-)

[skipped the patch itself]

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE
  2022-11-13 13:28         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
@ 2022-11-23 10:12           ` Thorsten Leemhuis
  0 siblings, 0 replies; 25+ messages in thread
From: Thorsten Leemhuis @ 2022-11-23 10:12 UTC (permalink / raw)
  To: Dmitry Baryshkov, Caleb Connolly
  Cc: Sean Paul, David Airlie, linux-arm-msm, Abhinav Kumar, dri-devel,
	Stephen Boyd, Bjorn Andersson, freedreno

Hi, this is your Linux kernel regression tracker.

On 13.11.22 14:28, Dmitry Baryshkov wrote:
> Hi Caleb,
> 
> On Fri, 11 Nov 2022 at 18:30, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>>
>> Hi,
>>
>> This patch has caused a regression on 6.1-rc for some devices that use
>> DSI panels. The new behaviour results in the DSI controller being
>> switched off before the panel unprepare hook is called. As a result,
>> panel drivers which call mipi_dsi_dcs_write() or similar in
>> unprepare() fail.
> 
> Thanks for the notice. Can you move your command stream to
> panel_disable() hook? (even if it's just as a temporary workaround)

Caleb, did you look into what Dmitry suggested? This issue is on my list
of tracked regressions in 6.1 and time is running out to get it fixed
before the release.

Or was there any progress to get this fixed and I just missed it?

Ciao, Thorsten (wearing his 'the Linux kernel's regression tracker' hat)

P.S.: As the Linux kernel's regression tracker I deal with a lot of
reports and sometimes miss something important when writing mails like
this. If that's the case here, don't hesitate to tell me in a public
reply, it's in everyone's interest to set the public record straight.

#regzbot ignore-activity

> From what I see from other panels, some of them call
> mipi_dsi_dcs_set_display_off() in the unprepare() hook, while others
> do it in disable().
> 
> Yes, this is (again) the DSI host vs device order here. Short story:
> the DRM has a notion of 'the display pipe (i.e. clocks and timing
> signals) feeding the bridge being running'. That's the difference
> between enable/pre_enable and disable/post_disable. For the DSI we
> have a third state, when the DSI clock and ln0 allow transferring
> commands to the panel, but the image is not enabled.
> 
> There was a somewhat promising patchset at [1], but it seems it went
> out of the radar. I can try working on an alternative (explicit)
> approach if I have time.
> 
> With respect to your panel. Let me quote the docs: 'Before stopping
> video transmission from the display controller it can be necessary to
> turn off the panel to avoid visual glitches. This is done in the
> .disable() function. Analogously to .enable() this typically involves
> turning off the backlight and waiting for some time to make sure no
> image is visible on the panel. It is then safe for the display
> controller to cease transmission of video data.'
> 
> So, if we stop the call chain after switching the DSI host off but
> before calling the panel's unprepare() hook, will we see any
> artifacts/image leftover/etc. on the panel? Generally I have the
> feeling that all panels should call mipi_dsi_dcs_set_display_off() in
> the .disable() hook, not in the .unprepare() one.
> 
> [1] https://lore.kernel.org/dri-devel/cover.1646406653.git.dave.stevenson@raspberrypi.com/
> 
>>
>> I've noticed it specifically on the OnePlus 6 (with upstream Samsung
>> s0fef00 panel driver) and the SHIFT6mq with an out of tree driver.
>>
>> On 12/07/2022 14:22, Dmitry Baryshkov wrote:
>>> Currently the DSI driver has two separate paths: one if the next device
>>> in a chain is a bridge and another one if the panel is connected
>>> directly to the DSI host. Simplify the code path by using panel-bridge
>>> driver (already selected in Kconfig) and dropping support for
>>> handling the panel directly.
>>>
>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> ---
>>>
>>> I'm not sending this as a separate patchset (I'd like to sort out mdp5
>>> first), but more of a preview of changes related to
>>> msm_dsi_manager_ext_bridge_init().
>>>
>>> ---
>>>   drivers/gpu/drm/msm/dsi/dsi.c         |  35 +---
>>>   drivers/gpu/drm/msm/dsi/dsi.h         |  16 +-
>>>   drivers/gpu/drm/msm/dsi/dsi_host.c    |  25 ---
>>>   drivers/gpu/drm/msm/dsi/dsi_manager.c | 283 +++-----------------------
>>>   4 files changed, 36 insertions(+), 323 deletions(-)
> 
> [skipped the patch itself]
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE #forregzbot
  2022-11-13 10:23         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE #forregzbot Thorsten Leemhuis
@ 2022-12-08 15:26           ` Thorsten Leemhuis
  0 siblings, 0 replies; 25+ messages in thread
From: Thorsten Leemhuis @ 2022-12-08 15:26 UTC (permalink / raw)
  To: regressions; +Cc: linux-arm-msm, freedreno, dri-devel



On 13.11.22 11:23, Thorsten Leemhuis wrote:
> [Note: this mail is primarily send for documentation purposes and/or for
> regzbot, my Linux kernel regression tracking bot. That's why I removed
> most or all folks from the list of recipients, but left any that looked
> like a mailing lists. These mails usually contain '#forregzbot' in the
> subject, to make them easy to spot and filter out.]
> 
> [TLDR: I'm adding this regression report to the list of tracked
> regressions; all text from me you find below is based on a few templates
> paragraphs you might have encountered already already in similar form.]
> 
> Hi, this is your Linux kernel regression tracker.
> 
> On 11.11.22 16:30, Caleb Connolly wrote:
>>
>> This patch has caused a regression on 6.1-rc for some devices that use
>> DSI panels. The new behaviour results in the DSI controller being
>> switched off before the panel unprepare hook is called. As a result,
>> panel drivers which call mipi_dsi_dcs_write() or similar in unprepare()
>> fail.
>>
>> I've noticed it specifically on the OnePlus 6 (with upstream Samsung
>> s0fef00 panel driver) and the SHIFT6mq with an out of tree driver.
> 
> Thanks for the report. To be sure below issue doesn't fall through the
> cracks unnoticed, I'm adding it to regzbot, my Linux kernel regression
> tracking bot:
> 
> #regzbot ^introduced 007ac0262b0d
> #regzbot title drm: msm: DSI controller being switched off before the
> panel unprepare hook is called
> #regzbot ignore-activity

#regzbot inconclusive: reporter MIA


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2022-12-08 15:26 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-11  9:43 [PATCH v2 0/4] drm/msm/dsi: stop using drm_panel directly Dmitry Baryshkov
2022-07-11  9:43 ` [PATCH v2 1/4] drm/mipi-dsi: pass DSC data through the struct mipi_dsi_device Dmitry Baryshkov
2022-07-11 17:41   ` Abhinav Kumar
2022-07-11  9:43 ` [PATCH v2 2/4] drm/msm/dsi: fetch DSC pps payload from " Dmitry Baryshkov
2022-07-11 17:42   ` Abhinav Kumar
2022-07-11  9:43 ` [PATCH v2 3/4] drm/panel: drop DSC pps pointer Dmitry Baryshkov
2022-07-11 17:52   ` Abhinav Kumar
2022-07-11  9:43 ` [PATCH v2 4/4] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
2022-07-11 22:39   ` Abhinav Kumar
2022-07-11 22:54     ` [Freedreno] " Abhinav Kumar
2022-07-12 10:13       ` Dmitry Baryshkov
2022-07-12 19:53         ` Abhinav Kumar
2022-07-12 10:00     ` Dmitry Baryshkov
2022-07-12 19:15       ` [Freedreno] " Abhinav Kumar
2022-07-12 20:10         ` Dmitry Baryshkov
2022-07-12 21:21           ` Abhinav Kumar
2022-07-12 13:22     ` [PATCH v2.5] " Dmitry Baryshkov
2022-07-14 21:54       ` [Freedreno] " Abhinav Kumar
2022-08-22 17:53         ` Dmitry Baryshkov
2022-08-27 21:34           ` Abhinav Kumar
2022-11-11 15:30       ` Caleb Connolly
2022-11-13 10:23         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE #forregzbot Thorsten Leemhuis
2022-12-08 15:26           ` Thorsten Leemhuis
2022-11-13 13:28         ` [PATCH v2.5] drm/msm/dsi: switch to DRM_PANEL_BRIDGE Dmitry Baryshkov
2022-11-23 10:12           ` Thorsten Leemhuis

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).