@@ -160,6 +160,58 @@ void drm_bridge_detach(struct drm_bridge *bridge)
bridge->dev = NULL;
}
+/**
+ * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain
+ * @encoder: encoder object
+ *
+ * RETURNS:
+ * the first bridge in the encoder chain, or NULL if there's no bridge
+ * attached to this encoder.
+ */
+struct drm_bridge *
+drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder)
+{
+ return encoder->bridge;
+}
+EXPORT_SYMBOL(drm_bridge_chain_get_first_bridge);
+
+/**
+ * drm_bridge_chain_get_last_bridge() - Get the last bridge in the chain
+ * @encoder: encoder object
+ *
+ * RETURNS:
+ * the last bridge in the encoder chain, or NULL if there's no bridge
+ * attached to this encoder.
+ */
+struct drm_bridge *
+drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder)
+{
+ struct drm_bridge *bridge = encoder->bridge;
+
+ while(bridge && bridge->next)
+ bridge = bridge->next;
+
+ return bridge;
+}
+EXPORT_SYMBOL(drm_bridge_chain_get_last_bridge);
+
+/**
+ * drm_bridge_chain_get_next_bridge() - Get the next bridge in the chain
+ * @bridge: bridge object
+ *
+ * RETURNS:
+ * the next bridge in the chain, or NULL if there's @bridge is the last.
+ */
+struct drm_bridge *
+drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge)
+{
+ if (!bridge || !bridge->encoder)
+ return NULL;
+
+ return bridge->next;
+}
+EXPORT_SYMBOL(drm_bridge_chain_get_next_bridge);
+
/**
* DOC: bridge callbacks
*
@@ -1243,7 +1243,7 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn,
mode->hdisplay, mode->vdisplay, mode->vrefresh,
!!(mode->flags & DRM_MODE_FLAG_INTERLACE), mode->clock * 1000);
- if (hdmi->bridge.next) {
+ if (drm_bridge_chain_get_next_bridge(&hdmi->bridge)) {
struct drm_display_mode adjusted_mode;
drm_mode_copy(&adjusted_mode, mode);
@@ -56,7 +56,7 @@ static void edp_bridge_mode_set(struct drm_bridge *bridge,
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if ((connector->encoder != NULL) &&
- (connector->encoder->bridge == bridge)) {
+ (drm_bridge_chain_get_first_bridge(connector->encoder) == bridge)) {
msm_edp_ctrl_timing_cfg(edp->ctrl,
adjusted_mode, &connector->display_info);
break;
@@ -215,11 +215,10 @@ static int omap_display_id(struct omap_dss_device *output)
node = display->dev->of_node;
omapdss_device_put(display);
} else if (output->bridge) {
- struct drm_bridge *bridge = output->bridge;
-
- while (bridge->next)
- bridge = bridge->next;
+ struct drm_encoder *encoder = output->bridge->encoder;
+ struct drm_bridge *bridge;
+ bridge = drm_bridge_chain_get_last_bridge(encoder);
node = bridge->of_node;
} else if (output->panel) {
node = output->panel->dev->of_node;
@@ -126,7 +126,8 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
for (dssdev = output; dssdev; dssdev = dssdev->next)
omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
- for (bridge = output->bridge; bridge; bridge = bridge->next) {
+ for (bridge = drm_bridge_chain_get_first_bridge(encoder);
+ bridge; bridge = drm_bridge_chain_get_next_bridge(bridge)) {
if (!bridge->timings)
continue;
@@ -14,6 +14,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_fb_cma_helper.h>
@@ -680,9 +681,10 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
const struct drm_display_mode *mode =
&crtc->state->adjusted_mode;
+ struct drm_bridge *bridge;
- rcar_lvds_clk_enable(encoder->base.bridge,
- mode->clock * 1000);
+ bridge = drm_bridge_chain_get_first_bridge(&encoder->base);
+ rcar_lvds_clk_enable(bridge, mode->clock * 1000);
}
rcar_du_crtc_start(rcrtc);
@@ -702,12 +704,14 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) {
struct rcar_du_encoder *encoder =
rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index];
+ struct drm_bridge *bridge;
/*
* Disable the LVDS clock output, see
* rcar_du_crtc_atomic_enable().
*/
- rcar_lvds_clk_disable(encoder->base.bridge);
+ bridge = drm_bridge_chain_get_first_bridge(&encoder->base);
+ rcar_lvds_clk_disable(bridge);
}
spin_lock_irq(&crtc->dev->event_lock);
@@ -1629,8 +1629,10 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,
struct drm_device *drm = dev_get_drvdata(master);
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct vc4_dsi *dsi = dev_get_drvdata(dev);
+ struct drm_bridge *bridge;
- if (dsi->encoder->bridge)
+ bridge = drm_bridge_chain_get_first_bridge(dsi->encoder);
+ if (bridge)
pm_runtime_disable(dev);
vc4_dsi_encoder_destroy(dsi->encoder);
@@ -409,6 +409,12 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np);
int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
struct drm_bridge *previous);
+struct drm_bridge *
+drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder);
+struct drm_bridge *
+drm_bridge_chain_get_last_bridge(struct drm_encoder *encoder);
+struct drm_bridge *
+drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge);
bool drm_bridge_chain_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
And use them in drivers accessing the encoder->bridge or bridge->next fields directly. This is part of our attempt to make the bridge chain a double-linked list based on the generic list helpers. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> --- drivers/gpu/drm/drm_bridge.c | 52 ++++++++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_hdmi.c | 2 +- drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +- drivers/gpu/drm/omapdrm/omap_drv.c | 7 ++-- drivers/gpu/drm/omapdrm/omap_encoder.c | 3 +- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 10 +++-- drivers/gpu/drm/vc4/vc4_dsi.c | 4 +- include/drm/drm_bridge.h | 6 +++ 8 files changed, 75 insertions(+), 11 deletions(-)