Hook up drm_bridge support in the omapdrm driver. Despite the recent
extensive preparation work, this is a rather intrusive change, as the
management of outputs needs to be adapted through the driver to handle
both omap_dss_device and drm_bridge.

Connector creation is skipped when using a drm_bridge, as the bridge
creates the connector internally. This creates issues with systems that
split connector operations (such as modes retrieval and hot-plug
detection) across different bridges. These systems can't be supported
using drm_bridge for now (their support through the omap_dss_device
infrastructure is not affected), this will be fixed in subsequent
changes.

Signed-off-by: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
Reviewed-by: Sebastian Reichel <sebastian.reic...@collabora.com>
---
Changes since v1:

- Fix typo in function name (updata -> update)
---
 drivers/gpu/drm/omapdrm/dss/base.c       | 27 ++++++++--
 drivers/gpu/drm/omapdrm/dss/omapdss.h    |  1 +
 drivers/gpu/drm/omapdrm/dss/output.c     | 21 +++++---
 drivers/gpu/drm/omapdrm/omap_connector.c | 16 ++++--
 drivers/gpu/drm/omapdrm/omap_connector.h |  1 -
 drivers/gpu/drm/omapdrm/omap_crtc.c      |  2 +-
 drivers/gpu/drm/omapdrm/omap_drv.c       | 69 +++++++++++++++++-------
 drivers/gpu/drm/omapdrm/omap_encoder.c   | 69 ++++++++++++++----------
 8 files changed, 145 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/omapdrm/dss/base.c 
b/drivers/gpu/drm/omapdrm/dss/base.c
index 81ea0f55cd75..09c9f2971aa2 100644
--- a/drivers/gpu/drm/omapdrm/dss/base.c
+++ b/drivers/gpu/drm/omapdrm/dss/base.c
@@ -19,6 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_graph.h>
+#include <linux/platform_device.h>
 
 #include "dss.h"
 #include "omapdss.h"
@@ -156,7 +157,7 @@ struct omap_dss_device *omapdss_device_next_output(struct 
omap_dss_device *from)
                        goto done;
                }
 
-               if (dssdev->id && dssdev->next)
+               if (dssdev->id && (dssdev->next || dssdev->bridge))
                        goto done;
        }
 
