From 05193dc38197021894b17239fafbd2eb1afe5a45 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 3 Dec 2019 15:15:08 +0100 Subject: drm/bridge: Make the bridge chain a double-linked list So that each element in the chain can easily access its predecessor. This will be needed to support bus format negotiation between elements of the bridge chain. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart Link: https://patchwork.freedesktop.org/patch/msgid/20191203141515.3597631-5-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 171 ++++++++++++++++++++++++++++--------------- 1 file changed, 111 insertions(+), 60 deletions(-) (limited to 'drivers/gpu/drm/drm_bridge.c') diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 54c874493c57..b6517b4fa3d1 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -55,7 +55,7 @@ * just provide additional hooks to get the desired output at the end of the * encoder chain. * - * Bridges can also be chained up using the &drm_bridge.next pointer. + * Bridges can also be chained up using the &drm_bridge.chain_node field. * * Both legacy CRTC helpers and the new atomic modeset helpers support bridges. */ @@ -128,20 +128,21 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, bridge->dev = encoder->dev; bridge->encoder = encoder; + if (previous) + list_add(&bridge->chain_node, &previous->chain_node); + else + list_add(&bridge->chain_node, &encoder->bridge_chain); + if (bridge->funcs->attach) { ret = bridge->funcs->attach(bridge); if (ret < 0) { + list_del(&bridge->chain_node); bridge->dev = NULL; bridge->encoder = NULL; return ret; } } - if (previous) - previous->next = bridge; - else - encoder->bridge = bridge; - return 0; } EXPORT_SYMBOL(drm_bridge_attach); @@ -157,6 +158,7 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (bridge->funcs->detach) bridge->funcs->detach(bridge); + list_del(&bridge->chain_node); bridge->dev = NULL; } @@ -190,18 +192,21 @@ bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - bool ret = true; + struct drm_encoder *encoder; if (!bridge) return true; - if (bridge->funcs->mode_fixup) - ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (!bridge->funcs->mode_fixup) + continue; - ret = ret && drm_bridge_chain_mode_fixup(bridge->next, mode, - adjusted_mode); + if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode)) + return false; + } - return ret; + return true; } EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); @@ -224,18 +229,24 @@ enum drm_mode_status drm_bridge_chain_mode_valid(struct drm_bridge *bridge, const struct drm_display_mode *mode) { - enum drm_mode_status ret = MODE_OK; + struct drm_encoder *encoder; if (!bridge) - return ret; + return MODE_OK; - if (bridge->funcs->mode_valid) - ret = bridge->funcs->mode_valid(bridge, mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + enum drm_mode_status ret; + + if (!bridge->funcs->mode_valid) + continue; - if (ret != MODE_OK) - return ret; + ret = bridge->funcs->mode_valid(bridge, mode); + if (ret != MODE_OK) + return ret; + } - return drm_bridge_chain_mode_valid(bridge->next, mode); + return MODE_OK; } EXPORT_SYMBOL(drm_bridge_chain_mode_valid); @@ -251,13 +262,20 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_valid); */ void drm_bridge_chain_disable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_bridge_chain_disable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->disable) + iter->funcs->disable(iter); - if (bridge->funcs->disable) - bridge->funcs->disable(bridge); + if (iter == bridge) + break; + } } EXPORT_SYMBOL(drm_bridge_chain_disable); @@ -274,13 +292,16 @@ EXPORT_SYMBOL(drm_bridge_chain_disable); */ void drm_bridge_chain_post_disable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->post_disable) - bridge->funcs->post_disable(bridge); - - drm_bridge_chain_post_disable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->post_disable) + bridge->funcs->post_disable(bridge); + } } EXPORT_SYMBOL(drm_bridge_chain_post_disable); @@ -300,13 +321,16 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->mode_set) - bridge->funcs->mode_set(bridge, mode, adjusted_mode); - - drm_bridge_chain_mode_set(bridge->next, mode, adjusted_mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->mode_set) + bridge->funcs->mode_set(bridge, mode, adjusted_mode); + } } EXPORT_SYMBOL(drm_bridge_chain_mode_set); @@ -323,13 +347,17 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set); */ void drm_bridge_chain_pre_enable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_bridge_chain_pre_enable(bridge->next); - - if (bridge->funcs->pre_enable) - bridge->funcs->pre_enable(bridge); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->pre_enable) + iter->funcs->pre_enable(iter); + } } EXPORT_SYMBOL(drm_bridge_chain_pre_enable); @@ -345,13 +373,16 @@ EXPORT_SYMBOL(drm_bridge_chain_pre_enable); */ void drm_bridge_chain_enable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->enable) - bridge->funcs->enable(bridge); - - drm_bridge_chain_enable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->enable) + bridge->funcs->enable(bridge); + } } EXPORT_SYMBOL(drm_bridge_chain_enable); @@ -370,15 +401,22 @@ EXPORT_SYMBOL(drm_bridge_chain_enable); void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_atomic_bridge_chain_disable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->atomic_disable) + iter->funcs->atomic_disable(iter, state); + else if (iter->funcs->disable) + iter->funcs->disable(iter); - if (bridge->funcs->atomic_disable) - bridge->funcs->atomic_disable(bridge, state); - else if (bridge->funcs->disable) - bridge->funcs->disable(bridge); + if (iter == bridge) + break; + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); @@ -398,15 +436,18 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->atomic_post_disable) - bridge->funcs->atomic_post_disable(bridge, state); - else if (bridge->funcs->post_disable) - bridge->funcs->post_disable(bridge); - - drm_atomic_bridge_chain_post_disable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->atomic_post_disable) + bridge->funcs->atomic_post_disable(bridge, state); + else if (bridge->funcs->post_disable) + bridge->funcs->post_disable(bridge); + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); @@ -426,15 +467,22 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_atomic_bridge_chain_pre_enable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->atomic_pre_enable) + iter->funcs->atomic_pre_enable(iter, state); + else if (iter->funcs->pre_enable) + iter->funcs->pre_enable(iter); - if (bridge->funcs->atomic_pre_enable) - bridge->funcs->atomic_pre_enable(bridge, state); - else if (bridge->funcs->pre_enable) - bridge->funcs->pre_enable(bridge); + if (iter == bridge) + break; + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); @@ -453,15 +501,18 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->atomic_enable) - bridge->funcs->atomic_enable(bridge, state); - else if (bridge->funcs->enable) - bridge->funcs->enable(bridge); - - drm_atomic_bridge_chain_enable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->atomic_enable) + bridge->funcs->atomic_enable(bridge, state); + else if (bridge->funcs->enable) + bridge->funcs->enable(bridge); + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); -- cgit v1.2.3