In general, for MIPI DSI there are three ways to represent the
pipeline for an upstream bridge to find the connected downstream
panel or bridge.

1. Child panel or bridge as a conventional device tree child node.
2. Child panel or bridge as an OF-graph port node.
3. Child panel or bridge as an OF-graph ports node.

There are three different downstream panels or bridges that are
possible to connect an upstream DSI host bridge - DSI Panel,
DSI Bridge, and I2C-Configured DSI bridge.

An example of the downstream panel represented as a child node,

&dsi {
   compatible = "samsung,exynos5433-mipi-dsi";

   ports {
        port@0 {
             reg = <0>;

             dsi_to_mic: endpoint {
                  remote-endpoint = <&mic_to_dsi>;
             };
        };
   };

   panel@0 {
        reg = <0>;
   };
};

An example of the downstream bridge represented as a port node,

&i2c4 {
   bridge@2c {
        compatible = "ti,sn65dsi84";

        ports {
             port@0 {
                  reg = <0>;

                  bridge_in_dsi: endpoint {
                       remote-endpoint = <&dsi_out_bridge>;
                       data-lanes = <1 2>;
                  };
             };

             port@2 {
                  reg = <2>;

                  bridge_out_panel: endpoint {
                       remote-endpoint = <&panel_out_bridge>;
                  };
             };
        };
   };
};

&dsi {
   compatible = "fsl,imx8mm-mipi-dsim";

   port {
        dsi_in_lcdif: endpoint@0 {
             reg = <0>;
             remote-endpoint = <&lcdif_out_dsi>;
        };

        dsi_out_bridge: endpoint@1 {
             reg = <1>;
             remote-endpoint = <&bridge_in_dsi>;
        };
   };
};

An example of the downstream bridge represented as a ports node,

&dsi {
   compatible = "fsl,imx8mm-mipi-dsim";

   ports {
        port@0 {
             reg = <0>;

             dsi_in_lcdif: endpoint@0 {
                  reg = <0>;
                  remote-endpoint = <&lcdif_out_dsi>;
             };
        };

        port@1 {
             reg = <1>;

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

In, summary it is possible to represent all three downstream slaves
devices using OF-graph port or ports node however only DSI Panel and
DSI Bridge are possible but not possible to represent I2C-Configured
DSI bridge child nodes since I2C-Configure bridges are child of I2C
node, not upstream DSI host bridge and it is must represent them
endpoint port linking.

This indeed means, the OF-graph port or ports representation is
mandatory for I2C-Configured DSI bridges.

This patch tries to add an OF-graph port or ports representation
detection code on top of existing child node detection.

It is possible to replace the entire detection code using existing
drm_of helper drm_of_find_panel_or_bridge but it will break the
Exynos DSI since the pipeline doesn't support OF-graph port or ports
node.

Overall, this patch has a combination of child and OF-graph pipeline
detections in order to support the backward compatibility of Exynos
DSI child node and i.MX8M Mini/Nano/Plus OF-graph port or ports
node pipelines.

This is the first common DSI host bridge driver that needs to support
all possible downstream connection pipeline combinations.

Tested-by: Marek Szyprowski <m.szyprow...@samsung.com>
Reviewed-by: Marek Vasut <ma...@denx.de>
Signed-off-by: Jagan Teki <ja...@amarulasolutions.com>
---
Changes for v16:
- collect TB from Marek S
- collect RB from Marek V
- fix multiline comment
Changes for v15:
- droped from drm_of
- added in exynos dsi
- updated commit messages
Changes for v13, v12:
- none
Changes for v11:
- drop extra line
Changes for v10:
- new patch

 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 38 +++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c 
b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index df15501b1075..bb0d2502ea02 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1470,18 +1470,52 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host 
*host,
        struct device *dev = dsi->dev;
        struct drm_encoder *encoder = &dsi->encoder;
        struct drm_device *drm = encoder->dev;
+       struct device_node *np = dev->of_node;
+       struct device_node *remote;
        struct drm_panel *panel;
        int ret;
 
-       panel = of_drm_find_panel(device->dev.of_node);
+       /*
+        * Devices can also be child nodes when we also control that device
+        * through the upstream device (ie, MIPI-DCS for a MIPI-DSI device).
+        *
+        * Lookup for a child node of the given parent that isn't either port
+        * or ports.
+        */
+       for_each_available_child_of_node(np, remote) {
+               if (of_node_name_eq(remote, "port") ||
+                   of_node_name_eq(remote, "ports"))
+                       continue;
+
+               goto of_find_panel_or_bridge;
+       }
+
+       /*
+        * of_graph_get_remote_node() produces a noisy error message if port
+        * node isn't found and the absence of the port is a legit case here,
+        * so at first we silently check whether graph presents in the
+        * device-tree node.
+        */
+       if (!of_graph_is_present(np))
+               return -ENODEV;
+
+       remote = of_graph_get_remote_node(np, 1, 0);
+
+of_find_panel_or_bridge:
+       if (!remote)
+               return -ENODEV;
+
+       panel = of_drm_find_panel(remote);
        if (!IS_ERR(panel)) {
                dsi->out_bridge = devm_drm_panel_bridge_add(dev, panel);
        } else {
-               dsi->out_bridge = of_drm_find_bridge(device->dev.of_node);
+               dsi->out_bridge = of_drm_find_bridge(remote);
                if (!dsi->out_bridge)
                        dsi->out_bridge = ERR_PTR(-EINVAL);
        }
 
+       of_node_put(remote);
+
        if (IS_ERR(dsi->out_bridge)) {
                ret = PTR_ERR(dsi->out_bridge);
                DRM_DEV_ERROR(dev, "failed to find the bridge: %d\n", ret);
-- 
2.25.1

Reply via email to