Commit e39a82bf authored by Jagan Teki's avatar Jagan Teki Committed by Inki Dae

drm: exynos: dsi: Lookup OF-graph or Child node devices

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: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: default avatarMarek Vasut <marex@denx.de>
Signed-off-by: default avatarJagan Teki <jagan@amarulasolutions.com>
Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
parent 56193b57
...@@ -1470,18 +1470,52 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, ...@@ -1470,18 +1470,52 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
struct device *dev = dsi->dev; struct device *dev = dsi->dev;
struct drm_encoder *encoder = &dsi->encoder; struct drm_encoder *encoder = &dsi->encoder;
struct drm_device *drm = encoder->dev; struct drm_device *drm = encoder->dev;
struct device_node *np = dev->of_node;
struct device_node *remote;
struct drm_panel *panel; struct drm_panel *panel;
int ret; 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)) { if (!IS_ERR(panel)) {
dsi->out_bridge = devm_drm_panel_bridge_add(dev, panel); dsi->out_bridge = devm_drm_panel_bridge_add(dev, panel);
} else { } else {
dsi->out_bridge = of_drm_find_bridge(device->dev.of_node); dsi->out_bridge = of_drm_find_bridge(remote);
if (!dsi->out_bridge) if (!dsi->out_bridge)
dsi->out_bridge = ERR_PTR(-EINVAL); dsi->out_bridge = ERR_PTR(-EINVAL);
} }
of_node_put(remote);
if (IS_ERR(dsi->out_bridge)) { if (IS_ERR(dsi->out_bridge)) {
ret = PTR_ERR(dsi->out_bridge); ret = PTR_ERR(dsi->out_bridge);
DRM_DEV_ERROR(dev, "failed to find the bridge: %d\n", ret); DRM_DEV_ERROR(dev, "failed to find the bridge: %d\n", ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment