All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/7] drm: sun4i: dsi: Convert drm bridge
@ 2021-11-22  6:52 ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

This series convert Allwinner DSI controller to full functional 
drm bridge driver for supporting all variants of DSI devices.

Here, are the previous version changes[1].

Patch 1: Drop the DRM bind race while attaching bridges

Patch 2: Move component_add into sun6i_dsi_attach

Patch 3: Convert the encoder to bridge driver

Patch 4: Add mode_set API

Patch 5: Enable DSI Panel

Patch 6: Enable DSI Bridge

Patch 7: Enable DSI Bridge (I2C)

[1] https://www.spinics.net/lists/arm-kernel/msg883560.html

Any inputs?
Jagan.

Jagan Teki (7):
  drm: sun4i: dsi: Drop DRM bind race with bridge attach
  drm: sun4i: dsi: Add component only once DSI device attached
  drm: sun4i: dsi: Convert to bridge driver
  drm: sun4i: dsi: Add mode_set function
  [DO NOT MERGE] ARM: dts: sun8i: bananapi-m2m: Enable S070WV20-CT16 Panel
  [DO NOT MERGE] ARM: dts: sun8i: bananapi-m2m: Enable ICN6211 DSI Bridge
  [DO NOT MERGE] ARM: dts: sun8i: Enable DLPC3433 Bridge (I2C)

 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts |  63 ++++++
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c       | 225 ++++++++++++-------
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h       |   9 +-
 3 files changed, 218 insertions(+), 79 deletions(-)

-- 
2.25.1


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

* [PATCH v5 0/7] drm: sun4i: dsi: Convert drm bridge
@ 2021-11-22  6:52 ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

This series convert Allwinner DSI controller to full functional 
drm bridge driver for supporting all variants of DSI devices.

Here, are the previous version changes[1].

Patch 1: Drop the DRM bind race while attaching bridges

Patch 2: Move component_add into sun6i_dsi_attach

Patch 3: Convert the encoder to bridge driver

Patch 4: Add mode_set API

Patch 5: Enable DSI Panel

Patch 6: Enable DSI Bridge

Patch 7: Enable DSI Bridge (I2C)

[1] https://www.spinics.net/lists/arm-kernel/msg883560.html

Any inputs?
Jagan.

Jagan Teki (7):
  drm: sun4i: dsi: Drop DRM bind race with bridge attach
  drm: sun4i: dsi: Add component only once DSI device attached
  drm: sun4i: dsi: Convert to bridge driver
  drm: sun4i: dsi: Add mode_set function
  [DO NOT MERGE] ARM: dts: sun8i: bananapi-m2m: Enable S070WV20-CT16 Panel
  [DO NOT MERGE] ARM: dts: sun8i: bananapi-m2m: Enable ICN6211 DSI Bridge
  [DO NOT MERGE] ARM: dts: sun8i: Enable DLPC3433 Bridge (I2C)

 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts |  63 ++++++
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c       | 225 ++++++++++++-------
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h       |   9 +-
 3 files changed, 218 insertions(+), 79 deletions(-)

-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v5 1/7] drm: sun4i: dsi: Drop DRM bind race with bridge attach
  2021-11-22  6:52 ` Jagan Teki
@ 2021-11-22  6:52   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

Existing host driver will keep looking for DRM pointer in
sun6i_dsi_attach and defers even if the particular DSI device
is found for the first time. Meanwhile it triggers the bind
callback and gets the DRM pointer and then continues the
sun6i_dsi_attach.

This makes a deadlock situation if sun6i_dsi_attach is trying
to find the bridge.

If interface bridge is trying to call host attach, then host
sun6i_dsi_attach is trying to find bridge and defers the
interface bridge even if it found the bridge as bind callback
does not complete at the movement. So, this sun6i_dsi_attach
defers interface bridge and triggers the bind callback and
tries to attach the bridge with a bridge pointer which is not
available at the moment.

Eventually these callbacks are triggered recursively, as
sun6i_dsi_attach defers interface bridge and bind callback
defers sun6i_dsi_attach due to invalid bridge ponter.

This patch prevents this situation by probing all DSI devices
on the pipeline first and then triggers the bind callback by
dropping exing DRM binding logic.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- new patch

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 10 +---------
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |  1 -
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 527c7b2474da..4bdcce8f1d84 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -967,14 +967,10 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 
 	if (IS_ERR(panel))
 		return PTR_ERR(panel);
-	if (!dsi->drm || !dsi->drm->registered)
-		return -EPROBE_DEFER;
 
 	dsi->panel = panel;
 	dsi->device = device;
 
-	drm_kms_helper_hotplug_event(dsi->drm);
-
 	dev_info(host->dev, "Attached device %s\n", device->name);
 
 	return 0;
@@ -988,8 +984,6 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
 	dsi->panel = NULL;
 	dsi->device = NULL;
 
-	drm_kms_helper_hotplug_event(dsi->drm);
-
 	return 0;
 }
 
@@ -1077,8 +1071,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 
 	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
 
-	dsi->drm = drm;
-
 	return 0;
 
 err_cleanup_connector:
@@ -1091,7 +1083,7 @@ static void sun6i_dsi_unbind(struct device *dev, struct device *master,
 {
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
 
-	dsi->drm = NULL;
+	drm_encoder_cleanup(&dsi->encoder);
 }
 
 static const struct component_ops sun6i_dsi_ops = {
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index c863900ae3b4..61e88ea6044d 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -29,7 +29,6 @@ struct sun6i_dsi {
 
 	struct device		*dev;
 	struct mipi_dsi_device	*device;
-	struct drm_device	*drm;
 	struct drm_panel	*panel;
 };
 
-- 
2.25.1


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

* [PATCH v5 1/7] drm: sun4i: dsi: Drop DRM bind race with bridge attach
@ 2021-11-22  6:52   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

Existing host driver will keep looking for DRM pointer in
sun6i_dsi_attach and defers even if the particular DSI device
is found for the first time. Meanwhile it triggers the bind
callback and gets the DRM pointer and then continues the
sun6i_dsi_attach.

This makes a deadlock situation if sun6i_dsi_attach is trying
to find the bridge.

If interface bridge is trying to call host attach, then host
sun6i_dsi_attach is trying to find bridge and defers the
interface bridge even if it found the bridge as bind callback
does not complete at the movement. So, this sun6i_dsi_attach
defers interface bridge and triggers the bind callback and
tries to attach the bridge with a bridge pointer which is not
available at the moment.

Eventually these callbacks are triggered recursively, as
sun6i_dsi_attach defers interface bridge and bind callback
defers sun6i_dsi_attach due to invalid bridge ponter.

This patch prevents this situation by probing all DSI devices
on the pipeline first and then triggers the bind callback by
dropping exing DRM binding logic.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- new patch

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 10 +---------
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |  1 -
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 527c7b2474da..4bdcce8f1d84 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -967,14 +967,10 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 
 	if (IS_ERR(panel))
 		return PTR_ERR(panel);
-	if (!dsi->drm || !dsi->drm->registered)
-		return -EPROBE_DEFER;
 
 	dsi->panel = panel;
 	dsi->device = device;
 
-	drm_kms_helper_hotplug_event(dsi->drm);
-
 	dev_info(host->dev, "Attached device %s\n", device->name);
 
 	return 0;
@@ -988,8 +984,6 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
 	dsi->panel = NULL;
 	dsi->device = NULL;
 
-	drm_kms_helper_hotplug_event(dsi->drm);
-
 	return 0;
 }
 
@@ -1077,8 +1071,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 
 	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
 
-	dsi->drm = drm;
-
 	return 0;
 
 err_cleanup_connector:
@@ -1091,7 +1083,7 @@ static void sun6i_dsi_unbind(struct device *dev, struct device *master,
 {
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
 
-	dsi->drm = NULL;
+	drm_encoder_cleanup(&dsi->encoder);
 }
 
 static const struct component_ops sun6i_dsi_ops = {
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index c863900ae3b4..61e88ea6044d 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -29,7 +29,6 @@ struct sun6i_dsi {
 
 	struct device		*dev;
 	struct mipi_dsi_device	*device;
-	struct drm_device	*drm;
 	struct drm_panel	*panel;
 };
 
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v5 2/7] drm: sun4i: dsi: Add component only once DSI device attached
  2021-11-22  6:52 ` Jagan Teki
@ 2021-11-22  6:52   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

Having component_add for running all drm bind callbacks returns
error or unbound due to chain of DSI devices connected across
bridge topology on a display pipeline.

In a typical bridge oriented display pipeline where the host is
connected to the bridge converter and that indeed connected to
a panel.

DRM => SUN6I DSI Host => Chipone ICN6211 => BananaPi Panel

The bridge converter is looking for a panel to probe first and
then attach the host. The host attach is looking for a bridge
converter to probe and preserve bridge pointer, at this movement
the host is trying to bind the all callbacks and one of the bind
callback in the DSI host is trying to find the bridge using the
bridge pointer in sun6i_dsi_attach call.

chipone_probe().start
    drm_of_find_panel_or_bridge
        mipi_dsi_attach
             sun6i_dsi_attach
                 drm_of_find_panel_or_bridge
chipone_probe().done

sun6i_dsi_probe().start
    mipi_dsi_host_register
        component_add
sun6i_dsi_probe().done

However, the movement when panel defers the probe, will make the
bridge converter defer the host attach call which eventually found
a NULL bridge pointer during DSI component bind callback.

So, in order to prevent this scenario of binding invalid bridge,
wait for DSI devices on the pipeline to probe first and start the
binding process by moving component_add in host probe to attach call.

chipone_probe().start
    drm_of_find_panel_or_bridge
        mipi_dsi_attach
             sun6i_dsi_attach
                 drm_of_find_panel_or_bridge
      		      component_add
chipone_probe().done

sun6i_dsi_probe().start
    mipi_dsi_host_register
sun6i_dsi_probe().done

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- new patch

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 119 +++++++++++++------------
 1 file changed, 60 insertions(+), 59 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 4bdcce8f1d84..43d9c9e5198d 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -959,11 +959,62 @@ static int sun6i_dsi_dcs_read(struct sun6i_dsi *dsi,
 	return 1;
 }
 
+static int sun6i_dsi_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	struct drm_device *drm = data;
+	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+	int ret;
+
+	drm_encoder_helper_add(&dsi->encoder,
+			       &sun6i_dsi_enc_helper_funcs);
+	ret = drm_simple_encoder_init(drm, &dsi->encoder,
+				      DRM_MODE_ENCODER_DSI);
+	if (ret) {
+		dev_err(dsi->dev, "Couldn't initialise the DSI encoder\n");
+		return ret;
+	}
+	dsi->encoder.possible_crtcs = BIT(0);
+
+	drm_connector_helper_add(&dsi->connector,
+				 &sun6i_dsi_connector_helper_funcs);
+	ret = drm_connector_init(drm, &dsi->connector,
+				 &sun6i_dsi_connector_funcs,
+				 DRM_MODE_CONNECTOR_DSI);
+	if (ret) {
+		dev_err(dsi->dev,
+			"Couldn't initialise the DSI connector\n");
+		goto err_cleanup_connector;
+	}
+
+	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
+
+	return 0;
+
+err_cleanup_connector:
+	drm_encoder_cleanup(&dsi->encoder);
+	return ret;
+}
+
+static void sun6i_dsi_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+
+	drm_encoder_cleanup(&dsi->encoder);
+}
+
+static const struct component_ops sun6i_dsi_ops = {
+	.bind	= sun6i_dsi_bind,
+	.unbind	= sun6i_dsi_unbind,
+};
+
 static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 			    struct mipi_dsi_device *device)
 {
 	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
 	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
+	int ret;
 
 	if (IS_ERR(panel))
 		return PTR_ERR(panel);
@@ -973,6 +1024,13 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 
 	dev_info(host->dev, "Attached device %s\n", device->name);
 
+	ret = component_add(dsi->dev, &sun6i_dsi_ops);
+	if (ret) {
+		dev_err(dsi->dev, "Couldn't register our component\n");
+		mipi_dsi_host_unregister(&dsi->host);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -984,6 +1042,8 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
 	dsi->panel = NULL;
 	dsi->device = NULL;
 
+	component_del(dsi->dev, &sun6i_dsi_ops);
+
 	return 0;
 }
 
@@ -1041,56 +1101,6 @@ static const struct regmap_config sun6i_dsi_regmap_config = {
 	.name		= "mipi-dsi",
 };
 
-static int sun6i_dsi_bind(struct device *dev, struct device *master,
-			 void *data)
-{
-	struct drm_device *drm = data;
-	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
-	int ret;
-
-	drm_encoder_helper_add(&dsi->encoder,
-			       &sun6i_dsi_enc_helper_funcs);
-	ret = drm_simple_encoder_init(drm, &dsi->encoder,
-				      DRM_MODE_ENCODER_DSI);
-	if (ret) {
-		dev_err(dsi->dev, "Couldn't initialise the DSI encoder\n");
-		return ret;
-	}
-	dsi->encoder.possible_crtcs = BIT(0);
-
-	drm_connector_helper_add(&dsi->connector,
-				 &sun6i_dsi_connector_helper_funcs);
-	ret = drm_connector_init(drm, &dsi->connector,
-				 &sun6i_dsi_connector_funcs,
-				 DRM_MODE_CONNECTOR_DSI);
-	if (ret) {
-		dev_err(dsi->dev,
-			"Couldn't initialise the DSI connector\n");
-		goto err_cleanup_connector;
-	}
-
-	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
-
-	return 0;
-
-err_cleanup_connector:
-	drm_encoder_cleanup(&dsi->encoder);
-	return ret;
-}
-
-static void sun6i_dsi_unbind(struct device *dev, struct device *master,
-			    void *data)
-{
-	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
-
-	drm_encoder_cleanup(&dsi->encoder);
-}
-
-static const struct component_ops sun6i_dsi_ops = {
-	.bind	= sun6i_dsi_bind,
-	.unbind	= sun6i_dsi_unbind,
-};
-
 static int sun6i_dsi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1172,16 +1182,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
 		goto err_unprotect_clk;
 	}
 
-	ret = component_add(&pdev->dev, &sun6i_dsi_ops);
-	if (ret) {
-		dev_err(dev, "Couldn't register our component\n");
-		goto err_remove_dsi_host;
-	}
-
 	return 0;
 
-err_remove_dsi_host:
-	mipi_dsi_host_unregister(&dsi->host);
 err_unprotect_clk:
 	clk_rate_exclusive_put(dsi->mod_clk);
 err_attach_clk:
@@ -1195,7 +1197,6 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
 
-	component_del(&pdev->dev, &sun6i_dsi_ops);
 	mipi_dsi_host_unregister(&dsi->host);
 	clk_rate_exclusive_put(dsi->mod_clk);
 
-- 
2.25.1


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

* [PATCH v5 2/7] drm: sun4i: dsi: Add component only once DSI device attached
@ 2021-11-22  6:52   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

Having component_add for running all drm bind callbacks returns
error or unbound due to chain of DSI devices connected across
bridge topology on a display pipeline.

In a typical bridge oriented display pipeline where the host is
connected to the bridge converter and that indeed connected to
a panel.

DRM => SUN6I DSI Host => Chipone ICN6211 => BananaPi Panel

The bridge converter is looking for a panel to probe first and
then attach the host. The host attach is looking for a bridge
converter to probe and preserve bridge pointer, at this movement
the host is trying to bind the all callbacks and one of the bind
callback in the DSI host is trying to find the bridge using the
bridge pointer in sun6i_dsi_attach call.

chipone_probe().start
    drm_of_find_panel_or_bridge
        mipi_dsi_attach
             sun6i_dsi_attach
                 drm_of_find_panel_or_bridge
chipone_probe().done

sun6i_dsi_probe().start
    mipi_dsi_host_register
        component_add
sun6i_dsi_probe().done

However, the movement when panel defers the probe, will make the
bridge converter defer the host attach call which eventually found
a NULL bridge pointer during DSI component bind callback.

So, in order to prevent this scenario of binding invalid bridge,
wait for DSI devices on the pipeline to probe first and start the
binding process by moving component_add in host probe to attach call.

chipone_probe().start
    drm_of_find_panel_or_bridge
        mipi_dsi_attach
             sun6i_dsi_attach
                 drm_of_find_panel_or_bridge
      		      component_add
chipone_probe().done

sun6i_dsi_probe().start
    mipi_dsi_host_register
sun6i_dsi_probe().done

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- new patch

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 119 +++++++++++++------------
 1 file changed, 60 insertions(+), 59 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 4bdcce8f1d84..43d9c9e5198d 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -959,11 +959,62 @@ static int sun6i_dsi_dcs_read(struct sun6i_dsi *dsi,
 	return 1;
 }
 
+static int sun6i_dsi_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	struct drm_device *drm = data;
+	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+	int ret;
+
+	drm_encoder_helper_add(&dsi->encoder,
+			       &sun6i_dsi_enc_helper_funcs);
+	ret = drm_simple_encoder_init(drm, &dsi->encoder,
+				      DRM_MODE_ENCODER_DSI);
+	if (ret) {
+		dev_err(dsi->dev, "Couldn't initialise the DSI encoder\n");
+		return ret;
+	}
+	dsi->encoder.possible_crtcs = BIT(0);
+
+	drm_connector_helper_add(&dsi->connector,
+				 &sun6i_dsi_connector_helper_funcs);
+	ret = drm_connector_init(drm, &dsi->connector,
+				 &sun6i_dsi_connector_funcs,
+				 DRM_MODE_CONNECTOR_DSI);
+	if (ret) {
+		dev_err(dsi->dev,
+			"Couldn't initialise the DSI connector\n");
+		goto err_cleanup_connector;
+	}
+
+	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
+
+	return 0;
+
+err_cleanup_connector:
+	drm_encoder_cleanup(&dsi->encoder);
+	return ret;
+}
+
+static void sun6i_dsi_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
+
+	drm_encoder_cleanup(&dsi->encoder);
+}
+
+static const struct component_ops sun6i_dsi_ops = {
+	.bind	= sun6i_dsi_bind,
+	.unbind	= sun6i_dsi_unbind,
+};
+
 static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 			    struct mipi_dsi_device *device)
 {
 	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
 	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
+	int ret;
 
 	if (IS_ERR(panel))
 		return PTR_ERR(panel);
@@ -973,6 +1024,13 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 
 	dev_info(host->dev, "Attached device %s\n", device->name);
 
+	ret = component_add(dsi->dev, &sun6i_dsi_ops);
+	if (ret) {
+		dev_err(dsi->dev, "Couldn't register our component\n");
+		mipi_dsi_host_unregister(&dsi->host);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -984,6 +1042,8 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
 	dsi->panel = NULL;
 	dsi->device = NULL;
 
+	component_del(dsi->dev, &sun6i_dsi_ops);
+
 	return 0;
 }
 
@@ -1041,56 +1101,6 @@ static const struct regmap_config sun6i_dsi_regmap_config = {
 	.name		= "mipi-dsi",
 };
 
-static int sun6i_dsi_bind(struct device *dev, struct device *master,
-			 void *data)
-{
-	struct drm_device *drm = data;
-	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
-	int ret;
-
-	drm_encoder_helper_add(&dsi->encoder,
-			       &sun6i_dsi_enc_helper_funcs);
-	ret = drm_simple_encoder_init(drm, &dsi->encoder,
-				      DRM_MODE_ENCODER_DSI);
-	if (ret) {
-		dev_err(dsi->dev, "Couldn't initialise the DSI encoder\n");
-		return ret;
-	}
-	dsi->encoder.possible_crtcs = BIT(0);
-
-	drm_connector_helper_add(&dsi->connector,
-				 &sun6i_dsi_connector_helper_funcs);
-	ret = drm_connector_init(drm, &dsi->connector,
-				 &sun6i_dsi_connector_funcs,
-				 DRM_MODE_CONNECTOR_DSI);
-	if (ret) {
-		dev_err(dsi->dev,
-			"Couldn't initialise the DSI connector\n");
-		goto err_cleanup_connector;
-	}
-
-	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
-
-	return 0;
-
-err_cleanup_connector:
-	drm_encoder_cleanup(&dsi->encoder);
-	return ret;
-}
-
-static void sun6i_dsi_unbind(struct device *dev, struct device *master,
-			    void *data)
-{
-	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
-
-	drm_encoder_cleanup(&dsi->encoder);
-}
-
-static const struct component_ops sun6i_dsi_ops = {
-	.bind	= sun6i_dsi_bind,
-	.unbind	= sun6i_dsi_unbind,
-};
-
 static int sun6i_dsi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1172,16 +1182,8 @@ static int sun6i_dsi_probe(struct platform_device *pdev)
 		goto err_unprotect_clk;
 	}
 
-	ret = component_add(&pdev->dev, &sun6i_dsi_ops);
-	if (ret) {
-		dev_err(dev, "Couldn't register our component\n");
-		goto err_remove_dsi_host;
-	}
-
 	return 0;
 
-err_remove_dsi_host:
-	mipi_dsi_host_unregister(&dsi->host);
 err_unprotect_clk:
 	clk_rate_exclusive_put(dsi->mod_clk);
 err_attach_clk:
@@ -1195,7 +1197,6 @@ static int sun6i_dsi_remove(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
 
-	component_del(&pdev->dev, &sun6i_dsi_ops);
 	mipi_dsi_host_unregister(&dsi->host);
 	clk_rate_exclusive_put(dsi->mod_clk);
 
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22  6:52 ` Jagan Teki
@ 2021-11-22  6:52   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

Some display panels would come up with a non-DSI output, those
can have an option to connect the DSI host by means of interface
bridge converter.

This DSI to non-DSI interface bridge converter would requires
DSI Host to handle drm bridge functionalities in order to DSI
Host to Interface bridge.

This patch convert the existing to a drm bridge driver with a
built-in encoder support for compatibility with existing
component drivers.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- add atomic APIs
- find host and device variant DSI devices.
Changes for v4, v3:
- none

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
 2 files changed, 96 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 43d9c9e5198d..a6a272b55f77 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -21,6 +21,7 @@
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
@@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
 	return 0;
 }
 
-static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
+static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
+					   struct drm_bridge_state *old_bridge_state)
 {
-	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
-	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
+	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
 	struct mipi_dsi_device *device = dsi->device;
 	union phy_configure_opts opts = { };
 	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
@@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
 	if (dsi->panel)
 		drm_panel_prepare(dsi->panel);
 
+	if (dsi->next_bridge)
+		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
+
 	/*
 	 * FIXME: This should be moved after the switch to HS mode.
 	 *
@@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
 	if (dsi->panel)
 		drm_panel_enable(dsi->panel);
 
+	if (dsi->next_bridge)
+		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
+
 	sun6i_dsi_start(dsi, DSI_START_HSC);
 
 	udelay(1000);
@@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
 	sun6i_dsi_start(dsi, DSI_START_HSD);
 }
 
-static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
+static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
+					    struct drm_bridge_state *old_bridge_state)
 {
-	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
 
 	DRM_DEBUG_DRIVER("Disabling DSI output\n");
 
 	if (dsi->panel) {
 		drm_panel_disable(dsi->panel);
 		drm_panel_unprepare(dsi->panel);
+	} else if (dsi->next_bridge) {
+		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
+		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
 	}
 
 	phy_power_off(dsi->dphy);
@@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
 };
 
-static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
-	.disable	= sun6i_dsi_encoder_disable,
-	.enable		= sun6i_dsi_encoder_enable,
+static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
+				   enum drm_bridge_attach_flags flags)
+{
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
+
+	if (dsi->next_bridge)
+		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
+					 NULL, 0);
+
+	return 0;
+}
+
+static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
+	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
+	.atomic_reset		= drm_atomic_helper_bridge_reset,
+	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
+	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
+	.attach			= sun6i_dsi_bridge_attach,
 };
 
 static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
@@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
 	int ret;
 
-	drm_encoder_helper_add(&dsi->encoder,
-			       &sun6i_dsi_enc_helper_funcs);
 	ret = drm_simple_encoder_init(drm, &dsi->encoder,
 				      DRM_MODE_ENCODER_DSI);
 	if (ret) {
@@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 	}
 	dsi->encoder.possible_crtcs = BIT(0);
 
-	drm_connector_helper_add(&dsi->connector,
-				 &sun6i_dsi_connector_helper_funcs);
-	ret = drm_connector_init(drm, &dsi->connector,
-				 &sun6i_dsi_connector_funcs,
-				 DRM_MODE_CONNECTOR_DSI);
+	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
 	if (ret) {
-		dev_err(dsi->dev,
-			"Couldn't initialise the DSI connector\n");
+		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
 		goto err_cleanup_connector;
 	}
 
-	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
+	if (dsi->panel) {
+		drm_connector_helper_add(&dsi->connector,
+					 &sun6i_dsi_connector_helper_funcs);
+		ret = drm_connector_init(drm, &dsi->connector,
+					 &sun6i_dsi_connector_funcs,
+					 DRM_MODE_CONNECTOR_DSI);
+		if (ret) {
+			dev_err(dsi->dev,
+				"Couldn't initialise the DSI connector\n");
+			goto err_cleanup_connector;
+		}
+
+		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
+	}
 
 	return 0;
 
@@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 			    struct mipi_dsi_device *device)
 {
 	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
-	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
+	struct device_node *remote = device->dev.of_node;
 	int ret;
 
-	if (IS_ERR(panel))
-		return PTR_ERR(panel);
+	if (!of_device_is_available(remote)) {
+		/**
+		 * I2C interfaced DSI bridges will register DSI host on the
+		 * bridge drivers instead of conventional device.
+		 *
+		 * Those are probed via host of_node instead of device of_node.
+		 */
+		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
+		if (!remote)
+			return -ENODEV;
+	}
+
+	dsi->panel = of_drm_find_panel(remote);
+	if (IS_ERR(dsi->panel)) {
+		dsi->panel = NULL;
+
+		dsi->next_bridge = of_drm_find_bridge(remote);
+		if (IS_ERR(dsi->next_bridge)) {
+			dev_err(dsi->dev, "failed to find bridge\n");
+			return PTR_ERR(dsi->next_bridge);
+		}
+	} else {
+		dsi->next_bridge = NULL;
+	}
+
+	of_node_put(remote);
 
-	dsi->panel = panel;
 	dsi->device = device;
 
-	dev_info(host->dev, "Attached device %s\n", device->name);
+	dev_info(host->dev, "Attached %s %s\n",
+		 device->name, dsi->panel ? "panel" : "bridge");
+
+	dsi->bridge.funcs = &sun6i_dsi_bridge_funcs;
+	dsi->bridge.of_node = dsi->dev->of_node;
+	dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+
+	drm_bridge_add(&dsi->bridge);
 
 	ret = component_add(dsi->dev, &sun6i_dsi_ops);
 	if (ret) {
@@ -1040,9 +1104,11 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
 	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
 
 	dsi->panel = NULL;
+	dsi->next_bridge = NULL;
 	dsi->device = NULL;
 
 	component_del(dsi->dev, &sun6i_dsi_ops);
+	drm_bridge_remove(&dsi->bridge);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index 61e88ea6044d..d269304691c9 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -16,6 +16,7 @@
 #define SUN6I_DSI_TCON_DIV	4
 
 struct sun6i_dsi {
+	struct drm_bridge	bridge;
 	struct drm_connector	connector;
 	struct drm_encoder	encoder;
 	struct mipi_dsi_host	host;
@@ -30,6 +31,7 @@ struct sun6i_dsi {
 	struct device		*dev;
 	struct mipi_dsi_device	*device;
 	struct drm_panel	*panel;
+	struct drm_bridge	*next_bridge;
 };
 
 static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
@@ -37,6 +39,11 @@ static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
 	return container_of(host, struct sun6i_dsi, host);
 };
 
+static inline struct sun6i_dsi *bridge_to_sun6i_dsi(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct sun6i_dsi, bridge);
+}
+
 static inline struct sun6i_dsi *connector_to_sun6i_dsi(struct drm_connector *connector)
 {
 	return container_of(connector, struct sun6i_dsi, connector);
-- 
2.25.1


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

* [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22  6:52   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

Some display panels would come up with a non-DSI output, those
can have an option to connect the DSI host by means of interface
bridge converter.

This DSI to non-DSI interface bridge converter would requires
DSI Host to handle drm bridge functionalities in order to DSI
Host to Interface bridge.

This patch convert the existing to a drm bridge driver with a
built-in encoder support for compatibility with existing
component drivers.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- add atomic APIs
- find host and device variant DSI devices.
Changes for v4, v3:
- none

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
 2 files changed, 96 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 43d9c9e5198d..a6a272b55f77 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -21,6 +21,7 @@
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
@@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
 	return 0;
 }
 
-static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
+static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
+					   struct drm_bridge_state *old_bridge_state)
 {
-	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
-	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
+	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
 	struct mipi_dsi_device *device = dsi->device;
 	union phy_configure_opts opts = { };
 	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
@@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
 	if (dsi->panel)
 		drm_panel_prepare(dsi->panel);
 
+	if (dsi->next_bridge)
+		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
+
 	/*
 	 * FIXME: This should be moved after the switch to HS mode.
 	 *
@@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
 	if (dsi->panel)
 		drm_panel_enable(dsi->panel);
 
+	if (dsi->next_bridge)
+		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
+
 	sun6i_dsi_start(dsi, DSI_START_HSC);
 
 	udelay(1000);
@@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
 	sun6i_dsi_start(dsi, DSI_START_HSD);
 }
 
-static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
+static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
+					    struct drm_bridge_state *old_bridge_state)
 {
-	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
 
 	DRM_DEBUG_DRIVER("Disabling DSI output\n");
 
 	if (dsi->panel) {
 		drm_panel_disable(dsi->panel);
 		drm_panel_unprepare(dsi->panel);
+	} else if (dsi->next_bridge) {
+		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
+		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
 	}
 
 	phy_power_off(dsi->dphy);
@@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
 };
 
-static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
-	.disable	= sun6i_dsi_encoder_disable,
-	.enable		= sun6i_dsi_encoder_enable,
+static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
+				   enum drm_bridge_attach_flags flags)
+{
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
+
+	if (dsi->next_bridge)
+		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
+					 NULL, 0);
+
+	return 0;
+}
+
+static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
+	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
+	.atomic_reset		= drm_atomic_helper_bridge_reset,
+	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
+	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
+	.attach			= sun6i_dsi_bridge_attach,
 };
 
 static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
@@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
 	int ret;
 
-	drm_encoder_helper_add(&dsi->encoder,
-			       &sun6i_dsi_enc_helper_funcs);
 	ret = drm_simple_encoder_init(drm, &dsi->encoder,
 				      DRM_MODE_ENCODER_DSI);
 	if (ret) {
@@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
 	}
 	dsi->encoder.possible_crtcs = BIT(0);
 
-	drm_connector_helper_add(&dsi->connector,
-				 &sun6i_dsi_connector_helper_funcs);
-	ret = drm_connector_init(drm, &dsi->connector,
-				 &sun6i_dsi_connector_funcs,
-				 DRM_MODE_CONNECTOR_DSI);
+	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
 	if (ret) {
-		dev_err(dsi->dev,
-			"Couldn't initialise the DSI connector\n");
+		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
 		goto err_cleanup_connector;
 	}
 
-	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
+	if (dsi->panel) {
+		drm_connector_helper_add(&dsi->connector,
+					 &sun6i_dsi_connector_helper_funcs);
+		ret = drm_connector_init(drm, &dsi->connector,
+					 &sun6i_dsi_connector_funcs,
+					 DRM_MODE_CONNECTOR_DSI);
+		if (ret) {
+			dev_err(dsi->dev,
+				"Couldn't initialise the DSI connector\n");
+			goto err_cleanup_connector;
+		}
+
+		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
+	}
 
 	return 0;
 
@@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
 			    struct mipi_dsi_device *device)
 {
 	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
-	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
+	struct device_node *remote = device->dev.of_node;
 	int ret;
 
-	if (IS_ERR(panel))
-		return PTR_ERR(panel);
+	if (!of_device_is_available(remote)) {
+		/**
+		 * I2C interfaced DSI bridges will register DSI host on the
+		 * bridge drivers instead of conventional device.
+		 *
+		 * Those are probed via host of_node instead of device of_node.
+		 */
+		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
+		if (!remote)
+			return -ENODEV;
+	}
+
+	dsi->panel = of_drm_find_panel(remote);
+	if (IS_ERR(dsi->panel)) {
+		dsi->panel = NULL;
+
+		dsi->next_bridge = of_drm_find_bridge(remote);
+		if (IS_ERR(dsi->next_bridge)) {
+			dev_err(dsi->dev, "failed to find bridge\n");
+			return PTR_ERR(dsi->next_bridge);
+		}
+	} else {
+		dsi->next_bridge = NULL;
+	}
+
+	of_node_put(remote);
 
-	dsi->panel = panel;
 	dsi->device = device;
 
-	dev_info(host->dev, "Attached device %s\n", device->name);
+	dev_info(host->dev, "Attached %s %s\n",
+		 device->name, dsi->panel ? "panel" : "bridge");
+
+	dsi->bridge.funcs = &sun6i_dsi_bridge_funcs;
+	dsi->bridge.of_node = dsi->dev->of_node;
+	dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+
+	drm_bridge_add(&dsi->bridge);
 
 	ret = component_add(dsi->dev, &sun6i_dsi_ops);
 	if (ret) {
@@ -1040,9 +1104,11 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
 	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
 
 	dsi->panel = NULL;
+	dsi->next_bridge = NULL;
 	dsi->device = NULL;
 
 	component_del(dsi->dev, &sun6i_dsi_ops);
+	drm_bridge_remove(&dsi->bridge);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index 61e88ea6044d..d269304691c9 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -16,6 +16,7 @@
 #define SUN6I_DSI_TCON_DIV	4
 
 struct sun6i_dsi {
+	struct drm_bridge	bridge;
 	struct drm_connector	connector;
 	struct drm_encoder	encoder;
 	struct mipi_dsi_host	host;
@@ -30,6 +31,7 @@ struct sun6i_dsi {
 	struct device		*dev;
 	struct mipi_dsi_device	*device;
 	struct drm_panel	*panel;
+	struct drm_bridge	*next_bridge;
 };
 
 static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
@@ -37,6 +39,11 @@ static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
 	return container_of(host, struct sun6i_dsi, host);
 };
 
+static inline struct sun6i_dsi *bridge_to_sun6i_dsi(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct sun6i_dsi, bridge);
+}
+
 static inline struct sun6i_dsi *connector_to_sun6i_dsi(struct drm_connector *connector)
 {
 	return container_of(connector, struct sun6i_dsi, connector);
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22  6:52 ` Jagan Teki
@ 2021-11-22  6:52   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

Get the display mode settings via mode_set bridge function
instead of explicitly de-reference.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- new patch

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 12 +++++++++++-
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |  1 +
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index a6a272b55f77..731af31e2bde 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -718,7 +718,7 @@ static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
 					   struct drm_bridge_state *old_bridge_state)
 {
 	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
-	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
+	struct drm_display_mode *mode = &dsi->mode;
 	struct mipi_dsi_device *device = dsi->device;
 	union phy_configure_opts opts = { };
 	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
@@ -854,6 +854,15 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
 };
 
+static void sun6i_dsi_bridge_mode_set(struct drm_bridge *bridge,
+				      const struct drm_display_mode *mode,
+				      const struct drm_display_mode *adjusted_mode)
+{
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
+
+	drm_mode_copy(&dsi->mode, adjusted_mode);
+}
+
 static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
 				   enum drm_bridge_attach_flags flags)
 {
@@ -872,6 +881,7 @@ static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
 	.atomic_reset		= drm_atomic_helper_bridge_reset,
 	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
 	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
+	.mode_set		= sun6i_dsi_bridge_mode_set,
 	.attach			= sun6i_dsi_bridge_attach,
 };
 
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index d269304691c9..acdd586a4157 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -20,6 +20,7 @@ struct sun6i_dsi {
 	struct drm_connector	connector;
 	struct drm_encoder	encoder;
 	struct mipi_dsi_host	host;
+	struct drm_display_mode	mode;
 
 	struct clk		*bus_clk;
 	struct clk		*mod_clk;
-- 
2.25.1


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

* [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22  6:52   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

Get the display mode settings via mode_set bridge function
instead of explicitly de-reference.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
Changes for v5:
- new patch

 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 12 +++++++++++-
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |  1 +
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index a6a272b55f77..731af31e2bde 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -718,7 +718,7 @@ static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
 					   struct drm_bridge_state *old_bridge_state)
 {
 	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
-	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
+	struct drm_display_mode *mode = &dsi->mode;
 	struct mipi_dsi_device *device = dsi->device;
 	union phy_configure_opts opts = { };
 	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
@@ -854,6 +854,15 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
 };
 
+static void sun6i_dsi_bridge_mode_set(struct drm_bridge *bridge,
+				      const struct drm_display_mode *mode,
+				      const struct drm_display_mode *adjusted_mode)
+{
+	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
+
+	drm_mode_copy(&dsi->mode, adjusted_mode);
+}
+
 static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
 				   enum drm_bridge_attach_flags flags)
 {
@@ -872,6 +881,7 @@ static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
 	.atomic_reset		= drm_atomic_helper_bridge_reset,
 	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
 	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
+	.mode_set		= sun6i_dsi_bridge_mode_set,
 	.attach			= sun6i_dsi_bridge_attach,
 };
 
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index d269304691c9..acdd586a4157 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -20,6 +20,7 @@ struct sun6i_dsi {
 	struct drm_connector	connector;
 	struct drm_encoder	encoder;
 	struct mipi_dsi_host	host;
+	struct drm_display_mode	mode;
 
 	struct clk		*bus_clk;
 	struct clk		*mod_clk;
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [DO NOT MERGE] [PATCH v5 5/7] ARM: dts: sun8i: bananapi-m2m: Enable S070WV20-CT16 Panel
  2021-11-22  6:52 ` Jagan Teki
@ 2021-11-22  6:52   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

This patch add support for Bananapi S070WV20-CT16 panel to
BPI-M2M board.

This specific DSI Bananapi S070WV20-CT16 panel driver is not
available in upstream, added for testing purpose.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts | 40 ++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index bf5b5e2f6168..b215c32996a3 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -44,6 +44,7 @@
 #include "sun8i-a33.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
 
 / {
 	model = "BananaPi M2 Magic";
@@ -61,6 +62,14 @@ chosen {
 		stdout-path = "serial0:115200n8";
 	};
 
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+		brightness-levels = <1 2 4 8 16 32 64 128 255>;
+		default-brightness-level = <8>;
+		enable-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* LCD-BL-EN: PL4 */
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
@@ -122,6 +131,27 @@ &dai {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&dphy {
+	status = "okay";
+};
+
+&dsi {
+	vcc-dsi-supply = <&reg_dcdc1>;		/* VCC-DSI */
+	status = "okay";
+
+	panel@0 {
+		compatible = "bananapi,s070wv20-ct16-icn6211";
+		reg = <0>;
+		reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
+		enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
+		backlight = <&backlight>;
+	};
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -157,6 +187,12 @@ &ohci0 {
 	status = "okay";
 };
 
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin>;
+	status = "okay";
+};
+
 &r_rsb {
 	status = "okay";
 
@@ -269,6 +305,10 @@ &sound {
 	status = "okay";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pb_pins>;
-- 
2.25.1


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

* [DO NOT MERGE] [PATCH v5 5/7] ARM: dts: sun8i: bananapi-m2m: Enable S070WV20-CT16 Panel
@ 2021-11-22  6:52   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

This patch add support for Bananapi S070WV20-CT16 panel to
BPI-M2M board.

This specific DSI Bananapi S070WV20-CT16 panel driver is not
available in upstream, added for testing purpose.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts | 40 ++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index bf5b5e2f6168..b215c32996a3 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -44,6 +44,7 @@
 #include "sun8i-a33.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
 
 / {
 	model = "BananaPi M2 Magic";
@@ -61,6 +62,14 @@ chosen {
 		stdout-path = "serial0:115200n8";
 	};
 
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+		brightness-levels = <1 2 4 8 16 32 64 128 255>;
+		default-brightness-level = <8>;
+		enable-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* LCD-BL-EN: PL4 */
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
@@ -122,6 +131,27 @@ &dai {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&dphy {
+	status = "okay";
+};
+
+&dsi {
+	vcc-dsi-supply = <&reg_dcdc1>;		/* VCC-DSI */
+	status = "okay";
+
+	panel@0 {
+		compatible = "bananapi,s070wv20-ct16-icn6211";
+		reg = <0>;
+		reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
+		enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
+		backlight = <&backlight>;
+	};
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -157,6 +187,12 @@ &ohci0 {
 	status = "okay";
 };
 
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin>;
+	status = "okay";
+};
+
 &r_rsb {
 	status = "okay";
 
@@ -269,6 +305,10 @@ &sound {
 	status = "okay";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pb_pins>;
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [DO NOT MERGE] [PATCH v5 6/7] ARM: dts: sun8i: bananapi-m2m: Enable ICN6211 DSI Bridge
  2021-11-22  6:52 ` Jagan Teki
@ 2021-11-22  6:52   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

Bananapi S070WV20-CT16 is a pure RGB output panel with ICN6211
DSI/RGB convertor bridge.

Enable bridge along with associated panel.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts | 63 ++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index bf5b5e2f6168..da6c1f2a0c74 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -44,6 +44,7 @@
 #include "sun8i-a33.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
 
 / {
 	model = "BananaPi M2 Magic";
@@ -61,6 +62,14 @@ chosen {
 		stdout-path = "serial0:115200n8";
 	};
 
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+		brightness-levels = <1 2 4 8 16 32 64 128 255>;
+		default-brightness-level = <8>;
+		enable-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* LCD-BL-EN: PL4 */
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
@@ -81,6 +90,18 @@ led-2 {
 		};
 	};
 
+	panel {
+		compatible = "bananapi,s070wv20-ct16";
+		enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
+		backlight = <&backlight>;
+
+		port {
+			panel_out_bridge: endpoint {
+				remote-endpoint = <&bridge_out_panel>;
+			};
+		};
+	};
+
 	reg_vcc5v0: vcc5v0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc5v0";
@@ -122,6 +143,38 @@ &dai {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&dphy {
+	status = "okay";
+};
+
+&dsi {
+	vcc-dsi-supply = <&reg_dcdc1>;		/* VCC-DSI */
+	status = "okay";
+
+	bridge@0 {
+		compatible = "chipone,icn6211";
+		reg = <0>;
+		enable-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			bridge_out: port@1 {
+				reg = <1>;
+
+				bridge_out_panel: endpoint {
+					remote-endpoint = <&panel_out_bridge>;
+				};
+			};
+		};
+	};
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -157,6 +210,12 @@ &ohci0 {
 	status = "okay";
 };
 
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin>;
+	status = "okay";
+};
+
 &r_rsb {
 	status = "okay";
 
@@ -269,6 +328,10 @@ &sound {
 	status = "okay";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pb_pins>;
-- 
2.25.1


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

* [DO NOT MERGE] [PATCH v5 6/7] ARM: dts: sun8i: bananapi-m2m: Enable ICN6211 DSI Bridge
@ 2021-11-22  6:52   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

Bananapi S070WV20-CT16 is a pure RGB output panel with ICN6211
DSI/RGB convertor bridge.

Enable bridge along with associated panel.

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts | 63 ++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index bf5b5e2f6168..da6c1f2a0c74 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -44,6 +44,7 @@
 #include "sun8i-a33.dtsi"
 
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pwm/pwm.h>
 
 / {
 	model = "BananaPi M2 Magic";
@@ -61,6 +62,14 @@ chosen {
 		stdout-path = "serial0:115200n8";
 	};
 
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+		brightness-levels = <1 2 4 8 16 32 64 128 255>;
+		default-brightness-level = <8>;
+		enable-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* LCD-BL-EN: PL4 */
+	};
+
 	leds {
 		compatible = "gpio-leds";
 
@@ -81,6 +90,18 @@ led-2 {
 		};
 	};
 
+	panel {
+		compatible = "bananapi,s070wv20-ct16";
+		enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
+		backlight = <&backlight>;
+
+		port {
+			panel_out_bridge: endpoint {
+				remote-endpoint = <&bridge_out_panel>;
+			};
+		};
+	};
+
 	reg_vcc5v0: vcc5v0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc5v0";
@@ -122,6 +143,38 @@ &dai {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&dphy {
+	status = "okay";
+};
+
+&dsi {
+	vcc-dsi-supply = <&reg_dcdc1>;		/* VCC-DSI */
+	status = "okay";
+
+	bridge@0 {
+		compatible = "chipone,icn6211";
+		reg = <0>;
+		enable-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			bridge_out: port@1 {
+				reg = <1>;
+
+				bridge_out_panel: endpoint {
+					remote-endpoint = <&panel_out_bridge>;
+				};
+			};
+		};
+	};
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -157,6 +210,12 @@ &ohci0 {
 	status = "okay";
 };
 
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin>;
+	status = "okay";
+};
+
 &r_rsb {
 	status = "okay";
 
@@ -269,6 +328,10 @@ &sound {
 	status = "okay";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pb_pins>;
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [DO NOT MERGE] [PATCH v5 7/7] ARM: dts: sun8i: Enable DLPC3433 Bridge (I2C)
  2021-11-22  6:52 ` Jagan Teki
@ 2021-11-22  6:52   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel, Jagan Teki

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 arch/arm/boot/dts/sun8i-r16-renew-vista-e.dts | 79 +++++++++++++++++--
 1 file changed, 73 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/sun8i-r16-renew-vista-e.dts b/arch/arm/boot/dts/sun8i-r16-renew-vista-e.dts
index d28b7b35a3c5..c3ee6a879ddb 100644
@@ -108,6 +102,17 @@ sel-lvds-mux {
 		};
 	};
 
+	panel {
+		compatible = "ti,dlpa3000a-720p";
+		/* backlight not required */
+
+		port {
+			panel_out_bridge: endpoint {
+				remote-endpoint = <&bridge_out_panel>;
+			};
+		};
+	};
+
 	reg_vcc5v0: vcc5v0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc5v0";
@@ -147,6 +152,32 @@ &dai {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&dphy {
+	status = "okay";
+};
+
+&dsi {
+	vcc-dsi-supply = <&reg_dcdc1>;		/* VCC-DSI */
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+
+			dsi_out_bridge: endpoint {
+				remote-endpoint = <&bridge_out_dsi>;
+			};
+		};
+	};
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -154,6 +185,38 @@ &ehci0 {
 &i2c1 {
 	clock-frequency = <100000>;
 	status = "okay";
+
+	bridge@1d {
+		compatible = "ti,dlpc3433";
+		reg = <0x1d>;
+		enable-gpios = <&pio 4 15 GPIO_ACTIVE_HIGH>;
+		vcc-supply = <&reg_dldo1>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			bridge_in: port@0 {
+				reg = <0>;
+
+				bridge_out_dsi: endpoint {
+					remote-endpoint = <&dsi_out_bridge>;
+					data-lanes = <0 1 2 3>;
+				};
+			};
+
+			bridge_out: port@1 {
+				reg = <1>;
+
+				bridge_out_panel: endpoint {
+					remote-endpoint = <&panel_out_bridge>;
+				};
+			};
+		};
+	};
 };
 
 &i2c2 {
@@ -321,6 +384,10 @@ &sound {
 		"Right DAC", "AIF1 Slot 0 Right";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pb_pins>;
-- 
2.25.1


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

* [DO NOT MERGE] [PATCH v5 7/7] ARM: dts: sun8i: Enable DLPC3433 Bridge (I2C)
@ 2021-11-22  6:52   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22  6:52 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula, Jagan Teki

Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 arch/arm/boot/dts/sun8i-r16-renew-vista-e.dts | 79 +++++++++++++++++--
 1 file changed, 73 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/sun8i-r16-renew-vista-e.dts b/arch/arm/boot/dts/sun8i-r16-renew-vista-e.dts
index d28b7b35a3c5..c3ee6a879ddb 100644
@@ -108,6 +102,17 @@ sel-lvds-mux {
 		};
 	};
 
+	panel {
+		compatible = "ti,dlpa3000a-720p";
+		/* backlight not required */
+
+		port {
+			panel_out_bridge: endpoint {
+				remote-endpoint = <&bridge_out_panel>;
+			};
+		};
+	};
+
 	reg_vcc5v0: vcc5v0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc5v0";
@@ -147,6 +152,32 @@ &dai {
 	status = "okay";
 };
 
+&de {
+	status = "okay";
+};
+
+&dphy {
+	status = "okay";
+};
+
+&dsi {
+	vcc-dsi-supply = <&reg_dcdc1>;		/* VCC-DSI */
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+
+			dsi_out_bridge: endpoint {
+				remote-endpoint = <&bridge_out_dsi>;
+			};
+		};
+	};
+};
+
 &ehci0 {
 	status = "okay";
 };
@@ -154,6 +185,38 @@ &ehci0 {
 &i2c1 {
 	clock-frequency = <100000>;
 	status = "okay";
+
+	bridge@1d {
+		compatible = "ti,dlpc3433";
+		reg = <0x1d>;
+		enable-gpios = <&pio 4 15 GPIO_ACTIVE_HIGH>;
+		vcc-supply = <&reg_dldo1>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			bridge_in: port@0 {
+				reg = <0>;
+
+				bridge_out_dsi: endpoint {
+					remote-endpoint = <&dsi_out_bridge>;
+					data-lanes = <0 1 2 3>;
+				};
+			};
+
+			bridge_out: port@1 {
+				reg = <1>;
+
+				bridge_out_panel: endpoint {
+					remote-endpoint = <&panel_out_bridge>;
+				};
+			};
+		};
+	};
 };
 
 &i2c2 {
@@ -321,6 +384,10 @@ &sound {
 		"Right DAC", "AIF1 Slot 0 Right";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_pb_pins>;
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22  6:52   ` Jagan Teki
@ 2021-11-22 10:07     ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 10:07 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 7948 bytes --]

On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> Some display panels would come up with a non-DSI output, those
> can have an option to connect the DSI host by means of interface
> bridge converter.
> 
> This DSI to non-DSI interface bridge converter would requires
> DSI Host to handle drm bridge functionalities in order to DSI
> Host to Interface bridge.

In order to do this you would need to use the DRM bridge API...

> This patch convert the existing to a drm bridge driver with a
> built-in encoder support for compatibility with existing
> component drivers.

... but changing the encoder driver to a bridge is completely
unnecessary to do so. Why did you need to make that change?

> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
>
> ---
> Changes for v5:
> - add atomic APIs
> - find host and device variant DSI devices.
> Changes for v4, v3:
> - none
> 
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>  2 files changed, 96 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> index 43d9c9e5198d..a6a272b55f77 100644
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> @@ -21,6 +21,7 @@
>  
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>  	return 0;
>  }
>  
> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> +					   struct drm_bridge_state *old_bridge_state)
>  {
> -	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>  	struct mipi_dsi_device *device = dsi->device;
>  	union phy_configure_opts opts = { };
>  	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_prepare(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> +

Please use the proper helpers.

>  	/*
>  	 * FIXME: This should be moved after the switch to HS mode.
>  	 *
> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_enable(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> +

Ditto

>  	sun6i_dsi_start(dsi, DSI_START_HSC);
>  
>  	udelay(1000);
> @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	sun6i_dsi_start(dsi, DSI_START_HSD);
>  }
>  
> -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> +					    struct drm_bridge_state *old_bridge_state)
>  {
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>  
>  	DRM_DEBUG_DRIVER("Disabling DSI output\n");
>  
>  	if (dsi->panel) {
>  		drm_panel_disable(dsi->panel);
>  		drm_panel_unprepare(dsi->panel);
> +	} else if (dsi->next_bridge) {
> +		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> +		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);

Ditto

>  	}
>  
>  	phy_power_off(dsi->dphy);
> @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
>  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
>  };
>  
> -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> -	.disable	= sun6i_dsi_encoder_disable,
> -	.enable		= sun6i_dsi_encoder_enable,
> +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> +				   enum drm_bridge_attach_flags flags)
> +{
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +
> +	if (dsi->next_bridge)
> +		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> +					 NULL, 0);
> +
> +	return 0;
> +}
> +
> +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
> +	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
> +	.attach			= sun6i_dsi_bridge_attach,
>  };
>  
>  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
>  	int ret;
>  
> -	drm_encoder_helper_add(&dsi->encoder,
> -			       &sun6i_dsi_enc_helper_funcs);
>  	ret = drm_simple_encoder_init(drm, &dsi->encoder,
>  				      DRM_MODE_ENCODER_DSI);
>  	if (ret) {
> @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	}
>  	dsi->encoder.possible_crtcs = BIT(0);
>  
> -	drm_connector_helper_add(&dsi->connector,
> -				 &sun6i_dsi_connector_helper_funcs);
> -	ret = drm_connector_init(drm, &dsi->connector,
> -				 &sun6i_dsi_connector_funcs,
> -				 DRM_MODE_CONNECTOR_DSI);
> +	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
>  	if (ret) {
> -		dev_err(dsi->dev,
> -			"Couldn't initialise the DSI connector\n");
> +		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
>  		goto err_cleanup_connector;
>  	}
>  
> -	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	if (dsi->panel) {
> +		drm_connector_helper_add(&dsi->connector,
> +					 &sun6i_dsi_connector_helper_funcs);
> +		ret = drm_connector_init(drm, &dsi->connector,
> +					 &sun6i_dsi_connector_funcs,
> +					 DRM_MODE_CONNECTOR_DSI);
> +		if (ret) {
> +			dev_err(dsi->dev,
> +				"Couldn't initialise the DSI connector\n");
> +			goto err_cleanup_connector;
> +		}
> +
> +		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	}
>  
>  	return 0;
>  
> @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
>  			    struct mipi_dsi_device *device)
>  {
>  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> -	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> +	struct device_node *remote = device->dev.of_node;
>  	int ret;
>  
> -	if (IS_ERR(panel))
> -		return PTR_ERR(panel);
> +	if (!of_device_is_available(remote)) {
> +		/**
> +		 * I2C interfaced DSI bridges will register DSI host on the
> +		 * bridge drivers instead of conventional device.
> +		 *
> +		 * Those are probed via host of_node instead of device of_node.
> +		 */

I have no idea what you mean here. Can you expand on what issue you've
tried to solve here?

> +		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> +		if (!remote)
> +			return -ENODEV;
> +	}
> +
> +	dsi->panel = of_drm_find_panel(remote);
> +	if (IS_ERR(dsi->panel)) {
> +		dsi->panel = NULL;
> +
> +		dsi->next_bridge = of_drm_find_bridge(remote);
> +		if (IS_ERR(dsi->next_bridge)) {
> +			dev_err(dsi->dev, "failed to find bridge\n");
> +			return PTR_ERR(dsi->next_bridge);
> +		}
> +	} else {
> +		dsi->next_bridge = NULL;
> +	}
> +
> +	of_node_put(remote);

Using devm_drm_of_get_bridge would greatly simplify the driver

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 10:07     ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 10:07 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula


[-- Attachment #1.1: Type: text/plain, Size: 7948 bytes --]

On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> Some display panels would come up with a non-DSI output, those
> can have an option to connect the DSI host by means of interface
> bridge converter.
> 
> This DSI to non-DSI interface bridge converter would requires
> DSI Host to handle drm bridge functionalities in order to DSI
> Host to Interface bridge.

In order to do this you would need to use the DRM bridge API...

> This patch convert the existing to a drm bridge driver with a
> built-in encoder support for compatibility with existing
> component drivers.

... but changing the encoder driver to a bridge is completely
unnecessary to do so. Why did you need to make that change?

> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
>
> ---
> Changes for v5:
> - add atomic APIs
> - find host and device variant DSI devices.
> Changes for v4, v3:
> - none
> 
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>  2 files changed, 96 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> index 43d9c9e5198d..a6a272b55f77 100644
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> @@ -21,6 +21,7 @@
>  
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>  	return 0;
>  }
>  
> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> +					   struct drm_bridge_state *old_bridge_state)
>  {
> -	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>  	struct mipi_dsi_device *device = dsi->device;
>  	union phy_configure_opts opts = { };
>  	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_prepare(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> +

Please use the proper helpers.

>  	/*
>  	 * FIXME: This should be moved after the switch to HS mode.
>  	 *
> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_enable(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> +

Ditto

>  	sun6i_dsi_start(dsi, DSI_START_HSC);
>  
>  	udelay(1000);
> @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	sun6i_dsi_start(dsi, DSI_START_HSD);
>  }
>  
> -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> +					    struct drm_bridge_state *old_bridge_state)
>  {
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>  
>  	DRM_DEBUG_DRIVER("Disabling DSI output\n");
>  
>  	if (dsi->panel) {
>  		drm_panel_disable(dsi->panel);
>  		drm_panel_unprepare(dsi->panel);
> +	} else if (dsi->next_bridge) {
> +		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> +		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);

Ditto

>  	}
>  
>  	phy_power_off(dsi->dphy);
> @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
>  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
>  };
>  
> -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> -	.disable	= sun6i_dsi_encoder_disable,
> -	.enable		= sun6i_dsi_encoder_enable,
> +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> +				   enum drm_bridge_attach_flags flags)
> +{
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +
> +	if (dsi->next_bridge)
> +		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> +					 NULL, 0);
> +
> +	return 0;
> +}
> +
> +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
> +	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
> +	.attach			= sun6i_dsi_bridge_attach,
>  };
>  
>  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
>  	int ret;
>  
> -	drm_encoder_helper_add(&dsi->encoder,
> -			       &sun6i_dsi_enc_helper_funcs);
>  	ret = drm_simple_encoder_init(drm, &dsi->encoder,
>  				      DRM_MODE_ENCODER_DSI);
>  	if (ret) {
> @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	}
>  	dsi->encoder.possible_crtcs = BIT(0);
>  
> -	drm_connector_helper_add(&dsi->connector,
> -				 &sun6i_dsi_connector_helper_funcs);
> -	ret = drm_connector_init(drm, &dsi->connector,
> -				 &sun6i_dsi_connector_funcs,
> -				 DRM_MODE_CONNECTOR_DSI);
> +	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
>  	if (ret) {
> -		dev_err(dsi->dev,
> -			"Couldn't initialise the DSI connector\n");
> +		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
>  		goto err_cleanup_connector;
>  	}
>  
> -	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	if (dsi->panel) {
> +		drm_connector_helper_add(&dsi->connector,
> +					 &sun6i_dsi_connector_helper_funcs);
> +		ret = drm_connector_init(drm, &dsi->connector,
> +					 &sun6i_dsi_connector_funcs,
> +					 DRM_MODE_CONNECTOR_DSI);
> +		if (ret) {
> +			dev_err(dsi->dev,
> +				"Couldn't initialise the DSI connector\n");
> +			goto err_cleanup_connector;
> +		}
> +
> +		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	}
>  
>  	return 0;
>  
> @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
>  			    struct mipi_dsi_device *device)
>  {
>  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> -	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> +	struct device_node *remote = device->dev.of_node;
>  	int ret;
>  
> -	if (IS_ERR(panel))
> -		return PTR_ERR(panel);
> +	if (!of_device_is_available(remote)) {
> +		/**
> +		 * I2C interfaced DSI bridges will register DSI host on the
> +		 * bridge drivers instead of conventional device.
> +		 *
> +		 * Those are probed via host of_node instead of device of_node.
> +		 */

I have no idea what you mean here. Can you expand on what issue you've
tried to solve here?

> +		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> +		if (!remote)
> +			return -ENODEV;
> +	}
> +
> +	dsi->panel = of_drm_find_panel(remote);
> +	if (IS_ERR(dsi->panel)) {
> +		dsi->panel = NULL;
> +
> +		dsi->next_bridge = of_drm_find_bridge(remote);
> +		if (IS_ERR(dsi->next_bridge)) {
> +			dev_err(dsi->dev, "failed to find bridge\n");
> +			return PTR_ERR(dsi->next_bridge);
> +		}
> +	} else {
> +		dsi->next_bridge = NULL;
> +	}
> +
> +	of_node_put(remote);

Using devm_drm_of_get_bridge would greatly simplify the driver

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22  6:52   ` Jagan Teki
@ 2021-11-22 10:07     ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 10:07 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 210 bytes --]

On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> Get the display mode settings via mode_set bridge function
> instead of explicitly de-reference.

What's wrong with dereferencing the mode?

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 10:07     ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 10:07 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula


[-- Attachment #1.1: Type: text/plain, Size: 210 bytes --]

On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> Get the display mode settings via mode_set bridge function
> instead of explicitly de-reference.

What's wrong with dereferencing the mode?

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 10:07     ` Maxime Ripard
@ 2021-11-22 12:45       ` Laurent Pinchart
  -1 siblings, 0 replies; 72+ messages in thread
From: Laurent Pinchart @ 2021-11-22 12:45 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Jagan Teki, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

Hi Maxime,

On Mon, Nov 22, 2021 at 11:07:12AM +0100, Maxime Ripard wrote:
> On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > Some display panels would come up with a non-DSI output, those
> > can have an option to connect the DSI host by means of interface
> > bridge converter.
> > 
> > This DSI to non-DSI interface bridge converter would requires
> > DSI Host to handle drm bridge functionalities in order to DSI
> > Host to Interface bridge.
> 
> In order to do this you would need to use the DRM bridge API...
> 
> > This patch convert the existing to a drm bridge driver with a
> > built-in encoder support for compatibility with existing
> > component drivers.
> 
> ... but changing the encoder driver to a bridge is completely
> unnecessary to do so. Why did you need to make that change?
> 
> > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> >
> > ---
> > Changes for v5:
> > - add atomic APIs
> > - find host and device variant DSI devices.
> > Changes for v4, v3:
> > - none
> > 
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >  2 files changed, 96 insertions(+), 23 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > index 43d9c9e5198d..a6a272b55f77 100644
> > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > @@ -21,6 +21,7 @@
> >  
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_of.h>
> >  #include <drm/drm_panel.h>
> >  #include <drm/drm_print.h>
> >  #include <drm/drm_probe_helper.h>
> > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >  	return 0;
> >  }
> >  
> > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +					   struct drm_bridge_state *old_bridge_state)
> >  {
> > -	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >  	struct mipi_dsi_device *device = dsi->device;
> >  	union phy_configure_opts opts = { };
> >  	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >  	if (dsi->panel)
> >  		drm_panel_prepare(dsi->panel);
> >  
> > +	if (dsi->next_bridge)
> > +		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > +
> 
> Please use the proper helpers.

I don't know about this series in particular, but overall we try to move
encoders to bridge drivers in order to standardize on a single API. The
drm_encoder can't be removed as it's exposed to userspace, so it then
becomes a dumb encoder, without any operation implemented.

> >  	/*
> >  	 * FIXME: This should be moved after the switch to HS mode.
> >  	 *
> > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >  	if (dsi->panel)
> >  		drm_panel_enable(dsi->panel);
> >  
> > +	if (dsi->next_bridge)
> > +		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > +
> 
> Ditto
> 
> >  	sun6i_dsi_start(dsi, DSI_START_HSC);
> >  
> >  	udelay(1000);
> > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >  	sun6i_dsi_start(dsi, DSI_START_HSD);
> >  }
> >  
> > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > +					    struct drm_bridge_state *old_bridge_state)
> >  {
> > -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> >  
> >  	DRM_DEBUG_DRIVER("Disabling DSI output\n");
> >  
> >  	if (dsi->panel) {
> >  		drm_panel_disable(dsi->panel);
> >  		drm_panel_unprepare(dsi->panel);
> > +	} else if (dsi->next_bridge) {
> > +		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > +		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> 
> Ditto
> 
> >  	}
> >  
> >  	phy_power_off(dsi->dphy);
> > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> >  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > -	.disable	= sun6i_dsi_encoder_disable,
> > -	.enable		= sun6i_dsi_encoder_enable,
> > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > +				   enum drm_bridge_attach_flags flags)
> > +{
> > +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +
> > +	if (dsi->next_bridge)
> > +		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > +					 NULL, 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> > +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> > +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> > +	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
> > +	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
> > +	.attach			= sun6i_dsi_bridge_attach,
> >  };
> >  
> >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >  	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> >  	int ret;
> >  
> > -	drm_encoder_helper_add(&dsi->encoder,
> > -			       &sun6i_dsi_enc_helper_funcs);
> >  	ret = drm_simple_encoder_init(drm, &dsi->encoder,
> >  				      DRM_MODE_ENCODER_DSI);
> >  	if (ret) {
> > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >  	}
> >  	dsi->encoder.possible_crtcs = BIT(0);
> >  
> > -	drm_connector_helper_add(&dsi->connector,
> > -				 &sun6i_dsi_connector_helper_funcs);
> > -	ret = drm_connector_init(drm, &dsi->connector,
> > -				 &sun6i_dsi_connector_funcs,
> > -				 DRM_MODE_CONNECTOR_DSI);
> > +	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> >  	if (ret) {
> > -		dev_err(dsi->dev,
> > -			"Couldn't initialise the DSI connector\n");
> > +		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> >  		goto err_cleanup_connector;
> >  	}
> >  
> > -	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +	if (dsi->panel) {
> > +		drm_connector_helper_add(&dsi->connector,
> > +					 &sun6i_dsi_connector_helper_funcs);
> > +		ret = drm_connector_init(drm, &dsi->connector,
> > +					 &sun6i_dsi_connector_funcs,
> > +					 DRM_MODE_CONNECTOR_DSI);
> > +		if (ret) {
> > +			dev_err(dsi->dev,
> > +				"Couldn't initialise the DSI connector\n");
> > +			goto err_cleanup_connector;
> > +		}
> > +
> > +		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +	}
> >  
> >  	return 0;
> >  
> > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> >  			    struct mipi_dsi_device *device)
> >  {
> >  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > -	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > +	struct device_node *remote = device->dev.of_node;
> >  	int ret;
> >  
> > -	if (IS_ERR(panel))
> > -		return PTR_ERR(panel);
> > +	if (!of_device_is_available(remote)) {
> > +		/**
> > +		 * I2C interfaced DSI bridges will register DSI host on the
> > +		 * bridge drivers instead of conventional device.
> > +		 *
> > +		 * Those are probed via host of_node instead of device of_node.
> > +		 */
> 
> I have no idea what you mean here. Can you expand on what issue you've
> tried to solve here?
> 
> > +		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > +		if (!remote)
> > +			return -ENODEV;
> > +	}
> > +
> > +	dsi->panel = of_drm_find_panel(remote);
> > +	if (IS_ERR(dsi->panel)) {
> > +		dsi->panel = NULL;
> > +
> > +		dsi->next_bridge = of_drm_find_bridge(remote);
> > +		if (IS_ERR(dsi->next_bridge)) {
> > +			dev_err(dsi->dev, "failed to find bridge\n");
> > +			return PTR_ERR(dsi->next_bridge);
> > +		}
> > +	} else {
> > +		dsi->next_bridge = NULL;
> > +	}
> > +
> > +	of_node_put(remote);
> 
> Using devm_drm_of_get_bridge would greatly simplify the driver
> 
> Maxime



-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 12:45       ` Laurent Pinchart
  0 siblings, 0 replies; 72+ messages in thread
From: Laurent Pinchart @ 2021-11-22 12:45 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Jagan Teki, Chen-Yu Tsai, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi Maxime,

On Mon, Nov 22, 2021 at 11:07:12AM +0100, Maxime Ripard wrote:
> On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > Some display panels would come up with a non-DSI output, those
> > can have an option to connect the DSI host by means of interface
> > bridge converter.
> > 
> > This DSI to non-DSI interface bridge converter would requires
> > DSI Host to handle drm bridge functionalities in order to DSI
> > Host to Interface bridge.
> 
> In order to do this you would need to use the DRM bridge API...
> 
> > This patch convert the existing to a drm bridge driver with a
> > built-in encoder support for compatibility with existing
> > component drivers.
> 
> ... but changing the encoder driver to a bridge is completely
> unnecessary to do so. Why did you need to make that change?
> 
> > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> >
> > ---
> > Changes for v5:
> > - add atomic APIs
> > - find host and device variant DSI devices.
> > Changes for v4, v3:
> > - none
> > 
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >  2 files changed, 96 insertions(+), 23 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > index 43d9c9e5198d..a6a272b55f77 100644
> > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > @@ -21,6 +21,7 @@
> >  
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_of.h>
> >  #include <drm/drm_panel.h>
> >  #include <drm/drm_print.h>
> >  #include <drm/drm_probe_helper.h>
> > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >  	return 0;
> >  }
> >  
> > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +					   struct drm_bridge_state *old_bridge_state)
> >  {
> > -	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >  	struct mipi_dsi_device *device = dsi->device;
> >  	union phy_configure_opts opts = { };
> >  	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >  	if (dsi->panel)
> >  		drm_panel_prepare(dsi->panel);
> >  
> > +	if (dsi->next_bridge)
> > +		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > +
> 
> Please use the proper helpers.

I don't know about this series in particular, but overall we try to move
encoders to bridge drivers in order to standardize on a single API. The
drm_encoder can't be removed as it's exposed to userspace, so it then
becomes a dumb encoder, without any operation implemented.

> >  	/*
> >  	 * FIXME: This should be moved after the switch to HS mode.
> >  	 *
> > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >  	if (dsi->panel)
> >  		drm_panel_enable(dsi->panel);
> >  
> > +	if (dsi->next_bridge)
> > +		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > +
> 
> Ditto
> 
> >  	sun6i_dsi_start(dsi, DSI_START_HSC);
> >  
> >  	udelay(1000);
> > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >  	sun6i_dsi_start(dsi, DSI_START_HSD);
> >  }
> >  
> > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > +					    struct drm_bridge_state *old_bridge_state)
> >  {
> > -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> >  
> >  	DRM_DEBUG_DRIVER("Disabling DSI output\n");
> >  
> >  	if (dsi->panel) {
> >  		drm_panel_disable(dsi->panel);
> >  		drm_panel_unprepare(dsi->panel);
> > +	} else if (dsi->next_bridge) {
> > +		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > +		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> 
> Ditto
> 
> >  	}
> >  
> >  	phy_power_off(dsi->dphy);
> > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> >  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > -	.disable	= sun6i_dsi_encoder_disable,
> > -	.enable		= sun6i_dsi_encoder_enable,
> > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > +				   enum drm_bridge_attach_flags flags)
> > +{
> > +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +
> > +	if (dsi->next_bridge)
> > +		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > +					 NULL, 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> > +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> > +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> > +	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
> > +	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
> > +	.attach			= sun6i_dsi_bridge_attach,
> >  };
> >  
> >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >  	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> >  	int ret;
> >  
> > -	drm_encoder_helper_add(&dsi->encoder,
> > -			       &sun6i_dsi_enc_helper_funcs);
> >  	ret = drm_simple_encoder_init(drm, &dsi->encoder,
> >  				      DRM_MODE_ENCODER_DSI);
> >  	if (ret) {
> > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >  	}
> >  	dsi->encoder.possible_crtcs = BIT(0);
> >  
> > -	drm_connector_helper_add(&dsi->connector,
> > -				 &sun6i_dsi_connector_helper_funcs);
> > -	ret = drm_connector_init(drm, &dsi->connector,
> > -				 &sun6i_dsi_connector_funcs,
> > -				 DRM_MODE_CONNECTOR_DSI);
> > +	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> >  	if (ret) {
> > -		dev_err(dsi->dev,
> > -			"Couldn't initialise the DSI connector\n");
> > +		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> >  		goto err_cleanup_connector;
> >  	}
> >  
> > -	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +	if (dsi->panel) {
> > +		drm_connector_helper_add(&dsi->connector,
> > +					 &sun6i_dsi_connector_helper_funcs);
> > +		ret = drm_connector_init(drm, &dsi->connector,
> > +					 &sun6i_dsi_connector_funcs,
> > +					 DRM_MODE_CONNECTOR_DSI);
> > +		if (ret) {
> > +			dev_err(dsi->dev,
> > +				"Couldn't initialise the DSI connector\n");
> > +			goto err_cleanup_connector;
> > +		}
> > +
> > +		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +	}
> >  
> >  	return 0;
> >  
> > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> >  			    struct mipi_dsi_device *device)
> >  {
> >  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > -	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > +	struct device_node *remote = device->dev.of_node;
> >  	int ret;
> >  
> > -	if (IS_ERR(panel))
> > -		return PTR_ERR(panel);
> > +	if (!of_device_is_available(remote)) {
> > +		/**
> > +		 * I2C interfaced DSI bridges will register DSI host on the
> > +		 * bridge drivers instead of conventional device.
> > +		 *
> > +		 * Those are probed via host of_node instead of device of_node.
> > +		 */
> 
> I have no idea what you mean here. Can you expand on what issue you've
> tried to solve here?
> 
> > +		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > +		if (!remote)
> > +			return -ENODEV;
> > +	}
> > +
> > +	dsi->panel = of_drm_find_panel(remote);
> > +	if (IS_ERR(dsi->panel)) {
> > +		dsi->panel = NULL;
> > +
> > +		dsi->next_bridge = of_drm_find_bridge(remote);
> > +		if (IS_ERR(dsi->next_bridge)) {
> > +			dev_err(dsi->dev, "failed to find bridge\n");
> > +			return PTR_ERR(dsi->next_bridge);
> > +		}
> > +	} else {
> > +		dsi->next_bridge = NULL;
> > +	}
> > +
> > +	of_node_put(remote);
> 
> Using devm_drm_of_get_bridge would greatly simplify the driver
> 
> Maxime



-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22  6:52   ` Jagan Teki
@ 2021-11-22 12:52     ` Neil Armstrong
  -1 siblings, 0 replies; 72+ messages in thread
From: Neil Armstrong @ 2021-11-22 12:52 UTC (permalink / raw)
  To: Jagan Teki, Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart,
	Robert Foss, Sam Ravnborg
  Cc: linux-sunxi, linux-amarula, linux-arm-kernel, dri-devel

On 22/11/2021 07:52, Jagan Teki wrote:
> Some display panels would come up with a non-DSI output, those
> can have an option to connect the DSI host by means of interface
> bridge converter.
> 
> This DSI to non-DSI interface bridge converter would requires
> DSI Host to handle drm bridge functionalities in order to DSI
> Host to Interface bridge.
> 
> This patch convert the existing to a drm bridge driver with a
> built-in encoder support for compatibility with existing
> component drivers.
> 
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> ---
> Changes for v5:
> - add atomic APIs
> - find host and device variant DSI devices.
> Changes for v4, v3:
> - none
> 
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>  2 files changed, 96 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> index 43d9c9e5198d..a6a272b55f77 100644
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> @@ -21,6 +21,7 @@
>  
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>  	return 0;
>  }
>  
> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> +					   struct drm_bridge_state *old_bridge_state)
>  {
> -	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>  	struct mipi_dsi_device *device = dsi->device;
>  	union phy_configure_opts opts = { };
>  	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_prepare(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> +
>  	/*
>  	 * FIXME: This should be moved after the switch to HS mode.
>  	 *
> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_enable(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> +


No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
be called automatically on the bridge chain.

>  	sun6i_dsi_start(dsi, DSI_START_HSC);
>  
>  	udelay(1000);
> @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	sun6i_dsi_start(dsi, DSI_START_HSD);
>  }
>  
> -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> +					    struct drm_bridge_state *old_bridge_state)
>  {
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>  
>  	DRM_DEBUG_DRIVER("Disabling DSI output\n");
>  
>  	if (dsi->panel) {
>  		drm_panel_disable(dsi->panel);
>  		drm_panel_unprepare(dsi->panel);
> +	} else if (dsi->next_bridge) {
> +		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> +		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);

Ditto

>  	}
>  
>  	phy_power_off(dsi->dphy);
> @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
>  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
>  };
>  
> -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> -	.disable	= sun6i_dsi_encoder_disable,
> -	.enable		= sun6i_dsi_encoder_enable,
> +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> +				   enum drm_bridge_attach_flags flags)
> +{
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +
> +	if (dsi->next_bridge)
> +		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> +					 NULL, 0);
> +
> +	return 0;
> +}
> +
> +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
> +	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
> +	.attach			= sun6i_dsi_bridge_attach,
>  };
>  
>  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
>  	int ret;
>  
> -	drm_encoder_helper_add(&dsi->encoder,
> -			       &sun6i_dsi_enc_helper_funcs);
>  	ret = drm_simple_encoder_init(drm, &dsi->encoder,
>  				      DRM_MODE_ENCODER_DSI);
>  	if (ret) {
> @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	}
>  	dsi->encoder.possible_crtcs = BIT(0);
>  
> -	drm_connector_helper_add(&dsi->connector,
> -				 &sun6i_dsi_connector_helper_funcs);
> -	ret = drm_connector_init(drm, &dsi->connector,
> -				 &sun6i_dsi_connector_funcs,
> -				 DRM_MODE_CONNECTOR_DSI);
> +	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
>  	if (ret) {
> -		dev_err(dsi->dev,
> -			"Couldn't initialise the DSI connector\n");
> +		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
>  		goto err_cleanup_connector;
>  	}
>  
> -	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	if (dsi->panel) {
> +		drm_connector_helper_add(&dsi->connector,
> +					 &sun6i_dsi_connector_helper_funcs);
> +		ret = drm_connector_init(drm, &dsi->connector,
> +					 &sun6i_dsi_connector_funcs,
> +					 DRM_MODE_CONNECTOR_DSI);
> +		if (ret) {
> +			dev_err(dsi->dev,
> +				"Couldn't initialise the DSI connector\n");
> +			goto err_cleanup_connector;
> +		}
> +
> +		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	}
>  
>  	return 0;
>  
> @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
>  			    struct mipi_dsi_device *device)
>  {
>  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> -	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> +	struct device_node *remote = device->dev.of_node;
>  	int ret;
>  
> -	if (IS_ERR(panel))
> -		return PTR_ERR(panel);
> +	if (!of_device_is_available(remote)) {
> +		/**
> +		 * I2C interfaced DSI bridges will register DSI host on the
> +		 * bridge drivers instead of conventional device.
> +		 *
> +		 * Those are probed via host of_node instead of device of_node.
> +		 */
> +		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> +		if (!remote)
> +			return -ENODEV;
> +	}
> +
> +	dsi->panel = of_drm_find_panel(remote);
> +	if (IS_ERR(dsi->panel)) {
> +		dsi->panel = NULL;
> +
> +		dsi->next_bridge = of_drm_find_bridge(remote);
> +		if (IS_ERR(dsi->next_bridge)) {
> +			dev_err(dsi->dev, "failed to find bridge\n");
> +			return PTR_ERR(dsi->next_bridge);
> +		}
> +	} else {
> +		dsi->next_bridge = NULL;
> +	}
> +
> +	of_node_put(remote);
>  
> -	dsi->panel = panel;
>  	dsi->device = device;
>  
> -	dev_info(host->dev, "Attached device %s\n", device->name);
> +	dev_info(host->dev, "Attached %s %s\n",
> +		 device->name, dsi->panel ? "panel" : "bridge");
> +
> +	dsi->bridge.funcs = &sun6i_dsi_bridge_funcs;
> +	dsi->bridge.of_node = dsi->dev->of_node;
> +	dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
> +
> +	drm_bridge_add(&dsi->bridge);
>  
>  	ret = component_add(dsi->dev, &sun6i_dsi_ops);
>  	if (ret) {
> @@ -1040,9 +1104,11 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
>  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
>  
>  	dsi->panel = NULL;
> +	dsi->next_bridge = NULL;
>  	dsi->device = NULL;
>  
>  	component_del(dsi->dev, &sun6i_dsi_ops);
> +	drm_bridge_remove(&dsi->bridge);
>  
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
> index 61e88ea6044d..d269304691c9 100644
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
> @@ -16,6 +16,7 @@
>  #define SUN6I_DSI_TCON_DIV	4
>  
>  struct sun6i_dsi {
> +	struct drm_bridge	bridge;
>  	struct drm_connector	connector;
>  	struct drm_encoder	encoder;
>  	struct mipi_dsi_host	host;
> @@ -30,6 +31,7 @@ struct sun6i_dsi {
>  	struct device		*dev;
>  	struct mipi_dsi_device	*device;
>  	struct drm_panel	*panel;
> +	struct drm_bridge	*next_bridge;
>  };
>  
>  static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
> @@ -37,6 +39,11 @@ static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
>  	return container_of(host, struct sun6i_dsi, host);
>  };
>  
> +static inline struct sun6i_dsi *bridge_to_sun6i_dsi(struct drm_bridge *bridge)
> +{
> +	return container_of(bridge, struct sun6i_dsi, bridge);
> +}
> +
>  static inline struct sun6i_dsi *connector_to_sun6i_dsi(struct drm_connector *connector)
>  {
>  	return container_of(connector, struct sun6i_dsi, connector);
> 


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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 12:52     ` Neil Armstrong
  0 siblings, 0 replies; 72+ messages in thread
From: Neil Armstrong @ 2021-11-22 12:52 UTC (permalink / raw)
  To: Jagan Teki, Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart,
	Robert Foss, Sam Ravnborg
  Cc: dri-devel, linux-arm-kernel, linux-sunxi, linux-amarula

On 22/11/2021 07:52, Jagan Teki wrote:
> Some display panels would come up with a non-DSI output, those
> can have an option to connect the DSI host by means of interface
> bridge converter.
> 
> This DSI to non-DSI interface bridge converter would requires
> DSI Host to handle drm bridge functionalities in order to DSI
> Host to Interface bridge.
> 
> This patch convert the existing to a drm bridge driver with a
> built-in encoder support for compatibility with existing
> component drivers.
> 
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> ---
> Changes for v5:
> - add atomic APIs
> - find host and device variant DSI devices.
> Changes for v4, v3:
> - none
> 
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>  2 files changed, 96 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> index 43d9c9e5198d..a6a272b55f77 100644
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> @@ -21,6 +21,7 @@
>  
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>  #include <drm/drm_print.h>
>  #include <drm/drm_probe_helper.h>
> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>  	return 0;
>  }
>  
> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> +					   struct drm_bridge_state *old_bridge_state)
>  {
> -	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +	struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>  	struct mipi_dsi_device *device = dsi->device;
>  	union phy_configure_opts opts = { };
>  	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_prepare(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> +
>  	/*
>  	 * FIXME: This should be moved after the switch to HS mode.
>  	 *
> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	if (dsi->panel)
>  		drm_panel_enable(dsi->panel);
>  
> +	if (dsi->next_bridge)
> +		dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> +


No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
be called automatically on the bridge chain.

>  	sun6i_dsi_start(dsi, DSI_START_HSC);
>  
>  	udelay(1000);
> @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>  	sun6i_dsi_start(dsi, DSI_START_HSD);
>  }
>  
> -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> +					    struct drm_bridge_state *old_bridge_state)
>  {
> -	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>  
>  	DRM_DEBUG_DRIVER("Disabling DSI output\n");
>  
>  	if (dsi->panel) {
>  		drm_panel_disable(dsi->panel);
>  		drm_panel_unprepare(dsi->panel);
> +	} else if (dsi->next_bridge) {
> +		dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> +		dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);

Ditto

>  	}
>  
>  	phy_power_off(dsi->dphy);
> @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
>  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
>  };
>  
> -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> -	.disable	= sun6i_dsi_encoder_disable,
> -	.enable		= sun6i_dsi_encoder_enable,
> +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> +				   enum drm_bridge_attach_flags flags)
> +{
> +	struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> +
> +	if (dsi->next_bridge)
> +		return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> +					 NULL, 0);
> +
> +	return 0;
> +}
> +
> +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> +	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
> +	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
> +	.atomic_reset		= drm_atomic_helper_bridge_reset,
> +	.atomic_enable		= sun6i_dsi_bridge_atomic_enable,
> +	.atomic_disable		= sun6i_dsi_bridge_atomic_disable,
> +	.attach			= sun6i_dsi_bridge_attach,
>  };
>  
>  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	struct sun6i_dsi *dsi = dev_get_drvdata(dev);
>  	int ret;
>  
> -	drm_encoder_helper_add(&dsi->encoder,
> -			       &sun6i_dsi_enc_helper_funcs);
>  	ret = drm_simple_encoder_init(drm, &dsi->encoder,
>  				      DRM_MODE_ENCODER_DSI);
>  	if (ret) {
> @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
>  	}
>  	dsi->encoder.possible_crtcs = BIT(0);
>  
> -	drm_connector_helper_add(&dsi->connector,
> -				 &sun6i_dsi_connector_helper_funcs);
> -	ret = drm_connector_init(drm, &dsi->connector,
> -				 &sun6i_dsi_connector_funcs,
> -				 DRM_MODE_CONNECTOR_DSI);
> +	ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
>  	if (ret) {
> -		dev_err(dsi->dev,
> -			"Couldn't initialise the DSI connector\n");
> +		dev_err(dsi->dev, "Couldn't attach drm bridge\n");
>  		goto err_cleanup_connector;
>  	}
>  
> -	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	if (dsi->panel) {
> +		drm_connector_helper_add(&dsi->connector,
> +					 &sun6i_dsi_connector_helper_funcs);
> +		ret = drm_connector_init(drm, &dsi->connector,
> +					 &sun6i_dsi_connector_funcs,
> +					 DRM_MODE_CONNECTOR_DSI);
> +		if (ret) {
> +			dev_err(dsi->dev,
> +				"Couldn't initialise the DSI connector\n");
> +			goto err_cleanup_connector;
> +		}
> +
> +		drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> +	}
>  
>  	return 0;
>  
> @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
>  			    struct mipi_dsi_device *device)
>  {
>  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> -	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> +	struct device_node *remote = device->dev.of_node;
>  	int ret;
>  
> -	if (IS_ERR(panel))
> -		return PTR_ERR(panel);
> +	if (!of_device_is_available(remote)) {
> +		/**
> +		 * I2C interfaced DSI bridges will register DSI host on the
> +		 * bridge drivers instead of conventional device.
> +		 *
> +		 * Those are probed via host of_node instead of device of_node.
> +		 */
> +		remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> +		if (!remote)
> +			return -ENODEV;
> +	}
> +
> +	dsi->panel = of_drm_find_panel(remote);
> +	if (IS_ERR(dsi->panel)) {
> +		dsi->panel = NULL;
> +
> +		dsi->next_bridge = of_drm_find_bridge(remote);
> +		if (IS_ERR(dsi->next_bridge)) {
> +			dev_err(dsi->dev, "failed to find bridge\n");
> +			return PTR_ERR(dsi->next_bridge);
> +		}
> +	} else {
> +		dsi->next_bridge = NULL;
> +	}
> +
> +	of_node_put(remote);
>  
> -	dsi->panel = panel;
>  	dsi->device = device;
>  
> -	dev_info(host->dev, "Attached device %s\n", device->name);
> +	dev_info(host->dev, "Attached %s %s\n",
> +		 device->name, dsi->panel ? "panel" : "bridge");
> +
> +	dsi->bridge.funcs = &sun6i_dsi_bridge_funcs;
> +	dsi->bridge.of_node = dsi->dev->of_node;
> +	dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
> +
> +	drm_bridge_add(&dsi->bridge);
>  
>  	ret = component_add(dsi->dev, &sun6i_dsi_ops);
>  	if (ret) {
> @@ -1040,9 +1104,11 @@ static int sun6i_dsi_detach(struct mipi_dsi_host *host,
>  	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
>  
>  	dsi->panel = NULL;
> +	dsi->next_bridge = NULL;
>  	dsi->device = NULL;
>  
>  	component_del(dsi->dev, &sun6i_dsi_ops);
> +	drm_bridge_remove(&dsi->bridge);
>  
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
> index 61e88ea6044d..d269304691c9 100644
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
> @@ -16,6 +16,7 @@
>  #define SUN6I_DSI_TCON_DIV	4
>  
>  struct sun6i_dsi {
> +	struct drm_bridge	bridge;
>  	struct drm_connector	connector;
>  	struct drm_encoder	encoder;
>  	struct mipi_dsi_host	host;
> @@ -30,6 +31,7 @@ struct sun6i_dsi {
>  	struct device		*dev;
>  	struct mipi_dsi_device	*device;
>  	struct drm_panel	*panel;
> +	struct drm_bridge	*next_bridge;
>  };
>  
>  static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
> @@ -37,6 +39,11 @@ static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
>  	return container_of(host, struct sun6i_dsi, host);
>  };
>  
> +static inline struct sun6i_dsi *bridge_to_sun6i_dsi(struct drm_bridge *bridge)
> +{
> +	return container_of(bridge, struct sun6i_dsi, bridge);
> +}
> +
>  static inline struct sun6i_dsi *connector_to_sun6i_dsi(struct drm_connector *connector)
>  {
>  	return container_of(connector, struct sun6i_dsi, connector);
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22 10:07     ` Maxime Ripard
@ 2021-11-22 13:05       ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:05 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 3:38 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> > Get the display mode settings via mode_set bridge function
> > instead of explicitly de-reference.
>
> What's wrong with dereferencing the mode?

Nothing wrong with dereferencing, however we have built-in API to that job.

Jagan.

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 13:05       ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:05 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 3:38 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> > Get the display mode settings via mode_set bridge function
> > instead of explicitly de-reference.
>
> What's wrong with dereferencing the mode?

Nothing wrong with dereferencing, however we have built-in API to that job.

Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 12:52     ` Neil Armstrong
@ 2021-11-22 13:16       ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:16 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: linux-amarula, linux-sunxi, dri-devel, Chen-Yu Tsai, Robert Foss,
	Sam Ravnborg, linux-arm-kernel, Laurent Pinchart

Hi Neil,

On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> On 22/11/2021 07:52, Jagan Teki wrote:
> > Some display panels would come up with a non-DSI output, those
> > can have an option to connect the DSI host by means of interface
> > bridge converter.
> >
> > This DSI to non-DSI interface bridge converter would requires
> > DSI Host to handle drm bridge functionalities in order to DSI
> > Host to Interface bridge.
> >
> > This patch convert the existing to a drm bridge driver with a
> > built-in encoder support for compatibility with existing
> > component drivers.
> >
> > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > ---
> > Changes for v5:
> > - add atomic APIs
> > - find host and device variant DSI devices.
> > Changes for v4, v3:
> > - none
> >
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >  2 files changed, 96 insertions(+), 23 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > index 43d9c9e5198d..a6a272b55f77 100644
> > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > @@ -21,6 +21,7 @@
> >
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_of.h>
> >  #include <drm/drm_panel.h>
> >  #include <drm/drm_print.h>
> >  #include <drm/drm_probe_helper.h>
> > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >       return 0;
> >  }
> >
> > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +                                        struct drm_bridge_state *old_bridge_state)
> >  {
> > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >       struct mipi_dsi_device *device = dsi->device;
> >       union phy_configure_opts opts = { };
> >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_prepare(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > +
> >       /*
> >        * FIXME: This should be moved after the switch to HS mode.
> >        *
> > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_enable(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > +
>
>
> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
> be called automatically on the bridge chain.

Correct, but the existing bridge chain (stack) is not compatible with
sun6i DSI start sequence. We cannot send any DCS once we start HS
mode.
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775

This specific problem can be fixed only if we change the bridge chain
from stack to queue. Please check this series
https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/

Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 13:16       ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:16 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi Neil,

On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> On 22/11/2021 07:52, Jagan Teki wrote:
> > Some display panels would come up with a non-DSI output, those
> > can have an option to connect the DSI host by means of interface
> > bridge converter.
> >
> > This DSI to non-DSI interface bridge converter would requires
> > DSI Host to handle drm bridge functionalities in order to DSI
> > Host to Interface bridge.
> >
> > This patch convert the existing to a drm bridge driver with a
> > built-in encoder support for compatibility with existing
> > component drivers.
> >
> > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > ---
> > Changes for v5:
> > - add atomic APIs
> > - find host and device variant DSI devices.
> > Changes for v4, v3:
> > - none
> >
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >  2 files changed, 96 insertions(+), 23 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > index 43d9c9e5198d..a6a272b55f77 100644
> > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > @@ -21,6 +21,7 @@
> >
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_of.h>
> >  #include <drm/drm_panel.h>
> >  #include <drm/drm_print.h>
> >  #include <drm/drm_probe_helper.h>
> > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >       return 0;
> >  }
> >
> > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +                                        struct drm_bridge_state *old_bridge_state)
> >  {
> > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >       struct mipi_dsi_device *device = dsi->device;
> >       union phy_configure_opts opts = { };
> >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_prepare(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > +
> >       /*
> >        * FIXME: This should be moved after the switch to HS mode.
> >        *
> > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_enable(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > +
>
>
> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
> be called automatically on the bridge chain.

Correct, but the existing bridge chain (stack) is not compatible with
sun6i DSI start sequence. We cannot send any DCS once we start HS
mode.
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775

This specific problem can be fixed only if we change the bridge chain
from stack to queue. Please check this series
https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/

Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22 13:05       ` Jagan Teki
@ 2021-11-22 13:28         ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 13:28 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 06:35:58PM +0530, Jagan Teki wrote:
> On Mon, Nov 22, 2021 at 3:38 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> > > Get the display mode settings via mode_set bridge function
> > > instead of explicitly de-reference.
> >
> > What's wrong with dereferencing the mode?
> 
> Nothing wrong with dereferencing, however we have built-in API to that job.

That's not an API though?

It's perfectly valid to dereference the pointer in atomic_enable, and
that patch would consume memory for no particular reason.

Maxime

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 13:28         ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 13:28 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 06:35:58PM +0530, Jagan Teki wrote:
> On Mon, Nov 22, 2021 at 3:38 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> > > Get the display mode settings via mode_set bridge function
> > > instead of explicitly de-reference.
> >
> > What's wrong with dereferencing the mode?
> 
> Nothing wrong with dereferencing, however we have built-in API to that job.

That's not an API though?

It's perfectly valid to dereference the pointer in atomic_enable, and
that patch would consume memory for no particular reason.

Maxime

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 10:07     ` Maxime Ripard
@ 2021-11-22 13:48       ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:48 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

Hi Maxime,

On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > Some display panels would come up with a non-DSI output, those
> > can have an option to connect the DSI host by means of interface
> > bridge converter.
> >
> > This DSI to non-DSI interface bridge converter would requires
> > DSI Host to handle drm bridge functionalities in order to DSI
> > Host to Interface bridge.
>
> In order to do this you would need to use the DRM bridge API...

Sorry, which bridge API do you mean?

>
> > This patch convert the existing to a drm bridge driver with a
> > built-in encoder support for compatibility with existing
> > component drivers.
>
> ... but changing the encoder driver to a bridge is completely
> unnecessary to do so. Why did you need to make that change?

Idea of this series is to convert the driver to bridge and use the
latest bridge function from the v1 series.

>
> > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> >
> > ---
> > Changes for v5:
> > - add atomic APIs
> > - find host and device variant DSI devices.
> > Changes for v4, v3:
> > - none
> >
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >  2 files changed, 96 insertions(+), 23 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > index 43d9c9e5198d..a6a272b55f77 100644
> > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > @@ -21,6 +21,7 @@
> >
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_of.h>
> >  #include <drm/drm_panel.h>
> >  #include <drm/drm_print.h>
> >  #include <drm/drm_probe_helper.h>
> > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >       return 0;
> >  }
> >
> > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +                                        struct drm_bridge_state *old_bridge_state)
> >  {
> > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >       struct mipi_dsi_device *device = dsi->device;
> >       union phy_configure_opts opts = { };
> >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_prepare(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > +
>
> Please use the proper helpers.

If we use bridge_functions we need to take atomic functions as
precedence as the next bridge functions might convert atomic calls.

>
> >       /*
> >        * FIXME: This should be moved after the switch to HS mode.
> >        *
> > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_enable(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > +
>
> Ditto
>
> >       sun6i_dsi_start(dsi, DSI_START_HSC);
> >
> >       udelay(1000);
> > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       sun6i_dsi_start(dsi, DSI_START_HSD);
> >  }
> >
> > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > +                                         struct drm_bridge_state *old_bridge_state)
> >  {
> > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> >
> >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> >
> >       if (dsi->panel) {
> >               drm_panel_disable(dsi->panel);
> >               drm_panel_unprepare(dsi->panel);
> > +     } else if (dsi->next_bridge) {
> > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
>
> Ditto
>
> >       }
> >
> >       phy_power_off(dsi->dphy);
> > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> >  };
> >
> > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > -     .disable        = sun6i_dsi_encoder_disable,
> > -     .enable         = sun6i_dsi_encoder_enable,
> > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > +                                enum drm_bridge_attach_flags flags)
> > +{
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +
> > +     if (dsi->next_bridge)
> > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > +                                      NULL, 0);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > +     .attach                 = sun6i_dsi_bridge_attach,
> >  };
> >
> >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> >       int ret;
> >
> > -     drm_encoder_helper_add(&dsi->encoder,
> > -                            &sun6i_dsi_enc_helper_funcs);
> >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> >                                     DRM_MODE_ENCODER_DSI);
> >       if (ret) {
> > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >       }
> >       dsi->encoder.possible_crtcs = BIT(0);
> >
> > -     drm_connector_helper_add(&dsi->connector,
> > -                              &sun6i_dsi_connector_helper_funcs);
> > -     ret = drm_connector_init(drm, &dsi->connector,
> > -                              &sun6i_dsi_connector_funcs,
> > -                              DRM_MODE_CONNECTOR_DSI);
> > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> >       if (ret) {
> > -             dev_err(dsi->dev,
> > -                     "Couldn't initialise the DSI connector\n");
> > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> >               goto err_cleanup_connector;
> >       }
> >
> > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +     if (dsi->panel) {
> > +             drm_connector_helper_add(&dsi->connector,
> > +                                      &sun6i_dsi_connector_helper_funcs);
> > +             ret = drm_connector_init(drm, &dsi->connector,
> > +                                      &sun6i_dsi_connector_funcs,
> > +                                      DRM_MODE_CONNECTOR_DSI);
> > +             if (ret) {
> > +                     dev_err(dsi->dev,
> > +                             "Couldn't initialise the DSI connector\n");
> > +                     goto err_cleanup_connector;
> > +             }
> > +
> > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +     }
> >
> >       return 0;
> >
> > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> >                           struct mipi_dsi_device *device)
> >  {
> >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > +     struct device_node *remote = device->dev.of_node;
> >       int ret;
> >
> > -     if (IS_ERR(panel))
> > -             return PTR_ERR(panel);
> > +     if (!of_device_is_available(remote)) {
> > +             /**
> > +              * I2C interfaced DSI bridges will register DSI host on the
> > +              * bridge drivers instead of conventional device.
> > +              *
> > +              * Those are probed via host of_node instead of device of_node.
> > +              */
>
> I have no idea what you mean here. Can you expand on what issue you've
> tried to solve here?

I2C interface DSI bridges will register DSI host on the bridge
drivers. Those can be found using host->dev->of_node and cannot be
find using device->dev.of_node

>
> > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > +             if (!remote)
> > +                     return -ENODEV;
> > +     }
> > +
> > +     dsi->panel = of_drm_find_panel(remote);
> > +     if (IS_ERR(dsi->panel)) {
> > +             dsi->panel = NULL;
> > +
> > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > +             if (IS_ERR(dsi->next_bridge)) {
> > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > +                     return PTR_ERR(dsi->next_bridge);
> > +             }
> > +     } else {
> > +             dsi->next_bridge = NULL;
> > +     }
> > +
> > +     of_node_put(remote);
>
> Using devm_drm_of_get_bridge would greatly simplify the driver

I'm aware of this and this would break the existing sunxi dsi binding,
we are not using ports based pipeline in dsi node. Of-course you have
pointed the same before, please check below
https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/

Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 13:48       ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:48 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi Maxime,

On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > Some display panels would come up with a non-DSI output, those
> > can have an option to connect the DSI host by means of interface
> > bridge converter.
> >
> > This DSI to non-DSI interface bridge converter would requires
> > DSI Host to handle drm bridge functionalities in order to DSI
> > Host to Interface bridge.
>
> In order to do this you would need to use the DRM bridge API...

Sorry, which bridge API do you mean?

>
> > This patch convert the existing to a drm bridge driver with a
> > built-in encoder support for compatibility with existing
> > component drivers.
>
> ... but changing the encoder driver to a bridge is completely
> unnecessary to do so. Why did you need to make that change?

Idea of this series is to convert the driver to bridge and use the
latest bridge function from the v1 series.

>
> > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> >
> > ---
> > Changes for v5:
> > - add atomic APIs
> > - find host and device variant DSI devices.
> > Changes for v4, v3:
> > - none
> >
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >  2 files changed, 96 insertions(+), 23 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > index 43d9c9e5198d..a6a272b55f77 100644
> > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > @@ -21,6 +21,7 @@
> >
> >  #include <drm/drm_atomic_helper.h>
> >  #include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_of.h>
> >  #include <drm/drm_panel.h>
> >  #include <drm/drm_print.h>
> >  #include <drm/drm_probe_helper.h>
> > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >       return 0;
> >  }
> >
> > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > +                                        struct drm_bridge_state *old_bridge_state)
> >  {
> > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >       struct mipi_dsi_device *device = dsi->device;
> >       union phy_configure_opts opts = { };
> >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_prepare(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > +
>
> Please use the proper helpers.

If we use bridge_functions we need to take atomic functions as
precedence as the next bridge functions might convert atomic calls.

>
> >       /*
> >        * FIXME: This should be moved after the switch to HS mode.
> >        *
> > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       if (dsi->panel)
> >               drm_panel_enable(dsi->panel);
> >
> > +     if (dsi->next_bridge)
> > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > +
>
> Ditto
>
> >       sun6i_dsi_start(dsi, DSI_START_HSC);
> >
> >       udelay(1000);
> > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >       sun6i_dsi_start(dsi, DSI_START_HSD);
> >  }
> >
> > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > +                                         struct drm_bridge_state *old_bridge_state)
> >  {
> > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> >
> >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> >
> >       if (dsi->panel) {
> >               drm_panel_disable(dsi->panel);
> >               drm_panel_unprepare(dsi->panel);
> > +     } else if (dsi->next_bridge) {
> > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
>
> Ditto
>
> >       }
> >
> >       phy_power_off(dsi->dphy);
> > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> >  };
> >
> > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > -     .disable        = sun6i_dsi_encoder_disable,
> > -     .enable         = sun6i_dsi_encoder_enable,
> > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > +                                enum drm_bridge_attach_flags flags)
> > +{
> > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > +
> > +     if (dsi->next_bridge)
> > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > +                                      NULL, 0);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > +     .attach                 = sun6i_dsi_bridge_attach,
> >  };
> >
> >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> >       int ret;
> >
> > -     drm_encoder_helper_add(&dsi->encoder,
> > -                            &sun6i_dsi_enc_helper_funcs);
> >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> >                                     DRM_MODE_ENCODER_DSI);
> >       if (ret) {
> > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> >       }
> >       dsi->encoder.possible_crtcs = BIT(0);
> >
> > -     drm_connector_helper_add(&dsi->connector,
> > -                              &sun6i_dsi_connector_helper_funcs);
> > -     ret = drm_connector_init(drm, &dsi->connector,
> > -                              &sun6i_dsi_connector_funcs,
> > -                              DRM_MODE_CONNECTOR_DSI);
> > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> >       if (ret) {
> > -             dev_err(dsi->dev,
> > -                     "Couldn't initialise the DSI connector\n");
> > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> >               goto err_cleanup_connector;
> >       }
> >
> > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +     if (dsi->panel) {
> > +             drm_connector_helper_add(&dsi->connector,
> > +                                      &sun6i_dsi_connector_helper_funcs);
> > +             ret = drm_connector_init(drm, &dsi->connector,
> > +                                      &sun6i_dsi_connector_funcs,
> > +                                      DRM_MODE_CONNECTOR_DSI);
> > +             if (ret) {
> > +                     dev_err(dsi->dev,
> > +                             "Couldn't initialise the DSI connector\n");
> > +                     goto err_cleanup_connector;
> > +             }
> > +
> > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > +     }
> >
> >       return 0;
> >
> > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> >                           struct mipi_dsi_device *device)
> >  {
> >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > +     struct device_node *remote = device->dev.of_node;
> >       int ret;
> >
> > -     if (IS_ERR(panel))
> > -             return PTR_ERR(panel);
> > +     if (!of_device_is_available(remote)) {
> > +             /**
> > +              * I2C interfaced DSI bridges will register DSI host on the
> > +              * bridge drivers instead of conventional device.
> > +              *
> > +              * Those are probed via host of_node instead of device of_node.
> > +              */
>
> I have no idea what you mean here. Can you expand on what issue you've
> tried to solve here?

I2C interface DSI bridges will register DSI host on the bridge
drivers. Those can be found using host->dev->of_node and cannot be
find using device->dev.of_node

>
> > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > +             if (!remote)
> > +                     return -ENODEV;
> > +     }
> > +
> > +     dsi->panel = of_drm_find_panel(remote);
> > +     if (IS_ERR(dsi->panel)) {
> > +             dsi->panel = NULL;
> > +
> > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > +             if (IS_ERR(dsi->next_bridge)) {
> > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > +                     return PTR_ERR(dsi->next_bridge);
> > +             }
> > +     } else {
> > +             dsi->next_bridge = NULL;
> > +     }
> > +
> > +     of_node_put(remote);
>
> Using devm_drm_of_get_bridge would greatly simplify the driver

I'm aware of this and this would break the existing sunxi dsi binding,
we are not using ports based pipeline in dsi node. Of-course you have
pointed the same before, please check below
https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/

Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22 13:28         ` Maxime Ripard
@ 2021-11-22 13:51           ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

Hi Maxime,

On Mon, Nov 22, 2021 at 6:58 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 06:35:58PM +0530, Jagan Teki wrote:
> > On Mon, Nov 22, 2021 at 3:38 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> > > > Get the display mode settings via mode_set bridge function
> > > > instead of explicitly de-reference.
> > >
> > > What's wrong with dereferencing the mode?
> >
> > Nothing wrong with dereferencing, however we have built-in API to that job.
>
> That's not an API though?

May be we can call it bridge or encoding function, I usually call
these ops are API's.

>
> It's perfectly valid to dereference the pointer in atomic_enable, and
> that patch would consume memory for no particular reason.

Again, I'm not pointing any mistake in dereference and certainly not
understand about what memory consumption issue here. I'm doing it here
since I'm doing it via mode_set in other drivers. No problem for me
either way.

Thanks,
Jagan.

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 13:51           ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 13:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi Maxime,

On Mon, Nov 22, 2021 at 6:58 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 06:35:58PM +0530, Jagan Teki wrote:
> > On Mon, Nov 22, 2021 at 3:38 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Mon, Nov 22, 2021 at 12:22:20PM +0530, Jagan Teki wrote:
> > > > Get the display mode settings via mode_set bridge function
> > > > instead of explicitly de-reference.
> > >
> > > What's wrong with dereferencing the mode?
> >
> > Nothing wrong with dereferencing, however we have built-in API to that job.
>
> That's not an API though?

May be we can call it bridge or encoding function, I usually call
these ops are API's.

>
> It's perfectly valid to dereference the pointer in atomic_enable, and
> that patch would consume memory for no particular reason.

Again, I'm not pointing any mistake in dereference and certainly not
understand about what memory consumption issue here. I'm doing it here
since I'm doing it via mode_set in other drivers. No problem for me
either way.

Thanks,
Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 13:48       ` Jagan Teki
@ 2021-11-22 14:04         ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 14:04 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> Hi Maxime,
> 
> On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > Some display panels would come up with a non-DSI output, those
> > > can have an option to connect the DSI host by means of interface
> > > bridge converter.
> > >
> > > This DSI to non-DSI interface bridge converter would requires
> > > DSI Host to handle drm bridge functionalities in order to DSI
> > > Host to Interface bridge.
> >
> > In order to do this you would need to use the DRM bridge API...
> 
> Sorry, which bridge API do you mean?

Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
we're doing in sun4i_rgb.c

> > > This patch convert the existing to a drm bridge driver with a
> > > built-in encoder support for compatibility with existing
> > > component drivers.
> >
> > ... but changing the encoder driver to a bridge is completely
> > unnecessary to do so. Why did you need to make that change?
> 
> Idea of this series is to convert the driver to bridge and use the
> latest bridge function from the v1 series.

Ok, but it's not at all what you mention in your commit log? You don't
need any of that in order to support a bridge downstream.

> >
> > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > >
> > > ---
> > > Changes for v5:
> > > - add atomic APIs
> > > - find host and device variant DSI devices.
> > > Changes for v4, v3:
> > > - none
> > >
> > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > index 43d9c9e5198d..a6a272b55f77 100644
> > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > @@ -21,6 +21,7 @@
> > >
> > >  #include <drm/drm_atomic_helper.h>
> > >  #include <drm/drm_mipi_dsi.h>
> > > +#include <drm/drm_of.h>
> > >  #include <drm/drm_panel.h>
> > >  #include <drm/drm_print.h>
> > >  #include <drm/drm_probe_helper.h>
> > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > >       return 0;
> > >  }
> > >
> > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > +                                        struct drm_bridge_state *old_bridge_state)
> > >  {
> > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > >       struct mipi_dsi_device *device = dsi->device;
> > >       union phy_configure_opts opts = { };
> > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > >       if (dsi->panel)
> > >               drm_panel_prepare(dsi->panel);
> > >
> > > +     if (dsi->next_bridge)
> > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > +
> >
> > Please use the proper helpers.
> 
> If we use bridge_functions we need to take atomic functions as
> precedence as the next bridge functions might convert atomic calls.

We've had this discussion over and over again, but this is something
that needs to be documented and / or in your commit log.

You must not deviate from the standard (and expected) behavior without
any kind of justification.

> >
> > >       /*
> > >        * FIXME: This should be moved after the switch to HS mode.
> > >        *
> > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > >       if (dsi->panel)
> > >               drm_panel_enable(dsi->panel);
> > >
> > > +     if (dsi->next_bridge)
> > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > +
> >
> > Ditto
> >
> > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > >
> > >       udelay(1000);
> > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > >  }
> > >
> > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > +                                         struct drm_bridge_state *old_bridge_state)
> > >  {
> > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > >
> > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > >
> > >       if (dsi->panel) {
> > >               drm_panel_disable(dsi->panel);
> > >               drm_panel_unprepare(dsi->panel);
> > > +     } else if (dsi->next_bridge) {
> > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> >
> > Ditto
> >
> > >       }
> > >
> > >       phy_power_off(dsi->dphy);
> > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > >  };
> > >
> > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > -     .disable        = sun6i_dsi_encoder_disable,
> > > -     .enable         = sun6i_dsi_encoder_enable,
> > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > +                                enum drm_bridge_attach_flags flags)
> > > +{
> > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > +
> > > +     if (dsi->next_bridge)
> > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > +                                      NULL, 0);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > +     .attach                 = sun6i_dsi_bridge_attach,
> > >  };
> > >
> > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > >       int ret;
> > >
> > > -     drm_encoder_helper_add(&dsi->encoder,
> > > -                            &sun6i_dsi_enc_helper_funcs);
> > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > >                                     DRM_MODE_ENCODER_DSI);
> > >       if (ret) {
> > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > >       }
> > >       dsi->encoder.possible_crtcs = BIT(0);
> > >
> > > -     drm_connector_helper_add(&dsi->connector,
> > > -                              &sun6i_dsi_connector_helper_funcs);
> > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > -                              &sun6i_dsi_connector_funcs,
> > > -                              DRM_MODE_CONNECTOR_DSI);
> > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > >       if (ret) {
> > > -             dev_err(dsi->dev,
> > > -                     "Couldn't initialise the DSI connector\n");
> > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > >               goto err_cleanup_connector;
> > >       }
> > >
> > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > +     if (dsi->panel) {
> > > +             drm_connector_helper_add(&dsi->connector,
> > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > +                                      &sun6i_dsi_connector_funcs,
> > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > +             if (ret) {
> > > +                     dev_err(dsi->dev,
> > > +                             "Couldn't initialise the DSI connector\n");
> > > +                     goto err_cleanup_connector;
> > > +             }
> > > +
> > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > +     }
> > >
> > >       return 0;
> > >
> > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > >                           struct mipi_dsi_device *device)
> > >  {
> > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > +     struct device_node *remote = device->dev.of_node;
> > >       int ret;
> > >
> > > -     if (IS_ERR(panel))
> > > -             return PTR_ERR(panel);
> > > +     if (!of_device_is_available(remote)) {
> > > +             /**
> > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > +              * bridge drivers instead of conventional device.
> > > +              *
> > > +              * Those are probed via host of_node instead of device of_node.
> > > +              */
> >
> > I have no idea what you mean here. Can you expand on what issue you've
> > tried to solve here?
> 
> I2C interface DSI bridges will register DSI host on the bridge
> drivers.

DSI bridges don't register a DSI host.

> Those can be found using host->dev->of_node and cannot be find using
> device->dev.of_node
> 
> >
> > > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > > +             if (!remote)
> > > +                     return -ENODEV;
> > > +     }
> > > +
> > > +     dsi->panel = of_drm_find_panel(remote);
> > > +     if (IS_ERR(dsi->panel)) {
> > > +             dsi->panel = NULL;
> > > +
> > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > +             if (IS_ERR(dsi->next_bridge)) {
> > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > +                     return PTR_ERR(dsi->next_bridge);
> > > +             }
> > > +     } else {
> > > +             dsi->next_bridge = NULL;
> > > +     }
> > > +
> > > +     of_node_put(remote);
> >
> > Using devm_drm_of_get_bridge would greatly simplify the driver
> 
> I'm aware of this and this would break the existing sunxi dsi binding,
> we are not using ports based pipeline in dsi node. Of-course you have
> pointed the same before, please check below
> https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/

Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
bindings and look for a panel or bridge not only through the OF graph,
but also on the child nodes

Maxime

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 14:04         ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 14:04 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> Hi Maxime,
> 
> On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > Some display panels would come up with a non-DSI output, those
> > > can have an option to connect the DSI host by means of interface
> > > bridge converter.
> > >
> > > This DSI to non-DSI interface bridge converter would requires
> > > DSI Host to handle drm bridge functionalities in order to DSI
> > > Host to Interface bridge.
> >
> > In order to do this you would need to use the DRM bridge API...
> 
> Sorry, which bridge API do you mean?

Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
we're doing in sun4i_rgb.c

> > > This patch convert the existing to a drm bridge driver with a
> > > built-in encoder support for compatibility with existing
> > > component drivers.
> >
> > ... but changing the encoder driver to a bridge is completely
> > unnecessary to do so. Why did you need to make that change?
> 
> Idea of this series is to convert the driver to bridge and use the
> latest bridge function from the v1 series.

Ok, but it's not at all what you mention in your commit log? You don't
need any of that in order to support a bridge downstream.

> >
> > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > >
> > > ---
> > > Changes for v5:
> > > - add atomic APIs
> > > - find host and device variant DSI devices.
> > > Changes for v4, v3:
> > > - none
> > >
> > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > index 43d9c9e5198d..a6a272b55f77 100644
> > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > @@ -21,6 +21,7 @@
> > >
> > >  #include <drm/drm_atomic_helper.h>
> > >  #include <drm/drm_mipi_dsi.h>
> > > +#include <drm/drm_of.h>
> > >  #include <drm/drm_panel.h>
> > >  #include <drm/drm_print.h>
> > >  #include <drm/drm_probe_helper.h>
> > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > >       return 0;
> > >  }
> > >
> > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > +                                        struct drm_bridge_state *old_bridge_state)
> > >  {
> > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > >       struct mipi_dsi_device *device = dsi->device;
> > >       union phy_configure_opts opts = { };
> > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > >       if (dsi->panel)
> > >               drm_panel_prepare(dsi->panel);
> > >
> > > +     if (dsi->next_bridge)
> > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > +
> >
> > Please use the proper helpers.
> 
> If we use bridge_functions we need to take atomic functions as
> precedence as the next bridge functions might convert atomic calls.

We've had this discussion over and over again, but this is something
that needs to be documented and / or in your commit log.

You must not deviate from the standard (and expected) behavior without
any kind of justification.

> >
> > >       /*
> > >        * FIXME: This should be moved after the switch to HS mode.
> > >        *
> > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > >       if (dsi->panel)
> > >               drm_panel_enable(dsi->panel);
> > >
> > > +     if (dsi->next_bridge)
> > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > +
> >
> > Ditto
> >
> > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > >
> > >       udelay(1000);
> > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > >  }
> > >
> > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > +                                         struct drm_bridge_state *old_bridge_state)
> > >  {
> > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > >
> > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > >
> > >       if (dsi->panel) {
> > >               drm_panel_disable(dsi->panel);
> > >               drm_panel_unprepare(dsi->panel);
> > > +     } else if (dsi->next_bridge) {
> > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> >
> > Ditto
> >
> > >       }
> > >
> > >       phy_power_off(dsi->dphy);
> > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > >  };
> > >
> > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > -     .disable        = sun6i_dsi_encoder_disable,
> > > -     .enable         = sun6i_dsi_encoder_enable,
> > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > +                                enum drm_bridge_attach_flags flags)
> > > +{
> > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > +
> > > +     if (dsi->next_bridge)
> > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > +                                      NULL, 0);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > +     .attach                 = sun6i_dsi_bridge_attach,
> > >  };
> > >
> > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > >       int ret;
> > >
> > > -     drm_encoder_helper_add(&dsi->encoder,
> > > -                            &sun6i_dsi_enc_helper_funcs);
> > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > >                                     DRM_MODE_ENCODER_DSI);
> > >       if (ret) {
> > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > >       }
> > >       dsi->encoder.possible_crtcs = BIT(0);
> > >
> > > -     drm_connector_helper_add(&dsi->connector,
> > > -                              &sun6i_dsi_connector_helper_funcs);
> > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > -                              &sun6i_dsi_connector_funcs,
> > > -                              DRM_MODE_CONNECTOR_DSI);
> > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > >       if (ret) {
> > > -             dev_err(dsi->dev,
> > > -                     "Couldn't initialise the DSI connector\n");
> > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > >               goto err_cleanup_connector;
> > >       }
> > >
> > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > +     if (dsi->panel) {
> > > +             drm_connector_helper_add(&dsi->connector,
> > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > +                                      &sun6i_dsi_connector_funcs,
> > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > +             if (ret) {
> > > +                     dev_err(dsi->dev,
> > > +                             "Couldn't initialise the DSI connector\n");
> > > +                     goto err_cleanup_connector;
> > > +             }
> > > +
> > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > +     }
> > >
> > >       return 0;
> > >
> > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > >                           struct mipi_dsi_device *device)
> > >  {
> > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > +     struct device_node *remote = device->dev.of_node;
> > >       int ret;
> > >
> > > -     if (IS_ERR(panel))
> > > -             return PTR_ERR(panel);
> > > +     if (!of_device_is_available(remote)) {
> > > +             /**
> > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > +              * bridge drivers instead of conventional device.
> > > +              *
> > > +              * Those are probed via host of_node instead of device of_node.
> > > +              */
> >
> > I have no idea what you mean here. Can you expand on what issue you've
> > tried to solve here?
> 
> I2C interface DSI bridges will register DSI host on the bridge
> drivers.

DSI bridges don't register a DSI host.

> Those can be found using host->dev->of_node and cannot be find using
> device->dev.of_node
> 
> >
> > > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > > +             if (!remote)
> > > +                     return -ENODEV;
> > > +     }
> > > +
> > > +     dsi->panel = of_drm_find_panel(remote);
> > > +     if (IS_ERR(dsi->panel)) {
> > > +             dsi->panel = NULL;
> > > +
> > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > +             if (IS_ERR(dsi->next_bridge)) {
> > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > +                     return PTR_ERR(dsi->next_bridge);
> > > +             }
> > > +     } else {
> > > +             dsi->next_bridge = NULL;
> > > +     }
> > > +
> > > +     of_node_put(remote);
> >
> > Using devm_drm_of_get_bridge would greatly simplify the driver
> 
> I'm aware of this and this would break the existing sunxi dsi binding,
> we are not using ports based pipeline in dsi node. Of-course you have
> pointed the same before, please check below
> https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/

Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
bindings and look for a panel or bridge not only through the OF graph,
but also on the child nodes

Maxime

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22 13:51           ` Jagan Teki
@ 2021-11-22 14:09             ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 14:09 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > It's perfectly valid to dereference the pointer in atomic_enable, and
> > that patch would consume memory for no particular reason.
> 
> Again, I'm not pointing any mistake in dereference and certainly not
> understand about what memory consumption issue here.

You add a struct drm_display_mode field to struct sun6i_dsi. It
increases the size of struct sun6i_dsi of sizeof(struct
drm_display_mode).

> I'm doing it here since I'm doing it via mode_set in other drivers. No
> problem for me either way.

But *why* are you doing so?

There might be a valid reason in other drivers, but there's none here
(that you mentioned at least).

Maxime

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 14:09             ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 14:09 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > It's perfectly valid to dereference the pointer in atomic_enable, and
> > that patch would consume memory for no particular reason.
> 
> Again, I'm not pointing any mistake in dereference and certainly not
> understand about what memory consumption issue here.

You add a struct drm_display_mode field to struct sun6i_dsi. It
increases the size of struct sun6i_dsi of sizeof(struct
drm_display_mode).

> I'm doing it here since I'm doing it via mode_set in other drivers. No
> problem for me either way.

But *why* are you doing so?

There might be a valid reason in other drivers, but there's none here
(that you mentioned at least).

Maxime

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 14:04         ` Maxime Ripard
@ 2021-11-22 14:19           ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 14:19 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

Hi Maxime,

On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > Hi Maxime,
> >
> > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > Some display panels would come up with a non-DSI output, those
> > > > can have an option to connect the DSI host by means of interface
> > > > bridge converter.
> > > >
> > > > This DSI to non-DSI interface bridge converter would requires
> > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > Host to Interface bridge.
> > >
> > > In order to do this you would need to use the DRM bridge API...
> >
> > Sorry, which bridge API do you mean?
>
> Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> we're doing in sun4i_rgb.c

Yes, we have drm_bridge_attach in bind and bridge_function.attach
calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
Not sure which API's I've missed.

>
> > > > This patch convert the existing to a drm bridge driver with a
> > > > built-in encoder support for compatibility with existing
> > > > component drivers.
> > >
> > > ... but changing the encoder driver to a bridge is completely
> > > unnecessary to do so. Why did you need to make that change?
> >
> > Idea of this series is to convert the driver to bridge and use the
> > latest bridge function from the v1 series.
>
> Ok, but it's not at all what you mention in your commit log? You don't
> need any of that in order to support a bridge downstream.

I've mentioned "Converting to bridge driver" and thought it has
meaning of converting encoder related function to bridge functions as
well. Not think about specific description to describe on commit
message. Will update this.

>
> > >
> > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > >
> > > > ---
> > > > Changes for v5:
> > > > - add atomic APIs
> > > > - find host and device variant DSI devices.
> > > > Changes for v4, v3:
> > > > - none
> > > >
> > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > @@ -21,6 +21,7 @@
> > > >
> > > >  #include <drm/drm_atomic_helper.h>
> > > >  #include <drm/drm_mipi_dsi.h>
> > > > +#include <drm/drm_of.h>
> > > >  #include <drm/drm_panel.h>
> > > >  #include <drm/drm_print.h>
> > > >  #include <drm/drm_probe_helper.h>
> > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > >       return 0;
> > > >  }
> > > >
> > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > >  {
> > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > >       struct mipi_dsi_device *device = dsi->device;
> > > >       union phy_configure_opts opts = { };
> > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > >       if (dsi->panel)
> > > >               drm_panel_prepare(dsi->panel);
> > > >
> > > > +     if (dsi->next_bridge)
> > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > +
> > >
> > > Please use the proper helpers.
> >
> > If we use bridge_functions we need to take atomic functions as
> > precedence as the next bridge functions might convert atomic calls.
>
> We've had this discussion over and over again, but this is something
> that needs to be documented and / or in your commit log.
>
> You must not deviate from the standard (and expected) behavior without
> any kind of justification.

Not exactly sure about what you mean, sorry. All these atomic bridge
functions are already documented if I'm not wrong and Laurent have
patches to switch the normal functions to atomic. Not sure what else
need to document here and need justification for it if the driver is
converting to bridge.

>
> > >
> > > >       /*
> > > >        * FIXME: This should be moved after the switch to HS mode.
> > > >        *
> > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > >       if (dsi->panel)
> > > >               drm_panel_enable(dsi->panel);
> > > >
> > > > +     if (dsi->next_bridge)
> > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > +
> > >
> > > Ditto
> > >
> > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > >
> > > >       udelay(1000);
> > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > >  }
> > > >
> > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > >  {
> > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > >
> > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > >
> > > >       if (dsi->panel) {
> > > >               drm_panel_disable(dsi->panel);
> > > >               drm_panel_unprepare(dsi->panel);
> > > > +     } else if (dsi->next_bridge) {
> > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > >
> > > Ditto
> > >
> > > >       }
> > > >
> > > >       phy_power_off(dsi->dphy);
> > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > >  };
> > > >
> > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > +                                enum drm_bridge_attach_flags flags)
> > > > +{
> > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > +
> > > > +     if (dsi->next_bridge)
> > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > +                                      NULL, 0);
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > >  };
> > > >
> > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > >       int ret;
> > > >
> > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > >                                     DRM_MODE_ENCODER_DSI);
> > > >       if (ret) {
> > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > >       }
> > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > >
> > > > -     drm_connector_helper_add(&dsi->connector,
> > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > -                              &sun6i_dsi_connector_funcs,
> > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > >       if (ret) {
> > > > -             dev_err(dsi->dev,
> > > > -                     "Couldn't initialise the DSI connector\n");
> > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > >               goto err_cleanup_connector;
> > > >       }
> > > >
> > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > +     if (dsi->panel) {
> > > > +             drm_connector_helper_add(&dsi->connector,
> > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > +                                      &sun6i_dsi_connector_funcs,
> > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > +             if (ret) {
> > > > +                     dev_err(dsi->dev,
> > > > +                             "Couldn't initialise the DSI connector\n");
> > > > +                     goto err_cleanup_connector;
> > > > +             }
> > > > +
> > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > +     }
> > > >
> > > >       return 0;
> > > >
> > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > >                           struct mipi_dsi_device *device)
> > > >  {
> > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > +     struct device_node *remote = device->dev.of_node;
> > > >       int ret;
> > > >
> > > > -     if (IS_ERR(panel))
> > > > -             return PTR_ERR(panel);
> > > > +     if (!of_device_is_available(remote)) {
> > > > +             /**
> > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > +              * bridge drivers instead of conventional device.
> > > > +              *
> > > > +              * Those are probed via host of_node instead of device of_node.
> > > > +              */
> > >
> > > I have no idea what you mean here. Can you expand on what issue you've
> > > tried to solve here?
> >
> > I2C interface DSI bridges will register DSI host on the bridge
> > drivers.
>
> DSI bridges don't register a DSI host.

Please check what I mean here,
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623

I've tested it anyway, if you have any relevant one please check as well.

>
> > Those can be found using host->dev->of_node and cannot be find using
> > device->dev.of_node
> >
> > >
> > > > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > > > +             if (!remote)
> > > > +                     return -ENODEV;
> > > > +     }
> > > > +
> > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > +     if (IS_ERR(dsi->panel)) {
> > > > +             dsi->panel = NULL;
> > > > +
> > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > +             }
> > > > +     } else {
> > > > +             dsi->next_bridge = NULL;
> > > > +     }
> > > > +
> > > > +     of_node_put(remote);
> > >
> > > Using devm_drm_of_get_bridge would greatly simplify the driver
> >
> > I'm aware of this and this would break the existing sunxi dsi binding,
> > we are not using ports based pipeline in dsi node. Of-course you have
> > pointed the same before, please check below
> > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
>
> Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> bindings and look for a panel or bridge not only through the OF graph,
> but also on the child nodes

Okay. I need to check this.

Thanks,
Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 14:19           ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 14:19 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi Maxime,

On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > Hi Maxime,
> >
> > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > Some display panels would come up with a non-DSI output, those
> > > > can have an option to connect the DSI host by means of interface
> > > > bridge converter.
> > > >
> > > > This DSI to non-DSI interface bridge converter would requires
> > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > Host to Interface bridge.
> > >
> > > In order to do this you would need to use the DRM bridge API...
> >
> > Sorry, which bridge API do you mean?
>
> Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> we're doing in sun4i_rgb.c

Yes, we have drm_bridge_attach in bind and bridge_function.attach
calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
Not sure which API's I've missed.

>
> > > > This patch convert the existing to a drm bridge driver with a
> > > > built-in encoder support for compatibility with existing
> > > > component drivers.
> > >
> > > ... but changing the encoder driver to a bridge is completely
> > > unnecessary to do so. Why did you need to make that change?
> >
> > Idea of this series is to convert the driver to bridge and use the
> > latest bridge function from the v1 series.
>
> Ok, but it's not at all what you mention in your commit log? You don't
> need any of that in order to support a bridge downstream.

I've mentioned "Converting to bridge driver" and thought it has
meaning of converting encoder related function to bridge functions as
well. Not think about specific description to describe on commit
message. Will update this.

>
> > >
> > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > >
> > > > ---
> > > > Changes for v5:
> > > > - add atomic APIs
> > > > - find host and device variant DSI devices.
> > > > Changes for v4, v3:
> > > > - none
> > > >
> > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > @@ -21,6 +21,7 @@
> > > >
> > > >  #include <drm/drm_atomic_helper.h>
> > > >  #include <drm/drm_mipi_dsi.h>
> > > > +#include <drm/drm_of.h>
> > > >  #include <drm/drm_panel.h>
> > > >  #include <drm/drm_print.h>
> > > >  #include <drm/drm_probe_helper.h>
> > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > >       return 0;
> > > >  }
> > > >
> > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > >  {
> > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > >       struct mipi_dsi_device *device = dsi->device;
> > > >       union phy_configure_opts opts = { };
> > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > >       if (dsi->panel)
> > > >               drm_panel_prepare(dsi->panel);
> > > >
> > > > +     if (dsi->next_bridge)
> > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > +
> > >
> > > Please use the proper helpers.
> >
> > If we use bridge_functions we need to take atomic functions as
> > precedence as the next bridge functions might convert atomic calls.
>
> We've had this discussion over and over again, but this is something
> that needs to be documented and / or in your commit log.
>
> You must not deviate from the standard (and expected) behavior without
> any kind of justification.

Not exactly sure about what you mean, sorry. All these atomic bridge
functions are already documented if I'm not wrong and Laurent have
patches to switch the normal functions to atomic. Not sure what else
need to document here and need justification for it if the driver is
converting to bridge.

>
> > >
> > > >       /*
> > > >        * FIXME: This should be moved after the switch to HS mode.
> > > >        *
> > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > >       if (dsi->panel)
> > > >               drm_panel_enable(dsi->panel);
> > > >
> > > > +     if (dsi->next_bridge)
> > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > +
> > >
> > > Ditto
> > >
> > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > >
> > > >       udelay(1000);
> > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > >  }
> > > >
> > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > >  {
> > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > >
> > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > >
> > > >       if (dsi->panel) {
> > > >               drm_panel_disable(dsi->panel);
> > > >               drm_panel_unprepare(dsi->panel);
> > > > +     } else if (dsi->next_bridge) {
> > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > >
> > > Ditto
> > >
> > > >       }
> > > >
> > > >       phy_power_off(dsi->dphy);
> > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > >  };
> > > >
> > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > +                                enum drm_bridge_attach_flags flags)
> > > > +{
> > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > +
> > > > +     if (dsi->next_bridge)
> > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > +                                      NULL, 0);
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > >  };
> > > >
> > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > >       int ret;
> > > >
> > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > >                                     DRM_MODE_ENCODER_DSI);
> > > >       if (ret) {
> > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > >       }
> > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > >
> > > > -     drm_connector_helper_add(&dsi->connector,
> > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > -                              &sun6i_dsi_connector_funcs,
> > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > >       if (ret) {
> > > > -             dev_err(dsi->dev,
> > > > -                     "Couldn't initialise the DSI connector\n");
> > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > >               goto err_cleanup_connector;
> > > >       }
> > > >
> > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > +     if (dsi->panel) {
> > > > +             drm_connector_helper_add(&dsi->connector,
> > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > +                                      &sun6i_dsi_connector_funcs,
> > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > +             if (ret) {
> > > > +                     dev_err(dsi->dev,
> > > > +                             "Couldn't initialise the DSI connector\n");
> > > > +                     goto err_cleanup_connector;
> > > > +             }
> > > > +
> > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > +     }
> > > >
> > > >       return 0;
> > > >
> > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > >                           struct mipi_dsi_device *device)
> > > >  {
> > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > +     struct device_node *remote = device->dev.of_node;
> > > >       int ret;
> > > >
> > > > -     if (IS_ERR(panel))
> > > > -             return PTR_ERR(panel);
> > > > +     if (!of_device_is_available(remote)) {
> > > > +             /**
> > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > +              * bridge drivers instead of conventional device.
> > > > +              *
> > > > +              * Those are probed via host of_node instead of device of_node.
> > > > +              */
> > >
> > > I have no idea what you mean here. Can you expand on what issue you've
> > > tried to solve here?
> >
> > I2C interface DSI bridges will register DSI host on the bridge
> > drivers.
>
> DSI bridges don't register a DSI host.

Please check what I mean here,
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623

I've tested it anyway, if you have any relevant one please check as well.

>
> > Those can be found using host->dev->of_node and cannot be find using
> > device->dev.of_node
> >
> > >
> > > > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > > > +             if (!remote)
> > > > +                     return -ENODEV;
> > > > +     }
> > > > +
> > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > +     if (IS_ERR(dsi->panel)) {
> > > > +             dsi->panel = NULL;
> > > > +
> > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > +             }
> > > > +     } else {
> > > > +             dsi->next_bridge = NULL;
> > > > +     }
> > > > +
> > > > +     of_node_put(remote);
> > >
> > > Using devm_drm_of_get_bridge would greatly simplify the driver
> >
> > I'm aware of this and this would break the existing sunxi dsi binding,
> > we are not using ports based pipeline in dsi node. Of-course you have
> > pointed the same before, please check below
> > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
>
> Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> bindings and look for a panel or bridge not only through the OF graph,
> but also on the child nodes

Okay. I need to check this.

Thanks,
Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22 14:09             ` Maxime Ripard
@ 2021-11-22 14:31               ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 14:31 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 7:39 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > > It's perfectly valid to dereference the pointer in atomic_enable, and
> > > that patch would consume memory for no particular reason.
> >
> > Again, I'm not pointing any mistake in dereference and certainly not
> > understand about what memory consumption issue here.
>
> You add a struct drm_display_mode field to struct sun6i_dsi. It
> increases the size of struct sun6i_dsi of sizeof(struct
> drm_display_mode).
>
> > I'm doing it here since I'm doing it via mode_set in other drivers. No
> > problem for me either way.
>
> But *why* are you doing so?
>
> There might be a valid reason in other drivers, but there's none here
> (that you mentioned at least).

The reason is to use existing bridge function instead of dereference
ie what I've mentioned. I don't have any other reasons.

Jagan.

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 14:31               ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 14:31 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 7:39 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > > It's perfectly valid to dereference the pointer in atomic_enable, and
> > > that patch would consume memory for no particular reason.
> >
> > Again, I'm not pointing any mistake in dereference and certainly not
> > understand about what memory consumption issue here.
>
> You add a struct drm_display_mode field to struct sun6i_dsi. It
> increases the size of struct sun6i_dsi of sizeof(struct
> drm_display_mode).
>
> > I'm doing it here since I'm doing it via mode_set in other drivers. No
> > problem for me either way.
>
> But *why* are you doing so?
>
> There might be a valid reason in other drivers, but there's none here
> (that you mentioned at least).

The reason is to use existing bridge function instead of dereference
ie what I've mentioned. I don't have any other reasons.

Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 14:19           ` Jagan Teki
@ 2021-11-22 15:04             ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 15:04 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 07:49:26PM +0530, Jagan Teki wrote:
> On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > > Some display panels would come up with a non-DSI output, those
> > > > > can have an option to connect the DSI host by means of interface
> > > > > bridge converter.
> > > > >
> > > > > This DSI to non-DSI interface bridge converter would requires
> > > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > > Host to Interface bridge.
> > > >
> > > > In order to do this you would need to use the DRM bridge API...
> > >
> > > Sorry, which bridge API do you mean?
> >
> > Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> > we're doing in sun4i_rgb.c
> 
> Yes, we have drm_bridge_attach in bind and bridge_function.attach
> calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
> Not sure which API's I've missed.

None, that's my point, you don't need anything else in order to do what
you wanted to achieve.

> >
> > > > > This patch convert the existing to a drm bridge driver with a
> > > > > built-in encoder support for compatibility with existing
> > > > > component drivers.
> > > >
> > > > ... but changing the encoder driver to a bridge is completely
> > > > unnecessary to do so. Why did you need to make that change?
> > >
> > > Idea of this series is to convert the driver to bridge and use the
> > > latest bridge function from the v1 series.
> >
> > Ok, but it's not at all what you mention in your commit log? You don't
> > need any of that in order to support a bridge downstream.
> 
> I've mentioned "Converting to bridge driver" and thought it has
> meaning of converting encoder related function to bridge functions as
> well. Not think about specific description to describe on commit
> message. Will update this.

But you provided no reason to do so. The only one you did mention was
that you wanted to support downstream bridges, but you don't need to
convert the DSI driver to a bridge in order to do that.

> > > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > > >
> > > > > ---
> > > > > Changes for v5:
> > > > > - add atomic APIs
> > > > > - find host and device variant DSI devices.
> > > > > Changes for v4, v3:
> > > > > - none
> > > > >
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > @@ -21,6 +21,7 @@
> > > > >
> > > > >  #include <drm/drm_atomic_helper.h>
> > > > >  #include <drm/drm_mipi_dsi.h>
> > > > > +#include <drm/drm_of.h>
> > > > >  #include <drm/drm_panel.h>
> > > > >  #include <drm/drm_print.h>
> > > > >  #include <drm/drm_probe_helper.h>
> > > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > > >       return 0;
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > > >       struct mipi_dsi_device *device = dsi->device;
> > > > >       union phy_configure_opts opts = { };
> > > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_prepare(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Please use the proper helpers.
> > >
> > > If we use bridge_functions we need to take atomic functions as
> > > precedence as the next bridge functions might convert atomic calls.
> >
> > We've had this discussion over and over again, but this is something
> > that needs to be documented and / or in your commit log.
> >
> > You must not deviate from the standard (and expected) behavior without
> > any kind of justification.
> 
> Not exactly sure about what you mean, sorry. All these atomic bridge
> functions are already documented if I'm not wrong and Laurent have
> patches to switch the normal functions to atomic. Not sure what else
> need to document here and need justification for it if the driver is
> converting to bridge.

There's two separate bridge in that discussion: the DSI controller
itself that you convert to a bridge, and the downstream DSI -> whatever
bridge.

The atomic functions in the "DSI controller bridge" are fine. But that
comment was about calling the downstream bridge ops directly from the
driver, which is something that no other driver is doing, deviates from
the expectations, and you didn't provide any explanation for that.

> >
> > > >
> > > > >       /*
> > > > >        * FIXME: This should be moved after the switch to HS mode.
> > > > >        *
> > > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_enable(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Ditto
> > > >
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > > >
> > > > >       udelay(1000);
> > > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > >
> > > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > > >
> > > > >       if (dsi->panel) {
> > > > >               drm_panel_disable(dsi->panel);
> > > > >               drm_panel_unprepare(dsi->panel);
> > > > > +     } else if (dsi->next_bridge) {
> > > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > > >
> > > > Ditto
> > > >
> > > > >       }
> > > > >
> > > > >       phy_power_off(dsi->dphy);
> > > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > > >  };
> > > > >
> > > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > > +                                enum drm_bridge_attach_flags flags)
> > > > > +{
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +
> > > > > +     if (dsi->next_bridge)
> > > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > > +                                      NULL, 0);
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > > >  };
> > > > >
> > > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > > >       int ret;
> > > > >
> > > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > > >                                     DRM_MODE_ENCODER_DSI);
> > > > >       if (ret) {
> > > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       }
> > > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > > >
> > > > > -     drm_connector_helper_add(&dsi->connector,
> > > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > > -                              &sun6i_dsi_connector_funcs,
> > > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > > >       if (ret) {
> > > > > -             dev_err(dsi->dev,
> > > > > -                     "Couldn't initialise the DSI connector\n");
> > > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > > >               goto err_cleanup_connector;
> > > > >       }
> > > > >
> > > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     if (dsi->panel) {
> > > > > +             drm_connector_helper_add(&dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_funcs,
> > > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > > +             if (ret) {
> > > > > +                     dev_err(dsi->dev,
> > > > > +                             "Couldn't initialise the DSI connector\n");
> > > > > +                     goto err_cleanup_connector;
> > > > > +             }
> > > > > +
> > > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     }
> > > > >
> > > > >       return 0;
> > > > >
> > > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > > >                           struct mipi_dsi_device *device)
> > > > >  {
> > > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > > +     struct device_node *remote = device->dev.of_node;
> > > > >       int ret;
> > > > >
> > > > > -     if (IS_ERR(panel))
> > > > > -             return PTR_ERR(panel);
> > > > > +     if (!of_device_is_available(remote)) {
> > > > > +             /**
> > > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > > +              * bridge drivers instead of conventional device.
> > > > > +              *
> > > > > +              * Those are probed via host of_node instead of device of_node.
> > > > > +              */
> > > >
> > > > I have no idea what you mean here. Can you expand on what issue you've
> > > > tried to solve here?
> > >
> > > I2C interface DSI bridges will register DSI host on the bridge
> > > drivers.
> >
> > DSI bridges don't register a DSI host.
> 
> Please check what I mean here,
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623
> 
> I've tested it anyway, if you have any relevant one please check as well.

That driver doesn't register a DSI Host though? It registers a DSI
device

Maxime

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 15:04             ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 15:04 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 07:49:26PM +0530, Jagan Teki wrote:
> On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > > Some display panels would come up with a non-DSI output, those
> > > > > can have an option to connect the DSI host by means of interface
> > > > > bridge converter.
> > > > >
> > > > > This DSI to non-DSI interface bridge converter would requires
> > > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > > Host to Interface bridge.
> > > >
> > > > In order to do this you would need to use the DRM bridge API...
> > >
> > > Sorry, which bridge API do you mean?
> >
> > Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> > we're doing in sun4i_rgb.c
> 
> Yes, we have drm_bridge_attach in bind and bridge_function.attach
> calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
> Not sure which API's I've missed.

None, that's my point, you don't need anything else in order to do what
you wanted to achieve.

> >
> > > > > This patch convert the existing to a drm bridge driver with a
> > > > > built-in encoder support for compatibility with existing
> > > > > component drivers.
> > > >
> > > > ... but changing the encoder driver to a bridge is completely
> > > > unnecessary to do so. Why did you need to make that change?
> > >
> > > Idea of this series is to convert the driver to bridge and use the
> > > latest bridge function from the v1 series.
> >
> > Ok, but it's not at all what you mention in your commit log? You don't
> > need any of that in order to support a bridge downstream.
> 
> I've mentioned "Converting to bridge driver" and thought it has
> meaning of converting encoder related function to bridge functions as
> well. Not think about specific description to describe on commit
> message. Will update this.

But you provided no reason to do so. The only one you did mention was
that you wanted to support downstream bridges, but you don't need to
convert the DSI driver to a bridge in order to do that.

> > > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > > >
> > > > > ---
> > > > > Changes for v5:
> > > > > - add atomic APIs
> > > > > - find host and device variant DSI devices.
> > > > > Changes for v4, v3:
> > > > > - none
> > > > >
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > @@ -21,6 +21,7 @@
> > > > >
> > > > >  #include <drm/drm_atomic_helper.h>
> > > > >  #include <drm/drm_mipi_dsi.h>
> > > > > +#include <drm/drm_of.h>
> > > > >  #include <drm/drm_panel.h>
> > > > >  #include <drm/drm_print.h>
> > > > >  #include <drm/drm_probe_helper.h>
> > > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > > >       return 0;
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > > >       struct mipi_dsi_device *device = dsi->device;
> > > > >       union phy_configure_opts opts = { };
> > > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_prepare(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Please use the proper helpers.
> > >
> > > If we use bridge_functions we need to take atomic functions as
> > > precedence as the next bridge functions might convert atomic calls.
> >
> > We've had this discussion over and over again, but this is something
> > that needs to be documented and / or in your commit log.
> >
> > You must not deviate from the standard (and expected) behavior without
> > any kind of justification.
> 
> Not exactly sure about what you mean, sorry. All these atomic bridge
> functions are already documented if I'm not wrong and Laurent have
> patches to switch the normal functions to atomic. Not sure what else
> need to document here and need justification for it if the driver is
> converting to bridge.

There's two separate bridge in that discussion: the DSI controller
itself that you convert to a bridge, and the downstream DSI -> whatever
bridge.

The atomic functions in the "DSI controller bridge" are fine. But that
comment was about calling the downstream bridge ops directly from the
driver, which is something that no other driver is doing, deviates from
the expectations, and you didn't provide any explanation for that.

> >
> > > >
> > > > >       /*
> > > > >        * FIXME: This should be moved after the switch to HS mode.
> > > > >        *
> > > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_enable(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Ditto
> > > >
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > > >
> > > > >       udelay(1000);
> > > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > >
> > > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > > >
> > > > >       if (dsi->panel) {
> > > > >               drm_panel_disable(dsi->panel);
> > > > >               drm_panel_unprepare(dsi->panel);
> > > > > +     } else if (dsi->next_bridge) {
> > > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > > >
> > > > Ditto
> > > >
> > > > >       }
> > > > >
> > > > >       phy_power_off(dsi->dphy);
> > > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > > >  };
> > > > >
> > > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > > +                                enum drm_bridge_attach_flags flags)
> > > > > +{
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +
> > > > > +     if (dsi->next_bridge)
> > > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > > +                                      NULL, 0);
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > > >  };
> > > > >
> > > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > > >       int ret;
> > > > >
> > > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > > >                                     DRM_MODE_ENCODER_DSI);
> > > > >       if (ret) {
> > > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       }
> > > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > > >
> > > > > -     drm_connector_helper_add(&dsi->connector,
> > > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > > -                              &sun6i_dsi_connector_funcs,
> > > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > > >       if (ret) {
> > > > > -             dev_err(dsi->dev,
> > > > > -                     "Couldn't initialise the DSI connector\n");
> > > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > > >               goto err_cleanup_connector;
> > > > >       }
> > > > >
> > > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     if (dsi->panel) {
> > > > > +             drm_connector_helper_add(&dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_funcs,
> > > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > > +             if (ret) {
> > > > > +                     dev_err(dsi->dev,
> > > > > +                             "Couldn't initialise the DSI connector\n");
> > > > > +                     goto err_cleanup_connector;
> > > > > +             }
> > > > > +
> > > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     }
> > > > >
> > > > >       return 0;
> > > > >
> > > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > > >                           struct mipi_dsi_device *device)
> > > > >  {
> > > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > > +     struct device_node *remote = device->dev.of_node;
> > > > >       int ret;
> > > > >
> > > > > -     if (IS_ERR(panel))
> > > > > -             return PTR_ERR(panel);
> > > > > +     if (!of_device_is_available(remote)) {
> > > > > +             /**
> > > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > > +              * bridge drivers instead of conventional device.
> > > > > +              *
> > > > > +              * Those are probed via host of_node instead of device of_node.
> > > > > +              */
> > > >
> > > > I have no idea what you mean here. Can you expand on what issue you've
> > > > tried to solve here?
> > >
> > > I2C interface DSI bridges will register DSI host on the bridge
> > > drivers.
> >
> > DSI bridges don't register a DSI host.
> 
> Please check what I mean here,
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623
> 
> I've tested it anyway, if you have any relevant one please check as well.

That driver doesn't register a DSI Host though? It registers a DSI
device

Maxime

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22 14:31               ` Jagan Teki
@ 2021-11-22 15:06                 ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 15:06 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 08:01:47PM +0530, Jagan Teki wrote:
> On Mon, Nov 22, 2021 at 7:39 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > > > It's perfectly valid to dereference the pointer in atomic_enable, and
> > > > that patch would consume memory for no particular reason.
> > >
> > > Again, I'm not pointing any mistake in dereference and certainly not
> > > understand about what memory consumption issue here.
> >
> > You add a struct drm_display_mode field to struct sun6i_dsi. It
> > increases the size of struct sun6i_dsi of sizeof(struct
> > drm_display_mode).
> >
> > > I'm doing it here since I'm doing it via mode_set in other drivers. No
> > > problem for me either way.
> >
> > But *why* are you doing so?
> >
> > There might be a valid reason in other drivers, but there's none here
> > (that you mentioned at least).
> 
> The reason is to use existing bridge function instead of dereference
> ie what I've mentioned. I don't have any other reasons.

This discussion is going in circles. Unless you have a reason other than
"because we can", NAK for the reasons already stated above.

Maxime

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 15:06                 ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-22 15:06 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 08:01:47PM +0530, Jagan Teki wrote:
> On Mon, Nov 22, 2021 at 7:39 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > > > It's perfectly valid to dereference the pointer in atomic_enable, and
> > > > that patch would consume memory for no particular reason.
> > >
> > > Again, I'm not pointing any mistake in dereference and certainly not
> > > understand about what memory consumption issue here.
> >
> > You add a struct drm_display_mode field to struct sun6i_dsi. It
> > increases the size of struct sun6i_dsi of sizeof(struct
> > drm_display_mode).
> >
> > > I'm doing it here since I'm doing it via mode_set in other drivers. No
> > > problem for me either way.
> >
> > But *why* are you doing so?
> >
> > There might be a valid reason in other drivers, but there's none here
> > (that you mentioned at least).
> 
> The reason is to use existing bridge function instead of dereference
> ie what I've mentioned. I don't have any other reasons.

This discussion is going in circles. Unless you have a reason other than
"because we can", NAK for the reasons already stated above.

Maxime

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
  2021-11-22 15:06                 ` Maxime Ripard
@ 2021-11-22 15:17                   ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 15:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 8:36 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 08:01:47PM +0530, Jagan Teki wrote:
> > On Mon, Nov 22, 2021 at 7:39 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > > > > It's perfectly valid to dereference the pointer in atomic_enable, and
> > > > > that patch would consume memory for no particular reason.
> > > >
> > > > Again, I'm not pointing any mistake in dereference and certainly not
> > > > understand about what memory consumption issue here.
> > >
> > > You add a struct drm_display_mode field to struct sun6i_dsi. It
> > > increases the size of struct sun6i_dsi of sizeof(struct
> > > drm_display_mode).
> > >
> > > > I'm doing it here since I'm doing it via mode_set in other drivers. No
> > > > problem for me either way.
> > >
> > > But *why* are you doing so?
> > >
> > > There might be a valid reason in other drivers, but there's none here
> > > (that you mentioned at least).
> >
> > The reason is to use existing bridge function instead of dereference
> > ie what I've mentioned. I don't have any other reasons.
>
> This discussion is going in circles. Unless you have a reason other than
> "because we can", NAK for the reasons already stated above.

Agreed your point.

Thanks,
Jagan.

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

* Re: [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function
@ 2021-11-22 15:17                   ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-22 15:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 8:36 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 08:01:47PM +0530, Jagan Teki wrote:
> > On Mon, Nov 22, 2021 at 7:39 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Mon, Nov 22, 2021 at 07:21:57PM +0530, Jagan Teki wrote:
> > > > > It's perfectly valid to dereference the pointer in atomic_enable, and
> > > > > that patch would consume memory for no particular reason.
> > > >
> > > > Again, I'm not pointing any mistake in dereference and certainly not
> > > > understand about what memory consumption issue here.
> > >
> > > You add a struct drm_display_mode field to struct sun6i_dsi. It
> > > increases the size of struct sun6i_dsi of sizeof(struct
> > > drm_display_mode).
> > >
> > > > I'm doing it here since I'm doing it via mode_set in other drivers. No
> > > > problem for me either way.
> > >
> > > But *why* are you doing so?
> > >
> > > There might be a valid reason in other drivers, but there's none here
> > > (that you mentioned at least).
> >
> > The reason is to use existing bridge function instead of dereference
> > ie what I've mentioned. I don't have any other reasons.
>
> This discussion is going in circles. Unless you have a reason other than
> "because we can", NAK for the reasons already stated above.

Agreed your point.

Thanks,
Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 13:16       ` Jagan Teki
@ 2021-11-22 15:35         ` Neil Armstrong
  -1 siblings, 0 replies; 72+ messages in thread
From: Neil Armstrong @ 2021-11-22 15:35 UTC (permalink / raw)
  To: Jagan Teki
  Cc: linux-amarula, linux-sunxi, dri-devel, Chen-Yu Tsai, Robert Foss,
	Sam Ravnborg, linux-arm-kernel, Laurent Pinchart

Hi,

On 22/11/2021 14:16, Jagan Teki wrote:
> Hi Neil,
> 
> On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> On 22/11/2021 07:52, Jagan Teki wrote:
>>> Some display panels would come up with a non-DSI output, those
>>> can have an option to connect the DSI host by means of interface
>>> bridge converter.
>>>
>>> This DSI to non-DSI interface bridge converter would requires
>>> DSI Host to handle drm bridge functionalities in order to DSI
>>> Host to Interface bridge.
>>>
>>> This patch convert the existing to a drm bridge driver with a
>>> built-in encoder support for compatibility with existing
>>> component drivers.
>>>
>>> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
>>> ---
>>> Changes for v5:
>>> - add atomic APIs
>>> - find host and device variant DSI devices.
>>> Changes for v4, v3:
>>> - none
>>>
>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>>>  2 files changed, 96 insertions(+), 23 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>> index 43d9c9e5198d..a6a272b55f77 100644
>>> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>> @@ -21,6 +21,7 @@
>>>
>>>  #include <drm/drm_atomic_helper.h>
>>>  #include <drm/drm_mipi_dsi.h>
>>> +#include <drm/drm_of.h>
>>>  #include <drm/drm_panel.h>
>>>  #include <drm/drm_print.h>
>>>  #include <drm/drm_probe_helper.h>
>>> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>>>       return 0;
>>>  }
>>>
>>> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
>>> +                                        struct drm_bridge_state *old_bridge_state)
>>>  {
>>> -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
>>> -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
>>> +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>>> +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>>>       struct mipi_dsi_device *device = dsi->device;
>>>       union phy_configure_opts opts = { };
>>>       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
>>> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>       if (dsi->panel)
>>>               drm_panel_prepare(dsi->panel);
>>>
>>> +     if (dsi->next_bridge)
>>> +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
>>> +
>>>       /*
>>>        * FIXME: This should be moved after the switch to HS mode.
>>>        *
>>> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>       if (dsi->panel)
>>>               drm_panel_enable(dsi->panel);
>>>
>>> +     if (dsi->next_bridge)
>>> +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
>>> +
>>
>>
>> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
>> be called automatically on the bridge chain.
> 
> Correct, but the existing bridge chain (stack) is not compatible with
> sun6i DSI start sequence. We cannot send any DCS once we start HS
> mode.
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775

It's a classical DSI sequence init issue, look at dw-mipi-dsi:
https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c

We setup the "command-mode" (low-speed) withing mode_set so when the next bridge dsi_pre_enable is called,
low-speed DCS can be sent, then the bridge enable() sets video mode (high-speed).
The disable still needs to call the next_bridge post_disable :
https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L893

You can send any low-speed DCS once HS mode is started if the HW supports it and the driver handles it, look
at the https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L397
The MIPI_DSI_MODE_LPM and MIPI_DSI_MSG_USE_LPM is used for that.

Neil

> 
> This specific problem can be fixed only if we change the bridge chain
> from stack to queue. Please check this series
> https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/
> 
> Jagan.
> 


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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 15:35         ` Neil Armstrong
  0 siblings, 0 replies; 72+ messages in thread
From: Neil Armstrong @ 2021-11-22 15:35 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi,

On 22/11/2021 14:16, Jagan Teki wrote:
> Hi Neil,
> 
> On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> On 22/11/2021 07:52, Jagan Teki wrote:
>>> Some display panels would come up with a non-DSI output, those
>>> can have an option to connect the DSI host by means of interface
>>> bridge converter.
>>>
>>> This DSI to non-DSI interface bridge converter would requires
>>> DSI Host to handle drm bridge functionalities in order to DSI
>>> Host to Interface bridge.
>>>
>>> This patch convert the existing to a drm bridge driver with a
>>> built-in encoder support for compatibility with existing
>>> component drivers.
>>>
>>> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
>>> ---
>>> Changes for v5:
>>> - add atomic APIs
>>> - find host and device variant DSI devices.
>>> Changes for v4, v3:
>>> - none
>>>
>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>>>  2 files changed, 96 insertions(+), 23 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>> index 43d9c9e5198d..a6a272b55f77 100644
>>> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>> @@ -21,6 +21,7 @@
>>>
>>>  #include <drm/drm_atomic_helper.h>
>>>  #include <drm/drm_mipi_dsi.h>
>>> +#include <drm/drm_of.h>
>>>  #include <drm/drm_panel.h>
>>>  #include <drm/drm_print.h>
>>>  #include <drm/drm_probe_helper.h>
>>> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>>>       return 0;
>>>  }
>>>
>>> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
>>> +                                        struct drm_bridge_state *old_bridge_state)
>>>  {
>>> -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
>>> -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
>>> +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>>> +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>>>       struct mipi_dsi_device *device = dsi->device;
>>>       union phy_configure_opts opts = { };
>>>       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
>>> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>       if (dsi->panel)
>>>               drm_panel_prepare(dsi->panel);
>>>
>>> +     if (dsi->next_bridge)
>>> +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
>>> +
>>>       /*
>>>        * FIXME: This should be moved after the switch to HS mode.
>>>        *
>>> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>       if (dsi->panel)
>>>               drm_panel_enable(dsi->panel);
>>>
>>> +     if (dsi->next_bridge)
>>> +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
>>> +
>>
>>
>> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
>> be called automatically on the bridge chain.
> 
> Correct, but the existing bridge chain (stack) is not compatible with
> sun6i DSI start sequence. We cannot send any DCS once we start HS
> mode.
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775

It's a classical DSI sequence init issue, look at dw-mipi-dsi:
https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c

We setup the "command-mode" (low-speed) withing mode_set so when the next bridge dsi_pre_enable is called,
low-speed DCS can be sent, then the bridge enable() sets video mode (high-speed).
The disable still needs to call the next_bridge post_disable :
https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L893

You can send any low-speed DCS once HS mode is started if the HW supports it and the driver handles it, look
at the https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L397
The MIPI_DSI_MODE_LPM and MIPI_DSI_MSG_USE_LPM is used for that.

Neil

> 
> This specific problem can be fixed only if we change the bridge chain
> from stack to queue. Please check this series
> https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/
> 
> Jagan.
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 15:35         ` Neil Armstrong
@ 2021-11-22 17:19           ` Dave Stevenson
  -1 siblings, 0 replies; 72+ messages in thread
From: Dave Stevenson @ 2021-11-22 17:19 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Sam Ravnborg, DRI Development, Chen-Yu Tsai, Robert Foss,
	linux-sunxi, Jagan Teki, linux-amarula, linux-arm-kernel,
	Laurent Pinchart

Hi

On Mon, 22 Nov 2021 at 15:35, Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> Hi,
>
> On 22/11/2021 14:16, Jagan Teki wrote:
> > Hi Neil,
> >
> > On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> >>
> >> On 22/11/2021 07:52, Jagan Teki wrote:
> >>> Some display panels would come up with a non-DSI output, those
> >>> can have an option to connect the DSI host by means of interface
> >>> bridge converter.
> >>>
> >>> This DSI to non-DSI interface bridge converter would requires
> >>> DSI Host to handle drm bridge functionalities in order to DSI
> >>> Host to Interface bridge.
> >>>
> >>> This patch convert the existing to a drm bridge driver with a
> >>> built-in encoder support for compatibility with existing
> >>> component drivers.
> >>>
> >>> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> >>> ---
> >>> Changes for v5:
> >>> - add atomic APIs
> >>> - find host and device variant DSI devices.
> >>> Changes for v4, v3:
> >>> - none
> >>>
> >>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >>>  2 files changed, 96 insertions(+), 23 deletions(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> >>> index 43d9c9e5198d..a6a272b55f77 100644
> >>> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> >>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> >>> @@ -21,6 +21,7 @@
> >>>
> >>>  #include <drm/drm_atomic_helper.h>
> >>>  #include <drm/drm_mipi_dsi.h>
> >>> +#include <drm/drm_of.h>
> >>>  #include <drm/drm_panel.h>
> >>>  #include <drm/drm_print.h>
> >>>  #include <drm/drm_probe_helper.h>
> >>> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >>>       return 0;
> >>>  }
> >>>
> >>> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >>> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> >>> +                                        struct drm_bridge_state *old_bridge_state)
> >>>  {
> >>> -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> >>> -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> >>> +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> >>> +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >>>       struct mipi_dsi_device *device = dsi->device;
> >>>       union phy_configure_opts opts = { };
> >>>       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> >>> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >>>       if (dsi->panel)
> >>>               drm_panel_prepare(dsi->panel);
> >>>
> >>> +     if (dsi->next_bridge)
> >>> +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> >>> +
> >>>       /*
> >>>        * FIXME: This should be moved after the switch to HS mode.
> >>>        *
> >>> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >>>       if (dsi->panel)
> >>>               drm_panel_enable(dsi->panel);
> >>>
> >>> +     if (dsi->next_bridge)
> >>> +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> >>> +
> >>
> >>
> >> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
> >> be called automatically on the bridge chain.
> >
> > Correct, but the existing bridge chain (stack) is not compatible with
> > sun6i DSI start sequence. We cannot send any DCS once we start HS
> > mode.
> > https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775
>
> It's a classical DSI sequence init issue, look at dw-mipi-dsi:
> https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
>
> We setup the "command-mode" (low-speed) withing mode_set so when the next bridge dsi_pre_enable is called,
> low-speed DCS can be sent, then the bridge enable() sets video mode (high-speed).
> The disable still needs to call the next_bridge post_disable :
> https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L893

Doesn't that mean the post_disable gets called twice? Once by the
dw-mipi-dsi driver and once by the framework.

> You can send any low-speed DCS once HS mode is started if the HW supports it and the driver handles it, look
> at the https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L397
> The MIPI_DSI_MODE_LPM and MIPI_DSI_MSG_USE_LPM is used for that.

This seems to be the same question as I was asking back in [1] and
continued in [2].

vc4 and Exynos break the chain apart so that they can initialise the
DSI host before the panel.
That doesn't work if the DSI host is an encoder, as the encoder
mode_valid call is missing the struct drm_display_info needed for
calling the bridge mode_valid function.
It also fails with the atomic operations as the framework can't see
the bridges/panels beyond the DSI host, and therefore doesn't create
the state for them.
This is why I've been trying to reinstate the chain as a whole for
vc4, however we then hit the issue of the downstream bridge/panel
pre_enables being called before the DSI host (be it a bridge or
encoder), therefore it's unlikely to have been powered up or
configured. The DSI bus is also generally going to be powered down
during the pre_enables, when many displays want it at LP-11.

It sounds like dw-mipi-dsi has a hack to the bridge operations and
powers up in mode_set (not what the docs say). sun6i sounds to have
some similar restrictions that these patches are trying to work
around.

The documentation for struct mipi_dsi_host_ops transfer [3] states:
 * Also note that those callbacks can be called no matter the state the
 * host is in. Drivers that need the underlying device to be powered to
 * perform these operations will first need to make sure it's been
 * properly enabled.

It sounds like neither of the above drivers do this.
As stated it would be valid to request a transfer from attach, at
which point mode_set hasn't been called, so dw-mipi-dsi falls down
there. sun4i can't send commands once in HS mode.
What's the correct behaviour if the hardware can't support sending the
transfer due to the state? Returning an error would be an obvious
step.


Is it time to actually thrash out the specifics of how DSI should be
implemented, and fix the DSI framework where it doesn't currently
work?

Previously proposed have been:
- a pre_pre_enable (called from encoder outwards) and a matching
post_post_disable (towards the encoder).
- a mechanism for the panel/bridge to request that the PHY is powered
up, so the bus is at LP-11, and the clock lane running if
!MIPI_DSI_CLOCK_NON_CONTINUOUS, before powering up the bridge.
(Powering up for transfers would be internal to the DSI host driver).

Do either or both of those solve the problem in this case? The first
is the easiest to implement, but does it cover all the current use
cases?
I don't quite see why dw-mipi-dsi calls the downstream post_disable
early. Are there really devices that want to send DSI DCS transfers
during shutdown? I'm guessing that's the reasoning, same as the power
up via mode_set.

There are already bridge drivers such as SN65DSI83 which don't follow
the requirements specified in the datasheet for power up sequences due
to issues in the framework. Hacking the bridge seems wrong.
(It configures the bridge from enable because it needs the DSI clock
lane running and LP-11 on the data lanes, but actually enable has the
data lanes active too. It should be in pre_enable, but the clock lane
isn't running then.)

Also undefined in DRM is how DSI burst mode parameters should be
configured, and the exact meaning of half the MIPI_DSI_MODE_* defines
and their interactions (eg MIPI_DSI_VIDEO_MODE_BURST, but not
MIPI_DSI_VIDEO [4]?).

Cheers
 Dave

[1] https://lists.freedesktop.org/archives/dri-devel/2021-July/313576.html
[2] https://lists.freedesktop.org/archives/dri-devel/2021-October/325853.html
[3] https://elixir.bootlin.com/linux/latest/source/include/drm/drm_mipi_dsi.h#L84
[4] https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c#L226


> >
> > This specific problem can be fixed only if we change the bridge chain
> > from stack to queue. Please check this series
> > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/
> >
> > Jagan.
> >
>

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-22 17:19           ` Dave Stevenson
  0 siblings, 0 replies; 72+ messages in thread
From: Dave Stevenson @ 2021-11-22 17:19 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Jagan Teki, linux-amarula, linux-sunxi, DRI Development,
	Chen-Yu Tsai, Robert Foss, Sam Ravnborg, linux-arm-kernel,
	Laurent Pinchart

Hi

On Mon, 22 Nov 2021 at 15:35, Neil Armstrong <narmstrong@baylibre.com> wrote:
>
> Hi,
>
> On 22/11/2021 14:16, Jagan Teki wrote:
> > Hi Neil,
> >
> > On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
> >>
> >> On 22/11/2021 07:52, Jagan Teki wrote:
> >>> Some display panels would come up with a non-DSI output, those
> >>> can have an option to connect the DSI host by means of interface
> >>> bridge converter.
> >>>
> >>> This DSI to non-DSI interface bridge converter would requires
> >>> DSI Host to handle drm bridge functionalities in order to DSI
> >>> Host to Interface bridge.
> >>>
> >>> This patch convert the existing to a drm bridge driver with a
> >>> built-in encoder support for compatibility with existing
> >>> component drivers.
> >>>
> >>> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> >>> ---
> >>> Changes for v5:
> >>> - add atomic APIs
> >>> - find host and device variant DSI devices.
> >>> Changes for v4, v3:
> >>> - none
> >>>
> >>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> >>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> >>>  2 files changed, 96 insertions(+), 23 deletions(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> >>> index 43d9c9e5198d..a6a272b55f77 100644
> >>> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> >>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> >>> @@ -21,6 +21,7 @@
> >>>
> >>>  #include <drm/drm_atomic_helper.h>
> >>>  #include <drm/drm_mipi_dsi.h>
> >>> +#include <drm/drm_of.h>
> >>>  #include <drm/drm_panel.h>
> >>>  #include <drm/drm_print.h>
> >>>  #include <drm/drm_probe_helper.h>
> >>> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> >>>       return 0;
> >>>  }
> >>>
> >>> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >>> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> >>> +                                        struct drm_bridge_state *old_bridge_state)
> >>>  {
> >>> -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> >>> -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> >>> +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> >>> +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> >>>       struct mipi_dsi_device *device = dsi->device;
> >>>       union phy_configure_opts opts = { };
> >>>       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> >>> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >>>       if (dsi->panel)
> >>>               drm_panel_prepare(dsi->panel);
> >>>
> >>> +     if (dsi->next_bridge)
> >>> +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> >>> +
> >>>       /*
> >>>        * FIXME: This should be moved after the switch to HS mode.
> >>>        *
> >>> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> >>>       if (dsi->panel)
> >>>               drm_panel_enable(dsi->panel);
> >>>
> >>> +     if (dsi->next_bridge)
> >>> +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> >>> +
> >>
> >>
> >> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
> >> be called automatically on the bridge chain.
> >
> > Correct, but the existing bridge chain (stack) is not compatible with
> > sun6i DSI start sequence. We cannot send any DCS once we start HS
> > mode.
> > https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775
>
> It's a classical DSI sequence init issue, look at dw-mipi-dsi:
> https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
>
> We setup the "command-mode" (low-speed) withing mode_set so when the next bridge dsi_pre_enable is called,
> low-speed DCS can be sent, then the bridge enable() sets video mode (high-speed).
> The disable still needs to call the next_bridge post_disable :
> https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L893

Doesn't that mean the post_disable gets called twice? Once by the
dw-mipi-dsi driver and once by the framework.

> You can send any low-speed DCS once HS mode is started if the HW supports it and the driver handles it, look
> at the https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L397
> The MIPI_DSI_MODE_LPM and MIPI_DSI_MSG_USE_LPM is used for that.

This seems to be the same question as I was asking back in [1] and
continued in [2].

vc4 and Exynos break the chain apart so that they can initialise the
DSI host before the panel.
That doesn't work if the DSI host is an encoder, as the encoder
mode_valid call is missing the struct drm_display_info needed for
calling the bridge mode_valid function.
It also fails with the atomic operations as the framework can't see
the bridges/panels beyond the DSI host, and therefore doesn't create
the state for them.
This is why I've been trying to reinstate the chain as a whole for
vc4, however we then hit the issue of the downstream bridge/panel
pre_enables being called before the DSI host (be it a bridge or
encoder), therefore it's unlikely to have been powered up or
configured. The DSI bus is also generally going to be powered down
during the pre_enables, when many displays want it at LP-11.

It sounds like dw-mipi-dsi has a hack to the bridge operations and
powers up in mode_set (not what the docs say). sun6i sounds to have
some similar restrictions that these patches are trying to work
around.

The documentation for struct mipi_dsi_host_ops transfer [3] states:
 * Also note that those callbacks can be called no matter the state the
 * host is in. Drivers that need the underlying device to be powered to
 * perform these operations will first need to make sure it's been
 * properly enabled.

It sounds like neither of the above drivers do this.
As stated it would be valid to request a transfer from attach, at
which point mode_set hasn't been called, so dw-mipi-dsi falls down
there. sun4i can't send commands once in HS mode.
What's the correct behaviour if the hardware can't support sending the
transfer due to the state? Returning an error would be an obvious
step.


Is it time to actually thrash out the specifics of how DSI should be
implemented, and fix the DSI framework where it doesn't currently
work?

Previously proposed have been:
- a pre_pre_enable (called from encoder outwards) and a matching
post_post_disable (towards the encoder).
- a mechanism for the panel/bridge to request that the PHY is powered
up, so the bus is at LP-11, and the clock lane running if
!MIPI_DSI_CLOCK_NON_CONTINUOUS, before powering up the bridge.
(Powering up for transfers would be internal to the DSI host driver).

Do either or both of those solve the problem in this case? The first
is the easiest to implement, but does it cover all the current use
cases?
I don't quite see why dw-mipi-dsi calls the downstream post_disable
early. Are there really devices that want to send DSI DCS transfers
during shutdown? I'm guessing that's the reasoning, same as the power
up via mode_set.

There are already bridge drivers such as SN65DSI83 which don't follow
the requirements specified in the datasheet for power up sequences due
to issues in the framework. Hacking the bridge seems wrong.
(It configures the bridge from enable because it needs the DSI clock
lane running and LP-11 on the data lanes, but actually enable has the
data lanes active too. It should be in pre_enable, but the clock lane
isn't running then.)

Also undefined in DRM is how DSI burst mode parameters should be
configured, and the exact meaning of half the MIPI_DSI_MODE_* defines
and their interactions (eg MIPI_DSI_VIDEO_MODE_BURST, but not
MIPI_DSI_VIDEO [4]?).

Cheers
 Dave

[1] https://lists.freedesktop.org/archives/dri-devel/2021-July/313576.html
[2] https://lists.freedesktop.org/archives/dri-devel/2021-October/325853.html
[3] https://elixir.bootlin.com/linux/latest/source/include/drm/drm_mipi_dsi.h#L84
[4] https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c#L226


> >
> > This specific problem can be fixed only if we change the bridge chain
> > from stack to queue. Please check this series
> > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/
> >
> > Jagan.
> >
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 17:19           ` Dave Stevenson
@ 2021-11-23  8:19             ` Neil Armstrong
  -1 siblings, 0 replies; 72+ messages in thread
From: Neil Armstrong @ 2021-11-23  8:19 UTC (permalink / raw)
  To: Dave Stevenson, Laurent Pinchart
  Cc: Sam Ravnborg, DRI Development, Chen-Yu Tsai, Robert Foss,
	linux-sunxi, Jagan Teki, linux-amarula, linux-arm-kernel

Hi Dave,

On 22/11/2021 18:19, Dave Stevenson wrote:
> Hi
> 
> On Mon, 22 Nov 2021 at 15:35, Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> Hi,
>>
>> On 22/11/2021 14:16, Jagan Teki wrote:
>>> Hi Neil,
>>>
>>> On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>>>
>>>> On 22/11/2021 07:52, Jagan Teki wrote:
>>>>> Some display panels would come up with a non-DSI output, those
>>>>> can have an option to connect the DSI host by means of interface
>>>>> bridge converter.
>>>>>
>>>>> This DSI to non-DSI interface bridge converter would requires
>>>>> DSI Host to handle drm bridge functionalities in order to DSI
>>>>> Host to Interface bridge.
>>>>>
>>>>> This patch convert the existing to a drm bridge driver with a
>>>>> built-in encoder support for compatibility with existing
>>>>> component drivers.
>>>>>
>>>>> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
>>>>> ---
>>>>> Changes for v5:
>>>>> - add atomic APIs
>>>>> - find host and device variant DSI devices.
>>>>> Changes for v4, v3:
>>>>> - none
>>>>>
>>>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>>>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>>>>>  2 files changed, 96 insertions(+), 23 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>>>> index 43d9c9e5198d..a6a272b55f77 100644
>>>>> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>>>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>>>> @@ -21,6 +21,7 @@
>>>>>
>>>>>  #include <drm/drm_atomic_helper.h>
>>>>>  #include <drm/drm_mipi_dsi.h>
>>>>> +#include <drm/drm_of.h>
>>>>>  #include <drm/drm_panel.h>
>>>>>  #include <drm/drm_print.h>
>>>>>  #include <drm/drm_probe_helper.h>
>>>>> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>>>>>       return 0;
>>>>>  }
>>>>>
>>>>> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>>> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
>>>>> +                                        struct drm_bridge_state *old_bridge_state)
>>>>>  {
>>>>> -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
>>>>> -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
>>>>> +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>>>>> +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>>>>>       struct mipi_dsi_device *device = dsi->device;
>>>>>       union phy_configure_opts opts = { };
>>>>>       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
>>>>> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>>>       if (dsi->panel)
>>>>>               drm_panel_prepare(dsi->panel);
>>>>>
>>>>> +     if (dsi->next_bridge)
>>>>> +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
>>>>> +
>>>>>       /*
>>>>>        * FIXME: This should be moved after the switch to HS mode.
>>>>>        *
>>>>> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>>>       if (dsi->panel)
>>>>>               drm_panel_enable(dsi->panel);
>>>>>
>>>>> +     if (dsi->next_bridge)
>>>>> +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
>>>>> +
>>>>
>>>>
>>>> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
>>>> be called automatically on the bridge chain.
>>>
>>> Correct, but the existing bridge chain (stack) is not compatible with
>>> sun6i DSI start sequence. We cannot send any DCS once we start HS
>>> mode.
>>> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775
>>
>> It's a classical DSI sequence init issue, look at dw-mipi-dsi:
>> https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
>>
>> We setup the "command-mode" (low-speed) withing mode_set so when the next bridge dsi_pre_enable is called,
>> low-speed DCS can be sent, then the bridge enable() sets video mode (high-speed).
>> The disable still needs to call the next_bridge post_disable :
>> https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L893
> 
> Doesn't that mean the post_disable gets called twice? Once by the
> dw-mipi-dsi driver and once by the framework.

Yes indeed

> 
>> You can send any low-speed DCS once HS mode is started if the HW supports it and the driver handles it, look
>> at the https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L397
>> The MIPI_DSI_MODE_LPM and MIPI_DSI_MSG_USE_LPM is used for that.
> 
> This seems to be the same question as I was asking back in [1] and
> continued in [2].
> 
> vc4 and Exynos break the chain apart so that they can initialise the
> DSI host before the panel.
> That doesn't work if the DSI host is an encoder, as the encoder
> mode_valid call is missing the struct drm_display_info needed for
> calling the bridge mode_valid function.
> It also fails with the atomic operations as the framework can't see
> the bridges/panels beyond the DSI host, and therefore doesn't create
> the state for them.
> This is why I've been trying to reinstate the chain as a whole for
> vc4, however we then hit the issue of the downstream bridge/panel
> pre_enables being called before the DSI host (be it a bridge or
> encoder), therefore it's unlikely to have been powered up or
> configured. The DSI bus is also generally going to be powered down
> during the pre_enables, when many displays want it at LP-11.
> 
> It sounds like dw-mipi-dsi has a hack to the bridge operations and
> powers up in mode_set (not what the docs say). sun6i sounds to have
> some similar restrictions that these patches are trying to work
> around.
> 
> The documentation for struct mipi_dsi_host_ops transfer [3] states:
>  * Also note that those callbacks can be called no matter the state the
>  * host is in. Drivers that need the underlying device to be powered to
>  * perform these operations will first need to make sure it's been
>  * properly enabled.
> 
> It sounds like neither of the above drivers do this.
> As stated it would be valid to request a transfer from attach, at
> which point mode_set hasn't been called, so dw-mipi-dsi falls down
> there. sun4i can't send commands once in HS mode.
> What's the correct behaviour if the hardware can't support sending the
> transfer due to the state? Returning an error would be an obvious
> step.
> 
> 
> Is it time to actually thrash out the specifics of how DSI should be
> implemented, and fix the DSI framework where it doesn't currently
> work?

Yes, we should fix this

> 
> Previously proposed have been:
> - a pre_pre_enable (called from encoder outwards) and a matching
> post_post_disable (towards the encoder).
> - a mechanism for the panel/bridge to request that the PHY is powered
> up, so the bus is at LP-11, and the clock lane running if
> !MIPI_DSI_CLOCK_NON_CONTINUOUS, before powering up the bridge.
> (Powering up for transfers would be internal to the DSI host driver).
> 
> Do either or both of those solve the problem in this case? The first
> is the easiest to implement, but does it cover all the current use
> cases?

I don't think it's a viable solution, because maybe some weird protocol will
need another pre_pre_pre_enable callback...

I don't have the solution in mind but it must be generic and simple,
smarter minds than mine should be able to think of it....

Maybe something like the format negotiation ? where each bridge can tell
if they need precedence on the next bridge for a particular callback ?

> I don't quite see why dw-mipi-dsi calls the downstream post_disable
> early. Are there really devices that want to send DSI DCS transfers
> during shutdown? I'm guessing that's the reasoning, same as the power
> up via mode_set.

Yes panels needs some DCS commands to correctly shut down the panel

> 
> There are already bridge drivers such as SN65DSI83 which don't follow
> the requirements specified in the datasheet for power up sequences due
> to issues in the framework. Hacking the bridge seems wrong.
> (It configures the bridge from enable because it needs the DSI clock
> lane running and LP-11 on the data lanes, but actually enable has the
> data lanes active too. It should be in pre_enable, but the clock lane
> isn't running then.)
> 
> Also undefined in DRM is how DSI burst mode parameters should be
> configured, and the exact meaning of half the MIPI_DSI_MODE_* defines
> and their interactions (eg MIPI_DSI_VIDEO_MODE_BURST, but not
> MIPI_DSI_VIDEO [4]?).
> 
> Cheers
>  Dave
> 
> [1] https://lists.freedesktop.org/archives/dri-devel/2021-July/313576.html
> [2] https://lists.freedesktop.org/archives/dri-devel/2021-October/325853.html
> [3] https://elixir.bootlin.com/linux/latest/source/include/drm/drm_mipi_dsi.h#L84
> [4] https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c#L226
> 
> 
>>>
>>> This specific problem can be fixed only if we change the bridge chain
>>> from stack to queue. Please check this series
>>> https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/
>>>
>>> Jagan.
>>>
>>


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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-23  8:19             ` Neil Armstrong
  0 siblings, 0 replies; 72+ messages in thread
From: Neil Armstrong @ 2021-11-23  8:19 UTC (permalink / raw)
  To: Dave Stevenson, Laurent Pinchart
  Cc: Jagan Teki, linux-amarula, linux-sunxi, DRI Development,
	Chen-Yu Tsai, Robert Foss, Sam Ravnborg, linux-arm-kernel

Hi Dave,

On 22/11/2021 18:19, Dave Stevenson wrote:
> Hi
> 
> On Mon, 22 Nov 2021 at 15:35, Neil Armstrong <narmstrong@baylibre.com> wrote:
>>
>> Hi,
>>
>> On 22/11/2021 14:16, Jagan Teki wrote:
>>> Hi Neil,
>>>
>>> On Mon, Nov 22, 2021 at 6:22 PM Neil Armstrong <narmstrong@baylibre.com> wrote:
>>>>
>>>> On 22/11/2021 07:52, Jagan Teki wrote:
>>>>> Some display panels would come up with a non-DSI output, those
>>>>> can have an option to connect the DSI host by means of interface
>>>>> bridge converter.
>>>>>
>>>>> This DSI to non-DSI interface bridge converter would requires
>>>>> DSI Host to handle drm bridge functionalities in order to DSI
>>>>> Host to Interface bridge.
>>>>>
>>>>> This patch convert the existing to a drm bridge driver with a
>>>>> built-in encoder support for compatibility with existing
>>>>> component drivers.
>>>>>
>>>>> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
>>>>> ---
>>>>> Changes for v5:
>>>>> - add atomic APIs
>>>>> - find host and device variant DSI devices.
>>>>> Changes for v4, v3:
>>>>> - none
>>>>>
>>>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
>>>>>  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
>>>>>  2 files changed, 96 insertions(+), 23 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>>>> index 43d9c9e5198d..a6a272b55f77 100644
>>>>> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>>>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>>>>> @@ -21,6 +21,7 @@
>>>>>
>>>>>  #include <drm/drm_atomic_helper.h>
>>>>>  #include <drm/drm_mipi_dsi.h>
>>>>> +#include <drm/drm_of.h>
>>>>>  #include <drm/drm_panel.h>
>>>>>  #include <drm/drm_print.h>
>>>>>  #include <drm/drm_probe_helper.h>
>>>>> @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
>>>>>       return 0;
>>>>>  }
>>>>>
>>>>> -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>>> +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
>>>>> +                                        struct drm_bridge_state *old_bridge_state)
>>>>>  {
>>>>> -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
>>>>> -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
>>>>> +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
>>>>> +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
>>>>>       struct mipi_dsi_device *device = dsi->device;
>>>>>       union phy_configure_opts opts = { };
>>>>>       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
>>>>> @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>>>       if (dsi->panel)
>>>>>               drm_panel_prepare(dsi->panel);
>>>>>
>>>>> +     if (dsi->next_bridge)
>>>>> +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
>>>>> +
>>>>>       /*
>>>>>        * FIXME: This should be moved after the switch to HS mode.
>>>>>        *
>>>>> @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
>>>>>       if (dsi->panel)
>>>>>               drm_panel_enable(dsi->panel);
>>>>>
>>>>> +     if (dsi->next_bridge)
>>>>> +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
>>>>> +
>>>>
>>>>
>>>> No need to call the next bridge atomic pre_enable/enable/disable/post_disable since they will
>>>> be called automatically on the bridge chain.
>>>
>>> Correct, but the existing bridge chain (stack) is not compatible with
>>> sun6i DSI start sequence. We cannot send any DCS once we start HS
>>> mode.
>>> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#n775
>>
>> It's a classical DSI sequence init issue, look at dw-mipi-dsi:
>> https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
>>
>> We setup the "command-mode" (low-speed) withing mode_set so when the next bridge dsi_pre_enable is called,
>> low-speed DCS can be sent, then the bridge enable() sets video mode (high-speed).
>> The disable still needs to call the next_bridge post_disable :
>> https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L893
> 
> Doesn't that mean the post_disable gets called twice? Once by the
> dw-mipi-dsi driver and once by the framework.

Yes indeed

> 
>> You can send any low-speed DCS once HS mode is started if the HW supports it and the driver handles it, look
>> at the https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L397
>> The MIPI_DSI_MODE_LPM and MIPI_DSI_MSG_USE_LPM is used for that.
> 
> This seems to be the same question as I was asking back in [1] and
> continued in [2].
> 
> vc4 and Exynos break the chain apart so that they can initialise the
> DSI host before the panel.
> That doesn't work if the DSI host is an encoder, as the encoder
> mode_valid call is missing the struct drm_display_info needed for
> calling the bridge mode_valid function.
> It also fails with the atomic operations as the framework can't see
> the bridges/panels beyond the DSI host, and therefore doesn't create
> the state for them.
> This is why I've been trying to reinstate the chain as a whole for
> vc4, however we then hit the issue of the downstream bridge/panel
> pre_enables being called before the DSI host (be it a bridge or
> encoder), therefore it's unlikely to have been powered up or
> configured. The DSI bus is also generally going to be powered down
> during the pre_enables, when many displays want it at LP-11.
> 
> It sounds like dw-mipi-dsi has a hack to the bridge operations and
> powers up in mode_set (not what the docs say). sun6i sounds to have
> some similar restrictions that these patches are trying to work
> around.
> 
> The documentation for struct mipi_dsi_host_ops transfer [3] states:
>  * Also note that those callbacks can be called no matter the state the
>  * host is in. Drivers that need the underlying device to be powered to
>  * perform these operations will first need to make sure it's been
>  * properly enabled.
> 
> It sounds like neither of the above drivers do this.
> As stated it would be valid to request a transfer from attach, at
> which point mode_set hasn't been called, so dw-mipi-dsi falls down
> there. sun4i can't send commands once in HS mode.
> What's the correct behaviour if the hardware can't support sending the
> transfer due to the state? Returning an error would be an obvious
> step.
> 
> 
> Is it time to actually thrash out the specifics of how DSI should be
> implemented, and fix the DSI framework where it doesn't currently
> work?

Yes, we should fix this

> 
> Previously proposed have been:
> - a pre_pre_enable (called from encoder outwards) and a matching
> post_post_disable (towards the encoder).
> - a mechanism for the panel/bridge to request that the PHY is powered
> up, so the bus is at LP-11, and the clock lane running if
> !MIPI_DSI_CLOCK_NON_CONTINUOUS, before powering up the bridge.
> (Powering up for transfers would be internal to the DSI host driver).
> 
> Do either or both of those solve the problem in this case? The first
> is the easiest to implement, but does it cover all the current use
> cases?

I don't think it's a viable solution, because maybe some weird protocol will
need another pre_pre_pre_enable callback...

I don't have the solution in mind but it must be generic and simple,
smarter minds than mine should be able to think of it....

Maybe something like the format negotiation ? where each bridge can tell
if they need precedence on the next bridge for a particular callback ?

> I don't quite see why dw-mipi-dsi calls the downstream post_disable
> early. Are there really devices that want to send DSI DCS transfers
> during shutdown? I'm guessing that's the reasoning, same as the power
> up via mode_set.

Yes panels needs some DCS commands to correctly shut down the panel

> 
> There are already bridge drivers such as SN65DSI83 which don't follow
> the requirements specified in the datasheet for power up sequences due
> to issues in the framework. Hacking the bridge seems wrong.
> (It configures the bridge from enable because it needs the DSI clock
> lane running and LP-11 on the data lanes, but actually enable has the
> data lanes active too. It should be in pre_enable, but the clock lane
> isn't running then.)
> 
> Also undefined in DRM is how DSI burst mode parameters should be
> configured, and the exact meaning of half the MIPI_DSI_MODE_* defines
> and their interactions (eg MIPI_DSI_VIDEO_MODE_BURST, but not
> MIPI_DSI_VIDEO [4]?).
> 
> Cheers
>  Dave
> 
> [1] https://lists.freedesktop.org/archives/dri-devel/2021-July/313576.html
> [2] https://lists.freedesktop.org/archives/dri-devel/2021-October/325853.html
> [3] https://elixir.bootlin.com/linux/latest/source/include/drm/drm_mipi_dsi.h#L84
> [4] https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c#L226
> 
> 
>>>
>>> This specific problem can be fixed only if we change the bridge chain
>>> from stack to queue. Please check this series
>>> https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-6-jagan@amarulasolutions.com/
>>>
>>> Jagan.
>>>
>>


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 14:19           ` Jagan Teki
@ 2021-11-23 18:32             ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-23 18:32 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

Hi Maxime,

On Mon, Nov 22, 2021 at 7:49 PM Jagan Teki <jagan@amarulasolutions.com> wrote:
>
> Hi Maxime,
>
> On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > > Hi Maxime,
> > >
> > > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > > Some display panels would come up with a non-DSI output, those
> > > > > can have an option to connect the DSI host by means of interface
> > > > > bridge converter.
> > > > >
> > > > > This DSI to non-DSI interface bridge converter would requires
> > > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > > Host to Interface bridge.
> > > >
> > > > In order to do this you would need to use the DRM bridge API...
> > >
> > > Sorry, which bridge API do you mean?
> >
> > Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> > we're doing in sun4i_rgb.c
>
> Yes, we have drm_bridge_attach in bind and bridge_function.attach
> calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
> Not sure which API's I've missed.
>
> >
> > > > > This patch convert the existing to a drm bridge driver with a
> > > > > built-in encoder support for compatibility with existing
> > > > > component drivers.
> > > >
> > > > ... but changing the encoder driver to a bridge is completely
> > > > unnecessary to do so. Why did you need to make that change?
> > >
> > > Idea of this series is to convert the driver to bridge and use the
> > > latest bridge function from the v1 series.
> >
> > Ok, but it's not at all what you mention in your commit log? You don't
> > need any of that in order to support a bridge downstream.
>
> I've mentioned "Converting to bridge driver" and thought it has
> meaning of converting encoder related function to bridge functions as
> well. Not think about specific description to describe on commit
> message. Will update this.
>
> >
> > > >
> > > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > > >
> > > > > ---
> > > > > Changes for v5:
> > > > > - add atomic APIs
> > > > > - find host and device variant DSI devices.
> > > > > Changes for v4, v3:
> > > > > - none
> > > > >
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > @@ -21,6 +21,7 @@
> > > > >
> > > > >  #include <drm/drm_atomic_helper.h>
> > > > >  #include <drm/drm_mipi_dsi.h>
> > > > > +#include <drm/drm_of.h>
> > > > >  #include <drm/drm_panel.h>
> > > > >  #include <drm/drm_print.h>
> > > > >  #include <drm/drm_probe_helper.h>
> > > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > > >       return 0;
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > > >       struct mipi_dsi_device *device = dsi->device;
> > > > >       union phy_configure_opts opts = { };
> > > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_prepare(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Please use the proper helpers.
> > >
> > > If we use bridge_functions we need to take atomic functions as
> > > precedence as the next bridge functions might convert atomic calls.
> >
> > We've had this discussion over and over again, but this is something
> > that needs to be documented and / or in your commit log.
> >
> > You must not deviate from the standard (and expected) behavior without
> > any kind of justification.
>
> Not exactly sure about what you mean, sorry. All these atomic bridge
> functions are already documented if I'm not wrong and Laurent have
> patches to switch the normal functions to atomic. Not sure what else
> need to document here and need justification for it if the driver is
> converting to bridge.
>
> >
> > > >
> > > > >       /*
> > > > >        * FIXME: This should be moved after the switch to HS mode.
> > > > >        *
> > > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_enable(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Ditto
> > > >
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > > >
> > > > >       udelay(1000);
> > > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > >
> > > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > > >
> > > > >       if (dsi->panel) {
> > > > >               drm_panel_disable(dsi->panel);
> > > > >               drm_panel_unprepare(dsi->panel);
> > > > > +     } else if (dsi->next_bridge) {
> > > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > > >
> > > > Ditto
> > > >
> > > > >       }
> > > > >
> > > > >       phy_power_off(dsi->dphy);
> > > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > > >  };
> > > > >
> > > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > > +                                enum drm_bridge_attach_flags flags)
> > > > > +{
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +
> > > > > +     if (dsi->next_bridge)
> > > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > > +                                      NULL, 0);
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > > >  };
> > > > >
> > > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > > >       int ret;
> > > > >
> > > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > > >                                     DRM_MODE_ENCODER_DSI);
> > > > >       if (ret) {
> > > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       }
> > > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > > >
> > > > > -     drm_connector_helper_add(&dsi->connector,
> > > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > > -                              &sun6i_dsi_connector_funcs,
> > > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > > >       if (ret) {
> > > > > -             dev_err(dsi->dev,
> > > > > -                     "Couldn't initialise the DSI connector\n");
> > > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > > >               goto err_cleanup_connector;
> > > > >       }
> > > > >
> > > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     if (dsi->panel) {
> > > > > +             drm_connector_helper_add(&dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_funcs,
> > > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > > +             if (ret) {
> > > > > +                     dev_err(dsi->dev,
> > > > > +                             "Couldn't initialise the DSI connector\n");
> > > > > +                     goto err_cleanup_connector;
> > > > > +             }
> > > > > +
> > > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     }
> > > > >
> > > > >       return 0;
> > > > >
> > > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > > >                           struct mipi_dsi_device *device)
> > > > >  {
> > > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > > +     struct device_node *remote = device->dev.of_node;
> > > > >       int ret;
> > > > >
> > > > > -     if (IS_ERR(panel))
> > > > > -             return PTR_ERR(panel);
> > > > > +     if (!of_device_is_available(remote)) {
> > > > > +             /**
> > > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > > +              * bridge drivers instead of conventional device.
> > > > > +              *
> > > > > +              * Those are probed via host of_node instead of device of_node.
> > > > > +              */
> > > >
> > > > I have no idea what you mean here. Can you expand on what issue you've
> > > > tried to solve here?
> > >
> > > I2C interface DSI bridges will register DSI host on the bridge
> > > drivers.
> >
> > DSI bridges don't register a DSI host.
>
> Please check what I mean here,
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623
>
> I've tested it anyway, if you have any relevant one please check as well.
>
> >
> > > Those can be found using host->dev->of_node and cannot be find using
> > > device->dev.of_node
> > >
> > > >
> > > > > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > > > > +             if (!remote)
> > > > > +                     return -ENODEV;
> > > > > +     }
> > > > > +
> > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > +             dsi->panel = NULL;
> > > > > +
> > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > +             }
> > > > > +     } else {
> > > > > +             dsi->next_bridge = NULL;
> > > > > +     }
> > > > > +
> > > > > +     of_node_put(remote);
> > > >
> > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > >
> > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > we are not using ports based pipeline in dsi node. Of-course you have
> > > pointed the same before, please check below
> > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> >
> > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > bindings and look for a panel or bridge not only through the OF graph,
> > but also on the child nodes
>
> Okay. I need to check this.