@@ -184,7 +185,18 @@ int omapdss_device_connect(struct dss_device *dss,
 {
        int ret;
 
-       dev_dbg(dst->dev, "connect\n");
+       dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n",
+               src ? dev_name(src->dev) : "NULL",
+               dst ? dev_name(dst->dev) : "NULL");
+
+       if (!dst) {
+               /*
+                * The destination is NULL when the source is connected to a
+                * bridge instead of a DSS device. Stop here, we will attach the
+                * bridge later when we will have a DRM encoder.
+                */
+               return src && src->bridge ? 0 : -EINVAL;
+       }
 
        if (omapdss_device_is_connected(dst))
                return -EBUSY;
@@ -204,7 +216,16 @@ EXPORT_SYMBOL_GPL(omapdss_device_connect);
 void omapdss_device_disconnect(struct omap_dss_device *src,
                               struct omap_dss_device *dst)
 {
-       dev_dbg(dst->dev, "disconnect\n");
+       struct dss_device *dss = src ? src->dss : dst->dss;
+
+       dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n",
+               src ? dev_name(src->dev) : "NULL",
+               dst ? dev_name(dst->dev) : "NULL");
+
+       if (!dst) {
+               WARN_ON(!src->bridge);
+               return;
+       }
 
        if (!dst->id && !omapdss_device_is_connected(dst)) {
                WARN_ON(!dst->display);
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h 
b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index ab5467a1e92c..f47e9b94288f 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -410,6 +410,7 @@ struct omap_dss_device {
 
        struct dss_device *dss;
        struct omap_dss_device *next;
+       struct drm_bridge *bridge;
 
        struct list_head list;
 
diff --git a/drivers/gpu/drm/omapdrm/dss/output.c 
b/drivers/gpu/drm/omapdrm/dss/output.c
index f25ecfd26534..2a53025c2fde 100644
--- a/drivers/gpu/drm/omapdrm/dss/output.c
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
@@ -20,25 +20,34 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/of_graph.h>
 
 #include "dss.h"
 #include "omapdss.h"
 
 int omapdss_device_init_output(struct omap_dss_device *out)
 {
-       out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
-       if (IS_ERR(out->next)) {
-               if (PTR_ERR(out->next) != -EPROBE_DEFER)
-                       dev_err(out->dev, "failed to find video sink\n");
-               return PTR_ERR(out->next);
+       struct device_node *remote_node;
+
+       remote_node = of_graph_get_remote_node(out->dev->of_node, 0, 0);
+       if (!remote_node) {
+               dev_dbg(out->dev, "failed to find video sink\n");
+               return 0;
        }
 
+       out->next = omapdss_find_device_by_node(remote_node);
+       out->bridge = of_drm_find_bridge(remote_node);
+
+       of_node_put(remote_node);
+
        if (out->next && out->type != out->next->type) {
                dev_err(out->dev, "output type and display type don't match\n");
+               omapdss_device_put(out->next);
+               out->next = NULL;
                return -EINVAL;
        }
 
-       return 0;
+       return out->next || out->bridge ? 0 : -EPROBE_DEFER;
 }
 EXPORT_SYMBOL(omapdss_device_init_output);
 
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c 
b/drivers/gpu/drm/omapdrm/omap_connector.c
index 487603c56b08..f528baa80114 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -304,9 +304,16 @@ static const struct drm_connector_helper_funcs 
omap_connector_helper_funcs = {
        .mode_valid = omap_connector_mode_valid,
 };
 
-static int omap_connector_get_type(struct omap_dss_device *display)
+static int omap_connector_get_type(struct omap_dss_device *output)
 {
-       switch (display->type) {
+       struct omap_dss_device *display;
+       enum omap_display_type type;
+
+       display = omapdss_display_get(output);
+       type = display->type;
+       omapdss_device_put(display);
+
+       switch (type) {
        case OMAP_DISPLAY_TYPE_HDMI:
                return DRM_MODE_CONNECTOR_HDMIA;
        case OMAP_DISPLAY_TYPE_DVI:
@@ -329,14 +336,13 @@ static int omap_connector_get_type(struct omap_dss_device 
*display)
 /* initialize connector */
 struct drm_connector *omap_connector_init(struct drm_device *dev,
                                          struct omap_dss_device *output,
-                                         struct omap_dss_device *display,
                                          struct drm_encoder *encoder)
 {
        struct drm_connector *connector = NULL;
        struct omap_connector *omap_connector;
        struct omap_dss_device *dssdev;
 
-       DBG("%s", display->name);
+       DBG("%s", output->name);
 
        omap_connector = kzalloc(sizeof(*omap_connector), GFP_KERNEL);
        if (!omap_connector)
@@ -349,7 +355,7 @@ struct drm_connector *omap_connector_init(struct drm_device 
*dev,
        connector->doublescan_allowed = 0;
 
        drm_connector_init(dev, connector, &omap_connector_funcs,
-                          omap_connector_get_type(display));
+                          omap_connector_get_type(output));
        drm_connector_helper_add(connector, &omap_connector_helper_funcs);
 
        /*
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.h 
b/drivers/gpu/drm/omapdrm/omap_connector.h
index 6b7d4d95e32b..608085219336 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.h
+++ b/drivers/gpu/drm/omapdrm/omap_connector.h
@@ -31,7 +31,6 @@ struct omap_dss_device;
 
 struct drm_connector *omap_connector_init(struct drm_device *dev,
                                          struct omap_dss_device *output,
-                                         struct omap_dss_device *display,
                                          struct drm_encoder *encoder);
 bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
 void omap_connector_enable_hpd(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c 
b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 0cea3824d3a6..4486152fd6cc 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -671,7 +671,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
                                        &omap_crtc_funcs, NULL);
        if (ret < 0) {
                dev_err(dev->dev, "%s(): could not init crtc for: %s\n",
-                       __func__, pipe->display->name);
+                       __func__, pipe->output->name);
                kfree(omap_crtc);
                return ERR_PTR(ret);
        }
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c 
b/drivers/gpu/drm/omapdrm/omap_drv.c
index 6b91f44e5a60..35c4669dc69d 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -140,9 +140,7 @@ static void omap_disconnect_pipelines(struct drm_device 
*ddev)
                omapdss_device_disconnect(NULL, pipe->output);
 
                omapdss_device_put(pipe->output);
-               omapdss_device_put(pipe->display);
                pipe->output = NULL;
-               pipe->display = NULL;
        }
 
        memset(&priv->channels, 0, sizeof(priv->channels));
@@ -169,7 +167,6 @@ static int omap_connect_pipelines(struct drm_device *ddev)
 
                        pipe = &priv->pipes[priv->num_pipes++];
                        pipe->output = omapdss_device_get(output);
-                       pipe->display = omapdss_display_get(output);
 
                        if (priv->num_pipes == ARRAY_SIZE(priv->pipes)) {
                                /* To balance the 'for_each_dss_output' loop */
@@ -207,6 +204,28 @@ static int omap_modeset_init_properties(struct drm_device 
*dev)
        return 0;
 }
 
+static int omap_display_id(struct omap_dss_device *output)
+{
+       struct device_node *node = NULL;
+
+       if (output->next) {
+               struct omap_dss_device *display;
+
+               display = omapdss_display_get(output);
+               node = display->dev->of_node;
+               omapdss_device_put(display);
+       } else {
+               struct drm_bridge *bridge = output->bridge;
+
+               while (bridge->next)
+                       bridge = bridge->next;
+
+               node = bridge->of_node;
+       }
+
+       return node ? of_alias_get_id(node, "display") : -ENODEV;
+}
+
 static int omap_modeset_init(struct drm_device *dev)
 {
        struct omap_drm_private *priv = dev->dev_private;
@@ -262,7 +281,10 @@ static int omap_modeset_init(struct drm_device *dev)
                priv->planes[priv->num_planes++] = plane;
        }
 
-       /* Create the encoders and get the pipelines aliases. */
+       /*
+        * Create the encoders, attach the bridges and get the pipeline alias
+        * IDs.
+        */
        for (i = 0; i < priv->num_pipes; i++) {
                struct omap_drm_pipeline *pipe = &priv->pipes[i];
                int id;
@@ -271,7 +293,14 @@ static int omap_modeset_init(struct drm_device *dev)
                if (!pipe->encoder)
                        return -ENOMEM;
 
-               id = of_alias_get_id(pipe->display->dev->of_node, "display");
+               if (pipe->output->bridge) {
+                       ret = drm_bridge_attach(pipe->encoder,
+                                               pipe->output->bridge, NULL);
+                       if (ret < 0)
+                               return ret;
+               }
+
+               id = omap_display_id(pipe->output);
                pipe->alias_id = id >= 0 ? id : i;
        }
 
@@ -297,16 +326,16 @@ static int omap_modeset_init(struct drm_device *dev)
        for (i = 0; i < priv->num_pipes; i++) {
                struct omap_drm_pipeline *pipe = &priv->pipes[i];
                struct drm_encoder *encoder = pipe->encoder;
-               struct drm_connector *connector;
                struct drm_crtc *crtc;
 
-               connector = omap_connector_init(dev, pipe->output,
-                                               pipe->display, encoder);
-               if (!connector)
-                       return -ENOMEM;
+               if (!pipe->output->bridge) {
+                       pipe->connector = omap_connector_init(dev, pipe->output,
+                                                             encoder);
+                       if (!pipe->connector)
+                               return -ENOMEM;
 
-               drm_connector_attach_encoder(connector, encoder);
-               pipe->connector = connector;
+                       drm_connector_attach_encoder(pipe->connector, encoder);
+               }
 
                crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
                if (IS_ERR(crtc))
@@ -350,10 +379,12 @@ static int omap_modeset_init(struct drm_device *dev)
 static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
 {
        struct omap_drm_private *priv = ddev->dev_private;
-       int i;
+       unsigned int i;
 
-       for (i = 0; i < priv->num_pipes; i++)
-               omap_connector_enable_hpd(priv->pipes[i].connector);
+       for (i = 0; i < priv->num_pipes; i++) {
+               if (priv->pipes[i].connector)
+                       omap_connector_enable_hpd(priv->pipes[i].connector);
+       }
 }
 
 /*
@@ -362,10 +393,12 @@ static void omap_modeset_enable_external_hpd(struct 
drm_device *ddev)
 static void omap_modeset_disable_external_hpd(struct drm_device *ddev)
 {
        struct omap_drm_private *priv = ddev->dev_private;
-       int i;
+       unsigned int i;
 
-       for (i = 0; i < priv->num_pipes; i++)
-               omap_connector_disable_hpd(priv->pipes[i].connector);
+       for (i = 0; i < priv->num_pipes; i++) {
+               if (priv->pipes[i].connector)
+                       omap_connector_disable_hpd(priv->pipes[i].connector);
+       }
 }
 
 /*
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c 
b/drivers/gpu/drm/omapdrm/omap_encoder.c
index e71d359a8f07..76f94cc0c0cf 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -51,6 +51,34 @@ static const struct drm_encoder_funcs omap_encoder_funcs = {
        .destroy = omap_encoder_destroy,
 };
 
+static void omap_encoder_update_videomode_flags(struct videomode *vm,
+                                               u32 bus_flags)
+{
+       if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW |
+                          DISPLAY_FLAGS_DE_HIGH))) {
+               if (bus_flags & DRM_BUS_FLAG_DE_LOW)
+                       vm->flags |= DISPLAY_FLAGS_DE_LOW;
+               else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
+                       vm->flags |= DISPLAY_FLAGS_DE_HIGH;
+       }
+
+       if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
+                          DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
+               if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
+                       vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+               else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
+                       vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+       }
+
+       if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
+                          DISPLAY_FLAGS_SYNC_NEGEDGE))) {
+               if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
+                       vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
+               else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
+                       vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
+       }
+}
+
 static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder,
                                       struct drm_display_mode *adjusted_mode)
 {
@@ -87,7 +115,9 @@ static void omap_encoder_mode_set(struct drm_encoder 
*encoder,
                                  struct drm_display_mode *adjusted_mode)
 {
        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
+       struct omap_dss_device *output = omap_encoder->output;
        struct omap_dss_device *dssdev;
+       struct drm_bridge *bridge;
        struct videomode vm = { 0 };
 
        drm_display_mode_to_videomode(adjusted_mode, &vm);
@@ -101,44 +131,29 @@ static void omap_encoder_mode_set(struct drm_encoder 
*encoder,
         *
         * A better solution is to use DRM's bus-flags through the whole driver.
         */
-       for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
-               unsigned long bus_flags = dssdev->bus_flags;
-
-               if (!(vm.flags & (DISPLAY_FLAGS_DE_LOW |
-                                 DISPLAY_FLAGS_DE_HIGH))) {
-                       if (bus_flags & DRM_BUS_FLAG_DE_LOW)
-                               vm.flags |= DISPLAY_FLAGS_DE_LOW;
-                       else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
-                               vm.flags |= DISPLAY_FLAGS_DE_HIGH;
-               }
+       for (dssdev = output; dssdev; dssdev = dssdev->next)
+               omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
 
-               if (!(vm.flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
-                                 DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
-                       if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
-                               vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
-                       else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
-                               vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
-               }
+       for (bridge = output->bridge; bridge; bridge = bridge->next) {
+               u32 bus_flags;
 
-               if (!(vm.flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
-                                 DISPLAY_FLAGS_SYNC_NEGEDGE))) {
-                       if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
-                               vm.flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
-                       else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
-                               vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
-               }
+               if (!bridge->timings)
+                       continue;
+
+               bus_flags = bridge->timings->input_bus_flags;
+               omap_encoder_update_videomode_flags(&vm, bus_flags);
        }
 
        /* Set timings for all devices in the display pipeline. */
-       dss_mgr_set_timings(omap_encoder->output, &vm);
+       dss_mgr_set_timings(output, &vm);
 
-       for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
+       for (dssdev = output; dssdev; dssdev = dssdev->next) {
                if (dssdev->ops->set_timings)
                        dssdev->ops->set_timings(dssdev, adjusted_mode);
        }
 
        /* Set the HDMI mode and HDMI infoframe if applicable. */
-       if (omap_encoder->output->type == OMAP_DISPLAY_TYPE_HDMI)
+       if (output->type == OMAP_DISPLAY_TYPE_HDMI)
                omap_encoder_hdmi_mode_set(encoder, adjusted_mode);
 }
 
-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to