Add support for bridge chips connected externally to the i.MX
DISP0/DISP1 DPI interfaces.

Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
---
 drivers/gpu/drm/imx/parallel-display.c | 71 ++++++++++++++++++++++++++++------
 1 file changed, 59 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/imx/parallel-display.c 
b/drivers/gpu/drm/imx/parallel-display.c
index 2d1fd02..830e56b 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -37,6 +37,7 @@ struct imx_parallel_display {
        u32 bus_format;
        struct drm_display_mode mode;
        struct drm_panel *panel;
+       struct drm_bridge *bridge;
 };

 static enum drm_connector_status imx_pd_connector_detect(
@@ -103,8 +104,23 @@ static void imx_pd_encoder_dpms(struct drm_encoder 
*encoder, int mode)
 static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
 {
        struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
-       imx_drm_set_bus_config(encoder, imxpd->bus_format, 2, 3,
-                              imxpd->connector.display_info.bus_flags);
+       struct drm_connector *connector;
+       u32 bus_format = imxpd->bus_format;
+       u32 bus_flags;
+
+       drm_for_each_connector(connector, encoder->dev) {
+               struct drm_display_info *di = &connector->display_info;
+
+               if (connector->encoder != encoder)
+                       continue;
+
+               bus_flags = di->bus_flags;
+               if (!bus_format && di->num_bus_formats)
+                       bus_format = di->bus_formats[0];
+               break;
+       }
+
+       imx_drm_set_bus_config(encoder, bus_format, 2, 3, bus_flags);
 }

 static void imx_pd_encoder_commit(struct drm_encoder *encoder)
@@ -174,15 +190,29 @@ static int imx_pd_register(struct drm_device *drm,
        drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
                         DRM_MODE_ENCODER_NONE, NULL);

-       drm_connector_helper_add(&imxpd->connector,
-                       &imx_pd_connector_helper_funcs);
-       drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
-                          DRM_MODE_CONNECTOR_VGA);
+       if (!imxpd->bridge) {
+               drm_connector_helper_add(&imxpd->connector,
+                               &imx_pd_connector_helper_funcs);
+               drm_connector_init(drm, &imxpd->connector,
+                                  &imx_pd_connector_funcs,
+                                  DRM_MODE_CONNECTOR_VGA);
+       }

        if (imxpd->panel)
                drm_panel_attach(imxpd->panel, &imxpd->connector);
-
-       drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
+       if (imxpd->bridge) {
+               imxpd->bridge->encoder = &imxpd->encoder;
+               imxpd->encoder.bridge = imxpd->bridge;
+               ret = drm_bridge_attach(drm, imxpd->bridge);
+               if (ret < 0) {
+                       dev_err(imxpd->dev, "failed to attach bridge: %d\n",
+                               ret);
+                       return ret;
+               }
+       } else {
+               drm_mode_connector_attach_encoder(&imxpd->connector,
+                                                 &imxpd->encoder);
+       }

        return 0;
 }
@@ -223,13 +253,30 @@ static int imx_pd_bind(struct device *dev, struct device 
*master, void *data)
                struct device_node *remote;

                remote = of_graph_get_remote_port_parent(ep);
+               if (!remote) {
+                       dev_warn(dev, "endpoint %s not connected\n",
+                                ep->full_name);
+                       of_node_put(ep);
+                       return -ENODEV;
+               }
                of_node_put(ep);
-               if (remote) {
-                       imxpd->panel = of_drm_find_panel(remote);
-                       of_node_put(remote);
+
+               imxpd->panel = of_drm_find_panel(remote);
+               if (imxpd->panel) {
+                       dev_dbg(dev, "found panel %s\n", remote->full_name);
+               } else {
+                       imxpd->bridge = of_drm_find_bridge(remote);
+                       if (imxpd->bridge)
+                               dev_dbg(dev, "found bridge %s\n",
+                                       remote->full_name);
                }
-               if (!imxpd->panel)
+               if (!imxpd->panel && !imxpd->bridge) {
+                       dev_dbg(dev, "waiting for panel or bridge %s\n",
+                               remote->full_name);
+                       of_node_put(remote);
                        return -EPROBE_DEFER;
+               }
+               of_node_put(remote);
        }

        imxpd->dev = dev;
-- 
2.8.1

Reply via email to