devm_drm_of_get_bridge is not working with legacy binding like the one
used in sun6i dsi
https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/

dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
if (IS_ERR(dsi->next_bridge))
           return PTR_ERR(dsi->next_bridge);

It is only working if we have ports on the pipeline, something like this
https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/

Please have a look and let me know if I miss anything?

Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-23 18:32             ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-23 18:32 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi Maxime,

On Mon, Nov 22, 2021 at 7:49 PM Jagan Teki <jagan@amarulasolutions.com> wrote:
>
> Hi Maxime,
>
> On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > > Hi Maxime,
> > >
> > > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > > Some display panels would come up with a non-DSI output, those
> > > > > can have an option to connect the DSI host by means of interface
> > > > > bridge converter.
> > > > >
> > > > > This DSI to non-DSI interface bridge converter would requires
> > > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > > Host to Interface bridge.
> > > >
> > > > In order to do this you would need to use the DRM bridge API...
> > >
> > > Sorry, which bridge API do you mean?
> >
> > Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> > we're doing in sun4i_rgb.c
>
> Yes, we have drm_bridge_attach in bind and bridge_function.attach
> calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
> Not sure which API's I've missed.
>
> >
> > > > > This patch convert the existing to a drm bridge driver with a
> > > > > built-in encoder support for compatibility with existing
> > > > > component drivers.
> > > >
> > > > ... but changing the encoder driver to a bridge is completely
> > > > unnecessary to do so. Why did you need to make that change?
> > >
> > > Idea of this series is to convert the driver to bridge and use the
> > > latest bridge function from the v1 series.
> >
> > Ok, but it's not at all what you mention in your commit log? You don't
> > need any of that in order to support a bridge downstream.
>
> I've mentioned "Converting to bridge driver" and thought it has
> meaning of converting encoder related function to bridge functions as
> well. Not think about specific description to describe on commit
> message. Will update this.
>
> >
> > > >
> > > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > > >
> > > > > ---
> > > > > Changes for v5:
> > > > > - add atomic APIs
> > > > > - find host and device variant DSI devices.
> > > > > Changes for v4, v3:
> > > > > - none
> > > > >
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > @@ -21,6 +21,7 @@
> > > > >
> > > > >  #include <drm/drm_atomic_helper.h>
> > > > >  #include <drm/drm_mipi_dsi.h>
> > > > > +#include <drm/drm_of.h>
> > > > >  #include <drm/drm_panel.h>
> > > > >  #include <drm/drm_print.h>
> > > > >  #include <drm/drm_probe_helper.h>
> > > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > > >       return 0;
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > > >       struct mipi_dsi_device *device = dsi->device;
> > > > >       union phy_configure_opts opts = { };
> > > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_prepare(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Please use the proper helpers.
> > >
> > > If we use bridge_functions we need to take atomic functions as
> > > precedence as the next bridge functions might convert atomic calls.
> >
> > We've had this discussion over and over again, but this is something
> > that needs to be documented and / or in your commit log.
> >
> > You must not deviate from the standard (and expected) behavior without
> > any kind of justification.
>
> Not exactly sure about what you mean, sorry. All these atomic bridge
> functions are already documented if I'm not wrong and Laurent have
> patches to switch the normal functions to atomic. Not sure what else
> need to document here and need justification for it if the driver is
> converting to bridge.
>
> >
> > > >
> > > > >       /*
> > > > >        * FIXME: This should be moved after the switch to HS mode.
> > > > >        *
> > > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       if (dsi->panel)
> > > > >               drm_panel_enable(dsi->panel);
> > > > >
> > > > > +     if (dsi->next_bridge)
> > > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > > +
> > > >
> > > > Ditto
> > > >
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > > >
> > > > >       udelay(1000);
> > > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > > >  }
> > > > >
> > > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > > >  {
> > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > >
> > > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > > >
> > > > >       if (dsi->panel) {
> > > > >               drm_panel_disable(dsi->panel);
> > > > >               drm_panel_unprepare(dsi->panel);
> > > > > +     } else if (dsi->next_bridge) {
> > > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > > >
> > > > Ditto
> > > >
> > > > >       }
> > > > >
> > > > >       phy_power_off(dsi->dphy);
> > > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > > >  };
> > > > >
> > > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > > +                                enum drm_bridge_attach_flags flags)
> > > > > +{
> > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > +
> > > > > +     if (dsi->next_bridge)
> > > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > > +                                      NULL, 0);
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > > >  };
> > > > >
> > > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > > >       int ret;
> > > > >
> > > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > > >                                     DRM_MODE_ENCODER_DSI);
> > > > >       if (ret) {
> > > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > >       }
> > > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > > >
> > > > > -     drm_connector_helper_add(&dsi->connector,
> > > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > > -                              &sun6i_dsi_connector_funcs,
> > > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > > >       if (ret) {
> > > > > -             dev_err(dsi->dev,
> > > > > -                     "Couldn't initialise the DSI connector\n");
> > > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > > >               goto err_cleanup_connector;
> > > > >       }
> > > > >
> > > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     if (dsi->panel) {
> > > > > +             drm_connector_helper_add(&dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > > +                                      &sun6i_dsi_connector_funcs,
> > > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > > +             if (ret) {
> > > > > +                     dev_err(dsi->dev,
> > > > > +                             "Couldn't initialise the DSI connector\n");
> > > > > +                     goto err_cleanup_connector;
> > > > > +             }
> > > > > +
> > > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > +     }
> > > > >
> > > > >       return 0;
> > > > >
> > > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > > >                           struct mipi_dsi_device *device)
> > > > >  {
> > > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > > +     struct device_node *remote = device->dev.of_node;
> > > > >       int ret;
> > > > >
> > > > > -     if (IS_ERR(panel))
> > > > > -             return PTR_ERR(panel);
> > > > > +     if (!of_device_is_available(remote)) {
> > > > > +             /**
> > > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > > +              * bridge drivers instead of conventional device.
> > > > > +              *
> > > > > +              * Those are probed via host of_node instead of device of_node.
> > > > > +              */
> > > >
> > > > I have no idea what you mean here. Can you expand on what issue you've
> > > > tried to solve here?
> > >
> > > I2C interface DSI bridges will register DSI host on the bridge
> > > drivers.
> >
> > DSI bridges don't register a DSI host.
>
> Please check what I mean here,
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623
>
> I've tested it anyway, if you have any relevant one please check as well.
>
> >
> > > Those can be found using host->dev->of_node and cannot be find using
> > > device->dev.of_node
> > >
> > > >
> > > > > +             remote = of_graph_get_remote_node(host->dev->of_node, 0, 0);
> > > > > +             if (!remote)
> > > > > +                     return -ENODEV;
> > > > > +     }
> > > > > +
> > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > +             dsi->panel = NULL;
> > > > > +
> > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > +             }
> > > > > +     } else {
> > > > > +             dsi->next_bridge = NULL;
> > > > > +     }
> > > > > +
> > > > > +     of_node_put(remote);
> > > >
> > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > >
> > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > we are not using ports based pipeline in dsi node. Of-course you have
> > > pointed the same before, please check below
> > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> >
> > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > bindings and look for a panel or bridge not only through the OF graph,
> > but also on the child nodes
>
> Okay. I need to check this.

