linux-samsung-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/16]  drm/exynos: Convert driver to drm bridge
@ 2020-09-11 13:53 ` Michael Tretter
  2020-09-11 13:53   ` [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge Michael Tretter
                     ` (15 more replies)
  0 siblings, 16 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:53 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
bridge and make it usable with other drivers. Although the driver is
converted, it still supports the component framework API to stay compliant
with the Exynos DRM driver.

The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
the Exynos Decon. The driver for the LCDIF does not use the component
framework, but uses drm bridges.

I don't have any Exynos SoC to actually test the series. I build a dummy to
test the bridge with a component driver, to make sure that at least the
initialization is working. Furthermore, tested the driver as a bridge with a
few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
should verify that the driver is still working on Exynos hardware.

I also changed the order of the patches to first make the driver more platform
independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
to 13) and finally expose the API, split the code and move the platform
independent driver to the bridges (patches 14 - 16). Hopefully this simplifies
testing/bisecting and helps me to understand potential error reports.

Also I added host_ops for attach/detach and the tearing effect handler to make
the calls into the platform code more visible.

Furthermore, the series should now apply to linux-next and correctly build the
exynos_defconfig.

Thanks,

Michael

Changelog:

v2:
- rebase on linux-next
- verify with exynos_defconfig
- fix crashes reported by Marek Szyprowski Exynos3250-based Rinato
- reorder patches
- add host_ops for platform specific code
- roughly test component framework integration with dummy

Michael Tretter (16):
  drm/encoder: remove obsolete documentation of bridge
  drm/exynos: remove in_bridge_node from exynos_dsi
  drm/exynos: use exynos_dsi as drvdata
  drm/exynos: extract helper functions for probe
  drm/exynos: move dsi host registration to probe
  drm/exynos: shift register values to fields on write
  drm/exynos: use identifier instead of register offsets
  drm/exynos: add host_ops callback for platform drivers
  drm/exynos: add callback for tearing effect handler
  drm/exynos: implement a drm bridge
  drm/exynos: convert encoder functions to bridge function
  drm/exynos: configure mode on drm bridge
  drm/exynos: get encoder from bridge whenever possible
  drm/exynos: add API functions for platform drivers
  drm/exynos: split out platform specific code
  drm/exynos: move bridge driver to bridges

 drivers/gpu/drm/bridge/Kconfig          |    9 +
 drivers/gpu/drm/bridge/Makefile         |    1 +
 drivers/gpu/drm/bridge/samsung-dsim.c   | 1790 +++++++++++++++++++++
 drivers/gpu/drm/exynos/Kconfig          |    5 +-
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 1927 ++---------------------
 include/drm/bridge/samsung-dsim.h       |   64 +
 include/drm/drm_encoder.h               |    1 -
 7 files changed, 2027 insertions(+), 1770 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/samsung-dsim.c
 create mode 100644 include/drm/bridge/samsung-dsim.h

-- 
2.20.1


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

* [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
@ 2020-09-11 13:53   ` Michael Tretter
  2020-11-07 15:07     ` Adam Ford
  2020-11-07 22:17     ` Sam Ravnborg
  2020-09-11 13:53   ` [PATCH v2 02/16] drm/exynos: remove in_bridge_node from exynos_dsi Michael Tretter
                     ` (14 subsequent siblings)
  15 siblings, 2 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:53 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter, Laurent Pinchart

In commit 05193dc38197 ("drm/bridge: Make the bridge chain a
double-linked list") the bridge has been removed and replaced by a
private field. Remove the leftover documentation of the removed field.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
v2: none
---
 include/drm/drm_encoder.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
index a60f5f1555ac..5dfa5f7a80a7 100644
--- a/include/drm/drm_encoder.h
+++ b/include/drm/drm_encoder.h
@@ -89,7 +89,6 @@ struct drm_encoder_funcs {
  * @head: list management
  * @base: base KMS object
  * @name: human readable name, can be overwritten by the driver
- * @bridge: bridge associated to the encoder
  * @funcs: control functions
  * @helper_private: mid-layer private data
  *
-- 
2.20.1


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

* [PATCH v2 02/16] drm/exynos: remove in_bridge_node from exynos_dsi
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
  2020-09-11 13:53   ` [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge Michael Tretter
@ 2020-09-11 13:53   ` Michael Tretter
  2020-11-07 22:19     ` Sam Ravnborg
  2020-09-11 13:54   ` [PATCH v2 03/16] drm/exynos: use exynos_dsi as drvdata Michael Tretter
                     ` (13 subsequent siblings)
  15 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:53 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

We do not need to keep a reference to the in_bridge_node, but we can
simply drop it, once we found and attached the previous bridge.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: none
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 1a1a2853a842..29f941b02210 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -282,7 +282,6 @@ struct exynos_dsi {
 	struct list_head transfer_list;
 
 	const struct exynos_dsi_driver_data *driver_data;
-	struct device_node *in_bridge_node;
 };
 
 #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
@@ -1684,8 +1683,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
 	if (ret < 0)
 		return ret;
 
-	dsi->in_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
-
 	return 0;
 }
 
@@ -1695,6 +1692,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 	struct drm_encoder *encoder = dev_get_drvdata(dev);
 	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
 	struct drm_device *drm_dev = data;
+	struct device_node *in_bridge_node;
 	struct drm_bridge *in_bridge;
 	int ret;
 
@@ -1706,10 +1704,12 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 	if (ret < 0)
 		return ret;
 
-	if (dsi->in_bridge_node) {
-		in_bridge = of_drm_find_bridge(dsi->in_bridge_node);
+	in_bridge_node = of_graph_get_remote_node(dev->of_node, DSI_PORT_IN, 0);
+	if (in_bridge_node) {
+		in_bridge = of_drm_find_bridge(in_bridge_node);
 		if (in_bridge)
 			drm_bridge_attach(encoder, in_bridge, NULL, 0);
+		of_node_put(in_bridge_node);
 	}
 
 	return mipi_dsi_host_register(&dsi->dsi_host);
@@ -1830,17 +1830,12 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
 err_disable_runtime:
 	pm_runtime_disable(dev);
-	of_node_put(dsi->in_bridge_node);
 
 	return ret;
 }
 
 static int exynos_dsi_remove(struct platform_device *pdev)
 {
-	struct exynos_dsi *dsi = platform_get_drvdata(pdev);
-
-	of_node_put(dsi->in_bridge_node);
-
 	pm_runtime_disable(&pdev->dev);
 
 	component_del(&pdev->dev, &exynos_dsi_component_ops);
-- 
2.20.1


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

* [PATCH v2 03/16] drm/exynos: use exynos_dsi as drvdata
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
  2020-09-11 13:53   ` [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge Michael Tretter
  2020-09-11 13:53   ` [PATCH v2 02/16] drm/exynos: remove in_bridge_node from exynos_dsi Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-11-07 22:24     ` Sam Ravnborg
  2020-09-11 13:54   ` [PATCH v2 04/16] drm/exynos: extract helper functions for probe Michael Tretter
                     ` (12 subsequent siblings)
  15 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

Use the exynos_dsi as drvdata instead of the encoder to further decouple
the driver from the encoder.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: drop removal of encoder_to_dsi
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 29f941b02210..ed04064afbb2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1689,8 +1689,8 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
 static int exynos_dsi_bind(struct device *dev, struct device *master,
 				void *data)
 {
-	struct drm_encoder *encoder = dev_get_drvdata(dev);
-	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct drm_encoder *encoder = &dsi->encoder;
 	struct drm_device *drm_dev = data;
 	struct device_node *in_bridge_node;
 	struct drm_bridge *in_bridge;
@@ -1718,8 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 static void exynos_dsi_unbind(struct device *dev, struct device *master,
 				void *data)
 {
-	struct drm_encoder *encoder = dev_get_drvdata(dev);
-	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct drm_encoder *encoder = &dsi->encoder;
 
 	exynos_dsi_disable(encoder);
 
@@ -1818,7 +1818,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	platform_set_drvdata(pdev, &dsi->encoder);
+	platform_set_drvdata(pdev, dsi);
 
 	pm_runtime_enable(dev);
 
@@ -1845,8 +1845,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
 
 static int __maybe_unused exynos_dsi_suspend(struct device *dev)
 {
-	struct drm_encoder *encoder = dev_get_drvdata(dev);
-	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+	struct exynos_dsi *dsi = dev_get_drvdata(dev);
 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
 	int ret, i;
 
@@ -1876,8 +1875,7 @@ static int __maybe_unused exynos_dsi_suspend(struct device *dev)
 
 static int __maybe_unused exynos_dsi_resume(struct device *dev)
 {
-	struct drm_encoder *encoder = dev_get_drvdata(dev);
-	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
+	struct exynos_dsi *dsi = dev_get_drvdata(dev);
 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
 	int ret, i;
 
-- 
2.20.1


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

* [PATCH v2 04/16] drm/exynos: extract helper functions for probe
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (2 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 03/16] drm/exynos: use exynos_dsi as drvdata Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-11-07 22:27     ` Sam Ravnborg
  2020-09-11 13:54   ` [PATCH v2 05/16] drm/exynos: move dsi host registration to probe Michael Tretter
                     ` (11 subsequent siblings)
  15 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

As the driver shall be usable with drivers that use the component
framework and drivers that don't, split the common probing code into a
separate function that can be called from different locations.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2:
- move pm_runtime_enable from helper to calling function
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 40 ++++++++++++++++++-------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index ed04064afbb2..f8e64b74a6dd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1731,7 +1731,7 @@ static const struct component_ops exynos_dsi_component_ops = {
 	.unbind	= exynos_dsi_unbind,
 };
 
-static int exynos_dsi_probe(struct platform_device *pdev)
+static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
@@ -1740,7 +1740,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
 	if (!dsi)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	/* To be checked as invalid one */
 	dsi->te_gpio = -ENOENT;
@@ -1763,14 +1763,14 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 	if (ret) {
 		if (ret != -EPROBE_DEFER)
 			dev_info(dev, "failed to get regulators: %d\n", ret);
-		return ret;
+		return ERR_PTR(ret);
 	}
 
 	dsi->clks = devm_kcalloc(dev,
 			dsi->driver_data->num_clks, sizeof(*dsi->clks),
 			GFP_KERNEL);
 	if (!dsi->clks)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	for (i = 0; i < dsi->driver_data->num_clks; i++) {
 		dsi->clks[i] = devm_clk_get(dev, clk_names[i]);
@@ -1784,7 +1784,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
 			dev_info(dev, "failed to get the clock: %s\n",
 					clk_names[i]);
-			return PTR_ERR(dsi->clks[i]);
+			return ERR_PTR(PTR_ERR(dsi->clks[i]));
 		}
 	}
 
@@ -1792,18 +1792,18 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 	dsi->reg_base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(dsi->reg_base)) {
 		dev_err(dev, "failed to remap io region\n");
-		return PTR_ERR(dsi->reg_base);
+		return dsi->reg_base;
 	}
 
 	dsi->phy = devm_phy_get(dev, "dsim");
 	if (IS_ERR(dsi->phy)) {
 		dev_info(dev, "failed to get dsim phy\n");
-		return PTR_ERR(dsi->phy);
+		return ERR_PTR(PTR_ERR(dsi->phy));
 	}
 
 	dsi->irq = platform_get_irq(pdev, 0);
 	if (dsi->irq < 0)
-		return dsi->irq;
+		return ERR_PTR(dsi->irq);
 
 	irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
 	ret = devm_request_threaded_irq(dev, dsi->irq, NULL,
@@ -1811,13 +1811,29 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 					dev_name(dev), dsi);
 	if (ret) {
 		dev_err(dev, "failed to request dsi irq\n");
-		return ret;
+		return ERR_PTR(ret);
 	}
 
 	ret = exynos_dsi_parse_dt(dsi);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
+
+	return dsi;
+}
+
+static void __exynos_dsi_remove(struct exynos_dsi *dsi)
+{
+}
 
+static int exynos_dsi_probe(struct platform_device *pdev)
+{
+	struct exynos_dsi *dsi;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	dsi = __exynos_dsi_probe(pdev);
+	if (IS_ERR(dsi))
+		return PTR_ERR(dsi);
 	platform_set_drvdata(pdev, dsi);
 
 	pm_runtime_enable(dev);
@@ -1836,8 +1852,12 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
 static int exynos_dsi_remove(struct platform_device *pdev)
 {
+	struct exynos_dsi *dsi = platform_get_drvdata(pdev);
+
 	pm_runtime_disable(&pdev->dev);
 
+	__exynos_dsi_remove(dsi);
+
 	component_del(&pdev->dev, &exynos_dsi_component_ops);
 
 	return 0;
-- 
2.20.1


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

* [PATCH v2 05/16] drm/exynos: move dsi host registration to probe
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (3 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 04/16] drm/exynos: extract helper functions for probe Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-11 13:54   ` [PATCH v2 06/16] drm/exynos: shift register values to fields on write Michael Tretter
                     ` (10 subsequent siblings)
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

Once the driver implements a drm_bridge, the bridge will be attached
during bind. The driver has to register the mipi dsi host before making
the driver available at the component framework, because the bridge is
only initialized when a mipi dsi device attaches.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: none
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index f8e64b74a6dd..41000214a5fe 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1712,7 +1712,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 		of_node_put(in_bridge_node);
 	}
 
-	return mipi_dsi_host_register(&dsi->dsi_host);
+	return 0;
 }
 
 static void exynos_dsi_unbind(struct device *dev, struct device *master,
@@ -1722,8 +1722,6 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master,
 	struct drm_encoder *encoder = &dsi->encoder;
 
 	exynos_dsi_disable(encoder);
-
-	mipi_dsi_host_unregister(&dsi->dsi_host);
 }
 
 static const struct component_ops exynos_dsi_component_ops = {
@@ -1818,11 +1816,16 @@ static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
 	if (ret)
 		return ERR_PTR(ret);
 
+	ret = mipi_dsi_host_register(&dsi->dsi_host);
+	if (ret)
+		return ERR_PTR(ret);
+
 	return dsi;
 }
 
 static void __exynos_dsi_remove(struct exynos_dsi *dsi)
 {
+	mipi_dsi_host_unregister(&dsi->dsi_host);
 }
 
 static int exynos_dsi_probe(struct platform_device *pdev)
-- 
2.20.1


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

* [PATCH v2 06/16] drm/exynos: shift register values to fields on write
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (4 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 05/16] drm/exynos: move dsi host registration to probe Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-11-07 22:39     ` Sam Ravnborg
  2020-09-11 13:54   ` [PATCH v2 07/16] drm/exynos: use identifier instead of register offsets Michael Tretter
                     ` (9 subsequent siblings)
  15 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

The phy timings are already shifted to the field position. If the driver
is reused on multiple platforms, this exposes the field positions to the
platform code.

Store only the timing values in the platform data and shift the value to
the field when writing the fields to the registers.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: none
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 88 +++++++++++++------------
 1 file changed, 46 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 41000214a5fe..0f2cac7ed944 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -399,54 +399,54 @@ static const unsigned int reg_values[] = {
 	[RESET_TYPE] = DSIM_SWRST,
 	[PLL_TIMER] = 500,
 	[STOP_STATE_CNT] = 0xf,
-	[PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x0af),
+	[PHYCTRL_ULPS_EXIT] = 0x0af,
 	[PHYCTRL_VREG_LP] = 0,
 	[PHYCTRL_SLEW_UP] = 0,
-	[PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x06),
-	[PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0b),
-	[PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x07),
-	[PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x27),
-	[PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0d),
-	[PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x08),
-	[PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x09),
-	[PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x0d),
-	[PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0b),
+	[PHYTIMING_LPX] = 0x06,
+	[PHYTIMING_HS_EXIT] = 0x0b,
+	[PHYTIMING_CLK_PREPARE] = 0x07,
+	[PHYTIMING_CLK_ZERO] = 0x27,
+	[PHYTIMING_CLK_POST] = 0x0d,
+	[PHYTIMING_CLK_TRAIL] = 0x08,
+	[PHYTIMING_HS_PREPARE] = 0x09,
+	[PHYTIMING_HS_ZERO] = 0x0d,
+	[PHYTIMING_HS_TRAIL] = 0x0b,
 };
 
 static const unsigned int exynos5422_reg_values[] = {
 	[RESET_TYPE] = DSIM_SWRST,
 	[PLL_TIMER] = 500,
 	[STOP_STATE_CNT] = 0xf,
-	[PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0xaf),
+	[PHYCTRL_ULPS_EXIT] = 0xaf,
 	[PHYCTRL_VREG_LP] = 0,
 	[PHYCTRL_SLEW_UP] = 0,
-	[PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x08),
-	[PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0d),
-	[PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x09),
-	[PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x30),
-	[PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0e),
-	[PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x0a),
-	[PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x0c),
-	[PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x11),
-	[PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0d),
+	[PHYTIMING_LPX] = 0x08,
+	[PHYTIMING_HS_EXIT] = 0x0d,
+	[PHYTIMING_CLK_PREPARE] = 0x09,
+	[PHYTIMING_CLK_ZERO] = 0x30,
+	[PHYTIMING_CLK_POST] = 0x0e,
+	[PHYTIMING_CLK_TRAIL] = 0x0a,
+	[PHYTIMING_HS_PREPARE] = 0x0c,
+	[PHYTIMING_HS_ZERO] = 0x11,
+	[PHYTIMING_HS_TRAIL] = 0x0d,
 };
 
 static const unsigned int exynos5433_reg_values[] = {
 	[RESET_TYPE] = DSIM_FUNCRST,
 	[PLL_TIMER] = 22200,
 	[STOP_STATE_CNT] = 0xa,
-	[PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x190),
-	[PHYCTRL_VREG_LP] = DSIM_PHYCTRL_B_DPHYCTL_VREG_LP,
-	[PHYCTRL_SLEW_UP] = DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP,
-	[PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x07),
-	[PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0c),
-	[PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x09),
-	[PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x2d),
-	[PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0e),
-	[PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x09),
-	[PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x0b),
-	[PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x10),
-	[PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0c),
+	[PHYCTRL_ULPS_EXIT] = 0x190,
+	[PHYCTRL_VREG_LP] = 1,
+	[PHYCTRL_SLEW_UP] = 1,
+	[PHYTIMING_LPX] = 0x07,
+	[PHYTIMING_HS_EXIT] = 0x0c,
+	[PHYTIMING_CLK_PREPARE] = 0x09,
+	[PHYTIMING_CLK_ZERO] = 0x2d,
+	[PHYTIMING_CLK_POST] = 0x0e,
+	[PHYTIMING_CLK_TRAIL] = 0x09,
+	[PHYTIMING_HS_PREPARE] = 0x0b,
+	[PHYTIMING_HS_ZERO] = 0x10,
+	[PHYTIMING_HS_TRAIL] = 0x0c,
 };
 
 static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
@@ -698,8 +698,11 @@ static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi)
 		return;
 
 	/* B D-PHY: D-PHY Master & Slave Analog Block control */
-	reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] |
-		reg_values[PHYCTRL_SLEW_UP];
+	reg = DSIM_PHYCTRL_ULPS_EXIT(reg_values[PHYCTRL_ULPS_EXIT]);
+	if (reg_values[PHYCTRL_VREG_LP])
+		reg |= DSIM_PHYCTRL_B_DPHYCTL_VREG_LP;
+	if (reg_values[PHYCTRL_SLEW_UP])
+		reg |= DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP;
 	exynos_dsi_write(dsi, DSIM_PHYCTRL_REG, reg);
 
 	/*
@@ -707,7 +710,8 @@ static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi)
 	 * T HS-EXIT: Time that the transmitter drives LP-11 following a HS
 	 *	burst
 	 */
-	reg = reg_values[PHYTIMING_LPX] | reg_values[PHYTIMING_HS_EXIT];
+	reg = DSIM_PHYTIMING_LPX(reg_values[PHYTIMING_LPX]) |
+		DSIM_PHYTIMING_HS_EXIT(reg_values[PHYTIMING_HS_EXIT]);
 	exynos_dsi_write(dsi, DSIM_PHYTIMING_REG, reg);
 
 	/*
@@ -723,11 +727,10 @@ static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi)
 	 * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after
 	 *	the last payload clock bit of a HS transmission burst
 	 */
-	reg = reg_values[PHYTIMING_CLK_PREPARE] |
-		reg_values[PHYTIMING_CLK_ZERO] |
-		reg_values[PHYTIMING_CLK_POST] |
-		reg_values[PHYTIMING_CLK_TRAIL];
-
+	reg = DSIM_PHYTIMING1_CLK_PREPARE(reg_values[PHYTIMING_CLK_PREPARE]) |
+		DSIM_PHYTIMING1_CLK_ZERO(reg_values[PHYTIMING_CLK_ZERO]) |
+		DSIM_PHYTIMING1_CLK_POST(reg_values[PHYTIMING_CLK_POST]) |
+		DSIM_PHYTIMING1_CLK_TRAIL(reg_values[PHYTIMING_CLK_TRAIL]);
 	exynos_dsi_write(dsi, DSIM_PHYTIMING1_REG, reg);
 
 	/*
@@ -739,8 +742,9 @@ static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi)
 	 * T HS-TRAIL: Time that the transmitter drives the flipped differential
 	 *	state after last payload data bit of a HS transmission burst
 	 */
-	reg = reg_values[PHYTIMING_HS_PREPARE] | reg_values[PHYTIMING_HS_ZERO] |
-		reg_values[PHYTIMING_HS_TRAIL];
+	reg = DSIM_PHYTIMING2_HS_PREPARE(reg_values[PHYTIMING_HS_PREPARE]) |
+		DSIM_PHYTIMING2_HS_ZERO(reg_values[PHYTIMING_HS_ZERO]) |
+		DSIM_PHYTIMING2_HS_TRAIL(reg_values[PHYTIMING_HS_TRAIL]);
 	exynos_dsi_write(dsi, DSIM_PHYTIMING2_REG, reg);
 }
 
-- 
2.20.1


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

* [PATCH v2 07/16] drm/exynos: use identifier instead of register offsets
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (5 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 06/16] drm/exynos: shift register values to fields on write Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-11 13:54   ` [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers Michael Tretter
                     ` (8 subsequent siblings)
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

Different revisions of the MIPI-DSI PHY have slightly different register
layouts. Currently, the register layout was stored per platform, which
makes it necessary to define the layout for each new platform.

Keep the register layout in the driver and use identifiers to specify
which register layout shall be used on a platform.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: none
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 54 ++++++++++++++++---------
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 0f2cac7ed944..1a15ae71205d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -239,8 +239,13 @@ struct exynos_dsi_transfer {
 #define DSIM_STATE_CMD_LPM		BIT(2)
 #define DSIM_STATE_VIDOUT_AVAILABLE	BIT(3)
 
+enum exynos_reg_offset {
+	EXYNOS_REG_OFS,
+	EXYNOS5433_REG_OFS
+};
+
 struct exynos_dsi_driver_data {
-	const unsigned int *reg_ofs;
+	enum exynos_reg_offset reg_ofs;
 	unsigned int plltmr_reg;
 	unsigned int has_freqband:1;
 	unsigned int has_clklane_stop:1;
@@ -317,18 +322,6 @@ enum reg_idx {
 	NUM_REGS
 };
 
-static inline void exynos_dsi_write(struct exynos_dsi *dsi, enum reg_idx idx,
-				    u32 val)
-{
-
-	writel(val, dsi->reg_base + dsi->driver_data->reg_ofs[idx]);
-}
-
-static inline u32 exynos_dsi_read(struct exynos_dsi *dsi, enum reg_idx idx)
-{
-	return readl(dsi->reg_base + dsi->driver_data->reg_ofs[idx]);
-}
-
 static const unsigned int exynos_reg_ofs[] = {
 	[DSIM_STATUS_REG] =  0x00,
 	[DSIM_SWRST_REG] =  0x04,
@@ -377,6 +370,31 @@ static const unsigned int exynos5433_reg_ofs[] = {
 	[DSIM_PHYTIMING2_REG] = 0xBC,
 };
 
+static inline void exynos_dsi_write(struct exynos_dsi *dsi, enum reg_idx idx,
+				    u32 val)
+{
+	const unsigned int *reg_ofs;
+
+	if (dsi->driver_data->reg_ofs == EXYNOS5433_REG_OFS)
+		reg_ofs = exynos5433_reg_ofs;
+	else
+		reg_ofs = exynos_reg_ofs;
+
+	writel(val, dsi->reg_base + reg_ofs[idx]);
+}
+
+static inline u32 exynos_dsi_read(struct exynos_dsi *dsi, enum reg_idx idx)
+{
+	const unsigned int *reg_ofs;
+
+	if (dsi->driver_data->reg_ofs == EXYNOS5433_REG_OFS)
+		reg_ofs = exynos5433_reg_ofs;
+	else
+		reg_ofs = exynos_reg_ofs;
+
+	return readl(dsi->reg_base + reg_ofs[idx]);
+}
+
 enum reg_value_idx {
 	RESET_TYPE,
 	PLL_TIMER,
@@ -450,7 +468,7 @@ static const unsigned int exynos5433_reg_values[] = {
 };
 
 static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
-	.reg_ofs = exynos_reg_ofs,
+	.reg_ofs = EXYNOS_REG_OFS,
 	.plltmr_reg = 0x50,
 	.has_freqband = 1,
 	.has_clklane_stop = 1,
@@ -462,7 +480,7 @@ static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
 };
 
 static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
-	.reg_ofs = exynos_reg_ofs,
+	.reg_ofs = EXYNOS_REG_OFS,
 	.plltmr_reg = 0x50,
 	.has_freqband = 1,
 	.has_clklane_stop = 1,
@@ -474,7 +492,7 @@ static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
 };
 
 static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
-	.reg_ofs = exynos_reg_ofs,
+	.reg_ofs = EXYNOS_REG_OFS,
 	.plltmr_reg = 0x58,
 	.num_clks = 2,
 	.max_freq = 1000,
@@ -484,7 +502,7 @@ static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
 };
 
 static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
-	.reg_ofs = exynos5433_reg_ofs,
+	.reg_ofs = EXYNOS5433_REG_OFS,
 	.plltmr_reg = 0xa0,
 	.has_clklane_stop = 1,
 	.num_clks = 5,
@@ -495,7 +513,7 @@ static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
 };
 
 static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
-	.reg_ofs = exynos5433_reg_ofs,
+	.reg_ofs = EXYNOS5433_REG_OFS,
 	.plltmr_reg = 0xa0,
 	.has_clklane_stop = 1,
 	.num_clks = 2,
-- 
2.20.1


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

* [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (6 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 07/16] drm/exynos: use identifier instead of register offsets Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-15 17:07     ` Andrzej Hajda
  2020-09-11 13:54   ` [PATCH v2 09/16] drm/exynos: add callback for tearing effect handler Michael Tretter
                     ` (7 subsequent siblings)
  15 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

Platform drivers need to be aware if a mipi dsi device attaches or
detaches. Add host_ops to the driver_data for attach and detach
callbacks and move the i80 mode selection and the hotplug handling into
the callback, because these depend on the drm driver.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2:
- new patch
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 64 ++++++++++++++++++++-----
 1 file changed, 53 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 1a15ae71205d..684a2fbef08a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -239,6 +239,12 @@ struct exynos_dsi_transfer {
 #define DSIM_STATE_CMD_LPM		BIT(2)
 #define DSIM_STATE_VIDOUT_AVAILABLE	BIT(3)
 
+struct exynos_dsi;
+struct exynos_dsi_host_ops {
+	int (*attach)(struct device *dev, struct mipi_dsi_device *device);
+	int (*detach)(struct device *dev, struct mipi_dsi_device *device);
+};
+
 enum exynos_reg_offset {
 	EXYNOS_REG_OFS,
 	EXYNOS5433_REG_OFS
@@ -254,6 +260,7 @@ struct exynos_dsi_driver_data {
 	unsigned int wait_for_reset;
 	unsigned int num_bits_resol;
 	const unsigned int *reg_values;
+	const struct exynos_dsi_host_ops *host_ops;
 };
 
 struct exynos_dsi {
@@ -467,6 +474,41 @@ static const unsigned int exynos5433_reg_values[] = {
 	[PHYTIMING_HS_TRAIL] = 0x0c,
 };
 
+static int __exynos_dsi_host_attach(struct device *dev,
+				    struct mipi_dsi_device *device)
+{
+	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct drm_device *drm = dsi->encoder.dev;
+	struct exynos_drm_crtc *crtc;
+
+	mutex_lock(&drm->mode_config.mutex);
+	crtc = exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD);
+	crtc->i80_mode = !(device->mode_flags & MIPI_DSI_MODE_VIDEO);
+	mutex_unlock(&drm->mode_config.mutex);
+
+	if (drm->mode_config.poll_enabled)
+		drm_kms_helper_hotplug_event(drm);
+
+	return 0;
+}
+
+static int __exynos_dsi_host_detach(struct device *dev,
+				     struct mipi_dsi_device *device)
+{
+	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct drm_device *drm = dsi->encoder.dev;
+
+	if (drm->mode_config.poll_enabled)
+		drm_kms_helper_hotplug_event(drm);
+
+	return 0;
+}
+
+static const struct exynos_dsi_host_ops exynos_dsi_host_ops = {
+	.attach = __exynos_dsi_host_attach,
+	.detach = __exynos_dsi_host_detach,
+};
+
 static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
 	.reg_ofs = EXYNOS_REG_OFS,
 	.plltmr_reg = 0x50,
@@ -477,6 +519,7 @@ static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
 	.wait_for_reset = 1,
 	.num_bits_resol = 11,
 	.reg_values = reg_values,
+	.host_ops = &exynos_dsi_host_ops,
 };
 
 static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
@@ -489,6 +532,7 @@ static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
 	.wait_for_reset = 1,
 	.num_bits_resol = 11,
 	.reg_values = reg_values,
+	.host_ops = &exynos_dsi_host_ops,
 };
 
 static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
@@ -499,6 +543,7 @@ static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
 	.wait_for_reset = 1,
 	.num_bits_resol = 11,
 	.reg_values = reg_values,
+	.host_ops = &exynos_dsi_host_ops,
 };
 
 static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
@@ -510,6 +555,7 @@ static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
 	.wait_for_reset = 0,
 	.num_bits_resol = 12,
 	.reg_values = exynos5433_reg_values,
+	.host_ops = &exynos_dsi_host_ops,
 };
 
 static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
@@ -521,6 +567,7 @@ static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
 	.wait_for_reset = 1,
 	.num_bits_resol = 12,
 	.reg_values = exynos5422_reg_values,
+	.host_ops = &exynos_dsi_host_ops,
 };
 
 static const struct of_device_id exynos_dsi_of_match[] = {
@@ -1551,8 +1598,8 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 				  struct mipi_dsi_device *device)
 {
 	struct exynos_dsi *dsi = host_to_dsi(host);
+	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
 	struct drm_encoder *encoder = &dsi->encoder;
-	struct drm_device *drm = encoder->dev;
 	struct drm_bridge *out_bridge;
 
 	out_bridge  = of_drm_find_bridge(device->dev.of_node);
@@ -1590,18 +1637,12 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 			return ret;
 	}
 
-	mutex_lock(&drm->mode_config.mutex);
-
 	dsi->lanes = device->lanes;
 	dsi->format = device->format;
 	dsi->mode_flags = device->mode_flags;
-	exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
-			!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
 
-	mutex_unlock(&drm->mode_config.mutex);
-
-	if (drm->mode_config.poll_enabled)
-		drm_kms_helper_hotplug_event(drm);
+	if (ops && ops->attach)
+		ops->attach(dsi->dsi_host.dev, device);
 
 	return 0;
 }
@@ -1610,6 +1651,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
 				  struct mipi_dsi_device *device)
 {
 	struct exynos_dsi *dsi = host_to_dsi(host);
+	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
 	struct drm_device *drm = dsi->encoder.dev;
 
 	if (dsi->panel) {
@@ -1625,8 +1667,8 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
 		INIT_LIST_HEAD(&dsi->bridge_chain);
 	}
 
-	if (drm->mode_config.poll_enabled)
-		drm_kms_helper_hotplug_event(drm);
+	if (ops && ops->detach)
+		ops->detach(dsi->dsi_host.dev, device);
 
 	exynos_dsi_unregister_te_irq(dsi);
 
-- 
2.20.1


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

* [PATCH v2 09/16] drm/exynos: add callback for tearing effect handler
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (7 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-11 13:54   ` [PATCH v2 10/16] drm/exynos: implement a drm bridge Michael Tretter
                     ` (6 subsequent siblings)
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

The tearing effect interrupts are not handled by the MIPI DSI bridge
driver, but the display controller driver.

Allow platforms to register a callback for the tearing effect interrupt.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2:
- add handler as callback in host_ops
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 684a2fbef08a..2d75f9877dc0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -243,6 +243,7 @@ struct exynos_dsi;
 struct exynos_dsi_host_ops {
 	int (*attach)(struct device *dev, struct mipi_dsi_device *device);
 	int (*detach)(struct device *dev, struct mipi_dsi_device *device);
+	void (*te_handler)(struct device *dev);
 };
 
 enum exynos_reg_offset {
@@ -504,9 +505,17 @@ static int __exynos_dsi_host_detach(struct device *dev,
 	return 0;
 }
 
+static void __exynos_dsi_te_handler(struct device *dev)
+{
+	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+
+	exynos_drm_crtc_te_handler(dsi->encoder.crtc);
+}
+
 static const struct exynos_dsi_host_ops exynos_dsi_host_ops = {
 	.attach = __exynos_dsi_host_attach,
 	.detach = __exynos_dsi_host_detach,
+	.te_handler = __exynos_dsi_te_handler,
 };
 
 static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
@@ -1354,11 +1363,12 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
 
 static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
 {
-	struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
-	struct drm_encoder *encoder = &dsi->encoder;
+	struct exynos_dsi *dsi = dev_id;
+	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
 
-	if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE)
-		exynos_drm_crtc_te_handler(encoder->crtc);
+	if (ops && ops->te_handler &&
+	    (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE))
+		ops->te_handler(dsi->dsi_host.dev);
 
 	return IRQ_HANDLED;
 }
-- 
2.20.1


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

* [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (8 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 09/16] drm/exynos: add callback for tearing effect handler Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-14  8:29     ` Marek Szyprowski
  2020-09-11 13:54   ` [PATCH v2 11/16] drm/exynos: convert encoder functions to bridge function Michael Tretter
                     ` (5 subsequent siblings)
  15 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

Make the exynos_dsi driver a full drm bridge that can be found and used
from other drivers.

Other drivers can only attach to the bridge, if a mipi dsi device
already attached to the bridge. This allows to defer the probe of the
display pipe until the downstream bridges are available, too.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2:
- move attach of out_bridge to bridge_attach
- add bridge_detach
- don't cleanup encoder if create_connector failed
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 103 +++++++++++++++++-------
 1 file changed, 75 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 2d75f9877dc0..5e7c1a99a3ee 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -266,6 +266,7 @@ struct exynos_dsi_driver_data {
 
 struct exynos_dsi {
 	struct drm_encoder encoder;
+	struct drm_bridge bridge;
 	struct mipi_dsi_host dsi_host;
 	struct drm_connector connector;
 	struct drm_panel *panel;
@@ -1602,6 +1603,60 @@ static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
 	.disable = exynos_dsi_disable,
 };
 
+static int exynos_dsi_bridge_attach(struct drm_bridge *bridge,
+				    enum drm_bridge_attach_flags flags)
+{
+	struct exynos_dsi *dsi = bridge->driver_private;
+	struct drm_encoder *encoder = bridge->encoder;
+	int ret;
+
+	if (!dsi->out_bridge && !dsi->panel)
+		return -EPROBE_DEFER;
+
+	if (dsi->out_bridge) {
+		ret = drm_bridge_attach(encoder, dsi->out_bridge,
+					bridge, flags);
+		if (ret)
+			return ret;
+		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
+	} else {
+		ret = exynos_dsi_create_connector(encoder);
+		if (ret)
+			return ret;
+
+		if (dsi->panel) {
+			dsi->connector.status = connector_status_connected;
+		}
+	}
+
+	return 0;
+}
+
+static void exynos_dsi_bridge_detach(struct drm_bridge *bridge)
+{
+	struct exynos_dsi *dsi = bridge->driver_private;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_device *drm = encoder->dev;
+
+	if (dsi->panel) {
+		mutex_lock(&drm->mode_config.mutex);
+		exynos_dsi_disable(&dsi->encoder);
+		dsi->panel = NULL;
+		dsi->connector.status = connector_status_disconnected;
+		mutex_unlock(&drm->mode_config.mutex);
+	} else {
+		if (dsi->out_bridge->funcs->detach)
+			dsi->out_bridge->funcs->detach(dsi->out_bridge);
+		dsi->out_bridge = NULL;
+		INIT_LIST_HEAD(&dsi->bridge_chain);
+	}
+}
+
+static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
+	.attach = exynos_dsi_bridge_attach,
+	.detach = exynos_dsi_bridge_detach,
+};
+
 MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
 
 static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
@@ -1609,25 +1664,12 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 {
 	struct exynos_dsi *dsi = host_to_dsi(host);
 	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
-	struct drm_encoder *encoder = &dsi->encoder;
 	struct drm_bridge *out_bridge;
 
-	out_bridge  = of_drm_find_bridge(device->dev.of_node);
+	out_bridge = of_drm_find_bridge(device->dev.of_node);
 	if (out_bridge) {
-		drm_bridge_attach(encoder, out_bridge, NULL, 0);
 		dsi->out_bridge = out_bridge;
-		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
 	} else {
-		int ret = exynos_dsi_create_connector(encoder);
-
-		if (ret) {
-			DRM_DEV_ERROR(dsi->dev,
-				      "failed to create connector ret = %d\n",
-				      ret);
-			drm_encoder_cleanup(encoder);
-			return ret;
-		}
-
 		dsi->panel = of_drm_find_panel(device->dev.of_node);
 		if (IS_ERR(dsi->panel))
 			dsi->panel = NULL;
@@ -1662,20 +1704,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
 {
 	struct exynos_dsi *dsi = host_to_dsi(host);
 	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
-	struct drm_device *drm = dsi->encoder.dev;
-
-	if (dsi->panel) {
-		mutex_lock(&drm->mode_config.mutex);
-		exynos_dsi_disable(&dsi->encoder);
-		dsi->panel = NULL;
-		dsi->connector.status = connector_status_disconnected;
-		mutex_unlock(&drm->mode_config.mutex);
-	} else {
-		if (dsi->out_bridge->funcs->detach)
-			dsi->out_bridge->funcs->detach(dsi->out_bridge);
-		dsi->out_bridge = NULL;
-		INIT_LIST_HEAD(&dsi->bridge_chain);
-	}
 
 	if (ops && ops->detach)
 		ops->detach(dsi->dsi_host.dev, device);
@@ -1786,7 +1814,15 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 		of_node_put(in_bridge_node);
 	}
 
+	ret = drm_bridge_attach(encoder, &dsi->bridge, in_bridge, 0);
+	if (ret)
+		goto err;
+
 	return 0;
+
+err:
+	drm_encoder_cleanup(encoder);
+	return ret;
 }
 
 static void exynos_dsi_unbind(struct device *dev, struct device *master,
@@ -1796,6 +1832,8 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master,
 	struct drm_encoder *encoder = &dsi->encoder;
 
 	exynos_dsi_disable(encoder);
+
+	drm_encoder_cleanup(encoder);
 }
 
 static const struct component_ops exynos_dsi_component_ops = {
@@ -1806,6 +1844,7 @@ static const struct component_ops exynos_dsi_component_ops = {
 static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct drm_bridge *bridge;
 	struct resource *res;
 	struct exynos_dsi *dsi;
 	int ret, i;
@@ -1894,11 +1933,19 @@ static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
 	if (ret)
 		return ERR_PTR(ret);
 
+	bridge = &dsi->bridge;
+	bridge->driver_private = dsi;
+	bridge->funcs = &exynos_dsi_bridge_funcs;
+	bridge->of_node = dev->of_node;
+	drm_bridge_add(bridge);
+
 	return dsi;
 }
 
 static void __exynos_dsi_remove(struct exynos_dsi *dsi)
 {
+	drm_bridge_remove(&dsi->bridge);
+
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 }
 
-- 
2.20.1


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

* [PATCH v2 11/16] drm/exynos: convert encoder functions to bridge function
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (9 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 10/16] drm/exynos: implement a drm bridge Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-11 13:54   ` [PATCH v2 12/16] drm/exynos: configure mode on drm bridge Michael Tretter
                     ` (4 subsequent siblings)
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

If other drivers use the exynos_dsi driver as a bridge, they might bring
their own encoder. Enable and disable the MIPI-DSI bridge using the
bridge functions instead of the encoder functions.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: none
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 33 +++++++++++++++----------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 5e7c1a99a3ee..a4f17d50d1d8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1455,9 +1455,8 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi)
 	}
 }
 
-static void exynos_dsi_enable(struct drm_encoder *encoder)
+static void exynos_dsi_enable(struct exynos_dsi *dsi)
 {
-	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
 	struct drm_bridge *iter;
 	int ret;
 
@@ -1505,9 +1504,8 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
 	pm_runtime_put(dsi->dev);
 }
 
-static void exynos_dsi_disable(struct drm_encoder *encoder)
+static void exynos_dsi_disable(struct exynos_dsi *dsi)
 {
-	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
 	struct drm_bridge *iter;
 
 	if (!(dsi->state & DSIM_STATE_ENABLED))
@@ -1598,11 +1596,6 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
 	return 0;
 }
 
-static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
-	.enable = exynos_dsi_enable,
-	.disable = exynos_dsi_disable,
-};
-
 static int exynos_dsi_bridge_attach(struct drm_bridge *bridge,
 				    enum drm_bridge_attach_flags flags)
 {
@@ -1640,7 +1633,7 @@ static void exynos_dsi_bridge_detach(struct drm_bridge *bridge)
 
 	if (dsi->panel) {
 		mutex_lock(&drm->mode_config.mutex);
-		exynos_dsi_disable(&dsi->encoder);
+		exynos_dsi_disable(dsi);
 		dsi->panel = NULL;
 		dsi->connector.status = connector_status_disconnected;
 		mutex_unlock(&drm->mode_config.mutex);
@@ -1652,9 +1645,25 @@ static void exynos_dsi_bridge_detach(struct drm_bridge *bridge)
 	}
 }
 
+static void exynos_dsi_bridge_enable(struct drm_bridge *bridge)
+{
+	struct exynos_dsi *dsi = bridge->driver_private;
+
+	exynos_dsi_enable(dsi);
+}
+
+static void exynos_dsi_bridge_disable(struct drm_bridge *bridge)
+{
+	struct exynos_dsi *dsi = bridge->driver_private;
+
+	exynos_dsi_disable(dsi);
+}
+
 static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
 	.attach = exynos_dsi_bridge_attach,
 	.detach = exynos_dsi_bridge_detach,
+	.enable = exynos_dsi_bridge_enable,
+	.disable = exynos_dsi_bridge_disable,
 };
 
 MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
@@ -1800,8 +1809,6 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 
 	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
 
-	drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
-
 	ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
 	if (ret < 0)
 		return ret;
@@ -1831,7 +1838,7 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master,
 	struct exynos_dsi *dsi = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &dsi->encoder;
 
-	exynos_dsi_disable(encoder);
+	exynos_dsi_disable(dsi);
 
 	drm_encoder_cleanup(encoder);
 }
-- 
2.20.1


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

* [PATCH v2 12/16] drm/exynos: configure mode on drm bridge
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (10 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 11/16] drm/exynos: convert encoder functions to bridge function Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-11 13:54   ` [PATCH v2 13/16] drm/exynos: get encoder from bridge whenever possible Michael Tretter
                     ` (3 subsequent siblings)
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

The driver uses the encoder to get the mode that shall be configured.
This is not possible, if the driver is used as a bridge, because the
encoder might not be used.

Use the mode_set function to set the display mode.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: none
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index a4f17d50d1d8..988447812333 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -288,6 +288,8 @@ struct exynos_dsi {
 	u32 mode_flags;
 	u32 format;
 
+	struct drm_display_mode mode;
+
 	int state;
 	struct drm_property *brightness;
 	struct completion completed;
@@ -961,7 +963,7 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi)
 
 static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi)
 {
-	struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode;
+	struct drm_display_mode *m = &dsi->mode;
 	unsigned int num_bits_resol = dsi->driver_data->num_bits_resol;
 	u32 reg;
 
@@ -1659,11 +1661,22 @@ static void exynos_dsi_bridge_disable(struct drm_bridge *bridge)
 	exynos_dsi_disable(dsi);
 }
 
+static void exynos_dsi_bridge_mode_set(struct drm_bridge *bridge,
+				       const struct drm_display_mode *mode,
+				       const struct drm_display_mode *adjusted_mode)
+{
+	struct exynos_dsi *dsi = bridge->driver_private;
+
+	/* The mode is set when actually enabling the device. */
+	drm_mode_copy(&dsi->mode, adjusted_mode);
+}
+
 static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
 	.attach = exynos_dsi_bridge_attach,
 	.detach = exynos_dsi_bridge_detach,
 	.enable = exynos_dsi_bridge_enable,
 	.disable = exynos_dsi_bridge_disable,
+	.mode_set = exynos_dsi_bridge_mode_set,
 };
 
 MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
-- 
2.20.1


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

* [PATCH v2 13/16] drm/exynos: get encoder from bridge whenever possible
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (11 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 12/16] drm/exynos: configure mode on drm bridge Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-11 13:54   ` [PATCH v2 14/16] drm/exynos: add API functions for platform drivers Michael Tretter
                     ` (2 subsequent siblings)
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

The bridge will not necessarily use the encoder of struct exynos_dsi,
but might use another encoder from another drm driver. Therefore, the
driver has to use the encoder from the bridge instead of the one from
exynos_dsi.

In the future, the struct exynos_dsi will not have an encoder at all.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2:
- add removal of encoder_to_dsi
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 988447812333..b9216785b2d7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -303,11 +303,6 @@ struct exynos_dsi {
 #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
 #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
 
-static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e)
-{
-	return container_of(e, struct exynos_dsi, encoder);
-}
-
 enum reg_idx {
 	DSIM_STATUS_REG,	/* Status register */
 	DSIM_SWRST_REG,		/* Software reset register */
@@ -1570,11 +1565,10 @@ static const struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs
 	.get_modes = exynos_dsi_get_modes,
 };
 
-static int exynos_dsi_create_connector(struct drm_encoder *encoder)
+static int exynos_dsi_create_connector(struct exynos_dsi *dsi)
 {
-	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
 	struct drm_connector *connector = &dsi->connector;
-	struct drm_device *drm = encoder->dev;
+	struct drm_device *drm = dsi->bridge.dev;
 	int ret;
 
 	connector->polled = DRM_CONNECTOR_POLL_HPD;
@@ -1589,7 +1583,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)
 
 	connector->status = connector_status_disconnected;
 	drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
-	drm_connector_attach_encoder(connector, encoder);
+	drm_connector_attach_encoder(connector, dsi->bridge.encoder);
 	if (!drm->registered)
 		return 0;
 
@@ -1615,7 +1609,7 @@ static int exynos_dsi_bridge_attach(struct drm_bridge *bridge,
 			return ret;
 		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
 	} else {
-		ret = exynos_dsi_create_connector(encoder);
+		ret = exynos_dsi_create_connector(dsi);
 		if (ret)
 			return ret;
 
-- 
2.20.1


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

* [PATCH v2 14/16] drm/exynos: add API functions for platform drivers
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (12 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 13/16] drm/exynos: get encoder from bridge whenever possible Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-09-11 13:54   ` [PATCH v2 15/16] drm/exynos: split out platform specific code Michael Tretter
  2020-11-09  3:15   ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Inki Dae
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

Add new functions for the probe/remove API, the bind/unbind API and
resume/suspend calls. Move everything exynos drm specific into separate
functions, which can easily be moved to other files.

Also split struct exynos_dsi into a generic and a platform specific
struct.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2:
- new patch
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 114 +++++++++++++++++-------
 1 file changed, 82 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index b9216785b2d7..ad70f5ce81ad 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -265,7 +265,6 @@ struct exynos_dsi_driver_data {
 };
 
 struct exynos_dsi {
-	struct drm_encoder encoder;
 	struct drm_bridge bridge;
 	struct mipi_dsi_host dsi_host;
 	struct drm_connector connector;
@@ -419,6 +418,11 @@ enum reg_value_idx {
 	PHYTIMING_HS_TRAIL
 };
 
+struct exynos_dsi_pltfm {
+	struct exynos_dsi *dsi;
+	struct drm_encoder encoder;
+};
+
 static const unsigned int reg_values[] = {
 	[RESET_TYPE] = DSIM_SWRST,
 	[PLL_TIMER] = 500,
@@ -476,7 +480,7 @@ static const unsigned int exynos5433_reg_values[] = {
 static int __exynos_dsi_host_attach(struct device *dev,
 				    struct mipi_dsi_device *device)
 {
-	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
 	struct drm_device *drm = dsi->encoder.dev;
 	struct exynos_drm_crtc *crtc;
 
@@ -494,7 +498,7 @@ static int __exynos_dsi_host_attach(struct device *dev,
 static int __exynos_dsi_host_detach(struct device *dev,
 				     struct mipi_dsi_device *device)
 {
-	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
 	struct drm_device *drm = dsi->encoder.dev;
 
 	if (drm->mode_config.poll_enabled)
@@ -505,7 +509,7 @@ static int __exynos_dsi_host_detach(struct device *dev,
 
 static void __exynos_dsi_te_handler(struct device *dev)
 {
-	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
 
 	exynos_drm_crtc_te_handler(dsi->encoder.crtc);
 }
@@ -1804,10 +1808,12 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
 	return 0;
 }
 
-static int exynos_dsi_bind(struct device *dev, struct device *master,
-				void *data)
+static int exynos_dsi_bind(struct exynos_dsi *dsi, struct drm_encoder *encoder);
+static void exynos_dsi_unbind(struct exynos_dsi *dsi);
+
+static int exynos_dsi_pltfm_bind(struct device *dev, struct device *master, void *data)
 {
-	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &dsi->encoder;
 	struct drm_device *drm_dev = data;
 	struct device_node *in_bridge_node;
@@ -1828,7 +1834,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 		of_node_put(in_bridge_node);
 	}
 
-	ret = drm_bridge_attach(encoder, &dsi->bridge, in_bridge, 0);
+	ret = exynos_dsi_bind(dsi->dsi, encoder);
 	if (ret)
 		goto err;
 
@@ -1839,20 +1845,20 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 	return ret;
 }
 
-static void exynos_dsi_unbind(struct device *dev, struct device *master,
-				void *data)
+static void exynos_dsi_pltfm_unbind(struct device *dev, struct device *master,
+				    void *data)
 {
-	struct exynos_dsi *dsi = dev_get_drvdata(dev);
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &dsi->encoder;
 
-	exynos_dsi_disable(dsi);
+	exynos_dsi_unbind(dsi->dsi);
 
 	drm_encoder_cleanup(encoder);
 }
 
-static const struct component_ops exynos_dsi_component_ops = {
-	.bind	= exynos_dsi_bind,
-	.unbind	= exynos_dsi_unbind,
+static const struct component_ops exynos_dsi_pltfm_component_ops = {
+	.bind	= exynos_dsi_pltfm_bind,
+	.unbind	= exynos_dsi_pltfm_unbind,
 };
 
 static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
@@ -1963,20 +1969,52 @@ static void __exynos_dsi_remove(struct exynos_dsi *dsi)
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 }
 
-static int exynos_dsi_probe(struct platform_device *pdev)
+/*
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+static struct exynos_dsi *exynos_dsi_probe(struct platform_device *pdev)
 {
-	struct exynos_dsi *dsi;
+	return __exynos_dsi_probe(pdev);
+}
+
+static void exynos_dsi_remove(struct exynos_dsi *dsi)
+{
+	return __exynos_dsi_remove(dsi);
+}
+
+/*
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+static int exynos_dsi_bind(struct exynos_dsi *dsi, struct drm_encoder *encoder)
+{
+	struct drm_bridge *previous = drm_bridge_chain_get_first_bridge(encoder);
+
+	return drm_bridge_attach(encoder, &dsi->bridge, previous, 0);
+}
+
+static void exynos_dsi_unbind(struct exynos_dsi *dsi)
+{
+	exynos_dsi_disable(dsi);
+}
+
+static int exynos_dsi_pltfm_probe(struct platform_device *pdev)
+{
+	struct exynos_dsi_pltfm *dsi;
 	struct device *dev = &pdev->dev;
 	int ret;
 
-	dsi = __exynos_dsi_probe(pdev);
-	if (IS_ERR(dsi))
-		return PTR_ERR(dsi);
+	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
 	platform_set_drvdata(pdev, dsi);
 
+	dsi->dsi = exynos_dsi_probe(pdev);
+	if (IS_ERR(dsi->dsi))
+		return PTR_ERR(dsi->dsi);
+
 	pm_runtime_enable(dev);
 
-	ret = component_add(dev, &exynos_dsi_component_ops);
+	ret = component_add(dev, &exynos_dsi_pltfm_component_ops);
 	if (ret)
 		goto err_disable_runtime;
 
@@ -1988,22 +2026,21 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int exynos_dsi_remove(struct platform_device *pdev)
+static int exynos_dsi_pltfm_remove(struct platform_device *pdev)
 {
-	struct exynos_dsi *dsi = platform_get_drvdata(pdev);
+	struct exynos_dsi_pltfm *dsi = platform_get_drvdata(pdev);
 
 	pm_runtime_disable(&pdev->dev);
 
-	__exynos_dsi_remove(dsi);
+	exynos_dsi_remove(dsi->dsi);
 
-	component_del(&pdev->dev, &exynos_dsi_component_ops);
+	component_del(&pdev->dev, &exynos_dsi_pltfm_component_ops);
 
 	return 0;
 }
 
-static int __maybe_unused exynos_dsi_suspend(struct device *dev)
+static int exynos_dsi_suspend(struct exynos_dsi *dsi)
 {
-	struct exynos_dsi *dsi = dev_get_drvdata(dev);
 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
 	int ret, i;
 
@@ -2031,9 +2068,8 @@ static int __maybe_unused exynos_dsi_suspend(struct device *dev)
 	return 0;
 }
 
-static int __maybe_unused exynos_dsi_resume(struct device *dev)
+static int exynos_dsi_resume(struct exynos_dsi *dsi)
 {
-	struct exynos_dsi *dsi = dev_get_drvdata(dev);
 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
 	int ret, i;
 
@@ -2065,15 +2101,29 @@ static int __maybe_unused exynos_dsi_resume(struct device *dev)
 	return ret;
 }
 
+static int __maybe_unused exynos_dsi_pltfm_suspend(struct device *dev)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+
+	return exynos_dsi_suspend(dsi->dsi);
+}
+
+static int __maybe_unused exynos_dsi_pltfm_resume(struct device *dev)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+
+	return exynos_dsi_resume(dsi->dsi);
+}
+
 static const struct dev_pm_ops exynos_dsi_pm_ops = {
-	SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL)
+	SET_RUNTIME_PM_OPS(exynos_dsi_pltfm_suspend, exynos_dsi_pltfm_resume, NULL)
 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 				pm_runtime_force_resume)
 };
 
 struct platform_driver dsi_driver = {
-	.probe = exynos_dsi_probe,
-	.remove = exynos_dsi_remove,
+	.probe = exynos_dsi_pltfm_probe,
+	.remove = exynos_dsi_pltfm_remove,
 	.driver = {
 		   .name = "exynos-dsi",
 		   .owner = THIS_MODULE,
-- 
2.20.1


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

* [PATCH v2 15/16] drm/exynos: split out platform specific code
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (13 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 14/16] drm/exynos: add API functions for platform drivers Michael Tretter
@ 2020-09-11 13:54   ` Michael Tretter
  2020-11-09  3:15   ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Inki Dae
  15 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-09-11 13:54 UTC (permalink / raw)
  To: dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim,
	Michael Tretter

Split the driver into the drm bridge driver and the exynos platform
specific driver.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
v2: none
---
 drivers/gpu/drm/exynos/Makefile               |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_dsi.c       | 372 +-----------------
 drivers/gpu/drm/exynos/exynos_drm_dsi.h       |  64 +++
 drivers/gpu/drm/exynos/exynos_drm_dsi_pltfm.c | 333 ++++++++++++++++
 4 files changed, 405 insertions(+), 366 deletions(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_dsi.h
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_dsi_pltfm.c

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 2fd2f3ee4fcf..add70b336935 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -11,7 +11,7 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
 exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON)	+= exynos5433_drm_decon.o
 exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON)	+= exynos7_drm_decon.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DPI)	+= exynos_drm_dpi.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_DSI)	+= exynos_drm_dsi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_DSI)	+= exynos_drm_dsi.o exynos_drm_dsi_pltfm.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DP)	+= exynos_dp.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER)	+= exynos_mixer.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index ad70f5ce81ad..e8aea9d90c34 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -32,8 +32,7 @@
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
 
-#include "exynos_drm_crtc.h"
-#include "exynos_drm_drv.h"
+#include "exynos_drm_dsi.h"
 
 /* returns true iff both arguments logically differs */
 #define NEQV(a, b) (!(a) ^ !(b))
@@ -44,10 +43,6 @@
 #define DSIM_TX_READY_HS_CLK		(1 << 10)
 #define DSIM_PLL_STABLE			(1 << 31)
 
-/* DSIM_SWRST */
-#define DSIM_FUNCRST			(1 << 16)
-#define DSIM_SWRST			(1 << 0)
-
 /* DSIM_TIMEOUT */
 #define DSIM_LPDR_TIMEOUT(x)		((x) << 0)
 #define DSIM_BTA_TIMEOUT(x)		((x) << 16)
@@ -239,31 +234,6 @@ struct exynos_dsi_transfer {
 #define DSIM_STATE_CMD_LPM		BIT(2)
 #define DSIM_STATE_VIDOUT_AVAILABLE	BIT(3)
 
-struct exynos_dsi;
-struct exynos_dsi_host_ops {
-	int (*attach)(struct device *dev, struct mipi_dsi_device *device);
-	int (*detach)(struct device *dev, struct mipi_dsi_device *device);
-	void (*te_handler)(struct device *dev);
-};
-
-enum exynos_reg_offset {
-	EXYNOS_REG_OFS,
-	EXYNOS5433_REG_OFS
-};
-
-struct exynos_dsi_driver_data {
-	enum exynos_reg_offset reg_ofs;
-	unsigned int plltmr_reg;
-	unsigned int has_freqband:1;
-	unsigned int has_clklane_stop:1;
-	unsigned int num_clks;
-	unsigned int max_freq;
-	unsigned int wait_for_reset;
-	unsigned int num_bits_resol;
-	const unsigned int *reg_values;
-	const struct exynos_dsi_host_ops *host_ops;
-};
-
 struct exynos_dsi {
 	struct drm_bridge bridge;
 	struct mipi_dsi_host dsi_host;
@@ -400,201 +370,6 @@ static inline u32 exynos_dsi_read(struct exynos_dsi *dsi, enum reg_idx idx)
 	return readl(dsi->reg_base + reg_ofs[idx]);
 }
 
-enum reg_value_idx {
-	RESET_TYPE,
-	PLL_TIMER,
-	STOP_STATE_CNT,
-	PHYCTRL_ULPS_EXIT,
-	PHYCTRL_VREG_LP,
-	PHYCTRL_SLEW_UP,
-	PHYTIMING_LPX,
-	PHYTIMING_HS_EXIT,
-	PHYTIMING_CLK_PREPARE,
-	PHYTIMING_CLK_ZERO,
-	PHYTIMING_CLK_POST,
-	PHYTIMING_CLK_TRAIL,
-	PHYTIMING_HS_PREPARE,
-	PHYTIMING_HS_ZERO,
-	PHYTIMING_HS_TRAIL
-};
-
-struct exynos_dsi_pltfm {
-	struct exynos_dsi *dsi;
-	struct drm_encoder encoder;
-};
-
-static const unsigned int reg_values[] = {
-	[RESET_TYPE] = DSIM_SWRST,
-	[PLL_TIMER] = 500,
-	[STOP_STATE_CNT] = 0xf,
-	[PHYCTRL_ULPS_EXIT] = 0x0af,
-	[PHYCTRL_VREG_LP] = 0,
-	[PHYCTRL_SLEW_UP] = 0,
-	[PHYTIMING_LPX] = 0x06,
-	[PHYTIMING_HS_EXIT] = 0x0b,
-	[PHYTIMING_CLK_PREPARE] = 0x07,
-	[PHYTIMING_CLK_ZERO] = 0x27,
-	[PHYTIMING_CLK_POST] = 0x0d,
-	[PHYTIMING_CLK_TRAIL] = 0x08,
-	[PHYTIMING_HS_PREPARE] = 0x09,
-	[PHYTIMING_HS_ZERO] = 0x0d,
-	[PHYTIMING_HS_TRAIL] = 0x0b,
-};
-
-static const unsigned int exynos5422_reg_values[] = {
-	[RESET_TYPE] = DSIM_SWRST,
-	[PLL_TIMER] = 500,
-	[STOP_STATE_CNT] = 0xf,
-	[PHYCTRL_ULPS_EXIT] = 0xaf,
-	[PHYCTRL_VREG_LP] = 0,
-	[PHYCTRL_SLEW_UP] = 0,
-	[PHYTIMING_LPX] = 0x08,
-	[PHYTIMING_HS_EXIT] = 0x0d,
-	[PHYTIMING_CLK_PREPARE] = 0x09,
-	[PHYTIMING_CLK_ZERO] = 0x30,
-	[PHYTIMING_CLK_POST] = 0x0e,
-	[PHYTIMING_CLK_TRAIL] = 0x0a,
-	[PHYTIMING_HS_PREPARE] = 0x0c,
-	[PHYTIMING_HS_ZERO] = 0x11,
-	[PHYTIMING_HS_TRAIL] = 0x0d,
-};
-
-static const unsigned int exynos5433_reg_values[] = {
-	[RESET_TYPE] = DSIM_FUNCRST,
-	[PLL_TIMER] = 22200,
-	[STOP_STATE_CNT] = 0xa,
-	[PHYCTRL_ULPS_EXIT] = 0x190,
-	[PHYCTRL_VREG_LP] = 1,
-	[PHYCTRL_SLEW_UP] = 1,
-	[PHYTIMING_LPX] = 0x07,
-	[PHYTIMING_HS_EXIT] = 0x0c,
-	[PHYTIMING_CLK_PREPARE] = 0x09,
-	[PHYTIMING_CLK_ZERO] = 0x2d,
-	[PHYTIMING_CLK_POST] = 0x0e,
-	[PHYTIMING_CLK_TRAIL] = 0x09,
-	[PHYTIMING_HS_PREPARE] = 0x0b,
-	[PHYTIMING_HS_ZERO] = 0x10,
-	[PHYTIMING_HS_TRAIL] = 0x0c,
-};
-
-static int __exynos_dsi_host_attach(struct device *dev,
-				    struct mipi_dsi_device *device)
-{
-	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
-	struct drm_device *drm = dsi->encoder.dev;
-	struct exynos_drm_crtc *crtc;
-
-	mutex_lock(&drm->mode_config.mutex);
-	crtc = exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD);
-	crtc->i80_mode = !(device->mode_flags & MIPI_DSI_MODE_VIDEO);
-	mutex_unlock(&drm->mode_config.mutex);
-
-	if (drm->mode_config.poll_enabled)
-		drm_kms_helper_hotplug_event(drm);
-
-	return 0;
-}
-
-static int __exynos_dsi_host_detach(struct device *dev,
-				     struct mipi_dsi_device *device)
-{
-	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
-	struct drm_device *drm = dsi->encoder.dev;
-
-	if (drm->mode_config.poll_enabled)
-		drm_kms_helper_hotplug_event(drm);
-
-	return 0;
-}
-
-static void __exynos_dsi_te_handler(struct device *dev)
-{
-	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
-
-	exynos_drm_crtc_te_handler(dsi->encoder.crtc);
-}
-
-static const struct exynos_dsi_host_ops exynos_dsi_host_ops = {
-	.attach = __exynos_dsi_host_attach,
-	.detach = __exynos_dsi_host_detach,
-	.te_handler = __exynos_dsi_te_handler,
-};
-
-static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
-	.reg_ofs = EXYNOS_REG_OFS,
-	.plltmr_reg = 0x50,
-	.has_freqband = 1,
-	.has_clklane_stop = 1,
-	.num_clks = 2,
-	.max_freq = 1000,
-	.wait_for_reset = 1,
-	.num_bits_resol = 11,
-	.reg_values = reg_values,
-	.host_ops = &exynos_dsi_host_ops,
-};
-
-static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
-	.reg_ofs = EXYNOS_REG_OFS,
-	.plltmr_reg = 0x50,
-	.has_freqband = 1,
-	.has_clklane_stop = 1,
-	.num_clks = 2,
-	.max_freq = 1000,
-	.wait_for_reset = 1,
-	.num_bits_resol = 11,
-	.reg_values = reg_values,
-	.host_ops = &exynos_dsi_host_ops,
-};
-
-static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
-	.reg_ofs = EXYNOS_REG_OFS,
-	.plltmr_reg = 0x58,
-	.num_clks = 2,
-	.max_freq = 1000,
-	.wait_for_reset = 1,
-	.num_bits_resol = 11,
-	.reg_values = reg_values,
-	.host_ops = &exynos_dsi_host_ops,
-};
-
-static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
-	.reg_ofs = EXYNOS5433_REG_OFS,
-	.plltmr_reg = 0xa0,
-	.has_clklane_stop = 1,
-	.num_clks = 5,
-	.max_freq = 1500,
-	.wait_for_reset = 0,
-	.num_bits_resol = 12,
-	.reg_values = exynos5433_reg_values,
-	.host_ops = &exynos_dsi_host_ops,
-};
-
-static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
-	.reg_ofs = EXYNOS5433_REG_OFS,
-	.plltmr_reg = 0xa0,
-	.has_clklane_stop = 1,
-	.num_clks = 2,
-	.max_freq = 1500,
-	.wait_for_reset = 1,
-	.num_bits_resol = 12,
-	.reg_values = exynos5422_reg_values,
-	.host_ops = &exynos_dsi_host_ops,
-};
-
-static const struct of_device_id exynos_dsi_of_match[] = {
-	{ .compatible = "samsung,exynos3250-mipi-dsi",
-	  .data = &exynos3_dsi_driver_data },
-	{ .compatible = "samsung,exynos4210-mipi-dsi",
-	  .data = &exynos4_dsi_driver_data },
-	{ .compatible = "samsung,exynos5410-mipi-dsi",
-	  .data = &exynos5_dsi_driver_data },
-	{ .compatible = "samsung,exynos5422-mipi-dsi",
-	  .data = &exynos5422_dsi_driver_data },
-	{ .compatible = "samsung,exynos5433-mipi-dsi",
-	  .data = &exynos5433_dsi_driver_data },
-	{ }
-};
-
 static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi)
 {
 	if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300)))
@@ -1677,8 +1452,6 @@ static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
 	.mode_set = exynos_dsi_bridge_mode_set,
 };
 
-MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
-
 static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 				  struct mipi_dsi_device *device)
 {
@@ -1779,11 +1552,6 @@ static int exynos_dsi_of_read_u32(const struct device_node *np,
 	return ret;
 }
 
-enum {
-	DSI_PORT_IN,
-	DSI_PORT_OUT
-};
-
 static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
 {
 	struct device *dev = dsi->dev;
@@ -1808,59 +1576,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
 	return 0;
 }
 
-static int exynos_dsi_bind(struct exynos_dsi *dsi, struct drm_encoder *encoder);
-static void exynos_dsi_unbind(struct exynos_dsi *dsi);
-
-static int exynos_dsi_pltfm_bind(struct device *dev, struct device *master, void *data)
-{
-	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
-	struct drm_encoder *encoder = &dsi->encoder;
-	struct drm_device *drm_dev = data;
-	struct device_node *in_bridge_node;
-	struct drm_bridge *in_bridge;
-	int ret;
-
-	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
-
-	ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
-	if (ret < 0)
-		return ret;
-
-	in_bridge_node = of_graph_get_remote_node(dev->of_node, DSI_PORT_IN, 0);
-	if (in_bridge_node) {
-		in_bridge = of_drm_find_bridge(in_bridge_node);
-		if (in_bridge)
-			drm_bridge_attach(encoder, in_bridge, NULL, 0);
-		of_node_put(in_bridge_node);
-	}
-
-	ret = exynos_dsi_bind(dsi->dsi, encoder);
-	if (ret)
-		goto err;
-
-	return 0;
-
-err:
-	drm_encoder_cleanup(encoder);
-	return ret;
-}
-
-static void exynos_dsi_pltfm_unbind(struct device *dev, struct device *master,
-				    void *data)
-{
-	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
-	struct drm_encoder *encoder = &dsi->encoder;
-
-	exynos_dsi_unbind(dsi->dsi);
-
-	drm_encoder_cleanup(encoder);
-}
-
-static const struct component_ops exynos_dsi_pltfm_component_ops = {
-	.bind	= exynos_dsi_pltfm_bind,
-	.unbind	= exynos_dsi_pltfm_unbind,
-};
-
 static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1972,12 +1687,12 @@ static void __exynos_dsi_remove(struct exynos_dsi *dsi)
 /*
  * Probe/remove API, used from platforms based on the DRM bridge API.
  */
-static struct exynos_dsi *exynos_dsi_probe(struct platform_device *pdev)
+struct exynos_dsi *exynos_dsi_probe(struct platform_device *pdev)
 {
 	return __exynos_dsi_probe(pdev);
 }
 
-static void exynos_dsi_remove(struct exynos_dsi *dsi)
+void exynos_dsi_remove(struct exynos_dsi *dsi)
 {
 	return __exynos_dsi_remove(dsi);
 }
@@ -1985,61 +1700,19 @@ static void exynos_dsi_remove(struct exynos_dsi *dsi)
 /*
  * Bind/unbind API, used from platforms based on the component framework.
  */
-static int exynos_dsi_bind(struct exynos_dsi *dsi, struct drm_encoder *encoder)
+int exynos_dsi_bind(struct exynos_dsi *dsi, struct drm_encoder *encoder)
 {
 	struct drm_bridge *previous = drm_bridge_chain_get_first_bridge(encoder);
 
 	return drm_bridge_attach(encoder, &dsi->bridge, previous, 0);
 }
 
-static void exynos_dsi_unbind(struct exynos_dsi *dsi)
+void exynos_dsi_unbind(struct exynos_dsi *dsi)
 {
 	exynos_dsi_disable(dsi);
 }
 
-static int exynos_dsi_pltfm_probe(struct platform_device *pdev)
-{
-	struct exynos_dsi_pltfm *dsi;
-	struct device *dev = &pdev->dev;
-	int ret;
-
-	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
-	if (!dsi)
-		return -ENOMEM;
-	platform_set_drvdata(pdev, dsi);
-
-	dsi->dsi = exynos_dsi_probe(pdev);
-	if (IS_ERR(dsi->dsi))
-		return PTR_ERR(dsi->dsi);
-
-	pm_runtime_enable(dev);
-
-	ret = component_add(dev, &exynos_dsi_pltfm_component_ops);
-	if (ret)
-		goto err_disable_runtime;
-
-	return 0;
-
-err_disable_runtime:
-	pm_runtime_disable(dev);
-
-	return ret;
-}
-
-static int exynos_dsi_pltfm_remove(struct platform_device *pdev)
-{
-	struct exynos_dsi_pltfm *dsi = platform_get_drvdata(pdev);
-
-	pm_runtime_disable(&pdev->dev);
-
-	exynos_dsi_remove(dsi->dsi);
-
-	component_del(&pdev->dev, &exynos_dsi_pltfm_component_ops);
-
-	return 0;
-}
-
-static int exynos_dsi_suspend(struct exynos_dsi *dsi)
+int exynos_dsi_suspend(struct exynos_dsi *dsi)
 {
 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
 	int ret, i;
@@ -2068,7 +1741,7 @@ static int exynos_dsi_suspend(struct exynos_dsi *dsi)
 	return 0;
 }
 
-static int exynos_dsi_resume(struct exynos_dsi *dsi)
+int exynos_dsi_resume(struct exynos_dsi *dsi)
 {
 	const struct exynos_dsi_driver_data *driver_data = dsi->driver_data;
 	int ret, i;
@@ -2101,37 +1774,6 @@ static int exynos_dsi_resume(struct exynos_dsi *dsi)
 	return ret;
 }
 
-static int __maybe_unused exynos_dsi_pltfm_suspend(struct device *dev)
-{
-	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
-
-	return exynos_dsi_suspend(dsi->dsi);
-}
-
-static int __maybe_unused exynos_dsi_pltfm_resume(struct device *dev)
-{
-	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
-
-	return exynos_dsi_resume(dsi->dsi);
-}
-
-static const struct dev_pm_ops exynos_dsi_pm_ops = {
-	SET_RUNTIME_PM_OPS(exynos_dsi_pltfm_suspend, exynos_dsi_pltfm_resume, NULL)
-	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-				pm_runtime_force_resume)
-};
-
-struct platform_driver dsi_driver = {
-	.probe = exynos_dsi_pltfm_probe,
-	.remove = exynos_dsi_pltfm_remove,
-	.driver = {
-		   .name = "exynos-dsi",
-		   .owner = THIS_MODULE,
-		   .pm = &exynos_dsi_pm_ops,
-		   .of_match_table = exynos_dsi_of_match,
-	},
-};
-
 MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
 MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
 MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.h b/drivers/gpu/drm/exynos/exynos_drm_dsi.h
new file mode 100644
index 000000000000..8fa3276889de
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __EXYNOS_DRM_DSI__
+#define __EXYNOS_DRM_DSI__
+
+struct drm_encoder;
+struct exynos_dsi;
+struct platform_device;
+struct mipi_dsi_device;
+
+enum exynos_reg_offset {
+	EXYNOS_REG_OFS,
+	EXYNOS5433_REG_OFS
+};
+
+struct exynos_dsi *exynos_dsi_probe(struct platform_device *pdev);
+void exynos_dsi_remove(struct exynos_dsi *dsi);
+int exynos_dsi_bind(struct exynos_dsi *dsi, struct drm_encoder *encoder);
+void exynos_dsi_unbind(struct exynos_dsi *dsi);
+
+int exynos_dsi_suspend(struct exynos_dsi *dsi);
+int exynos_dsi_resume(struct exynos_dsi *dsi);
+
+enum reg_value_idx {
+	RESET_TYPE,
+	PLL_TIMER,
+	STOP_STATE_CNT,
+	PHYCTRL_ULPS_EXIT,
+	PHYCTRL_VREG_LP,
+	PHYCTRL_SLEW_UP,
+	PHYTIMING_LPX,
+	PHYTIMING_HS_EXIT,
+	PHYTIMING_CLK_PREPARE,
+	PHYTIMING_CLK_ZERO,
+	PHYTIMING_CLK_POST,
+	PHYTIMING_CLK_TRAIL,
+	PHYTIMING_HS_PREPARE,
+	PHYTIMING_HS_ZERO,
+	PHYTIMING_HS_TRAIL
+};
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST			(1 << 16)
+#define DSIM_SWRST			(1 << 0)
+
+struct exynos_dsi_host_ops {
+	int (*attach)(struct device *dev, struct mipi_dsi_device *device);
+	int (*detach)(struct device *dev, struct mipi_dsi_device *device);
+	void (*te_handler)(struct device *dev);
+};
+
+struct exynos_dsi_driver_data {
+	enum exynos_reg_offset reg_ofs;
+	unsigned int plltmr_reg;
+	unsigned int has_freqband:1;
+	unsigned int has_clklane_stop:1;
+	unsigned int num_clks;
+	unsigned int max_freq;
+	unsigned int wait_for_reset;
+	unsigned int num_bits_resol;
+	const unsigned int *reg_values;
+	const struct exynos_dsi_host_ops *host_ops;
+};
+
+#endif /* __EXYNOS_DRM_DSI__ */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi_pltfm.c b/drivers/gpu/drm/exynos/exynos_drm_dsi_pltfm.c
new file mode 100644
index 000000000000..79d9ec6ade45
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi_pltfm.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Samsung SoC MIPI DSI Master driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Contacts: Tomasz Figa <t.figa@samsung.com>
+ */
+
+#include <linux/component.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "exynos_drm_crtc.h"
+#include "exynos_drm_drv.h"
+#include "exynos_drm_dsi.h"
+
+enum {
+	DSI_PORT_IN,
+	DSI_PORT_OUT
+};
+
+struct exynos_dsi_pltfm {
+	struct exynos_dsi *dsi;
+	struct drm_encoder encoder;
+};
+
+static const unsigned int reg_values[] = {
+	[RESET_TYPE] = DSIM_SWRST,
+	[PLL_TIMER] = 500,
+	[STOP_STATE_CNT] = 0xf,
+	[PHYCTRL_ULPS_EXIT] = 0x0af,
+	[PHYCTRL_VREG_LP] = 0,
+	[PHYCTRL_SLEW_UP] = 0,
+	[PHYTIMING_LPX] = 0x06,
+	[PHYTIMING_HS_EXIT] = 0x0b,
+	[PHYTIMING_CLK_PREPARE] = 0x07,
+	[PHYTIMING_CLK_ZERO] = 0x27,
+	[PHYTIMING_CLK_POST] = 0x0d,
+	[PHYTIMING_CLK_TRAIL] = 0x08,
+	[PHYTIMING_HS_PREPARE] = 0x09,
+	[PHYTIMING_HS_ZERO] = 0x0d,
+	[PHYTIMING_HS_TRAIL] = 0x0b,
+};
+
+static const unsigned int exynos5422_reg_values[] = {
+	[RESET_TYPE] = DSIM_SWRST,
+	[PLL_TIMER] = 500,
+	[STOP_STATE_CNT] = 0xf,
+	[PHYCTRL_ULPS_EXIT] = 0xaf,
+	[PHYCTRL_VREG_LP] = 0,
+	[PHYCTRL_SLEW_UP] = 0,
+	[PHYTIMING_LPX] = 0x08,
+	[PHYTIMING_HS_EXIT] = 0x0d,
+	[PHYTIMING_CLK_PREPARE] = 0x09,
+	[PHYTIMING_CLK_ZERO] = 0x30,
+	[PHYTIMING_CLK_POST] = 0x0e,
+	[PHYTIMING_CLK_TRAIL] = 0x0a,
+	[PHYTIMING_HS_PREPARE] = 0x0c,
+	[PHYTIMING_HS_ZERO] = 0x11,
+	[PHYTIMING_HS_TRAIL] = 0x0d,
+};
+
+static const unsigned int exynos5433_reg_values[] = {
+	[RESET_TYPE] = DSIM_FUNCRST,
+	[PLL_TIMER] = 22200,
+	[STOP_STATE_CNT] = 0xa,
+	[PHYCTRL_ULPS_EXIT] = 0x190,
+	[PHYCTRL_VREG_LP] = 1,
+	[PHYCTRL_SLEW_UP] = 1,
+	[PHYTIMING_LPX] = 0x07,
+	[PHYTIMING_HS_EXIT] = 0x0c,
+	[PHYTIMING_CLK_PREPARE] = 0x09,
+	[PHYTIMING_CLK_ZERO] = 0x2d,
+	[PHYTIMING_CLK_POST] = 0x0e,
+	[PHYTIMING_CLK_TRAIL] = 0x09,
+	[PHYTIMING_HS_PREPARE] = 0x0b,
+	[PHYTIMING_HS_ZERO] = 0x10,
+	[PHYTIMING_HS_TRAIL] = 0x0c,
+};
+
+static int __exynos_dsi_host_attach(struct device *dev,
+				    struct mipi_dsi_device *device)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+	struct drm_device *drm = dsi->encoder.dev;
+	struct exynos_drm_crtc *crtc;
+
+	mutex_lock(&drm->mode_config.mutex);
+	crtc = exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD);
+	crtc->i80_mode = !(device->mode_flags & MIPI_DSI_MODE_VIDEO);
+	mutex_unlock(&drm->mode_config.mutex);
+
+	if (drm->mode_config.poll_enabled)
+		drm_kms_helper_hotplug_event(drm);
+
+	return 0;
+}
+
+static int __exynos_dsi_host_detach(struct device *dev,
+				    struct mipi_dsi_device *device)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+	struct drm_device *drm = dsi->encoder.dev;
+
+	if (drm->mode_config.poll_enabled)
+		drm_kms_helper_hotplug_event(drm);
+
+	return 0;
+}
+
+static void __exynos_dsi_te_handler(struct device *dev)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+
+	exynos_drm_crtc_te_handler(dsi->encoder.crtc);
+}
+
+static const struct exynos_dsi_host_ops exynos_dsi_host_ops = {
+	.attach = __exynos_dsi_host_attach,
+	.detach = __exynos_dsi_host_detach,
+	.te_handler = __exynos_dsi_te_handler,
+};
+
+static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
+	.reg_ofs = EXYNOS_REG_OFS,
+	.plltmr_reg = 0x50,
+	.has_freqband = 1,
+	.has_clklane_stop = 1,
+	.num_clks = 2,
+	.max_freq = 1000,
+	.wait_for_reset = 1,
+	.num_bits_resol = 11,
+	.reg_values = reg_values,
+	.host_ops = &exynos_dsi_host_ops,
+};
+
+static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
+	.reg_ofs = EXYNOS_REG_OFS,
+	.plltmr_reg = 0x50,
+	.has_freqband = 1,
+	.has_clklane_stop = 1,
+	.num_clks = 2,
+	.max_freq = 1000,
+	.wait_for_reset = 1,
+	.num_bits_resol = 11,
+	.reg_values = reg_values,
+	.host_ops = &exynos_dsi_host_ops,
+};
+
+static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
+	.reg_ofs = EXYNOS_REG_OFS,
+	.plltmr_reg = 0x58,
+	.num_clks = 2,
+	.max_freq = 1000,
+	.wait_for_reset = 1,
+	.num_bits_resol = 11,
+	.reg_values = reg_values,
+	.host_ops = &exynos_dsi_host_ops,
+};
+
+static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
+	.reg_ofs = EXYNOS5433_REG_OFS,
+	.plltmr_reg = 0xa0,
+	.has_clklane_stop = 1,
+	.num_clks = 5,
+	.max_freq = 1500,
+	.wait_for_reset = 0,
+	.num_bits_resol = 12,
+	.reg_values = exynos5433_reg_values,
+	.host_ops = &exynos_dsi_host_ops,
+};
+
+static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
+	.reg_ofs = EXYNOS5433_REG_OFS,
+	.plltmr_reg = 0xa0,
+	.has_clklane_stop = 1,
+	.num_clks = 2,
+	.max_freq = 1500,
+	.wait_for_reset = 1,
+	.num_bits_resol = 12,
+	.reg_values = exynos5422_reg_values,
+	.host_ops = &exynos_dsi_host_ops,
+};
+
+static const struct of_device_id exynos_dsi_of_match[] = {
+	{ .compatible = "samsung,exynos3250-mipi-dsi",
+	  .data = &exynos3_dsi_driver_data },
+	{ .compatible = "samsung,exynos4210-mipi-dsi",
+	  .data = &exynos4_dsi_driver_data },
+	{ .compatible = "samsung,exynos5410-mipi-dsi",
+	  .data = &exynos5_dsi_driver_data },
+	{ .compatible = "samsung,exynos5422-mipi-dsi",
+	  .data = &exynos5422_dsi_driver_data },
+	{ .compatible = "samsung,exynos5433-mipi-dsi",
+	  .data = &exynos5433_dsi_driver_data },
+	{ }
+};
+
+static int exynos_dsi_pltfm_bind(struct device *dev, struct device *master, void *data)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+	struct drm_encoder *encoder = &dsi->encoder;
+	struct drm_device *drm_dev = data;
+	struct device_node *in_bridge_node;
+	struct drm_bridge *in_bridge;
+	int ret;
+
+	drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS);
+
+	ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD);
+	if (ret < 0)
+		return ret;
+
+	in_bridge_node = of_graph_get_remote_node(dev->of_node, DSI_PORT_IN, 0);
+	if (in_bridge_node) {
+		in_bridge = of_drm_find_bridge(in_bridge_node);
+		if (in_bridge)
+			drm_bridge_attach(encoder, in_bridge, NULL, 0);
+		of_node_put(in_bridge_node);
+	}
+
+	ret = exynos_dsi_bind(dsi->dsi, encoder);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	drm_encoder_cleanup(encoder);
+	return ret;
+}
+
+static void exynos_dsi_pltfm_unbind(struct device *dev, struct device *master,
+				    void *data)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+	struct drm_encoder *encoder = &dsi->encoder;
+
+	exynos_dsi_unbind(dsi->dsi);
+
+	drm_encoder_cleanup(encoder);
+}
+
+static const struct component_ops exynos_dsi_pltfm_component_ops = {
+	.bind	= exynos_dsi_pltfm_bind,
+	.unbind	= exynos_dsi_pltfm_unbind,
+};
+
+static int exynos_dsi_pltfm_probe(struct platform_device *pdev)
+{
+	struct exynos_dsi_pltfm *dsi;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, dsi);
+
+	dsi->dsi = exynos_dsi_probe(pdev);
+	if (IS_ERR(dsi->dsi))
+		return PTR_ERR(dsi->dsi);
+
+	pm_runtime_enable(dev);
+
+	ret = component_add(dev, &exynos_dsi_pltfm_component_ops);
+	if (ret)
+		goto err_disable_runtime;
+
+	return 0;
+
+err_disable_runtime:
+	pm_runtime_disable(dev);
+
+	return ret;
+}
+
+static int exynos_dsi_pltfm_remove(struct platform_device *pdev)
+{
+	struct exynos_dsi_pltfm *dsi = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+
+	exynos_dsi_remove(dsi->dsi);
+
+	component_del(&pdev->dev, &exynos_dsi_pltfm_component_ops);
+
+	return 0;
+}
+
+static int __maybe_unused exynos_dsi_pltfm_suspend(struct device *dev)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+
+	return exynos_dsi_suspend(dsi->dsi);
+}
+
+static int __maybe_unused exynos_dsi_pltfm_resume(struct device *dev)
+{
+	struct exynos_dsi_pltfm *dsi = dev_get_drvdata(dev);
+
+	return exynos_dsi_resume(dsi->dsi);
+}
+
+static const struct dev_pm_ops exynos_dsi_pm_ops = {
+	SET_RUNTIME_PM_OPS(exynos_dsi_pltfm_suspend, exynos_dsi_pltfm_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+struct platform_driver dsi_driver = {
+	.probe = exynos_dsi_pltfm_probe,
+	.remove = exynos_dsi_pltfm_remove,
+	.driver = {
+		   .name = "exynos-dsi",
+		   .owner = THIS_MODULE,
+		   .pm = &exynos_dsi_pm_ops,
+		   .of_match_table = exynos_dsi_of_match,
+	},
+};
+
+MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master");
+MODULE_LICENSE("GPL v2");
-- 
2.20.1


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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2020-09-11 13:54   ` [PATCH v2 10/16] drm/exynos: implement a drm bridge Michael Tretter
@ 2020-09-14  8:29     ` Marek Szyprowski
  2020-09-14 12:31       ` Marek Szyprowski
  0 siblings, 1 reply; 57+ messages in thread
From: Marek Szyprowski @ 2020-09-14  8:29 UTC (permalink / raw)
  To: Michael Tretter, dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim

Hi Michael,

On 11.09.2020 15:54, Michael Tretter wrote:
> Make the exynos_dsi driver a full drm bridge that can be found and used
> from other drivers.
>
> Other drivers can only attach to the bridge, if a mipi dsi device
> already attached to the bridge. This allows to defer the probe of the
> display pipe until the downstream bridges are available, too.
>
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>

This one (and the whole series applied) still fails on Exynos boards:

[drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
OF: graph: no port node found in /soc/dsi@11c80000
8<--- cut here ---
Unable to handle kernel NULL pointer dereference at virtual address 00000084
pgd = (ptrval)
[00000084] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 1 PID: 1 Comm: swapper/0 Not tainted 
5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
Hardware name: Samsung Exynos (Flattened Device Tree)
PC is at drm_bridge_attach+0x18/0x164
LR is at exynos_dsi_bind+0x88/0xa8
pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
sp : ef0dfca8  ip : 00000002  fp : c13190e0
r10: 00000000  r9 : ee46d580  r8 : c13190e0
r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c5387d  Table: 4000404a  DAC: 00000051
Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
Stack: (0xef0dfca8 to 0xef0e0000)
...
[<c0628c08>] (drm_bridge_attach) from [<c064d560>] 
(exynos_dsi_bind+0x88/0xa8)
[<c064d560>] (exynos_dsi_bind) from [<c066a800>] 
(component_bind_all+0xfc/0x290)
[<c066a800>] (component_bind_all) from [<c0649dc0>] 
(exynos_drm_bind+0xe4/0x19c)
[<c0649dc0>] (exynos_drm_bind) from [<c066ad74>] 
(try_to_bring_up_master+0x1e4/0x2c4)
[<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>] 
(component_master_add_with_match+0xd4/0x108)
[<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>] 
(exynos_drm_platform_probe+0xe4/0x110)
[<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>] 
(platform_drv_probe+0x6c/0xa4)
[<c0674e6c>] (platform_drv_probe) from [<c067242c>] 
(really_probe+0x200/0x4fc)
[<c067242c>] (really_probe) from [<c06728f0>] 
(driver_probe_device+0x78/0x1fc)
[<c06728f0>] (driver_probe_device) from [<c0672cd8>] 
(device_driver_attach+0x58/0x60)
[<c0672cd8>] (device_driver_attach) from [<c0672dbc>] 
(__driver_attach+0xdc/0x174)
[<c0672dbc>] (__driver_attach) from [<c06701b4>] 
(bus_for_each_dev+0x68/0xb4)
[<c06701b4>] (bus_for_each_dev) from [<c06714e8>] 
(bus_add_driver+0x158/0x214)
[<c06714e8>] (bus_add_driver) from [<c0673c1c>] (driver_register+0x78/0x110)
[<c0673c1c>] (driver_register) from [<c0649ca8>] 
(exynos_drm_init+0xe4/0x118)
[<c0649ca8>] (exynos_drm_init) from [<c0102484>] 
(do_one_initcall+0x8c/0x42c)
[<c0102484>] (do_one_initcall) from [<c11011c0>] 
(kernel_init_freeable+0x190/0x1dc)
[<c11011c0>] (kernel_init_freeable) from [<c0af7880>] 
(kernel_init+0x8/0x118)
[<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
Exception stack(0xef0dffb0 to 0xef0dfff8)
...
---[ end trace ee27f313f9ed9da1 ]---

# arm-linux-gnueabi-addr2line -e vmlinux c0628c08
drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)

I will try to debug it a bit more today.

> ---
> v2:
> - move attach of out_bridge to bridge_attach
> - add bridge_detach
> - don't cleanup encoder if create_connector failed
> ---
>   drivers/gpu/drm/exynos/exynos_drm_dsi.c | 103 +++++++++++++++++-------
>   1 file changed, 75 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index 2d75f9877dc0..5e7c1a99a3ee 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -266,6 +266,7 @@ struct exynos_dsi_driver_data {
>   
>   struct exynos_dsi {
>   	struct drm_encoder encoder;
> +	struct drm_bridge bridge;
>   	struct mipi_dsi_host dsi_host;
>   	struct drm_connector connector;
>   	struct drm_panel *panel;
> @@ -1602,6 +1603,60 @@ static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
>   	.disable = exynos_dsi_disable,
>   };
>   
> +static int exynos_dsi_bridge_attach(struct drm_bridge *bridge,
> +				    enum drm_bridge_attach_flags flags)
> +{
> +	struct exynos_dsi *dsi = bridge->driver_private;
> +	struct drm_encoder *encoder = bridge->encoder;
> +	int ret;
> +
> +	if (!dsi->out_bridge && !dsi->panel)
> +		return -EPROBE_DEFER;
> +
> +	if (dsi->out_bridge) {
> +		ret = drm_bridge_attach(encoder, dsi->out_bridge,
> +					bridge, flags);
> +		if (ret)
> +			return ret;
> +		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
> +	} else {
> +		ret = exynos_dsi_create_connector(encoder);
> +		if (ret)
> +			return ret;
> +
> +		if (dsi->panel) {
> +			dsi->connector.status = connector_status_connected;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos_dsi_bridge_detach(struct drm_bridge *bridge)
> +{
> +	struct exynos_dsi *dsi = bridge->driver_private;
> +	struct drm_encoder *encoder = bridge->encoder;
> +	struct drm_device *drm = encoder->dev;
> +
> +	if (dsi->panel) {
> +		mutex_lock(&drm->mode_config.mutex);
> +		exynos_dsi_disable(&dsi->encoder);
> +		dsi->panel = NULL;
> +		dsi->connector.status = connector_status_disconnected;
> +		mutex_unlock(&drm->mode_config.mutex);
> +	} else {
> +		if (dsi->out_bridge->funcs->detach)
> +			dsi->out_bridge->funcs->detach(dsi->out_bridge);
> +		dsi->out_bridge = NULL;
> +		INIT_LIST_HEAD(&dsi->bridge_chain);
> +	}
> +}
> +
> +static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
> +	.attach = exynos_dsi_bridge_attach,
> +	.detach = exynos_dsi_bridge_detach,
> +};
> +
>   MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
>   
>   static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> @@ -1609,25 +1664,12 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>   {
>   	struct exynos_dsi *dsi = host_to_dsi(host);
>   	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
> -	struct drm_encoder *encoder = &dsi->encoder;
>   	struct drm_bridge *out_bridge;
>   
> -	out_bridge  = of_drm_find_bridge(device->dev.of_node);
> +	out_bridge = of_drm_find_bridge(device->dev.of_node);
>   	if (out_bridge) {
> -		drm_bridge_attach(encoder, out_bridge, NULL, 0);
>   		dsi->out_bridge = out_bridge;
> -		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
>   	} else {
> -		int ret = exynos_dsi_create_connector(encoder);
> -
> -		if (ret) {
> -			DRM_DEV_ERROR(dsi->dev,
> -				      "failed to create connector ret = %d\n",
> -				      ret);
> -			drm_encoder_cleanup(encoder);
> -			return ret;
> -		}
> -
>   		dsi->panel = of_drm_find_panel(device->dev.of_node);
>   		if (IS_ERR(dsi->panel))
>   			dsi->panel = NULL;
> @@ -1662,20 +1704,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
>   {
>   	struct exynos_dsi *dsi = host_to_dsi(host);
>   	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
> -	struct drm_device *drm = dsi->encoder.dev;
> -
> -	if (dsi->panel) {
> -		mutex_lock(&drm->mode_config.mutex);
> -		exynos_dsi_disable(&dsi->encoder);
> -		dsi->panel = NULL;
> -		dsi->connector.status = connector_status_disconnected;
> -		mutex_unlock(&drm->mode_config.mutex);
> -	} else {
> -		if (dsi->out_bridge->funcs->detach)
> -			dsi->out_bridge->funcs->detach(dsi->out_bridge);
> -		dsi->out_bridge = NULL;
> -		INIT_LIST_HEAD(&dsi->bridge_chain);
> -	}
>   
>   	if (ops && ops->detach)
>   		ops->detach(dsi->dsi_host.dev, device);
> @@ -1786,7 +1814,15 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
>   		of_node_put(in_bridge_node);
>   	}
>   
> +	ret = drm_bridge_attach(encoder, &dsi->bridge, in_bridge, 0);
> +	if (ret)
> +		goto err;
> +
>   	return 0;
> +
> +err:
> +	drm_encoder_cleanup(encoder);
> +	return ret;
>   }
>   
>   static void exynos_dsi_unbind(struct device *dev, struct device *master,
> @@ -1796,6 +1832,8 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master,
>   	struct drm_encoder *encoder = &dsi->encoder;
>   
>   	exynos_dsi_disable(encoder);
> +
> +	drm_encoder_cleanup(encoder);
>   }
>   
>   static const struct component_ops exynos_dsi_component_ops = {
> @@ -1806,6 +1844,7 @@ static const struct component_ops exynos_dsi_component_ops = {
>   static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
>   {
>   	struct device *dev = &pdev->dev;
> +	struct drm_bridge *bridge;
>   	struct resource *res;
>   	struct exynos_dsi *dsi;
>   	int ret, i;
> @@ -1894,11 +1933,19 @@ static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
>   	if (ret)
>   		return ERR_PTR(ret);
>   
> +	bridge = &dsi->bridge;
> +	bridge->driver_private = dsi;
> +	bridge->funcs = &exynos_dsi_bridge_funcs;
> +	bridge->of_node = dev->of_node;
> +	drm_bridge_add(bridge);
> +
>   	return dsi;
>   }
>   
>   static void __exynos_dsi_remove(struct exynos_dsi *dsi)
>   {
> +	drm_bridge_remove(&dsi->bridge);
> +
>   	mipi_dsi_host_unregister(&dsi->dsi_host);
>   }
>   

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2020-09-14  8:29     ` Marek Szyprowski
@ 2020-09-14 12:31       ` Marek Szyprowski
  2020-09-14 20:01         ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Marek Szyprowski @ 2020-09-14 12:31 UTC (permalink / raw)
  To: Michael Tretter, dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, inki.dae, jy0922.shim, sw0312.kim

Hi,

On 14.09.2020 10:29, Marek Szyprowski wrote:
> On 11.09.2020 15:54, Michael Tretter wrote:
>> Make the exynos_dsi driver a full drm bridge that can be found and used
>> from other drivers.
>>
>> Other drivers can only attach to the bridge, if a mipi dsi device
>> already attached to the bridge. This allows to defer the probe of the
>> display pipe until the downstream bridges are available, too.
>>
>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> This one (and the whole series applied) still fails on Exynos boards:
>
> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> OF: graph: no port node found in /soc/dsi@11c80000
> 8<--- cut here ---
> Unable to handle kernel NULL pointer dereference at virtual address 00000084
> pgd = (ptrval)
> [00000084] *pgd=00000000
> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> Modules linked in:
> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> Hardware name: Samsung Exynos (Flattened Device Tree)
> PC is at drm_bridge_attach+0x18/0x164
> LR is at exynos_dsi_bind+0x88/0xa8
> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> Stack: (0xef0dfca8 to 0xef0e0000)
> ...
> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> (exynos_dsi_bind+0x88/0xa8)
> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> (component_bind_all+0xfc/0x290)
> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> (exynos_drm_bind+0xe4/0x19c)
> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> (try_to_bring_up_master+0x1e4/0x2c4)
> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> (component_master_add_with_match+0xd4/0x108)
> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> (exynos_drm_platform_probe+0xe4/0x110)
> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> (platform_drv_probe+0x6c/0xa4)
> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> (really_probe+0x200/0x4fc)
> [<c067242c>] (really_probe) from [<c06728f0>]
> (driver_probe_device+0x78/0x1fc)
> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> (device_driver_attach+0x58/0x60)
> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> (__driver_attach+0xdc/0x174)
> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> (bus_for_each_dev+0x68/0xb4)
> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> (bus_add_driver+0x158/0x214)
> [<c06714e8>] (bus_add_driver) from [<c0673c1c>] (driver_register+0x78/0x110)
> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> (exynos_drm_init+0xe4/0x118)
> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> (do_one_initcall+0x8c/0x42c)
> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> (kernel_init_freeable+0x190/0x1dc)
> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> (kernel_init+0x8/0x118)
> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> Exception stack(0xef0dffb0 to 0xef0dfff8)
> ...
> ---[ end trace ee27f313f9ed9da1 ]---
>
> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
>
> I will try to debug it a bit more today.

The above crash has been caused by lack of in_bridge initialization to 
NULL in exynos_dsi_bind() in this patch. However, fixing it reveals 
another issue:

[drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
OF: graph: no port node found in /soc/dsi@11c80000
8<--- cut here ---
Unable to handle kernel NULL pointer dereference at virtual address 00000280
pgd = (ptrval)
[00000280] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 
5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
Hardware name: Samsung Exynos (Flattened Device Tree)
PC is at __mutex_lock+0x54/0xb18
LR is at lock_is_held_type+0x80/0x138
pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
sp : ef0dfd30  ip : 33937b74  fp : c13193c8
r10: c1208eec  r9 : 00000000  r8 : ee45f808
r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c5387d  Table: 4000404a  DAC: 00000051
Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
Stack: (0xef0dfd30 to 0xef0e0000)
...
[<c0afc920>] (__mutex_lock) from [<c0afd400>] (mutex_lock_nested+0x1c/0x24)
[<c0afd400>] (mutex_lock_nested) from [<c064d4b8>] 
(__exynos_dsi_host_attach+0x20/0x6c)
[<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>] 
(exynos_dsi_host_attach+0x70/0x194)
[<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>] 
(s6e8aa0_probe+0x1b0/0x218)
[<c0656b64>] (s6e8aa0_probe) from [<c0672530>] (really_probe+0x200/0x4fc)
[<c0672530>] (really_probe) from [<c06729f4>] 
(driver_probe_device+0x78/0x1fc)
[<c06729f4>] (driver_probe_device) from [<c0672ddc>] 
(device_driver_attach+0x58/0x60)
[<c0672ddc>] (device_driver_attach) from [<c0672ec0>] 
(__driver_attach+0xdc/0x174)
[<c0672ec0>] (__driver_attach) from [<c06702b8>] 
(bus_for_each_dev+0x68/0xb4)
[<c06702b8>] (bus_for_each_dev) from [<c06715ec>] 
(bus_add_driver+0x158/0x214)
[<c06715ec>] (bus_add_driver) from [<c0673d20>] (driver_register+0x78/0x110)
[<c0673d20>] (driver_register) from [<c0102484>] 
(do_one_initcall+0x8c/0x42c)
[<c0102484>] (do_one_initcall) from [<c11011c0>] 
(kernel_init_freeable+0x190/0x1dc)
[<c11011c0>] (kernel_init_freeable) from [<c0af7988>] 
(kernel_init+0x8/0x118)
[<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
Exception stack(0xef0dffb0 to 0xef0dfff8)
...
---[ end trace c06e996ec2e8234d ]---

This means that dsi->encoder.dev is not initialized in 
__exynos_dsi_host_attach().

This happens, because drm_bridge_attach() in exynos_dsi_bind() returned 
earlier -517 (deferred probe), what causes cleanup of encoder and 
release of all drm resources.

Then however, the panel tries to register itself and 
exynos_dsi_host_attach() tries to access the released encoder (which is 
zeroed in drm_encoder_release) and rest of resources, what causes failure.

It looks that something is missing. Maybe mipi host has to be registered 
later, when bridge is ready? I have no idea how it is handled before 
this patch. Andrzej, could you comment it a bit?

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2020-09-14 12:31       ` Marek Szyprowski
@ 2020-09-14 20:01         ` Michael Tretter
  2020-09-14 21:19           ` Andrzej Hajda
  0 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-14 20:01 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: dri-devel, linux-samsung-soc, kernel, Laurent.pinchart, krzk,
	narmstrong, b.zolnierkie, sylvester.nawrocki, a.hajda, inki.dae,
	jy0922.shim, sw0312.kim

Hi,

On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> On 14.09.2020 10:29, Marek Szyprowski wrote:
> > On 11.09.2020 15:54, Michael Tretter wrote:
> >> Make the exynos_dsi driver a full drm bridge that can be found and used
> >> from other drivers.
> >>
> >> Other drivers can only attach to the bridge, if a mipi dsi device
> >> already attached to the bridge. This allows to defer the probe of the
> >> display pipe until the downstream bridges are available, too.
> >>
> >> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > This one (and the whole series applied) still fails on Exynos boards:
> >
> > [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > OF: graph: no port node found in /soc/dsi@11c80000
> > 8<--- cut here ---
> > Unable to handle kernel NULL pointer dereference at virtual address 00000084
> > pgd = (ptrval)
> > [00000084] *pgd=00000000
> > Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > Modules linked in:
> > CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > Hardware name: Samsung Exynos (Flattened Device Tree)
> > PC is at drm_bridge_attach+0x18/0x164
> > LR is at exynos_dsi_bind+0x88/0xa8
> > pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > Stack: (0xef0dfca8 to 0xef0e0000)
> > ...
> > [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > (exynos_dsi_bind+0x88/0xa8)
> > [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > (component_bind_all+0xfc/0x290)
> > [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > (exynos_drm_bind+0xe4/0x19c)
> > [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > (try_to_bring_up_master+0x1e4/0x2c4)
> > [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > (component_master_add_with_match+0xd4/0x108)
> > [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > (exynos_drm_platform_probe+0xe4/0x110)
> > [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > (platform_drv_probe+0x6c/0xa4)
> > [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > (really_probe+0x200/0x4fc)
> > [<c067242c>] (really_probe) from [<c06728f0>]
> > (driver_probe_device+0x78/0x1fc)
> > [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > (device_driver_attach+0x58/0x60)
> > [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > (__driver_attach+0xdc/0x174)
> > [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > (bus_for_each_dev+0x68/0xb4)
> > [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > (bus_add_driver+0x158/0x214)
> > [<c06714e8>] (bus_add_driver) from [<c0673c1c>] (driver_register+0x78/0x110)
> > [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > (exynos_drm_init+0xe4/0x118)
> > [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > (do_one_initcall+0x8c/0x42c)
> > [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > (kernel_init_freeable+0x190/0x1dc)
> > [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > (kernel_init+0x8/0x118)
> > [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > Exception stack(0xef0dffb0 to 0xef0dfff8)
> > ...
> > ---[ end trace ee27f313f9ed9da1 ]---
> >
> > # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> >
> > I will try to debug it a bit more today.
> 
> The above crash has been caused by lack of in_bridge initialization to 
> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals 
> another issue:
> 
> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> OF: graph: no port node found in /soc/dsi@11c80000
> 8<--- cut here ---
> Unable to handle kernel NULL pointer dereference at virtual address 00000280
> pgd = (ptrval)
> [00000280] *pgd=00000000
> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> Modules linked in:
> CPU: 0 PID: 1 Comm: swapper/0 Not tainted 
> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> Hardware name: Samsung Exynos (Flattened Device Tree)
> PC is at __mutex_lock+0x54/0xb18
> LR is at lock_is_held_type+0x80/0x138
> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> Stack: (0xef0dfd30 to 0xef0e0000)
> ...
> [<c0afc920>] (__mutex_lock) from [<c0afd400>] (mutex_lock_nested+0x1c/0x24)
> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>] 
> (__exynos_dsi_host_attach+0x20/0x6c)
> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>] 
> (exynos_dsi_host_attach+0x70/0x194)
> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>] 
> (s6e8aa0_probe+0x1b0/0x218)
> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>] (really_probe+0x200/0x4fc)
> [<c0672530>] (really_probe) from [<c06729f4>] 
> (driver_probe_device+0x78/0x1fc)
> [<c06729f4>] (driver_probe_device) from [<c0672ddc>] 
> (device_driver_attach+0x58/0x60)
> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>] 
> (__driver_attach+0xdc/0x174)
> [<c0672ec0>] (__driver_attach) from [<c06702b8>] 
> (bus_for_each_dev+0x68/0xb4)
> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>] 
> (bus_add_driver+0x158/0x214)
> [<c06715ec>] (bus_add_driver) from [<c0673d20>] (driver_register+0x78/0x110)
> [<c0673d20>] (driver_register) from [<c0102484>] 
> (do_one_initcall+0x8c/0x42c)
> [<c0102484>] (do_one_initcall) from [<c11011c0>] 
> (kernel_init_freeable+0x190/0x1dc)
> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>] 
> (kernel_init+0x8/0x118)
> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> Exception stack(0xef0dffb0 to 0xef0dfff8)
> ...
> ---[ end trace c06e996ec2e8234d ]---
> 
> This means that dsi->encoder.dev is not initialized in 
> __exynos_dsi_host_attach().
> 
> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned 
> earlier -517 (deferred probe), what causes cleanup of encoder and 
> release of all drm resources.
> 
> Then however, the panel tries to register itself and 
> exynos_dsi_host_attach() tries to access the released encoder (which is 
> zeroed in drm_encoder_release) and rest of resources, what causes failure.
> 
> It looks that something is missing. Maybe mipi host has to be registered 
> later, when bridge is ready? I have no idea how it is handled before 
> this patch. Andrzej, could you comment it a bit?

I intentionally changed the order, because if another bridge follows in the
pipeline, the probe of the drm driver has to be deferred until some bridge
provides a connector. The next bridge registers itself via the host_attach
function and the deferral is ensured via the bind for the bind/unbind API or
the bridge_attach function otherwise.

On the other hand, the bridge does not have an encoder until the mipi device
has been attached.

As a solution, the exynos dsi driver must initialize the encoder in
exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder via
exynos_dsi instead of the bridge.

Can you try to move everything except samsung_dsim_bind from exynos_dsi_bind
to exynos_dsi_probe (respectively for unbind) and report if it fixes the
crash.

Michael

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2020-09-14 20:01         ` Michael Tretter
@ 2020-09-14 21:19           ` Andrzej Hajda
  2020-09-15 19:40             ` Andrzej Hajda
  0 siblings, 1 reply; 57+ messages in thread
From: Andrzej Hajda @ 2020-09-14 21:19 UTC (permalink / raw)
  To: Michael Tretter, Marek Szyprowski
  Cc: linux-samsung-soc, jy0922.shim, narmstrong, b.zolnierkie,
	sw0312.kim, krzk, dri-devel, kernel, sylvester.nawrocki,
	Laurent.pinchart

Hi Marek, Michael,

On 14.09.2020 22:01, Michael Tretter wrote:
> Hi,
>
> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
>> On 14.09.2020 10:29, Marek Szyprowski wrote:
>>> On 11.09.2020 15:54, Michael Tretter wrote:
>>>> Make the exynos_dsi driver a full drm bridge that can be found and used
>>>> from other drivers.
>>>>
>>>> Other drivers can only attach to the bridge, if a mipi dsi device
>>>> already attached to the bridge. This allows to defer the probe of the
>>>> display pipe until the downstream bridges are available, too.
>>>>
>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
>>> This one (and the whole series applied) still fails on Exynos boards:
>>>
>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>> OF: graph: no port node found in /soc/dsi@11c80000
>>> 8<--- cut here ---
>>> Unable to handle kernel NULL pointer dereference at virtual address 00000084
>>> pgd = (ptrval)
>>> [00000084] *pgd=00000000
>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>> Modules linked in:
>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>> PC is at drm_bridge_attach+0x18/0x164
>>> LR is at exynos_dsi_bind+0x88/0xa8
>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>> Stack: (0xef0dfca8 to 0xef0e0000)
>>> ...
>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
>>> (exynos_dsi_bind+0x88/0xa8)
>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
>>> (component_bind_all+0xfc/0x290)
>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
>>> (exynos_drm_bind+0xe4/0x19c)
>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
>>> (try_to_bring_up_master+0x1e4/0x2c4)
>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
>>> (component_master_add_with_match+0xd4/0x108)
>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
>>> (exynos_drm_platform_probe+0xe4/0x110)
>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
>>> (platform_drv_probe+0x6c/0xa4)
>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
>>> (really_probe+0x200/0x4fc)
>>> [<c067242c>] (really_probe) from [<c06728f0>]
>>> (driver_probe_device+0x78/0x1fc)
>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
>>> (device_driver_attach+0x58/0x60)
>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
>>> (__driver_attach+0xdc/0x174)
>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
>>> (bus_for_each_dev+0x68/0xb4)
>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
>>> (bus_add_driver+0x158/0x214)
>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>] (driver_register+0x78/0x110)
>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
>>> (exynos_drm_init+0xe4/0x118)
>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
>>> (do_one_initcall+0x8c/0x42c)
>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>> (kernel_init_freeable+0x190/0x1dc)
>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
>>> (kernel_init+0x8/0x118)
>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>> ...
>>> ---[ end trace ee27f313f9ed9da1 ]---
>>>
>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
>>>
>>> I will try to debug it a bit more today.
>> The above crash has been caused by lack of in_bridge initialization to
>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
>> another issue:
>>
>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>> OF: graph: no port node found in /soc/dsi@11c80000
>> 8<--- cut here ---
>> Unable to handle kernel NULL pointer dereference at virtual address 00000280
>> pgd = (ptrval)
>> [00000280] *pgd=00000000
>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>> Modules linked in:
>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
>> Hardware name: Samsung Exynos (Flattened Device Tree)
>> PC is at __mutex_lock+0x54/0xb18
>> LR is at lock_is_held_type+0x80/0x138
>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>> Stack: (0xef0dfd30 to 0xef0e0000)
>> ...
>> [<c0afc920>] (__mutex_lock) from [<c0afd400>] (mutex_lock_nested+0x1c/0x24)
>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
>> (__exynos_dsi_host_attach+0x20/0x6c)
>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
>> (exynos_dsi_host_attach+0x70/0x194)
>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
>> (s6e8aa0_probe+0x1b0/0x218)
>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>] (really_probe+0x200/0x4fc)
>> [<c0672530>] (really_probe) from [<c06729f4>]
>> (driver_probe_device+0x78/0x1fc)
>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
>> (device_driver_attach+0x58/0x60)
>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
>> (__driver_attach+0xdc/0x174)
>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
>> (bus_for_each_dev+0x68/0xb4)
>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
>> (bus_add_driver+0x158/0x214)
>> [<c06715ec>] (bus_add_driver) from [<c0673d20>] (driver_register+0x78/0x110)
>> [<c0673d20>] (driver_register) from [<c0102484>]
>> (do_one_initcall+0x8c/0x42c)
>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>> (kernel_init_freeable+0x190/0x1dc)
>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
>> (kernel_init+0x8/0x118)
>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>> ...
>> ---[ end trace c06e996ec2e8234d ]---
>>
>> This means that dsi->encoder.dev is not initialized in
>> __exynos_dsi_host_attach().
>>
>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
>> earlier -517 (deferred probe), what causes cleanup of encoder and
>> release of all drm resources.
>>
>> Then however, the panel tries to register itself and
>> exynos_dsi_host_attach() tries to access the released encoder (which is
>> zeroed in drm_encoder_release) and rest of resources, what causes failure.
>>
>> It looks that something is missing. Maybe mipi host has to be registered
>> later, when bridge is ready? I have no idea how it is handled before
>> this patch. Andrzej, could you comment it a bit?
> I intentionally changed the order, because if another bridge follows in the
> pipeline, the probe of the drm driver has to be deferred until some bridge
> provides a connector. The next bridge registers itself via the host_attach
> function and the deferral is ensured via the bind for the bind/unbind API or
> the bridge_attach function otherwise.
>
> On the other hand, the bridge does not have an encoder until the mipi device
> has been attached.
>
> As a solution, the exynos dsi driver must initialize the encoder in
> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder via
> exynos_dsi instead of the bridge.
>
> Can you try to move everything except samsung_dsim_bind from exynos_dsi_bind
> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> crash.


The original behaviour is that encoder (exynos_dsi) is registered 
regardless of sink presence (initially panel, later also bridge) - it 
avoids multiple issues with deferred probe, device driver bind/unbind 
and module load/unload. Appearance or disappearance of sink is reported 
to host nicely via DSI attach/detach callbacks - and it is reflected in 
drm world as change state of the connector.

Registering DSI host in bind and unregistering in unbind assures that if 
mipi_dsi device is attached/detached the drm device is always present - 
it makes device/driver binding race free and allows to avoid additional 
locking.

Moving DSI host registration to probe changes everything, for sure it 
breaks the nice feature of DSI attach/detach callbacks and apparently 
can cause different issues depending on device bind order.

I will try to look at the patches tomorrow and maybe I can find more 
constructive comments :)


Regards

Andrzej


>
> Michael
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://protect2.fireeye.com/v1/url?k=4f0be936-129547ac-4f0a6279-0cc47a336fae-e9aecfc5418740e8&q=1&e=1d4b0871-5b85-47f3-9506-79c768643aee&u=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Fdri-devel

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

* Re: [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers
  2020-09-11 13:54   ` [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers Michael Tretter
@ 2020-09-15 17:07     ` Andrzej Hajda
  2020-09-15 18:02       ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Andrzej Hajda @ 2020-09-15 17:07 UTC (permalink / raw)
  To: Michael Tretter, dri-devel, linux-samsung-soc
  Cc: jy0922.shim, b.zolnierkie, narmstrong, sw0312.kim, krzk,
	Laurent.pinchart, kernel, sylvester.nawrocki


W dniu 11.09.2020 o 15:54, Michael Tretter pisze:
> Platform drivers need to be aware if a mipi dsi device attaches or
> detaches. Add host_ops to the driver_data for attach and detach
> callbacks and move the i80 mode selection and the hotplug handling into
> the callback, because these depend on the drm driver.
>
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> ---
> v2:
> - new patch
> ---
>   drivers/gpu/drm/exynos/exynos_drm_dsi.c | 64 ++++++++++++++++++++-----
>   1 file changed, 53 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index 1a15ae71205d..684a2fbef08a 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -239,6 +239,12 @@ struct exynos_dsi_transfer {
>   #define DSIM_STATE_CMD_LPM		BIT(2)
>   #define DSIM_STATE_VIDOUT_AVAILABLE	BIT(3)
>   
> +struct exynos_dsi;
> +struct exynos_dsi_host_ops {
> +	int (*attach)(struct device *dev, struct mipi_dsi_device *device);
> +	int (*detach)(struct device *dev, struct mipi_dsi_device *device);
> +};
> +
>   enum exynos_reg_offset {
>   	EXYNOS_REG_OFS,
>   	EXYNOS5433_REG_OFS
> @@ -254,6 +260,7 @@ struct exynos_dsi_driver_data {
>   	unsigned int wait_for_reset;
>   	unsigned int num_bits_resol;
>   	const unsigned int *reg_values;
> +	const struct exynos_dsi_host_ops *host_ops;
>   };
>   
>   struct exynos_dsi {
> @@ -467,6 +474,41 @@ static const unsigned int exynos5433_reg_values[] = {
>   	[PHYTIMING_HS_TRAIL] = 0x0c,
>   };
>   
> +static int __exynos_dsi_host_attach(struct device *dev,
> +				    struct mipi_dsi_device *device)
> +{
> +	struct exynos_dsi *dsi = dev_get_drvdata(dev);
> +	struct drm_device *drm = dsi->encoder.dev;


As I wrote yesterday drm device was guaranteed to be present here only 
if mipi dsi host registration was performed in component bind. In case 
it is performed in probe it will be always NULL, and the code does not 
make sense.


Regards

Andrzej



> +	struct exynos_drm_crtc *crtc;
> +
> +	mutex_lock(&drm->mode_config.mutex);
> +	crtc = exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD);
> +	crtc->i80_mode = !(device->mode_flags & MIPI_DSI_MODE_VIDEO);
> +	mutex_unlock(&drm->mode_config.mutex);
> +
> +	if (drm->mode_config.poll_enabled)
> +		drm_kms_helper_hotplug_event(drm);
> +
> +	return 0;
> +}
> +
> +static int __exynos_dsi_host_detach(struct device *dev,
> +				     struct mipi_dsi_device *device)
> +{
> +	struct exynos_dsi *dsi = dev_get_drvdata(dev);
> +	struct drm_device *drm = dsi->encoder.dev;
> +
> +	if (drm->mode_config.poll_enabled)
> +		drm_kms_helper_hotplug_event(drm);
> +
> +	return 0;
> +}
> +
> +static const struct exynos_dsi_host_ops exynos_dsi_host_ops = {
> +	.attach = __exynos_dsi_host_attach,
> +	.detach = __exynos_dsi_host_detach,
> +};
> +
>   static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
>   	.reg_ofs = EXYNOS_REG_OFS,
>   	.plltmr_reg = 0x50,
> @@ -477,6 +519,7 @@ static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
>   	.wait_for_reset = 1,
>   	.num_bits_resol = 11,
>   	.reg_values = reg_values,
> +	.host_ops = &exynos_dsi_host_ops,
>   };
>   
>   static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
> @@ -489,6 +532,7 @@ static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
>   	.wait_for_reset = 1,
>   	.num_bits_resol = 11,
>   	.reg_values = reg_values,
> +	.host_ops = &exynos_dsi_host_ops,
>   };
>   
>   static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
> @@ -499,6 +543,7 @@ static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
>   	.wait_for_reset = 1,
>   	.num_bits_resol = 11,
>   	.reg_values = reg_values,
> +	.host_ops = &exynos_dsi_host_ops,
>   };
>   
>   static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
> @@ -510,6 +555,7 @@ static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
>   	.wait_for_reset = 0,
>   	.num_bits_resol = 12,
>   	.reg_values = exynos5433_reg_values,
> +	.host_ops = &exynos_dsi_host_ops,
>   };
>   
>   static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
> @@ -521,6 +567,7 @@ static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
>   	.wait_for_reset = 1,
>   	.num_bits_resol = 12,
>   	.reg_values = exynos5422_reg_values,
> +	.host_ops = &exynos_dsi_host_ops,
>   };
>   
>   static const struct of_device_id exynos_dsi_of_match[] = {
> @@ -1551,8 +1598,8 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>   				  struct mipi_dsi_device *device)
>   {
>   	struct exynos_dsi *dsi = host_to_dsi(host);
> +	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
>   	struct drm_encoder *encoder = &dsi->encoder;
> -	struct drm_device *drm = encoder->dev;
>   	struct drm_bridge *out_bridge;
>   
>   	out_bridge  = of_drm_find_bridge(device->dev.of_node);
> @@ -1590,18 +1637,12 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>   			return ret;
>   	}
>   
> -	mutex_lock(&drm->mode_config.mutex);
> -
>   	dsi->lanes = device->lanes;
>   	dsi->format = device->format;
>   	dsi->mode_flags = device->mode_flags;
> -	exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
> -			!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
>   
> -	mutex_unlock(&drm->mode_config.mutex);
> -
> -	if (drm->mode_config.poll_enabled)
> -		drm_kms_helper_hotplug_event(drm);
> +	if (ops && ops->attach)
> +		ops->attach(dsi->dsi_host.dev, device);
>   
>   	return 0;
>   }
> @@ -1610,6 +1651,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
>   				  struct mipi_dsi_device *device)
>   {
>   	struct exynos_dsi *dsi = host_to_dsi(host);
> +	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
>   	struct drm_device *drm = dsi->encoder.dev;
>   
>   	if (dsi->panel) {
> @@ -1625,8 +1667,8 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
>   		INIT_LIST_HEAD(&dsi->bridge_chain);
>   	}
>   
> -	if (drm->mode_config.poll_enabled)
> -		drm_kms_helper_hotplug_event(drm);
> +	if (ops && ops->detach)
> +		ops->detach(dsi->dsi_host.dev, device);
>   
>   	exynos_dsi_unregister_te_irq(dsi);
>   

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

* Re: [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers
  2020-09-15 17:07     ` Andrzej Hajda
@ 2020-09-15 18:02       ` Michael Tretter
  2020-09-16 22:01         ` Andrzej Hajda
  0 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-09-15 18:02 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, Laurent.pinchart, kernel,
	sylvester.nawrocki

On Tue, 15 Sep 2020 19:07:59 +0200, Andrzej Hajda wrote:
> 
> W dniu 11.09.2020 o 15:54, Michael Tretter pisze:
> > Platform drivers need to be aware if a mipi dsi device attaches or
> > detaches. Add host_ops to the driver_data for attach and detach
> > callbacks and move the i80 mode selection and the hotplug handling into
> > the callback, because these depend on the drm driver.
> >
> > Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > ---
> > v2:
> > - new patch
> > ---
> >   drivers/gpu/drm/exynos/exynos_drm_dsi.c | 64 ++++++++++++++++++++-----
> >   1 file changed, 53 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > index 1a15ae71205d..684a2fbef08a 100644
> > --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > @@ -239,6 +239,12 @@ struct exynos_dsi_transfer {
> >   #define DSIM_STATE_CMD_LPM		BIT(2)
> >   #define DSIM_STATE_VIDOUT_AVAILABLE	BIT(3)
> >   
> > +struct exynos_dsi;
> > +struct exynos_dsi_host_ops {
> > +	int (*attach)(struct device *dev, struct mipi_dsi_device *device);
> > +	int (*detach)(struct device *dev, struct mipi_dsi_device *device);
> > +};
> > +
> >   enum exynos_reg_offset {
> >   	EXYNOS_REG_OFS,
> >   	EXYNOS5433_REG_OFS
> > @@ -254,6 +260,7 @@ struct exynos_dsi_driver_data {
> >   	unsigned int wait_for_reset;
> >   	unsigned int num_bits_resol;
> >   	const unsigned int *reg_values;
> > +	const struct exynos_dsi_host_ops *host_ops;
> >   };
> >   
> >   struct exynos_dsi {
> > @@ -467,6 +474,41 @@ static const unsigned int exynos5433_reg_values[] = {
> >   	[PHYTIMING_HS_TRAIL] = 0x0c,
> >   };
> >   
> > +static int __exynos_dsi_host_attach(struct device *dev,
> > +				    struct mipi_dsi_device *device)
> > +{
> > +	struct exynos_dsi *dsi = dev_get_drvdata(dev);
> > +	struct drm_device *drm = dsi->encoder.dev;
> 
> 
> As I wrote yesterday drm device was guaranteed to be present here only 
> if mipi dsi host registration was performed in component bind. In case 
> it is performed in probe it will be always NULL, and the code does not 
> make sense.

Correct, but if the driver is used as a drm bridge, there won't be an encoder
until bridge_attach. Mipi dsi devices defer their probe until the mipi dsi
host is available. If I move the mipi dsi host registration into
bridge_attach, the driver does not know if the next device is another bridge
or a panel during bridge_attach, but the driver cannot successfully return
from bridge_attach, because then the drm driver expects a connector.

I guess that the encoder should be initialized before registering the mipi dsi
host during probe instead of bind. The probe won't be rolled back on
PROBE_DEFER during bind and the encoder will be available in host_attach.
When splitting the driver into the exynos platform specific code and the more
generic code, there won't be an encoder during host_attach in the generic
code, but the host_ops callback could (and will) use the platform specific
encoder, which is available before bridge_attach.

Does this make sense to you?

Michael

> 
> 
> Regards
> 
> Andrzej
> 
> 
> 
> > +	struct exynos_drm_crtc *crtc;
> > +
> > +	mutex_lock(&drm->mode_config.mutex);
> > +	crtc = exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD);
> > +	crtc->i80_mode = !(device->mode_flags & MIPI_DSI_MODE_VIDEO);
> > +	mutex_unlock(&drm->mode_config.mutex);
> > +
> > +	if (drm->mode_config.poll_enabled)
> > +		drm_kms_helper_hotplug_event(drm);
> > +
> > +	return 0;
> > +}
> > +
> > +static int __exynos_dsi_host_detach(struct device *dev,
> > +				     struct mipi_dsi_device *device)
> > +{
> > +	struct exynos_dsi *dsi = dev_get_drvdata(dev);
> > +	struct drm_device *drm = dsi->encoder.dev;
> > +
> > +	if (drm->mode_config.poll_enabled)
> > +		drm_kms_helper_hotplug_event(drm);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct exynos_dsi_host_ops exynos_dsi_host_ops = {
> > +	.attach = __exynos_dsi_host_attach,
> > +	.detach = __exynos_dsi_host_detach,
> > +};
> > +
> >   static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
> >   	.reg_ofs = EXYNOS_REG_OFS,
> >   	.plltmr_reg = 0x50,
> > @@ -477,6 +519,7 @@ static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
> >   	.wait_for_reset = 1,
> >   	.num_bits_resol = 11,
> >   	.reg_values = reg_values,
> > +	.host_ops = &exynos_dsi_host_ops,
> >   };
> >   
> >   static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
> > @@ -489,6 +532,7 @@ static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
> >   	.wait_for_reset = 1,
> >   	.num_bits_resol = 11,
> >   	.reg_values = reg_values,
> > +	.host_ops = &exynos_dsi_host_ops,
> >   };
> >   
> >   static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
> > @@ -499,6 +543,7 @@ static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
> >   	.wait_for_reset = 1,
> >   	.num_bits_resol = 11,
> >   	.reg_values = reg_values,
> > +	.host_ops = &exynos_dsi_host_ops,
> >   };
> >   
> >   static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
> > @@ -510,6 +555,7 @@ static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
> >   	.wait_for_reset = 0,
> >   	.num_bits_resol = 12,
> >   	.reg_values = exynos5433_reg_values,
> > +	.host_ops = &exynos_dsi_host_ops,
> >   };
> >   
> >   static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
> > @@ -521,6 +567,7 @@ static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
> >   	.wait_for_reset = 1,
> >   	.num_bits_resol = 12,
> >   	.reg_values = exynos5422_reg_values,
> > +	.host_ops = &exynos_dsi_host_ops,
> >   };
> >   
> >   static const struct of_device_id exynos_dsi_of_match[] = {
> > @@ -1551,8 +1598,8 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> >   				  struct mipi_dsi_device *device)
> >   {
> >   	struct exynos_dsi *dsi = host_to_dsi(host);
> > +	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
> >   	struct drm_encoder *encoder = &dsi->encoder;
> > -	struct drm_device *drm = encoder->dev;
> >   	struct drm_bridge *out_bridge;
> >   
> >   	out_bridge  = of_drm_find_bridge(device->dev.of_node);
> > @@ -1590,18 +1637,12 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> >   			return ret;
> >   	}
> >   
> > -	mutex_lock(&drm->mode_config.mutex);
> > -
> >   	dsi->lanes = device->lanes;
> >   	dsi->format = device->format;
> >   	dsi->mode_flags = device->mode_flags;
> > -	exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
> > -			!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
> >   
> > -	mutex_unlock(&drm->mode_config.mutex);
> > -
> > -	if (drm->mode_config.poll_enabled)
> > -		drm_kms_helper_hotplug_event(drm);
> > +	if (ops && ops->attach)
> > +		ops->attach(dsi->dsi_host.dev, device);
> >   
> >   	return 0;
> >   }
> > @@ -1610,6 +1651,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
> >   				  struct mipi_dsi_device *device)
> >   {
> >   	struct exynos_dsi *dsi = host_to_dsi(host);
> > +	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
> >   	struct drm_device *drm = dsi->encoder.dev;
> >   
> >   	if (dsi->panel) {
> > @@ -1625,8 +1667,8 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
> >   		INIT_LIST_HEAD(&dsi->bridge_chain);
> >   	}
> >   
> > -	if (drm->mode_config.poll_enabled)
> > -		drm_kms_helper_hotplug_event(drm);
> > +	if (ops && ops->detach)
> > +		ops->detach(dsi->dsi_host.dev, device);
> >   
> >   	exynos_dsi_unregister_te_irq(dsi);
> >   
> 

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2020-09-14 21:19           ` Andrzej Hajda
@ 2020-09-15 19:40             ` Andrzej Hajda
  2021-02-01 16:33               ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Andrzej Hajda @ 2020-09-15 19:40 UTC (permalink / raw)
  To: Michael Tretter, Marek Szyprowski
  Cc: linux-samsung-soc, jy0922.shim, narmstrong, b.zolnierkie,
	sw0312.kim, krzk, dri-devel, kernel, sylvester.nawrocki,
	Laurent.pinchart

Hi again,

W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> Hi Marek, Michael,
>
> On 14.09.2020 22:01, Michael Tretter wrote:
>> Hi,
>>
>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
>>>> On 11.09.2020 15:54, Michael Tretter wrote:
>>>>> Make the exynos_dsi driver a full drm bridge that can be found and 
>>>>> used
>>>>> from other drivers.
>>>>>
>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
>>>>> already attached to the bridge. This allows to defer the probe of the
>>>>> display pipe until the downstream bridges are available, too.
>>>>>
>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
>>>> This one (and the whole series applied) still fails on Exynos boards:
>>>>
>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping 
>>>> operations
>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>> 8<--- cut here ---
>>>> Unable to handle kernel NULL pointer dereference at virtual address 
>>>> 00000084
>>>> pgd = (ptrval)
>>>> [00000084] *pgd=00000000
>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>> Modules linked in:
>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>> PC is at drm_bridge_attach+0x18/0x164
>>>> LR is at exynos_dsi_bind+0x88/0xa8
>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>> Stack: (0xef0dfca8 to 0xef0e0000)
>>>> ...
>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
>>>> (exynos_dsi_bind+0x88/0xa8)
>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
>>>> (component_bind_all+0xfc/0x290)
>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
>>>> (exynos_drm_bind+0xe4/0x19c)
>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
>>>> (try_to_bring_up_master+0x1e4/0x2c4)
>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
>>>> (component_master_add_with_match+0xd4/0x108)
>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
>>>> (exynos_drm_platform_probe+0xe4/0x110)
>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
>>>> (platform_drv_probe+0x6c/0xa4)
>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
>>>> (really_probe+0x200/0x4fc)
>>>> [<c067242c>] (really_probe) from [<c06728f0>]
>>>> (driver_probe_device+0x78/0x1fc)
>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
>>>> (device_driver_attach+0x58/0x60)
>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
>>>> (__driver_attach+0xdc/0x174)
>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
>>>> (bus_for_each_dev+0x68/0xb4)
>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
>>>> (bus_add_driver+0x158/0x214)
>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>] 
>>>> (driver_register+0x78/0x110)
>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
>>>> (exynos_drm_init+0xe4/0x118)
>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
>>>> (do_one_initcall+0x8c/0x42c)
>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>> (kernel_init_freeable+0x190/0x1dc)
>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
>>>> (kernel_init+0x8/0x118)
>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>> ...
>>>> ---[ end trace ee27f313f9ed9da1 ]---
>>>>
>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
>>>>
>>>> I will try to debug it a bit more today.
>>> The above crash has been caused by lack of in_bridge initialization to
>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
>>> another issue:
>>>
>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>> OF: graph: no port node found in /soc/dsi@11c80000
>>> 8<--- cut here ---
>>> Unable to handle kernel NULL pointer dereference at virtual address 
>>> 00000280
>>> pgd = (ptrval)
>>> [00000280] *pgd=00000000
>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>> Modules linked in:
>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>> PC is at __mutex_lock+0x54/0xb18
>>> LR is at lock_is_held_type+0x80/0x138
>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>> Stack: (0xef0dfd30 to 0xef0e0000)
>>> ...
>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>] 
>>> (mutex_lock_nested+0x1c/0x24)
>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
>>> (__exynos_dsi_host_attach+0x20/0x6c)
>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
>>> (exynos_dsi_host_attach+0x70/0x194)
>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
>>> (s6e8aa0_probe+0x1b0/0x218)
>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>] 
>>> (really_probe+0x200/0x4fc)
>>> [<c0672530>] (really_probe) from [<c06729f4>]
>>> (driver_probe_device+0x78/0x1fc)
>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
>>> (device_driver_attach+0x58/0x60)
>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
>>> (__driver_attach+0xdc/0x174)
>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
>>> (bus_for_each_dev+0x68/0xb4)
>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
>>> (bus_add_driver+0x158/0x214)
>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>] 
>>> (driver_register+0x78/0x110)
>>> [<c0673d20>] (driver_register) from [<c0102484>]
>>> (do_one_initcall+0x8c/0x42c)
>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>> (kernel_init_freeable+0x190/0x1dc)
>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
>>> (kernel_init+0x8/0x118)
>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>> ...
>>> ---[ end trace c06e996ec2e8234d ]---
>>>
>>> This means that dsi->encoder.dev is not initialized in
>>> __exynos_dsi_host_attach().
>>>
>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
>>> earlier -517 (deferred probe), what causes cleanup of encoder and
>>> release of all drm resources.
>>>
>>> Then however, the panel tries to register itself and
>>> exynos_dsi_host_attach() tries to access the released encoder (which is
>>> zeroed in drm_encoder_release) and rest of resources, what causes 
>>> failure.
>>>
>>> It looks that something is missing. Maybe mipi host has to be 
>>> registered
>>> later, when bridge is ready? I have no idea how it is handled before
>>> this patch. Andrzej, could you comment it a bit?
>> I intentionally changed the order, because if another bridge follows 
>> in the
>> pipeline, the probe of the drm driver has to be deferred until some 
>> bridge
>> provides a connector. The next bridge registers itself via the 
>> host_attach
>> function and the deferral is ensured via the bind for the bind/unbind 
>> API or
>> the bridge_attach function otherwise.
>>
>> On the other hand, the bridge does not have an encoder until the mipi 
>> device
>> has been attached.
>>
>> As a solution, the exynos dsi driver must initialize the encoder in
>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder 
>> via
>> exynos_dsi instead of the bridge.
>>
>> Can you try to move everything except samsung_dsim_bind from 
>> exynos_dsi_bind
>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
>> crash.
>
>
> The original behaviour is that encoder (exynos_dsi) is registered 
> regardless of sink presence (initially panel, later also bridge) - it 
> avoids multiple issues with deferred probe, device driver bind/unbind 
> and module load/unload. Appearance or disappearance of sink is 
> reported to host nicely via DSI attach/detach callbacks - and it is 
> reflected in drm world as change state of the connector.
>
> Registering DSI host in bind and unregistering in unbind assures that 
> if mipi_dsi device is attached/detached the drm device is always 
> present - it makes device/driver binding race free and allows to avoid 
> additional locking.
>
> Moving DSI host registration to probe changes everything, for sure it 
> breaks the nice feature of DSI attach/detach callbacks and apparently 
> can cause different issues depending on device bind order.
>
> I will try to look at the patches tomorrow and maybe I can find more 
> constructive comments :)


As I said yesterday, exynos_dsi driver uses dsi host attach/detach 
callbacks to control appearance/disappearance of downstream device. It 
allows to:

1. Safely bind/unbind different device drivers at any time and at any 
order, without killing exynos_drm and/or crashing system.

2. Avoid issues with late drm init - on some platforms exynos_drm device 
appeared too late, due to deferred probe, and resulted in black screen 
in userspace.


Now if we want to convert exynos_dsi to drm_bridge I see following options:

A. Forgot about callbacks and make the exynos_drm to defer probing until 
exynos_dsi bridge is available, probably it will cause later exynos_drm 
appearance, thus probably black screen on some targets. So for sure it 
will be suboptimal. Making it bridge unbind safe would be another 
problem, but most developers do not care about it so why should we? :)

B. Try to mimic current behaviour - exynos_dsi register bridge ASAP, 
even if downstream devices are not yet attached, on attach/detach notify 
drm about it via connector status change, for this dsi_host registration 
should be performed from drm_bridge attach, I guess.


Option A is more standard, but is unsafe and causes other issues.

Option B keeps current behaviour.


Regards

Andrzej


>
>
> Regards
>
> Andrzej
>
>
>>
>> Michael
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://protect2.fireeye.com/v1/url?k=4f0be936-129547ac-4f0a6279-0cc47a336fae-e9aecfc5418740e8&q=1&e=1d4b0871-5b85-47f3-9506-79c768643aee&u=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Fdri-devel 
>>

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

* Re: [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers
  2020-09-15 18:02       ` Michael Tretter
@ 2020-09-16 22:01         ` Andrzej Hajda
  0 siblings, 0 replies; 57+ messages in thread
From: Andrzej Hajda @ 2020-09-16 22:01 UTC (permalink / raw)
  To: Michael Tretter
  Cc: linux-samsung-soc, jy0922.shim, narmstrong, b.zolnierkie,
	sw0312.kim, dri-devel, krzk, kernel, sylvester.nawrocki,
	Laurent.pinchart


W dniu 15.09.2020 o 20:02, Michael Tretter pisze:
> On Tue, 15 Sep 2020 19:07:59 +0200, Andrzej Hajda wrote:
>> W dniu 11.09.2020 o 15:54, Michael Tretter pisze:
>>> Platform drivers need to be aware if a mipi dsi device attaches or
>>> detaches. Add host_ops to the driver_data for attach and detach
>>> callbacks and move the i80 mode selection and the hotplug handling into
>>> the callback, because these depend on the drm driver.
>>>
>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
>>> ---
>>> v2:
>>> - new patch
>>> ---
>>>    drivers/gpu/drm/exynos/exynos_drm_dsi.c | 64 ++++++++++++++++++++-----
>>>    1 file changed, 53 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>>> index 1a15ae71205d..684a2fbef08a 100644
>>> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>>> @@ -239,6 +239,12 @@ struct exynos_dsi_transfer {
>>>    #define DSIM_STATE_CMD_LPM		BIT(2)
>>>    #define DSIM_STATE_VIDOUT_AVAILABLE	BIT(3)
>>>    
>>> +struct exynos_dsi;
>>> +struct exynos_dsi_host_ops {
>>> +	int (*attach)(struct device *dev, struct mipi_dsi_device *device);
>>> +	int (*detach)(struct device *dev, struct mipi_dsi_device *device);
>>> +};
>>> +
>>>    enum exynos_reg_offset {
>>>    	EXYNOS_REG_OFS,
>>>    	EXYNOS5433_REG_OFS
>>> @@ -254,6 +260,7 @@ struct exynos_dsi_driver_data {
>>>    	unsigned int wait_for_reset;
>>>    	unsigned int num_bits_resol;
>>>    	const unsigned int *reg_values;
>>> +	const struct exynos_dsi_host_ops *host_ops;
>>>    };
>>>    
>>>    struct exynos_dsi {
>>> @@ -467,6 +474,41 @@ static const unsigned int exynos5433_reg_values[] = {
>>>    	[PHYTIMING_HS_TRAIL] = 0x0c,
>>>    };
>>>    
>>> +static int __exynos_dsi_host_attach(struct device *dev,
>>> +				    struct mipi_dsi_device *device)
>>> +{
>>> +	struct exynos_dsi *dsi = dev_get_drvdata(dev);
>>> +	struct drm_device *drm = dsi->encoder.dev;
>>
>> As I wrote yesterday drm device was guaranteed to be present here only
>> if mipi dsi host registration was performed in component bind. In case
>> it is performed in probe it will be always NULL, and the code does not
>> make sense.
> Correct, but if the driver is used as a drm bridge, there won't be an encoder
> until bridge_attach. Mipi dsi devices defer their probe until the mipi dsi
> host is available. If I move the mipi dsi host registration into
> bridge_attach, the driver does not know if the next device is another bridge
> or a panel during bridge_attach, but the driver cannot successfully return
> from bridge_attach, because then the drm driver expects a connector.


Hmm, I am not sure why do you think driver expects connector on return 
of briddge_attach.


>
> I guess that the encoder should be initialized before registering the mipi dsi
> host during probe instead of bind.


But you should have already drm dev on encoder init which in probe is 
unavailable.



> The probe won't be rolled back on
> PROBE_DEFER during bind and the encoder will be available in host_attach.
> When splitting the driver into the exynos platform specific code and the more
> generic code, there won't be an encoder during host_attach in the generic
> code, but the host_ops callback could (and will) use the platform specific
> encoder, which is available before bridge_attach.
>
> Does this make sense to you?


Nope :) But maybe I am missing sth.

Generally I see two ways (which I have already described in different 
e-mail, in different words):

A. Static - we wait for every part of display stack to be probed, then 
create drm_dev - typical approach, but slow (deferred probe causes late 
drm creation), and racy - only(?) component framework and DSI bus have 
possibility to signal driver unbind, so we can react on it properly.

B. Dynamic - drm framework requires only crtcs and encoders to be 
attached to drm on init, connectors, and hidden parts (drm_bridges, 
drm_panels) can be created/destroyed and attached/detached at any time 
(almost), so lets take advantage of it - create drm_dev ASAP and attach 
other parts when they become available, the only issue is that there is 
no generic way to be notified when given parts becomes available - in 
interesting area only mipi devices have such notifications via attach 
callbacks.


So either we convert exynos_dsi to A either we continue B approach. In 
second case we should assure mipi_dsi host is created if drm_dev is 
available.


Regards

Andrzej



>
> Michael
>
>>
>> Regards
>>
>> Andrzej
>>
>>
>>
>>> +	struct exynos_drm_crtc *crtc;
>>> +
>>> +	mutex_lock(&drm->mode_config.mutex);
>>> +	crtc = exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD);
>>> +	crtc->i80_mode = !(device->mode_flags & MIPI_DSI_MODE_VIDEO);
>>> +	mutex_unlock(&drm->mode_config.mutex);
>>> +
>>> +	if (drm->mode_config.poll_enabled)
>>> +		drm_kms_helper_hotplug_event(drm);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int __exynos_dsi_host_detach(struct device *dev,
>>> +				     struct mipi_dsi_device *device)
>>> +{
>>> +	struct exynos_dsi *dsi = dev_get_drvdata(dev);
>>> +	struct drm_device *drm = dsi->encoder.dev;
>>> +
>>> +	if (drm->mode_config.poll_enabled)
>>> +		drm_kms_helper_hotplug_event(drm);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct exynos_dsi_host_ops exynos_dsi_host_ops = {
>>> +	.attach = __exynos_dsi_host_attach,
>>> +	.detach = __exynos_dsi_host_detach,
>>> +};
>>> +
>>>    static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
>>>    	.reg_ofs = EXYNOS_REG_OFS,
>>>    	.plltmr_reg = 0x50,
>>> @@ -477,6 +519,7 @@ static const struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
>>>    	.wait_for_reset = 1,
>>>    	.num_bits_resol = 11,
>>>    	.reg_values = reg_values,
>>> +	.host_ops = &exynos_dsi_host_ops,
>>>    };
>>>    
>>>    static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
>>> @@ -489,6 +532,7 @@ static const struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
>>>    	.wait_for_reset = 1,
>>>    	.num_bits_resol = 11,
>>>    	.reg_values = reg_values,
>>> +	.host_ops = &exynos_dsi_host_ops,
>>>    };
>>>    
>>>    static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
>>> @@ -499,6 +543,7 @@ static const struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
>>>    	.wait_for_reset = 1,
>>>    	.num_bits_resol = 11,
>>>    	.reg_values = reg_values,
>>> +	.host_ops = &exynos_dsi_host_ops,
>>>    };
>>>    
>>>    static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
>>> @@ -510,6 +555,7 @@ static const struct exynos_dsi_driver_data exynos5433_dsi_driver_data = {
>>>    	.wait_for_reset = 0,
>>>    	.num_bits_resol = 12,
>>>    	.reg_values = exynos5433_reg_values,
>>> +	.host_ops = &exynos_dsi_host_ops,
>>>    };
>>>    
>>>    static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
>>> @@ -521,6 +567,7 @@ static const struct exynos_dsi_driver_data exynos5422_dsi_driver_data = {
>>>    	.wait_for_reset = 1,
>>>    	.num_bits_resol = 12,
>>>    	.reg_values = exynos5422_reg_values,
>>> +	.host_ops = &exynos_dsi_host_ops,
>>>    };
>>>    
>>>    static const struct of_device_id exynos_dsi_of_match[] = {
>>> @@ -1551,8 +1598,8 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>>>    				  struct mipi_dsi_device *device)
>>>    {
>>>    	struct exynos_dsi *dsi = host_to_dsi(host);
>>> +	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
>>>    	struct drm_encoder *encoder = &dsi->encoder;
>>> -	struct drm_device *drm = encoder->dev;
>>>    	struct drm_bridge *out_bridge;
>>>    
>>>    	out_bridge  = of_drm_find_bridge(device->dev.of_node);
>>> @@ -1590,18 +1637,12 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
>>>    			return ret;
>>>    	}
>>>    
>>> -	mutex_lock(&drm->mode_config.mutex);
>>> -
>>>    	dsi->lanes = device->lanes;
>>>    	dsi->format = device->format;
>>>    	dsi->mode_flags = device->mode_flags;
>>> -	exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
>>> -			!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
>>>    
>>> -	mutex_unlock(&drm->mode_config.mutex);
>>> -
>>> -	if (drm->mode_config.poll_enabled)
>>> -		drm_kms_helper_hotplug_event(drm);
>>> +	if (ops && ops->attach)
>>> +		ops->attach(dsi->dsi_host.dev, device);
>>>    
>>>    	return 0;
>>>    }
>>> @@ -1610,6 +1651,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
>>>    				  struct mipi_dsi_device *device)
>>>    {
>>>    	struct exynos_dsi *dsi = host_to_dsi(host);
>>> +	const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops;
>>>    	struct drm_device *drm = dsi->encoder.dev;
>>>    
>>>    	if (dsi->panel) {
>>> @@ -1625,8 +1667,8 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
>>>    		INIT_LIST_HEAD(&dsi->bridge_chain);
>>>    	}
>>>    
>>> -	if (drm->mode_config.poll_enabled)
>>> -		drm_kms_helper_hotplug_event(drm);
>>> +	if (ops && ops->detach)
>>> +		ops->detach(dsi->dsi_host.dev, device);
>>>    
>>>    	exynos_dsi_unregister_te_irq(dsi);
>>>    
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://protect2.fireeye.com/v1/url?k=80c78954-dd15920c-80c6021b-0cc47a31c8b4-c39fad41cb70b194&q=1&e=b51d6682-ba72-48c0-b0c9-013866ba39ab&u=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Fdri-devel

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

* Re: [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge
  2020-09-11 13:53   ` [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge Michael Tretter
@ 2020-11-07 15:07     ` Adam Ford
  2020-11-10  8:46       ` Michael Tretter
  2020-11-07 22:17     ` Sam Ravnborg
  1 sibling, 1 reply; 57+ messages in thread
From: Adam Ford @ 2020-11-07 15:07 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim,
	Bartlomiej Zolnierkiewicz, Neil Armstrong, sw0312.kim,
	Krzysztof Kozlowski, a.hajda, Laurent Pinchart, Sascha Hauer,
	sylvester.nawrocki

On Fri, Sep 11, 2020 at 8:54 AM Michael Tretter
<m.tretter@pengutronix.de> wrote:
>
> In commit 05193dc38197 ("drm/bridge: Make the bridge chain a
> double-linked list") the bridge has been removed and replaced by a
> private field. Remove the leftover documentation of the removed field.
>
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

What is the status of this series?  I know of at least one other patch
series depending on this.

adam

> ---
> v2: none
> ---
>  include/drm/drm_encoder.h | 1 -
>  1 file changed, 1 deletion(-)
>
> diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
> index a60f5f1555ac..5dfa5f7a80a7 100644
> --- a/include/drm/drm_encoder.h
> +++ b/include/drm/drm_encoder.h
> @@ -89,7 +89,6 @@ struct drm_encoder_funcs {
>   * @head: list management
>   * @base: base KMS object
>   * @name: human readable name, can be overwritten by the driver
> - * @bridge: bridge associated to the encoder
>   * @funcs: control functions
>   * @helper_private: mid-layer private data
>   *
> --
> 2.20.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge
  2020-09-11 13:53   ` [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge Michael Tretter
  2020-11-07 15:07     ` Adam Ford
@ 2020-11-07 22:17     ` Sam Ravnborg
  1 sibling, 0 replies; 57+ messages in thread
From: Sam Ravnborg @ 2020-11-07 22:17 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent Pinchart, kernel,
	sylvester.nawrocki

On Fri, Sep 11, 2020 at 03:53:58PM +0200, Michael Tretter wrote:
> In commit 05193dc38197 ("drm/bridge: Make the bridge chain a
> double-linked list") the bridge has been removed and replaced by a
> private field. Remove the leftover documentation of the removed field.
> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Hi Michael.

Applied to drm-misc-next, thanks.
The rest of this patch-set is exynos stuff, that the maintainer needs to
deal with but I will try to take a look at some of the patches.

	Sam

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

* Re: [PATCH v2 02/16] drm/exynos: remove in_bridge_node from exynos_dsi
  2020-09-11 13:53   ` [PATCH v2 02/16] drm/exynos: remove in_bridge_node from exynos_dsi Michael Tretter
@ 2020-11-07 22:19     ` Sam Ravnborg
  0 siblings, 0 replies; 57+ messages in thread
From: Sam Ravnborg @ 2020-11-07 22:19 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent.pinchart, kernel,
	sylvester.nawrocki

On Fri, Sep 11, 2020 at 03:53:59PM +0200, Michael Tretter wrote:
> We do not need to keep a reference to the in_bridge_node, but we can
> simply drop it, once we found and attached the previous bridge.
> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>

Note: I expect exynos people to pick it up.

	Sam

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

* Re: [PATCH v2 03/16] drm/exynos: use exynos_dsi as drvdata
  2020-09-11 13:54   ` [PATCH v2 03/16] drm/exynos: use exynos_dsi as drvdata Michael Tretter
@ 2020-11-07 22:24     ` Sam Ravnborg
  2020-11-09  2:24       ` Inki Dae
  0 siblings, 1 reply; 57+ messages in thread
From: Sam Ravnborg @ 2020-11-07 22:24 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent.pinchart, kernel,
	sylvester.nawrocki

On Fri, Sep 11, 2020 at 03:54:00PM +0200, Michael Tretter wrote:
> Use the exynos_dsi as drvdata instead of the encoder to further decouple
> the driver from the encoder.
> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>

Likewise, the exynos people are expected to pick this up.

	Sam

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

* Re: [PATCH v2 04/16] drm/exynos: extract helper functions for probe
  2020-09-11 13:54   ` [PATCH v2 04/16] drm/exynos: extract helper functions for probe Michael Tretter
@ 2020-11-07 22:27     ` Sam Ravnborg
  2020-11-09  2:52       ` Inki Dae
  0 siblings, 1 reply; 57+ messages in thread
From: Sam Ravnborg @ 2020-11-07 22:27 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent.pinchart, kernel,
	sylvester.nawrocki

On Fri, Sep 11, 2020 at 03:54:01PM +0200, Michael Tretter wrote:
> As the driver shall be usable with drivers that use the component
> framework and drivers that don't, split the common probing code into a
> separate function that can be called from different locations.
> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>

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

* Re: [PATCH v2 06/16] drm/exynos: shift register values to fields on write
  2020-09-11 13:54   ` [PATCH v2 06/16] drm/exynos: shift register values to fields on write Michael Tretter
@ 2020-11-07 22:39     ` Sam Ravnborg
  2020-11-10  8:28       ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Sam Ravnborg @ 2020-11-07 22:39 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent.pinchart, kernel,
	sylvester.nawrocki, Adrian Ratiu

Hi Michael.

On Fri, Sep 11, 2020 at 03:54:03PM +0200, Michael Tretter wrote:
> The phy timings are already shifted to the field position. If the driver
> is reused on multiple platforms, this exposes the field positions to the
> platform code.
> 
> Store only the timing values in the platform data and shift the value to
> the field when writing the fields to the registers.
> 
> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>

This and the following patch smells like the regmap functionality is
partly open coded. regmaps supports defining different register layouts
and select the correct layout at runtime.

See for example:
https://www.collabora.com/news-and-blog/blog/2020/05/27/using-regmaps-to-make-linux-drivers-more-generic/
or
https://www.youtube.com/watch?v=0RPDGANArFc

Some parts is not a perfect fit - but using regmaps will make it better
as a general and well-known solution is used.

@Adrian - see https://lore.kernel.org/dri-devel/20200911135413.3654800-1-m.tretter@pengutronix.de/T/#m8e211c8cce915168cf2b8c4eef1c7ec9b8447af8
for the original patch.

	Sam

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

* Re: [PATCH v2 03/16] drm/exynos: use exynos_dsi as drvdata
  2020-11-07 22:24     ` Sam Ravnborg
@ 2020-11-09  2:24       ` Inki Dae
  0 siblings, 0 replies; 57+ messages in thread
From: Inki Dae @ 2020-11-09  2:24 UTC (permalink / raw)
  To: Sam Ravnborg, Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent.pinchart, kernel,
	sylvester.nawrocki



20. 11. 8. 오전 7:24에 Sam Ravnborg 이(가) 쓴 글:
> On Fri, Sep 11, 2020 at 03:54:00PM +0200, Michael Tretter wrote:
>> Use the exynos_dsi as drvdata instead of the encoder to further decouple
>> the driver from the encoder.
>>
>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
> 
> Likewise, the exynos people are expected to pick this up.

Cleanup patch so picked it up.

Thanks,
Inki Dae


> 
> 	Sam
> 

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

* Re: [PATCH v2 04/16] drm/exynos: extract helper functions for probe
  2020-11-07 22:27     ` Sam Ravnborg
@ 2020-11-09  2:52       ` Inki Dae
  0 siblings, 0 replies; 57+ messages in thread
From: Inki Dae @ 2020-11-09  2:52 UTC (permalink / raw)
  To: Sam Ravnborg, Michael Tretter
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent.pinchart, kernel,
	sylvester.nawrocki



20. 11. 8. 오전 7:27에 Sam Ravnborg 이(가) 쓴 글:
> On Fri, Sep 11, 2020 at 03:54:01PM +0200, Michael Tretter wrote:
>> As the driver shall be usable with drivers that use the component
>> framework and drivers that don't, split the common probing code into a
>> separate function that can be called from different locations.
>>
>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> Reviewed-by: Sam Ravnborg <sam@ravnborg.org>

This patch and other are related to what this patch series do. However, this patch makes Exynos board not working yet.
So excepting patches 2 to 3, I will wait for that this patch series will be fixed and reviewed more.

Thanks,
Inki Dae

> 

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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
                     ` (14 preceding siblings ...)
  2020-09-11 13:54   ` [PATCH v2 15/16] drm/exynos: split out platform specific code Michael Tretter
@ 2020-11-09  3:15   ` Inki Dae
  2020-11-10  8:13     ` Michael Tretter
  15 siblings, 1 reply; 57+ messages in thread
From: Inki Dae @ 2020-11-09  3:15 UTC (permalink / raw)
  To: Michael Tretter, dri-devel, linux-samsung-soc
  Cc: kernel, Laurent.pinchart, krzk, narmstrong, b.zolnierkie,
	sylvester.nawrocki, a.hajda, jy0922.shim, sw0312.kim

Hi Michael,

Thanks for your contribution.

20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
> This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
> bridge and make it usable with other drivers. Although the driver is
> converted, it still supports the component framework API to stay compliant
> with the Exynos DRM driver.
> 
> The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
> i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
> the Exynos Decon. The driver for the LCDIF does not use the component
> framework, but uses drm bridges.
> 
> I don't have any Exynos SoC to actually test the series. I build a dummy to
> test the bridge with a component driver, to make sure that at least the
> initialization is working. Furthermore, tested the driver as a bridge with a
> few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
> should verify that the driver is still working on Exynos hardware.
> 
> I also changed the order of the patches to first make the driver more platform
> independent (patches 2 to 8), then convert to a drm bridge driver (patches 10

Just a fundamental question,
A MIPI-DSI(Display Serial Interface) bus device would be one of an encoder type of devices not bridge such as DSI to LVDS and LVDS to DSI bridge devices, and also image enhancer and image compressor in case of Exynos.
Why do you want to convert such MIPI-DSI driver to bridge type of driver? Seems not sensible. The reason would be just to share MIPI-DSI phy driver for Exynos with i.MX8M Mini?

Thanks,
Inki Dae


> to 13) and finally expose the API, split the code and move the platform
> independent driver to the bridges (patches 14 - 16). Hopefully this simplifies
> testing/bisecting and helps me to understand potential error reports.
> 
> Also I added host_ops for attach/detach and the tearing effect handler to make
> the calls into the platform code more visible.
> 
> Furthermore, the series should now apply to linux-next and correctly build the
> exynos_defconfig.
> 
> Thanks,
> 
> Michael
> 
> Changelog:
> 
> v2:
> - rebase on linux-next
> - verify with exynos_defconfig
> - fix crashes reported by Marek Szyprowski Exynos3250-based Rinato
> - reorder patches
> - add host_ops for platform specific code
> - roughly test component framework integration with dummy
> 
> Michael Tretter (16):
>   drm/encoder: remove obsolete documentation of bridge
>   drm/exynos: remove in_bridge_node from exynos_dsi
>   drm/exynos: use exynos_dsi as drvdata
>   drm/exynos: extract helper functions for probe
>   drm/exynos: move dsi host registration to probe
>   drm/exynos: shift register values to fields on write
>   drm/exynos: use identifier instead of register offsets
>   drm/exynos: add host_ops callback for platform drivers
>   drm/exynos: add callback for tearing effect handler
>   drm/exynos: implement a drm bridge
>   drm/exynos: convert encoder functions to bridge function
>   drm/exynos: configure mode on drm bridge
>   drm/exynos: get encoder from bridge whenever possible
>   drm/exynos: add API functions for platform drivers
>   drm/exynos: split out platform specific code
>   drm/exynos: move bridge driver to bridges
> 
>  drivers/gpu/drm/bridge/Kconfig          |    9 +
>  drivers/gpu/drm/bridge/Makefile         |    1 +
>  drivers/gpu/drm/bridge/samsung-dsim.c   | 1790 +++++++++++++++++++++
>  drivers/gpu/drm/exynos/Kconfig          |    5 +-
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c | 1927 ++---------------------
>  include/drm/bridge/samsung-dsim.h       |   64 +
>  include/drm/drm_encoder.h               |    1 -
>  7 files changed, 2027 insertions(+), 1770 deletions(-)
>  create mode 100644 drivers/gpu/drm/bridge/samsung-dsim.c
>  create mode 100644 include/drm/bridge/samsung-dsim.h
> 

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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-11-09  3:15   ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Inki Dae
@ 2020-11-10  8:13     ` Michael Tretter
  2020-11-10 12:34       ` Marek Szyprowski
  2020-11-11  3:04       ` Inki Dae
  0 siblings, 2 replies; 57+ messages in thread
From: Michael Tretter @ 2020-11-10  8:13 UTC (permalink / raw)
  To: Inki Dae
  Cc: dri-devel, linux-samsung-soc, kernel, Laurent.pinchart, krzk,
	narmstrong, b.zolnierkie, sylvester.nawrocki, a.hajda,
	jy0922.shim, sw0312.kim

On Mon, 09 Nov 2020 12:15:39 +0900, Inki Dae wrote:
> 20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
> > This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
> > bridge and make it usable with other drivers. Although the driver is
> > converted, it still supports the component framework API to stay compliant
> > with the Exynos DRM driver.
> > 
> > The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
> > i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
> > the Exynos Decon. The driver for the LCDIF does not use the component
> > framework, but uses drm bridges.
> > 
> > I don't have any Exynos SoC to actually test the series. I build a dummy to
> > test the bridge with a component driver, to make sure that at least the
> > initialization is working. Furthermore, tested the driver as a bridge with a
> > few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
> > should verify that the driver is still working on Exynos hardware.
> > 
> > I also changed the order of the patches to first make the driver more platform
> > independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
> 
> Just a fundamental question, A MIPI-DSI(Display Serial Interface) bus device
> would be one of an encoder type of devices not bridge such as DSI to LVDS
> and LVDS to DSI bridge devices, and also image enhancer and image compressor
> in case of Exynos.

I don't understand, why the MIPI-DSI bus device would be an encoder type and
DSI to LVDS or MIPI-DSI to HDMI would be bridges. For example, the device tree
documentation for the DSIM states that the DSIM receives RGB video as input
and produces MIPI-DSI as output. Thus, the DSIM is basically a parallel RGB to
MIPI-DSI bridge and the encoder is the LCD controller that encodes the video
data as parallel RGB.

On the i.MX8MM, the LCDIF is already the encoder. On Exynos, the series
implements the encoder in the platform glue, but in the end the encoder can
probably be moved to the DECON.

> Why do you want to convert such MIPI-DSI driver to bridge type of driver?
> Seems not sensible. The reason would be just to share MIPI-DSI phy driver
> for Exynos with i.MX8M Mini?

Yes, the reason is that the driver should be shared between Exynos and
i.MX8MM. It is the same IP and I don't see a reason why we should introduce
another driver for the same IP if the driver works for both SoCs.

Michael

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

* Re: [PATCH v2 06/16] drm/exynos: shift register values to fields on write
  2020-11-07 22:39     ` Sam Ravnborg
@ 2020-11-10  8:28       ` Michael Tretter
  0 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-11-10  8:28 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: dri-devel, linux-samsung-soc, jy0922.shim, b.zolnierkie,
	narmstrong, sw0312.kim, krzk, a.hajda, Laurent.pinchart, kernel,
	sylvester.nawrocki, Adrian Ratiu

On Sat, 07 Nov 2020 23:39:30 +0100, Sam Ravnborg wrote:
> On Fri, Sep 11, 2020 at 03:54:03PM +0200, Michael Tretter wrote:
> > The phy timings are already shifted to the field position. If the driver
> > is reused on multiple platforms, this exposes the field positions to the
> > platform code.
> > 
> > Store only the timing values in the platform data and shift the value to
> > the field when writing the fields to the registers.
> > 
> > Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> 
> This and the following patch smells like the regmap functionality is
> partly open coded. regmaps supports defining different register layouts
> and select the correct layout at runtime.
> 
> See for example:
> https://www.collabora.com/news-and-blog/blog/2020/05/27/using-regmaps-to-make-linux-drivers-more-generic/
> or
> https://www.youtube.com/watch?v=0RPDGANArFc
> 
> Some parts is not a perfect fit - but using regmaps will make it better
> as a general and well-known solution is used.

I considered using regmaps, but there was something that didn't work out.
Unfortunately, I don't remember, what it actually was. Therefore, it is
probably best to use regmaps here.

Michael

> 
> @Adrian - see https://lore.kernel.org/dri-devel/20200911135413.3654800-1-m.tretter@pengutronix.de/T/#m8e211c8cce915168cf2b8c4eef1c7ec9b8447af8
> for the original patch.
> 
> 	Sam
> 

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

* Re: [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge
  2020-11-07 15:07     ` Adam Ford
@ 2020-11-10  8:46       ` Michael Tretter
  0 siblings, 0 replies; 57+ messages in thread
From: Michael Tretter @ 2020-11-10  8:46 UTC (permalink / raw)
  To: Adam Ford
  Cc: dri-devel, linux-samsung-soc, jy0922.shim,
	Bartlomiej Zolnierkiewicz, Neil Armstrong, sw0312.kim,
	Krzysztof Kozlowski, a.hajda, Laurent Pinchart, Sascha Hauer,
	sylvester.nawrocki

On Sat, 07 Nov 2020 09:07:19 -0600, Adam Ford wrote:
> On Fri, Sep 11, 2020 at 8:54 AM Michael Tretter
> <m.tretter@pengutronix.de> wrote:
> >
> > In commit 05193dc38197 ("drm/bridge: Make the bridge chain a
> > double-linked list") the bridge has been removed and replaced by a
> > private field. Remove the leftover documentation of the removed field.
> >
> > Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> What is the status of this series?  I know of at least one other patch
> series depending on this.

Sorry for that. I lately didn't have time to work on the series.

There are two big open TODOs:

- How should this bridge react if there is no out bridge available, yet? This
  series implements a static approach by returning EPROBE_DEFER from
  bridge_attach if there isn't a next bridge, connector or display. Andrezej
  suggested a dynamic approach which allows to attach this bridge without a
  next bridge and dynamically add further bridges/panels. The latter approach
  didn't work with the mxsfb driver, but I didn't have time to look into this.

- The component framework stuff that allows to use the bridge with the Exynos
  driver should not go into the bridge driver, but stay in the platform part.

Michael

> 
> adam
> 
> > ---
> > v2: none
> > ---
> >  include/drm/drm_encoder.h | 1 -
> >  1 file changed, 1 deletion(-)
> >
> > diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h
> > index a60f5f1555ac..5dfa5f7a80a7 100644
> > --- a/include/drm/drm_encoder.h
> > +++ b/include/drm/drm_encoder.h
> > @@ -89,7 +89,6 @@ struct drm_encoder_funcs {
> >   * @head: list management
> >   * @base: base KMS object
> >   * @name: human readable name, can be overwritten by the driver
> > - * @bridge: bridge associated to the encoder
> >   * @funcs: control functions
> >   * @helper_private: mid-layer private data
> >   *
> > --
> > 2.20.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-11-10  8:13     ` Michael Tretter
@ 2020-11-10 12:34       ` Marek Szyprowski
  2020-11-10 18:52         ` Sam Ravnborg
  2020-11-11  3:04       ` Inki Dae
  1 sibling, 1 reply; 57+ messages in thread
From: Marek Szyprowski @ 2020-11-10 12:34 UTC (permalink / raw)
  To: Michael Tretter, Inki Dae
  Cc: dri-devel, linux-samsung-soc, kernel, Laurent.pinchart, krzk,
	narmstrong, b.zolnierkie, sylvester.nawrocki, a.hajda,
	jy0922.shim, sw0312.kim

Hi Michael,

On 10.11.2020 09:13, Michael Tretter wrote:
> On Mon, 09 Nov 2020 12:15:39 +0900, Inki Dae wrote:
>> 20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
>>> This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
>>> bridge and make it usable with other drivers. Although the driver is
>>> converted, it still supports the component framework API to stay compliant
>>> with the Exynos DRM driver.
>>>
>>> The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
>>> i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
>>> the Exynos Decon. The driver for the LCDIF does not use the component
>>> framework, but uses drm bridges.
>>>
>>> I don't have any Exynos SoC to actually test the series. I build a dummy to
>>> test the bridge with a component driver, to make sure that at least the
>>> initialization is working. Furthermore, tested the driver as a bridge with a
>>> few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
>>> should verify that the driver is still working on Exynos hardware.
>>>
>>> I also changed the order of the patches to first make the driver more platform
>>> independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
>> Just a fundamental question, A MIPI-DSI(Display Serial Interface) bus device
>> would be one of an encoder type of devices not bridge such as DSI to LVDS
>> and LVDS to DSI bridge devices, and also image enhancer and image compressor
>> in case of Exynos.
> I don't understand, why the MIPI-DSI bus device would be an encoder type and
> DSI to LVDS or MIPI-DSI to HDMI would be bridges. For example, the device tree
> documentation for the DSIM states that the DSIM receives RGB video as input
> and produces MIPI-DSI as output. Thus, the DSIM is basically a parallel RGB to
> MIPI-DSI bridge and the encoder is the LCD controller that encodes the video
> data as parallel RGB.
>
> On the i.MX8MM, the LCDIF is already the encoder. On Exynos, the series
> implements the encoder in the platform glue, but in the end the encoder can
> probably be moved to the DECON.

This is probably the historical decision. That time when Exynos DSI 
driver has been implemented, support for DRM bridges wasn't ready enough 
to use to for such purpose.

Frankly, I'm still not convinced that the current DRM bridge framework 
provides everything needed to reimplement the Exynos DSI driver with all 
its features. There are a lots of corner cases and order-specific bits 
in turning on/off the display pipeline, which don't map nicely to the 
bridge pre_enable (called in post-order) and enable (called in 
pre-order) callbacks. Especially if you consider that there might be 
another bridge before and after.

I think that Andrzej Hajda already pointed those drawbacks of the 
current design. Last week I've spent some significant amount of time 
playing with exynos dsi code to check how to match its operations 
(especially the runtime power management) to this design with the 
current boards (Arndale with additional DSI->LVDS bridge and panel, 
Trats2 with DSI panel and TM2e with MIC 'in-bridge' and DSI panel), but 
without a success.

>> Why do you want to convert such MIPI-DSI driver to bridge type of driver?
>> Seems not sensible. The reason would be just to share MIPI-DSI phy driver
>> for Exynos with i.MX8M Mini?
> Yes, the reason is that the driver should be shared between Exynos and
> i.MX8MM. It is the same IP and I don't see a reason why we should introduce
> another driver for the same IP if the driver works for both SoCs.

I think that the easiest way to share this driver between Exynos and iMX 
would be to extract the low-level code (the code that plays with 
hardware registers) to the common plane, while keeping the separate DRM 
glue, device component and platform device parts. This way the Exynos 
will continue to use it in the current form, while iMX can start using 
it as DRM bridge. A bit similar approach is used with exynos_dp driver 
and analogix_dp bridge shared with other SoCs.

I hope that later, when the bridge related issue are resolved, the 
Exynos can be converted too, so the encoder creation moved to FIMD and 
Decon.

Best regards

-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-11-10 12:34       ` Marek Szyprowski
@ 2020-11-10 18:52         ` Sam Ravnborg
  0 siblings, 0 replies; 57+ messages in thread
From: Sam Ravnborg @ 2020-11-10 18:52 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: Michael Tretter, Inki Dae, linux-samsung-soc, jy0922.shim,
	narmstrong, b.zolnierkie, sw0312.kim, krzk, a.hajda, dri-devel,
	kernel, sylvester.nawrocki, Laurent.pinchart

Hi Marek,

On Tue, Nov 10, 2020 at 01:34:26PM +0100, Marek Szyprowski wrote:
> Hi Michael,
> 
> On 10.11.2020 09:13, Michael Tretter wrote:
> > On Mon, 09 Nov 2020 12:15:39 +0900, Inki Dae wrote:
> >> 20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
> >>> This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
> >>> bridge and make it usable with other drivers. Although the driver is
> >>> converted, it still supports the component framework API to stay compliant
> >>> with the Exynos DRM driver.
> >>>
> >>> The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
> >>> i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
> >>> the Exynos Decon. The driver for the LCDIF does not use the component
> >>> framework, but uses drm bridges.
> >>>
> >>> I don't have any Exynos SoC to actually test the series. I build a dummy to
> >>> test the bridge with a component driver, to make sure that at least the
> >>> initialization is working. Furthermore, tested the driver as a bridge with a
> >>> few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
> >>> should verify that the driver is still working on Exynos hardware.
> >>>
> >>> I also changed the order of the patches to first make the driver more platform
> >>> independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
> >> Just a fundamental question, A MIPI-DSI(Display Serial Interface) bus device
> >> would be one of an encoder type of devices not bridge such as DSI to LVDS
> >> and LVDS to DSI bridge devices, and also image enhancer and image compressor
> >> in case of Exynos.
> > I don't understand, why the MIPI-DSI bus device would be an encoder type and
> > DSI to LVDS or MIPI-DSI to HDMI would be bridges. For example, the device tree
> > documentation for the DSIM states that the DSIM receives RGB video as input
> > and produces MIPI-DSI as output. Thus, the DSIM is basically a parallel RGB to
> > MIPI-DSI bridge and the encoder is the LCD controller that encodes the video
> > data as parallel RGB.
> >
> > On the i.MX8MM, the LCDIF is already the encoder. On Exynos, the series
> > implements the encoder in the platform glue, but in the end the encoder can
> > probably be moved to the DECON.
> 
> This is probably the historical decision. That time when Exynos DSI 
> driver has been implemented, support for DRM bridges wasn't ready enough 
> to use to for such purpose.
> 
> Frankly, I'm still not convinced that the current DRM bridge framework 
> provides everything needed to reimplement the Exynos DSI driver with all 
> its features. There are a lots of corner cases and order-specific bits 
> in turning on/off the display pipeline, which don't map nicely to the 
> bridge pre_enable (called in post-order) and enable (called in 
> pre-order) callbacks. Especially if you consider that there might be 
> another bridge before and after.
> 
> I think that Andrzej Hajda already pointed those drawbacks of the 
> current design. Last week I've spent some significant amount of time 
> playing with exynos dsi code to check how to match its operations 
> (especially the runtime power management) to this design with the 
> current boards (Arndale with additional DSI->LVDS bridge and panel, 
> Trats2 with DSI panel and TM2e with MIC 'in-bridge' and DSI panel), but 
> without a success.

Can you help by iterating the missing pieces in the current bridge
infrastructure? Maybe it is something we can work out in a way that
benefits more than one bridge driver.

It would be nice with specific issues to look into.

Thanks in advance,

	Sam

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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-11-10  8:13     ` Michael Tretter
  2020-11-10 12:34       ` Marek Szyprowski
@ 2020-11-11  3:04       ` Inki Dae
  2020-11-11  3:11         ` Inki Dae
  1 sibling, 1 reply; 57+ messages in thread
From: Inki Dae @ 2020-11-11  3:04 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, kernel, Laurent.pinchart, krzk,
	narmstrong, b.zolnierkie, sylvester.nawrocki, a.hajda,
	jy0922.shim, sw0312.kim



20. 11. 10. 오후 5:13에 Michael Tretter 이(가) 쓴 글:
> On Mon, 09 Nov 2020 12:15:39 +0900, Inki Dae wrote:
>> 20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
>>> This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
>>> bridge and make it usable with other drivers. Although the driver is
>>> converted, it still supports the component framework API to stay compliant
>>> with the Exynos DRM driver.
>>>
>>> The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
>>> i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
>>> the Exynos Decon. The driver for the LCDIF does not use the component
>>> framework, but uses drm bridges.
>>>
>>> I don't have any Exynos SoC to actually test the series. I build a dummy to
>>> test the bridge with a component driver, to make sure that at least the
>>> initialization is working. Furthermore, tested the driver as a bridge with a
>>> few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
>>> should verify that the driver is still working on Exynos hardware.
>>>
>>> I also changed the order of the patches to first make the driver more platform
>>> independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
>>
>> Just a fundamental question, A MIPI-DSI(Display Serial Interface) bus device
>> would be one of an encoder type of devices not bridge such as DSI to LVDS
>> and LVDS to DSI bridge devices, and also image enhancer and image compressor
>> in case of Exynos.
> 
> I don't understand, why the MIPI-DSI bus device would be an encoder type and
> DSI to LVDS or MIPI-DSI to HDMI would be bridges. For example, the device tree
> documentation for the DSIM states that the DSIM receives RGB video as input
> and produces MIPI-DSI as output. Thus, the DSIM is basically a parallel RGB to

MIPI-DSI receives RGB video as input and encodes it to MIPI packet and then transfers the packet to MIPI panel.
And finally, MIPI panel decodes the packet and updates it - RGB data - on its SRAM.

MIPI-DSI driver programs how the RGB video should be made as MIPI packet. For more detail, you could refer to MIPI-DSI spec.
This would be why we handle MIPI-DSI driver as an encoder like other ARM SoC DRM drivers did.

> MIPI-DSI bridge and the encoder is the LCD controller that encodes the video
> data as parallel RGB.
> 
> On the i.MX8MM, the LCDIF is already the encoder. On Exynos, the series
> implements the encoder in the platform glue, but in the end the encoder can
> probably be moved to the DECON.

As you know, Display controller can transfer RGB video to various devices such as RGB panel, CPU panel, LVDS panel via LVDS bridge, MIPI panel via MIPI-DSI bus device, and so on like below,

Display Controller --> RGB panel or CPU panel.
Display Controller --> LVDS bridge --> LVDS panel.
Display Controller --> MIPI DSI bus device --> MIPI Panel.
...

Display controller drivers such as FIMD and DECON series in case of Exynos don't create an encoder driver-internally instead of it depends on Display pipeline configuration - what kind of Display panel is used.
In fact, if the Display pipeline uses RGB panel or CPU panel without Display bus device such as MIPI-DSI, then FIMD and DECON drivers create an encoder for it internally - just we separated the code to consider other type of panels.

On the I.MX8MM, could you share how to handle an encoder if some board has only MIPI-DSI panel, and in this case, where is an encoder for it created? I looked into I.MX8MM DRM driver but didn't find MIPI-DSI driver.
Seems that they support only parallel display, HDMI and LVDS panel.

Thanks,
Inki Dae

> 
>> Why do you want to convert such MIPI-DSI driver to bridge type of driver?
>> Seems not sensible. The reason would be just to share MIPI-DSI phy driver
>> for Exynos with i.MX8M Mini?
> 
> Yes, the reason is that the driver should be shared between Exynos and
> i.MX8MM. It is the same IP and I don't see a reason why we should introduce
> another driver for the same IP if the driver works for both SoCs.
> 
> Michael
> 

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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-11-11  3:04       ` Inki Dae
@ 2020-11-11  3:11         ` Inki Dae
  2020-11-11 10:18           ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Inki Dae @ 2020-11-11  3:11 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, kernel, Laurent.pinchart, krzk,
	narmstrong, b.zolnierkie, sylvester.nawrocki, a.hajda,
	jy0922.shim, sw0312.kim



20. 11. 11. 오후 12:04에 Inki Dae 이(가) 쓴 글:
> 
> 
> 20. 11. 10. 오후 5:13에 Michael Tretter 이(가) 쓴 글:
>> On Mon, 09 Nov 2020 12:15:39 +0900, Inki Dae wrote:
>>> 20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
>>>> This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
>>>> bridge and make it usable with other drivers. Although the driver is
>>>> converted, it still supports the component framework API to stay compliant
>>>> with the Exynos DRM driver.
>>>>
>>>> The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
>>>> i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
>>>> the Exynos Decon. The driver for the LCDIF does not use the component
>>>> framework, but uses drm bridges.
>>>>
>>>> I don't have any Exynos SoC to actually test the series. I build a dummy to
>>>> test the bridge with a component driver, to make sure that at least the
>>>> initialization is working. Furthermore, tested the driver as a bridge with a
>>>> few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
>>>> should verify that the driver is still working on Exynos hardware.
>>>>
>>>> I also changed the order of the patches to first make the driver more platform
>>>> independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
>>>
>>> Just a fundamental question, A MIPI-DSI(Display Serial Interface) bus device
>>> would be one of an encoder type of devices not bridge such as DSI to LVDS
>>> and LVDS to DSI bridge devices, and also image enhancer and image compressor
>>> in case of Exynos.
>>
>> I don't understand, why the MIPI-DSI bus device would be an encoder type and
>> DSI to LVDS or MIPI-DSI to HDMI would be bridges. For example, the device tree
>> documentation for the DSIM states that the DSIM receives RGB video as input
>> and produces MIPI-DSI as output. Thus, the DSIM is basically a parallel RGB to
> 
> MIPI-DSI receives RGB video as input and encodes it to MIPI packet and then transfers the packet to MIPI panel.
> And finally, MIPI panel decodes the packet and updates it - RGB data - on its SRAM.
> 
> MIPI-DSI driver programs how the RGB video should be made as MIPI packet. For more detail, you could refer to MIPI-DSI spec.
> This would be why we handle MIPI-DSI driver as an encoder like other ARM SoC DRM drivers did.
> 
>> MIPI-DSI bridge and the encoder is the LCD controller that encodes the video
>> data as parallel RGB.
>>
>> On the i.MX8MM, the LCDIF is already the encoder. On Exynos, the series
>> implements the encoder in the platform glue, but in the end the encoder can
>> probably be moved to the DECON.
> 
> As you know, Display controller can transfer RGB video to various devices such as RGB panel, CPU panel, LVDS panel via LVDS bridge, MIPI panel via MIPI-DSI bus device, and so on like below,
> 
> Display Controller --> RGB panel or CPU panel.
> Display Controller --> LVDS bridge --> LVDS panel.
> Display Controller --> MIPI DSI bus device --> MIPI Panel.
> ...
> 
> Display controller drivers such as FIMD and DECON series in case of Exynos don't create an encoder driver-internally instead of it depends on Display pipeline configuration - what kind of Display panel is used.
> In fact, if the Display pipeline uses RGB panel or CPU panel without Display bus device such as MIPI-DSI, then FIMD and DECON drivers create an encoder for it internally - just we separated the code to consider other type of panels.
> 
> On the I.MX8MM, could you share how to handle an encoder if some board has only MIPI-DSI panel, and in this case, where is an encoder for it created? I looked into I.MX8MM DRM driver but didn't find MIPI-DSI driver.
> Seems that they support only parallel display, HDMI and LVDS panel.

One more thing, If I saw correctly, the LVDS driver of IMX DRM - lmx_ldb - creates an encoder internally like MIPI-DSI driver of Exynos DRM did.

> 
> Thanks,
> Inki Dae
> 
>>
>>> Why do you want to convert such MIPI-DSI driver to bridge type of driver?
>>> Seems not sensible. The reason would be just to share MIPI-DSI phy driver
>>> for Exynos with i.MX8M Mini?
>>
>> Yes, the reason is that the driver should be shared between Exynos and
>> i.MX8MM. It is the same IP and I don't see a reason why we should introduce
>> another driver for the same IP if the driver works for both SoCs.
>>
>> Michael
>>
> 

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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-11-11  3:11         ` Inki Dae
@ 2020-11-11 10:18           ` Michael Tretter
  2020-11-13  9:34             ` Inki Dae
  0 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2020-11-11 10:18 UTC (permalink / raw)
  To: Inki Dae
  Cc: dri-devel, linux-samsung-soc, kernel, Laurent.pinchart, krzk,
	narmstrong, b.zolnierkie, sylvester.nawrocki, a.hajda,
	jy0922.shim, sw0312.kim

On Wed, 11 Nov 2020 12:11:15 +0900, Inki Dae wrote:
> 20. 11. 11. 오후 12:04에 Inki Dae 이(가) 쓴 글:
> > 20. 11. 10. 오후 5:13에 Michael Tretter 이(가) 쓴 글:
> >> On Mon, 09 Nov 2020 12:15:39 +0900, Inki Dae wrote:
> >>> 20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
> >>>> This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
> >>>> bridge and make it usable with other drivers. Although the driver is
> >>>> converted, it still supports the component framework API to stay compliant
> >>>> with the Exynos DRM driver.
> >>>>
> >>>> The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
> >>>> i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
> >>>> the Exynos Decon. The driver for the LCDIF does not use the component
> >>>> framework, but uses drm bridges.
> >>>>
> >>>> I don't have any Exynos SoC to actually test the series. I build a dummy to
> >>>> test the bridge with a component driver, to make sure that at least the
> >>>> initialization is working. Furthermore, tested the driver as a bridge with a
> >>>> few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
> >>>> should verify that the driver is still working on Exynos hardware.
> >>>>
> >>>> I also changed the order of the patches to first make the driver more platform
> >>>> independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
> >>>
> >>> Just a fundamental question, A MIPI-DSI(Display Serial Interface) bus device
> >>> would be one of an encoder type of devices not bridge such as DSI to LVDS
> >>> and LVDS to DSI bridge devices, and also image enhancer and image compressor
> >>> in case of Exynos.
> >>
> >> I don't understand, why the MIPI-DSI bus device would be an encoder type and
> >> DSI to LVDS or MIPI-DSI to HDMI would be bridges. For example, the device tree
> >> documentation for the DSIM states that the DSIM receives RGB video as input
> >> and produces MIPI-DSI as output. Thus, the DSIM is basically a parallel RGB to
> > 
> > MIPI-DSI receives RGB video as input and encodes it to MIPI packet and then transfers the packet to MIPI panel.
> > And finally, MIPI panel decodes the packet and updates it - RGB data - on its SRAM.
> > 
> > MIPI-DSI driver programs how the RGB video should be made as MIPI packet. For more detail, you could refer to MIPI-DSI spec.
> > This would be why we handle MIPI-DSI driver as an encoder like other ARM SoC DRM drivers did.
> > 
> >> MIPI-DSI bridge and the encoder is the LCD controller that encodes the video
> >> data as parallel RGB.
> >>
> >> On the i.MX8MM, the LCDIF is already the encoder. On Exynos, the series
> >> implements the encoder in the platform glue, but in the end the encoder can
> >> probably be moved to the DECON.
> > 
> > As you know, Display controller can transfer RGB video to various devices such as RGB panel, CPU panel, LVDS panel via LVDS bridge, MIPI panel via MIPI-DSI bus device, and so on like below,
> > 
> > Display Controller --> RGB panel or CPU panel.
> > Display Controller --> LVDS bridge --> LVDS panel.
> > Display Controller --> MIPI DSI bus device --> MIPI Panel.
> > ...
> > 
> > Display controller drivers such as FIMD and DECON series in case of Exynos don't create an encoder driver-internally instead of it depends on Display pipeline configuration - what kind of Display panel is used.
> > In fact, if the Display pipeline uses RGB panel or CPU panel without Display bus device such as MIPI-DSI, then FIMD and DECON drivers create an encoder for it internally - just we separated the code to consider other type of panels.

What happens if I add a MIPI-DSI --> HDMI bridge to the Display pipeline? Then
the Pipeline is

Display Controller --> MIPI DSI bus device --> HDMI bridge --> HDMI Panel

If the type of the Display panel decides which part of the pipeline provides
the encoder, the HDMI bridge driver would be responsible for creating the
encoder, right? Thus, the MIPI-DSI driver would not be responsible for
creating the encoder and would also get the encoder from another driver.
Therefore, I prefer to think of the Display Controller as the encoder and
other bridges are just bridges.

BTW, this is exactly the Display pipeline that is used on the i.MX8MM EVK.

> > 
> > On the I.MX8MM, could you share how to handle an encoder if some board has only MIPI-DSI panel, and in this case, where is an encoder for it created? I looked into I.MX8MM DRM driver but didn't find MIPI-DSI driver.
> > Seems that they support only parallel display, HDMI and LVDS panel.
> 
> One more thing, If I saw correctly, the LVDS driver of IMX DRM - lmx_ldb - creates an encoder internally like MIPI-DSI driver of Exynos DRM did.

Yes, but the IMX DRM driver is not used on the i.MX8MM. The i.MX8MM uses the
LCDIF display controller instead of the IPU of the i.MX6. The driver for the
LCDIF is the mxsfb driver, which in turn uses the drm_simple_display_pipe,
which already provides the encoder. Therefore, to use a bridge driver with a
driver based on a drm_simple_display_pipe, the bridge driver must accept other
encoders.

Michael

> 
> > 
> > Thanks,
> > Inki Dae
> > 
> >>
> >>> Why do you want to convert such MIPI-DSI driver to bridge type of driver?
> >>> Seems not sensible. The reason would be just to share MIPI-DSI phy driver
> >>> for Exynos with i.MX8M Mini?
> >>
> >> Yes, the reason is that the driver should be shared between Exynos and
> >> i.MX8MM. It is the same IP and I don't see a reason why we should introduce
> >> another driver for the same IP if the driver works for both SoCs.
> >>
> >> Michael
> >>
> > 
> 

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

* Re: [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge
  2020-11-11 10:18           ` Michael Tretter
@ 2020-11-13  9:34             ` Inki Dae
  0 siblings, 0 replies; 57+ messages in thread
From: Inki Dae @ 2020-11-13  9:34 UTC (permalink / raw)
  To: Michael Tretter
  Cc: dri-devel, linux-samsung-soc, kernel, Laurent.pinchart, krzk,
	narmstrong, b.zolnierkie, sylvester.nawrocki, a.hajda,
	jy0922.shim, sw0312.kim



20. 11. 11. 오후 7:18에 Michael Tretter 이(가) 쓴 글:
> On Wed, 11 Nov 2020 12:11:15 +0900, Inki Dae wrote:
>> 20. 11. 11. 오후 12:04에 Inki Dae 이(가) 쓴 글:
>>> 20. 11. 10. 오후 5:13에 Michael Tretter 이(가) 쓴 글:
>>>> On Mon, 09 Nov 2020 12:15:39 +0900, Inki Dae wrote:
>>>>> 20. 9. 11. 오후 10:53에 Michael Tretter 이(가) 쓴 글:
>>>>>> This is v2 of the series to convert the Exynos MIPI DSI driver into a drm
>>>>>> bridge and make it usable with other drivers. Although the driver is
>>>>>> converted, it still supports the component framework API to stay compliant
>>>>>> with the Exynos DRM driver.
>>>>>>
>>>>>> The Exynos MIPI DSI Phy is also found on the i.MX8M Mini. However, on the
>>>>>> i.MX8M Mini, the bridge is driven by an LCDIF display controller instead of
>>>>>> the Exynos Decon. The driver for the LCDIF does not use the component
>>>>>> framework, but uses drm bridges.
>>>>>>
>>>>>> I don't have any Exynos SoC to actually test the series. I build a dummy to
>>>>>> test the bridge with a component driver, to make sure that at least the
>>>>>> initialization is working. Furthermore, tested the driver as a bridge with a
>>>>>> few additional unfinished patches on the i.MX8M Mini EVK. However, somebody
>>>>>> should verify that the driver is still working on Exynos hardware.
>>>>>>
>>>>>> I also changed the order of the patches to first make the driver more platform
>>>>>> independent (patches 2 to 8), then convert to a drm bridge driver (patches 10
>>>>>
>>>>> Just a fundamental question, A MIPI-DSI(Display Serial Interface) bus device
>>>>> would be one of an encoder type of devices not bridge such as DSI to LVDS
>>>>> and LVDS to DSI bridge devices, and also image enhancer and image compressor
>>>>> in case of Exynos.
>>>>
>>>> I don't understand, why the MIPI-DSI bus device would be an encoder type and
>>>> DSI to LVDS or MIPI-DSI to HDMI would be bridges. For example, the device tree
>>>> documentation for the DSIM states that the DSIM receives RGB video as input
>>>> and produces MIPI-DSI as output. Thus, the DSIM is basically a parallel RGB to
>>>
>>> MIPI-DSI receives RGB video as input and encodes it to MIPI packet and then transfers the packet to MIPI panel.
>>> And finally, MIPI panel decodes the packet and updates it - RGB data - on its SRAM.
>>>
>>> MIPI-DSI driver programs how the RGB video should be made as MIPI packet. For more detail, you could refer to MIPI-DSI spec.
>>> This would be why we handle MIPI-DSI driver as an encoder like other ARM SoC DRM drivers did.
>>>
>>>> MIPI-DSI bridge and the encoder is the LCD controller that encodes the video
>>>> data as parallel RGB.
>>>>
>>>> On the i.MX8MM, the LCDIF is already the encoder. On Exynos, the series
>>>> implements the encoder in the platform glue, but in the end the encoder can
>>>> probably be moved to the DECON.
>>>
>>> As you know, Display controller can transfer RGB video to various devices such as RGB panel, CPU panel, LVDS panel via LVDS bridge, MIPI panel via MIPI-DSI bus device, and so on like below,
>>>
>>> Display Controller --> RGB panel or CPU panel.
>>> Display Controller --> LVDS bridge --> LVDS panel.
>>> Display Controller --> MIPI DSI bus device --> MIPI Panel.
>>> ...
>>>
>>> Display controller drivers such as FIMD and DECON series in case of Exynos don't create an encoder driver-internally instead of it depends on Display pipeline configuration - what kind of Display panel is used.
>>> In fact, if the Display pipeline uses RGB panel or CPU panel without Display bus device such as MIPI-DSI, then FIMD and DECON drivers create an encoder for it internally - just we separated the code to consider other type of panels.
> 
> What happens if I add a MIPI-DSI --> HDMI bridge to the Display pipeline? Then
> the Pipeline is
> 
> Display Controller --> MIPI DSI bus device --> HDMI bridge --> HDMI Panel
> 
> If the type of the Display panel decides which part of the pipeline provides
> the encoder, the HDMI bridge driver would be responsible for creating the

HDMI bridge driver will create only an bridge because this is not encoder device but bridge device such as LVDS bridge.

Display Controller(CRTC) --> MIPI DSI bus device(Encoder) --> HDMI bridge(Bridge) --> HDMI Panel(Connector)

> encoder, right? Thus, the MIPI-DSI driver would not be responsible for
> creating the encoder and would also get the encoder from another driver.

I think MIPI-DSI is an encoder device as I mentioned earlier so MIPI-DSI driver would be responsible for creating the encoder.

> Therefore, I prefer to think of the Display Controller as the encoder and
> other bridges are just bridges.

So crtc driver will create an encoder internally in case of parallel RGB Panel *because encoder device isn't used*. On the other hand, each encoder driver will be an encoder in case of other type of panel - which is needed for Display bus device such as MIPI-DSI device.

Thanks,
Inki Dae

> 
> BTW, this is exactly the Display pipeline that is used on the i.MX8MM EVK.
> 
>>>
>>> On the I.MX8MM, could you share how to handle an encoder if some board has only MIPI-DSI panel, and in this case, where is an encoder for it created? I looked into I.MX8MM DRM driver but didn't find MIPI-DSI driver.
>>> Seems that they support only parallel display, HDMI and LVDS panel.
>>
>> One more thing, If I saw correctly, the LVDS driver of IMX DRM - lmx_ldb - creates an encoder internally like MIPI-DSI driver of Exynos DRM did.
> 
> Yes, but the IMX DRM driver is not used on the i.MX8MM. The i.MX8MM uses the
> LCDIF display controller instead of the IPU of the i.MX6. The driver for the
> LCDIF is the mxsfb driver, which in turn uses the drm_simple_display_pipe,
> which already provides the encoder. Therefore, to use a bridge driver with a
> driver based on a drm_simple_display_pipe, the bridge driver must accept other
> encoders.
> 
> Michael
> 
>>
>>>
>>> Thanks,
>>> Inki Dae
>>>
>>>>
>>>>> Why do you want to convert such MIPI-DSI driver to bridge type of driver?
>>>>> Seems not sensible. The reason would be just to share MIPI-DSI phy driver
>>>>> for Exynos with i.MX8M Mini?
>>>>
>>>> Yes, the reason is that the driver should be shared between Exynos and
>>>> i.MX8MM. It is the same IP and I don't see a reason why we should introduce
>>>> another driver for the same IP if the driver works for both SoCs.
>>>>
>>>> Michael
>>>>
>>>
>>
> 

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2020-09-15 19:40             ` Andrzej Hajda
@ 2021-02-01 16:33               ` Michael Tretter
  2021-02-03 20:31                 ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2021-02-01 16:33 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Marek Szyprowski, linux-samsung-soc, jy0922.shim, narmstrong,
	b.zolnierkie, sw0312.kim, krzk, dri-devel, kernel,
	sylvester.nawrocki, Laurent.pinchart, l.stach, frieder.schrempf,
	festevam, abel.vesa, aisheng.dong, shawnguo, linux-imx, tharvey,
	ch, aford173

On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > On 14.09.2020 22:01, Michael Tretter wrote:
> >> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> >>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> >>>> On 11.09.2020 15:54, Michael Tretter wrote:
> >>>>> Make the exynos_dsi driver a full drm bridge that can be found and 
> >>>>> used
> >>>>> from other drivers.
> >>>>>
> >>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> >>>>> already attached to the bridge. This allows to defer the probe of the
> >>>>> display pipe until the downstream bridges are available, too.
> >>>>>
> >>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> >>>> This one (and the whole series applied) still fails on Exynos boards:
> >>>>
> >>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping 
> >>>> operations
> >>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>>> OF: graph: no port node found in /soc/dsi@11c80000
> >>>> 8<--- cut here ---
> >>>> Unable to handle kernel NULL pointer dereference at virtual address 
> >>>> 00000084
> >>>> pgd = (ptrval)
> >>>> [00000084] *pgd=00000000
> >>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>>> Modules linked in:
> >>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> >>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> >>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>>> PC is at drm_bridge_attach+0x18/0x164
> >>>> LR is at exynos_dsi_bind+0x88/0xa8
> >>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> >>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> >>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> >>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> >>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> >>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>>> Stack: (0xef0dfca8 to 0xef0e0000)
> >>>> ...
> >>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> >>>> (exynos_dsi_bind+0x88/0xa8)
> >>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> >>>> (component_bind_all+0xfc/0x290)
> >>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> >>>> (exynos_drm_bind+0xe4/0x19c)
> >>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> >>>> (try_to_bring_up_master+0x1e4/0x2c4)
> >>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> >>>> (component_master_add_with_match+0xd4/0x108)
> >>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> >>>> (exynos_drm_platform_probe+0xe4/0x110)
> >>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> >>>> (platform_drv_probe+0x6c/0xa4)
> >>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> >>>> (really_probe+0x200/0x4fc)
> >>>> [<c067242c>] (really_probe) from [<c06728f0>]
> >>>> (driver_probe_device+0x78/0x1fc)
> >>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> >>>> (device_driver_attach+0x58/0x60)
> >>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> >>>> (__driver_attach+0xdc/0x174)
> >>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> >>>> (bus_for_each_dev+0x68/0xb4)
> >>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> >>>> (bus_add_driver+0x158/0x214)
> >>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>] 
> >>>> (driver_register+0x78/0x110)
> >>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> >>>> (exynos_drm_init+0xe4/0x118)
> >>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> >>>> (do_one_initcall+0x8c/0x42c)
> >>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>>> (kernel_init_freeable+0x190/0x1dc)
> >>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> >>>> (kernel_init+0x8/0x118)
> >>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>>> ...
> >>>> ---[ end trace ee27f313f9ed9da1 ]---
> >>>>
> >>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> >>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> >>>>
> >>>> I will try to debug it a bit more today.
> >>> The above crash has been caused by lack of in_bridge initialization to
> >>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> >>> another issue:
> >>>
> >>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> >>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>> OF: graph: no port node found in /soc/dsi@11c80000
> >>> 8<--- cut here ---
> >>> Unable to handle kernel NULL pointer dereference at virtual address 
> >>> 00000280
> >>> pgd = (ptrval)
> >>> [00000280] *pgd=00000000
> >>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>> Modules linked in:
> >>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> >>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> >>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>> PC is at __mutex_lock+0x54/0xb18
> >>> LR is at lock_is_held_type+0x80/0x138
> >>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> >>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> >>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> >>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> >>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> >>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>> Stack: (0xef0dfd30 to 0xef0e0000)
> >>> ...
> >>> [<c0afc920>] (__mutex_lock) from [<c0afd400>] 
> >>> (mutex_lock_nested+0x1c/0x24)
> >>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> >>> (__exynos_dsi_host_attach+0x20/0x6c)
> >>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> >>> (exynos_dsi_host_attach+0x70/0x194)
> >>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> >>> (s6e8aa0_probe+0x1b0/0x218)
> >>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>] 
> >>> (really_probe+0x200/0x4fc)
> >>> [<c0672530>] (really_probe) from [<c06729f4>]
> >>> (driver_probe_device+0x78/0x1fc)
> >>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> >>> (device_driver_attach+0x58/0x60)
> >>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> >>> (__driver_attach+0xdc/0x174)
> >>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> >>> (bus_for_each_dev+0x68/0xb4)
> >>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> >>> (bus_add_driver+0x158/0x214)
> >>> [<c06715ec>] (bus_add_driver) from [<c0673d20>] 
> >>> (driver_register+0x78/0x110)
> >>> [<c0673d20>] (driver_register) from [<c0102484>]
> >>> (do_one_initcall+0x8c/0x42c)
> >>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>> (kernel_init_freeable+0x190/0x1dc)
> >>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> >>> (kernel_init+0x8/0x118)
> >>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>> ...
> >>> ---[ end trace c06e996ec2e8234d ]---
> >>>
> >>> This means that dsi->encoder.dev is not initialized in
> >>> __exynos_dsi_host_attach().
> >>>
> >>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> >>> earlier -517 (deferred probe), what causes cleanup of encoder and
> >>> release of all drm resources.
> >>>
> >>> Then however, the panel tries to register itself and
> >>> exynos_dsi_host_attach() tries to access the released encoder (which is
> >>> zeroed in drm_encoder_release) and rest of resources, what causes 
> >>> failure.
> >>>
> >>> It looks that something is missing. Maybe mipi host has to be 
> >>> registered
> >>> later, when bridge is ready? I have no idea how it is handled before
> >>> this patch. Andrzej, could you comment it a bit?
> >> I intentionally changed the order, because if another bridge follows 
> >> in the
> >> pipeline, the probe of the drm driver has to be deferred until some 
> >> bridge
> >> provides a connector. The next bridge registers itself via the 
> >> host_attach
> >> function and the deferral is ensured via the bind for the bind/unbind 
> >> API or
> >> the bridge_attach function otherwise.
> >>
> >> On the other hand, the bridge does not have an encoder until the mipi 
> >> device
> >> has been attached.
> >>
> >> As a solution, the exynos dsi driver must initialize the encoder in
> >> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder 
> >> via
> >> exynos_dsi instead of the bridge.
> >>
> >> Can you try to move everything except samsung_dsim_bind from 
> >> exynos_dsi_bind
> >> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> >> crash.
> >
> >
> > The original behaviour is that encoder (exynos_dsi) is registered 
> > regardless of sink presence (initially panel, later also bridge) - it 
> > avoids multiple issues with deferred probe, device driver bind/unbind 
> > and module load/unload. Appearance or disappearance of sink is 
> > reported to host nicely via DSI attach/detach callbacks - and it is 
> > reflected in drm world as change state of the connector.
> >
> > Registering DSI host in bind and unregistering in unbind assures that 
> > if mipi_dsi device is attached/detached the drm device is always 
> > present - it makes device/driver binding race free and allows to avoid 
> > additional locking.
> >
> > Moving DSI host registration to probe changes everything, for sure it 
> > breaks the nice feature of DSI attach/detach callbacks and apparently 
> > can cause different issues depending on device bind order.
> >
> > I will try to look at the patches tomorrow and maybe I can find more 
> > constructive comments :)
> 
> 
> As I said yesterday, exynos_dsi driver uses dsi host attach/detach 
> callbacks to control appearance/disappearance of downstream device. It 
> allows to:
> 
> 1. Safely bind/unbind different device drivers at any time and at any 
> order, without killing exynos_drm and/or crashing system.
> 
> 2. Avoid issues with late drm init - on some platforms exynos_drm device 
> appeared too late, due to deferred probe, and resulted in black screen 
> in userspace.
> 
> 
> Now if we want to convert exynos_dsi to drm_bridge I see following options:
> 
> A. Forgot about callbacks and make the exynos_drm to defer probing until 
> exynos_dsi bridge is available, probably it will cause later exynos_drm 
> appearance, thus probably black screen on some targets. So for sure it 
> will be suboptimal. Making it bridge unbind safe would be another 
> problem, but most developers do not care about it so why should we? :)
> 
> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP, 
> even if downstream devices are not yet attached, on attach/detach notify 
> drm about it via connector status change, for this dsi_host registration 
> should be performed from drm_bridge attach, I guess.
> 
> 
> Option A is more standard, but is unsafe and causes other issues.
> 
> Option B keeps current behaviour.

Maybe we can have both, but I am not sure, if I am missing something:

I still prefer option A for the samsung-dsim driver, because it is more
standard, simpler and avoids issues with encoders, connectors or handling
hotplug.

The idea is to use two bridges in the exynos-dsi driver: One bridge in the
samsung-dsim driver which implements option A and defers probing of the drm
driver until the next bridge is attached. And a second bridge in the
exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
device to appear) and implements the hotplug handling for notifying drm via
connector status change.

The driver for the i.MX8M would use the samsung-dsim bridge without an
additional bridge.

This allows the samsung-dsim driver to expose the standard behavior while the
exynos_dsi may stick to the existing behavior for the exynos_drm driver.

I hope this makes sense and does not sound too crazy. It might be difficult to
get the probing and mipi host/device registration correct, but I will try, if
this can work.

Michael

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-01 16:33               ` Michael Tretter
@ 2021-02-03 20:31                 ` Michael Tretter
  2021-02-04 10:17                   ` Daniel Vetter
  0 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2021-02-03 20:31 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Marek Szyprowski, linux-samsung-soc, jy0922.shim, narmstrong,
	b.zolnierkie, sw0312.kim, krzk, dri-devel, kernel,
	sylvester.nawrocki, Laurent.pinchart, l.stach, frieder.schrempf,
	festevam, abel.vesa, aisheng.dong, shawnguo, linux-imx, tharvey,
	ch, aford173, marex

On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> > W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > > On 14.09.2020 22:01, Michael Tretter wrote:
> > >> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> > >>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> > >>>> On 11.09.2020 15:54, Michael Tretter wrote:
> > >>>>> Make the exynos_dsi driver a full drm bridge that can be found and 
> > >>>>> used
> > >>>>> from other drivers.
> > >>>>>
> > >>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> > >>>>> already attached to the bridge. This allows to defer the probe of the
> > >>>>> display pipe until the downstream bridges are available, too.
> > >>>>>
> > >>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > >>>> This one (and the whole series applied) still fails on Exynos boards:
> > >>>>
> > >>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping 
> > >>>> operations
> > >>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > >>>> OF: graph: no port node found in /soc/dsi@11c80000
> > >>>> 8<--- cut here ---
> > >>>> Unable to handle kernel NULL pointer dereference at virtual address 
> > >>>> 00000084
> > >>>> pgd = (ptrval)
> > >>>> [00000084] *pgd=00000000
> > >>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > >>>> Modules linked in:
> > >>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > >>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > >>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > >>>> PC is at drm_bridge_attach+0x18/0x164
> > >>>> LR is at exynos_dsi_bind+0x88/0xa8
> > >>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > >>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > >>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > >>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > >>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > >>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > >>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > >>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > >>>> Stack: (0xef0dfca8 to 0xef0e0000)
> > >>>> ...
> > >>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > >>>> (exynos_dsi_bind+0x88/0xa8)
> > >>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > >>>> (component_bind_all+0xfc/0x290)
> > >>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > >>>> (exynos_drm_bind+0xe4/0x19c)
> > >>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > >>>> (try_to_bring_up_master+0x1e4/0x2c4)
> > >>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > >>>> (component_master_add_with_match+0xd4/0x108)
> > >>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > >>>> (exynos_drm_platform_probe+0xe4/0x110)
> > >>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > >>>> (platform_drv_probe+0x6c/0xa4)
> > >>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > >>>> (really_probe+0x200/0x4fc)
> > >>>> [<c067242c>] (really_probe) from [<c06728f0>]
> > >>>> (driver_probe_device+0x78/0x1fc)
> > >>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > >>>> (device_driver_attach+0x58/0x60)
> > >>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > >>>> (__driver_attach+0xdc/0x174)
> > >>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > >>>> (bus_for_each_dev+0x68/0xb4)
> > >>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > >>>> (bus_add_driver+0x158/0x214)
> > >>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>] 
> > >>>> (driver_register+0x78/0x110)
> > >>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > >>>> (exynos_drm_init+0xe4/0x118)
> > >>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > >>>> (do_one_initcall+0x8c/0x42c)
> > >>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > >>>> (kernel_init_freeable+0x190/0x1dc)
> > >>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > >>>> (kernel_init+0x8/0x118)
> > >>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > >>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > >>>> ...
> > >>>> ---[ end trace ee27f313f9ed9da1 ]---
> > >>>>
> > >>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > >>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> > >>>>
> > >>>> I will try to debug it a bit more today.
> > >>> The above crash has been caused by lack of in_bridge initialization to
> > >>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> > >>> another issue:
> > >>>
> > >>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > >>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > >>> OF: graph: no port node found in /soc/dsi@11c80000
> > >>> 8<--- cut here ---
> > >>> Unable to handle kernel NULL pointer dereference at virtual address 
> > >>> 00000280
> > >>> pgd = (ptrval)
> > >>> [00000280] *pgd=00000000
> > >>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > >>> Modules linked in:
> > >>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> > >>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> > >>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > >>> PC is at __mutex_lock+0x54/0xb18
> > >>> LR is at lock_is_held_type+0x80/0x138
> > >>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> > >>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> > >>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> > >>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> > >>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> > >>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > >>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > >>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > >>> Stack: (0xef0dfd30 to 0xef0e0000)
> > >>> ...
> > >>> [<c0afc920>] (__mutex_lock) from [<c0afd400>] 
> > >>> (mutex_lock_nested+0x1c/0x24)
> > >>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> > >>> (__exynos_dsi_host_attach+0x20/0x6c)
> > >>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> > >>> (exynos_dsi_host_attach+0x70/0x194)
> > >>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> > >>> (s6e8aa0_probe+0x1b0/0x218)
> > >>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>] 
> > >>> (really_probe+0x200/0x4fc)
> > >>> [<c0672530>] (really_probe) from [<c06729f4>]
> > >>> (driver_probe_device+0x78/0x1fc)
> > >>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> > >>> (device_driver_attach+0x58/0x60)
> > >>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> > >>> (__driver_attach+0xdc/0x174)
> > >>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> > >>> (bus_for_each_dev+0x68/0xb4)
> > >>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> > >>> (bus_add_driver+0x158/0x214)
> > >>> [<c06715ec>] (bus_add_driver) from [<c0673d20>] 
> > >>> (driver_register+0x78/0x110)
> > >>> [<c0673d20>] (driver_register) from [<c0102484>]
> > >>> (do_one_initcall+0x8c/0x42c)
> > >>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > >>> (kernel_init_freeable+0x190/0x1dc)
> > >>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> > >>> (kernel_init+0x8/0x118)
> > >>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > >>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > >>> ...
> > >>> ---[ end trace c06e996ec2e8234d ]---
> > >>>
> > >>> This means that dsi->encoder.dev is not initialized in
> > >>> __exynos_dsi_host_attach().
> > >>>
> > >>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> > >>> earlier -517 (deferred probe), what causes cleanup of encoder and
> > >>> release of all drm resources.
> > >>>
> > >>> Then however, the panel tries to register itself and
> > >>> exynos_dsi_host_attach() tries to access the released encoder (which is
> > >>> zeroed in drm_encoder_release) and rest of resources, what causes 
> > >>> failure.
> > >>>
> > >>> It looks that something is missing. Maybe mipi host has to be 
> > >>> registered
> > >>> later, when bridge is ready? I have no idea how it is handled before
> > >>> this patch. Andrzej, could you comment it a bit?
> > >> I intentionally changed the order, because if another bridge follows 
> > >> in the
> > >> pipeline, the probe of the drm driver has to be deferred until some 
> > >> bridge
> > >> provides a connector. The next bridge registers itself via the 
> > >> host_attach
> > >> function and the deferral is ensured via the bind for the bind/unbind 
> > >> API or
> > >> the bridge_attach function otherwise.
> > >>
> > >> On the other hand, the bridge does not have an encoder until the mipi 
> > >> device
> > >> has been attached.
> > >>
> > >> As a solution, the exynos dsi driver must initialize the encoder in
> > >> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder 
> > >> via
> > >> exynos_dsi instead of the bridge.
> > >>
> > >> Can you try to move everything except samsung_dsim_bind from 
> > >> exynos_dsi_bind
> > >> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> > >> crash.
> > >
> > >
> > > The original behaviour is that encoder (exynos_dsi) is registered 
> > > regardless of sink presence (initially panel, later also bridge) - it 
> > > avoids multiple issues with deferred probe, device driver bind/unbind 
> > > and module load/unload. Appearance or disappearance of sink is 
> > > reported to host nicely via DSI attach/detach callbacks - and it is 
> > > reflected in drm world as change state of the connector.
> > >
> > > Registering DSI host in bind and unregistering in unbind assures that 
> > > if mipi_dsi device is attached/detached the drm device is always 
> > > present - it makes device/driver binding race free and allows to avoid 
> > > additional locking.
> > >
> > > Moving DSI host registration to probe changes everything, for sure it 
> > > breaks the nice feature of DSI attach/detach callbacks and apparently 
> > > can cause different issues depending on device bind order.
> > >
> > > I will try to look at the patches tomorrow and maybe I can find more 
> > > constructive comments :)
> > 
> > 
> > As I said yesterday, exynos_dsi driver uses dsi host attach/detach 
> > callbacks to control appearance/disappearance of downstream device. It 
> > allows to:
> > 
> > 1. Safely bind/unbind different device drivers at any time and at any 
> > order, without killing exynos_drm and/or crashing system.
> > 
> > 2. Avoid issues with late drm init - on some platforms exynos_drm device 
> > appeared too late, due to deferred probe, and resulted in black screen 
> > in userspace.
> > 
> > 
> > Now if we want to convert exynos_dsi to drm_bridge I see following options:
> > 
> > A. Forgot about callbacks and make the exynos_drm to defer probing until 
> > exynos_dsi bridge is available, probably it will cause later exynos_drm 
> > appearance, thus probably black screen on some targets. So for sure it 
> > will be suboptimal. Making it bridge unbind safe would be another 
> > problem, but most developers do not care about it so why should we? :)
> > 
> > B. Try to mimic current behaviour - exynos_dsi register bridge ASAP, 
> > even if downstream devices are not yet attached, on attach/detach notify 
> > drm about it via connector status change, for this dsi_host registration 
> > should be performed from drm_bridge attach, I guess.
> > 
> > 
> > Option A is more standard, but is unsafe and causes other issues.
> > 
> > Option B keeps current behaviour.
> 
> Maybe we can have both, but I am not sure, if I am missing something:
> 
> I still prefer option A for the samsung-dsim driver, because it is more
> standard, simpler and avoids issues with encoders, connectors or handling
> hotplug.
> 
> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> samsung-dsim driver which implements option A and defers probing of the drm
> driver until the next bridge is attached. And a second bridge in the
> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> device to appear) and implements the hotplug handling for notifying drm via
> connector status change.
> 
> The driver for the i.MX8M would use the samsung-dsim bridge without an
> additional bridge.
> 
> This allows the samsung-dsim driver to expose the standard behavior while the
> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> 
> I hope this makes sense and does not sound too crazy. It might be difficult to
> get the probing and mipi host/device registration correct, but I will try, if
> this can work.

Adding two bridges for being able to support hotplugging adds many special
cases to the bridge driver and still requires more custom API to correctly add
the second bridge. I don't think that this a viable path to go.

This leaves us with:

Option A) Standard drm_bridge behavior, which is currently implemented, but
incompatible with the currently expected behavior of exynos_drm.

Option B) Creating the drm device without all bridges being attached, which
would work with the exynos_drm driver, but breaks for the standard drm_bridge
behavior, especially, if the encoder/connector is created at the beginning of
the pipeline and passed downwards when the bridges are attached.

Option C) Extracting only low level register accesses into shared code, adding
a custom interface and implementing the drm_bridge handling in the platform
specific code.

None of the options really convinces me.

Michael

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-03 20:31                 ` Michael Tretter
@ 2021-02-04 10:17                   ` Daniel Vetter
  2021-02-04 10:56                     ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2021-02-04 10:17 UTC (permalink / raw)
  To: Michael Tretter
  Cc: Andrzej Hajda, ch, Neil Armstrong, dri-devel, frieder.schrempf,
	Laurent Pinchart, Marek Szyprowski, Marek Vasut,
	linux-samsung-soc, Joonyoung Shim, Krzysztof Kozlowski,
	dl-linux-imx, Bartlomiej Zolnierkiewicz, sylvester.nawrocki,
	aford173, abel.vesa, aisheng.dong, Seung-Woo Kim, Sascha Hauer,
	Shawn Guo

On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter <m.tretter@pengutronix.de> wrote:
>
> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> > On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> > > W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > > > On 14.09.2020 22:01, Michael Tretter wrote:
> > > >> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> > > >>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> > > >>>> On 11.09.2020 15:54, Michael Tretter wrote:
> > > >>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> > > >>>>> used
> > > >>>>> from other drivers.
> > > >>>>>
> > > >>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> > > >>>>> already attached to the bridge. This allows to defer the probe of the
> > > >>>>> display pipe until the downstream bridges are available, too.
> > > >>>>>
> > > >>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > > >>>> This one (and the whole series applied) still fails on Exynos boards:
> > > >>>>
> > > >>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> > > >>>> operations
> > > >>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > >>>> OF: graph: no port node found in /soc/dsi@11c80000
> > > >>>> 8<--- cut here ---
> > > >>>> Unable to handle kernel NULL pointer dereference at virtual address
> > > >>>> 00000084
> > > >>>> pgd = (ptrval)
> > > >>>> [00000084] *pgd=00000000
> > > >>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > >>>> Modules linked in:
> > > >>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > > >>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > > >>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > >>>> PC is at drm_bridge_attach+0x18/0x164
> > > >>>> LR is at exynos_dsi_bind+0x88/0xa8
> > > >>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > > >>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > > >>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > > >>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > > >>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > > >>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > >>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > >>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > >>>> Stack: (0xef0dfca8 to 0xef0e0000)
> > > >>>> ...
> > > >>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > > >>>> (exynos_dsi_bind+0x88/0xa8)
> > > >>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > > >>>> (component_bind_all+0xfc/0x290)
> > > >>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > > >>>> (exynos_drm_bind+0xe4/0x19c)
> > > >>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > > >>>> (try_to_bring_up_master+0x1e4/0x2c4)
> > > >>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > > >>>> (component_master_add_with_match+0xd4/0x108)
> > > >>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > > >>>> (exynos_drm_platform_probe+0xe4/0x110)
> > > >>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > > >>>> (platform_drv_probe+0x6c/0xa4)
> > > >>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > > >>>> (really_probe+0x200/0x4fc)
> > > >>>> [<c067242c>] (really_probe) from [<c06728f0>]
> > > >>>> (driver_probe_device+0x78/0x1fc)
> > > >>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > > >>>> (device_driver_attach+0x58/0x60)
> > > >>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > > >>>> (__driver_attach+0xdc/0x174)
> > > >>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > > >>>> (bus_for_each_dev+0x68/0xb4)
> > > >>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > > >>>> (bus_add_driver+0x158/0x214)
> > > >>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> > > >>>> (driver_register+0x78/0x110)
> > > >>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > > >>>> (exynos_drm_init+0xe4/0x118)
> > > >>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > > >>>> (do_one_initcall+0x8c/0x42c)
> > > >>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > >>>> (kernel_init_freeable+0x190/0x1dc)
> > > >>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > > >>>> (kernel_init+0x8/0x118)
> > > >>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > >>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > >>>> ...
> > > >>>> ---[ end trace ee27f313f9ed9da1 ]---
> > > >>>>
> > > >>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > > >>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> > > >>>>
> > > >>>> I will try to debug it a bit more today.
> > > >>> The above crash has been caused by lack of in_bridge initialization to
> > > >>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> > > >>> another issue:
> > > >>>
> > > >>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > > >>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > >>> OF: graph: no port node found in /soc/dsi@11c80000
> > > >>> 8<--- cut here ---
> > > >>> Unable to handle kernel NULL pointer dereference at virtual address
> > > >>> 00000280
> > > >>> pgd = (ptrval)
> > > >>> [00000280] *pgd=00000000
> > > >>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > >>> Modules linked in:
> > > >>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> > > >>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> > > >>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > >>> PC is at __mutex_lock+0x54/0xb18
> > > >>> LR is at lock_is_held_type+0x80/0x138
> > > >>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> > > >>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> > > >>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> > > >>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> > > >>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> > > >>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > >>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > >>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > >>> Stack: (0xef0dfd30 to 0xef0e0000)
> > > >>> ...
> > > >>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> > > >>> (mutex_lock_nested+0x1c/0x24)
> > > >>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> > > >>> (__exynos_dsi_host_attach+0x20/0x6c)
> > > >>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> > > >>> (exynos_dsi_host_attach+0x70/0x194)
> > > >>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> > > >>> (s6e8aa0_probe+0x1b0/0x218)
> > > >>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> > > >>> (really_probe+0x200/0x4fc)
> > > >>> [<c0672530>] (really_probe) from [<c06729f4>]
> > > >>> (driver_probe_device+0x78/0x1fc)
> > > >>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> > > >>> (device_driver_attach+0x58/0x60)
> > > >>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> > > >>> (__driver_attach+0xdc/0x174)
> > > >>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> > > >>> (bus_for_each_dev+0x68/0xb4)
> > > >>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> > > >>> (bus_add_driver+0x158/0x214)
> > > >>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> > > >>> (driver_register+0x78/0x110)
> > > >>> [<c0673d20>] (driver_register) from [<c0102484>]
> > > >>> (do_one_initcall+0x8c/0x42c)
> > > >>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > >>> (kernel_init_freeable+0x190/0x1dc)
> > > >>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> > > >>> (kernel_init+0x8/0x118)
> > > >>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > >>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > >>> ...
> > > >>> ---[ end trace c06e996ec2e8234d ]---
> > > >>>
> > > >>> This means that dsi->encoder.dev is not initialized in
> > > >>> __exynos_dsi_host_attach().
> > > >>>
> > > >>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> > > >>> earlier -517 (deferred probe), what causes cleanup of encoder and
> > > >>> release of all drm resources.
> > > >>>
> > > >>> Then however, the panel tries to register itself and
> > > >>> exynos_dsi_host_attach() tries to access the released encoder (which is
> > > >>> zeroed in drm_encoder_release) and rest of resources, what causes
> > > >>> failure.
> > > >>>
> > > >>> It looks that something is missing. Maybe mipi host has to be
> > > >>> registered
> > > >>> later, when bridge is ready? I have no idea how it is handled before
> > > >>> this patch. Andrzej, could you comment it a bit?
> > > >> I intentionally changed the order, because if another bridge follows
> > > >> in the
> > > >> pipeline, the probe of the drm driver has to be deferred until some
> > > >> bridge
> > > >> provides a connector. The next bridge registers itself via the
> > > >> host_attach
> > > >> function and the deferral is ensured via the bind for the bind/unbind
> > > >> API or
> > > >> the bridge_attach function otherwise.
> > > >>
> > > >> On the other hand, the bridge does not have an encoder until the mipi
> > > >> device
> > > >> has been attached.
> > > >>
> > > >> As a solution, the exynos dsi driver must initialize the encoder in
> > > >> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> > > >> via
> > > >> exynos_dsi instead of the bridge.
> > > >>
> > > >> Can you try to move everything except samsung_dsim_bind from
> > > >> exynos_dsi_bind
> > > >> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> > > >> crash.
> > > >
> > > >
> > > > The original behaviour is that encoder (exynos_dsi) is registered
> > > > regardless of sink presence (initially panel, later also bridge) - it
> > > > avoids multiple issues with deferred probe, device driver bind/unbind
> > > > and module load/unload. Appearance or disappearance of sink is
> > > > reported to host nicely via DSI attach/detach callbacks - and it is
> > > > reflected in drm world as change state of the connector.
> > > >
> > > > Registering DSI host in bind and unregistering in unbind assures that
> > > > if mipi_dsi device is attached/detached the drm device is always
> > > > present - it makes device/driver binding race free and allows to avoid
> > > > additional locking.
> > > >
> > > > Moving DSI host registration to probe changes everything, for sure it
> > > > breaks the nice feature of DSI attach/detach callbacks and apparently
> > > > can cause different issues depending on device bind order.
> > > >
> > > > I will try to look at the patches tomorrow and maybe I can find more
> > > > constructive comments :)
> > >
> > >
> > > As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> > > callbacks to control appearance/disappearance of downstream device. It
> > > allows to:
> > >
> > > 1. Safely bind/unbind different device drivers at any time and at any
> > > order, without killing exynos_drm and/or crashing system.
> > >
> > > 2. Avoid issues with late drm init - on some platforms exynos_drm device
> > > appeared too late, due to deferred probe, and resulted in black screen
> > > in userspace.
> > >
> > >
> > > Now if we want to convert exynos_dsi to drm_bridge I see following options:
> > >
> > > A. Forgot about callbacks and make the exynos_drm to defer probing until
> > > exynos_dsi bridge is available, probably it will cause later exynos_drm
> > > appearance, thus probably black screen on some targets. So for sure it
> > > will be suboptimal. Making it bridge unbind safe would be another
> > > problem, but most developers do not care about it so why should we? :)
> > >
> > > B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> > > even if downstream devices are not yet attached, on attach/detach notify
> > > drm about it via connector status change, for this dsi_host registration
> > > should be performed from drm_bridge attach, I guess.
> > >
> > >
> > > Option A is more standard, but is unsafe and causes other issues.
> > >
> > > Option B keeps current behaviour.
> >
> > Maybe we can have both, but I am not sure, if I am missing something:
> >
> > I still prefer option A for the samsung-dsim driver, because it is more
> > standard, simpler and avoids issues with encoders, connectors or handling
> > hotplug.
> >
> > The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> > samsung-dsim driver which implements option A and defers probing of the drm
> > driver until the next bridge is attached. And a second bridge in the
> > exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> > device to appear) and implements the hotplug handling for notifying drm via
> > connector status change.
> >
> > The driver for the i.MX8M would use the samsung-dsim bridge without an
> > additional bridge.
> >
> > This allows the samsung-dsim driver to expose the standard behavior while the
> > exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> >
> > I hope this makes sense and does not sound too crazy. It might be difficult to
> > get the probing and mipi host/device registration correct, but I will try, if
> > this can work.
>
> Adding two bridges for being able to support hotplugging adds many special
> cases to the bridge driver and still requires more custom API to correctly add
> the second bridge. I don't think that this a viable path to go.

Just jumping in here: You cannot hotplug/hotremove anything from a
drm_device after drm_dev_register has been called, except
drm_connector. I didn't dig into details here so not sure whether you
want to late-bind your bridge after drm_dev_register is called or not,
so might just be fyi and not relevant to the discussion.
-Daniel

>
> This leaves us with:
>
> Option A) Standard drm_bridge behavior, which is currently implemented, but
> incompatible with the currently expected behavior of exynos_drm.
>
> Option B) Creating the drm device without all bridges being attached, which
> would work with the exynos_drm driver, but breaks for the standard drm_bridge
> behavior, especially, if the encoder/connector is created at the beginning of
> the pipeline and passed downwards when the bridges are attached.
>
> Option C) Extracting only low level register accesses into shared code, adding
> a custom interface and implementing the drm_bridge handling in the platform
> specific code.
>
> None of the options really convinces me.
>
> Michael
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-04 10:17                   ` Daniel Vetter
@ 2021-02-04 10:56                     ` Michael Tretter
  2021-02-04 16:05                       ` Daniel Vetter
  0 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2021-02-04 10:56 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Andrzej Hajda, ch, Neil Armstrong, dri-devel, frieder.schrempf,
	Laurent Pinchart, Marek Szyprowski, Marek Vasut,
	linux-samsung-soc, Joonyoung Shim, Krzysztof Kozlowski,
	dl-linux-imx, Bartlomiej Zolnierkiewicz, sylvester.nawrocki,
	aford173, abel.vesa, aisheng.dong, Seung-Woo Kim, Sascha Hauer,
	Shawn Guo

On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter <m.tretter@pengutronix.de> wrote:
> >
> > On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> > > On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> > > > W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > > > > On 14.09.2020 22:01, Michael Tretter wrote:
> > > > >> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> > > > >>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> > > > >>>> On 11.09.2020 15:54, Michael Tretter wrote:
> > > > >>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> > > > >>>>> used
> > > > >>>>> from other drivers.
> > > > >>>>>
> > > > >>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> > > > >>>>> already attached to the bridge. This allows to defer the probe of the
> > > > >>>>> display pipe until the downstream bridges are available, too.
> > > > >>>>>
> > > > >>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > > > >>>> This one (and the whole series applied) still fails on Exynos boards:
> > > > >>>>
> > > > >>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> > > > >>>> operations
> > > > >>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > > >>>> OF: graph: no port node found in /soc/dsi@11c80000
> > > > >>>> 8<--- cut here ---
> > > > >>>> Unable to handle kernel NULL pointer dereference at virtual address
> > > > >>>> 00000084
> > > > >>>> pgd = (ptrval)
> > > > >>>> [00000084] *pgd=00000000
> > > > >>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > > >>>> Modules linked in:
> > > > >>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > > > >>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > > > >>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > > >>>> PC is at drm_bridge_attach+0x18/0x164
> > > > >>>> LR is at exynos_dsi_bind+0x88/0xa8
> > > > >>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > > > >>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > > > >>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > > > >>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > > > >>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > > > >>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > > >>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > > >>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > > >>>> Stack: (0xef0dfca8 to 0xef0e0000)
> > > > >>>> ...
> > > > >>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > > > >>>> (exynos_dsi_bind+0x88/0xa8)
> > > > >>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > > > >>>> (component_bind_all+0xfc/0x290)
> > > > >>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > > > >>>> (exynos_drm_bind+0xe4/0x19c)
> > > > >>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > > > >>>> (try_to_bring_up_master+0x1e4/0x2c4)
> > > > >>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > > > >>>> (component_master_add_with_match+0xd4/0x108)
> > > > >>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > > > >>>> (exynos_drm_platform_probe+0xe4/0x110)
> > > > >>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > > > >>>> (platform_drv_probe+0x6c/0xa4)
> > > > >>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > > > >>>> (really_probe+0x200/0x4fc)
> > > > >>>> [<c067242c>] (really_probe) from [<c06728f0>]
> > > > >>>> (driver_probe_device+0x78/0x1fc)
> > > > >>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > > > >>>> (device_driver_attach+0x58/0x60)
> > > > >>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > > > >>>> (__driver_attach+0xdc/0x174)
> > > > >>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > > > >>>> (bus_for_each_dev+0x68/0xb4)
> > > > >>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > > > >>>> (bus_add_driver+0x158/0x214)
> > > > >>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> > > > >>>> (driver_register+0x78/0x110)
> > > > >>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > > > >>>> (exynos_drm_init+0xe4/0x118)
> > > > >>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > > > >>>> (do_one_initcall+0x8c/0x42c)
> > > > >>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > > >>>> (kernel_init_freeable+0x190/0x1dc)
> > > > >>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > > > >>>> (kernel_init+0x8/0x118)
> > > > >>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > > >>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > > >>>> ...
> > > > >>>> ---[ end trace ee27f313f9ed9da1 ]---
> > > > >>>>
> > > > >>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > > > >>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> > > > >>>>
> > > > >>>> I will try to debug it a bit more today.
> > > > >>> The above crash has been caused by lack of in_bridge initialization to
> > > > >>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> > > > >>> another issue:
> > > > >>>
> > > > >>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > > > >>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > > >>> OF: graph: no port node found in /soc/dsi@11c80000
> > > > >>> 8<--- cut here ---
> > > > >>> Unable to handle kernel NULL pointer dereference at virtual address
> > > > >>> 00000280
> > > > >>> pgd = (ptrval)
> > > > >>> [00000280] *pgd=00000000
> > > > >>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > > >>> Modules linked in:
> > > > >>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> > > > >>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> > > > >>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > > >>> PC is at __mutex_lock+0x54/0xb18
> > > > >>> LR is at lock_is_held_type+0x80/0x138
> > > > >>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> > > > >>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> > > > >>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> > > > >>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> > > > >>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> > > > >>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > > >>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > > >>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > > >>> Stack: (0xef0dfd30 to 0xef0e0000)
> > > > >>> ...
> > > > >>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> > > > >>> (mutex_lock_nested+0x1c/0x24)
> > > > >>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> > > > >>> (__exynos_dsi_host_attach+0x20/0x6c)
> > > > >>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> > > > >>> (exynos_dsi_host_attach+0x70/0x194)
> > > > >>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> > > > >>> (s6e8aa0_probe+0x1b0/0x218)
> > > > >>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> > > > >>> (really_probe+0x200/0x4fc)
> > > > >>> [<c0672530>] (really_probe) from [<c06729f4>]
> > > > >>> (driver_probe_device+0x78/0x1fc)
> > > > >>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> > > > >>> (device_driver_attach+0x58/0x60)
> > > > >>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> > > > >>> (__driver_attach+0xdc/0x174)
> > > > >>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> > > > >>> (bus_for_each_dev+0x68/0xb4)
> > > > >>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> > > > >>> (bus_add_driver+0x158/0x214)
> > > > >>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> > > > >>> (driver_register+0x78/0x110)
> > > > >>> [<c0673d20>] (driver_register) from [<c0102484>]
> > > > >>> (do_one_initcall+0x8c/0x42c)
> > > > >>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > > >>> (kernel_init_freeable+0x190/0x1dc)
> > > > >>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> > > > >>> (kernel_init+0x8/0x118)
> > > > >>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > > >>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > > >>> ...
> > > > >>> ---[ end trace c06e996ec2e8234d ]---
> > > > >>>
> > > > >>> This means that dsi->encoder.dev is not initialized in
> > > > >>> __exynos_dsi_host_attach().
> > > > >>>
> > > > >>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> > > > >>> earlier -517 (deferred probe), what causes cleanup of encoder and
> > > > >>> release of all drm resources.
> > > > >>>
> > > > >>> Then however, the panel tries to register itself and
> > > > >>> exynos_dsi_host_attach() tries to access the released encoder (which is
> > > > >>> zeroed in drm_encoder_release) and rest of resources, what causes
> > > > >>> failure.
> > > > >>>
> > > > >>> It looks that something is missing. Maybe mipi host has to be
> > > > >>> registered
> > > > >>> later, when bridge is ready? I have no idea how it is handled before
> > > > >>> this patch. Andrzej, could you comment it a bit?
> > > > >> I intentionally changed the order, because if another bridge follows
> > > > >> in the
> > > > >> pipeline, the probe of the drm driver has to be deferred until some
> > > > >> bridge
> > > > >> provides a connector. The next bridge registers itself via the
> > > > >> host_attach
> > > > >> function and the deferral is ensured via the bind for the bind/unbind
> > > > >> API or
> > > > >> the bridge_attach function otherwise.
> > > > >>
> > > > >> On the other hand, the bridge does not have an encoder until the mipi
> > > > >> device
> > > > >> has been attached.
> > > > >>
> > > > >> As a solution, the exynos dsi driver must initialize the encoder in
> > > > >> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> > > > >> via
> > > > >> exynos_dsi instead of the bridge.
> > > > >>
> > > > >> Can you try to move everything except samsung_dsim_bind from
> > > > >> exynos_dsi_bind
> > > > >> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> > > > >> crash.
> > > > >
> > > > >
> > > > > The original behaviour is that encoder (exynos_dsi) is registered
> > > > > regardless of sink presence (initially panel, later also bridge) - it
> > > > > avoids multiple issues with deferred probe, device driver bind/unbind
> > > > > and module load/unload. Appearance or disappearance of sink is
> > > > > reported to host nicely via DSI attach/detach callbacks - and it is
> > > > > reflected in drm world as change state of the connector.
> > > > >
> > > > > Registering DSI host in bind and unregistering in unbind assures that
> > > > > if mipi_dsi device is attached/detached the drm device is always
> > > > > present - it makes device/driver binding race free and allows to avoid
> > > > > additional locking.
> > > > >
> > > > > Moving DSI host registration to probe changes everything, for sure it
> > > > > breaks the nice feature of DSI attach/detach callbacks and apparently
> > > > > can cause different issues depending on device bind order.
> > > > >
> > > > > I will try to look at the patches tomorrow and maybe I can find more
> > > > > constructive comments :)
> > > >
> > > >
> > > > As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> > > > callbacks to control appearance/disappearance of downstream device. It
> > > > allows to:
> > > >
> > > > 1. Safely bind/unbind different device drivers at any time and at any
> > > > order, without killing exynos_drm and/or crashing system.
> > > >
> > > > 2. Avoid issues with late drm init - on some platforms exynos_drm device
> > > > appeared too late, due to deferred probe, and resulted in black screen
> > > > in userspace.
> > > >
> > > >
> > > > Now if we want to convert exynos_dsi to drm_bridge I see following options:
> > > >
> > > > A. Forgot about callbacks and make the exynos_drm to defer probing until
> > > > exynos_dsi bridge is available, probably it will cause later exynos_drm
> > > > appearance, thus probably black screen on some targets. So for sure it
> > > > will be suboptimal. Making it bridge unbind safe would be another
> > > > problem, but most developers do not care about it so why should we? :)
> > > >
> > > > B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> > > > even if downstream devices are not yet attached, on attach/detach notify
> > > > drm about it via connector status change, for this dsi_host registration
> > > > should be performed from drm_bridge attach, I guess.
> > > >
> > > >
> > > > Option A is more standard, but is unsafe and causes other issues.
> > > >
> > > > Option B keeps current behaviour.
> > >
> > > Maybe we can have both, but I am not sure, if I am missing something:
> > >
> > > I still prefer option A for the samsung-dsim driver, because it is more
> > > standard, simpler and avoids issues with encoders, connectors or handling
> > > hotplug.
> > >
> > > The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> > > samsung-dsim driver which implements option A and defers probing of the drm
> > > driver until the next bridge is attached. And a second bridge in the
> > > exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> > > device to appear) and implements the hotplug handling for notifying drm via
> > > connector status change.
> > >
> > > The driver for the i.MX8M would use the samsung-dsim bridge without an
> > > additional bridge.
> > >
> > > This allows the samsung-dsim driver to expose the standard behavior while the
> > > exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> > >
> > > I hope this makes sense and does not sound too crazy. It might be difficult to
> > > get the probing and mipi host/device registration correct, but I will try, if
> > > this can work.
> >
> > Adding two bridges for being able to support hotplugging adds many special
> > cases to the bridge driver and still requires more custom API to correctly add
> > the second bridge. I don't think that this a viable path to go.
> 
> Just jumping in here: You cannot hotplug/hotremove anything from a
> drm_device after drm_dev_register has been called, except
> drm_connector. I didn't dig into details here so not sure whether you
> want to late-bind your bridge after drm_dev_register is called or not,
> so might just be fyi and not relevant to the discussion.

Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
driver (i.e. Option B)

exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
device might attach to the DSI host and call exynos_dsi_host_attach. In
exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
attaches this bridge to the encoder _after_ drm_dev_register has been called.
This is invalid behavior, right?

Michael

> -Daniel
> 
> >
> > This leaves us with:
> >
> > Option A) Standard drm_bridge behavior, which is currently implemented, but
> > incompatible with the currently expected behavior of exynos_drm.
> >
> > Option B) Creating the drm device without all bridges being attached, which
> > would work with the exynos_drm driver, but breaks for the standard drm_bridge
> > behavior, especially, if the encoder/connector is created at the beginning of
> > the pipeline and passed downwards when the bridges are attached.
> >
> > Option C) Extracting only low level register accesses into shared code, adding
> > a custom interface and implementing the drm_bridge handling in the platform
> > specific code.
> >
> > None of the options really convinces me.
> >
> > Michael
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-04 10:56                     ` Michael Tretter
@ 2021-02-04 16:05                       ` Daniel Vetter
  2021-02-04 16:28                         ` Andrzej Hajda
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2021-02-04 16:05 UTC (permalink / raw)
  To: Michael Tretter
  Cc: Daniel Vetter, Andrzej Hajda, ch, Neil Armstrong, dri-devel,
	frieder.schrempf, Laurent Pinchart, Marek Szyprowski,
	Marek Vasut, linux-samsung-soc, Joonyoung Shim,
	Krzysztof Kozlowski, dl-linux-imx, Bartlomiej Zolnierkiewicz,
	sylvester.nawrocki, aford173, abel.vesa, aisheng.dong,
	Seung-Woo Kim, Sascha Hauer, Shawn Guo

On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> > On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter <m.tretter@pengutronix.de> wrote:
> > >
> > > On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> > > > On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> > > > > W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > > > > > On 14.09.2020 22:01, Michael Tretter wrote:
> > > > > >> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> > > > > >>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> > > > > >>>> On 11.09.2020 15:54, Michael Tretter wrote:
> > > > > >>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> > > > > >>>>> used
> > > > > >>>>> from other drivers.
> > > > > >>>>>
> > > > > >>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> > > > > >>>>> already attached to the bridge. This allows to defer the probe of the
> > > > > >>>>> display pipe until the downstream bridges are available, too.
> > > > > >>>>>
> > > > > >>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > > > > >>>> This one (and the whole series applied) still fails on Exynos boards:
> > > > > >>>>
> > > > > >>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> > > > > >>>> operations
> > > > > >>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > > > >>>> OF: graph: no port node found in /soc/dsi@11c80000
> > > > > >>>> 8<--- cut here ---
> > > > > >>>> Unable to handle kernel NULL pointer dereference at virtual address
> > > > > >>>> 00000084
> > > > > >>>> pgd = (ptrval)
> > > > > >>>> [00000084] *pgd=00000000
> > > > > >>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > > > >>>> Modules linked in:
> > > > > >>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > > > > >>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > > > > >>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > > > >>>> PC is at drm_bridge_attach+0x18/0x164
> > > > > >>>> LR is at exynos_dsi_bind+0x88/0xa8
> > > > > >>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > > > > >>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > > > > >>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > > > > >>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > > > > >>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > > > > >>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > > > >>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > > > >>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > > > >>>> Stack: (0xef0dfca8 to 0xef0e0000)
> > > > > >>>> ...
> > > > > >>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > > > > >>>> (exynos_dsi_bind+0x88/0xa8)
> > > > > >>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > > > > >>>> (component_bind_all+0xfc/0x290)
> > > > > >>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > > > > >>>> (exynos_drm_bind+0xe4/0x19c)
> > > > > >>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > > > > >>>> (try_to_bring_up_master+0x1e4/0x2c4)
> > > > > >>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > > > > >>>> (component_master_add_with_match+0xd4/0x108)
> > > > > >>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > > > > >>>> (exynos_drm_platform_probe+0xe4/0x110)
> > > > > >>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > > > > >>>> (platform_drv_probe+0x6c/0xa4)
> > > > > >>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > > > > >>>> (really_probe+0x200/0x4fc)
> > > > > >>>> [<c067242c>] (really_probe) from [<c06728f0>]
> > > > > >>>> (driver_probe_device+0x78/0x1fc)
> > > > > >>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > > > > >>>> (device_driver_attach+0x58/0x60)
> > > > > >>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > > > > >>>> (__driver_attach+0xdc/0x174)
> > > > > >>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > > > > >>>> (bus_for_each_dev+0x68/0xb4)
> > > > > >>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > > > > >>>> (bus_add_driver+0x158/0x214)
> > > > > >>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> > > > > >>>> (driver_register+0x78/0x110)
> > > > > >>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > > > > >>>> (exynos_drm_init+0xe4/0x118)
> > > > > >>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > > > > >>>> (do_one_initcall+0x8c/0x42c)
> > > > > >>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > > > >>>> (kernel_init_freeable+0x190/0x1dc)
> > > > > >>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > > > > >>>> (kernel_init+0x8/0x118)
> > > > > >>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > > > >>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > > > >>>> ...
> > > > > >>>> ---[ end trace ee27f313f9ed9da1 ]---
> > > > > >>>>
> > > > > >>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > > > > >>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> > > > > >>>>
> > > > > >>>> I will try to debug it a bit more today.
> > > > > >>> The above crash has been caused by lack of in_bridge initialization to
> > > > > >>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> > > > > >>> another issue:
> > > > > >>>
> > > > > >>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > > > > >>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > > > >>> OF: graph: no port node found in /soc/dsi@11c80000
> > > > > >>> 8<--- cut here ---
> > > > > >>> Unable to handle kernel NULL pointer dereference at virtual address
> > > > > >>> 00000280
> > > > > >>> pgd = (ptrval)
> > > > > >>> [00000280] *pgd=00000000
> > > > > >>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > > > >>> Modules linked in:
> > > > > >>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> > > > > >>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> > > > > >>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > > > >>> PC is at __mutex_lock+0x54/0xb18
> > > > > >>> LR is at lock_is_held_type+0x80/0x138
> > > > > >>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> > > > > >>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> > > > > >>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> > > > > >>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> > > > > >>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> > > > > >>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > > > >>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > > > >>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > > > >>> Stack: (0xef0dfd30 to 0xef0e0000)
> > > > > >>> ...
> > > > > >>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> > > > > >>> (mutex_lock_nested+0x1c/0x24)
> > > > > >>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> > > > > >>> (__exynos_dsi_host_attach+0x20/0x6c)
> > > > > >>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> > > > > >>> (exynos_dsi_host_attach+0x70/0x194)
> > > > > >>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> > > > > >>> (s6e8aa0_probe+0x1b0/0x218)
> > > > > >>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> > > > > >>> (really_probe+0x200/0x4fc)
> > > > > >>> [<c0672530>] (really_probe) from [<c06729f4>]
> > > > > >>> (driver_probe_device+0x78/0x1fc)
> > > > > >>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> > > > > >>> (device_driver_attach+0x58/0x60)
> > > > > >>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> > > > > >>> (__driver_attach+0xdc/0x174)
> > > > > >>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> > > > > >>> (bus_for_each_dev+0x68/0xb4)
> > > > > >>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> > > > > >>> (bus_add_driver+0x158/0x214)
> > > > > >>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> > > > > >>> (driver_register+0x78/0x110)
> > > > > >>> [<c0673d20>] (driver_register) from [<c0102484>]
> > > > > >>> (do_one_initcall+0x8c/0x42c)
> > > > > >>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > > > >>> (kernel_init_freeable+0x190/0x1dc)
> > > > > >>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> > > > > >>> (kernel_init+0x8/0x118)
> > > > > >>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > > > >>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > > > >>> ...
> > > > > >>> ---[ end trace c06e996ec2e8234d ]---
> > > > > >>>
> > > > > >>> This means that dsi->encoder.dev is not initialized in
> > > > > >>> __exynos_dsi_host_attach().
> > > > > >>>
> > > > > >>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> > > > > >>> earlier -517 (deferred probe), what causes cleanup of encoder and
> > > > > >>> release of all drm resources.
> > > > > >>>
> > > > > >>> Then however, the panel tries to register itself and
> > > > > >>> exynos_dsi_host_attach() tries to access the released encoder (which is
> > > > > >>> zeroed in drm_encoder_release) and rest of resources, what causes
> > > > > >>> failure.
> > > > > >>>
> > > > > >>> It looks that something is missing. Maybe mipi host has to be
> > > > > >>> registered
> > > > > >>> later, when bridge is ready? I have no idea how it is handled before
> > > > > >>> this patch. Andrzej, could you comment it a bit?
> > > > > >> I intentionally changed the order, because if another bridge follows
> > > > > >> in the
> > > > > >> pipeline, the probe of the drm driver has to be deferred until some
> > > > > >> bridge
> > > > > >> provides a connector. The next bridge registers itself via the
> > > > > >> host_attach
> > > > > >> function and the deferral is ensured via the bind for the bind/unbind
> > > > > >> API or
> > > > > >> the bridge_attach function otherwise.
> > > > > >>
> > > > > >> On the other hand, the bridge does not have an encoder until the mipi
> > > > > >> device
> > > > > >> has been attached.
> > > > > >>
> > > > > >> As a solution, the exynos dsi driver must initialize the encoder in
> > > > > >> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> > > > > >> via
> > > > > >> exynos_dsi instead of the bridge.
> > > > > >>
> > > > > >> Can you try to move everything except samsung_dsim_bind from
> > > > > >> exynos_dsi_bind
> > > > > >> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> > > > > >> crash.
> > > > > >
> > > > > >
> > > > > > The original behaviour is that encoder (exynos_dsi) is registered
> > > > > > regardless of sink presence (initially panel, later also bridge) - it
> > > > > > avoids multiple issues with deferred probe, device driver bind/unbind
> > > > > > and module load/unload. Appearance or disappearance of sink is
> > > > > > reported to host nicely via DSI attach/detach callbacks - and it is
> > > > > > reflected in drm world as change state of the connector.
> > > > > >
> > > > > > Registering DSI host in bind and unregistering in unbind assures that
> > > > > > if mipi_dsi device is attached/detached the drm device is always
> > > > > > present - it makes device/driver binding race free and allows to avoid
> > > > > > additional locking.
> > > > > >
> > > > > > Moving DSI host registration to probe changes everything, for sure it
> > > > > > breaks the nice feature of DSI attach/detach callbacks and apparently
> > > > > > can cause different issues depending on device bind order.
> > > > > >
> > > > > > I will try to look at the patches tomorrow and maybe I can find more
> > > > > > constructive comments :)
> > > > >
> > > > >
> > > > > As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> > > > > callbacks to control appearance/disappearance of downstream device. It
> > > > > allows to:
> > > > >
> > > > > 1. Safely bind/unbind different device drivers at any time and at any
> > > > > order, without killing exynos_drm and/or crashing system.
> > > > >
> > > > > 2. Avoid issues with late drm init - on some platforms exynos_drm device
> > > > > appeared too late, due to deferred probe, and resulted in black screen
> > > > > in userspace.
> > > > >
> > > > >
> > > > > Now if we want to convert exynos_dsi to drm_bridge I see following options:
> > > > >
> > > > > A. Forgot about callbacks and make the exynos_drm to defer probing until
> > > > > exynos_dsi bridge is available, probably it will cause later exynos_drm
> > > > > appearance, thus probably black screen on some targets. So for sure it
> > > > > will be suboptimal. Making it bridge unbind safe would be another
> > > > > problem, but most developers do not care about it so why should we? :)
> > > > >
> > > > > B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> > > > > even if downstream devices are not yet attached, on attach/detach notify
> > > > > drm about it via connector status change, for this dsi_host registration
> > > > > should be performed from drm_bridge attach, I guess.
> > > > >
> > > > >
> > > > > Option A is more standard, but is unsafe and causes other issues.
> > > > >
> > > > > Option B keeps current behaviour.
> > > >
> > > > Maybe we can have both, but I am not sure, if I am missing something:
> > > >
> > > > I still prefer option A for the samsung-dsim driver, because it is more
> > > > standard, simpler and avoids issues with encoders, connectors or handling
> > > > hotplug.
> > > >
> > > > The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> > > > samsung-dsim driver which implements option A and defers probing of the drm
> > > > driver until the next bridge is attached. And a second bridge in the
> > > > exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> > > > device to appear) and implements the hotplug handling for notifying drm via
> > > > connector status change.
> > > >
> > > > The driver for the i.MX8M would use the samsung-dsim bridge without an
> > > > additional bridge.
> > > >
> > > > This allows the samsung-dsim driver to expose the standard behavior while the
> > > > exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> > > >
> > > > I hope this makes sense and does not sound too crazy. It might be difficult to
> > > > get the probing and mipi host/device registration correct, but I will try, if
> > > > this can work.
> > >
> > > Adding two bridges for being able to support hotplugging adds many special
> > > cases to the bridge driver and still requires more custom API to correctly add
> > > the second bridge. I don't think that this a viable path to go.
> > 
> > Just jumping in here: You cannot hotplug/hotremove anything from a
> > drm_device after drm_dev_register has been called, except
> > drm_connector. I didn't dig into details here so not sure whether you
> > want to late-bind your bridge after drm_dev_register is called or not,
> > so might just be fyi and not relevant to the discussion.
> 
> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
> driver (i.e. Option B)
> 
> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
> device might attach to the DSI host and call exynos_dsi_host_attach. In
> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
> attaches this bridge to the encoder _after_ drm_dev_register has been called.
> This is invalid behavior, right?

Definitely not supported, I don't think we have the right locks in place
to make sure this works.

Now if your _only_ adding a drm_bridge (and not an encoder or anything
like that), and you are adding the drm_connector correctly (like a
hotplugged DP MST sink), then that would at least work from a uapi pov.
Because drm_bridge isn't exposed as an uapi object.

But yeah, as-is, don't :-)

The solution here is a bunch of EPROBE_DEFER handling until all your
bridges are loaded, with or without the assistance of component.c
framework. Only then call drm_dev_register.
-Daniel

> 
> Michael
> 
> > -Daniel
> > 
> > >
> > > This leaves us with:
> > >
> > > Option A) Standard drm_bridge behavior, which is currently implemented, but
> > > incompatible with the currently expected behavior of exynos_drm.
> > >
> > > Option B) Creating the drm device without all bridges being attached, which
> > > would work with the exynos_drm driver, but breaks for the standard drm_bridge
> > > behavior, especially, if the encoder/connector is created at the beginning of
> > > the pipeline and passed downwards when the bridges are attached.
> > >
> > > Option C) Extracting only low level register accesses into shared code, adding
> > > a custom interface and implementing the drm_bridge handling in the platform
> > > specific code.
> > >
> > > None of the options really convinces me.
> > >
> > > Michael
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-04 16:05                       ` Daniel Vetter
@ 2021-02-04 16:28                         ` Andrzej Hajda
  2021-02-04 17:19                           ` Daniel Vetter
  0 siblings, 1 reply; 57+ messages in thread
From: Andrzej Hajda @ 2021-02-04 16:28 UTC (permalink / raw)
  To: Daniel Vetter, Michael Tretter
  Cc: Marek Vasut, aisheng.dong, linux-samsung-soc, ch, Neil Armstrong,
	Shawn Guo, Krzysztof Kozlowski, Seung-Woo Kim, dl-linux-imx,
	frieder.schrempf, abel.vesa, Bartlomiej Zolnierkiewicz,
	dri-devel, Joonyoung Shim, sylvester.nawrocki, Marek Szyprowski,
	aford173, Sascha Hauer, Laurent Pinchart


W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
> On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
>> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
>>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter <m.tretter@pengutronix.de> wrote:
>>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
>>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
>>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
>>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
>>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
>>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
>>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
>>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
>>>>>>>>>>> used
>>>>>>>>>>> from other drivers.
>>>>>>>>>>>
>>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
>>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
>>>>>>>>>>> display pipe until the downstream bridges are available, too.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
>>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
>>>>>>>>>>
>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
>>>>>>>>>> operations
>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>>> 8<--- cut here ---
>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>>> 00000084
>>>>>>>>>> pgd = (ptrval)
>>>>>>>>>> [00000084] *pgd=00000000
>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>>> Modules linked in:
>>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
>>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
>>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
>>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
>>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
>>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
>>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
>>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
>>>>>>>>>> ...
>>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
>>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
>>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
>>>>>>>>>> (component_bind_all+0xfc/0x290)
>>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
>>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
>>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
>>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
>>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
>>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
>>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
>>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
>>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
>>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
>>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
>>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
>>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
>>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
>>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
>>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
>>>>>>>>>> (exynos_drm_init+0xe4/0x118)
>>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
>>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>>> ...
>>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
>>>>>>>>>>
>>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
>>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
>>>>>>>>>>
>>>>>>>>>> I will try to debug it a bit more today.
>>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
>>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
>>>>>>>>> another issue:
>>>>>>>>>
>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>> 8<--- cut here ---
>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>> 00000280
>>>>>>>>> pgd = (ptrval)
>>>>>>>>> [00000280] *pgd=00000000
>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>> Modules linked in:
>>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>> PC is at __mutex_lock+0x54/0xb18
>>>>>>>>> LR is at lock_is_held_type+0x80/0x138
>>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
>>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
>>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
>>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
>>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
>>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
>>>>>>>>> ...
>>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
>>>>>>>>> (mutex_lock_nested+0x1c/0x24)
>>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
>>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
>>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
>>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
>>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
>>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
>>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>> ...
>>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
>>>>>>>>>
>>>>>>>>> This means that dsi->encoder.dev is not initialized in
>>>>>>>>> __exynos_dsi_host_attach().
>>>>>>>>>
>>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
>>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
>>>>>>>>> release of all drm resources.
>>>>>>>>>
>>>>>>>>> Then however, the panel tries to register itself and
>>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
>>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
>>>>>>>>> failure.
>>>>>>>>>
>>>>>>>>> It looks that something is missing. Maybe mipi host has to be
>>>>>>>>> registered
>>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
>>>>>>>>> this patch. Andrzej, could you comment it a bit?
>>>>>>>> I intentionally changed the order, because if another bridge follows
>>>>>>>> in the
>>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
>>>>>>>> bridge
>>>>>>>> provides a connector. The next bridge registers itself via the
>>>>>>>> host_attach
>>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
>>>>>>>> API or
>>>>>>>> the bridge_attach function otherwise.
>>>>>>>>
>>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
>>>>>>>> device
>>>>>>>> has been attached.
>>>>>>>>
>>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
>>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
>>>>>>>> via
>>>>>>>> exynos_dsi instead of the bridge.
>>>>>>>>
>>>>>>>> Can you try to move everything except samsung_dsim_bind from
>>>>>>>> exynos_dsi_bind
>>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
>>>>>>>> crash.
>>>>>>>
>>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
>>>>>>> regardless of sink presence (initially panel, later also bridge) - it
>>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
>>>>>>> and module load/unload. Appearance or disappearance of sink is
>>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
>>>>>>> reflected in drm world as change state of the connector.
>>>>>>>
>>>>>>> Registering DSI host in bind and unregistering in unbind assures that
>>>>>>> if mipi_dsi device is attached/detached the drm device is always
>>>>>>> present - it makes device/driver binding race free and allows to avoid
>>>>>>> additional locking.
>>>>>>>
>>>>>>> Moving DSI host registration to probe changes everything, for sure it
>>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
>>>>>>> can cause different issues depending on device bind order.
>>>>>>>
>>>>>>> I will try to look at the patches tomorrow and maybe I can find more
>>>>>>> constructive comments :)
>>>>>>
>>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
>>>>>> callbacks to control appearance/disappearance of downstream device. It
>>>>>> allows to:
>>>>>>
>>>>>> 1. Safely bind/unbind different device drivers at any time and at any
>>>>>> order, without killing exynos_drm and/or crashing system.
>>>>>>
>>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
>>>>>> appeared too late, due to deferred probe, and resulted in black screen
>>>>>> in userspace.
>>>>>>
>>>>>>
>>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
>>>>>>
>>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
>>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
>>>>>> appearance, thus probably black screen on some targets. So for sure it
>>>>>> will be suboptimal. Making it bridge unbind safe would be another
>>>>>> problem, but most developers do not care about it so why should we? :)
>>>>>>
>>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
>>>>>> even if downstream devices are not yet attached, on attach/detach notify
>>>>>> drm about it via connector status change, for this dsi_host registration
>>>>>> should be performed from drm_bridge attach, I guess.
>>>>>>
>>>>>>
>>>>>> Option A is more standard, but is unsafe and causes other issues.
>>>>>>
>>>>>> Option B keeps current behaviour.
>>>>> Maybe we can have both, but I am not sure, if I am missing something:
>>>>>
>>>>> I still prefer option A for the samsung-dsim driver, because it is more
>>>>> standard, simpler and avoids issues with encoders, connectors or handling
>>>>> hotplug.
>>>>>
>>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
>>>>> samsung-dsim driver which implements option A and defers probing of the drm
>>>>> driver until the next bridge is attached. And a second bridge in the
>>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
>>>>> device to appear) and implements the hotplug handling for notifying drm via
>>>>> connector status change.
>>>>>
>>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
>>>>> additional bridge.
>>>>>
>>>>> This allows the samsung-dsim driver to expose the standard behavior while the
>>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
>>>>>
>>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
>>>>> get the probing and mipi host/device registration correct, but I will try, if
>>>>> this can work.
>>>> Adding two bridges for being able to support hotplugging adds many special
>>>> cases to the bridge driver and still requires more custom API to correctly add
>>>> the second bridge. I don't think that this a viable path to go.
>>> Just jumping in here: You cannot hotplug/hotremove anything from a
>>> drm_device after drm_dev_register has been called, except
>>> drm_connector. I didn't dig into details here so not sure whether you
>>> want to late-bind your bridge after drm_dev_register is called or not,
>>> so might just be fyi and not relevant to the discussion.
>> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
>> driver (i.e. Option B)
>>
>> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
>> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
>> device might attach to the DSI host and call exynos_dsi_host_attach. In
>> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
>> attaches this bridge to the encoder _after_ drm_dev_register has been called.
>> This is invalid behavior, right?
> Definitely not supported, I don't think we have the right locks in place
> to make sure this works.
>
> Now if your _only_ adding a drm_bridge (and not an encoder or anything
> like that), and you are adding the drm_connector correctly (like a
> hotplugged DP MST sink), then that would at least work from a uapi pov.
> Because drm_bridge isn't exposed as an uapi object.
>
> But yeah, as-is, don't :-)
>
> The solution here is a bunch of EPROBE_DEFER handling until all your
> bridges are loaded, with or without the assistance of component.c
> framework. Only then call drm_dev_register.
> -Daniel


I have impression we have similar conversation already.

As you stated drm_bridge and drm_panel are not exposed to userspace so 
there shouldn't be problem with them from uapi PoV.

On the other side drm_panel or drm_bridge are not used until pipeline 
enters connected state (at least they were not some time ago :) ). The 
issue is that bridge exposes drm_connector, but as you stated (again :) 
) connectors can be hotplugged, so in theory it should work. Practical 
tests shows that it also works, but bugs can be still there.

Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and 
decided there is no display), and does not handle unbinding/re-binding 
drivers.


Regards

Andrzej


>
>> Michael
>>
>>> -Daniel
>>>
>>>> This leaves us with:
>>>>
>>>> Option A) Standard drm_bridge behavior, which is currently implemented, but
>>>> incompatible with the currently expected behavior of exynos_drm.
>>>>
>>>> Option B) Creating the drm device without all bridges being attached, which
>>>> would work with the exynos_drm driver, but breaks for the standard drm_bridge
>>>> behavior, especially, if the encoder/connector is created at the beginning of
>>>> the pipeline and passed downwards when the bridges are attached.
>>>>
>>>> Option C) Extracting only low level register accesses into shared code, adding
>>>> a custom interface and implementing the drm_bridge handling in the platform
>>>> specific code.
>>>>
>>>> None of the options really convinces me.
>>>>
>>>> Michael
>>>> _______________________________________________
>>>> dri-devel mailing list
>>>> dri-devel@lists.freedesktop.org
>>>> https://protect2.fireeye.com/v1/url?k=9b91fda0-c40ac4d5-9b9076ef-0cc47a31ce4e-a7f88871f6fd42d4&q=1&e=f2cfade9-8ecf-4697-88b3-69d93ed38361&u=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Fdri-devel

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-04 16:28                         ` Andrzej Hajda
@ 2021-02-04 17:19                           ` Daniel Vetter
  2021-02-04 17:26                             ` Laurent Pinchart
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2021-02-04 17:19 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Michael Tretter, Marek Vasut, aisheng.dong, linux-samsung-soc,
	ch, Neil Armstrong, Shawn Guo, Krzysztof Kozlowski,
	Seung-Woo Kim, dl-linux-imx, frieder.schrempf, abel.vesa,
	Bartlomiej Zolnierkiewicz, dri-devel, Joonyoung Shim,
	sylvester.nawrocki, Marek Szyprowski, aford173, Sascha Hauer,
	Laurent Pinchart

On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda <a.hajda@samsung.com> wrote:
>
>
> W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
> > On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
> >> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> >>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter <m.tretter@pengutronix.de> wrote:
> >>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> >>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> >>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> >>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
> >>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> >>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> >>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
> >>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> >>>>>>>>>>> used
> >>>>>>>>>>> from other drivers.
> >>>>>>>>>>>
> >>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> >>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
> >>>>>>>>>>> display pipe until the downstream bridges are available, too.
> >>>>>>>>>>>
> >>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> >>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
> >>>>>>>>>>
> >>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> >>>>>>>>>> operations
> >>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> >>>>>>>>>> 8<--- cut here ---
> >>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> >>>>>>>>>> 00000084
> >>>>>>>>>> pgd = (ptrval)
> >>>>>>>>>> [00000084] *pgd=00000000
> >>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>>>>>>>>> Modules linked in:
> >>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> >>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> >>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
> >>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
> >>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> >>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> >>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> >>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> >>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> >>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
> >>>>>>>>>> ...
> >>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> >>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
> >>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> >>>>>>>>>> (component_bind_all+0xfc/0x290)
> >>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> >>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
> >>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> >>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
> >>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> >>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
> >>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> >>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
> >>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> >>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
> >>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> >>>>>>>>>> (really_probe+0x200/0x4fc)
> >>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
> >>>>>>>>>> (driver_probe_device+0x78/0x1fc)
> >>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> >>>>>>>>>> (device_driver_attach+0x58/0x60)
> >>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> >>>>>>>>>> (__driver_attach+0xdc/0x174)
> >>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> >>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> >>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> >>>>>>>>>> (bus_add_driver+0x158/0x214)
> >>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> >>>>>>>>>> (driver_register+0x78/0x110)
> >>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> >>>>>>>>>> (exynos_drm_init+0xe4/0x118)
> >>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> >>>>>>>>>> (do_one_initcall+0x8c/0x42c)
> >>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> >>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> >>>>>>>>>> (kernel_init+0x8/0x118)
> >>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>>>>>>>>> ...
> >>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
> >>>>>>>>>>
> >>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> >>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> >>>>>>>>>>
> >>>>>>>>>> I will try to debug it a bit more today.
> >>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
> >>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> >>>>>>>>> another issue:
> >>>>>>>>>
> >>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> >>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> >>>>>>>>> 8<--- cut here ---
> >>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> >>>>>>>>> 00000280
> >>>>>>>>> pgd = (ptrval)
> >>>>>>>>> [00000280] *pgd=00000000
> >>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>>>>>>>> Modules linked in:
> >>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> >>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> >>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>>>>>>>> PC is at __mutex_lock+0x54/0xb18
> >>>>>>>>> LR is at lock_is_held_type+0x80/0x138
> >>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> >>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> >>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> >>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> >>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> >>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
> >>>>>>>>> ...
> >>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> >>>>>>>>> (mutex_lock_nested+0x1c/0x24)
> >>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> >>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
> >>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> >>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
> >>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> >>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
> >>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> >>>>>>>>> (really_probe+0x200/0x4fc)
> >>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
> >>>>>>>>> (driver_probe_device+0x78/0x1fc)
> >>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> >>>>>>>>> (device_driver_attach+0x58/0x60)
> >>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> >>>>>>>>> (__driver_attach+0xdc/0x174)
> >>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> >>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> >>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> >>>>>>>>> (bus_add_driver+0x158/0x214)
> >>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> >>>>>>>>> (driver_register+0x78/0x110)
> >>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
> >>>>>>>>> (do_one_initcall+0x8c/0x42c)
> >>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> >>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> >>>>>>>>> (kernel_init+0x8/0x118)
> >>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>>>>>>>> ...
> >>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
> >>>>>>>>>
> >>>>>>>>> This means that dsi->encoder.dev is not initialized in
> >>>>>>>>> __exynos_dsi_host_attach().
> >>>>>>>>>
> >>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> >>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
> >>>>>>>>> release of all drm resources.
> >>>>>>>>>
> >>>>>>>>> Then however, the panel tries to register itself and
> >>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
> >>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
> >>>>>>>>> failure.
> >>>>>>>>>
> >>>>>>>>> It looks that something is missing. Maybe mipi host has to be
> >>>>>>>>> registered
> >>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
> >>>>>>>>> this patch. Andrzej, could you comment it a bit?
> >>>>>>>> I intentionally changed the order, because if another bridge follows
> >>>>>>>> in the
> >>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
> >>>>>>>> bridge
> >>>>>>>> provides a connector. The next bridge registers itself via the
> >>>>>>>> host_attach
> >>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
> >>>>>>>> API or
> >>>>>>>> the bridge_attach function otherwise.
> >>>>>>>>
> >>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
> >>>>>>>> device
> >>>>>>>> has been attached.
> >>>>>>>>
> >>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
> >>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> >>>>>>>> via
> >>>>>>>> exynos_dsi instead of the bridge.
> >>>>>>>>
> >>>>>>>> Can you try to move everything except samsung_dsim_bind from
> >>>>>>>> exynos_dsi_bind
> >>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> >>>>>>>> crash.
> >>>>>>>
> >>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
> >>>>>>> regardless of sink presence (initially panel, later also bridge) - it
> >>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
> >>>>>>> and module load/unload. Appearance or disappearance of sink is
> >>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
> >>>>>>> reflected in drm world as change state of the connector.
> >>>>>>>
> >>>>>>> Registering DSI host in bind and unregistering in unbind assures that
> >>>>>>> if mipi_dsi device is attached/detached the drm device is always
> >>>>>>> present - it makes device/driver binding race free and allows to avoid
> >>>>>>> additional locking.
> >>>>>>>
> >>>>>>> Moving DSI host registration to probe changes everything, for sure it
> >>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
> >>>>>>> can cause different issues depending on device bind order.
> >>>>>>>
> >>>>>>> I will try to look at the patches tomorrow and maybe I can find more
> >>>>>>> constructive comments :)
> >>>>>>
> >>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> >>>>>> callbacks to control appearance/disappearance of downstream device. It
> >>>>>> allows to:
> >>>>>>
> >>>>>> 1. Safely bind/unbind different device drivers at any time and at any
> >>>>>> order, without killing exynos_drm and/or crashing system.
> >>>>>>
> >>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
> >>>>>> appeared too late, due to deferred probe, and resulted in black screen
> >>>>>> in userspace.
> >>>>>>
> >>>>>>
> >>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
> >>>>>>
> >>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
> >>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
> >>>>>> appearance, thus probably black screen on some targets. So for sure it
> >>>>>> will be suboptimal. Making it bridge unbind safe would be another
> >>>>>> problem, but most developers do not care about it so why should we? :)
> >>>>>>
> >>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> >>>>>> even if downstream devices are not yet attached, on attach/detach notify
> >>>>>> drm about it via connector status change, for this dsi_host registration
> >>>>>> should be performed from drm_bridge attach, I guess.
> >>>>>>
> >>>>>>
> >>>>>> Option A is more standard, but is unsafe and causes other issues.
> >>>>>>
> >>>>>> Option B keeps current behaviour.
> >>>>> Maybe we can have both, but I am not sure, if I am missing something:
> >>>>>
> >>>>> I still prefer option A for the samsung-dsim driver, because it is more
> >>>>> standard, simpler and avoids issues with encoders, connectors or handling
> >>>>> hotplug.
> >>>>>
> >>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> >>>>> samsung-dsim driver which implements option A and defers probing of the drm
> >>>>> driver until the next bridge is attached. And a second bridge in the
> >>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> >>>>> device to appear) and implements the hotplug handling for notifying drm via
> >>>>> connector status change.
> >>>>>
> >>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
> >>>>> additional bridge.
> >>>>>
> >>>>> This allows the samsung-dsim driver to expose the standard behavior while the
> >>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> >>>>>
> >>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
> >>>>> get the probing and mipi host/device registration correct, but I will try, if
> >>>>> this can work.
> >>>> Adding two bridges for being able to support hotplugging adds many special
> >>>> cases to the bridge driver and still requires more custom API to correctly add
> >>>> the second bridge. I don't think that this a viable path to go.
> >>> Just jumping in here: You cannot hotplug/hotremove anything from a
> >>> drm_device after drm_dev_register has been called, except
> >>> drm_connector. I didn't dig into details here so not sure whether you
> >>> want to late-bind your bridge after drm_dev_register is called or not,
> >>> so might just be fyi and not relevant to the discussion.
> >> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
> >> driver (i.e. Option B)
> >>
> >> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
> >> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
> >> device might attach to the DSI host and call exynos_dsi_host_attach. In
> >> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
> >> attaches this bridge to the encoder _after_ drm_dev_register has been called.
> >> This is invalid behavior, right?
> > Definitely not supported, I don't think we have the right locks in place
> > to make sure this works.
> >
> > Now if your _only_ adding a drm_bridge (and not an encoder or anything
> > like that), and you are adding the drm_connector correctly (like a
> > hotplugged DP MST sink), then that would at least work from a uapi pov.
> > Because drm_bridge isn't exposed as an uapi object.
> >
> > But yeah, as-is, don't :-)
> >
> > The solution here is a bunch of EPROBE_DEFER handling until all your
> > bridges are loaded, with or without the assistance of component.c
> > framework. Only then call drm_dev_register.
> > -Daniel
>
>
> I have impression we have similar conversation already.
>
> As you stated drm_bridge and drm_panel are not exposed to userspace so
> there shouldn't be problem with them from uapi PoV.
>
> On the other side drm_panel or drm_bridge are not used until pipeline
> enters connected state (at least they were not some time ago :) ). The
> issue is that bridge exposes drm_connector, but as you stated (again :)
> ) connectors can be hotplugged, so in theory it should work. Practical
> tests shows that it also works, but bugs can be still there.
>
> Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
> decided there is no display), and does not handle unbinding/re-binding
> drivers.

Rebinding drivers should be fixed now, with a bunch of fixes in driver
core. If not, we need to fix this more.

Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
seem to go anywhere), not paper over it with bad architecture in
drivers.

There's also a bit the issue that most userspace handles panels in a
special way, and if they don't find the panel at first, that doesn't
work. Stuff like "which is the main screen" on laptops.

So yeah please fix this properly.
-Daniel

>
>
> Regards
>
> Andrzej
>
>
> >
> >> Michael
> >>
> >>> -Daniel
> >>>
> >>>> This leaves us with:
> >>>>
> >>>> Option A) Standard drm_bridge behavior, which is currently implemented, but
> >>>> incompatible with the currently expected behavior of exynos_drm.
> >>>>
> >>>> Option B) Creating the drm device without all bridges being attached, which
> >>>> would work with the exynos_drm driver, but breaks for the standard drm_bridge
> >>>> behavior, especially, if the encoder/connector is created at the beginning of
> >>>> the pipeline and passed downwards when the bridges are attached.
> >>>>
> >>>> Option C) Extracting only low level register accesses into shared code, adding
> >>>> a custom interface and implementing the drm_bridge handling in the platform
> >>>> specific code.
> >>>>
> >>>> None of the options really convinces me.
> >>>>
> >>>> Michael
> >>>> _______________________________________________
> >>>> dri-devel mailing list
> >>>> dri-devel@lists.freedesktop.org
> >>>> https://protect2.fireeye.com/v1/url?k=9b91fda0-c40ac4d5-9b9076ef-0cc47a31ce4e-a7f88871f6fd42d4&q=1&e=f2cfade9-8ecf-4697-88b3-69d93ed38361&u=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Fdri-devel



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-04 17:19                           ` Daniel Vetter
@ 2021-02-04 17:26                             ` Laurent Pinchart
  2021-02-04 17:46                               ` Daniel Vetter
  0 siblings, 1 reply; 57+ messages in thread
From: Laurent Pinchart @ 2021-02-04 17:26 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Andrzej Hajda, Michael Tretter, Marek Vasut, aisheng.dong,
	linux-samsung-soc, ch, Neil Armstrong, Shawn Guo,
	Krzysztof Kozlowski, Seung-Woo Kim, dl-linux-imx,
	frieder.schrempf, abel.vesa, Bartlomiej Zolnierkiewicz,
	dri-devel, Joonyoung Shim, sylvester.nawrocki, Marek Szyprowski,
	aford173, Sascha Hauer

Hi Daniel,

On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
> On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
> > W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
> > > On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
> > >> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> > >>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
> > >>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> > >>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> > >>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > >>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
> > >>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> > >>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> > >>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
> > >>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> > >>>>>>>>>>> used
> > >>>>>>>>>>> from other drivers.
> > >>>>>>>>>>>
> > >>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> > >>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
> > >>>>>>>>>>> display pipe until the downstream bridges are available, too.
> > >>>>>>>>>>>
> > >>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > >>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
> > >>>>>>>>>>
> > >>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> > >>>>>>>>>> operations
> > >>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > >>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> > >>>>>>>>>> 8<--- cut here ---
> > >>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> > >>>>>>>>>> 00000084
> > >>>>>>>>>> pgd = (ptrval)
> > >>>>>>>>>> [00000084] *pgd=00000000
> > >>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > >>>>>>>>>> Modules linked in:
> > >>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > >>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > >>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > >>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
> > >>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
> > >>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > >>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > >>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > >>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > >>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > >>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > >>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > >>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > >>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
> > >>>>>>>>>> ...
> > >>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > >>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
> > >>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > >>>>>>>>>> (component_bind_all+0xfc/0x290)
> > >>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > >>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
> > >>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > >>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
> > >>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > >>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
> > >>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > >>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
> > >>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > >>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
> > >>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > >>>>>>>>>> (really_probe+0x200/0x4fc)
> > >>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
> > >>>>>>>>>> (driver_probe_device+0x78/0x1fc)
> > >>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > >>>>>>>>>> (device_driver_attach+0x58/0x60)
> > >>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > >>>>>>>>>> (__driver_attach+0xdc/0x174)
> > >>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > >>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> > >>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > >>>>>>>>>> (bus_add_driver+0x158/0x214)
> > >>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> > >>>>>>>>>> (driver_register+0x78/0x110)
> > >>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > >>>>>>>>>> (exynos_drm_init+0xe4/0x118)
> > >>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > >>>>>>>>>> (do_one_initcall+0x8c/0x42c)
> > >>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > >>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> > >>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > >>>>>>>>>> (kernel_init+0x8/0x118)
> > >>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > >>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > >>>>>>>>>> ...
> > >>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
> > >>>>>>>>>>
> > >>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > >>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> > >>>>>>>>>>
> > >>>>>>>>>> I will try to debug it a bit more today.
> > >>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
> > >>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> > >>>>>>>>> another issue:
> > >>>>>>>>>
> > >>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > >>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > >>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> > >>>>>>>>> 8<--- cut here ---
> > >>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> > >>>>>>>>> 00000280
> > >>>>>>>>> pgd = (ptrval)
> > >>>>>>>>> [00000280] *pgd=00000000
> > >>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > >>>>>>>>> Modules linked in:
> > >>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> > >>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> > >>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > >>>>>>>>> PC is at __mutex_lock+0x54/0xb18
> > >>>>>>>>> LR is at lock_is_held_type+0x80/0x138
> > >>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> > >>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> > >>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> > >>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> > >>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> > >>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > >>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > >>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > >>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
> > >>>>>>>>> ...
> > >>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> > >>>>>>>>> (mutex_lock_nested+0x1c/0x24)
> > >>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> > >>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
> > >>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> > >>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
> > >>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> > >>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
> > >>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> > >>>>>>>>> (really_probe+0x200/0x4fc)
> > >>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
> > >>>>>>>>> (driver_probe_device+0x78/0x1fc)
> > >>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> > >>>>>>>>> (device_driver_attach+0x58/0x60)
> > >>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> > >>>>>>>>> (__driver_attach+0xdc/0x174)
> > >>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> > >>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> > >>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> > >>>>>>>>> (bus_add_driver+0x158/0x214)
> > >>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> > >>>>>>>>> (driver_register+0x78/0x110)
> > >>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
> > >>>>>>>>> (do_one_initcall+0x8c/0x42c)
> > >>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > >>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> > >>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> > >>>>>>>>> (kernel_init+0x8/0x118)
> > >>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > >>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > >>>>>>>>> ...
> > >>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
> > >>>>>>>>>
> > >>>>>>>>> This means that dsi->encoder.dev is not initialized in
> > >>>>>>>>> __exynos_dsi_host_attach().
> > >>>>>>>>>
> > >>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> > >>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
> > >>>>>>>>> release of all drm resources.
> > >>>>>>>>>
> > >>>>>>>>> Then however, the panel tries to register itself and
> > >>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
> > >>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
> > >>>>>>>>> failure.
> > >>>>>>>>>
> > >>>>>>>>> It looks that something is missing. Maybe mipi host has to be
> > >>>>>>>>> registered
> > >>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
> > >>>>>>>>> this patch. Andrzej, could you comment it a bit?
> > >>>>>>>> I intentionally changed the order, because if another bridge follows
> > >>>>>>>> in the
> > >>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
> > >>>>>>>> bridge
> > >>>>>>>> provides a connector. The next bridge registers itself via the
> > >>>>>>>> host_attach
> > >>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
> > >>>>>>>> API or
> > >>>>>>>> the bridge_attach function otherwise.
> > >>>>>>>>
> > >>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
> > >>>>>>>> device
> > >>>>>>>> has been attached.
> > >>>>>>>>
> > >>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
> > >>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> > >>>>>>>> via
> > >>>>>>>> exynos_dsi instead of the bridge.
> > >>>>>>>>
> > >>>>>>>> Can you try to move everything except samsung_dsim_bind from
> > >>>>>>>> exynos_dsi_bind
> > >>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> > >>>>>>>> crash.
> > >>>>>>>
> > >>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
> > >>>>>>> regardless of sink presence (initially panel, later also bridge) - it
> > >>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
> > >>>>>>> and module load/unload. Appearance or disappearance of sink is
> > >>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
> > >>>>>>> reflected in drm world as change state of the connector.
> > >>>>>>>
> > >>>>>>> Registering DSI host in bind and unregistering in unbind assures that
> > >>>>>>> if mipi_dsi device is attached/detached the drm device is always
> > >>>>>>> present - it makes device/driver binding race free and allows to avoid
> > >>>>>>> additional locking.
> > >>>>>>>
> > >>>>>>> Moving DSI host registration to probe changes everything, for sure it
> > >>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
> > >>>>>>> can cause different issues depending on device bind order.
> > >>>>>>>
> > >>>>>>> I will try to look at the patches tomorrow and maybe I can find more
> > >>>>>>> constructive comments :)
> > >>>>>>
> > >>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> > >>>>>> callbacks to control appearance/disappearance of downstream device. It
> > >>>>>> allows to:
> > >>>>>>
> > >>>>>> 1. Safely bind/unbind different device drivers at any time and at any
> > >>>>>> order, without killing exynos_drm and/or crashing system.
> > >>>>>>
> > >>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
> > >>>>>> appeared too late, due to deferred probe, and resulted in black screen
> > >>>>>> in userspace.
> > >>>>>>
> > >>>>>>
> > >>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
> > >>>>>>
> > >>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
> > >>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
> > >>>>>> appearance, thus probably black screen on some targets. So for sure it
> > >>>>>> will be suboptimal. Making it bridge unbind safe would be another
> > >>>>>> problem, but most developers do not care about it so why should we? :)
> > >>>>>>
> > >>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> > >>>>>> even if downstream devices are not yet attached, on attach/detach notify
> > >>>>>> drm about it via connector status change, for this dsi_host registration
> > >>>>>> should be performed from drm_bridge attach, I guess.
> > >>>>>>
> > >>>>>>
> > >>>>>> Option A is more standard, but is unsafe and causes other issues.
> > >>>>>>
> > >>>>>> Option B keeps current behaviour.
> > >>>>> Maybe we can have both, but I am not sure, if I am missing something:
> > >>>>>
> > >>>>> I still prefer option A for the samsung-dsim driver, because it is more
> > >>>>> standard, simpler and avoids issues with encoders, connectors or handling
> > >>>>> hotplug.
> > >>>>>
> > >>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> > >>>>> samsung-dsim driver which implements option A and defers probing of the drm
> > >>>>> driver until the next bridge is attached. And a second bridge in the
> > >>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> > >>>>> device to appear) and implements the hotplug handling for notifying drm via
> > >>>>> connector status change.
> > >>>>>
> > >>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
> > >>>>> additional bridge.
> > >>>>>
> > >>>>> This allows the samsung-dsim driver to expose the standard behavior while the
> > >>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> > >>>>>
> > >>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
> > >>>>> get the probing and mipi host/device registration correct, but I will try, if
> > >>>>> this can work.
> > >>>> Adding two bridges for being able to support hotplugging adds many special
> > >>>> cases to the bridge driver and still requires more custom API to correctly add
> > >>>> the second bridge. I don't think that this a viable path to go.
> > >>> Just jumping in here: You cannot hotplug/hotremove anything from a
> > >>> drm_device after drm_dev_register has been called, except
> > >>> drm_connector. I didn't dig into details here so not sure whether you
> > >>> want to late-bind your bridge after drm_dev_register is called or not,
> > >>> so might just be fyi and not relevant to the discussion.
> > >> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
> > >> driver (i.e. Option B)
> > >>
> > >> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
> > >> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
> > >> device might attach to the DSI host and call exynos_dsi_host_attach. In
> > >> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
> > >> attaches this bridge to the encoder _after_ drm_dev_register has been called.
> > >> This is invalid behavior, right?
> > > Definitely not supported, I don't think we have the right locks in place
> > > to make sure this works.
> > >
> > > Now if your _only_ adding a drm_bridge (and not an encoder or anything
> > > like that), and you are adding the drm_connector correctly (like a
> > > hotplugged DP MST sink), then that would at least work from a uapi pov.
> > > Because drm_bridge isn't exposed as an uapi object.
> > >
> > > But yeah, as-is, don't :-)
> > >
> > > The solution here is a bunch of EPROBE_DEFER handling until all your
> > > bridges are loaded, with or without the assistance of component.c
> > > framework. Only then call drm_dev_register.
> >
> > I have impression we have similar conversation already.
> >
> > As you stated drm_bridge and drm_panel are not exposed to userspace so
> > there shouldn't be problem with them from uapi PoV.
> >
> > On the other side drm_panel or drm_bridge are not used until pipeline
> > enters connected state (at least they were not some time ago :) ). The
> > issue is that bridge exposes drm_connector, but as you stated (again :)
> > ) connectors can be hotplugged, so in theory it should work. Practical
> > tests shows that it also works, but bugs can be still there.
> >
> > Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
> > decided there is no display), and does not handle unbinding/re-binding
> > drivers.
> 
> Rebinding drivers should be fixed now, with a bunch of fixes in driver
> core. If not, we need to fix this more.
> 
> Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
> we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
> seem to go anywhere), not paper over it with bad architecture in
> drivers.

I've heard this argument multiple times, but it sounds more like an
attempt to ignore the problem and hope it will fall on someone else's
plate :-) Improvement in the probe deferral mechanism are certainly an
option to explore, but as far as I can tell nobody has proven that this
mechanism is or will be able to solve all problems related to probe
ordering dependencies. I wouldn't rule out the need for different
solutions for some of the issues.

> There's also a bit the issue that most userspace handles panels in a
> special way, and if they don't find the panel at first, that doesn't
> work. Stuff like "which is the main screen" on laptops.
> 
> So yeah please fix this properly.
>
> > >>>> This leaves us with:
> > >>>>
> > >>>> Option A) Standard drm_bridge behavior, which is currently implemented, but
> > >>>> incompatible with the currently expected behavior of exynos_drm.
> > >>>>
> > >>>> Option B) Creating the drm device without all bridges being attached, which
> > >>>> would work with the exynos_drm driver, but breaks for the standard drm_bridge
> > >>>> behavior, especially, if the encoder/connector is created at the beginning of
> > >>>> the pipeline and passed downwards when the bridges are attached.
> > >>>>
> > >>>> Option C) Extracting only low level register accesses into shared code, adding
> > >>>> a custom interface and implementing the drm_bridge handling in the platform
> > >>>> specific code.
> > >>>>
> > >>>> None of the options really convinces me.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-04 17:26                             ` Laurent Pinchart
@ 2021-02-04 17:46                               ` Daniel Vetter
  2021-02-10  9:10                                 ` Frieder Schrempf
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2021-02-04 17:46 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Andrzej Hajda, Michael Tretter, Marek Vasut, aisheng.dong,
	linux-samsung-soc, ch, Neil Armstrong, Shawn Guo,
	Krzysztof Kozlowski, Seung-Woo Kim, dl-linux-imx,
	frieder.schrempf, abel.vesa, Bartlomiej Zolnierkiewicz,
	dri-devel, Joonyoung Shim, sylvester.nawrocki, Marek Szyprowski,
	aford173, Sascha Hauer

On Thu, Feb 4, 2021 at 6:26 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Daniel,
>
> On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
> > On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
> > > W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
> > > > On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
> > > >> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> > > >>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
> > > >>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> > > >>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> > > >>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > > >>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
> > > >>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> > > >>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> > > >>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
> > > >>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> > > >>>>>>>>>>> used
> > > >>>>>>>>>>> from other drivers.
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> > > >>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
> > > >>>>>>>>>>> display pipe until the downstream bridges are available, too.
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > > >>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
> > > >>>>>>>>>>
> > > >>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> > > >>>>>>>>>> operations
> > > >>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > >>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> > > >>>>>>>>>> 8<--- cut here ---
> > > >>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> > > >>>>>>>>>> 00000084
> > > >>>>>>>>>> pgd = (ptrval)
> > > >>>>>>>>>> [00000084] *pgd=00000000
> > > >>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > >>>>>>>>>> Modules linked in:
> > > >>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > > >>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > > >>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > >>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
> > > >>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
> > > >>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > > >>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > > >>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > > >>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > > >>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > > >>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > >>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > >>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > >>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
> > > >>>>>>>>>> ...
> > > >>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > > >>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
> > > >>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > > >>>>>>>>>> (component_bind_all+0xfc/0x290)
> > > >>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > > >>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
> > > >>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > > >>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
> > > >>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > > >>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
> > > >>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > > >>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
> > > >>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > > >>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
> > > >>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > > >>>>>>>>>> (really_probe+0x200/0x4fc)
> > > >>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
> > > >>>>>>>>>> (driver_probe_device+0x78/0x1fc)
> > > >>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > > >>>>>>>>>> (device_driver_attach+0x58/0x60)
> > > >>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > > >>>>>>>>>> (__driver_attach+0xdc/0x174)
> > > >>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > > >>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> > > >>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > > >>>>>>>>>> (bus_add_driver+0x158/0x214)
> > > >>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> > > >>>>>>>>>> (driver_register+0x78/0x110)
> > > >>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > > >>>>>>>>>> (exynos_drm_init+0xe4/0x118)
> > > >>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > > >>>>>>>>>> (do_one_initcall+0x8c/0x42c)
> > > >>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > >>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> > > >>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > > >>>>>>>>>> (kernel_init+0x8/0x118)
> > > >>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > >>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > >>>>>>>>>> ...
> > > >>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
> > > >>>>>>>>>>
> > > >>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > > >>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> > > >>>>>>>>>>
> > > >>>>>>>>>> I will try to debug it a bit more today.
> > > >>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
> > > >>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> > > >>>>>>>>> another issue:
> > > >>>>>>>>>
> > > >>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > > >>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > >>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> > > >>>>>>>>> 8<--- cut here ---
> > > >>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> > > >>>>>>>>> 00000280
> > > >>>>>>>>> pgd = (ptrval)
> > > >>>>>>>>> [00000280] *pgd=00000000
> > > >>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > >>>>>>>>> Modules linked in:
> > > >>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> > > >>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> > > >>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> > > >>>>>>>>> PC is at __mutex_lock+0x54/0xb18
> > > >>>>>>>>> LR is at lock_is_held_type+0x80/0x138
> > > >>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> > > >>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> > > >>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> > > >>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> > > >>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> > > >>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > >>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > >>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > >>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
> > > >>>>>>>>> ...
> > > >>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> > > >>>>>>>>> (mutex_lock_nested+0x1c/0x24)
> > > >>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> > > >>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
> > > >>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> > > >>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
> > > >>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> > > >>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
> > > >>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> > > >>>>>>>>> (really_probe+0x200/0x4fc)
> > > >>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
> > > >>>>>>>>> (driver_probe_device+0x78/0x1fc)
> > > >>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> > > >>>>>>>>> (device_driver_attach+0x58/0x60)
> > > >>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> > > >>>>>>>>> (__driver_attach+0xdc/0x174)
> > > >>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> > > >>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> > > >>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> > > >>>>>>>>> (bus_add_driver+0x158/0x214)
> > > >>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> > > >>>>>>>>> (driver_register+0x78/0x110)
> > > >>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
> > > >>>>>>>>> (do_one_initcall+0x8c/0x42c)
> > > >>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > >>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> > > >>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> > > >>>>>>>>> (kernel_init+0x8/0x118)
> > > >>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > >>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > >>>>>>>>> ...
> > > >>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
> > > >>>>>>>>>
> > > >>>>>>>>> This means that dsi->encoder.dev is not initialized in
> > > >>>>>>>>> __exynos_dsi_host_attach().
> > > >>>>>>>>>
> > > >>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> > > >>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
> > > >>>>>>>>> release of all drm resources.
> > > >>>>>>>>>
> > > >>>>>>>>> Then however, the panel tries to register itself and
> > > >>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
> > > >>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
> > > >>>>>>>>> failure.
> > > >>>>>>>>>
> > > >>>>>>>>> It looks that something is missing. Maybe mipi host has to be
> > > >>>>>>>>> registered
> > > >>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
> > > >>>>>>>>> this patch. Andrzej, could you comment it a bit?
> > > >>>>>>>> I intentionally changed the order, because if another bridge follows
> > > >>>>>>>> in the
> > > >>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
> > > >>>>>>>> bridge
> > > >>>>>>>> provides a connector. The next bridge registers itself via the
> > > >>>>>>>> host_attach
> > > >>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
> > > >>>>>>>> API or
> > > >>>>>>>> the bridge_attach function otherwise.
> > > >>>>>>>>
> > > >>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
> > > >>>>>>>> device
> > > >>>>>>>> has been attached.
> > > >>>>>>>>
> > > >>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
> > > >>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> > > >>>>>>>> via
> > > >>>>>>>> exynos_dsi instead of the bridge.
> > > >>>>>>>>
> > > >>>>>>>> Can you try to move everything except samsung_dsim_bind from
> > > >>>>>>>> exynos_dsi_bind
> > > >>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> > > >>>>>>>> crash.
> > > >>>>>>>
> > > >>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
> > > >>>>>>> regardless of sink presence (initially panel, later also bridge) - it
> > > >>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
> > > >>>>>>> and module load/unload. Appearance or disappearance of sink is
> > > >>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
> > > >>>>>>> reflected in drm world as change state of the connector.
> > > >>>>>>>
> > > >>>>>>> Registering DSI host in bind and unregistering in unbind assures that
> > > >>>>>>> if mipi_dsi device is attached/detached the drm device is always
> > > >>>>>>> present - it makes device/driver binding race free and allows to avoid
> > > >>>>>>> additional locking.
> > > >>>>>>>
> > > >>>>>>> Moving DSI host registration to probe changes everything, for sure it
> > > >>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
> > > >>>>>>> can cause different issues depending on device bind order.
> > > >>>>>>>
> > > >>>>>>> I will try to look at the patches tomorrow and maybe I can find more
> > > >>>>>>> constructive comments :)
> > > >>>>>>
> > > >>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> > > >>>>>> callbacks to control appearance/disappearance of downstream device. It
> > > >>>>>> allows to:
> > > >>>>>>
> > > >>>>>> 1. Safely bind/unbind different device drivers at any time and at any
> > > >>>>>> order, without killing exynos_drm and/or crashing system.
> > > >>>>>>
> > > >>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
> > > >>>>>> appeared too late, due to deferred probe, and resulted in black screen
> > > >>>>>> in userspace.
> > > >>>>>>
> > > >>>>>>
> > > >>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
> > > >>>>>>
> > > >>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
> > > >>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
> > > >>>>>> appearance, thus probably black screen on some targets. So for sure it
> > > >>>>>> will be suboptimal. Making it bridge unbind safe would be another
> > > >>>>>> problem, but most developers do not care about it so why should we? :)
> > > >>>>>>
> > > >>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> > > >>>>>> even if downstream devices are not yet attached, on attach/detach notify
> > > >>>>>> drm about it via connector status change, for this dsi_host registration
> > > >>>>>> should be performed from drm_bridge attach, I guess.
> > > >>>>>>
> > > >>>>>>
> > > >>>>>> Option A is more standard, but is unsafe and causes other issues.
> > > >>>>>>
> > > >>>>>> Option B keeps current behaviour.
> > > >>>>> Maybe we can have both, but I am not sure, if I am missing something:
> > > >>>>>
> > > >>>>> I still prefer option A for the samsung-dsim driver, because it is more
> > > >>>>> standard, simpler and avoids issues with encoders, connectors or handling
> > > >>>>> hotplug.
> > > >>>>>
> > > >>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> > > >>>>> samsung-dsim driver which implements option A and defers probing of the drm
> > > >>>>> driver until the next bridge is attached. And a second bridge in the
> > > >>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> > > >>>>> device to appear) and implements the hotplug handling for notifying drm via
> > > >>>>> connector status change.
> > > >>>>>
> > > >>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
> > > >>>>> additional bridge.
> > > >>>>>
> > > >>>>> This allows the samsung-dsim driver to expose the standard behavior while the
> > > >>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> > > >>>>>
> > > >>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
> > > >>>>> get the probing and mipi host/device registration correct, but I will try, if
> > > >>>>> this can work.
> > > >>>> Adding two bridges for being able to support hotplugging adds many special
> > > >>>> cases to the bridge driver and still requires more custom API to correctly add
> > > >>>> the second bridge. I don't think that this a viable path to go.
> > > >>> Just jumping in here: You cannot hotplug/hotremove anything from a
> > > >>> drm_device after drm_dev_register has been called, except
> > > >>> drm_connector. I didn't dig into details here so not sure whether you
> > > >>> want to late-bind your bridge after drm_dev_register is called or not,
> > > >>> so might just be fyi and not relevant to the discussion.
> > > >> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
> > > >> driver (i.e. Option B)
> > > >>
> > > >> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
> > > >> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
> > > >> device might attach to the DSI host and call exynos_dsi_host_attach. In
> > > >> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
> > > >> attaches this bridge to the encoder _after_ drm_dev_register has been called.
> > > >> This is invalid behavior, right?
> > > > Definitely not supported, I don't think we have the right locks in place
> > > > to make sure this works.
> > > >
> > > > Now if your _only_ adding a drm_bridge (and not an encoder or anything
> > > > like that), and you are adding the drm_connector correctly (like a
> > > > hotplugged DP MST sink), then that would at least work from a uapi pov.
> > > > Because drm_bridge isn't exposed as an uapi object.
> > > >
> > > > But yeah, as-is, don't :-)
> > > >
> > > > The solution here is a bunch of EPROBE_DEFER handling until all your
> > > > bridges are loaded, with or without the assistance of component.c
> > > > framework. Only then call drm_dev_register.
> > >
> > > I have impression we have similar conversation already.
> > >
> > > As you stated drm_bridge and drm_panel are not exposed to userspace so
> > > there shouldn't be problem with them from uapi PoV.
> > >
> > > On the other side drm_panel or drm_bridge are not used until pipeline
> > > enters connected state (at least they were not some time ago :) ). The
> > > issue is that bridge exposes drm_connector, but as you stated (again :)
> > > ) connectors can be hotplugged, so in theory it should work. Practical
> > > tests shows that it also works, but bugs can be still there.
> > >
> > > Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
> > > decided there is no display), and does not handle unbinding/re-binding
> > > drivers.
> >
> > Rebinding drivers should be fixed now, with a bunch of fixes in driver
> > core. If not, we need to fix this more.
> >
> > Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
> > we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
> > seem to go anywhere), not paper over it with bad architecture in
> > drivers.
>
> I've heard this argument multiple times, but it sounds more like an
> attempt to ignore the problem and hope it will fall on someone else's
> plate :-) Improvement in the probe deferral mechanism are certainly an
> option to explore, but as far as I can tell nobody has proven that this
> mechanism is or will be able to solve all problems related to probe
> ordering dependencies. I wouldn't rule out the need for different
> solutions for some of the issues.

Then build another one. But adding hotplug for stuff that is there,
and shouldn't be hotplugged, just because it's easier on driver
writers and harder on userspace isn't really a good approach.
-Daniel

> > There's also a bit the issue that most userspace handles panels in a
> > special way, and if they don't find the panel at first, that doesn't
> > work. Stuff like "which is the main screen" on laptops.
> >
> > So yeah please fix this properly.
> >
> > > >>>> This leaves us with:
> > > >>>>
> > > >>>> Option A) Standard drm_bridge behavior, which is currently implemented, but
> > > >>>> incompatible with the currently expected behavior of exynos_drm.
> > > >>>>
> > > >>>> Option B) Creating the drm device without all bridges being attached, which
> > > >>>> would work with the exynos_drm driver, but breaks for the standard drm_bridge
> > > >>>> behavior, especially, if the encoder/connector is created at the beginning of
> > > >>>> the pipeline and passed downwards when the bridges are attached.
> > > >>>>
> > > >>>> Option C) Extracting only low level register accesses into shared code, adding
> > > >>>> a custom interface and implementing the drm_bridge handling in the platform
> > > >>>> specific code.
> > > >>>>
> > > >>>> None of the options really convinces me.
>
> --
> Regards,
>
> Laurent Pinchart



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-04 17:46                               ` Daniel Vetter
@ 2021-02-10  9:10                                 ` Frieder Schrempf
  2021-02-18  8:04                                   ` Michael Tretter
  0 siblings, 1 reply; 57+ messages in thread
From: Frieder Schrempf @ 2021-02-10  9:10 UTC (permalink / raw)
  To: Daniel Vetter, Laurent Pinchart
  Cc: Andrzej Hajda, Michael Tretter, Marek Vasut, aisheng.dong,
	linux-samsung-soc, ch, Neil Armstrong, Shawn Guo,
	Krzysztof Kozlowski, Seung-Woo Kim, dl-linux-imx, abel.vesa,
	Bartlomiej Zolnierkiewicz, dri-devel, Joonyoung Shim,
	sylvester.nawrocki, Marek Szyprowski, aford173, Sascha Hauer

On 04.02.21 18:46, Daniel Vetter wrote:
> On Thu, Feb 4, 2021 at 6:26 PM Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
>>
>> Hi Daniel,
>>
>> On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
>>> On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
>>>> W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
>>>>> On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
>>>>>> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
>>>>>>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
>>>>>>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
>>>>>>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
>>>>>>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
>>>>>>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
>>>>>>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
>>>>>>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
>>>>>>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
>>>>>>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
>>>>>>>>>>>>>>> used
>>>>>>>>>>>>>>> from other drivers.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
>>>>>>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
>>>>>>>>>>>>>>> display pipe until the downstream bridges are available, too.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
>>>>>>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
>>>>>>>>>>>>>> operations
>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>>>>>>> 8<--- cut here ---
>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>>>>>>> 00000084
>>>>>>>>>>>>>> pgd = (ptrval)
>>>>>>>>>>>>>> [00000084] *pgd=00000000
>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>>>>>>> Modules linked in:
>>>>>>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
>>>>>>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
>>>>>>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
>>>>>>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
>>>>>>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
>>>>>>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
>>>>>>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
>>>>>>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
>>>>>>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
>>>>>>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
>>>>>>>>>>>>>> (component_bind_all+0xfc/0x290)
>>>>>>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
>>>>>>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
>>>>>>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
>>>>>>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
>>>>>>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
>>>>>>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
>>>>>>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
>>>>>>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
>>>>>>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
>>>>>>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
>>>>>>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
>>>>>>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
>>>>>>>>>>>>>> (exynos_drm_init+0xe4/0x118)
>>>>>>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
>>>>>>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I will try to debug it a bit more today.
>>>>>>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
>>>>>>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
>>>>>>>>>>>>> another issue:
>>>>>>>>>>>>>
>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>>>>>> 8<--- cut here ---
>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>>>>>> 00000280
>>>>>>>>>>>>> pgd = (ptrval)
>>>>>>>>>>>>> [00000280] *pgd=00000000
>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>>>>>> Modules linked in:
>>>>>>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>>>>>> PC is at __mutex_lock+0x54/0xb18
>>>>>>>>>>>>> LR is at lock_is_held_type+0x80/0x138
>>>>>>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
>>>>>>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
>>>>>>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
>>>>>>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
>>>>>>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
>>>>>>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
>>>>>>>>>>>>> ...
>>>>>>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
>>>>>>>>>>>>> (mutex_lock_nested+0x1c/0x24)
>>>>>>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
>>>>>>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
>>>>>>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
>>>>>>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
>>>>>>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
>>>>>>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
>>>>>>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
>>>>>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
>>>>>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>>>>>> ...
>>>>>>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
>>>>>>>>>>>>>
>>>>>>>>>>>>> This means that dsi->encoder.dev is not initialized in
>>>>>>>>>>>>> __exynos_dsi_host_attach().
>>>>>>>>>>>>>
>>>>>>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
>>>>>>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
>>>>>>>>>>>>> release of all drm resources.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Then however, the panel tries to register itself and
>>>>>>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
>>>>>>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
>>>>>>>>>>>>> failure.
>>>>>>>>>>>>>
>>>>>>>>>>>>> It looks that something is missing. Maybe mipi host has to be
>>>>>>>>>>>>> registered
>>>>>>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
>>>>>>>>>>>>> this patch. Andrzej, could you comment it a bit?
>>>>>>>>>>>> I intentionally changed the order, because if another bridge follows
>>>>>>>>>>>> in the
>>>>>>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
>>>>>>>>>>>> bridge
>>>>>>>>>>>> provides a connector. The next bridge registers itself via the
>>>>>>>>>>>> host_attach
>>>>>>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
>>>>>>>>>>>> API or
>>>>>>>>>>>> the bridge_attach function otherwise.
>>>>>>>>>>>>
>>>>>>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
>>>>>>>>>>>> device
>>>>>>>>>>>> has been attached.
>>>>>>>>>>>>
>>>>>>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
>>>>>>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
>>>>>>>>>>>> via
>>>>>>>>>>>> exynos_dsi instead of the bridge.
>>>>>>>>>>>>
>>>>>>>>>>>> Can you try to move everything except samsung_dsim_bind from
>>>>>>>>>>>> exynos_dsi_bind
>>>>>>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
>>>>>>>>>>>> crash.
>>>>>>>>>>>
>>>>>>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
>>>>>>>>>>> regardless of sink presence (initially panel, later also bridge) - it
>>>>>>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
>>>>>>>>>>> and module load/unload. Appearance or disappearance of sink is
>>>>>>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
>>>>>>>>>>> reflected in drm world as change state of the connector.
>>>>>>>>>>>
>>>>>>>>>>> Registering DSI host in bind and unregistering in unbind assures that
>>>>>>>>>>> if mipi_dsi device is attached/detached the drm device is always
>>>>>>>>>>> present - it makes device/driver binding race free and allows to avoid
>>>>>>>>>>> additional locking.
>>>>>>>>>>>
>>>>>>>>>>> Moving DSI host registration to probe changes everything, for sure it
>>>>>>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
>>>>>>>>>>> can cause different issues depending on device bind order.
>>>>>>>>>>>
>>>>>>>>>>> I will try to look at the patches tomorrow and maybe I can find more
>>>>>>>>>>> constructive comments :)
>>>>>>>>>>
>>>>>>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
>>>>>>>>>> callbacks to control appearance/disappearance of downstream device. It
>>>>>>>>>> allows to:
>>>>>>>>>>
>>>>>>>>>> 1. Safely bind/unbind different device drivers at any time and at any
>>>>>>>>>> order, without killing exynos_drm and/or crashing system.
>>>>>>>>>>
>>>>>>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
>>>>>>>>>> appeared too late, due to deferred probe, and resulted in black screen
>>>>>>>>>> in userspace.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
>>>>>>>>>>
>>>>>>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
>>>>>>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
>>>>>>>>>> appearance, thus probably black screen on some targets. So for sure it
>>>>>>>>>> will be suboptimal. Making it bridge unbind safe would be another
>>>>>>>>>> problem, but most developers do not care about it so why should we? :)
>>>>>>>>>>
>>>>>>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
>>>>>>>>>> even if downstream devices are not yet attached, on attach/detach notify
>>>>>>>>>> drm about it via connector status change, for this dsi_host registration
>>>>>>>>>> should be performed from drm_bridge attach, I guess.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Option A is more standard, but is unsafe and causes other issues.
>>>>>>>>>>
>>>>>>>>>> Option B keeps current behaviour.
>>>>>>>>> Maybe we can have both, but I am not sure, if I am missing something:
>>>>>>>>>
>>>>>>>>> I still prefer option A for the samsung-dsim driver, because it is more
>>>>>>>>> standard, simpler and avoids issues with encoders, connectors or handling
>>>>>>>>> hotplug.
>>>>>>>>>
>>>>>>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
>>>>>>>>> samsung-dsim driver which implements option A and defers probing of the drm
>>>>>>>>> driver until the next bridge is attached. And a second bridge in the
>>>>>>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
>>>>>>>>> device to appear) and implements the hotplug handling for notifying drm via
>>>>>>>>> connector status change.
>>>>>>>>>
>>>>>>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
>>>>>>>>> additional bridge.
>>>>>>>>>
>>>>>>>>> This allows the samsung-dsim driver to expose the standard behavior while the
>>>>>>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
>>>>>>>>>
>>>>>>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
>>>>>>>>> get the probing and mipi host/device registration correct, but I will try, if
>>>>>>>>> this can work.
>>>>>>>> Adding two bridges for being able to support hotplugging adds many special
>>>>>>>> cases to the bridge driver and still requires more custom API to correctly add
>>>>>>>> the second bridge. I don't think that this a viable path to go.
>>>>>>> Just jumping in here: You cannot hotplug/hotremove anything from a
>>>>>>> drm_device after drm_dev_register has been called, except
>>>>>>> drm_connector. I didn't dig into details here so not sure whether you
>>>>>>> want to late-bind your bridge after drm_dev_register is called or not,
>>>>>>> so might just be fyi and not relevant to the discussion.
>>>>>> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
>>>>>> driver (i.e. Option B)
>>>>>>
>>>>>> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
>>>>>> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
>>>>>> device might attach to the DSI host and call exynos_dsi_host_attach. In
>>>>>> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
>>>>>> attaches this bridge to the encoder _after_ drm_dev_register has been called.
>>>>>> This is invalid behavior, right?
>>>>> Definitely not supported, I don't think we have the right locks in place
>>>>> to make sure this works.
>>>>>
>>>>> Now if your _only_ adding a drm_bridge (and not an encoder or anything
>>>>> like that), and you are adding the drm_connector correctly (like a
>>>>> hotplugged DP MST sink), then that would at least work from a uapi pov.
>>>>> Because drm_bridge isn't exposed as an uapi object.
>>>>>
>>>>> But yeah, as-is, don't :-)
>>>>>
>>>>> The solution here is a bunch of EPROBE_DEFER handling until all your
>>>>> bridges are loaded, with or without the assistance of component.c
>>>>> framework. Only then call drm_dev_register.
>>>>
>>>> I have impression we have similar conversation already.
>>>>
>>>> As you stated drm_bridge and drm_panel are not exposed to userspace so
>>>> there shouldn't be problem with them from uapi PoV.
>>>>
>>>> On the other side drm_panel or drm_bridge are not used until pipeline
>>>> enters connected state (at least they were not some time ago :) ). The
>>>> issue is that bridge exposes drm_connector, but as you stated (again :)
>>>> ) connectors can be hotplugged, so in theory it should work. Practical
>>>> tests shows that it also works, but bugs can be still there.
>>>>
>>>> Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
>>>> decided there is no display), and does not handle unbinding/re-binding
>>>> drivers.
>>>
>>> Rebinding drivers should be fixed now, with a bunch of fixes in driver
>>> core. If not, we need to fix this more.
>>>
>>> Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
>>> we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
>>> seem to go anywhere), not paper over it with bad architecture in
>>> drivers.
>>
>> I've heard this argument multiple times, but it sounds more like an
>> attempt to ignore the problem and hope it will fall on someone else's
>> plate :-) Improvement in the probe deferral mechanism are certainly an
>> option to explore, but as far as I can tell nobody has proven that this
>> mechanism is or will be able to solve all problems related to probe
>> ordering dependencies. I wouldn't rule out the need for different
>> solutions for some of the issues.
> 
> Then build another one. But adding hotplug for stuff that is there,
> and shouldn't be hotplugged, just because it's easier on driver
> writers and harder on userspace isn't really a good approach.
> -Daniel

I think it is quite clear that replacing or reworking the deferral 
mechanism is out of scope for this discussion, which is why I would like 
to come back to the original issue and sum this up as far as I 
understand it (which is not really far when it comes to the details):

We have the existing exynos driver that avoids the standard deferral 
mechanism in favor of something that works but Daniel describes as 
"definitely not supported".

We have a proposal from Michael for converting the driver to the 
standard drm_bridge behavior and more work from Michael and Marek based 
on this to implement the platform specific parts for i.MX8MM.

 From the i.MX8MM POV this approach already received some testing and 
looks good as far as I can judge. Upstreaming this solution is blocked 
because of objections from the Samsung maintainers.

Sorry if I'm being blunt or naive, but where to go from here?

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-10  9:10                                 ` Frieder Schrempf
@ 2021-02-18  8:04                                   ` Michael Tretter
  2021-02-18 16:02                                     ` Andrzej Hajda
  0 siblings, 1 reply; 57+ messages in thread
From: Michael Tretter @ 2021-02-18  8:04 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Daniel Vetter, Laurent Pinchart, Andrzej Hajda, Marek Vasut,
	aisheng.dong, linux-samsung-soc, ch, Neil Armstrong, Shawn Guo,
	Krzysztof Kozlowski, Seung-Woo Kim, dl-linux-imx, abel.vesa,
	Bartlomiej Zolnierkiewicz, dri-devel, Joonyoung Shim,
	sylvester.nawrocki, Marek Szyprowski, aford173, Sascha Hauer,
	inki.dae, kyungmin.park

On Wed, 10 Feb 2021 10:10:37 +0100, Frieder Schrempf wrote:
> On 04.02.21 18:46, Daniel Vetter wrote:
> > On Thu, Feb 4, 2021 at 6:26 PM Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> > > On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
> > > > On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
> > > > > W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
> > > > > > On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
> > > > > > > On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> > > > > > > > On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
> > > > > > > > > On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> > > > > > > > > > On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> > > > > > > > > > > W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> > > > > > > > > > > > On 14.09.2020 22:01, Michael Tretter wrote:
> > > > > > > > > > > > > On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> > > > > > > > > > > > > > On 14.09.2020 10:29, Marek Szyprowski wrote:
> > > > > > > > > > > > > > > On 11.09.2020 15:54, Michael Tretter wrote:
> > > > > > > > > > > > > > > > Make the exynos_dsi driver a full drm bridge that can be found and
> > > > > > > > > > > > > > > > used
> > > > > > > > > > > > > > > > from other drivers.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Other drivers can only attach to the bridge, if a mipi dsi device
> > > > > > > > > > > > > > > > already attached to the bridge. This allows to defer the probe of the
> > > > > > > > > > > > > > > > display pipe until the downstream bridges are available, too.
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> > > > > > > > > > > > > > > This one (and the whole series applied) still fails on Exynos boards:
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> > > > > > > > > > > > > > > operations
> > > > > > > > > > > > > > > exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > > > > > > > > > > > > > OF: graph: no port node found in /soc/dsi@11c80000
> > > > > > > > > > > > > > > 8<--- cut here ---
> > > > > > > > > > > > > > > Unable to handle kernel NULL pointer dereference at virtual address
> > > > > > > > > > > > > > > 00000084
> > > > > > > > > > > > > > > pgd = (ptrval)
> > > > > > > > > > > > > > > [00000084] *pgd=00000000
> > > > > > > > > > > > > > > Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > > > > > > > > > > > > > Modules linked in:
> > > > > > > > > > > > > > > CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> > > > > > > > > > > > > > > 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> > > > > > > > > > > > > > > Hardware name: Samsung Exynos (Flattened Device Tree)
> > > > > > > > > > > > > > > PC is at drm_bridge_attach+0x18/0x164
> > > > > > > > > > > > > > > LR is at exynos_dsi_bind+0x88/0xa8
> > > > > > > > > > > > > > > pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> > > > > > > > > > > > > > > sp : ef0dfca8  ip : 00000002  fp : c13190e0
> > > > > > > > > > > > > > > r10: 00000000  r9 : ee46d580  r8 : c13190e0
> > > > > > > > > > > > > > > r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> > > > > > > > > > > > > > > r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> > > > > > > > > > > > > > > Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > > > > > > > > > > > > > Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > > > > > > > > > > > > > Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > > > > > > > > > > > > > Stack: (0xef0dfca8 to 0xef0e0000)
> > > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > > [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> > > > > > > > > > > > > > > (exynos_dsi_bind+0x88/0xa8)
> > > > > > > > > > > > > > > [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> > > > > > > > > > > > > > > (component_bind_all+0xfc/0x290)
> > > > > > > > > > > > > > > [<c066a800>] (component_bind_all) from [<c0649dc0>]
> > > > > > > > > > > > > > > (exynos_drm_bind+0xe4/0x19c)
> > > > > > > > > > > > > > > [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> > > > > > > > > > > > > > > (try_to_bring_up_master+0x1e4/0x2c4)
> > > > > > > > > > > > > > > [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> > > > > > > > > > > > > > > (component_master_add_with_match+0xd4/0x108)
> > > > > > > > > > > > > > > [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> > > > > > > > > > > > > > > (exynos_drm_platform_probe+0xe4/0x110)
> > > > > > > > > > > > > > > [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> > > > > > > > > > > > > > > (platform_drv_probe+0x6c/0xa4)
> > > > > > > > > > > > > > > [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> > > > > > > > > > > > > > > (really_probe+0x200/0x4fc)
> > > > > > > > > > > > > > > [<c067242c>] (really_probe) from [<c06728f0>]
> > > > > > > > > > > > > > > (driver_probe_device+0x78/0x1fc)
> > > > > > > > > > > > > > > [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> > > > > > > > > > > > > > > (device_driver_attach+0x58/0x60)
> > > > > > > > > > > > > > > [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> > > > > > > > > > > > > > > (__driver_attach+0xdc/0x174)
> > > > > > > > > > > > > > > [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> > > > > > > > > > > > > > > (bus_for_each_dev+0x68/0xb4)
> > > > > > > > > > > > > > > [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> > > > > > > > > > > > > > > (bus_add_driver+0x158/0x214)
> > > > > > > > > > > > > > > [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> > > > > > > > > > > > > > > (driver_register+0x78/0x110)
> > > > > > > > > > > > > > > [<c0673c1c>] (driver_register) from [<c0649ca8>]
> > > > > > > > > > > > > > > (exynos_drm_init+0xe4/0x118)
> > > > > > > > > > > > > > > [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> > > > > > > > > > > > > > > (do_one_initcall+0x8c/0x42c)
> > > > > > > > > > > > > > > [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > > > > > > > > > > > > > (kernel_init_freeable+0x190/0x1dc)
> > > > > > > > > > > > > > > [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> > > > > > > > > > > > > > > (kernel_init+0x8/0x118)
> > > > > > > > > > > > > > > [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > > > > > > > > > > > > > Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > > ---[ end trace ee27f313f9ed9da1 ]---
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> > > > > > > > > > > > > > > drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > I will try to debug it a bit more today.
> > > > > > > > > > > > > > The above crash has been caused by lack of in_bridge initialization to
> > > > > > > > > > > > > > NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> > > > > > > > > > > > > > another issue:
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> > > > > > > > > > > > > > exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> > > > > > > > > > > > > > OF: graph: no port node found in /soc/dsi@11c80000
> > > > > > > > > > > > > > 8<--- cut here ---
> > > > > > > > > > > > > > Unable to handle kernel NULL pointer dereference at virtual address
> > > > > > > > > > > > > > 00000280
> > > > > > > > > > > > > > pgd = (ptrval)
> > > > > > > > > > > > > > [00000280] *pgd=00000000
> > > > > > > > > > > > > > Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> > > > > > > > > > > > > > Modules linked in:
> > > > > > > > > > > > > > CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> > > > > > > > > > > > > > 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> > > > > > > > > > > > > > Hardware name: Samsung Exynos (Flattened Device Tree)
> > > > > > > > > > > > > > PC is at __mutex_lock+0x54/0xb18
> > > > > > > > > > > > > > LR is at lock_is_held_type+0x80/0x138
> > > > > > > > > > > > > > pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> > > > > > > > > > > > > > sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> > > > > > > > > > > > > > r10: c1208eec  r9 : 00000000  r8 : ee45f808
> > > > > > > > > > > > > > r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> > > > > > > > > > > > > > r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> > > > > > > > > > > > > > Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> > > > > > > > > > > > > > Control: 10c5387d  Table: 4000404a  DAC: 00000051
> > > > > > > > > > > > > > Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> > > > > > > > > > > > > > Stack: (0xef0dfd30 to 0xef0e0000)
> > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> > > > > > > > > > > > > > (mutex_lock_nested+0x1c/0x24)
> > > > > > > > > > > > > > [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> > > > > > > > > > > > > > (__exynos_dsi_host_attach+0x20/0x6c)
> > > > > > > > > > > > > > [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> > > > > > > > > > > > > > (exynos_dsi_host_attach+0x70/0x194)
> > > > > > > > > > > > > > [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> > > > > > > > > > > > > > (s6e8aa0_probe+0x1b0/0x218)
> > > > > > > > > > > > > > [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> > > > > > > > > > > > > > (really_probe+0x200/0x4fc)
> > > > > > > > > > > > > > [<c0672530>] (really_probe) from [<c06729f4>]
> > > > > > > > > > > > > > (driver_probe_device+0x78/0x1fc)
> > > > > > > > > > > > > > [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> > > > > > > > > > > > > > (device_driver_attach+0x58/0x60)
> > > > > > > > > > > > > > [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> > > > > > > > > > > > > > (__driver_attach+0xdc/0x174)
> > > > > > > > > > > > > > [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> > > > > > > > > > > > > > (bus_for_each_dev+0x68/0xb4)
> > > > > > > > > > > > > > [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> > > > > > > > > > > > > > (bus_add_driver+0x158/0x214)
> > > > > > > > > > > > > > [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> > > > > > > > > > > > > > (driver_register+0x78/0x110)
> > > > > > > > > > > > > > [<c0673d20>] (driver_register) from [<c0102484>]
> > > > > > > > > > > > > > (do_one_initcall+0x8c/0x42c)
> > > > > > > > > > > > > > [<c0102484>] (do_one_initcall) from [<c11011c0>]
> > > > > > > > > > > > > > (kernel_init_freeable+0x190/0x1dc)
> > > > > > > > > > > > > > [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> > > > > > > > > > > > > > (kernel_init+0x8/0x118)
> > > > > > > > > > > > > > [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> > > > > > > > > > > > > > Exception stack(0xef0dffb0 to 0xef0dfff8)
> > > > > > > > > > > > > > ...
> > > > > > > > > > > > > > ---[ end trace c06e996ec2e8234d ]---
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > This means that dsi->encoder.dev is not initialized in
> > > > > > > > > > > > > > __exynos_dsi_host_attach().
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> > > > > > > > > > > > > > earlier -517 (deferred probe), what causes cleanup of encoder and
> > > > > > > > > > > > > > release of all drm resources.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > Then however, the panel tries to register itself and
> > > > > > > > > > > > > > exynos_dsi_host_attach() tries to access the released encoder (which is
> > > > > > > > > > > > > > zeroed in drm_encoder_release) and rest of resources, what causes
> > > > > > > > > > > > > > failure.
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > It looks that something is missing. Maybe mipi host has to be
> > > > > > > > > > > > > > registered
> > > > > > > > > > > > > > later, when bridge is ready? I have no idea how it is handled before
> > > > > > > > > > > > > > this patch. Andrzej, could you comment it a bit?
> > > > > > > > > > > > > I intentionally changed the order, because if another bridge follows
> > > > > > > > > > > > > in the
> > > > > > > > > > > > > pipeline, the probe of the drm driver has to be deferred until some
> > > > > > > > > > > > > bridge
> > > > > > > > > > > > > provides a connector. The next bridge registers itself via the
> > > > > > > > > > > > > host_attach
> > > > > > > > > > > > > function and the deferral is ensured via the bind for the bind/unbind
> > > > > > > > > > > > > API or
> > > > > > > > > > > > > the bridge_attach function otherwise.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > On the other hand, the bridge does not have an encoder until the mipi
> > > > > > > > > > > > > device
> > > > > > > > > > > > > has been attached.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > As a solution, the exynos dsi driver must initialize the encoder in
> > > > > > > > > > > > > exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> > > > > > > > > > > > > via
> > > > > > > > > > > > > exynos_dsi instead of the bridge.
> > > > > > > > > > > > > 
> > > > > > > > > > > > > Can you try to move everything except samsung_dsim_bind from
> > > > > > > > > > > > > exynos_dsi_bind
> > > > > > > > > > > > > to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> > > > > > > > > > > > > crash.
> > > > > > > > > > > > 
> > > > > > > > > > > > The original behaviour is that encoder (exynos_dsi) is registered
> > > > > > > > > > > > regardless of sink presence (initially panel, later also bridge) - it
> > > > > > > > > > > > avoids multiple issues with deferred probe, device driver bind/unbind
> > > > > > > > > > > > and module load/unload. Appearance or disappearance of sink is
> > > > > > > > > > > > reported to host nicely via DSI attach/detach callbacks - and it is
> > > > > > > > > > > > reflected in drm world as change state of the connector.
> > > > > > > > > > > > 
> > > > > > > > > > > > Registering DSI host in bind and unregistering in unbind assures that
> > > > > > > > > > > > if mipi_dsi device is attached/detached the drm device is always
> > > > > > > > > > > > present - it makes device/driver binding race free and allows to avoid
> > > > > > > > > > > > additional locking.
> > > > > > > > > > > > 
> > > > > > > > > > > > Moving DSI host registration to probe changes everything, for sure it
> > > > > > > > > > > > breaks the nice feature of DSI attach/detach callbacks and apparently
> > > > > > > > > > > > can cause different issues depending on device bind order.
> > > > > > > > > > > > 
> > > > > > > > > > > > I will try to look at the patches tomorrow and maybe I can find more
> > > > > > > > > > > > constructive comments :)
> > > > > > > > > > > 
> > > > > > > > > > > As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> > > > > > > > > > > callbacks to control appearance/disappearance of downstream device. It
> > > > > > > > > > > allows to:
> > > > > > > > > > > 
> > > > > > > > > > > 1. Safely bind/unbind different device drivers at any time and at any
> > > > > > > > > > > order, without killing exynos_drm and/or crashing system.
> > > > > > > > > > > 
> > > > > > > > > > > 2. Avoid issues with late drm init - on some platforms exynos_drm device
> > > > > > > > > > > appeared too late, due to deferred probe, and resulted in black screen
> > > > > > > > > > > in userspace.
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > Now if we want to convert exynos_dsi to drm_bridge I see following options:
> > > > > > > > > > > 
> > > > > > > > > > > A. Forgot about callbacks and make the exynos_drm to defer probing until
> > > > > > > > > > > exynos_dsi bridge is available, probably it will cause later exynos_drm
> > > > > > > > > > > appearance, thus probably black screen on some targets. So for sure it
> > > > > > > > > > > will be suboptimal. Making it bridge unbind safe would be another
> > > > > > > > > > > problem, but most developers do not care about it so why should we? :)
> > > > > > > > > > > 
> > > > > > > > > > > B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> > > > > > > > > > > even if downstream devices are not yet attached, on attach/detach notify
> > > > > > > > > > > drm about it via connector status change, for this dsi_host registration
> > > > > > > > > > > should be performed from drm_bridge attach, I guess.
> > > > > > > > > > > 
> > > > > > > > > > > 
> > > > > > > > > > > Option A is more standard, but is unsafe and causes other issues.
> > > > > > > > > > > 
> > > > > > > > > > > Option B keeps current behaviour.
> > > > > > > > > > Maybe we can have both, but I am not sure, if I am missing something:
> > > > > > > > > > 
> > > > > > > > > > I still prefer option A for the samsung-dsim driver, because it is more
> > > > > > > > > > standard, simpler and avoids issues with encoders, connectors or handling
> > > > > > > > > > hotplug.
> > > > > > > > > > 
> > > > > > > > > > The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> > > > > > > > > > samsung-dsim driver which implements option A and defers probing of the drm
> > > > > > > > > > driver until the next bridge is attached. And a second bridge in the
> > > > > > > > > > exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> > > > > > > > > > device to appear) and implements the hotplug handling for notifying drm via
> > > > > > > > > > connector status change.
> > > > > > > > > > 
> > > > > > > > > > The driver for the i.MX8M would use the samsung-dsim bridge without an
> > > > > > > > > > additional bridge.
> > > > > > > > > > 
> > > > > > > > > > This allows the samsung-dsim driver to expose the standard behavior while the
> > > > > > > > > > exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> > > > > > > > > > 
> > > > > > > > > > I hope this makes sense and does not sound too crazy. It might be difficult to
> > > > > > > > > > get the probing and mipi host/device registration correct, but I will try, if
> > > > > > > > > > this can work.
> > > > > > > > > Adding two bridges for being able to support hotplugging adds many special
> > > > > > > > > cases to the bridge driver and still requires more custom API to correctly add
> > > > > > > > > the second bridge. I don't think that this a viable path to go.
> > > > > > > > Just jumping in here: You cannot hotplug/hotremove anything from a
> > > > > > > > drm_device after drm_dev_register has been called, except
> > > > > > > > drm_connector. I didn't dig into details here so not sure whether you
> > > > > > > > want to late-bind your bridge after drm_dev_register is called or not,
> > > > > > > > so might just be fyi and not relevant to the discussion.
> > > > > > > Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
> > > > > > > driver (i.e. Option B)
> > > > > > > 
> > > > > > > exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
> > > > > > > exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
> > > > > > > device might attach to the DSI host and call exynos_dsi_host_attach. In
> > > > > > > exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
> > > > > > > attaches this bridge to the encoder _after_ drm_dev_register has been called.
> > > > > > > This is invalid behavior, right?
> > > > > > Definitely not supported, I don't think we have the right locks in place
> > > > > > to make sure this works.
> > > > > > 
> > > > > > Now if your _only_ adding a drm_bridge (and not an encoder or anything
> > > > > > like that), and you are adding the drm_connector correctly (like a
> > > > > > hotplugged DP MST sink), then that would at least work from a uapi pov.
> > > > > > Because drm_bridge isn't exposed as an uapi object.
> > > > > > 
> > > > > > But yeah, as-is, don't :-)
> > > > > > 
> > > > > > The solution here is a bunch of EPROBE_DEFER handling until all your
> > > > > > bridges are loaded, with or without the assistance of component.c
> > > > > > framework. Only then call drm_dev_register.
> > > > > 
> > > > > I have impression we have similar conversation already.
> > > > > 
> > > > > As you stated drm_bridge and drm_panel are not exposed to userspace so
> > > > > there shouldn't be problem with them from uapi PoV.
> > > > > 
> > > > > On the other side drm_panel or drm_bridge are not used until pipeline
> > > > > enters connected state (at least they were not some time ago :) ). The
> > > > > issue is that bridge exposes drm_connector, but as you stated (again :)
> > > > > ) connectors can be hotplugged, so in theory it should work. Practical
> > > > > tests shows that it also works, but bugs can be still there.
> > > > > 
> > > > > Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
> > > > > decided there is no display), and does not handle unbinding/re-binding
> > > > > drivers.
> > > > 
> > > > Rebinding drivers should be fixed now, with a bunch of fixes in driver
> > > > core. If not, we need to fix this more.
> > > > 
> > > > Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
> > > > we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
> > > > seem to go anywhere), not paper over it with bad architecture in
> > > > drivers.
> > > 
> > > I've heard this argument multiple times, but it sounds more like an
> > > attempt to ignore the problem and hope it will fall on someone else's
> > > plate :-) Improvement in the probe deferral mechanism are certainly an
> > > option to explore, but as far as I can tell nobody has proven that this
> > > mechanism is or will be able to solve all problems related to probe
> > > ordering dependencies. I wouldn't rule out the need for different
> > > solutions for some of the issues.
> > 
> > Then build another one. But adding hotplug for stuff that is there,
> > and shouldn't be hotplugged, just because it's easier on driver
> > writers and harder on userspace isn't really a good approach.
> > -Daniel
> 
> I think it is quite clear that replacing or reworking the deferral mechanism
> is out of scope for this discussion, which is why I would like to come back
> to the original issue and sum this up as far as I understand it (which is
> not really far when it comes to the details):
> 
> We have the existing exynos driver that avoids the standard deferral
> mechanism in favor of something that works but Daniel describes as
> "definitely not supported".
> 
> We have a proposal from Michael for converting the driver to the standard
> drm_bridge behavior and more work from Michael and Marek based on this to
> implement the platform specific parts for i.MX8MM.
> 
> From the i.MX8MM POV this approach already received some testing and looks
> good as far as I can judge. Upstreaming this solution is blocked because of
> objections from the Samsung maintainers.
> 
> Sorry if I'm being blunt or naive, but where to go from here?
> 

Maybe some more information by the Samsung maintainers would help:

If I understand correctly, the main reason for the non-standard behavior is a
userspace application that runs into a timeout if the drm-device does not
appear in time. Correct? Is there something we can do about that?

The other reason is the convenience of binding and unbinding a bridge driver,
while the drm device is kept available. Correct? Is this used in development,
testing, or production?

Is there anything else that prevents the exynos drm from switching to the
standard behavior?

Would a exynos drm specific wrapper, which uses a standard bridge driver but
exposes the non-standard behavior, be acceptable? (Unfortunately, my first try
on something like that felt really awkward and didn't really work.)

Michael

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-18  8:04                                   ` Michael Tretter
@ 2021-02-18 16:02                                     ` Andrzej Hajda
  2021-02-23 12:07                                       ` Daniel Vetter
  0 siblings, 1 reply; 57+ messages in thread
From: Andrzej Hajda @ 2021-02-18 16:02 UTC (permalink / raw)
  To: Michael Tretter, Frieder Schrempf
  Cc: ch, Neil Armstrong, dri-devel, Laurent Pinchart,
	Marek Szyprowski, Marek Vasut, linux-samsung-soc, abel.vesa,
	Krzysztof Kozlowski, dl-linux-imx, Sascha Hauer,
	Bartlomiej Zolnierkiewicz, sylvester.nawrocki, aford173,
	Joonyoung Shim, aisheng.dong, Seung-Woo Kim, kyungmin.park,
	Shawn Guo

Hi Michael,

W dniu 18.02.2021 o 09:04, Michael Tretter pisze:
> On Wed, 10 Feb 2021 10:10:37 +0100, Frieder Schrempf wrote:
>> On 04.02.21 18:46, Daniel Vetter wrote:
>>> On Thu, Feb 4, 2021 at 6:26 PM Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
>>>> On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
>>>>> On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
>>>>>> W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
>>>>>>> On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
>>>>>>>> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
>>>>>>>>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
>>>>>>>>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
>>>>>>>>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
>>>>>>>>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
>>>>>>>>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
>>>>>>>>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
>>>>>>>>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
>>>>>>>>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
>>>>>>>>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
>>>>>>>>>>>>>>>>> used
>>>>>>>>>>>>>>>>> from other drivers.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
>>>>>>>>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
>>>>>>>>>>>>>>>>> display pipe until the downstream bridges are available, too.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
>>>>>>>>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
>>>>>>>>>>>>>>>> operations
>>>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>>>>>>>>> 8<--- cut here ---
>>>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>>>>>>>>> 00000084
>>>>>>>>>>>>>>>> pgd = (ptrval)
>>>>>>>>>>>>>>>> [00000084] *pgd=00000000
>>>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>>>>>>>>> Modules linked in:
>>>>>>>>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
>>>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
>>>>>>>>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
>>>>>>>>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
>>>>>>>>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
>>>>>>>>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
>>>>>>>>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
>>>>>>>>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
>>>>>>>>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
>>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
>>>>>>>>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
>>>>>>>>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
>>>>>>>>>>>>>>>> (component_bind_all+0xfc/0x290)
>>>>>>>>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
>>>>>>>>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
>>>>>>>>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
>>>>>>>>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
>>>>>>>>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
>>>>>>>>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
>>>>>>>>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
>>>>>>>>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
>>>>>>>>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
>>>>>>>>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
>>>>>>>>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
>>>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
>>>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
>>>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
>>>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
>>>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
>>>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
>>>>>>>>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
>>>>>>>>>>>>>>>> (exynos_drm_init+0xe4/0x118)
>>>>>>>>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
>>>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
>>>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
>>>>>>>>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> I will try to debug it a bit more today.
>>>>>>>>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
>>>>>>>>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
>>>>>>>>>>>>>>> another issue:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
>>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>>>>>>>> 8<--- cut here ---
>>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>>>>>>>> 00000280
>>>>>>>>>>>>>>> pgd = (ptrval)
>>>>>>>>>>>>>>> [00000280] *pgd=00000000
>>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>>>>>>>> Modules linked in:
>>>>>>>>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
>>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>>>>>>>> PC is at __mutex_lock+0x54/0xb18
>>>>>>>>>>>>>>> LR is at lock_is_held_type+0x80/0x138
>>>>>>>>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
>>>>>>>>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
>>>>>>>>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
>>>>>>>>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
>>>>>>>>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
>>>>>>>>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
>>>>>>>>>>>>>>> (mutex_lock_nested+0x1c/0x24)
>>>>>>>>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
>>>>>>>>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
>>>>>>>>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
>>>>>>>>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
>>>>>>>>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
>>>>>>>>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
>>>>>>>>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
>>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
>>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
>>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
>>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
>>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
>>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
>>>>>>>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
>>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
>>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> This means that dsi->encoder.dev is not initialized in
>>>>>>>>>>>>>>> __exynos_dsi_host_attach().
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
>>>>>>>>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
>>>>>>>>>>>>>>> release of all drm resources.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Then however, the panel tries to register itself and
>>>>>>>>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
>>>>>>>>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
>>>>>>>>>>>>>>> failure.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> It looks that something is missing. Maybe mipi host has to be
>>>>>>>>>>>>>>> registered
>>>>>>>>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
>>>>>>>>>>>>>>> this patch. Andrzej, could you comment it a bit?
>>>>>>>>>>>>>> I intentionally changed the order, because if another bridge follows
>>>>>>>>>>>>>> in the
>>>>>>>>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
>>>>>>>>>>>>>> bridge
>>>>>>>>>>>>>> provides a connector. The next bridge registers itself via the
>>>>>>>>>>>>>> host_attach
>>>>>>>>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
>>>>>>>>>>>>>> API or
>>>>>>>>>>>>>> the bridge_attach function otherwise.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
>>>>>>>>>>>>>> device
>>>>>>>>>>>>>> has been attached.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
>>>>>>>>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
>>>>>>>>>>>>>> via
>>>>>>>>>>>>>> exynos_dsi instead of the bridge.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Can you try to move everything except samsung_dsim_bind from
>>>>>>>>>>>>>> exynos_dsi_bind
>>>>>>>>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
>>>>>>>>>>>>>> crash.
>>>>>>>>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
>>>>>>>>>>>>> regardless of sink presence (initially panel, later also bridge) - it
>>>>>>>>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
>>>>>>>>>>>>> and module load/unload. Appearance or disappearance of sink is
>>>>>>>>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
>>>>>>>>>>>>> reflected in drm world as change state of the connector.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Registering DSI host in bind and unregistering in unbind assures that
>>>>>>>>>>>>> if mipi_dsi device is attached/detached the drm device is always
>>>>>>>>>>>>> present - it makes device/driver binding race free and allows to avoid
>>>>>>>>>>>>> additional locking.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Moving DSI host registration to probe changes everything, for sure it
>>>>>>>>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
>>>>>>>>>>>>> can cause different issues depending on device bind order.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I will try to look at the patches tomorrow and maybe I can find more
>>>>>>>>>>>>> constructive comments :)
>>>>>>>>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
>>>>>>>>>>>> callbacks to control appearance/disappearance of downstream device. It
>>>>>>>>>>>> allows to:
>>>>>>>>>>>>
>>>>>>>>>>>> 1. Safely bind/unbind different device drivers at any time and at any
>>>>>>>>>>>> order, without killing exynos_drm and/or crashing system.
>>>>>>>>>>>>
>>>>>>>>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
>>>>>>>>>>>> appeared too late, due to deferred probe, and resulted in black screen
>>>>>>>>>>>> in userspace.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
>>>>>>>>>>>>
>>>>>>>>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
>>>>>>>>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
>>>>>>>>>>>> appearance, thus probably black screen on some targets. So for sure it
>>>>>>>>>>>> will be suboptimal. Making it bridge unbind safe would be another
>>>>>>>>>>>> problem, but most developers do not care about it so why should we? :)
>>>>>>>>>>>>
>>>>>>>>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
>>>>>>>>>>>> even if downstream devices are not yet attached, on attach/detach notify
>>>>>>>>>>>> drm about it via connector status change, for this dsi_host registration
>>>>>>>>>>>> should be performed from drm_bridge attach, I guess.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Option A is more standard, but is unsafe and causes other issues.
>>>>>>>>>>>>
>>>>>>>>>>>> Option B keeps current behaviour.
>>>>>>>>>>> Maybe we can have both, but I am not sure, if I am missing something:
>>>>>>>>>>>
>>>>>>>>>>> I still prefer option A for the samsung-dsim driver, because it is more
>>>>>>>>>>> standard, simpler and avoids issues with encoders, connectors or handling
>>>>>>>>>>> hotplug.
>>>>>>>>>>>
>>>>>>>>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
>>>>>>>>>>> samsung-dsim driver which implements option A and defers probing of the drm
>>>>>>>>>>> driver until the next bridge is attached. And a second bridge in the
>>>>>>>>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
>>>>>>>>>>> device to appear) and implements the hotplug handling for notifying drm via
>>>>>>>>>>> connector status change.
>>>>>>>>>>>
>>>>>>>>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
>>>>>>>>>>> additional bridge.
>>>>>>>>>>>
>>>>>>>>>>> This allows the samsung-dsim driver to expose the standard behavior while the
>>>>>>>>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
>>>>>>>>>>>
>>>>>>>>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
>>>>>>>>>>> get the probing and mipi host/device registration correct, but I will try, if
>>>>>>>>>>> this can work.
>>>>>>>>>> Adding two bridges for being able to support hotplugging adds many special
>>>>>>>>>> cases to the bridge driver and still requires more custom API to correctly add
>>>>>>>>>> the second bridge. I don't think that this a viable path to go.
>>>>>>>>> Just jumping in here: You cannot hotplug/hotremove anything from a
>>>>>>>>> drm_device after drm_dev_register has been called, except
>>>>>>>>> drm_connector. I didn't dig into details here so not sure whether you
>>>>>>>>> want to late-bind your bridge after drm_dev_register is called or not,
>>>>>>>>> so might just be fyi and not relevant to the discussion.
>>>>>>>> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
>>>>>>>> driver (i.e. Option B)
>>>>>>>>
>>>>>>>> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
>>>>>>>> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
>>>>>>>> device might attach to the DSI host and call exynos_dsi_host_attach. In
>>>>>>>> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
>>>>>>>> attaches this bridge to the encoder _after_ drm_dev_register has been called.
>>>>>>>> This is invalid behavior, right?
>>>>>>> Definitely not supported, I don't think we have the right locks in place
>>>>>>> to make sure this works.
>>>>>>>
>>>>>>> Now if your _only_ adding a drm_bridge (and not an encoder or anything
>>>>>>> like that), and you are adding the drm_connector correctly (like a
>>>>>>> hotplugged DP MST sink), then that would at least work from a uapi pov.
>>>>>>> Because drm_bridge isn't exposed as an uapi object.
>>>>>>>
>>>>>>> But yeah, as-is, don't :-)
>>>>>>>
>>>>>>> The solution here is a bunch of EPROBE_DEFER handling until all your
>>>>>>> bridges are loaded, with or without the assistance of component.c
>>>>>>> framework. Only then call drm_dev_register.
>>>>>> I have impression we have similar conversation already.
>>>>>>
>>>>>> As you stated drm_bridge and drm_panel are not exposed to userspace so
>>>>>> there shouldn't be problem with them from uapi PoV.
>>>>>>
>>>>>> On the other side drm_panel or drm_bridge are not used until pipeline
>>>>>> enters connected state (at least they were not some time ago :) ). The
>>>>>> issue is that bridge exposes drm_connector, but as you stated (again :)
>>>>>> ) connectors can be hotplugged, so in theory it should work. Practical
>>>>>> tests shows that it also works, but bugs can be still there.
>>>>>>
>>>>>> Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
>>>>>> decided there is no display), and does not handle unbinding/re-binding
>>>>>> drivers.
>>>>> Rebinding drivers should be fixed now, with a bunch of fixes in driver
>>>>> core. If not, we need to fix this more.
>>>>>
>>>>> Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
>>>>> we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
>>>>> seem to go anywhere), not paper over it with bad architecture in
>>>>> drivers.
>>>> I've heard this argument multiple times, but it sounds more like an
>>>> attempt to ignore the problem and hope it will fall on someone else's
>>>> plate :-) Improvement in the probe deferral mechanism are certainly an
>>>> option to explore, but as far as I can tell nobody has proven that this
>>>> mechanism is or will be able to solve all problems related to probe
>>>> ordering dependencies. I wouldn't rule out the need for different
>>>> solutions for some of the issues.
>>> Then build another one. But adding hotplug for stuff that is there,
>>> and shouldn't be hotplugged, just because it's easier on driver
>>> writers and harder on userspace isn't really a good approach.
>>> -Daniel
>> I think it is quite clear that replacing or reworking the deferral mechanism
>> is out of scope for this discussion, which is why I would like to come back
>> to the original issue and sum this up as far as I understand it (which is
>> not really far when it comes to the details):
>>
>> We have the existing exynos driver that avoids the standard deferral
>> mechanism in favor of something that works but Daniel describes as
>> "definitely not supported".
>>
>> We have a proposal from Michael for converting the driver to the standard
>> drm_bridge behavior and more work from Michael and Marek based on this to
>> implement the platform specific parts for i.MX8MM.
>>
>>  From the i.MX8MM POV this approach already received some testing and looks
>> good as far as I can judge. Upstreaming this solution is blocked because of
>> objections from the Samsung maintainers.
>>
>> Sorry if I'm being blunt or naive, but where to go from here?
>>
> Maybe some more information by the Samsung maintainers would help:
>
> If I understand correctly, the main reason for the non-standard behavior is a
> userspace application that runs into a timeout if the drm-device does not
> appear in time. Correct? Is there something we can do about that?
>
> The other reason is the convenience of binding and unbinding a bridge driver,
> while the drm device is kept available. Correct? Is this used in development,
> testing, or production?
>
> Is there anything else that prevents the exynos drm from switching to the
> standard behavior?
>
> Would a exynos drm specific wrapper, which uses a standard bridge driver but
> exposes the non-standard behavior, be acceptable? (Unfortunately, my first try
> on something like that felt really awkward and didn't really work.)

Even if we drop this 'non-standard' behaviour, your task will be still 
quite difficult to fulfil - you are trying to completely rewrite core 
component of Exynos display pipeline without hardware to test.

ExynosDSI is used in almost all Exynos platforms supported mainline (ls 
-1 arch/arm*/boot/dts/exynos*.dts | wc shows 35). It has different hw 
versions (4 compatibles) and is used in different configurations (video 
mode, command mode, with hw/sw trigger, connected to panels/bridges) and 
for sure with big heritage, since it was one of the 1st DSI drivers.

Rewriting such driver is challenging, even with access to hw.

So maybe it would be better to move common parts in your and exynos 
driver to 'shared library' and use it in both drivers - this way you 
have bigger chances to avoid traps.


Regards

Andrzej


>
> Michael
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://protect2.fireeye.com/v1/url?k=08365e03-57ad66fe-0837d54c-000babff317b-bdb6592fde86cf24&q=1&e=db1ed315-991b-408c-827a-4b6cbf2b4e3e&u=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Fdri-devel
>

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-18 16:02                                     ` Andrzej Hajda
@ 2021-02-23 12:07                                       ` Daniel Vetter
  2021-04-20 11:42                                         ` Frieder Schrempf
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2021-02-23 12:07 UTC (permalink / raw)
  To: Andrzej Hajda, airlied
  Cc: Michael Tretter, Frieder Schrempf, Marek Vasut, aisheng.dong,
	linux-samsung-soc, ch, Neil Armstrong, Shawn Guo,
	Bartlomiej Zolnierkiewicz, Seung-Woo Kim, dl-linux-imx,
	dri-devel, abel.vesa, Kyungmin Park, Laurent Pinchart,
	Sascha Hauer, Krzysztof Kozlowski, sylvester.nawrocki,
	Joonyoung Shim, aford173, Marek Szyprowski

On Thu, Feb 18, 2021 at 5:02 PM Andrzej Hajda <a.hajda@samsung.com> wrote:
>
> Hi Michael,
>
> W dniu 18.02.2021 o 09:04, Michael Tretter pisze:
> > On Wed, 10 Feb 2021 10:10:37 +0100, Frieder Schrempf wrote:
> >> On 04.02.21 18:46, Daniel Vetter wrote:
> >>> On Thu, Feb 4, 2021 at 6:26 PM Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> >>>> On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
> >>>>> On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
> >>>>>> W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
> >>>>>>> On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
> >>>>>>>> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> >>>>>>>>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
> >>>>>>>>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> >>>>>>>>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> >>>>>>>>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> >>>>>>>>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
> >>>>>>>>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> >>>>>>>>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> >>>>>>>>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
> >>>>>>>>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> >>>>>>>>>>>>>>>>> used
> >>>>>>>>>>>>>>>>> from other drivers.
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> >>>>>>>>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
> >>>>>>>>>>>>>>>>> display pipe until the downstream bridges are available, too.
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> >>>>>>>>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> >>>>>>>>>>>>>>>> operations
> >>>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> >>>>>>>>>>>>>>>> 8<--- cut here ---
> >>>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> >>>>>>>>>>>>>>>> 00000084
> >>>>>>>>>>>>>>>> pgd = (ptrval)
> >>>>>>>>>>>>>>>> [00000084] *pgd=00000000
> >>>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>>>>>>>>>>>>>>> Modules linked in:
> >>>>>>>>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> >>>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> >>>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>>>>>>>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
> >>>>>>>>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
> >>>>>>>>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> >>>>>>>>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> >>>>>>>>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> >>>>>>>>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> >>>>>>>>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> >>>>>>>>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>>>>>>>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
> >>>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> >>>>>>>>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
> >>>>>>>>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> >>>>>>>>>>>>>>>> (component_bind_all+0xfc/0x290)
> >>>>>>>>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> >>>>>>>>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
> >>>>>>>>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> >>>>>>>>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
> >>>>>>>>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> >>>>>>>>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
> >>>>>>>>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> >>>>>>>>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
> >>>>>>>>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> >>>>>>>>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
> >>>>>>>>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> >>>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
> >>>>>>>>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
> >>>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
> >>>>>>>>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> >>>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
> >>>>>>>>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> >>>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
> >>>>>>>>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> >>>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> >>>>>>>>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> >>>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
> >>>>>>>>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> >>>>>>>>>>>>>>>> (driver_register+0x78/0x110)
> >>>>>>>>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> >>>>>>>>>>>>>>>> (exynos_drm_init+0xe4/0x118)
> >>>>>>>>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> >>>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
> >>>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> >>>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> >>>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
> >>>>>>>>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> >>>>>>>>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>> I will try to debug it a bit more today.
> >>>>>>>>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
> >>>>>>>>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> >>>>>>>>>>>>>>> another issue:
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> >>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> >>>>>>>>>>>>>>> 8<--- cut here ---
> >>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> >>>>>>>>>>>>>>> 00000280
> >>>>>>>>>>>>>>> pgd = (ptrval)
> >>>>>>>>>>>>>>> [00000280] *pgd=00000000
> >>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>>>>>>>>>>>>>> Modules linked in:
> >>>>>>>>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> >>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> >>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>>>>>>>>>>>>>> PC is at __mutex_lock+0x54/0xb18
> >>>>>>>>>>>>>>> LR is at lock_is_held_type+0x80/0x138
> >>>>>>>>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> >>>>>>>>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> >>>>>>>>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> >>>>>>>>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> >>>>>>>>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> >>>>>>>>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>>>>>>>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
> >>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> >>>>>>>>>>>>>>> (mutex_lock_nested+0x1c/0x24)
> >>>>>>>>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> >>>>>>>>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
> >>>>>>>>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> >>>>>>>>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
> >>>>>>>>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> >>>>>>>>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
> >>>>>>>>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> >>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
> >>>>>>>>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
> >>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
> >>>>>>>>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> >>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
> >>>>>>>>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> >>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
> >>>>>>>>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> >>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> >>>>>>>>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> >>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
> >>>>>>>>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> >>>>>>>>>>>>>>> (driver_register+0x78/0x110)
> >>>>>>>>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
> >>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
> >>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> >>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> >>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
> >>>>>>>>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> This means that dsi->encoder.dev is not initialized in
> >>>>>>>>>>>>>>> __exynos_dsi_host_attach().
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> >>>>>>>>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
> >>>>>>>>>>>>>>> release of all drm resources.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> Then however, the panel tries to register itself and
> >>>>>>>>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
> >>>>>>>>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
> >>>>>>>>>>>>>>> failure.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> It looks that something is missing. Maybe mipi host has to be
> >>>>>>>>>>>>>>> registered
> >>>>>>>>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
> >>>>>>>>>>>>>>> this patch. Andrzej, could you comment it a bit?
> >>>>>>>>>>>>>> I intentionally changed the order, because if another bridge follows
> >>>>>>>>>>>>>> in the
> >>>>>>>>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
> >>>>>>>>>>>>>> bridge
> >>>>>>>>>>>>>> provides a connector. The next bridge registers itself via the
> >>>>>>>>>>>>>> host_attach
> >>>>>>>>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
> >>>>>>>>>>>>>> API or
> >>>>>>>>>>>>>> the bridge_attach function otherwise.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
> >>>>>>>>>>>>>> device
> >>>>>>>>>>>>>> has been attached.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
> >>>>>>>>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> >>>>>>>>>>>>>> via
> >>>>>>>>>>>>>> exynos_dsi instead of the bridge.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> Can you try to move everything except samsung_dsim_bind from
> >>>>>>>>>>>>>> exynos_dsi_bind
> >>>>>>>>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> >>>>>>>>>>>>>> crash.
> >>>>>>>>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
> >>>>>>>>>>>>> regardless of sink presence (initially panel, later also bridge) - it
> >>>>>>>>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
> >>>>>>>>>>>>> and module load/unload. Appearance or disappearance of sink is
> >>>>>>>>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
> >>>>>>>>>>>>> reflected in drm world as change state of the connector.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> Registering DSI host in bind and unregistering in unbind assures that
> >>>>>>>>>>>>> if mipi_dsi device is attached/detached the drm device is always
> >>>>>>>>>>>>> present - it makes device/driver binding race free and allows to avoid
> >>>>>>>>>>>>> additional locking.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> Moving DSI host registration to probe changes everything, for sure it
> >>>>>>>>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
> >>>>>>>>>>>>> can cause different issues depending on device bind order.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> I will try to look at the patches tomorrow and maybe I can find more
> >>>>>>>>>>>>> constructive comments :)
> >>>>>>>>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> >>>>>>>>>>>> callbacks to control appearance/disappearance of downstream device. It
> >>>>>>>>>>>> allows to:
> >>>>>>>>>>>>
> >>>>>>>>>>>> 1. Safely bind/unbind different device drivers at any time and at any
> >>>>>>>>>>>> order, without killing exynos_drm and/or crashing system.
> >>>>>>>>>>>>
> >>>>>>>>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
> >>>>>>>>>>>> appeared too late, due to deferred probe, and resulted in black screen
> >>>>>>>>>>>> in userspace.
> >>>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
> >>>>>>>>>>>>
> >>>>>>>>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
> >>>>>>>>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
> >>>>>>>>>>>> appearance, thus probably black screen on some targets. So for sure it
> >>>>>>>>>>>> will be suboptimal. Making it bridge unbind safe would be another
> >>>>>>>>>>>> problem, but most developers do not care about it so why should we? :)
> >>>>>>>>>>>>
> >>>>>>>>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> >>>>>>>>>>>> even if downstream devices are not yet attached, on attach/detach notify
> >>>>>>>>>>>> drm about it via connector status change, for this dsi_host registration
> >>>>>>>>>>>> should be performed from drm_bridge attach, I guess.
> >>>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>> Option A is more standard, but is unsafe and causes other issues.
> >>>>>>>>>>>>
> >>>>>>>>>>>> Option B keeps current behaviour.
> >>>>>>>>>>> Maybe we can have both, but I am not sure, if I am missing something:
> >>>>>>>>>>>
> >>>>>>>>>>> I still prefer option A for the samsung-dsim driver, because it is more
> >>>>>>>>>>> standard, simpler and avoids issues with encoders, connectors or handling
> >>>>>>>>>>> hotplug.
> >>>>>>>>>>>
> >>>>>>>>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> >>>>>>>>>>> samsung-dsim driver which implements option A and defers probing of the drm
> >>>>>>>>>>> driver until the next bridge is attached. And a second bridge in the
> >>>>>>>>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> >>>>>>>>>>> device to appear) and implements the hotplug handling for notifying drm via
> >>>>>>>>>>> connector status change.
> >>>>>>>>>>>
> >>>>>>>>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
> >>>>>>>>>>> additional bridge.
> >>>>>>>>>>>
> >>>>>>>>>>> This allows the samsung-dsim driver to expose the standard behavior while the
> >>>>>>>>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> >>>>>>>>>>>
> >>>>>>>>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
> >>>>>>>>>>> get the probing and mipi host/device registration correct, but I will try, if
> >>>>>>>>>>> this can work.
> >>>>>>>>>> Adding two bridges for being able to support hotplugging adds many special
> >>>>>>>>>> cases to the bridge driver and still requires more custom API to correctly add
> >>>>>>>>>> the second bridge. I don't think that this a viable path to go.
> >>>>>>>>> Just jumping in here: You cannot hotplug/hotremove anything from a
> >>>>>>>>> drm_device after drm_dev_register has been called, except
> >>>>>>>>> drm_connector. I didn't dig into details here so not sure whether you
> >>>>>>>>> want to late-bind your bridge after drm_dev_register is called or not,
> >>>>>>>>> so might just be fyi and not relevant to the discussion.
> >>>>>>>> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
> >>>>>>>> driver (i.e. Option B)
> >>>>>>>>
> >>>>>>>> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
> >>>>>>>> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
> >>>>>>>> device might attach to the DSI host and call exynos_dsi_host_attach. In
> >>>>>>>> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
> >>>>>>>> attaches this bridge to the encoder _after_ drm_dev_register has been called.
> >>>>>>>> This is invalid behavior, right?
> >>>>>>> Definitely not supported, I don't think we have the right locks in place
> >>>>>>> to make sure this works.
> >>>>>>>
> >>>>>>> Now if your _only_ adding a drm_bridge (and not an encoder or anything
> >>>>>>> like that), and you are adding the drm_connector correctly (like a
> >>>>>>> hotplugged DP MST sink), then that would at least work from a uapi pov.
> >>>>>>> Because drm_bridge isn't exposed as an uapi object.
> >>>>>>>
> >>>>>>> But yeah, as-is, don't :-)
> >>>>>>>
> >>>>>>> The solution here is a bunch of EPROBE_DEFER handling until all your
> >>>>>>> bridges are loaded, with or without the assistance of component.c
> >>>>>>> framework. Only then call drm_dev_register.
> >>>>>> I have impression we have similar conversation already.
> >>>>>>
> >>>>>> As you stated drm_bridge and drm_panel are not exposed to userspace so
> >>>>>> there shouldn't be problem with them from uapi PoV.
> >>>>>>
> >>>>>> On the other side drm_panel or drm_bridge are not used until pipeline
> >>>>>> enters connected state (at least they were not some time ago :) ). The
> >>>>>> issue is that bridge exposes drm_connector, but as you stated (again :)
> >>>>>> ) connectors can be hotplugged, so in theory it should work. Practical
> >>>>>> tests shows that it also works, but bugs can be still there.
> >>>>>>
> >>>>>> Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
> >>>>>> decided there is no display), and does not handle unbinding/re-binding
> >>>>>> drivers.
> >>>>> Rebinding drivers should be fixed now, with a bunch of fixes in driver
> >>>>> core. If not, we need to fix this more.
> >>>>>
> >>>>> Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
> >>>>> we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
> >>>>> seem to go anywhere), not paper over it with bad architecture in
> >>>>> drivers.
> >>>> I've heard this argument multiple times, but it sounds more like an
> >>>> attempt to ignore the problem and hope it will fall on someone else's
> >>>> plate :-) Improvement in the probe deferral mechanism are certainly an
> >>>> option to explore, but as far as I can tell nobody has proven that this
> >>>> mechanism is or will be able to solve all problems related to probe
> >>>> ordering dependencies. I wouldn't rule out the need for different
> >>>> solutions for some of the issues.
> >>> Then build another one. But adding hotplug for stuff that is there,
> >>> and shouldn't be hotplugged, just because it's easier on driver
> >>> writers and harder on userspace isn't really a good approach.
> >>> -Daniel
> >> I think it is quite clear that replacing or reworking the deferral mechanism
> >> is out of scope for this discussion, which is why I would like to come back
> >> to the original issue and sum this up as far as I understand it (which is
> >> not really far when it comes to the details):
> >>
> >> We have the existing exynos driver that avoids the standard deferral
> >> mechanism in favor of something that works but Daniel describes as
> >> "definitely not supported".
> >>
> >> We have a proposal from Michael for converting the driver to the standard
> >> drm_bridge behavior and more work from Michael and Marek based on this to
> >> implement the platform specific parts for i.MX8MM.
> >>
> >>  From the i.MX8MM POV this approach already received some testing and looks
> >> good as far as I can judge. Upstreaming this solution is blocked because of
> >> objections from the Samsung maintainers.
> >>
> >> Sorry if I'm being blunt or naive, but where to go from here?
> >>
> > Maybe some more information by the Samsung maintainers would help:
> >
> > If I understand correctly, the main reason for the non-standard behavior is a
> > userspace application that runs into a timeout if the drm-device does not
> > appear in time. Correct? Is there something we can do about that?
> >
> > The other reason is the convenience of binding and unbinding a bridge driver,
> > while the drm device is kept available. Correct? Is this used in development,
> > testing, or production?
> >
> > Is there anything else that prevents the exynos drm from switching to the
> > standard behavior?
> >
> > Would a exynos drm specific wrapper, which uses a standard bridge driver but
> > exposes the non-standard behavior, be acceptable? (Unfortunately, my first try
> > on something like that felt really awkward and didn't really work.)
>
> Even if we drop this 'non-standard' behaviour, your task will be still
> quite difficult to fulfil - you are trying to completely rewrite core
> component of Exynos display pipeline without hardware to test.
>
> ExynosDSI is used in almost all Exynos platforms supported mainline (ls
> -1 arch/arm*/boot/dts/exynos*.dts | wc shows 35). It has different hw
> versions (4 compatibles) and is used in different configurations (video
> mode, command mode, with hw/sw trigger, connected to panels/bridges) and
> for sure with big heritage, since it was one of the 1st DSI drivers.
>
> Rewriting such driver is challenging, even with access to hw.
>
> So maybe it would be better to move common parts in your and exynos
> driver to 'shared library' and use it in both drivers - this way you
> have bigger chances to avoid traps.

If exynos really can't be fixed up in a reasonable way, then I think
sharing code doesn't make much sense - you drag the new driver down
with the old one that's just hanging in there the wrong way round. For
that case just copypaste the exynos code into a new clean drm_bridge
driver, and done.

That would also mean that new exynos support in drm/exynos would need
to be stalled until this is sorted out (at least for new platforms),
since continuing the old way really doesn't sound so great. Wouldn't
be the first time we just end up with a driver fork because the old
one has too much heritage and is too hard to change.

Note that this can also be done within one driver codebase, e.g.
nouveau has still legacy modeset code for nv04-nv4x, and atomic from
nv50+ going forward.

Should be possible to find a pragmatic solution here going forward,
despite tons of hw and heritage. If we use existing hard to retest hw
support to stop new driver submissions from doing the right thing,
that's a clear failure, we need a better approach here.
-Daniel

>
>
> Regards
>
> Andrzej
>
>
> >
> > Michael
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://protect2.fireeye.com/v1/url?k=08365e03-57ad66fe-0837d54c-000babff317b-bdb6592fde86cf24&q=1&e=db1ed315-991b-408c-827a-4b6cbf2b4e3e&u=https%3A%2F%2Flists.freedesktop.org%2Fmailman%2Flistinfo%2Fdri-devel
> >
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-02-23 12:07                                       ` Daniel Vetter
@ 2021-04-20 11:42                                         ` Frieder Schrempf
  2021-04-20 14:27                                           ` Laurent Pinchart
  0 siblings, 1 reply; 57+ messages in thread
From: Frieder Schrempf @ 2021-04-20 11:42 UTC (permalink / raw)
  To: Daniel Vetter, Andrzej Hajda, airlied
  Cc: Michael Tretter, Marek Vasut, aisheng.dong, linux-samsung-soc,
	ch, Neil Armstrong, Shawn Guo, Bartlomiej Zolnierkiewicz,
	Seung-Woo Kim, dl-linux-imx, dri-devel, abel.vesa, Kyungmin Park,
	Laurent Pinchart, Sascha Hauer, Krzysztof Kozlowski,
	sylvester.nawrocki, Joonyoung Shim, aford173, Marek Szyprowski

On 23.02.21 13:07, Daniel Vetter wrote:
> On Thu, Feb 18, 2021 at 5:02 PM Andrzej Hajda <a.hajda@samsung.com> wrote:
>>
>> Hi Michael,
>>
>> W dniu 18.02.2021 o 09:04, Michael Tretter pisze:
>>> On Wed, 10 Feb 2021 10:10:37 +0100, Frieder Schrempf wrote:
>>>> On 04.02.21 18:46, Daniel Vetter wrote:
>>>>> On Thu, Feb 4, 2021 at 6:26 PM Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
>>>>>> On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
>>>>>>> On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
>>>>>>>> W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
>>>>>>>>> On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
>>>>>>>>>> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
>>>>>>>>>>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
>>>>>>>>>>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
>>>>>>>>>>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
>>>>>>>>>>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
>>>>>>>>>>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
>>>>>>>>>>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
>>>>>>>>>>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
>>>>>>>>>>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
>>>>>>>>>>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
>>>>>>>>>>>>>>>>>>> used
>>>>>>>>>>>>>>>>>>> from other drivers.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
>>>>>>>>>>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
>>>>>>>>>>>>>>>>>>> display pipe until the downstream bridges are available, too.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
>>>>>>>>>>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
>>>>>>>>>>>>>>>>>> operations
>>>>>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>>>>>>>>>>> 8<--- cut here ---
>>>>>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>>>>>>>>>>> 00000084
>>>>>>>>>>>>>>>>>> pgd = (ptrval)
>>>>>>>>>>>>>>>>>> [00000084] *pgd=00000000
>>>>>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>>>>>>>>>>> Modules linked in:
>>>>>>>>>>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
>>>>>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>>>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
>>>>>>>>>>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
>>>>>>>>>>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
>>>>>>>>>>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
>>>>>>>>>>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
>>>>>>>>>>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
>>>>>>>>>>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
>>>>>>>>>>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>>>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
>>>>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
>>>>>>>>>>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
>>>>>>>>>>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
>>>>>>>>>>>>>>>>>> (component_bind_all+0xfc/0x290)
>>>>>>>>>>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
>>>>>>>>>>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
>>>>>>>>>>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
>>>>>>>>>>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
>>>>>>>>>>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
>>>>>>>>>>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
>>>>>>>>>>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
>>>>>>>>>>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
>>>>>>>>>>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
>>>>>>>>>>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
>>>>>>>>>>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
>>>>>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>>>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
>>>>>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>>>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
>>>>>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>>>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
>>>>>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>>>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
>>>>>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>>>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
>>>>>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>>>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
>>>>>>>>>>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>>>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
>>>>>>>>>>>>>>>>>> (exynos_drm_init+0xe4/0x118)
>>>>>>>>>>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
>>>>>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
>>>>>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>>>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
>>>>>>>>>>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> I will try to debug it a bit more today.
>>>>>>>>>>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
>>>>>>>>>>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
>>>>>>>>>>>>>>>>> another issue:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
>>>>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
>>>>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
>>>>>>>>>>>>>>>>> 8<--- cut here ---
>>>>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
>>>>>>>>>>>>>>>>> 00000280
>>>>>>>>>>>>>>>>> pgd = (ptrval)
>>>>>>>>>>>>>>>>> [00000280] *pgd=00000000
>>>>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
>>>>>>>>>>>>>>>>> Modules linked in:
>>>>>>>>>>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
>>>>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
>>>>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
>>>>>>>>>>>>>>>>> PC is at __mutex_lock+0x54/0xb18
>>>>>>>>>>>>>>>>> LR is at lock_is_held_type+0x80/0x138
>>>>>>>>>>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
>>>>>>>>>>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
>>>>>>>>>>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
>>>>>>>>>>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
>>>>>>>>>>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
>>>>>>>>>>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
>>>>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
>>>>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
>>>>>>>>>>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
>>>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
>>>>>>>>>>>>>>>>> (mutex_lock_nested+0x1c/0x24)
>>>>>>>>>>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
>>>>>>>>>>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
>>>>>>>>>>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
>>>>>>>>>>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
>>>>>>>>>>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
>>>>>>>>>>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
>>>>>>>>>>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
>>>>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
>>>>>>>>>>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
>>>>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
>>>>>>>>>>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
>>>>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
>>>>>>>>>>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
>>>>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
>>>>>>>>>>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
>>>>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
>>>>>>>>>>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
>>>>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
>>>>>>>>>>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
>>>>>>>>>>>>>>>>> (driver_register+0x78/0x110)
>>>>>>>>>>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
>>>>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
>>>>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
>>>>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
>>>>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
>>>>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
>>>>>>>>>>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
>>>>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
>>>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> This means that dsi->encoder.dev is not initialized in
>>>>>>>>>>>>>>>>> __exynos_dsi_host_attach().
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
>>>>>>>>>>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
>>>>>>>>>>>>>>>>> release of all drm resources.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Then however, the panel tries to register itself and
>>>>>>>>>>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
>>>>>>>>>>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
>>>>>>>>>>>>>>>>> failure.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> It looks that something is missing. Maybe mipi host has to be
>>>>>>>>>>>>>>>>> registered
>>>>>>>>>>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
>>>>>>>>>>>>>>>>> this patch. Andrzej, could you comment it a bit?
>>>>>>>>>>>>>>>> I intentionally changed the order, because if another bridge follows
>>>>>>>>>>>>>>>> in the
>>>>>>>>>>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
>>>>>>>>>>>>>>>> bridge
>>>>>>>>>>>>>>>> provides a connector. The next bridge registers itself via the
>>>>>>>>>>>>>>>> host_attach
>>>>>>>>>>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
>>>>>>>>>>>>>>>> API or
>>>>>>>>>>>>>>>> the bridge_attach function otherwise.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
>>>>>>>>>>>>>>>> device
>>>>>>>>>>>>>>>> has been attached.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
>>>>>>>>>>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
>>>>>>>>>>>>>>>> via
>>>>>>>>>>>>>>>> exynos_dsi instead of the bridge.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Can you try to move everything except samsung_dsim_bind from
>>>>>>>>>>>>>>>> exynos_dsi_bind
>>>>>>>>>>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
>>>>>>>>>>>>>>>> crash.
>>>>>>>>>>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
>>>>>>>>>>>>>>> regardless of sink presence (initially panel, later also bridge) - it
>>>>>>>>>>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
>>>>>>>>>>>>>>> and module load/unload. Appearance or disappearance of sink is
>>>>>>>>>>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
>>>>>>>>>>>>>>> reflected in drm world as change state of the connector.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Registering DSI host in bind and unregistering in unbind assures that
>>>>>>>>>>>>>>> if mipi_dsi device is attached/detached the drm device is always
>>>>>>>>>>>>>>> present - it makes device/driver binding race free and allows to avoid
>>>>>>>>>>>>>>> additional locking.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Moving DSI host registration to probe changes everything, for sure it
>>>>>>>>>>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
>>>>>>>>>>>>>>> can cause different issues depending on device bind order.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I will try to look at the patches tomorrow and maybe I can find more
>>>>>>>>>>>>>>> constructive comments :)
>>>>>>>>>>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
>>>>>>>>>>>>>> callbacks to control appearance/disappearance of downstream device. It
>>>>>>>>>>>>>> allows to:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 1. Safely bind/unbind different device drivers at any time and at any
>>>>>>>>>>>>>> order, without killing exynos_drm and/or crashing system.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
>>>>>>>>>>>>>> appeared too late, due to deferred probe, and resulted in black screen
>>>>>>>>>>>>>> in userspace.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
>>>>>>>>>>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
>>>>>>>>>>>>>> appearance, thus probably black screen on some targets. So for sure it
>>>>>>>>>>>>>> will be suboptimal. Making it bridge unbind safe would be another
>>>>>>>>>>>>>> problem, but most developers do not care about it so why should we? :)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
>>>>>>>>>>>>>> even if downstream devices are not yet attached, on attach/detach notify
>>>>>>>>>>>>>> drm about it via connector status change, for this dsi_host registration
>>>>>>>>>>>>>> should be performed from drm_bridge attach, I guess.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Option A is more standard, but is unsafe and causes other issues.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Option B keeps current behaviour.
>>>>>>>>>>>>> Maybe we can have both, but I am not sure, if I am missing something:
>>>>>>>>>>>>>
>>>>>>>>>>>>> I still prefer option A for the samsung-dsim driver, because it is more
>>>>>>>>>>>>> standard, simpler and avoids issues with encoders, connectors or handling
>>>>>>>>>>>>> hotplug.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
>>>>>>>>>>>>> samsung-dsim driver which implements option A and defers probing of the drm
>>>>>>>>>>>>> driver until the next bridge is attached. And a second bridge in the
>>>>>>>>>>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
>>>>>>>>>>>>> device to appear) and implements the hotplug handling for notifying drm via
>>>>>>>>>>>>> connector status change.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
>>>>>>>>>>>>> additional bridge.
>>>>>>>>>>>>>
>>>>>>>>>>>>> This allows the samsung-dsim driver to expose the standard behavior while the
>>>>>>>>>>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
>>>>>>>>>>>>> get the probing and mipi host/device registration correct, but I will try, if
>>>>>>>>>>>>> this can work.
>>>>>>>>>>>> Adding two bridges for being able to support hotplugging adds many special
>>>>>>>>>>>> cases to the bridge driver and still requires more custom API to correctly add
>>>>>>>>>>>> the second bridge. I don't think that this a viable path to go.
>>>>>>>>>>> Just jumping in here: You cannot hotplug/hotremove anything from a
>>>>>>>>>>> drm_device after drm_dev_register has been called, except
>>>>>>>>>>> drm_connector. I didn't dig into details here so not sure whether you
>>>>>>>>>>> want to late-bind your bridge after drm_dev_register is called or not,
>>>>>>>>>>> so might just be fyi and not relevant to the discussion.
>>>>>>>>>> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
>>>>>>>>>> driver (i.e. Option B)
>>>>>>>>>>
>>>>>>>>>> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
>>>>>>>>>> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
>>>>>>>>>> device might attach to the DSI host and call exynos_dsi_host_attach. In
>>>>>>>>>> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
>>>>>>>>>> attaches this bridge to the encoder _after_ drm_dev_register has been called.
>>>>>>>>>> This is invalid behavior, right?
>>>>>>>>> Definitely not supported, I don't think we have the right locks in place
>>>>>>>>> to make sure this works.
>>>>>>>>>
>>>>>>>>> Now if your _only_ adding a drm_bridge (and not an encoder or anything
>>>>>>>>> like that), and you are adding the drm_connector correctly (like a
>>>>>>>>> hotplugged DP MST sink), then that would at least work from a uapi pov.
>>>>>>>>> Because drm_bridge isn't exposed as an uapi object.
>>>>>>>>>
>>>>>>>>> But yeah, as-is, don't :-)
>>>>>>>>>
>>>>>>>>> The solution here is a bunch of EPROBE_DEFER handling until all your
>>>>>>>>> bridges are loaded, with or without the assistance of component.c
>>>>>>>>> framework. Only then call drm_dev_register.
>>>>>>>> I have impression we have similar conversation already.
>>>>>>>>
>>>>>>>> As you stated drm_bridge and drm_panel are not exposed to userspace so
>>>>>>>> there shouldn't be problem with them from uapi PoV.
>>>>>>>>
>>>>>>>> On the other side drm_panel or drm_bridge are not used until pipeline
>>>>>>>> enters connected state (at least they were not some time ago :) ). The
>>>>>>>> issue is that bridge exposes drm_connector, but as you stated (again :)
>>>>>>>> ) connectors can be hotplugged, so in theory it should work. Practical
>>>>>>>> tests shows that it also works, but bugs can be still there.
>>>>>>>>
>>>>>>>> Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
>>>>>>>> decided there is no display), and does not handle unbinding/re-binding
>>>>>>>> drivers.
>>>>>>> Rebinding drivers should be fixed now, with a bunch of fixes in driver
>>>>>>> core. If not, we need to fix this more.
>>>>>>>
>>>>>>> Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
>>>>>>> we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
>>>>>>> seem to go anywhere), not paper over it with bad architecture in
>>>>>>> drivers.
>>>>>> I've heard this argument multiple times, but it sounds more like an
>>>>>> attempt to ignore the problem and hope it will fall on someone else's
>>>>>> plate :-) Improvement in the probe deferral mechanism are certainly an
>>>>>> option to explore, but as far as I can tell nobody has proven that this
>>>>>> mechanism is or will be able to solve all problems related to probe
>>>>>> ordering dependencies. I wouldn't rule out the need for different
>>>>>> solutions for some of the issues.
>>>>> Then build another one. But adding hotplug for stuff that is there,
>>>>> and shouldn't be hotplugged, just because it's easier on driver
>>>>> writers and harder on userspace isn't really a good approach.
>>>>> -Daniel
>>>> I think it is quite clear that replacing or reworking the deferral mechanism
>>>> is out of scope for this discussion, which is why I would like to come back
>>>> to the original issue and sum this up as far as I understand it (which is
>>>> not really far when it comes to the details):
>>>>
>>>> We have the existing exynos driver that avoids the standard deferral
>>>> mechanism in favor of something that works but Daniel describes as
>>>> "definitely not supported".
>>>>
>>>> We have a proposal from Michael for converting the driver to the standard
>>>> drm_bridge behavior and more work from Michael and Marek based on this to
>>>> implement the platform specific parts for i.MX8MM.
>>>>
>>>>   From the i.MX8MM POV this approach already received some testing and looks
>>>> good as far as I can judge. Upstreaming this solution is blocked because of
>>>> objections from the Samsung maintainers.
>>>>
>>>> Sorry if I'm being blunt or naive, but where to go from here?
>>>>
>>> Maybe some more information by the Samsung maintainers would help:
>>>
>>> If I understand correctly, the main reason for the non-standard behavior is a
>>> userspace application that runs into a timeout if the drm-device does not
>>> appear in time. Correct? Is there something we can do about that?
>>>
>>> The other reason is the convenience of binding and unbinding a bridge driver,
>>> while the drm device is kept available. Correct? Is this used in development,
>>> testing, or production?
>>>
>>> Is there anything else that prevents the exynos drm from switching to the
>>> standard behavior?
>>>
>>> Would a exynos drm specific wrapper, which uses a standard bridge driver but
>>> exposes the non-standard behavior, be acceptable? (Unfortunately, my first try
>>> on something like that felt really awkward and didn't really work.)
>>
>> Even if we drop this 'non-standard' behaviour, your task will be still
>> quite difficult to fulfil - you are trying to completely rewrite core
>> component of Exynos display pipeline without hardware to test.
>>
>> ExynosDSI is used in almost all Exynos platforms supported mainline (ls
>> -1 arch/arm*/boot/dts/exynos*.dts | wc shows 35). It has different hw
>> versions (4 compatibles) and is used in different configurations (video
>> mode, command mode, with hw/sw trigger, connected to panels/bridges) and
>> for sure with big heritage, since it was one of the 1st DSI drivers.
>>
>> Rewriting such driver is challenging, even with access to hw.
>>
>> So maybe it would be better to move common parts in your and exynos
>> driver to 'shared library' and use it in both drivers - this way you
>> have bigger chances to avoid traps.
> 
> If exynos really can't be fixed up in a reasonable way, then I think
> sharing code doesn't make much sense - you drag the new driver down
> with the old one that's just hanging in there the wrong way round. For
> that case just copypaste the exynos code into a new clean drm_bridge
> driver, and done.
> 
> That would also mean that new exynos support in drm/exynos would need
> to be stalled until this is sorted out (at least for new platforms),
> since continuing the old way really doesn't sound so great. Wouldn't
> be the first time we just end up with a driver fork because the old
> one has too much heritage and is too hard to change.
> 
> Note that this can also be done within one driver codebase, e.g.
> nouveau has still legacy modeset code for nv04-nv4x, and atomic from
> nv50+ going forward.
> 
> Should be possible to find a pragmatic solution here going forward,
> despite tons of hw and heritage. If we use existing hard to retest hw
> support to stop new driver submissions from doing the right thing,
> that's a clear failure, we need a better approach here.
> -Daniel
> 

Right, and I just wanted to add that there seems to be a similar (maybe 
less complex?) situation for the CSIS CSI controller. In that case we 
already have two separate drivers for pretty much the same hardware in 
the media subsystem, media/platform/exynos4-is/mipi-csis.c for the 
exynos and staging/media/imx/imx7-mipi-csis.c for the imx.

I don't know the history for this, but it just came to my mind that this 
case is related and it might be interesting for the scope of this 
discussion.

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

* Re: [PATCH v2 10/16] drm/exynos: implement a drm bridge
  2021-04-20 11:42                                         ` Frieder Schrempf
@ 2021-04-20 14:27                                           ` Laurent Pinchart
  0 siblings, 0 replies; 57+ messages in thread
From: Laurent Pinchart @ 2021-04-20 14:27 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Daniel Vetter, Andrzej Hajda, airlied, Michael Tretter,
	Marek Vasut, aisheng.dong, linux-samsung-soc, ch, Neil Armstrong,
	Shawn Guo, Bartlomiej Zolnierkiewicz, Seung-Woo Kim,
	dl-linux-imx, dri-devel, abel.vesa, Kyungmin Park, Sascha Hauer,
	Krzysztof Kozlowski, sylvester.nawrocki, Joonyoung Shim,
	aford173, Marek Szyprowski

Hi Frieder,

On Tue, Apr 20, 2021 at 01:42:05PM +0200, Frieder Schrempf wrote:
> On 23.02.21 13:07, Daniel Vetter wrote:
> > On Thu, Feb 18, 2021 at 5:02 PM Andrzej Hajda <a.hajda@samsung.com> wrote:
> >> W dniu 18.02.2021 o 09:04, Michael Tretter pisze:
> >>> On Wed, 10 Feb 2021 10:10:37 +0100, Frieder Schrempf wrote:
> >>>> On 04.02.21 18:46, Daniel Vetter wrote:
> >>>>> On Thu, Feb 4, 2021 at 6:26 PM Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> >>>>>> On Thu, Feb 04, 2021 at 06:19:22PM +0100, Daniel Vetter wrote:
> >>>>>>> On Thu, Feb 4, 2021 at 5:28 PM Andrzej Hajda wrote:
> >>>>>>>> W dniu 04.02.2021 o 17:05, Daniel Vetter pisze:
> >>>>>>>>> On Thu, Feb 04, 2021 at 11:56:32AM +0100, Michael Tretter wrote:
> >>>>>>>>>> On Thu, 04 Feb 2021 11:17:49 +0100, Daniel Vetter wrote:
> >>>>>>>>>>> On Wed, Feb 3, 2021 at 9:32 PM Michael Tretter wrote:
> >>>>>>>>>>>> On Mon, 01 Feb 2021 17:33:14 +0100, Michael Tretter wrote:
> >>>>>>>>>>>>> On Tue, 15 Sep 2020 21:40:40 +0200, Andrzej Hajda wrote:
> >>>>>>>>>>>>>> W dniu 14.09.2020 o 23:19, Andrzej Hajda pisze:
> >>>>>>>>>>>>>>> On 14.09.2020 22:01, Michael Tretter wrote:
> >>>>>>>>>>>>>>>> On Mon, 14 Sep 2020 14:31:19 +0200, Marek Szyprowski wrote:
> >>>>>>>>>>>>>>>>> On 14.09.2020 10:29, Marek Szyprowski wrote:
> >>>>>>>>>>>>>>>>>> On 11.09.2020 15:54, Michael Tretter wrote:
> >>>>>>>>>>>>>>>>>>> Make the exynos_dsi driver a full drm bridge that can be found and
> >>>>>>>>>>>>>>>>>>> used
> >>>>>>>>>>>>>>>>>>> from other drivers.
> >>>>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>>> Other drivers can only attach to the bridge, if a mipi dsi device
> >>>>>>>>>>>>>>>>>>> already attached to the bridge. This allows to defer the probe of the
> >>>>>>>>>>>>>>>>>>> display pipe until the downstream bridges are available, too.
> >>>>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>>> Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
> >>>>>>>>>>>>>>>>>> This one (and the whole series applied) still fails on Exynos boards:
> >>>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping
> >>>>>>>>>>>>>>>>>> operations
> >>>>>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>>>>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> >>>>>>>>>>>>>>>>>> 8<--- cut here ---
> >>>>>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> >>>>>>>>>>>>>>>>>> 00000084
> >>>>>>>>>>>>>>>>>> pgd = (ptrval)
> >>>>>>>>>>>>>>>>>> [00000084] *pgd=00000000
> >>>>>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>>>>>>>>>>>>>>>>> Modules linked in:
> >>>>>>>>>>>>>>>>>> CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> >>>>>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608
> >>>>>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>>>>>>>>>>>>>>>>> PC is at drm_bridge_attach+0x18/0x164
> >>>>>>>>>>>>>>>>>> LR is at exynos_dsi_bind+0x88/0xa8
> >>>>>>>>>>>>>>>>>> pc : [<c0628c08>]    lr : [<c064d560>]    psr: 20000013
> >>>>>>>>>>>>>>>>>> sp : ef0dfca8  ip : 00000002  fp : c13190e0
> >>>>>>>>>>>>>>>>>> r10: 00000000  r9 : ee46d580  r8 : c13190e0
> >>>>>>>>>>>>>>>>>> r7 : ee438800  r6 : 00000018  r5 : ef253810  r4 : ef39e840
> >>>>>>>>>>>>>>>>>> r3 : 00000000  r2 : 00000018  r1 : ef39e888  r0 : ef39e840
> >>>>>>>>>>>>>>>>>> Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>>>>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>>>>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>>>>>>>>>>>>>>>>> Stack: (0xef0dfca8 to 0xef0e0000)
> >>>>>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>>>>> [<c0628c08>] (drm_bridge_attach) from [<c064d560>]
> >>>>>>>>>>>>>>>>>> (exynos_dsi_bind+0x88/0xa8)
> >>>>>>>>>>>>>>>>>> [<c064d560>] (exynos_dsi_bind) from [<c066a800>]
> >>>>>>>>>>>>>>>>>> (component_bind_all+0xfc/0x290)
> >>>>>>>>>>>>>>>>>> [<c066a800>] (component_bind_all) from [<c0649dc0>]
> >>>>>>>>>>>>>>>>>> (exynos_drm_bind+0xe4/0x19c)
> >>>>>>>>>>>>>>>>>> [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>]
> >>>>>>>>>>>>>>>>>> (try_to_bring_up_master+0x1e4/0x2c4)
> >>>>>>>>>>>>>>>>>> [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>]
> >>>>>>>>>>>>>>>>>> (component_master_add_with_match+0xd4/0x108)
> >>>>>>>>>>>>>>>>>> [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>]
> >>>>>>>>>>>>>>>>>> (exynos_drm_platform_probe+0xe4/0x110)
> >>>>>>>>>>>>>>>>>> [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>]
> >>>>>>>>>>>>>>>>>> (platform_drv_probe+0x6c/0xa4)
> >>>>>>>>>>>>>>>>>> [<c0674e6c>] (platform_drv_probe) from [<c067242c>]
> >>>>>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
> >>>>>>>>>>>>>>>>>> [<c067242c>] (really_probe) from [<c06728f0>]
> >>>>>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
> >>>>>>>>>>>>>>>>>> [<c06728f0>] (driver_probe_device) from [<c0672cd8>]
> >>>>>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
> >>>>>>>>>>>>>>>>>> [<c0672cd8>] (device_driver_attach) from [<c0672dbc>]
> >>>>>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
> >>>>>>>>>>>>>>>>>> [<c0672dbc>] (__driver_attach) from [<c06701b4>]
> >>>>>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> >>>>>>>>>>>>>>>>>> [<c06701b4>] (bus_for_each_dev) from [<c06714e8>]
> >>>>>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
> >>>>>>>>>>>>>>>>>> [<c06714e8>] (bus_add_driver) from [<c0673c1c>]
> >>>>>>>>>>>>>>>>>> (driver_register+0x78/0x110)
> >>>>>>>>>>>>>>>>>> [<c0673c1c>] (driver_register) from [<c0649ca8>]
> >>>>>>>>>>>>>>>>>> (exynos_drm_init+0xe4/0x118)
> >>>>>>>>>>>>>>>>>> [<c0649ca8>] (exynos_drm_init) from [<c0102484>]
> >>>>>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
> >>>>>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>>>>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> >>>>>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7880>]
> >>>>>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
> >>>>>>>>>>>>>>>>>> [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>>>>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>>>>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>>>>> ---[ end trace ee27f313f9ed9da1 ]---
> >>>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>> # arm-linux-gnueabi-addr2line -e vmlinux c0628c08
> >>>>>>>>>>>>>>>>>> drivers/gpu/drm/drm_bridge.c:184 (discriminator 1)
> >>>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>> I will try to debug it a bit more today.
> >>>>>>>>>>>>>>>>> The above crash has been caused by lack of in_bridge initialization to
> >>>>>>>>>>>>>>>>> NULL in exynos_dsi_bind() in this patch. However, fixing it reveals
> >>>>>>>>>>>>>>>>> another issue:
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations
> >>>>>>>>>>>>>>>>> exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops)
> >>>>>>>>>>>>>>>>> OF: graph: no port node found in /soc/dsi@11c80000
> >>>>>>>>>>>>>>>>> 8<--- cut here ---
> >>>>>>>>>>>>>>>>> Unable to handle kernel NULL pointer dereference at virtual address
> >>>>>>>>>>>>>>>>> 00000280
> >>>>>>>>>>>>>>>>> pgd = (ptrval)
> >>>>>>>>>>>>>>>>> [00000280] *pgd=00000000
> >>>>>>>>>>>>>>>>> Internal error: Oops: 5 [#1] PREEMPT SMP ARM
> >>>>>>>>>>>>>>>>> Modules linked in:
> >>>>>>>>>>>>>>>>> CPU: 0 PID: 1 Comm: swapper/0 Not tainted
> >>>>>>>>>>>>>>>>> 5.9.0-rc4-next-20200911-00010-g417dc70d70ec-dirty #1613
> >>>>>>>>>>>>>>>>> Hardware name: Samsung Exynos (Flattened Device Tree)
> >>>>>>>>>>>>>>>>> PC is at __mutex_lock+0x54/0xb18
> >>>>>>>>>>>>>>>>> LR is at lock_is_held_type+0x80/0x138
> >>>>>>>>>>>>>>>>> pc : [<c0afc920>]    lr : [<c0af63e8>]    psr: 60000013
> >>>>>>>>>>>>>>>>> sp : ef0dfd30  ip : 33937b74  fp : c13193c8
> >>>>>>>>>>>>>>>>> r10: c1208eec  r9 : 00000000  r8 : ee45f808
> >>>>>>>>>>>>>>>>> r7 : c19561a4  r6 : 00000000  r5 : 00000000  r4 : 0000024c
> >>>>>>>>>>>>>>>>> r3 : 00000000  r2 : 00204140  r1 : c124f13c  r0 : 00000000
> >>>>>>>>>>>>>>>>> Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
> >>>>>>>>>>>>>>>>> Control: 10c5387d  Table: 4000404a  DAC: 00000051
> >>>>>>>>>>>>>>>>> Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
> >>>>>>>>>>>>>>>>> Stack: (0xef0dfd30 to 0xef0e0000)
> >>>>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>>>> [<c0afc920>] (__mutex_lock) from [<c0afd400>]
> >>>>>>>>>>>>>>>>> (mutex_lock_nested+0x1c/0x24)
> >>>>>>>>>>>>>>>>> [<c0afd400>] (mutex_lock_nested) from [<c064d4b8>]
> >>>>>>>>>>>>>>>>> (__exynos_dsi_host_attach+0x20/0x6c)
> >>>>>>>>>>>>>>>>> [<c064d4b8>] (__exynos_dsi_host_attach) from [<c064d914>]
> >>>>>>>>>>>>>>>>> (exynos_dsi_host_attach+0x70/0x194)
> >>>>>>>>>>>>>>>>> [<c064d914>] (exynos_dsi_host_attach) from [<c0656b64>]
> >>>>>>>>>>>>>>>>> (s6e8aa0_probe+0x1b0/0x218)
> >>>>>>>>>>>>>>>>> [<c0656b64>] (s6e8aa0_probe) from [<c0672530>]
> >>>>>>>>>>>>>>>>> (really_probe+0x200/0x4fc)
> >>>>>>>>>>>>>>>>> [<c0672530>] (really_probe) from [<c06729f4>]
> >>>>>>>>>>>>>>>>> (driver_probe_device+0x78/0x1fc)
> >>>>>>>>>>>>>>>>> [<c06729f4>] (driver_probe_device) from [<c0672ddc>]
> >>>>>>>>>>>>>>>>> (device_driver_attach+0x58/0x60)
> >>>>>>>>>>>>>>>>> [<c0672ddc>] (device_driver_attach) from [<c0672ec0>]
> >>>>>>>>>>>>>>>>> (__driver_attach+0xdc/0x174)
> >>>>>>>>>>>>>>>>> [<c0672ec0>] (__driver_attach) from [<c06702b8>]
> >>>>>>>>>>>>>>>>> (bus_for_each_dev+0x68/0xb4)
> >>>>>>>>>>>>>>>>> [<c06702b8>] (bus_for_each_dev) from [<c06715ec>]
> >>>>>>>>>>>>>>>>> (bus_add_driver+0x158/0x214)
> >>>>>>>>>>>>>>>>> [<c06715ec>] (bus_add_driver) from [<c0673d20>]
> >>>>>>>>>>>>>>>>> (driver_register+0x78/0x110)
> >>>>>>>>>>>>>>>>> [<c0673d20>] (driver_register) from [<c0102484>]
> >>>>>>>>>>>>>>>>> (do_one_initcall+0x8c/0x42c)
> >>>>>>>>>>>>>>>>> [<c0102484>] (do_one_initcall) from [<c11011c0>]
> >>>>>>>>>>>>>>>>> (kernel_init_freeable+0x190/0x1dc)
> >>>>>>>>>>>>>>>>> [<c11011c0>] (kernel_init_freeable) from [<c0af7988>]
> >>>>>>>>>>>>>>>>> (kernel_init+0x8/0x118)
> >>>>>>>>>>>>>>>>> [<c0af7988>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20)
> >>>>>>>>>>>>>>>>> Exception stack(0xef0dffb0 to 0xef0dfff8)
> >>>>>>>>>>>>>>>>> ...
> >>>>>>>>>>>>>>>>> ---[ end trace c06e996ec2e8234d ]---
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> This means that dsi->encoder.dev is not initialized in
> >>>>>>>>>>>>>>>>> __exynos_dsi_host_attach().
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> This happens, because drm_bridge_attach() in exynos_dsi_bind() returned
> >>>>>>>>>>>>>>>>> earlier -517 (deferred probe), what causes cleanup of encoder and
> >>>>>>>>>>>>>>>>> release of all drm resources.
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> Then however, the panel tries to register itself and
> >>>>>>>>>>>>>>>>> exynos_dsi_host_attach() tries to access the released encoder (which is
> >>>>>>>>>>>>>>>>> zeroed in drm_encoder_release) and rest of resources, what causes
> >>>>>>>>>>>>>>>>> failure.
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>> It looks that something is missing. Maybe mipi host has to be
> >>>>>>>>>>>>>>>>> registered
> >>>>>>>>>>>>>>>>> later, when bridge is ready? I have no idea how it is handled before
> >>>>>>>>>>>>>>>>> this patch. Andrzej, could you comment it a bit?
> >>>>>>>>>>>>>>>> I intentionally changed the order, because if another bridge follows
> >>>>>>>>>>>>>>>> in the
> >>>>>>>>>>>>>>>> pipeline, the probe of the drm driver has to be deferred until some
> >>>>>>>>>>>>>>>> bridge
> >>>>>>>>>>>>>>>> provides a connector. The next bridge registers itself via the
> >>>>>>>>>>>>>>>> host_attach
> >>>>>>>>>>>>>>>> function and the deferral is ensured via the bind for the bind/unbind
> >>>>>>>>>>>>>>>> API or
> >>>>>>>>>>>>>>>> the bridge_attach function otherwise.
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>> On the other hand, the bridge does not have an encoder until the mipi
> >>>>>>>>>>>>>>>> device
> >>>>>>>>>>>>>>>> has been attached.
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>> As a solution, the exynos dsi driver must initialize the encoder in
> >>>>>>>>>>>>>>>> exynos_dsi_probe instead of in exynos_dsi_bind and access the encoder
> >>>>>>>>>>>>>>>> via
> >>>>>>>>>>>>>>>> exynos_dsi instead of the bridge.
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>> Can you try to move everything except samsung_dsim_bind from
> >>>>>>>>>>>>>>>> exynos_dsi_bind
> >>>>>>>>>>>>>>>> to exynos_dsi_probe (respectively for unbind) and report if it fixes the
> >>>>>>>>>>>>>>>> crash.
> >>>>>>>>>>>>>>> The original behaviour is that encoder (exynos_dsi) is registered
> >>>>>>>>>>>>>>> regardless of sink presence (initially panel, later also bridge) - it
> >>>>>>>>>>>>>>> avoids multiple issues with deferred probe, device driver bind/unbind
> >>>>>>>>>>>>>>> and module load/unload. Appearance or disappearance of sink is
> >>>>>>>>>>>>>>> reported to host nicely via DSI attach/detach callbacks - and it is
> >>>>>>>>>>>>>>> reflected in drm world as change state of the connector.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> Registering DSI host in bind and unregistering in unbind assures that
> >>>>>>>>>>>>>>> if mipi_dsi device is attached/detached the drm device is always
> >>>>>>>>>>>>>>> present - it makes device/driver binding race free and allows to avoid
> >>>>>>>>>>>>>>> additional locking.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> Moving DSI host registration to probe changes everything, for sure it
> >>>>>>>>>>>>>>> breaks the nice feature of DSI attach/detach callbacks and apparently
> >>>>>>>>>>>>>>> can cause different issues depending on device bind order.
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> I will try to look at the patches tomorrow and maybe I can find more
> >>>>>>>>>>>>>>> constructive comments :)
> >>>>>>>>>>>>>> As I said yesterday, exynos_dsi driver uses dsi host attach/detach
> >>>>>>>>>>>>>> callbacks to control appearance/disappearance of downstream device. It
> >>>>>>>>>>>>>> allows to:
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> 1. Safely bind/unbind different device drivers at any time and at any
> >>>>>>>>>>>>>> order, without killing exynos_drm and/or crashing system.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> 2. Avoid issues with late drm init - on some platforms exynos_drm device
> >>>>>>>>>>>>>> appeared too late, due to deferred probe, and resulted in black screen
> >>>>>>>>>>>>>> in userspace.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> Now if we want to convert exynos_dsi to drm_bridge I see following options:
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> A. Forgot about callbacks and make the exynos_drm to defer probing until
> >>>>>>>>>>>>>> exynos_dsi bridge is available, probably it will cause later exynos_drm
> >>>>>>>>>>>>>> appearance, thus probably black screen on some targets. So for sure it
> >>>>>>>>>>>>>> will be suboptimal. Making it bridge unbind safe would be another
> >>>>>>>>>>>>>> problem, but most developers do not care about it so why should we? :)
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> B. Try to mimic current behaviour - exynos_dsi register bridge ASAP,
> >>>>>>>>>>>>>> even if downstream devices are not yet attached, on attach/detach notify
> >>>>>>>>>>>>>> drm about it via connector status change, for this dsi_host registration
> >>>>>>>>>>>>>> should be performed from drm_bridge attach, I guess.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> Option A is more standard, but is unsafe and causes other issues.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> Option B keeps current behaviour.
> >>>>>>>>>>>>> Maybe we can have both, but I am not sure, if I am missing something:
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> I still prefer option A for the samsung-dsim driver, because it is more
> >>>>>>>>>>>>> standard, simpler and avoids issues with encoders, connectors or handling
> >>>>>>>>>>>>> hotplug.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> The idea is to use two bridges in the exynos-dsi driver: One bridge in the
> >>>>>>>>>>>>> samsung-dsim driver which implements option A and defers probing of the drm
> >>>>>>>>>>>>> driver until the next bridge is attached. And a second bridge in the
> >>>>>>>>>>>>> exynos_dsi that attaches to the first bridge (thus, allowing the exynos_drm
> >>>>>>>>>>>>> device to appear) and implements the hotplug handling for notifying drm via
> >>>>>>>>>>>>> connector status change.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> The driver for the i.MX8M would use the samsung-dsim bridge without an
> >>>>>>>>>>>>> additional bridge.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> This allows the samsung-dsim driver to expose the standard behavior while the
> >>>>>>>>>>>>> exynos_dsi may stick to the existing behavior for the exynos_drm driver.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> I hope this makes sense and does not sound too crazy. It might be difficult to
> >>>>>>>>>>>>> get the probing and mipi host/device registration correct, but I will try, if
> >>>>>>>>>>>>> this can work.
> >>>>>>>>>>>> Adding two bridges for being able to support hotplugging adds many special
> >>>>>>>>>>>> cases to the bridge driver and still requires more custom API to correctly add
> >>>>>>>>>>>> the second bridge. I don't think that this a viable path to go.
> >>>>>>>>>>> Just jumping in here: You cannot hotplug/hotremove anything from a
> >>>>>>>>>>> drm_device after drm_dev_register has been called, except
> >>>>>>>>>>> drm_connector. I didn't dig into details here so not sure whether you
> >>>>>>>>>>> want to late-bind your bridge after drm_dev_register is called or not,
> >>>>>>>>>>> so might just be fyi and not relevant to the discussion.
> >>>>>>>>>> Thanks. AFAIC that is exactly what is currently implemented in the exynos_drm
> >>>>>>>>>> driver (i.e. Option B)
> >>>>>>>>>>
> >>>>>>>>>> exynos_dsi_bind configures the encoder and registers a DSI host. Afterwards,
> >>>>>>>>>> exynos_drm_bind (as component_master_ops) calls drm_dev_register. Later, a DSI
> >>>>>>>>>> device might attach to the DSI host and call exynos_dsi_host_attach. In
> >>>>>>>>>> exynos_dsi_host_attach, the driver finds the drm_bridge for the DSI device and
> >>>>>>>>>> attaches this bridge to the encoder _after_ drm_dev_register has been called.
> >>>>>>>>>> This is invalid behavior, right?
> >>>>>>>>> Definitely not supported, I don't think we have the right locks in place
> >>>>>>>>> to make sure this works.
> >>>>>>>>>
> >>>>>>>>> Now if your _only_ adding a drm_bridge (and not an encoder or anything
> >>>>>>>>> like that), and you are adding the drm_connector correctly (like a
> >>>>>>>>> hotplugged DP MST sink), then that would at least work from a uapi pov.
> >>>>>>>>> Because drm_bridge isn't exposed as an uapi object.
> >>>>>>>>>
> >>>>>>>>> But yeah, as-is, don't :-)
> >>>>>>>>>
> >>>>>>>>> The solution here is a bunch of EPROBE_DEFER handling until all your
> >>>>>>>>> bridges are loaded, with or without the assistance of component.c
> >>>>>>>>> framework. Only then call drm_dev_register.
> >>>>>>>> I have impression we have similar conversation already.
> >>>>>>>>
> >>>>>>>> As you stated drm_bridge and drm_panel are not exposed to userspace so
> >>>>>>>> there shouldn't be problem with them from uapi PoV.
> >>>>>>>>
> >>>>>>>> On the other side drm_panel or drm_bridge are not used until pipeline
> >>>>>>>> enters connected state (at least they were not some time ago :) ). The
> >>>>>>>> issue is that bridge exposes drm_connector, but as you stated (again :)
> >>>>>>>> ) connectors can be hotplugged, so in theory it should work. Practical
> >>>>>>>> tests shows that it also works, but bugs can be still there.
> >>>>>>>>
> >>>>>>>> Bunch of EPROBE_DEFER was very slow (as a result userspace timeouted and
> >>>>>>>> decided there is no display), and does not handle unbinding/re-binding
> >>>>>>>> drivers.
> >>>>>>> Rebinding drivers should be fixed now, with a bunch of fixes in driver
> >>>>>>> core. If not, we need to fix this more.
> >>>>>>>
> >>>>>>> Also, EPROBE_DEFER is how this is supposed to work. If it's too slow,
> >>>>>>> we need to fix EPROBE_DEFER (there's ideas for pre-sorting that never
> >>>>>>> seem to go anywhere), not paper over it with bad architecture in
> >>>>>>> drivers.
> >>>>>> I've heard this argument multiple times, but it sounds more like an
> >>>>>> attempt to ignore the problem and hope it will fall on someone else's
> >>>>>> plate :-) Improvement in the probe deferral mechanism are certainly an
> >>>>>> option to explore, but as far as I can tell nobody has proven that this
> >>>>>> mechanism is or will be able to solve all problems related to probe
> >>>>>> ordering dependencies. I wouldn't rule out the need for different
> >>>>>> solutions for some of the issues.
> >>>>> Then build another one. But adding hotplug for stuff that is there,
> >>>>> and shouldn't be hotplugged, just because it's easier on driver
> >>>>> writers and harder on userspace isn't really a good approach.
> >>>>> -Daniel
> >>>> I think it is quite clear that replacing or reworking the deferral mechanism
> >>>> is out of scope for this discussion, which is why I would like to come back
> >>>> to the original issue and sum this up as far as I understand it (which is
> >>>> not really far when it comes to the details):
> >>>>
> >>>> We have the existing exynos driver that avoids the standard deferral
> >>>> mechanism in favor of something that works but Daniel describes as
> >>>> "definitely not supported".
> >>>>
> >>>> We have a proposal from Michael for converting the driver to the standard
> >>>> drm_bridge behavior and more work from Michael and Marek based on this to
> >>>> implement the platform specific parts for i.MX8MM.
> >>>>
> >>>>   From the i.MX8MM POV this approach already received some testing and looks
> >>>> good as far as I can judge. Upstreaming this solution is blocked because of
> >>>> objections from the Samsung maintainers.
> >>>>
> >>>> Sorry if I'm being blunt or naive, but where to go from here?
> >>>>
> >>> Maybe some more information by the Samsung maintainers would help:
> >>>
> >>> If I understand correctly, the main reason for the non-standard behavior is a
> >>> userspace application that runs into a timeout if the drm-device does not
> >>> appear in time. Correct? Is there something we can do about that?
> >>>
> >>> The other reason is the convenience of binding and unbinding a bridge driver,
> >>> while the drm device is kept available. Correct? Is this used in development,
> >>> testing, or production?
> >>>
> >>> Is there anything else that prevents the exynos drm from switching to the
> >>> standard behavior?
> >>>
> >>> Would a exynos drm specific wrapper, which uses a standard bridge driver but
> >>> exposes the non-standard behavior, be acceptable? (Unfortunately, my first try
> >>> on something like that felt really awkward and didn't really work.)
> >>
> >> Even if we drop this 'non-standard' behaviour, your task will be still
> >> quite difficult to fulfil - you are trying to completely rewrite core
> >> component of Exynos display pipeline without hardware to test.
> >>
> >> ExynosDSI is used in almost all Exynos platforms supported mainline (ls
> >> -1 arch/arm*/boot/dts/exynos*.dts | wc shows 35). It has different hw
> >> versions (4 compatibles) and is used in different configurations (video
> >> mode, command mode, with hw/sw trigger, connected to panels/bridges) and
> >> for sure with big heritage, since it was one of the 1st DSI drivers.
> >>
> >> Rewriting such driver is challenging, even with access to hw.
> >>
> >> So maybe it would be better to move common parts in your and exynos
> >> driver to 'shared library' and use it in both drivers - this way you
> >> have bigger chances to avoid traps.
> > 
> > If exynos really can't be fixed up in a reasonable way, then I think
> > sharing code doesn't make much sense - you drag the new driver down
> > with the old one that's just hanging in there the wrong way round. For
> > that case just copypaste the exynos code into a new clean drm_bridge
> > driver, and done.
> > 
> > That would also mean that new exynos support in drm/exynos would need
> > to be stalled until this is sorted out (at least for new platforms),
> > since continuing the old way really doesn't sound so great. Wouldn't
> > be the first time we just end up with a driver fork because the old
> > one has too much heritage and is too hard to change.
> > 
> > Note that this can also be done within one driver codebase, e.g.
> > nouveau has still legacy modeset code for nv04-nv4x, and atomic from
> > nv50+ going forward.
> > 
> > Should be possible to find a pragmatic solution here going forward,
> > despite tons of hw and heritage. If we use existing hard to retest hw
> > support to stop new driver submissions from doing the right thing,
> > that's a clear failure, we need a better approach here.
> > -Daniel
> 
> Right, and I just wanted to add that there seems to be a similar (maybe 
> less complex?) situation for the CSIS CSI controller. In that case we 
> already have two separate drivers for pretty much the same hardware in 
> the media subsystem, media/platform/exynos4-is/mipi-csis.c for the 
> exynos and staging/media/imx/imx7-mipi-csis.c for the imx.

And we would have at least a third on in
staging/media/imx/imx8-mipi-csi2-sam.c if we followed the NXP BSP :-)
I've added support for i.MX8 to the imx7-mipi-csis driver recently, and
I'm half-tempted to merge it with the
media/platform/exynos4-is/mipi-csis.c driver at some point. Lack of
Exynos test hardware and documentation, as well as of time, will likely
prevent that from happening, but if someone wanted to give it a go, it
would be nice.

> I don't know the history for this, but it just came to my mind that this 
> case is related and it might be interesting for the scope of this 
> discussion.

I think staging/media/imx/imx7-mipi-csis.c was developed in the NXP BSP,
and we merged it upstream without realizing it was the same IP core as
media/platform/exynos4-is/mipi-csis.c.

-- 
Regards,

Laurent Pinchart

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

end of thread, other threads:[~2021-04-20 14:27 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20200911165401epcas1p3c7ee84dd01db93f472d6fa21c1100f29@epcas1p3.samsung.com>
2020-09-11 13:53 ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Michael Tretter
2020-09-11 13:53   ` [PATCH v2 01/16] drm/encoder: remove obsolete documentation of bridge Michael Tretter
2020-11-07 15:07     ` Adam Ford
2020-11-10  8:46       ` Michael Tretter
2020-11-07 22:17     ` Sam Ravnborg
2020-09-11 13:53   ` [PATCH v2 02/16] drm/exynos: remove in_bridge_node from exynos_dsi Michael Tretter
2020-11-07 22:19     ` Sam Ravnborg
2020-09-11 13:54   ` [PATCH v2 03/16] drm/exynos: use exynos_dsi as drvdata Michael Tretter
2020-11-07 22:24     ` Sam Ravnborg
2020-11-09  2:24       ` Inki Dae
2020-09-11 13:54   ` [PATCH v2 04/16] drm/exynos: extract helper functions for probe Michael Tretter
2020-11-07 22:27     ` Sam Ravnborg
2020-11-09  2:52       ` Inki Dae
2020-09-11 13:54   ` [PATCH v2 05/16] drm/exynos: move dsi host registration to probe Michael Tretter
2020-09-11 13:54   ` [PATCH v2 06/16] drm/exynos: shift register values to fields on write Michael Tretter
2020-11-07 22:39     ` Sam Ravnborg
2020-11-10  8:28       ` Michael Tretter
2020-09-11 13:54   ` [PATCH v2 07/16] drm/exynos: use identifier instead of register offsets Michael Tretter
2020-09-11 13:54   ` [PATCH v2 08/16] drm/exynos: add host_ops callback for platform drivers Michael Tretter
2020-09-15 17:07     ` Andrzej Hajda
2020-09-15 18:02       ` Michael Tretter
2020-09-16 22:01         ` Andrzej Hajda
2020-09-11 13:54   ` [PATCH v2 09/16] drm/exynos: add callback for tearing effect handler Michael Tretter
2020-09-11 13:54   ` [PATCH v2 10/16] drm/exynos: implement a drm bridge Michael Tretter
2020-09-14  8:29     ` Marek Szyprowski
2020-09-14 12:31       ` Marek Szyprowski
2020-09-14 20:01         ` Michael Tretter
2020-09-14 21:19           ` Andrzej Hajda
2020-09-15 19:40             ` Andrzej Hajda
2021-02-01 16:33               ` Michael Tretter
2021-02-03 20:31                 ` Michael Tretter
2021-02-04 10:17                   ` Daniel Vetter
2021-02-04 10:56                     ` Michael Tretter
2021-02-04 16:05                       ` Daniel Vetter
2021-02-04 16:28                         ` Andrzej Hajda
2021-02-04 17:19                           ` Daniel Vetter
2021-02-04 17:26                             ` Laurent Pinchart
2021-02-04 17:46                               ` Daniel Vetter
2021-02-10  9:10                                 ` Frieder Schrempf
2021-02-18  8:04                                   ` Michael Tretter
2021-02-18 16:02                                     ` Andrzej Hajda
2021-02-23 12:07                                       ` Daniel Vetter
2021-04-20 11:42                                         ` Frieder Schrempf
2021-04-20 14:27                                           ` Laurent Pinchart
2020-09-11 13:54   ` [PATCH v2 11/16] drm/exynos: convert encoder functions to bridge function Michael Tretter
2020-09-11 13:54   ` [PATCH v2 12/16] drm/exynos: configure mode on drm bridge Michael Tretter
2020-09-11 13:54   ` [PATCH v2 13/16] drm/exynos: get encoder from bridge whenever possible Michael Tretter
2020-09-11 13:54   ` [PATCH v2 14/16] drm/exynos: add API functions for platform drivers Michael Tretter
2020-09-11 13:54   ` [PATCH v2 15/16] drm/exynos: split out platform specific code Michael Tretter
2020-11-09  3:15   ` [PATCH v2 00/16] drm/exynos: Convert driver to drm bridge Inki Dae
2020-11-10  8:13     ` Michael Tretter
2020-11-10 12:34       ` Marek Szyprowski
2020-11-10 18:52         ` Sam Ravnborg
2020-11-11  3:04       ` Inki Dae
2020-11-11  3:11         ` Inki Dae
2020-11-11 10:18           ` Michael Tretter
2020-11-13  9:34             ` Inki Dae

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