For bridge hotplug we need to successfully probe a card with an incomplete
bridge chain, i.e. a chain whose last bridge currently in bridge_chain
needs a next_bridge to work. Such a card would have no connector, and be
able to add one as soon as the followong bridges are added up to the tail
bridge (e.g. a panel_bridge or a connector_bridge).

Currently common DRM code is unable to tell whether the last bridge
currently in the chain is the tail bridge (= the pipeline is complete) or
not.

Add drm_bridge_is_tail(), and a .is_tail func for it to rely on, so common
code can know whether a bridge is a tail bridge or needs a next_bridge.

Signed-off-by: Luca Ceresoli <[email protected]>
---
 drivers/gpu/drm/drm_bridge.c | 28 ++++++++++++++++++++++++++++
 include/drm/drm_bridge.h     | 19 +++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index c62d17e84d4f..2b539c9749a6 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -646,6 +646,34 @@ void drm_bridge_detach(struct drm_bridge *bridge)
        drm_bridge_put(bridge);
 }
 
+/**
+ * drm_bridge_is_tail - check whether the bridge is the last required to
+ *                      have a full pipeline
+ * @bridge: the bridge to check
+ *
+ * Tell whether this is a tail bridge, i.e. a bridge that does not need a
+ * next bridge to work. E.g. a panel_bridge is final, a DSI-to-LVDS bridge
+ * is not.
+ *
+ * In case of hotplug the last bridge currently in the chain (as in
+ * drm_bridge_chain_get_last_bridge()) might not be final, and be waiting
+ * for a pipeline tail to be connected.
+ *
+ * Return: true if this bridge does not need a next bridge to work, false
+ * otherwise
+ */
+bool drm_bridge_is_tail(struct drm_bridge *bridge)
+{
+       if (!(bridge->ops & DRM_BRIDGE_OP_IS_TAIL)) {
+               drm_warn_once(bridge->dev, "is_tail func not implemented by 
bridge %ps!",
+                             bridge->funcs);
+               return false;
+       }
+
+       return bridge->funcs->is_tail(bridge);
+}
+EXPORT_SYMBOL(drm_bridge_is_tail);
+
 /**
  * DOC: bridge operations
  *
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 4ba3a5deef9a..d783a6fb93a0 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -78,6 +78,19 @@ struct drm_bridge_funcs {
        int (*attach)(struct drm_bridge *bridge, struct drm_encoder *encoder,
                      enum drm_bridge_attach_flags flags);
 
+       /**
+        * @is_tail:
+        *
+        * Returns true if this is a tail bridge, i.e. it does not need a
+        * next bridge to work. E.g. a panel_bridge is a tail bridge, a
+        * DSI-to-LVDS bridge is not a tail bridge (no matter whether the
+        * next bridge is present or not).
+        *
+        * The @is_tail callback is optional but it is required if the
+        * bridge is part of a pipeline with hot-pluggable components.
+        */
+       bool (*is_tail)(struct drm_bridge *bridge);
+
        /**
         * @destroy:
         *
@@ -1092,6 +1105,11 @@ enum drm_bridge_ops {
         * &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks.
         */
        DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10),
+       /**
+        * @DRM_BRIDGE_OP_IS_TAIL: The bridge implements the
+        * &drm_bridge_funcs->is_tail callback.
+        */
+       DRM_BRIDGE_OP_IS_TAIL = BIT(11),
 };
 
 /**
@@ -1323,6 +1341,7 @@ void drm_bridge_remove(struct drm_bridge *bridge);
 int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
                      struct drm_bridge *previous,
                      enum drm_bridge_attach_flags flags);
+bool drm_bridge_is_tail(struct drm_bridge *bridge);
 
 #ifdef CONFIG_OF
 struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np);

-- 
2.54.0

Reply via email to