devm_drm_of_get_bridge is not working with legacy binding like the one
used in sun6i dsi
https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/

dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
if (IS_ERR(dsi->next_bridge))
           return PTR_ERR(dsi->next_bridge);

It is only working if we have ports on the pipeline, something like this
https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/

Please have a look and let me know if I miss anything?

Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-23 18:32             ` Jagan Teki
@ 2021-11-25 14:15               ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-25 14:15 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 2269 bytes --]

On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > +             dsi->panel = NULL;
> > > > > > +
> > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > +             }
> > > > > > +     } else {
> > > > > > +             dsi->next_bridge = NULL;
> > > > > > +     }
> > > > > > +
> > > > > > +     of_node_put(remote);
> > > > >
> > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > >
> > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > pointed the same before, please check below
> > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > >
> > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > bindings and look for a panel or bridge not only through the OF graph,
> > > but also on the child nodes
> >
> > Okay. I need to check this.
> 
> devm_drm_of_get_bridge is not working with legacy binding like the one
> used in sun6i dsi

There's nothing legacy about it.

> https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> 
> dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> if (IS_ERR(dsi->next_bridge))
>            return PTR_ERR(dsi->next_bridge);
> 
> It is only working if we have ports on the pipeline, something like this
> https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> 
> Please have a look and let me know if I miss anything?

Yes, you're missing the answer you quoted earlier:

> > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > bindings and look for a panel or bridge not only through the OF graph,
> > > but also on the child nodes

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-25 14:15               ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-25 14:15 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula


[-- Attachment #1.1: Type: text/plain, Size: 2269 bytes --]

On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > +             dsi->panel = NULL;
> > > > > > +
> > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > +             }
> > > > > > +     } else {
> > > > > > +             dsi->next_bridge = NULL;
> > > > > > +     }
> > > > > > +
> > > > > > +     of_node_put(remote);
> > > > >
> > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > >
> > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > pointed the same before, please check below
> > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > >
> > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > bindings and look for a panel or bridge not only through the OF graph,
> > > but also on the child nodes
> >
> > Okay. I need to check this.
> 
> devm_drm_of_get_bridge is not working with legacy binding like the one
> used in sun6i dsi

There's nothing legacy about it.

> https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> 
> dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> if (IS_ERR(dsi->next_bridge))
>            return PTR_ERR(dsi->next_bridge);
> 
> It is only working if we have ports on the pipeline, something like this
> https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> 
> Please have a look and let me know if I miss anything?

Yes, you're missing the answer you quoted earlier:

> > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > bindings and look for a panel or bridge not only through the OF graph,
> > > but also on the child nodes

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-25 14:15               ` Maxime Ripard
@ 2021-11-25 14:25                 ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-25 14:25 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

Hi,

On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > +             dsi->panel = NULL;
> > > > > > > +
> > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > +             }
> > > > > > > +     } else {
> > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > +     }
> > > > > > > +
> > > > > > > +     of_node_put(remote);
> > > > > >
> > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > >
> > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > pointed the same before, please check below
> > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > >
> > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > but also on the child nodes
> > >
> > > Okay. I need to check this.
> >
> > devm_drm_of_get_bridge is not working with legacy binding like the one
> > used in sun6i dsi
>
> There's nothing legacy about it.

What I'm mean legacy here with current binding used in sun6i-dsi like this.

&dsi {
          vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
          status = "okay";

         panel@0 {
                   compatible = "bananapi,s070wv20-ct16-icn6211";
                   reg = <0>;
                   reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
LCD-RST: PL5 */
                  enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
LCD-PWR-EN: PB7 */
                  backlight = <&backlight>;
        };
};

devm_drm_of_get_bridge cannot find the device with above binding and
able to find the device with below binding.

&dsi {
       vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
       status = "okay";

      ports {
            #address-cells = <1>;
            #size-cells = <0>;

           dsi_out: port@0 {
                   reg = <0>;

                  dsi_out_bridge: endpoint {
                            remote-endpoint = <&bridge_out_dsi>;
                  };
           };
      };

      panel@0 {
             compatible = "bananapi,s070wv20-ct16-icn6211";
             reg = <0>;
             reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
             enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
             backlight = <&backlight>;

              port {
                        bridge_out_dsi: endpoint {
                                remote-endpoint = <&dsi_out_bridge>;
                        };
                };
       };
};

>
> > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> >
> > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > if (IS_ERR(dsi->next_bridge))
> >            return PTR_ERR(dsi->next_bridge);
> >
> > It is only working if we have ports on the pipeline, something like this
> > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> >
> > Please have a look and let me know if I miss anything?
>
> Yes, you're missing the answer you quoted earlier:

Yes, I'm trying to resolve the comment one after another. Will get back.

Thanks,
Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-25 14:25                 ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-25 14:25 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

Hi,

On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > +             dsi->panel = NULL;
> > > > > > > +
> > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > +             }
> > > > > > > +     } else {
> > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > +     }
> > > > > > > +
> > > > > > > +     of_node_put(remote);
> > > > > >
> > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > >
> > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > pointed the same before, please check below
> > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > >
> > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > but also on the child nodes
> > >
> > > Okay. I need to check this.
> >
> > devm_drm_of_get_bridge is not working with legacy binding like the one
> > used in sun6i dsi
>
> There's nothing legacy about it.

What I'm mean legacy here with current binding used in sun6i-dsi like this.

&dsi {
          vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
          status = "okay";

         panel@0 {
                   compatible = "bananapi,s070wv20-ct16-icn6211";
                   reg = <0>;
                   reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
LCD-RST: PL5 */
                  enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
LCD-PWR-EN: PB7 */
                  backlight = <&backlight>;
        };
};

devm_drm_of_get_bridge cannot find the device with above binding and
able to find the device with below binding.

&dsi {
       vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
       status = "okay";

      ports {
            #address-cells = <1>;
            #size-cells = <0>;

           dsi_out: port@0 {
                   reg = <0>;

                  dsi_out_bridge: endpoint {
                            remote-endpoint = <&bridge_out_dsi>;
                  };
           };
      };

      panel@0 {
             compatible = "bananapi,s070wv20-ct16-icn6211";
             reg = <0>;
             reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
             enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
             backlight = <&backlight>;

              port {
                        bridge_out_dsi: endpoint {
                                remote-endpoint = <&dsi_out_bridge>;
                        };
                };
       };
};

>
> > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> >
> > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > if (IS_ERR(dsi->next_bridge))
> >            return PTR_ERR(dsi->next_bridge);
> >
> > It is only working if we have ports on the pipeline, something like this
> > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> >
> > Please have a look and let me know if I miss anything?
>
> Yes, you're missing the answer you quoted earlier:

Yes, I'm trying to resolve the comment one after another. Will get back.

Thanks,
Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-25 14:25                 ` Jagan Teki
@ 2021-11-25 16:10                   ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-25 16:10 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 4283 bytes --]

On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> Hi,
> 
> On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > +             dsi->panel = NULL;
> > > > > > > > +
> > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > +             }
> > > > > > > > +     } else {
> > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > +     }
> > > > > > > > +
> > > > > > > > +     of_node_put(remote);
> > > > > > >
> > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > >
> > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > pointed the same before, please check below
> > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > >
> > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > but also on the child nodes
> > > >
> > > > Okay. I need to check this.
> > >
> > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > used in sun6i dsi
> >
> > There's nothing legacy about it.
> 
> What I'm mean legacy here with current binding used in sun6i-dsi like this.
> 
> &dsi {
>           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
>           status = "okay";
> 
>          panel@0 {
>                    compatible = "bananapi,s070wv20-ct16-icn6211";
>                    reg = <0>;
>                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> LCD-RST: PL5 */
>                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> LCD-PWR-EN: PB7 */
>                   backlight = <&backlight>;
>         };
> };

Yes, I know, it's the generic DSI binding. It's still not legacy.

> devm_drm_of_get_bridge cannot find the device with above binding and
> able to find the device with below binding.
> 
> &dsi {
>        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
>        status = "okay";
> 
>       ports {
>             #address-cells = <1>;
>             #size-cells = <0>;
> 
>            dsi_out: port@0 {
>                    reg = <0>;
> 
>                   dsi_out_bridge: endpoint {
>                             remote-endpoint = <&bridge_out_dsi>;
>                   };
>            };
>       };
> 
>       panel@0 {
>              compatible = "bananapi,s070wv20-ct16-icn6211";
>              reg = <0>;
>              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
>              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
>              backlight = <&backlight>;
> 
>               port {
>                         bridge_out_dsi: endpoint {
>                                 remote-endpoint = <&dsi_out_bridge>;
>                         };
>                 };
>        };
> };

Yes, I know, and that's because ...

> >
> > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > >
> > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > if (IS_ERR(dsi->next_bridge))
> > >            return PTR_ERR(dsi->next_bridge);
> > >
> > > It is only working if we have ports on the pipeline, something like this
> > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > >
> > > Please have a look and let me know if I miss anything?
> >
> > Yes, you're missing the answer you quoted earlier:
> 
> Yes, I'm trying to resolve the comment one after another. Will get back.

... You've ignored that comment.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-25 16:10                   ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-25 16:10 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula


[-- Attachment #1.1: Type: text/plain, Size: 4283 bytes --]

On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> Hi,
> 
> On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > +             dsi->panel = NULL;
> > > > > > > > +
> > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > +             }
> > > > > > > > +     } else {
> > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > +     }
> > > > > > > > +
> > > > > > > > +     of_node_put(remote);
> > > > > > >
> > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > >
> > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > pointed the same before, please check below
> > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > >
> > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > but also on the child nodes
> > > >
> > > > Okay. I need to check this.
> > >
> > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > used in sun6i dsi
> >
> > There's nothing legacy about it.
> 
> What I'm mean legacy here with current binding used in sun6i-dsi like this.
> 
> &dsi {
>           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
>           status = "okay";
> 
>          panel@0 {
>                    compatible = "bananapi,s070wv20-ct16-icn6211";
>                    reg = <0>;
>                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> LCD-RST: PL5 */
>                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> LCD-PWR-EN: PB7 */
>                   backlight = <&backlight>;
>         };
> };

Yes, I know, it's the generic DSI binding. It's still not legacy.

> devm_drm_of_get_bridge cannot find the device with above binding and
> able to find the device with below binding.
> 
> &dsi {
>        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
>        status = "okay";
> 
>       ports {
>             #address-cells = <1>;
>             #size-cells = <0>;
> 
>            dsi_out: port@0 {
>                    reg = <0>;
> 
>                   dsi_out_bridge: endpoint {
>                             remote-endpoint = <&bridge_out_dsi>;
>                   };
>            };
>       };
> 
>       panel@0 {
>              compatible = "bananapi,s070wv20-ct16-icn6211";
>              reg = <0>;
>              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
>              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
>              backlight = <&backlight>;
> 
>               port {
>                         bridge_out_dsi: endpoint {
>                                 remote-endpoint = <&dsi_out_bridge>;
>                         };
>                 };
>        };
> };

Yes, I know, and that's because ...

> >
> > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > >
> > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > if (IS_ERR(dsi->next_bridge))
> > >            return PTR_ERR(dsi->next_bridge);
> > >
> > > It is only working if we have ports on the pipeline, something like this
> > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > >
> > > Please have a look and let me know if I miss anything?
> >
> > Yes, you're missing the answer you quoted earlier:
> 
> Yes, I'm trying to resolve the comment one after another. Will get back.

... You've ignored that comment.

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-25 16:10                   ` Maxime Ripard
@ 2021-11-25 16:14                     ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-25 16:14 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > Hi,
> >
> > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > +
> > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > +             }
> > > > > > > > > +     } else {
> > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > +     }
> > > > > > > > > +
> > > > > > > > > +     of_node_put(remote);
> > > > > > > >
> > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > >
> > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > pointed the same before, please check below
> > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > >
> > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > but also on the child nodes
> > > > >
> > > > > Okay. I need to check this.
> > > >
> > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > used in sun6i dsi
> > >
> > > There's nothing legacy about it.
> >
> > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> >
> > &dsi {
> >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> >           status = "okay";
> >
> >          panel@0 {
> >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> >                    reg = <0>;
> >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > LCD-RST: PL5 */
> >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > LCD-PWR-EN: PB7 */
> >                   backlight = <&backlight>;
> >         };
> > };
>
> Yes, I know, it's the generic DSI binding. It's still not legacy.
>
> > devm_drm_of_get_bridge cannot find the device with above binding and
> > able to find the device with below binding.
> >
> > &dsi {
> >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> >        status = "okay";
> >
> >       ports {
> >             #address-cells = <1>;
> >             #size-cells = <0>;
> >
> >            dsi_out: port@0 {
> >                    reg = <0>;
> >
> >                   dsi_out_bridge: endpoint {
> >                             remote-endpoint = <&bridge_out_dsi>;
> >                   };
> >            };
> >       };
> >
> >       panel@0 {
> >              compatible = "bananapi,s070wv20-ct16-icn6211";
> >              reg = <0>;
> >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> >              backlight = <&backlight>;
> >
> >               port {
> >                         bridge_out_dsi: endpoint {
> >                                 remote-endpoint = <&dsi_out_bridge>;
> >                         };
> >                 };
> >        };
> > };
>
> Yes, I know, and that's because ...

Okay. I will use find panel and bridge separately instead of
devm_drm_of_get_bridge in version patches.

>
> > >
> > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > >
> > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > if (IS_ERR(dsi->next_bridge))
> > > >            return PTR_ERR(dsi->next_bridge);
> > > >
> > > > It is only working if we have ports on the pipeline, something like this
> > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > >
> > > > Please have a look and let me know if I miss anything?
> > >
> > > Yes, you're missing the answer you quoted earlier:
> >
> > Yes, I'm trying to resolve the comment one after another. Will get back.
>
> ... You've ignored that comment.

Not understand which comment you mean. There are few about bridge
conversion details, I will send my comments.

Thanks,
Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-25 16:14                     ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-25 16:14 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > Hi,
> >
> > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > +
> > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > +             }
> > > > > > > > > +     } else {
> > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > +     }
> > > > > > > > > +
> > > > > > > > > +     of_node_put(remote);
> > > > > > > >
> > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > >
> > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > pointed the same before, please check below
> > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > >
> > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > but also on the child nodes
> > > > >
> > > > > Okay. I need to check this.
> > > >
> > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > used in sun6i dsi
> > >
> > > There's nothing legacy about it.
> >
> > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> >
> > &dsi {
> >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> >           status = "okay";
> >
> >          panel@0 {
> >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> >                    reg = <0>;
> >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > LCD-RST: PL5 */
> >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > LCD-PWR-EN: PB7 */
> >                   backlight = <&backlight>;
> >         };
> > };
>
> Yes, I know, it's the generic DSI binding. It's still not legacy.
>
> > devm_drm_of_get_bridge cannot find the device with above binding and
> > able to find the device with below binding.
> >
> > &dsi {
> >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> >        status = "okay";
> >
> >       ports {
> >             #address-cells = <1>;
> >             #size-cells = <0>;
> >
> >            dsi_out: port@0 {
> >                    reg = <0>;
> >
> >                   dsi_out_bridge: endpoint {
> >                             remote-endpoint = <&bridge_out_dsi>;
> >                   };
> >            };
> >       };
> >
> >       panel@0 {
> >              compatible = "bananapi,s070wv20-ct16-icn6211";
> >              reg = <0>;
> >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> >              backlight = <&backlight>;
> >
> >               port {
> >                         bridge_out_dsi: endpoint {
> >                                 remote-endpoint = <&dsi_out_bridge>;
> >                         };
> >                 };
> >        };
> > };
>
> Yes, I know, and that's because ...

Okay. I will use find panel and bridge separately instead of
devm_drm_of_get_bridge in version patches.

>
> > >
> > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > >
> > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > if (IS_ERR(dsi->next_bridge))
> > > >            return PTR_ERR(dsi->next_bridge);
> > > >
> > > > It is only working if we have ports on the pipeline, something like this
> > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > >
> > > > Please have a look and let me know if I miss anything?
> > >
> > > Yes, you're missing the answer you quoted earlier:
> >
> > Yes, I'm trying to resolve the comment one after another. Will get back.
>
> ... You've ignored that comment.

Not understand which comment you mean. There are few about bridge
conversion details, I will send my comments.

Thanks,
Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-22 15:04             ` Maxime Ripard
@ 2021-11-25 16:17               ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-25 16:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Mon, Nov 22, 2021 at 8:34 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 07:49:26PM +0530, Jagan Teki wrote:
> > On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > > > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > > >
> > > > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > > > Some display panels would come up with a non-DSI output, those
> > > > > > can have an option to connect the DSI host by means of interface
> > > > > > bridge converter.
> > > > > >
> > > > > > This DSI to non-DSI interface bridge converter would requires
> > > > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > > > Host to Interface bridge.
> > > > >
> > > > > In order to do this you would need to use the DRM bridge API...
> > > >
> > > > Sorry, which bridge API do you mean?
> > >
> > > Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> > > we're doing in sun4i_rgb.c
> >
> > Yes, we have drm_bridge_attach in bind and bridge_function.attach
> > calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
> > Not sure which API's I've missed.
>
> None, that's my point, you don't need anything else in order to do what
> you wanted to achieve.

Correct, the order is some how confused in this patch. I will fix it
in next version.

>
> > >
> > > > > > This patch convert the existing to a drm bridge driver with a
> > > > > > built-in encoder support for compatibility with existing
> > > > > > component drivers.
> > > > >
> > > > > ... but changing the encoder driver to a bridge is completely
> > > > > unnecessary to do so. Why did you need to make that change?
> > > >
> > > > Idea of this series is to convert the driver to bridge and use the
> > > > latest bridge function from the v1 series.
> > >
> > > Ok, but it's not at all what you mention in your commit log? You don't
> > > need any of that in order to support a bridge downstream.
> >
> > I've mentioned "Converting to bridge driver" and thought it has
> > meaning of converting encoder related function to bridge functions as
> > well. Not think about specific description to describe on commit
> > message. Will update this.
>
> But you provided no reason to do so. The only one you did mention was
> that you wanted to support downstream bridges, but you don't need to
> convert the DSI driver to a bridge in order to do that.

Okay. Look like I've combined both downstream bridge support and
converting bridge together. This what it totally confused, I will fix
it.

>
> > > > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > > > >
> > > > > > ---
> > > > > > Changes for v5:
> > > > > > - add atomic APIs
> > > > > > - find host and device variant DSI devices.
> > > > > > Changes for v4, v3:
> > > > > > - none
> > > > > >
> > > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > > @@ -21,6 +21,7 @@
> > > > > >
> > > > > >  #include <drm/drm_atomic_helper.h>
> > > > > >  #include <drm/drm_mipi_dsi.h>
> > > > > > +#include <drm/drm_of.h>
> > > > > >  #include <drm/drm_panel.h>
> > > > > >  #include <drm/drm_print.h>
> > > > > >  #include <drm/drm_probe_helper.h>
> > > > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > > > >       return 0;
> > > > > >  }
> > > > > >
> > > > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > > > >  {
> > > > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > > > >       struct mipi_dsi_device *device = dsi->device;
> > > > > >       union phy_configure_opts opts = { };
> > > > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > >       if (dsi->panel)
> > > > > >               drm_panel_prepare(dsi->panel);
> > > > > >
> > > > > > +     if (dsi->next_bridge)
> > > > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > > > +
> > > > >
> > > > > Please use the proper helpers.
> > > >
> > > > If we use bridge_functions we need to take atomic functions as
> > > > precedence as the next bridge functions might convert atomic calls.
> > >
> > > We've had this discussion over and over again, but this is something
> > > that needs to be documented and / or in your commit log.
> > >
> > > You must not deviate from the standard (and expected) behavior without
> > > any kind of justification.
> >
> > Not exactly sure about what you mean, sorry. All these atomic bridge
> > functions are already documented if I'm not wrong and Laurent have
> > patches to switch the normal functions to atomic. Not sure what else
> > need to document here and need justification for it if the driver is
> > converting to bridge.
>
> There's two separate bridge in that discussion: the DSI controller
> itself that you convert to a bridge, and the downstream DSI -> whatever
> bridge.
>
> The atomic functions in the "DSI controller bridge" are fine. But that
> comment was about calling the downstream bridge ops directly from the
> driver, which is something that no other driver is doing, deviates from
> the expectations, and you didn't provide any explanation for that.

Clear for me now. Agreed what you are saying.

>
> > >
> > > > >
> > > > > >       /*
> > > > > >        * FIXME: This should be moved after the switch to HS mode.
> > > > > >        *
> > > > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > >       if (dsi->panel)
> > > > > >               drm_panel_enable(dsi->panel);
> > > > > >
> > > > > > +     if (dsi->next_bridge)
> > > > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > > > +
> > > > >
> > > > > Ditto
> > > > >
> > > > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > > > >
> > > > > >       udelay(1000);
> > > > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > > > >  }
> > > > > >
> > > > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > > > >  {
> > > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > >
> > > > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > > > >
> > > > > >       if (dsi->panel) {
> > > > > >               drm_panel_disable(dsi->panel);
> > > > > >               drm_panel_unprepare(dsi->panel);
> > > > > > +     } else if (dsi->next_bridge) {
> > > > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > > > >
> > > > > Ditto
> > > > >
> > > > > >       }
> > > > > >
> > > > > >       phy_power_off(dsi->dphy);
> > > > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > > > >  };
> > > > > >
> > > > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > > > +                                enum drm_bridge_attach_flags flags)
> > > > > > +{
> > > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > > +
> > > > > > +     if (dsi->next_bridge)
> > > > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > > > +                                      NULL, 0);
> > > > > > +
> > > > > > +     return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > > > >  };
> > > > > >
> > > > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > > > >       int ret;
> > > > > >
> > > > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > > > >                                     DRM_MODE_ENCODER_DSI);
> > > > > >       if (ret) {
> > > > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > > >       }
> > > > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > > > >
> > > > > > -     drm_connector_helper_add(&dsi->connector,
> > > > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > > > -                              &sun6i_dsi_connector_funcs,
> > > > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > > > >       if (ret) {
> > > > > > -             dev_err(dsi->dev,
> > > > > > -                     "Couldn't initialise the DSI connector\n");
> > > > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > > > >               goto err_cleanup_connector;
> > > > > >       }
> > > > > >
> > > > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > > +     if (dsi->panel) {
> > > > > > +             drm_connector_helper_add(&dsi->connector,
> > > > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > > > +                                      &sun6i_dsi_connector_funcs,
> > > > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > > > +             if (ret) {
> > > > > > +                     dev_err(dsi->dev,
> > > > > > +                             "Couldn't initialise the DSI connector\n");
> > > > > > +                     goto err_cleanup_connector;
> > > > > > +             }
> > > > > > +
> > > > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > > +     }
> > > > > >
> > > > > >       return 0;
> > > > > >
> > > > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > > > >                           struct mipi_dsi_device *device)
> > > > > >  {
> > > > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > > > +     struct device_node *remote = device->dev.of_node;
> > > > > >       int ret;
> > > > > >
> > > > > > -     if (IS_ERR(panel))
> > > > > > -             return PTR_ERR(panel);
> > > > > > +     if (!of_device_is_available(remote)) {
> > > > > > +             /**
> > > > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > > > +              * bridge drivers instead of conventional device.
> > > > > > +              *
> > > > > > +              * Those are probed via host of_node instead of device of_node.
> > > > > > +              */
> > > > >
> > > > > I have no idea what you mean here. Can you expand on what issue you've
> > > > > tried to solve here?
> > > >
> > > > I2C interface DSI bridges will register DSI host on the bridge
> > > > drivers.
> > >
> > > DSI bridges don't register a DSI host.
> >
> > Please check what I mean here,
> > https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623
> >
> > I've tested it anyway, if you have any relevant one please check as well.
>
> That driver doesn't register a DSI Host though? It registers a DSI
> device

Correct.

Thanks,
Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-25 16:17               ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-25 16:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Mon, Nov 22, 2021 at 8:34 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Mon, Nov 22, 2021 at 07:49:26PM +0530, Jagan Teki wrote:
> > On Mon, Nov 22, 2021 at 7:35 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > On Mon, Nov 22, 2021 at 07:18:13PM +0530, Jagan Teki wrote:
> > > > On Mon, Nov 22, 2021 at 3:37 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > > >
> > > > > On Mon, Nov 22, 2021 at 12:22:19PM +0530, Jagan Teki wrote:
> > > > > > Some display panels would come up with a non-DSI output, those
> > > > > > can have an option to connect the DSI host by means of interface
> > > > > > bridge converter.
> > > > > >
> > > > > > This DSI to non-DSI interface bridge converter would requires
> > > > > > DSI Host to handle drm bridge functionalities in order to DSI
> > > > > > Host to Interface bridge.
> > > > >
> > > > > In order to do this you would need to use the DRM bridge API...
> > > >
> > > > Sorry, which bridge API do you mean?
> > >
> > > Any variant of of_drm_find_bridge, and drm_bridge_attach. Just like
> > > we're doing in sun4i_rgb.c
> >
> > Yes, we have drm_bridge_attach in bind and bridge_function.attach
> > calls in this patch and of_drm_find_bridge in sun6i_mipi_dsi_attach.
> > Not sure which API's I've missed.
>
> None, that's my point, you don't need anything else in order to do what
> you wanted to achieve.

Correct, the order is some how confused in this patch. I will fix it
in next version.

>
> > >
> > > > > > This patch convert the existing to a drm bridge driver with a
> > > > > > built-in encoder support for compatibility with existing
> > > > > > component drivers.
> > > > >
> > > > > ... but changing the encoder driver to a bridge is completely
> > > > > unnecessary to do so. Why did you need to make that change?
> > > >
> > > > Idea of this series is to convert the driver to bridge and use the
> > > > latest bridge function from the v1 series.
> > >
> > > Ok, but it's not at all what you mention in your commit log? You don't
> > > need any of that in order to support a bridge downstream.
> >
> > I've mentioned "Converting to bridge driver" and thought it has
> > meaning of converting encoder related function to bridge functions as
> > well. Not think about specific description to describe on commit
> > message. Will update this.
>
> But you provided no reason to do so. The only one you did mention was
> that you wanted to support downstream bridges, but you don't need to
> convert the DSI driver to a bridge in order to do that.

Okay. Look like I've combined both downstream bridge support and
converting bridge together. This what it totally confused, I will fix
it.

>
> > > > > > Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
> > > > > >
> > > > > > ---
> > > > > > Changes for v5:
> > > > > > - add atomic APIs
> > > > > > - find host and device variant DSI devices.
> > > > > > Changes for v4, v3:
> > > > > > - none
> > > > > >
> > > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 112 ++++++++++++++++++++-----
> > > > > >  drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |   7 ++
> > > > > >  2 files changed, 96 insertions(+), 23 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > > index 43d9c9e5198d..a6a272b55f77 100644
> > > > > > --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > > +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> > > > > > @@ -21,6 +21,7 @@
> > > > > >
> > > > > >  #include <drm/drm_atomic_helper.h>
> > > > > >  #include <drm/drm_mipi_dsi.h>
> > > > > > +#include <drm/drm_of.h>
> > > > > >  #include <drm/drm_panel.h>
> > > > > >  #include <drm/drm_print.h>
> > > > > >  #include <drm/drm_probe_helper.h>
> > > > > > @@ -713,10 +714,11 @@ static int sun6i_dsi_start(struct sun6i_dsi *dsi,
> > > > > >       return 0;
> > > > > >  }
> > > > > >
> > > > > > -static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > > +static void sun6i_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
> > > > > > +                                        struct drm_bridge_state *old_bridge_state)
> > > > > >  {
> > > > > > -     struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> > > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > > +     struct drm_display_mode *mode = &bridge->encoder->crtc->state->adjusted_mode;
> > > > > >       struct mipi_dsi_device *device = dsi->device;
> > > > > >       union phy_configure_opts opts = { };
> > > > > >       struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
> > > > > > @@ -772,6 +774,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > >       if (dsi->panel)
> > > > > >               drm_panel_prepare(dsi->panel);
> > > > > >
> > > > > > +     if (dsi->next_bridge)
> > > > > > +             dsi->next_bridge->funcs->atomic_pre_enable(dsi->next_bridge, old_bridge_state);
> > > > > > +
> > > > >
> > > > > Please use the proper helpers.
> > > >
> > > > If we use bridge_functions we need to take atomic functions as
> > > > precedence as the next bridge functions might convert atomic calls.
> > >
> > > We've had this discussion over and over again, but this is something
> > > that needs to be documented and / or in your commit log.
> > >
> > > You must not deviate from the standard (and expected) behavior without
> > > any kind of justification.
> >
> > Not exactly sure about what you mean, sorry. All these atomic bridge
> > functions are already documented if I'm not wrong and Laurent have
> > patches to switch the normal functions to atomic. Not sure what else
> > need to document here and need justification for it if the driver is
> > converting to bridge.
>
> There's two separate bridge in that discussion: the DSI controller
> itself that you convert to a bridge, and the downstream DSI -> whatever
> bridge.
>
> The atomic functions in the "DSI controller bridge" are fine. But that
> comment was about calling the downstream bridge ops directly from the
> driver, which is something that no other driver is doing, deviates from
> the expectations, and you didn't provide any explanation for that.

Clear for me now. Agreed what you are saying.

>
> > >
> > > > >
> > > > > >       /*
> > > > > >        * FIXME: This should be moved after the switch to HS mode.
> > > > > >        *
> > > > > > @@ -787,6 +792,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > >       if (dsi->panel)
> > > > > >               drm_panel_enable(dsi->panel);
> > > > > >
> > > > > > +     if (dsi->next_bridge)
> > > > > > +             dsi->next_bridge->funcs->atomic_enable(dsi->next_bridge, old_bridge_state);
> > > > > > +
> > > > >
> > > > > Ditto
> > > > >
> > > > > >       sun6i_dsi_start(dsi, DSI_START_HSC);
> > > > > >
> > > > > >       udelay(1000);
> > > > > > @@ -794,15 +802,19 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)
> > > > > >       sun6i_dsi_start(dsi, DSI_START_HSD);
> > > > > >  }
> > > > > >
> > > > > > -static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
> > > > > > +static void sun6i_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
> > > > > > +                                         struct drm_bridge_state *old_bridge_state)
> > > > > >  {
> > > > > > -     struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> > > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > >
> > > > > >       DRM_DEBUG_DRIVER("Disabling DSI output\n");
> > > > > >
> > > > > >       if (dsi->panel) {
> > > > > >               drm_panel_disable(dsi->panel);
> > > > > >               drm_panel_unprepare(dsi->panel);
> > > > > > +     } else if (dsi->next_bridge) {
> > > > > > +             dsi->next_bridge->funcs->atomic_disable(dsi->next_bridge, old_bridge_state);
> > > > > > +             dsi->next_bridge->funcs->atomic_post_disable(dsi->next_bridge, old_bridge_state);
> > > > >
> > > > > Ditto
> > > > >
> > > > > >       }
> > > > > >
> > > > > >       phy_power_off(dsi->dphy);
> > > > > > @@ -842,9 +854,25 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
> > > > > >       .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
> > > > > >  };
> > > > > >
> > > > > > -static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
> > > > > > -     .disable        = sun6i_dsi_encoder_disable,
> > > > > > -     .enable         = sun6i_dsi_encoder_enable,
> > > > > > +static int sun6i_dsi_bridge_attach(struct drm_bridge *bridge,
> > > > > > +                                enum drm_bridge_attach_flags flags)
> > > > > > +{
> > > > > > +     struct sun6i_dsi *dsi = bridge_to_sun6i_dsi(bridge);
> > > > > > +
> > > > > > +     if (dsi->next_bridge)
> > > > > > +             return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
> > > > > > +                                      NULL, 0);
> > > > > > +
> > > > > > +     return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static const struct drm_bridge_funcs sun6i_dsi_bridge_funcs = {
> > > > > > +     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> > > > > > +     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
> > > > > > +     .atomic_reset           = drm_atomic_helper_bridge_reset,
> > > > > > +     .atomic_enable          = sun6i_dsi_bridge_atomic_enable,
> > > > > > +     .atomic_disable         = sun6i_dsi_bridge_atomic_disable,
> > > > > > +     .attach                 = sun6i_dsi_bridge_attach,
> > > > > >  };
> > > > > >
> > > > > >  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
> > > > > > @@ -966,8 +994,6 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > > >       struct sun6i_dsi *dsi = dev_get_drvdata(dev);
> > > > > >       int ret;
> > > > > >
> > > > > > -     drm_encoder_helper_add(&dsi->encoder,
> > > > > > -                            &sun6i_dsi_enc_helper_funcs);
> > > > > >       ret = drm_simple_encoder_init(drm, &dsi->encoder,
> > > > > >                                     DRM_MODE_ENCODER_DSI);
> > > > > >       if (ret) {
> > > > > > @@ -976,18 +1002,26 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master,
> > > > > >       }
> > > > > >       dsi->encoder.possible_crtcs = BIT(0);
> > > > > >
> > > > > > -     drm_connector_helper_add(&dsi->connector,
> > > > > > -                              &sun6i_dsi_connector_helper_funcs);
> > > > > > -     ret = drm_connector_init(drm, &dsi->connector,
> > > > > > -                              &sun6i_dsi_connector_funcs,
> > > > > > -                              DRM_MODE_CONNECTOR_DSI);
> > > > > > +     ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0);
> > > > > >       if (ret) {
> > > > > > -             dev_err(dsi->dev,
> > > > > > -                     "Couldn't initialise the DSI connector\n");
> > > > > > +             dev_err(dsi->dev, "Couldn't attach drm bridge\n");
> > > > > >               goto err_cleanup_connector;
> > > > > >       }
> > > > > >
> > > > > > -     drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > > +     if (dsi->panel) {
> > > > > > +             drm_connector_helper_add(&dsi->connector,
> > > > > > +                                      &sun6i_dsi_connector_helper_funcs);
> > > > > > +             ret = drm_connector_init(drm, &dsi->connector,
> > > > > > +                                      &sun6i_dsi_connector_funcs,
> > > > > > +                                      DRM_MODE_CONNECTOR_DSI);
> > > > > > +             if (ret) {
> > > > > > +                     dev_err(dsi->dev,
> > > > > > +                             "Couldn't initialise the DSI connector\n");
> > > > > > +                     goto err_cleanup_connector;
> > > > > > +             }
> > > > > > +
> > > > > > +             drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
> > > > > > +     }
> > > > > >
> > > > > >       return 0;
> > > > > >
> > > > > > @@ -1013,16 +1047,46 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
> > > > > >                           struct mipi_dsi_device *device)
> > > > > >  {
> > > > > >       struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
> > > > > > -     struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);
> > > > > > +     struct device_node *remote = device->dev.of_node;
> > > > > >       int ret;
> > > > > >
> > > > > > -     if (IS_ERR(panel))
> > > > > > -             return PTR_ERR(panel);
> > > > > > +     if (!of_device_is_available(remote)) {
> > > > > > +             /**
> > > > > > +              * I2C interfaced DSI bridges will register DSI host on the
> > > > > > +              * bridge drivers instead of conventional device.
> > > > > > +              *
> > > > > > +              * Those are probed via host of_node instead of device of_node.
> > > > > > +              */
> > > > >
> > > > > I have no idea what you mean here. Can you expand on what issue you've
> > > > > tried to solve here?
> > > >
> > > > I2C interface DSI bridges will register DSI host on the bridge
> > > > drivers.
> > >
> > > DSI bridges don't register a DSI host.
> >
> > Please check what I mean here,
> > https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/bridge/ti-sn65dsi83.c#n623
> >
> > I've tested it anyway, if you have any relevant one please check as well.
>
> That driver doesn't register a DSI Host though? It registers a DSI
> device

Correct.

Thanks,
Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-25 16:14                     ` Jagan Teki
@ 2021-11-26 16:04                       ` Maxime Ripard
  -1 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-26 16:04 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 5806 bytes --]

On Thu, Nov 25, 2021 at 09:44:14PM +0530, Jagan Teki wrote:
> On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > > Hi,
> > >
> > > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > > +
> > > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > > +             }
> > > > > > > > > > +     } else {
> > > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > > +     }
> > > > > > > > > > +
> > > > > > > > > > +     of_node_put(remote);
> > > > > > > > >
> > > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > > >
> > > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > > pointed the same before, please check below
> > > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > > >
> > > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > > but also on the child nodes
> > > > > >
> > > > > > Okay. I need to check this.
> > > > >
> > > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > > used in sun6i dsi
> > > >
> > > > There's nothing legacy about it.
> > >
> > > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> > >
> > > &dsi {
> > >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > >           status = "okay";
> > >
> > >          panel@0 {
> > >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> > >                    reg = <0>;
> > >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > > LCD-RST: PL5 */
> > >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > > LCD-PWR-EN: PB7 */
> > >                   backlight = <&backlight>;
> > >         };
> > > };
> >
> > Yes, I know, it's the generic DSI binding. It's still not legacy.
> >
> > > devm_drm_of_get_bridge cannot find the device with above binding and
> > > able to find the device with below binding.
> > >
> > > &dsi {
> > >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > >        status = "okay";
> > >
> > >       ports {
> > >             #address-cells = <1>;
> > >             #size-cells = <0>;
> > >
> > >            dsi_out: port@0 {
> > >                    reg = <0>;
> > >
> > >                   dsi_out_bridge: endpoint {
> > >                             remote-endpoint = <&bridge_out_dsi>;
> > >                   };
> > >            };
> > >       };
> > >
> > >       panel@0 {
> > >              compatible = "bananapi,s070wv20-ct16-icn6211";
> > >              reg = <0>;
> > >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> > >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> > >              backlight = <&backlight>;
> > >
> > >               port {
> > >                         bridge_out_dsi: endpoint {
> > >                                 remote-endpoint = <&dsi_out_bridge>;
> > >                         };
> > >                 };
> > >        };
> > > };
> >
> > Yes, I know, and that's because ...
> 
> Okay. I will use find panel and bridge separately instead of
> devm_drm_of_get_bridge in version patches.

That's not been my point, at all?

I mean, that whole discussion has been because you shouldn't do that.

> >
> > > >
> > > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > > >
> > > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > > if (IS_ERR(dsi->next_bridge))
> > > > >            return PTR_ERR(dsi->next_bridge);
> > > > >
> > > > > It is only working if we have ports on the pipeline, something like this
> > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > > >
> > > > > Please have a look and let me know if I miss anything?
> > > >
> > > > Yes, you're missing the answer you quoted earlier:
> > >
> > > Yes, I'm trying to resolve the comment one after another. Will get back.
> >
> > ... You've ignored that comment.
> 
> Not understand which comment you mean. There are few about bridge
> conversion details, I will send my comments.

The one that got quoted there and you removed. For reference:

> Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> bindings and look for a panel or bridge not only through the OF graph,
> but also on the child nodes

devm_drm_of_get_bridge uses drm_of_find_panel_or_bridge under the hood,
so of course it won't find it if drm_of_find_panel_or_bridge doesn't.
You need to modify drm_of_find_panel_or_bridge to also look for child
devices and see if there's a panel or bridge registered for that child
node. Then devm_drm_of_get_bridge will work as you intend it to.

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-26 16:04                       ` Maxime Ripard
  0 siblings, 0 replies; 72+ messages in thread
From: Maxime Ripard @ 2021-11-26 16:04 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula


[-- Attachment #1.1: Type: text/plain, Size: 5806 bytes --]

On Thu, Nov 25, 2021 at 09:44:14PM +0530, Jagan Teki wrote:
> On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > > Hi,
> > >
> > > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > > +
> > > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > > +             }
> > > > > > > > > > +     } else {
> > > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > > +     }
> > > > > > > > > > +
> > > > > > > > > > +     of_node_put(remote);
> > > > > > > > >
> > > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > > >
> > > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > > pointed the same before, please check below
> > > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > > >
> > > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > > but also on the child nodes
> > > > > >
> > > > > > Okay. I need to check this.
> > > > >
> > > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > > used in sun6i dsi
> > > >
> > > > There's nothing legacy about it.
> > >
> > > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> > >
> > > &dsi {
> > >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > >           status = "okay";
> > >
> > >          panel@0 {
> > >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> > >                    reg = <0>;
> > >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > > LCD-RST: PL5 */
> > >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > > LCD-PWR-EN: PB7 */
> > >                   backlight = <&backlight>;
> > >         };
> > > };
> >
> > Yes, I know, it's the generic DSI binding. It's still not legacy.
> >
> > > devm_drm_of_get_bridge cannot find the device with above binding and
> > > able to find the device with below binding.
> > >
> > > &dsi {
> > >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > >        status = "okay";
> > >
> > >       ports {
> > >             #address-cells = <1>;
> > >             #size-cells = <0>;
> > >
> > >            dsi_out: port@0 {
> > >                    reg = <0>;
> > >
> > >                   dsi_out_bridge: endpoint {
> > >                             remote-endpoint = <&bridge_out_dsi>;
> > >                   };
> > >            };
> > >       };
> > >
> > >       panel@0 {
> > >              compatible = "bananapi,s070wv20-ct16-icn6211";
> > >              reg = <0>;
> > >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> > >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> > >              backlight = <&backlight>;
> > >
> > >               port {
> > >                         bridge_out_dsi: endpoint {
> > >                                 remote-endpoint = <&dsi_out_bridge>;
> > >                         };
> > >                 };
> > >        };
> > > };
> >
> > Yes, I know, and that's because ...
> 
> Okay. I will use find panel and bridge separately instead of
> devm_drm_of_get_bridge in version patches.

That's not been my point, at all?

I mean, that whole discussion has been because you shouldn't do that.

> >
> > > >
> > > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > > >
> > > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > > if (IS_ERR(dsi->next_bridge))
> > > > >            return PTR_ERR(dsi->next_bridge);
> > > > >
> > > > > It is only working if we have ports on the pipeline, something like this
> > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > > >
> > > > > Please have a look and let me know if I miss anything?
> > > >
> > > > Yes, you're missing the answer you quoted earlier:
> > >
> > > Yes, I'm trying to resolve the comment one after another. Will get back.
> >
> > ... You've ignored that comment.
> 
> Not understand which comment you mean. There are few about bridge
> conversion details, I will send my comments.

The one that got quoted there and you removed. For reference:

> Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> bindings and look for a panel or bridge not only through the OF graph,
> but also on the child nodes

devm_drm_of_get_bridge uses drm_of_find_panel_or_bridge under the hood,
so of course it won't find it if drm_of_find_panel_or_bridge doesn't.
You need to modify drm_of_find_panel_or_bridge to also look for child
devices and see if there's a panel or bridge registered for that child
node. Then devm_drm_of_get_bridge will work as you intend it to.

Maxime

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-26 16:04                       ` Maxime Ripard
@ 2021-11-30  7:39                         ` Jagan Teki
  -1 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-30  7:39 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Neil Armstrong, Robert Foss, linux-sunxi, dri-devel,
	Chen-Yu Tsai, Laurent Pinchart, Sam Ravnborg, linux-amarula,
	linux-arm-kernel

On Fri, Nov 26, 2021 at 9:34 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Thu, Nov 25, 2021 at 09:44:14PM +0530, Jagan Teki wrote:
> > On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > > > Hi,
> > > >
> > > > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > > >
> > > > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > > > +
> > > > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > > > +             }
> > > > > > > > > > > +     } else {
> > > > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > > > +     }
> > > > > > > > > > > +
> > > > > > > > > > > +     of_node_put(remote);
> > > > > > > > > >
> > > > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > > > >
> > > > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > > > pointed the same before, please check below
> > > > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > > > >
> > > > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > > > but also on the child nodes
> > > > > > >
> > > > > > > Okay. I need to check this.
> > > > > >
> > > > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > > > used in sun6i dsi
> > > > >
> > > > > There's nothing legacy about it.
> > > >
> > > > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> > > >
> > > > &dsi {
> > > >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > >           status = "okay";
> > > >
> > > >          panel@0 {
> > > >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> > > >                    reg = <0>;
> > > >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > > > LCD-RST: PL5 */
> > > >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > > > LCD-PWR-EN: PB7 */
> > > >                   backlight = <&backlight>;
> > > >         };
> > > > };
> > >
> > > Yes, I know, it's the generic DSI binding. It's still not legacy.
> > >
> > > > devm_drm_of_get_bridge cannot find the device with above binding and
> > > > able to find the device with below binding.
> > > >
> > > > &dsi {
> > > >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > >        status = "okay";
> > > >
> > > >       ports {
> > > >             #address-cells = <1>;
> > > >             #size-cells = <0>;
> > > >
> > > >            dsi_out: port@0 {
> > > >                    reg = <0>;
> > > >
> > > >                   dsi_out_bridge: endpoint {
> > > >                             remote-endpoint = <&bridge_out_dsi>;
> > > >                   };
> > > >            };
> > > >       };
> > > >
> > > >       panel@0 {
> > > >              compatible = "bananapi,s070wv20-ct16-icn6211";
> > > >              reg = <0>;
> > > >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> > > >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> > > >              backlight = <&backlight>;
> > > >
> > > >               port {
> > > >                         bridge_out_dsi: endpoint {
> > > >                                 remote-endpoint = <&dsi_out_bridge>;
> > > >                         };
> > > >                 };
> > > >        };
> > > > };
> > >
> > > Yes, I know, and that's because ...
> >
> > Okay. I will use find panel and bridge separately instead of
> > devm_drm_of_get_bridge in version patches.
>
> That's not been my point, at all?
>
> I mean, that whole discussion has been because you shouldn't do that.
>
> > >
> > > > >
> > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > > > >
> > > > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > > > if (IS_ERR(dsi->next_bridge))
> > > > > >            return PTR_ERR(dsi->next_bridge);
> > > > > >
> > > > > > It is only working if we have ports on the pipeline, something like this
> > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > > > >
> > > > > > Please have a look and let me know if I miss anything?
> > > > >
> > > > > Yes, you're missing the answer you quoted earlier:
> > > >
> > > > Yes, I'm trying to resolve the comment one after another. Will get back.
> > >
> > > ... You've ignored that comment.
> >
> > Not understand which comment you mean. There are few about bridge
> > conversion details, I will send my comments.
>
> The one that got quoted there and you removed. For reference:
>
> > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > bindings and look for a panel or bridge not only through the OF graph,
> > but also on the child nodes
>
> devm_drm_of_get_bridge uses drm_of_find_panel_or_bridge under the hood,
> so of course it won't find it if drm_of_find_panel_or_bridge doesn't.
> You need to modify drm_of_find_panel_or_bridge to also look for child
> devices and see if there's a panel or bridge registered for that child
> node. Then devm_drm_of_get_bridge will work as you intend it to.

Got it now, I will make necessary changes.

Thanks,
Jagan.

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-11-30  7:39                         ` Jagan Teki
  0 siblings, 0 replies; 72+ messages in thread
From: Jagan Teki @ 2021-11-30  7:39 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong, Robert Foss,
	Sam Ravnborg, dri-devel, linux-arm-kernel, linux-sunxi,
	linux-amarula

On Fri, Nov 26, 2021 at 9:34 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
> On Thu, Nov 25, 2021 at 09:44:14PM +0530, Jagan Teki wrote:
> > On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > >
> > > On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > > > Hi,
> > > >
> > > > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > > >
> > > > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > > > +
> > > > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > > > +             }
> > > > > > > > > > > +     } else {
> > > > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > > > +     }
> > > > > > > > > > > +
> > > > > > > > > > > +     of_node_put(remote);
> > > > > > > > > >
> > > > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > > > >
> > > > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > > > pointed the same before, please check below
> > > > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > > > >
> > > > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > > > but also on the child nodes
> > > > > > >
> > > > > > > Okay. I need to check this.
> > > > > >
> > > > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > > > used in sun6i dsi
> > > > >
> > > > > There's nothing legacy about it.
> > > >
> > > > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> > > >
> > > > &dsi {
> > > >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > >           status = "okay";
> > > >
> > > >          panel@0 {
> > > >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> > > >                    reg = <0>;
> > > >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > > > LCD-RST: PL5 */
> > > >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > > > LCD-PWR-EN: PB7 */
> > > >                   backlight = <&backlight>;
> > > >         };
> > > > };
> > >
> > > Yes, I know, it's the generic DSI binding. It's still not legacy.
> > >
> > > > devm_drm_of_get_bridge cannot find the device with above binding and
> > > > able to find the device with below binding.
> > > >
> > > > &dsi {
> > > >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > >        status = "okay";
> > > >
> > > >       ports {
> > > >             #address-cells = <1>;
> > > >             #size-cells = <0>;
> > > >
> > > >            dsi_out: port@0 {
> > > >                    reg = <0>;
> > > >
> > > >                   dsi_out_bridge: endpoint {
> > > >                             remote-endpoint = <&bridge_out_dsi>;
> > > >                   };
> > > >            };
> > > >       };
> > > >
> > > >       panel@0 {
> > > >              compatible = "bananapi,s070wv20-ct16-icn6211";
> > > >              reg = <0>;
> > > >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> > > >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> > > >              backlight = <&backlight>;
> > > >
> > > >               port {
> > > >                         bridge_out_dsi: endpoint {
> > > >                                 remote-endpoint = <&dsi_out_bridge>;
> > > >                         };
> > > >                 };
> > > >        };
> > > > };
> > >
> > > Yes, I know, and that's because ...
> >
> > Okay. I will use find panel and bridge separately instead of
> > devm_drm_of_get_bridge in version patches.
>
> That's not been my point, at all?
>
> I mean, that whole discussion has been because you shouldn't do that.
>
> > >
> > > > >
> > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > > > >
> > > > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > > > if (IS_ERR(dsi->next_bridge))
> > > > > >            return PTR_ERR(dsi->next_bridge);
> > > > > >
> > > > > > It is only working if we have ports on the pipeline, something like this
> > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > > > >
> > > > > > Please have a look and let me know if I miss anything?
> > > > >
> > > > > Yes, you're missing the answer you quoted earlier:
> > > >
> > > > Yes, I'm trying to resolve the comment one after another. Will get back.
> > >
> > > ... You've ignored that comment.
> >
> > Not understand which comment you mean. There are few about bridge
> > conversion details, I will send my comments.
>
> The one that got quoted there and you removed. For reference:
>
> > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > bindings and look for a panel or bridge not only through the OF graph,
> > but also on the child nodes
>
> devm_drm_of_get_bridge uses drm_of_find_panel_or_bridge under the hood,
> so of course it won't find it if drm_of_find_panel_or_bridge doesn't.
> You need to modify drm_of_find_panel_or_bridge to also look for child
> devices and see if there's a panel or bridge registered for that child
> node. Then devm_drm_of_get_bridge will work as you intend it to.

Got it now, I will make necessary changes.

Thanks,
Jagan.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
  2021-11-30  7:39                         ` Jagan Teki
@ 2021-12-05 17:39                           ` Michael Nazzareno Trimarchi
  -1 siblings, 0 replies; 72+ messages in thread
From: Michael Nazzareno Trimarchi @ 2021-12-05 17:39 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Maxime Ripard, Chen-Yu Tsai, Laurent Pinchart, Neil Armstrong,
	Robert Foss, Sam Ravnborg, dri-devel, linux-arm-kernel,
	linux-sunxi, linux-amarula

Hi Jagan

@@ -1503,28 +1506,18 @@ static int samsung_dsim_panel_or_bridge(struct
samsung_dsim *dsi,
 {
        struct drm_bridge *panel_bridge;
        struct drm_panel *panel;
-       struct device_node *remote;
-
-       if (of_graph_is_present(node)) {
-               remote = of_graph_get_remote_node(node, DSI_PORT_OUT, 0);
-               if (!remote)
-                       return -ENODEV;
+       int ret;

-               node = remote;
-       }
+       ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel,
+                                         &panel_bridge);
+       if (ret)
+               return ret;

-       panel_bridge = of_drm_find_bridge(node);
-       if (!panel_bridge) {
-               panel = of_drm_find_panel(node);
-               if (!IS_ERR(panel)) {
-                       panel_bridge = drm_panel_bridge_add(panel);
-                       if (IS_ERR(panel_bridge))
-                               return PTR_ERR(panel_bridge);
-               }
+       if (panel) {
+               panel_bridge = drm_panel_bridge_add(panel);
+               if (IS_ERR(panel_bridge))
+                       return PTR_ERR(panel_bridge);
        }
-
-       of_node_put(node);
-
        dsi->out_bridge = panel_bridge;

I need to apply this change to register my panel on imx8mn even mode I
found that
@@ -1594,11 +1587,15 @@ static int samsung_dsim_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;
+
+       if (!drm)
+               return 0;
+
+       mutex_lock(&drm->mode_config.mutex);

mode_config is not initialized in this path.

Michael



On Tue, Nov 30, 2021 at 8:39 AM Jagan Teki <jagan@amarulasolutions.com> wrote:
>
> On Fri, Nov 26, 2021 at 9:34 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Thu, Nov 25, 2021 at 09:44:14PM +0530, Jagan Teki wrote:
> > > On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > > > > Hi,
> > > > >
> > > > > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > > > >
> > > > > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > > > > +
> > > > > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > > > > +             }
> > > > > > > > > > > > +     } else {
> > > > > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > > > > +     }
> > > > > > > > > > > > +
> > > > > > > > > > > > +     of_node_put(remote);
> > > > > > > > > > >
> > > > > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > > > > >
> > > > > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > > > > pointed the same before, please check below
> > > > > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > > > > >
> > > > > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > > > > but also on the child nodes
> > > > > > > >
> > > > > > > > Okay. I need to check this.
> > > > > > >
> > > > > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > > > > used in sun6i dsi
> > > > > >
> > > > > > There's nothing legacy about it.
> > > > >
> > > > > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> > > > >
> > > > > &dsi {
> > > > >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > > >           status = "okay";
> > > > >
> > > > >          panel@0 {
> > > > >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> > > > >                    reg = <0>;
> > > > >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > > > > LCD-RST: PL5 */
> > > > >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > > > > LCD-PWR-EN: PB7 */
> > > > >                   backlight = <&backlight>;
> > > > >         };
> > > > > };
> > > >
> > > > Yes, I know, it's the generic DSI binding. It's still not legacy.
> > > >
> > > > > devm_drm_of_get_bridge cannot find the device with above binding and
> > > > > able to find the device with below binding.
> > > > >
> > > > > &dsi {
> > > > >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > > >        status = "okay";
> > > > >
> > > > >       ports {
> > > > >             #address-cells = <1>;
> > > > >             #size-cells = <0>;
> > > > >
> > > > >            dsi_out: port@0 {
> > > > >                    reg = <0>;
> > > > >
> > > > >                   dsi_out_bridge: endpoint {
> > > > >                             remote-endpoint = <&bridge_out_dsi>;
> > > > >                   };
> > > > >            };
> > > > >       };
> > > > >
> > > > >       panel@0 {
> > > > >              compatible = "bananapi,s070wv20-ct16-icn6211";
> > > > >              reg = <0>;
> > > > >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> > > > >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> > > > >              backlight = <&backlight>;
> > > > >
> > > > >               port {
> > > > >                         bridge_out_dsi: endpoint {
> > > > >                                 remote-endpoint = <&dsi_out_bridge>;
> > > > >                         };
> > > > >                 };
> > > > >        };
> > > > > };
> > > >
> > > > Yes, I know, and that's because ...
> > >
> > > Okay. I will use find panel and bridge separately instead of
> > > devm_drm_of_get_bridge in version patches.
> >
> > That's not been my point, at all?
> >
> > I mean, that whole discussion has been because you shouldn't do that.
> >
> > > >
> > > > > >
> > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > > > > >
> > > > > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > > > > if (IS_ERR(dsi->next_bridge))
> > > > > > >            return PTR_ERR(dsi->next_bridge);
> > > > > > >
> > > > > > > It is only working if we have ports on the pipeline, something like this
> > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > > > > >
> > > > > > > Please have a look and let me know if I miss anything?
> > > > > >
> > > > > > Yes, you're missing the answer you quoted earlier:
> > > > >
> > > > > Yes, I'm trying to resolve the comment one after another. Will get back.
> > > >
> > > > ... You've ignored that comment.
> > >
> > > Not understand which comment you mean. There are few about bridge
> > > conversion details, I will send my comments.
> >
> > The one that got quoted there and you removed. For reference:
> >
> > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > bindings and look for a panel or bridge not only through the OF graph,
> > > but also on the child nodes
> >
> > devm_drm_of_get_bridge uses drm_of_find_panel_or_bridge under the hood,
> > so of course it won't find it if drm_of_find_panel_or_bridge doesn't.
> > You need to modify drm_of_find_panel_or_bridge to also look for child
> > devices and see if there's a panel or bridge registered for that child
> > node. Then devm_drm_of_get_bridge will work as you intend it to.
>
> Got it now, I will make necessary changes.
>
> Thanks,
> Jagan.
>
>


-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver
@ 2021-12-05 17:39                           ` Michael Nazzareno Trimarchi
  0 siblings, 0 replies; 72+ messages in thread
From: Michael Nazzareno Trimarchi @ 2021-12-05 17:39 UTC (permalink / raw)
  To: Jagan Teki
  Cc: Neil Armstrong, linux-amarula, dri-devel, linux-sunxi,
	Robert Foss, Chen-Yu Tsai, Maxime Ripard, Sam Ravnborg,
	linux-arm-kernel, Laurent Pinchart

Hi Jagan

@@ -1503,28 +1506,18 @@ static int samsung_dsim_panel_or_bridge(struct
samsung_dsim *dsi,
 {
        struct drm_bridge *panel_bridge;
        struct drm_panel *panel;
-       struct device_node *remote;
-
-       if (of_graph_is_present(node)) {
-               remote = of_graph_get_remote_node(node, DSI_PORT_OUT, 0);
-               if (!remote)
-                       return -ENODEV;
+       int ret;

-               node = remote;
-       }
+       ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel,
+                                         &panel_bridge);
+       if (ret)
+               return ret;

-       panel_bridge = of_drm_find_bridge(node);
-       if (!panel_bridge) {
-               panel = of_drm_find_panel(node);
-               if (!IS_ERR(panel)) {
-                       panel_bridge = drm_panel_bridge_add(panel);
-                       if (IS_ERR(panel_bridge))
-                               return PTR_ERR(panel_bridge);
-               }
+       if (panel) {
+               panel_bridge = drm_panel_bridge_add(panel);
+               if (IS_ERR(panel_bridge))
+                       return PTR_ERR(panel_bridge);
        }
-
-       of_node_put(node);
-
        dsi->out_bridge = panel_bridge;

I need to apply this change to register my panel on imx8mn even mode I
found that
@@ -1594,11 +1587,15 @@ static int samsung_dsim_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;
+
+       if (!drm)
+               return 0;
+
+       mutex_lock(&drm->mode_config.mutex);

mode_config is not initialized in this path.

Michael



On Tue, Nov 30, 2021 at 8:39 AM Jagan Teki <jagan@amarulasolutions.com> wrote:
>
> On Fri, Nov 26, 2021 at 9:34 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >
> > On Thu, Nov 25, 2021 at 09:44:14PM +0530, Jagan Teki wrote:
> > > On Thu, Nov 25, 2021 at 9:40 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > >
> > > > On Thu, Nov 25, 2021 at 07:55:41PM +0530, Jagan Teki wrote:
> > > > > Hi,
> > > > >
> > > > > On Thu, Nov 25, 2021 at 7:45 PM Maxime Ripard <maxime@cerno.tech> wrote:
> > > > > >
> > > > > > On Wed, Nov 24, 2021 at 12:02:47AM +0530, Jagan Teki wrote:
> > > > > > > > > > > > +     dsi->panel = of_drm_find_panel(remote);
> > > > > > > > > > > > +     if (IS_ERR(dsi->panel)) {
> > > > > > > > > > > > +             dsi->panel = NULL;
> > > > > > > > > > > > +
> > > > > > > > > > > > +             dsi->next_bridge = of_drm_find_bridge(remote);
> > > > > > > > > > > > +             if (IS_ERR(dsi->next_bridge)) {
> > > > > > > > > > > > +                     dev_err(dsi->dev, "failed to find bridge\n");
> > > > > > > > > > > > +                     return PTR_ERR(dsi->next_bridge);
> > > > > > > > > > > > +             }
> > > > > > > > > > > > +     } else {
> > > > > > > > > > > > +             dsi->next_bridge = NULL;
> > > > > > > > > > > > +     }
> > > > > > > > > > > > +
> > > > > > > > > > > > +     of_node_put(remote);
> > > > > > > > > > >
> > > > > > > > > > > Using devm_drm_of_get_bridge would greatly simplify the driver
> > > > > > > > > >
> > > > > > > > > > I'm aware of this and this would break the existing sunxi dsi binding,
> > > > > > > > > > we are not using ports based pipeline in dsi node. Of-course you have
> > > > > > > > > > pointed the same before, please check below
> > > > > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210322140152.101709-2-jagan@amarulasolutions.com/
> > > > > > > > >
> > > > > > > > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > > > > > > > bindings and look for a panel or bridge not only through the OF graph,
> > > > > > > > > but also on the child nodes
> > > > > > > >
> > > > > > > > Okay. I need to check this.
> > > > > > >
> > > > > > > devm_drm_of_get_bridge is not working with legacy binding like the one
> > > > > > > used in sun6i dsi
> > > > > >
> > > > > > There's nothing legacy about it.
> > > > >
> > > > > What I'm mean legacy here with current binding used in sun6i-dsi like this.
> > > > >
> > > > > &dsi {
> > > > >           vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > > >           status = "okay";
> > > > >
> > > > >          panel@0 {
> > > > >                    compatible = "bananapi,s070wv20-ct16-icn6211";
> > > > >                    reg = <0>;
> > > > >                    reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /*
> > > > > LCD-RST: PL5 */
> > > > >                   enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /*
> > > > > LCD-PWR-EN: PB7 */
> > > > >                   backlight = <&backlight>;
> > > > >         };
> > > > > };
> > > >
> > > > Yes, I know, it's the generic DSI binding. It's still not legacy.
> > > >
> > > > > devm_drm_of_get_bridge cannot find the device with above binding and
> > > > > able to find the device with below binding.
> > > > >
> > > > > &dsi {
> > > > >        vcc-dsi-supply = <&reg_dcdc1>; /* VCC-DSI */
> > > > >        status = "okay";
> > > > >
> > > > >       ports {
> > > > >             #address-cells = <1>;
> > > > >             #size-cells = <0>;
> > > > >
> > > > >            dsi_out: port@0 {
> > > > >                    reg = <0>;
> > > > >
> > > > >                   dsi_out_bridge: endpoint {
> > > > >                             remote-endpoint = <&bridge_out_dsi>;
> > > > >                   };
> > > > >            };
> > > > >       };
> > > > >
> > > > >       panel@0 {
> > > > >              compatible = "bananapi,s070wv20-ct16-icn6211";
> > > > >              reg = <0>;
> > > > >              reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
> > > > >              enable-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* LCD-PWR-EN: PB7 */
> > > > >              backlight = <&backlight>;
> > > > >
> > > > >               port {
> > > > >                         bridge_out_dsi: endpoint {
> > > > >                                 remote-endpoint = <&dsi_out_bridge>;
> > > > >                         };
> > > > >                 };
> > > > >        };
> > > > > };
> > > >
> > > > Yes, I know, and that's because ...
> > >
> > > Okay. I will use find panel and bridge separately instead of
> > > devm_drm_of_get_bridge in version patches.
> >
> > That's not been my point, at all?
> >
> > I mean, that whole discussion has been because you shouldn't do that.
> >
> > > >
> > > > > >
> > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20211122065223.88059-6-jagan@amarulasolutions.com/
> > > > > > >
> > > > > > > dsi->next_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 0, 0);
> > > > > > > if (IS_ERR(dsi->next_bridge))
> > > > > > >            return PTR_ERR(dsi->next_bridge);
> > > > > > >
> > > > > > > It is only working if we have ports on the pipeline, something like this
> > > > > > > https://patchwork.kernel.org/project/dri-devel/patch/20210214194102.126146-8-jagan@amarulasolutions.com/
> > > > > > >
> > > > > > > Please have a look and let me know if I miss anything?
> > > > > >
> > > > > > Yes, you're missing the answer you quoted earlier:
> > > > >
> > > > > Yes, I'm trying to resolve the comment one after another. Will get back.
> > > >
> > > > ... You've ignored that comment.
> > >
> > > Not understand which comment you mean. There are few about bridge
> > > conversion details, I will send my comments.
> >
> > The one that got quoted there and you removed. For reference:
> >
> > > Then drm_of_find_panel_or_bridge needs to be adjusted to handle the DSI
> > > bindings and look for a panel or bridge not only through the OF graph,
> > > but also on the child nodes
> >
> > devm_drm_of_get_bridge uses drm_of_find_panel_or_bridge under the hood,
> > so of course it won't find it if drm_of_find_panel_or_bridge doesn't.
> > You need to modify drm_of_find_panel_or_bridge to also look for child
> > devices and see if there's a panel or bridge registered for that child
> > node. Then devm_drm_of_get_bridge will work as you intend it to.
>
> Got it now, I will make necessary changes.
>
> Thanks,
> Jagan.
>
>


-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael@amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info@amarulasolutions.com
www.amarulasolutions.com

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

end of thread, other threads:[~2021-12-06 10:29 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-22  6:52 [PATCH v5 0/7] drm: sun4i: dsi: Convert drm bridge Jagan Teki
2021-11-22  6:52 ` Jagan Teki
2021-11-22  6:52 ` [PATCH v5 1/7] drm: sun4i: dsi: Drop DRM bind race with bridge attach Jagan Teki
2021-11-22  6:52   ` Jagan Teki
2021-11-22  6:52 ` [PATCH v5 2/7] drm: sun4i: dsi: Add component only once DSI device attached Jagan Teki
2021-11-22  6:52   ` Jagan Teki
2021-11-22  6:52 ` [PATCH v5 3/7] drm: sun4i: dsi: Convert to bridge driver Jagan Teki
2021-11-22  6:52   ` Jagan Teki
2021-11-22 10:07   ` Maxime Ripard
2021-11-22 10:07     ` Maxime Ripard
2021-11-22 12:45     ` Laurent Pinchart
2021-11-22 12:45       ` Laurent Pinchart
2021-11-22 13:48     ` Jagan Teki
2021-11-22 13:48       ` Jagan Teki
2021-11-22 14:04       ` Maxime Ripard
2021-11-22 14:04         ` Maxime Ripard
2021-11-22 14:19         ` Jagan Teki
2021-11-22 14:19           ` Jagan Teki
2021-11-22 15:04           ` Maxime Ripard
2021-11-22 15:04             ` Maxime Ripard
2021-11-25 16:17             ` Jagan Teki
2021-11-25 16:17               ` Jagan Teki
2021-11-23 18:32           ` Jagan Teki
2021-11-23 18:32             ` Jagan Teki
2021-11-25 14:15             ` Maxime Ripard
2021-11-25 14:15               ` Maxime Ripard
2021-11-25 14:25               ` Jagan Teki
2021-11-25 14:25                 ` Jagan Teki
2021-11-25 16:10                 ` Maxime Ripard
2021-11-25 16:10                   ` Maxime Ripard
2021-11-25 16:14                   ` Jagan Teki
2021-11-25 16:14                     ` Jagan Teki
2021-11-26 16:04                     ` Maxime Ripard
2021-11-26 16:04                       ` Maxime Ripard
2021-11-30  7:39                       ` Jagan Teki
2021-11-30  7:39                         ` Jagan Teki
2021-12-05 17:39                         ` Michael Nazzareno Trimarchi
2021-12-05 17:39                           ` Michael Nazzareno Trimarchi
2021-11-22 12:52   ` Neil Armstrong
2021-11-22 12:52     ` Neil Armstrong
2021-11-22 13:16     ` Jagan Teki
2021-11-22 13:16       ` Jagan Teki
2021-11-22 15:35       ` Neil Armstrong
2021-11-22 15:35         ` Neil Armstrong
2021-11-22 17:19         ` Dave Stevenson
2021-11-22 17:19           ` Dave Stevenson
2021-11-23  8:19           ` Neil Armstrong
2021-11-23  8:19             ` Neil Armstrong
2021-11-22  6:52 ` [PATCH v5 4/7] drm: sun4i: dsi: Add mode_set function Jagan Teki
2021-11-22  6:52   ` Jagan Teki
2021-11-22 10:07   ` Maxime Ripard
2021-11-22 10:07     ` Maxime Ripard
2021-11-22 13:05     ` Jagan Teki
2021-11-22 13:05       ` Jagan Teki
2021-11-22 13:28       ` Maxime Ripard
2021-11-22 13:28         ` Maxime Ripard
2021-11-22 13:51         ` Jagan Teki
2021-11-22 13:51           ` Jagan Teki
2021-11-22 14:09           ` Maxime Ripard
2021-11-22 14:09             ` Maxime Ripard
2021-11-22 14:31             ` Jagan Teki
2021-11-22 14:31               ` Jagan Teki
2021-11-22 15:06               ` Maxime Ripard
2021-11-22 15:06                 ` Maxime Ripard
2021-11-22 15:17                 ` Jagan Teki
2021-11-22 15:17                   ` Jagan Teki
2021-11-22  6:52 ` [DO NOT MERGE] [PATCH v5 5/7] ARM: dts: sun8i: bananapi-m2m: Enable S070WV20-CT16 Panel Jagan Teki
2021-11-22  6:52   ` Jagan Teki
2021-11-22  6:52 ` [DO NOT MERGE] [PATCH v5 6/7] ARM: dts: sun8i: bananapi-m2m: Enable ICN6211 DSI Bridge Jagan Teki
2021-11-22  6:52   ` Jagan Teki
2021-11-22  6:52 ` [DO NOT MERGE] [PATCH v5 7/7] ARM: dts: sun8i: Enable DLPC3433 Bridge (I2C) Jagan Teki
2021-11-22  6:52   ` Jagan Teki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.