From ea099adfdf4bf35903dc1c0f59a0d60175759c70 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 3 Dec 2019 15:15:05 +0100 Subject: drm/bridge: Rename bridge helpers targeting a bridge chain Change the prefix of bridge helpers targeting a bridge chain from drm_bridge_ to drm_bridge_chain_ to better reflect the fact that the operation will happen on all elements of chain, starting at the bridge passed in argument. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Acked-by: Laurent Pinchart Link: https://patchwork.freedesktop.org/patch/msgid/20191203141515.3597631-2-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 125 ++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 61 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 cba537c99e43..54c874493c57 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -172,8 +172,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) */ /** - * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the - * encoder chain + * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the + * encoder chain * @bridge: bridge control structure * @mode: desired mode to be set for the bridge * @adjusted_mode: updated mode that works for this bridge @@ -186,9 +186,9 @@ void drm_bridge_detach(struct drm_bridge *bridge) * RETURNS: * true on success, false on failure */ -bool drm_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +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; @@ -198,15 +198,16 @@ bool drm_bridge_mode_fixup(struct drm_bridge *bridge, if (bridge->funcs->mode_fixup) ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode); - ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode); + ret = ret && drm_bridge_chain_mode_fixup(bridge->next, mode, + adjusted_mode); return ret; } -EXPORT_SYMBOL(drm_bridge_mode_fixup); +EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); /** - * drm_bridge_mode_valid - validate the mode against all bridges in the - * encoder chain. + * drm_bridge_chain_mode_valid - validate the mode against all bridges in the + * encoder chain. * @bridge: bridge control structure * @mode: desired mode to be validated * @@ -219,8 +220,9 @@ EXPORT_SYMBOL(drm_bridge_mode_fixup); * RETURNS: * MODE_OK on success, drm_mode_status Enum error code on failure */ -enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_mode *mode) +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; @@ -233,12 +235,12 @@ enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, if (ret != MODE_OK) return ret; - return drm_bridge_mode_valid(bridge->next, mode); + return drm_bridge_chain_mode_valid(bridge->next, mode); } -EXPORT_SYMBOL(drm_bridge_mode_valid); +EXPORT_SYMBOL(drm_bridge_chain_mode_valid); /** - * drm_bridge_disable - disables all bridges in the encoder chain + * drm_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder @@ -247,20 +249,21 @@ EXPORT_SYMBOL(drm_bridge_mode_valid); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_disable(struct drm_bridge *bridge) +void drm_bridge_chain_disable(struct drm_bridge *bridge) { if (!bridge) return; - drm_bridge_disable(bridge->next); + drm_bridge_chain_disable(bridge->next); if (bridge->funcs->disable) bridge->funcs->disable(bridge); } -EXPORT_SYMBOL(drm_bridge_disable); +EXPORT_SYMBOL(drm_bridge_chain_disable); /** - * drm_bridge_post_disable - cleans up after disabling all bridges in the encoder chain + * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the + * encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.post_disable op for all the bridges in the @@ -269,7 +272,7 @@ EXPORT_SYMBOL(drm_bridge_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_post_disable(struct drm_bridge *bridge) +void drm_bridge_chain_post_disable(struct drm_bridge *bridge) { if (!bridge) return; @@ -277,25 +280,25 @@ void drm_bridge_post_disable(struct drm_bridge *bridge) if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); - drm_bridge_post_disable(bridge->next); + drm_bridge_chain_post_disable(bridge->next); } -EXPORT_SYMBOL(drm_bridge_post_disable); +EXPORT_SYMBOL(drm_bridge_chain_post_disable); /** - * drm_bridge_mode_set - set proposed mode for all bridges in the - * encoder chain + * drm_bridge_chain_mode_set - set proposed mode for all bridges in the + * encoder chain * @bridge: bridge control structure - * @mode: desired mode to be set for the bridge - * @adjusted_mode: updated mode that works for this bridge + * @mode: desired mode to be set for the encoder chain + * @adjusted_mode: updated mode that works for this encoder chain * * Calls &drm_bridge_funcs.mode_set op for all the bridges in the * encoder chain, starting from the first bridge to the last. * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) +void drm_bridge_chain_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { if (!bridge) return; @@ -303,13 +306,13 @@ void drm_bridge_mode_set(struct drm_bridge *bridge, if (bridge->funcs->mode_set) bridge->funcs->mode_set(bridge, mode, adjusted_mode); - drm_bridge_mode_set(bridge->next, mode, adjusted_mode); + drm_bridge_chain_mode_set(bridge->next, mode, adjusted_mode); } -EXPORT_SYMBOL(drm_bridge_mode_set); +EXPORT_SYMBOL(drm_bridge_chain_mode_set); /** - * drm_bridge_pre_enable - prepares for enabling all - * bridges in the encoder chain + * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the + * encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder @@ -318,20 +321,20 @@ EXPORT_SYMBOL(drm_bridge_mode_set); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_pre_enable(struct drm_bridge *bridge) +void drm_bridge_chain_pre_enable(struct drm_bridge *bridge) { if (!bridge) return; - drm_bridge_pre_enable(bridge->next); + drm_bridge_chain_pre_enable(bridge->next); if (bridge->funcs->pre_enable) bridge->funcs->pre_enable(bridge); } -EXPORT_SYMBOL(drm_bridge_pre_enable); +EXPORT_SYMBOL(drm_bridge_chain_pre_enable); /** - * drm_bridge_enable - enables all bridges in the encoder chain + * drm_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder @@ -340,7 +343,7 @@ EXPORT_SYMBOL(drm_bridge_pre_enable); * * Note that the bridge passed should be the one closest to the encoder */ -void drm_bridge_enable(struct drm_bridge *bridge) +void drm_bridge_chain_enable(struct drm_bridge *bridge) { if (!bridge) return; @@ -348,12 +351,12 @@ void drm_bridge_enable(struct drm_bridge *bridge) if (bridge->funcs->enable) bridge->funcs->enable(bridge); - drm_bridge_enable(bridge->next); + drm_bridge_chain_enable(bridge->next); } -EXPORT_SYMBOL(drm_bridge_enable); +EXPORT_SYMBOL(drm_bridge_chain_enable); /** - * drm_atomic_bridge_disable - disables all bridges in the encoder chain + * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -364,24 +367,24 @@ EXPORT_SYMBOL(drm_bridge_enable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; - drm_atomic_bridge_disable(bridge->next, state); + drm_atomic_bridge_chain_disable(bridge->next, state); if (bridge->funcs->atomic_disable) bridge->funcs->atomic_disable(bridge, state); else if (bridge->funcs->disable) bridge->funcs->disable(bridge); } -EXPORT_SYMBOL(drm_atomic_bridge_disable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); /** - * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the - * encoder chain + * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges + * in the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -392,8 +395,8 @@ EXPORT_SYMBOL(drm_atomic_bridge_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; @@ -403,13 +406,13 @@ void drm_atomic_bridge_post_disable(struct drm_bridge *bridge, else if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); - drm_atomic_bridge_post_disable(bridge->next, state); + drm_atomic_bridge_chain_post_disable(bridge->next, state); } -EXPORT_SYMBOL(drm_atomic_bridge_post_disable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); /** - * drm_atomic_bridge_pre_enable - prepares for enabling all bridges in the - * encoder chain + * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in + * the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -420,23 +423,23 @@ EXPORT_SYMBOL(drm_atomic_bridge_post_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; - drm_atomic_bridge_pre_enable(bridge->next, state); + drm_atomic_bridge_chain_pre_enable(bridge->next, state); if (bridge->funcs->atomic_pre_enable) bridge->funcs->atomic_pre_enable(bridge, state); else if (bridge->funcs->pre_enable) bridge->funcs->pre_enable(bridge); } -EXPORT_SYMBOL(drm_atomic_bridge_pre_enable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); /** - * drm_atomic_bridge_enable - enables all bridges in the encoder chain + * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -447,8 +450,8 @@ EXPORT_SYMBOL(drm_atomic_bridge_pre_enable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; @@ -458,9 +461,9 @@ void drm_atomic_bridge_enable(struct drm_bridge *bridge, else if (bridge->funcs->enable) bridge->funcs->enable(bridge); - drm_atomic_bridge_enable(bridge->next, state); + drm_atomic_bridge_chain_enable(bridge->next, state); } -EXPORT_SYMBOL(drm_atomic_bridge_enable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); #ifdef CONFIG_OF /** -- cgit v1.2.3 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 +++++++++++++++++++++----------- drivers/gpu/drm/drm_encoder.c | 16 +-- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 5 +- drivers/gpu/drm/vc4/vc4_dsi.c | 10 +- include/drm/drm_bridge.h | 12 ++- include/drm/drm_encoder.h | 7 +- 6 files changed, 143 insertions(+), 78 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); diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index a2cc7e7241a9..e555281f43d4 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -140,6 +140,7 @@ int drm_encoder_init(struct drm_device *dev, goto out_put; } + INIT_LIST_HEAD(&encoder->bridge_chain); list_add_tail(&encoder->head, &dev->mode_config.encoder_list); encoder->index = dev->mode_config.num_encoder++; @@ -160,23 +161,16 @@ EXPORT_SYMBOL(drm_encoder_init); void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; + struct drm_bridge *bridge, *next; /* Note that the encoder_list is considered to be static; should we * remove the drm_encoder at runtime we would have to decrement all * the indices on the drm_encoder after us in the encoder_list. */ - if (encoder->bridge) { - struct drm_bridge *bridge; - struct drm_bridge *next; - - bridge = drm_bridge_chain_get_first_bridge(encoder); - while (bridge) { - next = drm_bridge_get_next_bridge(bridge); - drm_bridge_detach(bridge); - bridge = next; - } - } + list_for_each_entry_safe(bridge, next, &encoder->bridge_chain, + chain_node) + drm_bridge_detach(bridge); drm_mode_object_unregister(dev, &encoder->base); kfree(encoder->name); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index d984097704b8..7de82e22252a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -255,6 +255,7 @@ struct exynos_dsi { struct mipi_dsi_host dsi_host; struct drm_connector connector; struct drm_panel *panel; + struct list_head bridge_chain; struct drm_bridge *out_bridge; struct device *dev; @@ -1522,7 +1523,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, if (out_bridge) { drm_bridge_attach(encoder, out_bridge, NULL); dsi->out_bridge = out_bridge; - encoder->bridge = NULL; + list_splice(&encoder->bridge_chain, &dsi->bridge_chain); } else { int ret = exynos_dsi_create_connector(encoder); @@ -1588,6 +1589,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, if (dsi->out_bridge->funcs->detach) dsi->out_bridge->funcs->detach(dsi->out_bridge); dsi->out_bridge = NULL; + INIT_LIST_HEAD(&dsi->bridge_chain); } if (drm->mode_config.poll_enabled) @@ -1735,6 +1737,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) init_completion(&dsi->completed); spin_lock_init(&dsi->transfer_lock); INIT_LIST_HEAD(&dsi->transfer_list); + INIT_LIST_HEAD(&dsi->bridge_chain); dsi->dsi_host.ops = &exynos_dsi_ops; dsi->dsi_host.dev = dev; diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index ff81b54ea281..6c5b80ad6154 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -499,6 +499,7 @@ struct vc4_dsi { struct mipi_dsi_host dsi_host; struct drm_encoder *encoder; struct drm_bridge *bridge; + struct list_head bridge_chain; void __iomem *regs; @@ -1460,6 +1461,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) GFP_KERNEL); if (!vc4_dsi_encoder) return -ENOMEM; + + INIT_LIST_HEAD(&dsi->bridge_chain); vc4_dsi_encoder->base.type = VC4_ENCODER_TYPE_DSI1; vc4_dsi_encoder->dsi = dsi; dsi->encoder = &vc4_dsi_encoder->base.base; @@ -1610,7 +1613,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) * from our driver, since we need to sequence them within the * encoder's enable/disable paths. */ - dsi->encoder->bridge = NULL; + list_splice(&dsi->encoder->bridge_chain, &dsi->bridge_chain); if (dsi->port == 0) vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset); @@ -1632,6 +1635,11 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, if (dsi->bridge) pm_runtime_disable(dev); + /* + * Restore the bridge_chain so the bridge detach procedure can happen + * normally. + */ + list_splice(&dsi->bridge_chain, &dsi->encoder->bridge_chain); vc4_dsi_encoder_destroy(dsi->encoder); if (dsi->port == 1) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index bd78c256b1ed..c118726469ee 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -384,8 +384,8 @@ struct drm_bridge { struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ struct drm_encoder *encoder; - /** @next: the next bridge in the encoder chain */ - struct drm_bridge *next; + /** @chain_node: used to form a bridge chain */ + struct list_head chain_node; #ifdef CONFIG_OF /** @of_node: device node pointer to the bridge */ struct device_node *of_node; @@ -420,7 +420,10 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, static inline struct drm_bridge * drm_bridge_get_next_bridge(struct drm_bridge *bridge) { - return bridge->next; + if (list_is_last(&bridge->chain_node, &bridge->encoder->bridge_chain)) + return NULL; + + return list_next_entry(bridge, chain_node); } /** @@ -434,7 +437,8 @@ drm_bridge_get_next_bridge(struct drm_bridge *bridge) static inline struct drm_bridge * drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder) { - return encoder->bridge; + return list_first_entry_or_null(&encoder->bridge_chain, + struct drm_bridge, chain_node); } bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index f06164f44efe..5623994b6e9e 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -172,7 +172,12 @@ struct drm_encoder { * &drm_connector_state.crtc. */ struct drm_crtc *crtc; - struct drm_bridge *bridge; + + /** + * @bridge_chain: Bridges attached to this encoder. + */ + struct list_head bridge_chain; + const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; }; -- cgit v1.2.3 From f3fdbc721b8bc99c692716cf9a3cf061b5a49a18 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 3 Dec 2019 15:15:11 +0100 Subject: drm/bridge: Clarify the atomic enable/disable hooks semantics The [pre_]enable/[post_]disable hooks are passed the old atomic state. Update the doc and rename the arguments to make it clear. Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart Reviewed-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20191203141515.3597631-8-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 24 ++++++++++++------------ include/drm/drm_bridge.h | 8 ++++---- 2 files changed, 16 insertions(+), 16 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 b6517b4fa3d1..c2cf0c90fa26 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -389,7 +389,7 @@ EXPORT_SYMBOL(drm_bridge_chain_enable); /** * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_disable (falls back on * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain, @@ -399,7 +399,7 @@ EXPORT_SYMBOL(drm_bridge_chain_enable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; struct drm_bridge *iter; @@ -410,7 +410,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, 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); + iter->funcs->atomic_disable(iter, old_state); else if (iter->funcs->disable) iter->funcs->disable(iter); @@ -424,7 +424,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges * in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_post_disable (falls back on * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain, @@ -434,7 +434,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; @@ -444,7 +444,7 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, 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); + bridge->funcs->atomic_post_disable(bridge, old_state); else if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); } @@ -455,7 +455,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in * the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain, @@ -465,7 +465,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; struct drm_bridge *iter; @@ -476,7 +476,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, 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); + iter->funcs->atomic_pre_enable(iter, old_state); else if (iter->funcs->pre_enable) iter->funcs->pre_enable(iter); @@ -489,7 +489,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); /** * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_enable (falls back on * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain, @@ -499,7 +499,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; @@ -509,7 +509,7 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, 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); + bridge->funcs->atomic_enable(bridge, old_state); else if (bridge->funcs->enable) bridge->funcs->enable(bridge); } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index bfb0385163f1..d7d714023050 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -263,7 +263,7 @@ struct drm_bridge_funcs { * The @atomic_pre_enable callback is optional. */ void (*atomic_pre_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_enable: @@ -288,7 +288,7 @@ struct drm_bridge_funcs { * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_disable: * @@ -311,7 +311,7 @@ struct drm_bridge_funcs { * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_post_disable: @@ -337,7 +337,7 @@ struct drm_bridge_funcs { * The @atomic_post_disable callback is optional. */ void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); }; /** -- cgit v1.2.3 From 6ed7e9625fa6a6ee8230945820544767ed5799c4 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 6 Jan 2020 15:34:06 +0100 Subject: drm/bridge: Add a drm_bridge_state object One of the last remaining objects to not have its atomic state. This is being motivated by our attempt to support runtime bus-format negotiation between elements of the bridge chain. This patch just paves the road for such a feature by adding a new drm_bridge_state object inheriting from drm_private_obj so we can re-use some of the existing state initialization/tracking logic. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart Signed-off-by: Neil Armstrong Reviewed by: Jernej Skrabec Tested-by: Jonas Karlman Link: https://patchwork.freedesktop.org/patch/msgid/20200106143409.32321-2-narmstrong@baylibre.com --- drivers/gpu/drm/drm_atomic.c | 39 ++++++++++ drivers/gpu/drm/drm_atomic_helper.c | 20 ++++++ drivers/gpu/drm/drm_bridge.c | 139 ++++++++++++++++++++++++++++++++++-- include/drm/drm_atomic.h | 3 + include/drm/drm_bridge.h | 114 +++++++++++++++++++++++++++++ 5 files changed, 309 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/drm_bridge.c') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index d33691512a8e..bf1b9c37d515 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -1017,6 +1018,44 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, connector->funcs->atomic_print_state(p, state); } +/** + * drm_atomic_add_encoder_bridges - add bridges attached to an encoder + * @state: atomic state + * @encoder: DRM encoder + * + * This function adds all bridges attached to @encoder. This is needed to add + * bridge states to @state and make them available when + * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are + * called + * + * Returns: + * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK + * then the w/w mutex code has detected a deadlock and the entire atomic + * sequence must be restarted. All other errors are fatal. + */ +int +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, + struct drm_encoder *encoder) +{ + struct drm_bridge_state *bridge_state; + struct drm_bridge *bridge; + + if (!encoder) + return 0; + + DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", + encoder->base.id, encoder->name, state); + + drm_for_each_bridge_in_chain(encoder, bridge) { + bridge_state = drm_atomic_get_bridge_state(state, bridge); + if (IS_ERR(bridge_state)) + return PTR_ERR(bridge_state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_add_encoder_bridges); + /** * drm_atomic_add_affected_connectors - add connectors for CRTC * @state: atomic state diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4511c2e07bb9..ad8eae98d9e8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -730,6 +730,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; } + /* + * Iterate over all connectors again, and add all affected bridges to + * the state. + */ + for_each_oldnew_connector_in_state(state, connector, + old_connector_state, + new_connector_state, i) { + struct drm_encoder *encoder; + + encoder = old_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + + encoder = new_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + } + ret = mode_valid(state); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index c2cf0c90fa26..a213c9042f2c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -89,6 +90,74 @@ void drm_bridge_remove(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_remove); +static struct drm_bridge_state * +drm_atomic_default_bridge_duplicate_state(struct drm_bridge *bridge) +{ + struct drm_bridge_state *new; + + if (WARN_ON(!bridge->base.state)) + return NULL; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (new) + __drm_atomic_helper_bridge_duplicate_state(bridge, new); + + return new; +} + +static struct drm_private_state * +drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj) +{ + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + struct drm_bridge_state *state; + + if (bridge->funcs->atomic_duplicate_state) + state = bridge->funcs->atomic_duplicate_state(bridge); + else + state = drm_atomic_default_bridge_duplicate_state(bridge); + + return state ? &state->base : NULL; +} + +static void +drm_atomic_default_bridge_destroy_state(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + /* Just a simple kfree() for now */ + kfree(state); +} + +static void +drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj, + struct drm_private_state *s) +{ + struct drm_bridge_state *state = drm_priv_to_bridge_state(s); + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + + if (bridge->funcs->atomic_destroy_state) + bridge->funcs->atomic_destroy_state(bridge, state); + else + drm_atomic_default_bridge_destroy_state(bridge, state); +} + +static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { + .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state, + .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, +}; + +static struct drm_bridge_state * +drm_atomic_default_bridge_reset(struct drm_bridge *bridge) +{ + struct drm_bridge_state *bridge_state; + + bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL); + if (!bridge_state) + return ERR_PTR(-ENOMEM); + + __drm_atomic_helper_bridge_reset(bridge, bridge_state); + return bridge_state; +} + /** * drm_bridge_attach - attach the bridge to an encoder's chain * @@ -114,6 +183,7 @@ EXPORT_SYMBOL(drm_bridge_remove); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous) { + struct drm_bridge_state *state; int ret; if (!encoder || !bridge) @@ -135,15 +205,35 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, 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 (ret < 0) + goto err_reset_bridge; } + if (bridge->funcs->atomic_reset) + state = bridge->funcs->atomic_reset(bridge); + else + state = drm_atomic_default_bridge_reset(bridge); + + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto err_detach_bridge; + } + + drm_atomic_private_obj_init(bridge->dev, &bridge->base, + &state->base, + &drm_bridge_priv_state_funcs); + return 0; + +err_detach_bridge: + if (bridge->funcs->detach) + bridge->funcs->detach(bridge); + +err_reset_bridge: + bridge->dev = NULL; + bridge->encoder = NULL; + list_del(&bridge->chain_node); + return ret; } EXPORT_SYMBOL(drm_bridge_attach); @@ -155,6 +245,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (WARN_ON(!bridge->dev)) return; + drm_atomic_private_obj_fini(&bridge->base); + if (bridge->funcs->detach) bridge->funcs->detach(bridge); @@ -516,6 +608,41 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); +/** + * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its + * default + * @bridge: the bridge this state is refers to + * @state: bridge state to initialize + * + * Initialize the bridge state to default values. This is meant to be* called + * by the bridge &drm_plane_funcs.reset hook for bridges that subclass the + * bridge state. + */ +void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + memset(state, 0, sizeof(*state)); + state->bridge = bridge; +} +EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset); + +/** + * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state + * @bridge: bridge object + * @state: atomic bridge state + * + * Copies atomic state from a bridge's current state and resets inferred values. + * This is useful for drivers that subclass the bridge state. + */ +void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + __drm_atomic_helper_private_obj_duplicate_state(&bridge->base, + &state->base); + state->bridge = bridge; +} +EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state); + #ifdef CONFIG_OF /** * of_drm_find_bridge - find the bridge corresponding to the device node in diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 951dfb15c27b..ccce65e14917 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -669,6 +669,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state, return plane->state; } +int __must_check +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, + struct drm_encoder *encoder); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 694e153a7531..fc7c71f4de55 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -25,6 +25,8 @@ #include #include + +#include #include #include #include @@ -33,6 +35,23 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; +/** + * struct drm_bridge_state - Atomic bridge state object + * @base: inherit from &drm_private_state + * @bridge: the bridge this state refers to + */ +struct drm_bridge_state { + struct drm_private_state base; + + struct drm_bridge *bridge; +}; + +static inline struct drm_bridge_state * +drm_priv_to_bridge_state(struct drm_private_state *priv) +{ + return container_of(priv, struct drm_bridge_state, base); +} + /** * struct drm_bridge_funcs - drm_bridge control functions */ @@ -338,6 +357,49 @@ struct drm_bridge_funcs { */ void (*atomic_post_disable)(struct drm_bridge *bridge, struct drm_atomic_state *old_state); + + /** + * @atomic_duplicate_state: + * + * Duplicate the current bridge state object (which is guaranteed to be + * non-NULL). + * + * The atomic_duplicate_state() is optional. When not implemented the + * core allocates a drm_bridge_state object and calls + * &__drm_atomic_helper_bridge_duplicate_state() to initialize it. + * + * RETURNS: + * A valid drm_bridge_state object or NULL if the allocation fails. + */ + struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge); + + /** + * @atomic_destroy_state: + * + * Destroy a bridge state object previously allocated by + * &drm_bridge_funcs.atomic_duplicate_state(). + * + * The atomic_destroy_state hook is optional. When not implemented the + * core calls kfree() on the state. + */ + void (*atomic_destroy_state)(struct drm_bridge *bridge, + struct drm_bridge_state *state); + + /** + * @atomic_reset: + * + * Reset the bridge to a predefined state (or retrieve its current + * state) and return a &drm_bridge_state object matching this state. + * This function is called at attach time. + * + * The atomic_reset hook is optional. When not implemented the core + * allocates a new state and calls &__drm_atomic_helper_bridge_reset(). + * + * RETURNS: + * A valid drm_bridge_state object in case of success, an ERR_PTR() + * giving the reason of the failure otherwise. + */ + struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge); }; /** @@ -380,6 +442,8 @@ struct drm_bridge_timings { * struct drm_bridge - central DRM bridge control structure */ struct drm_bridge { + /** @base: inherit from &drm_private_object */ + struct drm_private_obj base; /** @dev: DRM device this bridge belongs to */ struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ @@ -404,6 +468,12 @@ struct drm_bridge { void *driver_private; }; +static inline struct drm_bridge * +drm_priv_to_bridge(struct drm_private_obj *priv) +{ + return container_of(priv, struct drm_bridge, base); +} + void drm_bridge_add(struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); struct drm_bridge *of_drm_find_bridge(struct device_node *np); @@ -491,6 +561,50 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); +void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, + struct drm_bridge_state *state); +void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, + struct drm_bridge_state *new); + +static inline struct drm_bridge_state * +drm_atomic_get_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge) +{ + struct drm_private_state *obj_state; + + obj_state = drm_atomic_get_private_obj_state(state, &bridge->base); + if (IS_ERR(obj_state)) + return ERR_CAST(obj_state); + + return drm_priv_to_bridge_state(obj_state); +} + +static inline struct drm_bridge_state * +drm_atomic_get_old_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge) +{ + struct drm_private_state *obj_state; + + obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base); + if (!obj_state) + return NULL; + + return drm_priv_to_bridge_state(obj_state); +} + +static inline struct drm_bridge_state * +drm_atomic_get_new_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge) +{ + struct drm_private_state *obj_state; + + obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base); + if (!obj_state) + return NULL; + + return drm_priv_to_bridge_state(obj_state); +} + #ifdef CONFIG_DRM_PANEL_BRIDGE struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, -- cgit v1.2.3 From f7619a58ef9299c42a604ede063bb6e5b88098fb Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 6 Jan 2020 15:34:07 +0100 Subject: drm/bridge: Patch atomic hooks to take a drm_bridge_state This way the drm_bridge_funcs interface is consistent with the rest of the subsystem. The only driver implementing those hooks (analogix DP) is patched too. Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart Signed-off-by: Neil Armstrong Reviewed by: Jernej Skrabec Tested-by: Jonas Karlman [narmstrong: renamed state as old_bridge_state in rcar_lvds_atomic_disable] Link: https://patchwork.freedesktop.org/patch/msgid/20200106143409.32321-3-narmstrong@baylibre.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 41 +++++++++------ drivers/gpu/drm/drm_bridge.c | 61 +++++++++++++++++----- drivers/gpu/drm/rcar-du/rcar_lvds.c | 8 +-- include/drm/drm_bridge.h | 8 +-- 4 files changed, 82 insertions(+), 36 deletions(-) (limited to 'drivers/gpu/drm/drm_bridge.c') diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 6effe532f820..6fab71985cd4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1289,19 +1289,21 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, return conn_state->crtc; } -static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); /* Don't touch the panel if we're coming back from PSR */ if (old_crtc_state && old_crtc_state->self_refresh_active) return; @@ -1366,20 +1368,22 @@ out_dp_clk_pre: return ret; } -static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int timeout_loop = 0; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); /* Not a full enable, just disable PSR and continue */ if (old_crtc_state && old_crtc_state->self_refresh_active) { ret = analogix_dp_disable_psr(dp); @@ -1440,18 +1444,20 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) dp->dpms_mode = DRM_MODE_DPMS_OFF; } -static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) goto out; - new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); if (!new_crtc_state) goto out; @@ -1463,20 +1469,21 @@ out: analogix_dp_bridge_disable(bridge); } -static -void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +static void +analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, state); + crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) return; - new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); if (!new_crtc_state || !new_crtc_state->self_refresh_active) return; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index a213c9042f2c..872e159fcb42 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -501,10 +501,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_disable) - iter->funcs->atomic_disable(iter, old_state); - else if (iter->funcs->disable) + if (iter->funcs->atomic_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_disable(iter, old_bridge_state); + } else if (iter->funcs->disable) { iter->funcs->disable(iter); + } if (iter == bridge) break; @@ -535,10 +544,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, 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, old_state); - else if (bridge->funcs->post_disable) + if (bridge->funcs->atomic_post_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_post_disable(bridge, + old_bridge_state); + } else if (bridge->funcs->post_disable) { bridge->funcs->post_disable(bridge); + } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); @@ -567,10 +586,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, 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, old_state); - else if (iter->funcs->pre_enable) + if (iter->funcs->atomic_pre_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_pre_enable(iter, old_bridge_state); + } else if (iter->funcs->pre_enable) { iter->funcs->pre_enable(iter); + } if (iter == bridge) break; @@ -600,10 +628,19 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_enable) - bridge->funcs->atomic_enable(bridge, old_state); - else if (bridge->funcs->enable) + if (bridge->funcs->atomic_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_enable(bridge, old_bridge_state); + } else if (bridge->funcs->enable) { bridge->funcs->enable(bridge); + } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 8ffa4fbbdeb3..961519ce6634 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -590,8 +590,9 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge, } static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_bridge_state *old_bridge_state) { + struct drm_atomic_state *state = old_bridge_state->base.state; struct drm_connector *connector; struct drm_crtc *crtc; @@ -603,7 +604,7 @@ static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, } static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_bridge_state *old_bridge_state) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); @@ -618,7 +619,8 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, /* Disable the companion LVDS encoder in dual-link mode. */ if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - lvds->companion->funcs->atomic_disable(lvds->companion, state); + lvds->companion->funcs->atomic_disable(lvds->companion, + old_bridge_state); clk_disable_unprepare(lvds->clocks.mod); } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index fc7c71f4de55..52d3ed150618 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -282,7 +282,7 @@ struct drm_bridge_funcs { * The @atomic_pre_enable callback is optional. */ void (*atomic_pre_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_enable: @@ -307,7 +307,7 @@ struct drm_bridge_funcs { * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_disable: * @@ -330,7 +330,7 @@ struct drm_bridge_funcs { * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_post_disable: @@ -356,7 +356,7 @@ struct drm_bridge_funcs { * The @atomic_post_disable callback is optional. */ void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_duplicate_state: -- cgit v1.2.3 From b86d895524ab7281da8ca788e3666ab622fc8620 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 6 Jan 2020 15:34:08 +0100 Subject: drm/bridge: Add an ->atomic_check() hook So that bridge drivers have a way to check/reject an atomic operation. The drm_atomic_bridge_chain_check() (which is just a wrapper around the ->atomic_check() hook) is called in place of drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented, the core falls back on ->mode_fixup(), so the behavior should stay the same for existing bridge drivers). Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart Signed-off-by: Neil Armstrong Reviewed by: Jernej Skrabec Tested-by: Jonas Karlman Link: https://patchwork.freedesktop.org/patch/msgid/20200106143409.32321-4-narmstrong@baylibre.com --- drivers/gpu/drm/drm_atomic_helper.c | 12 +++---- drivers/gpu/drm/drm_bridge.c | 62 +++++++++++++++++++++++++++++++++++++ include/drm/drm_bridge.h | 29 ++++++++++++++++- 3 files changed, 96 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/drm_bridge.c') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ad8eae98d9e8..afe14f72a824 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) funcs = encoder->helper_private; bridge = drm_bridge_chain_get_first_bridge(encoder); - ret = drm_bridge_chain_mode_fixup(bridge, - &new_crtc_state->mode, - &new_crtc_state->adjusted_mode); - if (!ret) { - DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); - return -EINVAL; + ret = drm_atomic_bridge_chain_check(bridge, + new_crtc_state, + new_conn_state); + if (ret) { + DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); + return ret; } if (funcs && funcs->atomic_check) { diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 872e159fcb42..8e4b799150b0 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -645,6 +645,68 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); +static int drm_atomic_bridge_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + if (bridge->funcs->atomic_check) { + struct drm_bridge_state *bridge_state; + int ret; + + bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + bridge); + if (WARN_ON(!bridge_state)) + return -EINVAL; + + ret = bridge->funcs->atomic_check(bridge, bridge_state, + crtc_state, conn_state); + if (ret) + return ret; + } else if (bridge->funcs->mode_fixup) { + if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode, + &crtc_state->adjusted_mode)) + return -EINVAL; + } + + return 0; +} + +/** + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain + * @bridge: bridge control structure + * @crtc_state: new CRTC state + * @conn_state: new connector state + * + * Calls &drm_bridge_funcs.atomic_check() (falls back on + * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, + * starting from the last bridge to the first. These are called before calling + * &drm_encoder_helper_funcs.atomic_check() + * + * RETURNS: + * 0 on success, a negative error code on failure + */ +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge *iter; + + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + int ret; + + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); + if (ret) + return ret; + + if (iter == bridge) + break; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_check); + /** * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its * default diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 52d3ed150618..ae0595c70132 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -128,7 +128,9 @@ struct drm_bridge_funcs { * this function passes all other callbacks must succeed for this * configuration. * - * The @mode_fixup callback is optional. + * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup() + * is not called when &drm_bridge_funcs.atomic_check() is implemented, + * so only one of them should be provided. * * NOTE: * @@ -385,6 +387,28 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); + /** + * @atomic_check: + * + * This method is responsible for checking bridge state correctness. + * It can also check the state of the surrounding components in chain + * to make sure the whole pipeline can work properly. + * + * &drm_bridge_funcs.atomic_check() hooks are called in reverse + * order (from the last to the first bridge). + * + * This method is optional. &drm_bridge_funcs.mode_fixup() is not + * called when &drm_bridge_funcs.atomic_check() is implemented, so only + * one of them should be provided. + * + * RETURNS: + * zero if the check passed, a negative error code otherwise. + */ + int (*atomic_check)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); + /** * @atomic_reset: * @@ -552,6 +576,9 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); void drm_bridge_chain_enable(struct drm_bridge *bridge); +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, struct drm_atomic_state *state); void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, -- cgit v1.2.3 From e351e4d5eaec713b2d4780c79f68702e88f2a212 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 6 Jan 2020 15:34:09 +0100 Subject: drm/bridge: Add the necessary bits to support bus format negotiation drm_bridge_state is extended to describe the input and output bus configurations. These bus configurations are exposed through the drm_bus_cfg struct which encodes the configuration of a physical bus between two components in an output pipeline, usually between two bridges, an encoder and a bridge, or a bridge and a connector. The bus configuration is stored in drm_bridge_state separately for the input and output buses, as seen from the point of view of each bridge. The bus configuration of a bridge output is usually identical to the configuration of the next bridge's input, but may differ if the signals are modified between the two bridges, for instance by an inverter on the board. The input and output configurations of a bridge may differ if the bridge modifies the signals internally, for instance by performing format conversion, or*modifying signals polarities. Bus format negotiation is automated by the core, drivers just have to implement the ->atomic_get_{output,input}_bus_fmts() hooks if they want to take part to this negotiation. Negotiation happens in reverse order, starting from the last element of the chain (the one directly connected to the display) up to the first element of the chain (the one connected to the encoder). During this negotiation all supported formats are tested until we find one that works, meaning that the formats array should be in decreasing preference order (assuming the driver has a preference order). Note that the bus format negotiation works even if some elements in the chain don't implement the ->atomic_get_{output,input}_bus_fmts() hooks. In that case, the core advertises only MEDIA_BUS_FMT_FIXED and lets the previous bridge element decide what to do (most of the time, bridge drivers will pick a default bus format or extract this piece of information from somewhere else, like a FW property). Signed-off-by: Boris Brezillon Signed-off-by: Neil Armstrong Reviewed by: Jernej Skrabec Tested-by: Jonas Karlman [narmstrong: fixed doc in include/drm/drm_bridge.h:69 fmt->format] Link: https://patchwork.freedesktop.org/patch/msgid/20200106143409.32321-5-narmstrong@baylibre.com --- drivers/gpu/drm/drm_bridge.c | 267 ++++++++++++++++++++++++++++++++++++++++++- include/drm/drm_bridge.h | 124 ++++++++++++++++++++ 2 files changed, 390 insertions(+), 1 deletion(-) (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 8e4b799150b0..37400607e9b7 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -671,13 +671,261 @@ static int drm_atomic_bridge_check(struct drm_bridge *bridge, return 0; } +/** + * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to + * the input end of a bridge + * @bridge: bridge control structure + * @bridge_state: new bridge state + * @crtc_state: new CRTC state + * @conn_state: new connector state + * @output_fmt: tested output bus format + * @num_input_fmts: will contain the size of the returned array + * + * This helper is a pluggable implementation of the + * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't + * modify the bus configuration between their input and their output. It + * returns an array of input formats with a single element set to @output_fmt. + * + * RETURNS: + * a valid format array of size @num_input_fmts, or NULL if the allocation + * failed + */ +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + u32 *input_fmts; + + input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); + if (!input_fmts) { + *num_input_fmts = 0; + return NULL; + } + + *num_input_fmts = 1; + input_fmts[0] = output_fmt; + return input_fmts; +} +EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt); + +static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, + struct drm_bridge *cur_bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 out_bus_fmt) +{ + struct drm_bridge_state *cur_state; + unsigned int num_in_bus_fmts, i; + struct drm_bridge *prev_bridge; + u32 *in_bus_fmts; + int ret; + + prev_bridge = drm_bridge_get_prev_bridge(cur_bridge); + cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, + cur_bridge); + if (WARN_ON(!cur_state)) + return -EINVAL; + + /* + * If bus format negotiation is not supported by this bridge, let's + * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and + * hope that it can handle this situation gracefully (by providing + * appropriate default values). + */ + if (!cur_bridge->funcs->atomic_get_input_bus_fmts) { + if (cur_bridge != first_bridge) { + ret = select_bus_fmt_recursive(first_bridge, + prev_bridge, crtc_state, + conn_state, + MEDIA_BUS_FMT_FIXED); + if (ret) + return ret; + } + + cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; + cur_state->output_bus_cfg.format = out_bus_fmt; + return 0; + } + + in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge, + cur_state, + crtc_state, + conn_state, + out_bus_fmt, + &num_in_bus_fmts); + if (!num_in_bus_fmts) + return -ENOTSUPP; + else if (!in_bus_fmts) + return -ENOMEM; + + if (first_bridge == cur_bridge) { + cur_state->input_bus_cfg.format = in_bus_fmts[0]; + cur_state->output_bus_cfg.format = out_bus_fmt; + kfree(in_bus_fmts); + return 0; + } + + for (i = 0; i < num_in_bus_fmts; i++) { + ret = select_bus_fmt_recursive(first_bridge, prev_bridge, + crtc_state, conn_state, + in_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + if (!ret) { + cur_state->input_bus_cfg.format = in_bus_fmts[i]; + cur_state->output_bus_cfg.format = out_bus_fmt; + } + + kfree(in_bus_fmts); + return ret; +} + +/* + * This function is called by &drm_atomic_bridge_chain_check() just before + * calling &drm_bridge_funcs.atomic_check() on all elements of the chain. + * It performs bus format negotiation between bridge elements. The negotiation + * happens in reverse order, starting from the last element in the chain up to + * @bridge. + * + * Negotiation starts by retrieving supported output bus formats on the last + * bridge element and testing them one by one. The test is recursive, meaning + * that for each tested output format, the whole chain will be walked backward, + * and each element will have to choose an input bus format that can be + * transcoded to the requested output format. When a bridge element does not + * support transcoding into a specific output format -ENOTSUPP is returned and + * the next bridge element will have to try a different format. If none of the + * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail. + * + * This implementation is relying on + * &drm_bridge_funcs.atomic_get_output_bus_fmts() and + * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported + * input/output formats. + * + * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by + * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts() + * tries a single format: &drm_connector.display_info.bus_formats[0] if + * available, MEDIA_BUS_FMT_FIXED otherwise. + * + * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented, + * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the + * bridge element that lacks this hook and asks the previous element in the + * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what + * to do in that case (fail if they want to enforce bus format negotiation, or + * provide a reasonable default if they need to support pipelines where not + * all elements support bus format negotiation). + */ +static int +drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_connector *conn = conn_state->connector; + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge_state *last_bridge_state; + unsigned int i, num_out_bus_fmts; + struct drm_bridge *last_bridge; + u32 *out_bus_fmts; + int ret = 0; + + last_bridge = list_last_entry(&encoder->bridge_chain, + struct drm_bridge, chain_node); + last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + last_bridge); + if (WARN_ON(!last_bridge_state)) + return -EINVAL; + + if (last_bridge->funcs->atomic_get_output_bus_fmts) { + const struct drm_bridge_funcs *funcs = last_bridge->funcs; + + out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge, + last_bridge_state, + crtc_state, + conn_state, + &num_out_bus_fmts); + if (!num_out_bus_fmts) + return -ENOTSUPP; + else if (!out_bus_fmts) + return -ENOMEM; + } else { + num_out_bus_fmts = 1; + out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); + if (!out_bus_fmts) + return -ENOMEM; + + if (conn->display_info.num_bus_formats && + conn->display_info.bus_formats) + out_bus_fmts[0] = conn->display_info.bus_formats[0]; + else + out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; + } + + for (i = 0; i < num_out_bus_fmts; i++) { + ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state, + conn_state, out_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + kfree(out_bus_fmts); + + return ret; +} + +static void +drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge, + struct drm_connector *conn, + struct drm_atomic_state *state) +{ + struct drm_bridge_state *bridge_state, *next_bridge_state; + struct drm_bridge *next_bridge; + u32 output_flags; + + bridge_state = drm_atomic_get_new_bridge_state(state, bridge); + next_bridge = drm_bridge_get_next_bridge(bridge); + + /* + * Let's try to apply the most common case here, that is, propagate + * display_info flags for the last bridge, and propagate the input + * flags of the next bridge element to the output end of the current + * bridge when the bridge is not the last one. + * There are exceptions to this rule, like when signal inversion is + * happening at the board level, but that's something drivers can deal + * with from their &drm_bridge_funcs.atomic_check() implementation by + * simply overriding the flags value we've set here. + */ + if (!next_bridge) { + output_flags = conn->display_info.bus_flags; + } else { + next_bridge_state = drm_atomic_get_new_bridge_state(state, + next_bridge); + output_flags = next_bridge_state->input_bus_cfg.flags; + } + + bridge_state->output_bus_cfg.flags = output_flags; + + /* + * Propage the output flags to the input end of the bridge. Again, it's + * not necessarily what all bridges want, but that's what most of them + * do, and by doing that by default we avoid forcing drivers to + * duplicate the "dummy propagation" logic. + */ + bridge_state->input_bus_cfg.flags = output_flags; +} + /** * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain * @bridge: bridge control structure * @crtc_state: new CRTC state * @conn_state: new connector state * - * Calls &drm_bridge_funcs.atomic_check() (falls back on + * First trigger a bus format negotiation before calling + * &drm_bridge_funcs.atomic_check() (falls back on * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, * starting from the last bridge to the first. These are called before calling * &drm_encoder_helper_funcs.atomic_check() @@ -689,12 +937,29 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct drm_connector *conn = conn_state->connector; struct drm_encoder *encoder = bridge->encoder; struct drm_bridge *iter; + int ret; + + ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, + conn_state); + if (ret) + return ret; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; + /* + * Bus flags are propagated by default. If a bridge needs to + * tweak the input bus flags for any reason, it should happen + * in its &drm_bridge_funcs.atomic_check() implementation such + * that preceding bridges in the chain can propagate the new + * bus flags. + */ + drm_atomic_bridge_propagate_bus_flags(iter, conn, + crtc_state->state); + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); if (ret) return ret; diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index ae0595c70132..46e15526b087 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -35,6 +35,38 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; +/** + * struct drm_bus_cfg - bus configuration + * + * This structure stores the configuration of a physical bus between two + * components in an output pipeline, usually between two bridges, an encoder + * and a bridge, or a bridge and a connector. + * + * The bus configuration is stored in &drm_bridge_state separately for the + * input and output buses, as seen from the point of view of each bridge. The + * bus configuration of a bridge output is usually identical to the + * configuration of the next bridge's input, but may differ if the signals are + * modified between the two bridges, for instance by an inverter on the board. + * The input and output configurations of a bridge may differ if the bridge + * modifies the signals internally, for instance by performing format + * conversion, or modifying signals polarities. + */ +struct drm_bus_cfg { + /** + * @format: format used on this bus (one of the MEDIA_BUS_FMT_* format) + * + * This field should not be directly modified by drivers + * (&drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus + * format negotiation). + */ + u32 format; + + /** + * @flags: DRM_BUS_* flags used on this bus + */ + u32 flags; +}; + /** * struct drm_bridge_state - Atomic bridge state object * @base: inherit from &drm_private_state @@ -44,6 +76,16 @@ struct drm_bridge_state { struct drm_private_state base; struct drm_bridge *bridge; + + /** + * @input_bus_cfg: input bus configuration + */ + struct drm_bus_cfg input_bus_cfg; + + /** + * @output_bus_cfg: input bus configuration + */ + struct drm_bus_cfg output_bus_cfg; }; static inline struct drm_bridge_state * @@ -387,6 +429,72 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); + /** + * @atomic_get_output_bus_fmts: + * + * Return the supported bus formats on the output end of a bridge. + * The returned array must be allocated with kmalloc() and will be + * freed by the caller. If the allocation fails, NULL should be + * returned. num_output_fmts must be set to the returned array size. + * Formats listed in the returned array should be listed in decreasing + * preference order (the core will try all formats until it finds one + * that works). + * + * This method is only called on the last element of the bridge chain + * as part of the bus format negotiation process that happens in + * &drm_atomic_bridge_chain_select_bus_fmts(). + * This method is optional. When not implemented, the core will + * fall back to &drm_connector.display_info.bus_formats[0] if + * &drm_connector.display_info.num_bus_formats > 0, + * or to MEDIA_BUS_FMT_FIXED otherwise. + */ + u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts); + + /** + * @atomic_get_input_bus_fmts: + * + * Return the supported bus formats on the input end of a bridge for + * a specific output bus format. + * + * The returned array must be allocated with kmalloc() and will be + * freed by the caller. If the allocation fails, NULL should be + * returned. num_output_fmts must be set to the returned array size. + * Formats listed in the returned array should be listed in decreasing + * preference order (the core will try all formats until it finds one + * that works). When the format is not supported NULL should be + * returned and *num_output_fmts should be set to 0. + * + * This method is called on all elements of the bridge chain as part of + * the bus format negotiation process that happens in + * &drm_atomic_bridge_chain_select_bus_fmts(). + * This method is optional. When not implemented, the core will bypass + * bus format negotiation on this element of the bridge without + * failing, and the previous element in the chain will be passed + * MEDIA_BUS_FMT_FIXED as its output bus format. + * + * Bridge drivers that need to support being linked to bridges that are + * not supporting bus format negotiation should handle the + * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a + * sensible default value or extracting this information from somewhere + * else (FW property, &drm_display_mode, &drm_display_info, ...) + * + * Note: Even if input format selection on the first bridge has no + * impact on the negotiation process (bus format negotiation stops once + * we reach the first element of the chain), drivers are expected to + * return accurate input formats as the input format may be used to + * configure the CRTC output appropriately. + */ + u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts); + /** * @atomic_check: * @@ -401,6 +509,14 @@ struct drm_bridge_funcs { * called when &drm_bridge_funcs.atomic_check() is implemented, so only * one of them should be provided. * + * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or + * &drm_bridge_state.output_bus_cfg.flags it should should happen in + * this function. By default the &drm_bridge_state.output_bus_cfg.flags + * field is set to the next bridge + * &drm_bridge_state.input_bus_cfg.flags value or + * &drm_connector.display_info.bus_flags if the bridge is the last + * element in the chain. + * * RETURNS: * zero if the check passed, a negative error code otherwise. */ @@ -588,6 +704,14 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts); + void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, struct drm_bridge_state *state); void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, -- cgit v1.2.3 From b18398c16e176513502f962b642f89225039ef1f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 12:30:31 +0100 Subject: drm/bridge: Fix a NULL pointer dereference in drm_atomic_bridge_chain_check() drm_atomic_bridge_chain_check() callers can pass a NULL bridge. Let's bail out before dereferencing the bridge pointer when that happens. Reported-by: Chris Wilson Fixes: b86d895524ab ("drm/bridge: Add an ->atomic_check() hook") Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20200107113031.435604-1-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (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 37400607e9b7..32d43bfeeca1 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -938,15 +938,19 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_connector_state *conn_state) { struct drm_connector *conn = conn_state->connector; - struct drm_encoder *encoder = bridge->encoder; + struct drm_encoder *encoder; struct drm_bridge *iter; int ret; + if (!bridge) + return 0; + ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, conn_state); if (ret) return ret; + encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; -- cgit v1.2.3 From 6ae1a4bbe1138e883c34ea78ef29986d9f420bd7 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:03 +0100 Subject: Revert "drm/bridge: Fix a NULL pointer dereference in drm_atomic_bridge_chain_check()" This reverts commit b18398c16e17 ("drm/bridge: Fix a NULL pointer dereference in drm_atomic_bridge_chain_check()"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-2-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 6 +----- 1 file changed, 1 insertion(+), 5 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 32d43bfeeca1..37400607e9b7 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -938,19 +938,15 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_connector_state *conn_state) { struct drm_connector *conn = conn_state->connector; - struct drm_encoder *encoder; + struct drm_encoder *encoder = bridge->encoder; struct drm_bridge *iter; int ret; - if (!bridge) - return 0; - ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, conn_state); if (ret) return ret; - encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; -- cgit v1.2.3 From 3dfbf2d3d05eccb0d4ffb4f30467519e601a5db6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:04 +0100 Subject: Revert "drm/bridge: Add the necessary bits to support bus format negotiation" This reverts commit e351e4d5eaec ("drm/bridge: Add the necessary bits to support bus format negotiation"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-3-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_bridge.c | 267 +------------------------------------------ include/drm/drm_bridge.h | 124 -------------------- 2 files changed, 1 insertion(+), 390 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 37400607e9b7..8e4b799150b0 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -671,261 +671,13 @@ static int drm_atomic_bridge_check(struct drm_bridge *bridge, return 0; } -/** - * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to - * the input end of a bridge - * @bridge: bridge control structure - * @bridge_state: new bridge state - * @crtc_state: new CRTC state - * @conn_state: new connector state - * @output_fmt: tested output bus format - * @num_input_fmts: will contain the size of the returned array - * - * This helper is a pluggable implementation of the - * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't - * modify the bus configuration between their input and their output. It - * returns an array of input formats with a single element set to @output_fmt. - * - * RETURNS: - * a valid format array of size @num_input_fmts, or NULL if the allocation - * failed - */ -u32 * -drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts) -{ - u32 *input_fmts; - - input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); - if (!input_fmts) { - *num_input_fmts = 0; - return NULL; - } - - *num_input_fmts = 1; - input_fmts[0] = output_fmt; - return input_fmts; -} -EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt); - -static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, - struct drm_bridge *cur_bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 out_bus_fmt) -{ - struct drm_bridge_state *cur_state; - unsigned int num_in_bus_fmts, i; - struct drm_bridge *prev_bridge; - u32 *in_bus_fmts; - int ret; - - prev_bridge = drm_bridge_get_prev_bridge(cur_bridge); - cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, - cur_bridge); - if (WARN_ON(!cur_state)) - return -EINVAL; - - /* - * If bus format negotiation is not supported by this bridge, let's - * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and - * hope that it can handle this situation gracefully (by providing - * appropriate default values). - */ - if (!cur_bridge->funcs->atomic_get_input_bus_fmts) { - if (cur_bridge != first_bridge) { - ret = select_bus_fmt_recursive(first_bridge, - prev_bridge, crtc_state, - conn_state, - MEDIA_BUS_FMT_FIXED); - if (ret) - return ret; - } - - cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; - cur_state->output_bus_cfg.format = out_bus_fmt; - return 0; - } - - in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge, - cur_state, - crtc_state, - conn_state, - out_bus_fmt, - &num_in_bus_fmts); - if (!num_in_bus_fmts) - return -ENOTSUPP; - else if (!in_bus_fmts) - return -ENOMEM; - - if (first_bridge == cur_bridge) { - cur_state->input_bus_cfg.format = in_bus_fmts[0]; - cur_state->output_bus_cfg.format = out_bus_fmt; - kfree(in_bus_fmts); - return 0; - } - - for (i = 0; i < num_in_bus_fmts; i++) { - ret = select_bus_fmt_recursive(first_bridge, prev_bridge, - crtc_state, conn_state, - in_bus_fmts[i]); - if (ret != -ENOTSUPP) - break; - } - - if (!ret) { - cur_state->input_bus_cfg.format = in_bus_fmts[i]; - cur_state->output_bus_cfg.format = out_bus_fmt; - } - - kfree(in_bus_fmts); - return ret; -} - -/* - * This function is called by &drm_atomic_bridge_chain_check() just before - * calling &drm_bridge_funcs.atomic_check() on all elements of the chain. - * It performs bus format negotiation between bridge elements. The negotiation - * happens in reverse order, starting from the last element in the chain up to - * @bridge. - * - * Negotiation starts by retrieving supported output bus formats on the last - * bridge element and testing them one by one. The test is recursive, meaning - * that for each tested output format, the whole chain will be walked backward, - * and each element will have to choose an input bus format that can be - * transcoded to the requested output format. When a bridge element does not - * support transcoding into a specific output format -ENOTSUPP is returned and - * the next bridge element will have to try a different format. If none of the - * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail. - * - * This implementation is relying on - * &drm_bridge_funcs.atomic_get_output_bus_fmts() and - * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported - * input/output formats. - * - * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by - * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts() - * tries a single format: &drm_connector.display_info.bus_formats[0] if - * available, MEDIA_BUS_FMT_FIXED otherwise. - * - * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented, - * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the - * bridge element that lacks this hook and asks the previous element in the - * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what - * to do in that case (fail if they want to enforce bus format negotiation, or - * provide a reasonable default if they need to support pipelines where not - * all elements support bus format negotiation). - */ -static int -drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_connector *conn = conn_state->connector; - struct drm_encoder *encoder = bridge->encoder; - struct drm_bridge_state *last_bridge_state; - unsigned int i, num_out_bus_fmts; - struct drm_bridge *last_bridge; - u32 *out_bus_fmts; - int ret = 0; - - last_bridge = list_last_entry(&encoder->bridge_chain, - struct drm_bridge, chain_node); - last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, - last_bridge); - if (WARN_ON(!last_bridge_state)) - return -EINVAL; - - if (last_bridge->funcs->atomic_get_output_bus_fmts) { - const struct drm_bridge_funcs *funcs = last_bridge->funcs; - - out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge, - last_bridge_state, - crtc_state, - conn_state, - &num_out_bus_fmts); - if (!num_out_bus_fmts) - return -ENOTSUPP; - else if (!out_bus_fmts) - return -ENOMEM; - } else { - num_out_bus_fmts = 1; - out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL); - if (!out_bus_fmts) - return -ENOMEM; - - if (conn->display_info.num_bus_formats && - conn->display_info.bus_formats) - out_bus_fmts[0] = conn->display_info.bus_formats[0]; - else - out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; - } - - for (i = 0; i < num_out_bus_fmts; i++) { - ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state, - conn_state, out_bus_fmts[i]); - if (ret != -ENOTSUPP) - break; - } - - kfree(out_bus_fmts); - - return ret; -} - -static void -drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge, - struct drm_connector *conn, - struct drm_atomic_state *state) -{ - struct drm_bridge_state *bridge_state, *next_bridge_state; - struct drm_bridge *next_bridge; - u32 output_flags; - - bridge_state = drm_atomic_get_new_bridge_state(state, bridge); - next_bridge = drm_bridge_get_next_bridge(bridge); - - /* - * Let's try to apply the most common case here, that is, propagate - * display_info flags for the last bridge, and propagate the input - * flags of the next bridge element to the output end of the current - * bridge when the bridge is not the last one. - * There are exceptions to this rule, like when signal inversion is - * happening at the board level, but that's something drivers can deal - * with from their &drm_bridge_funcs.atomic_check() implementation by - * simply overriding the flags value we've set here. - */ - if (!next_bridge) { - output_flags = conn->display_info.bus_flags; - } else { - next_bridge_state = drm_atomic_get_new_bridge_state(state, - next_bridge); - output_flags = next_bridge_state->input_bus_cfg.flags; - } - - bridge_state->output_bus_cfg.flags = output_flags; - - /* - * Propage the output flags to the input end of the bridge. Again, it's - * not necessarily what all bridges want, but that's what most of them - * do, and by doing that by default we avoid forcing drivers to - * duplicate the "dummy propagation" logic. - */ - bridge_state->input_bus_cfg.flags = output_flags; -} - /** * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain * @bridge: bridge control structure * @crtc_state: new CRTC state * @conn_state: new connector state * - * First trigger a bus format negotiation before calling - * &drm_bridge_funcs.atomic_check() (falls back on + * Calls &drm_bridge_funcs.atomic_check() (falls back on * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, * starting from the last bridge to the first. These are called before calling * &drm_encoder_helper_funcs.atomic_check() @@ -937,29 +689,12 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct drm_connector *conn = conn_state->connector; struct drm_encoder *encoder = bridge->encoder; struct drm_bridge *iter; - int ret; - - ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, - conn_state); - if (ret) - return ret; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; - /* - * Bus flags are propagated by default. If a bridge needs to - * tweak the input bus flags for any reason, it should happen - * in its &drm_bridge_funcs.atomic_check() implementation such - * that preceding bridges in the chain can propagate the new - * bus flags. - */ - drm_atomic_bridge_propagate_bus_flags(iter, conn, - crtc_state->state); - ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); if (ret) return ret; diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 46e15526b087..ae0595c70132 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -35,38 +35,6 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; -/** - * struct drm_bus_cfg - bus configuration - * - * This structure stores the configuration of a physical bus between two - * components in an output pipeline, usually between two bridges, an encoder - * and a bridge, or a bridge and a connector. - * - * The bus configuration is stored in &drm_bridge_state separately for the - * input and output buses, as seen from the point of view of each bridge. The - * bus configuration of a bridge output is usually identical to the - * configuration of the next bridge's input, but may differ if the signals are - * modified between the two bridges, for instance by an inverter on the board. - * The input and output configurations of a bridge may differ if the bridge - * modifies the signals internally, for instance by performing format - * conversion, or modifying signals polarities. - */ -struct drm_bus_cfg { - /** - * @format: format used on this bus (one of the MEDIA_BUS_FMT_* format) - * - * This field should not be directly modified by drivers - * (&drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus - * format negotiation). - */ - u32 format; - - /** - * @flags: DRM_BUS_* flags used on this bus - */ - u32 flags; -}; - /** * struct drm_bridge_state - Atomic bridge state object * @base: inherit from &drm_private_state @@ -76,16 +44,6 @@ struct drm_bridge_state { struct drm_private_state base; struct drm_bridge *bridge; - - /** - * @input_bus_cfg: input bus configuration - */ - struct drm_bus_cfg input_bus_cfg; - - /** - * @output_bus_cfg: input bus configuration - */ - struct drm_bus_cfg output_bus_cfg; }; static inline struct drm_bridge_state * @@ -429,72 +387,6 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); - /** - * @atomic_get_output_bus_fmts: - * - * Return the supported bus formats on the output end of a bridge. - * The returned array must be allocated with kmalloc() and will be - * freed by the caller. If the allocation fails, NULL should be - * returned. num_output_fmts must be set to the returned array size. - * Formats listed in the returned array should be listed in decreasing - * preference order (the core will try all formats until it finds one - * that works). - * - * This method is only called on the last element of the bridge chain - * as part of the bus format negotiation process that happens in - * &drm_atomic_bridge_chain_select_bus_fmts(). - * This method is optional. When not implemented, the core will - * fall back to &drm_connector.display_info.bus_formats[0] if - * &drm_connector.display_info.num_bus_formats > 0, - * or to MEDIA_BUS_FMT_FIXED otherwise. - */ - u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - unsigned int *num_output_fmts); - - /** - * @atomic_get_input_bus_fmts: - * - * Return the supported bus formats on the input end of a bridge for - * a specific output bus format. - * - * The returned array must be allocated with kmalloc() and will be - * freed by the caller. If the allocation fails, NULL should be - * returned. num_output_fmts must be set to the returned array size. - * Formats listed in the returned array should be listed in decreasing - * preference order (the core will try all formats until it finds one - * that works). When the format is not supported NULL should be - * returned and *num_output_fmts should be set to 0. - * - * This method is called on all elements of the bridge chain as part of - * the bus format negotiation process that happens in - * &drm_atomic_bridge_chain_select_bus_fmts(). - * This method is optional. When not implemented, the core will bypass - * bus format negotiation on this element of the bridge without - * failing, and the previous element in the chain will be passed - * MEDIA_BUS_FMT_FIXED as its output bus format. - * - * Bridge drivers that need to support being linked to bridges that are - * not supporting bus format negotiation should handle the - * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a - * sensible default value or extracting this information from somewhere - * else (FW property, &drm_display_mode, &drm_display_info, ...) - * - * Note: Even if input format selection on the first bridge has no - * impact on the negotiation process (bus format negotiation stops once - * we reach the first element of the chain), drivers are expected to - * return accurate input formats as the input format may be used to - * configure the CRTC output appropriately. - */ - u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts); - /** * @atomic_check: * @@ -509,14 +401,6 @@ struct drm_bridge_funcs { * called when &drm_bridge_funcs.atomic_check() is implemented, so only * one of them should be provided. * - * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or - * &drm_bridge_state.output_bus_cfg.flags it should should happen in - * this function. By default the &drm_bridge_state.output_bus_cfg.flags - * field is set to the next bridge - * &drm_bridge_state.input_bus_cfg.flags value or - * &drm_connector.display_info.bus_flags if the bridge is the last - * element in the chain. - * * RETURNS: * zero if the check passed, a negative error code otherwise. */ @@ -704,14 +588,6 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); -u32 * -drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts); - void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, struct drm_bridge_state *state); void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, -- cgit v1.2.3 From 8de679abc8ae81463d3fec495a21a6ca0a65bade Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:05 +0100 Subject: Revert "drm/bridge: Add an ->atomic_check() hook" This reverts commit b86d895524ab ("drm/bridge: Add an ->atomic_check() hook"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-4-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_atomic_helper.c | 12 +++---- drivers/gpu/drm/drm_bridge.c | 62 ------------------------------------- include/drm/drm_bridge.h | 29 +---------------- 3 files changed, 7 insertions(+), 96 deletions(-) (limited to 'drivers/gpu/drm/drm_bridge.c') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index afe14f72a824..ad8eae98d9e8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) funcs = encoder->helper_private; bridge = drm_bridge_chain_get_first_bridge(encoder); - ret = drm_atomic_bridge_chain_check(bridge, - new_crtc_state, - new_conn_state); - if (ret) { - DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); - return ret; + ret = drm_bridge_chain_mode_fixup(bridge, + &new_crtc_state->mode, + &new_crtc_state->adjusted_mode); + if (!ret) { + DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); + return -EINVAL; } if (funcs && funcs->atomic_check) { diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 8e4b799150b0..872e159fcb42 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -645,68 +645,6 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); -static int drm_atomic_bridge_check(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - if (bridge->funcs->atomic_check) { - struct drm_bridge_state *bridge_state; - int ret; - - bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, - bridge); - if (WARN_ON(!bridge_state)) - return -EINVAL; - - ret = bridge->funcs->atomic_check(bridge, bridge_state, - crtc_state, conn_state); - if (ret) - return ret; - } else if (bridge->funcs->mode_fixup) { - if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode, - &crtc_state->adjusted_mode)) - return -EINVAL; - } - - return 0; -} - -/** - * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain - * @bridge: bridge control structure - * @crtc_state: new CRTC state - * @conn_state: new connector state - * - * Calls &drm_bridge_funcs.atomic_check() (falls back on - * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, - * starting from the last bridge to the first. These are called before calling - * &drm_encoder_helper_funcs.atomic_check() - * - * RETURNS: - * 0 on success, a negative error code on failure - */ -int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_encoder *encoder = bridge->encoder; - struct drm_bridge *iter; - - list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - int ret; - - ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); - if (ret) - return ret; - - if (iter == bridge) - break; - } - - return 0; -} -EXPORT_SYMBOL(drm_atomic_bridge_chain_check); - /** * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its * default diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index ae0595c70132..52d3ed150618 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -128,9 +128,7 @@ struct drm_bridge_funcs { * this function passes all other callbacks must succeed for this * configuration. * - * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup() - * is not called when &drm_bridge_funcs.atomic_check() is implemented, - * so only one of them should be provided. + * The @mode_fixup callback is optional. * * NOTE: * @@ -387,28 +385,6 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); - /** - * @atomic_check: - * - * This method is responsible for checking bridge state correctness. - * It can also check the state of the surrounding components in chain - * to make sure the whole pipeline can work properly. - * - * &drm_bridge_funcs.atomic_check() hooks are called in reverse - * order (from the last to the first bridge). - * - * This method is optional. &drm_bridge_funcs.mode_fixup() is not - * called when &drm_bridge_funcs.atomic_check() is implemented, so only - * one of them should be provided. - * - * RETURNS: - * zero if the check passed, a negative error code otherwise. - */ - int (*atomic_check)(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state); - /** * @atomic_reset: * @@ -576,9 +552,6 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); void drm_bridge_chain_enable(struct drm_bridge *bridge); -int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state); void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, struct drm_atomic_state *state); void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, -- cgit v1.2.3 From b470743bedbacc7552763c0d973abe958aa0ff87 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:06 +0100 Subject: Revert "drm/bridge: Patch atomic hooks to take a drm_bridge_state" This reverts commit f7619a58ef92 ("drm/bridge: Patch atomic hooks to take a drm_bridge_state"). Commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") introduced a circular dependency between drm.ko and drm_kms_helper.ko which uncovered a misdesign in how the whole thing was implemented. Let's revert all patches depending on the bridge_state infrastructure for now. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-5-boris.brezillon@collabora.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 41 ++++++--------- drivers/gpu/drm/drm_bridge.c | 61 +++++----------------- drivers/gpu/drm/rcar-du/rcar_lvds.c | 8 ++- include/drm/drm_bridge.h | 8 +-- 4 files changed, 36 insertions(+), 82 deletions(-) (limited to 'drivers/gpu/drm/drm_bridge.c') diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 6fab71985cd4..6effe532f820 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1289,21 +1289,19 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, return conn_state->crtc; } -static void -analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); /* Don't touch the panel if we're coming back from PSR */ if (old_crtc_state && old_crtc_state->self_refresh_active) return; @@ -1368,22 +1366,20 @@ out_dp_clk_pre: return ret; } -static void -analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int timeout_loop = 0; int ret; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) return; - old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); + old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); /* Not a full enable, just disable PSR and continue */ if (old_crtc_state && old_crtc_state->self_refresh_active) { ret = analogix_dp_disable_psr(dp); @@ -1444,20 +1440,18 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) dp->dpms_mode = DRM_MODE_DPMS_OFF; } -static void -analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) goto out; - new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); if (!new_crtc_state) goto out; @@ -1469,21 +1463,20 @@ out: analogix_dp_bridge_disable(bridge); } -static void -analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) +static +void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct drm_atomic_state *old_state = old_bridge_state->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; int ret; - crtc = analogix_dp_get_new_crtc(dp, old_state); + crtc = analogix_dp_get_new_crtc(dp, state); if (!crtc) return; - new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); if (!new_crtc_state || !new_crtc_state->self_refresh_active) return; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 872e159fcb42..a213c9042f2c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -501,19 +501,10 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_disable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - iter); - if (WARN_ON(!old_bridge_state)) - return; - - iter->funcs->atomic_disable(iter, old_bridge_state); - } else if (iter->funcs->disable) { + if (iter->funcs->atomic_disable) + iter->funcs->atomic_disable(iter, old_state); + else if (iter->funcs->disable) iter->funcs->disable(iter); - } if (iter == bridge) break; @@ -544,20 +535,10 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_post_disable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - bridge); - if (WARN_ON(!old_bridge_state)) - return; - - bridge->funcs->atomic_post_disable(bridge, - old_bridge_state); - } else if (bridge->funcs->post_disable) { + if (bridge->funcs->atomic_post_disable) + bridge->funcs->atomic_post_disable(bridge, old_state); + else if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); - } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); @@ -586,19 +567,10 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_pre_enable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - iter); - if (WARN_ON(!old_bridge_state)) - return; - - iter->funcs->atomic_pre_enable(iter, old_bridge_state); - } else if (iter->funcs->pre_enable) { + if (iter->funcs->atomic_pre_enable) + iter->funcs->atomic_pre_enable(iter, old_state); + else if (iter->funcs->pre_enable) iter->funcs->pre_enable(iter); - } if (iter == bridge) break; @@ -628,19 +600,10 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_enable) { - struct drm_bridge_state *old_bridge_state; - - old_bridge_state = - drm_atomic_get_old_bridge_state(old_state, - bridge); - if (WARN_ON(!old_bridge_state)) - return; - - bridge->funcs->atomic_enable(bridge, old_bridge_state); - } else if (bridge->funcs->enable) { + if (bridge->funcs->atomic_enable) + bridge->funcs->atomic_enable(bridge, old_state); + else if (bridge->funcs->enable) bridge->funcs->enable(bridge); - } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 961519ce6634..8ffa4fbbdeb3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -590,9 +590,8 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge, } static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { - struct drm_atomic_state *state = old_bridge_state->base.state; struct drm_connector *connector; struct drm_crtc *crtc; @@ -604,7 +603,7 @@ static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, } static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state) + struct drm_atomic_state *state) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); @@ -619,8 +618,7 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, /* Disable the companion LVDS encoder in dual-link mode. */ if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - lvds->companion->funcs->atomic_disable(lvds->companion, - old_bridge_state); + lvds->companion->funcs->atomic_disable(lvds->companion, state); clk_disable_unprepare(lvds->clocks.mod); } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 52d3ed150618..fc7c71f4de55 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -282,7 +282,7 @@ struct drm_bridge_funcs { * The @atomic_pre_enable callback is optional. */ void (*atomic_pre_enable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_enable: @@ -307,7 +307,7 @@ struct drm_bridge_funcs { * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_disable: * @@ -330,7 +330,7 @@ struct drm_bridge_funcs { * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_post_disable: @@ -356,7 +356,7 @@ struct drm_bridge_funcs { * The @atomic_post_disable callback is optional. */ void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_bridge_state *old_bridge_state); + struct drm_atomic_state *old_state); /** * @atomic_duplicate_state: -- cgit v1.2.3 From 09912635230374bdca2aca620d183f1834b3140c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jan 2020 19:58:07 +0100 Subject: Revert "drm/bridge: Add a drm_bridge_state object" This reverts commit 6ed7e9625fa6 ("drm/bridge: Add a drm_bridge_state object") which introduced a circular dependency between drm.ko and drm_kms_helper.ko. Looks like the helper/core split is not appropriate and fixing that is not simple. Signed-off-by: Boris Brezillon Acked-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20200107185807.606999-6-boris.brezillon@collabora.com --- drivers/gpu/drm/drm_atomic.c | 39 ---------- drivers/gpu/drm/drm_atomic_helper.c | 20 ------ drivers/gpu/drm/drm_bridge.c | 139 ++---------------------------------- include/drm/drm_atomic.h | 3 - include/drm/drm_bridge.h | 114 ----------------------------- 5 files changed, 6 insertions(+), 309 deletions(-) (limited to 'drivers/gpu/drm/drm_bridge.c') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index bf1b9c37d515..d33691512a8e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -1018,44 +1017,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, connector->funcs->atomic_print_state(p, state); } -/** - * drm_atomic_add_encoder_bridges - add bridges attached to an encoder - * @state: atomic state - * @encoder: DRM encoder - * - * This function adds all bridges attached to @encoder. This is needed to add - * bridge states to @state and make them available when - * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are - * called - * - * Returns: - * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK - * then the w/w mutex code has detected a deadlock and the entire atomic - * sequence must be restarted. All other errors are fatal. - */ -int -drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, - struct drm_encoder *encoder) -{ - struct drm_bridge_state *bridge_state; - struct drm_bridge *bridge; - - if (!encoder) - return 0; - - DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", - encoder->base.id, encoder->name, state); - - drm_for_each_bridge_in_chain(encoder, bridge) { - bridge_state = drm_atomic_get_bridge_state(state, bridge); - if (IS_ERR(bridge_state)) - return PTR_ERR(bridge_state); - } - - return 0; -} -EXPORT_SYMBOL(drm_atomic_add_encoder_bridges); - /** * drm_atomic_add_affected_connectors - add connectors for CRTC * @state: atomic state diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ad8eae98d9e8..4511c2e07bb9 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -730,26 +730,6 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; } - /* - * Iterate over all connectors again, and add all affected bridges to - * the state. - */ - for_each_oldnew_connector_in_state(state, connector, - old_connector_state, - new_connector_state, i) { - struct drm_encoder *encoder; - - encoder = old_connector_state->best_encoder; - ret = drm_atomic_add_encoder_bridges(state, encoder); - if (ret) - return ret; - - encoder = new_connector_state->best_encoder; - ret = drm_atomic_add_encoder_bridges(state, encoder); - if (ret) - return ret; - } - ret = mode_valid(state); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index a213c9042f2c..c2cf0c90fa26 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -90,74 +89,6 @@ void drm_bridge_remove(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_remove); -static struct drm_bridge_state * -drm_atomic_default_bridge_duplicate_state(struct drm_bridge *bridge) -{ - struct drm_bridge_state *new; - - if (WARN_ON(!bridge->base.state)) - return NULL; - - new = kzalloc(sizeof(*new), GFP_KERNEL); - if (new) - __drm_atomic_helper_bridge_duplicate_state(bridge, new); - - return new; -} - -static struct drm_private_state * -drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj) -{ - struct drm_bridge *bridge = drm_priv_to_bridge(obj); - struct drm_bridge_state *state; - - if (bridge->funcs->atomic_duplicate_state) - state = bridge->funcs->atomic_duplicate_state(bridge); - else - state = drm_atomic_default_bridge_duplicate_state(bridge); - - return state ? &state->base : NULL; -} - -static void -drm_atomic_default_bridge_destroy_state(struct drm_bridge *bridge, - struct drm_bridge_state *state) -{ - /* Just a simple kfree() for now */ - kfree(state); -} - -static void -drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj, - struct drm_private_state *s) -{ - struct drm_bridge_state *state = drm_priv_to_bridge_state(s); - struct drm_bridge *bridge = drm_priv_to_bridge(obj); - - if (bridge->funcs->atomic_destroy_state) - bridge->funcs->atomic_destroy_state(bridge, state); - else - drm_atomic_default_bridge_destroy_state(bridge, state); -} - -static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { - .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state, - .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, -}; - -static struct drm_bridge_state * -drm_atomic_default_bridge_reset(struct drm_bridge *bridge) -{ - struct drm_bridge_state *bridge_state; - - bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL); - if (!bridge_state) - return ERR_PTR(-ENOMEM); - - __drm_atomic_helper_bridge_reset(bridge, bridge_state); - return bridge_state; -} - /** * drm_bridge_attach - attach the bridge to an encoder's chain * @@ -183,7 +114,6 @@ drm_atomic_default_bridge_reset(struct drm_bridge *bridge) int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous) { - struct drm_bridge_state *state; int ret; if (!encoder || !bridge) @@ -205,35 +135,15 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, if (bridge->funcs->attach) { ret = bridge->funcs->attach(bridge); - if (ret < 0) - goto err_reset_bridge; - } - - if (bridge->funcs->atomic_reset) - state = bridge->funcs->atomic_reset(bridge); - else - state = drm_atomic_default_bridge_reset(bridge); - - if (IS_ERR(state)) { - ret = PTR_ERR(state); - goto err_detach_bridge; + if (ret < 0) { + list_del(&bridge->chain_node); + bridge->dev = NULL; + bridge->encoder = NULL; + return ret; + } } - drm_atomic_private_obj_init(bridge->dev, &bridge->base, - &state->base, - &drm_bridge_priv_state_funcs); - return 0; - -err_detach_bridge: - if (bridge->funcs->detach) - bridge->funcs->detach(bridge); - -err_reset_bridge: - bridge->dev = NULL; - bridge->encoder = NULL; - list_del(&bridge->chain_node); - return ret; } EXPORT_SYMBOL(drm_bridge_attach); @@ -245,8 +155,6 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (WARN_ON(!bridge->dev)) return; - drm_atomic_private_obj_fini(&bridge->base); - if (bridge->funcs->detach) bridge->funcs->detach(bridge); @@ -608,41 +516,6 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); -/** - * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its - * default - * @bridge: the bridge this state is refers to - * @state: bridge state to initialize - * - * Initialize the bridge state to default values. This is meant to be* called - * by the bridge &drm_plane_funcs.reset hook for bridges that subclass the - * bridge state. - */ -void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, - struct drm_bridge_state *state) -{ - memset(state, 0, sizeof(*state)); - state->bridge = bridge; -} -EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset); - -/** - * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state - * @bridge: bridge object - * @state: atomic bridge state - * - * Copies atomic state from a bridge's current state and resets inferred values. - * This is useful for drivers that subclass the bridge state. - */ -void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, - struct drm_bridge_state *state) -{ - __drm_atomic_helper_private_obj_duplicate_state(&bridge->base, - &state->base); - state->bridge = bridge; -} -EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state); - #ifdef CONFIG_OF /** * of_drm_find_bridge - find the bridge corresponding to the device node in diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index ccce65e14917..951dfb15c27b 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -669,9 +669,6 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state, return plane->state; } -int __must_check -drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, - struct drm_encoder *encoder); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index fc7c71f4de55..694e153a7531 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -25,8 +25,6 @@ #include #include - -#include #include #include #include @@ -35,23 +33,6 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; -/** - * struct drm_bridge_state - Atomic bridge state object - * @base: inherit from &drm_private_state - * @bridge: the bridge this state refers to - */ -struct drm_bridge_state { - struct drm_private_state base; - - struct drm_bridge *bridge; -}; - -static inline struct drm_bridge_state * -drm_priv_to_bridge_state(struct drm_private_state *priv) -{ - return container_of(priv, struct drm_bridge_state, base); -} - /** * struct drm_bridge_funcs - drm_bridge control functions */ @@ -357,49 +338,6 @@ struct drm_bridge_funcs { */ void (*atomic_post_disable)(struct drm_bridge *bridge, struct drm_atomic_state *old_state); - - /** - * @atomic_duplicate_state: - * - * Duplicate the current bridge state object (which is guaranteed to be - * non-NULL). - * - * The atomic_duplicate_state() is optional. When not implemented the - * core allocates a drm_bridge_state object and calls - * &__drm_atomic_helper_bridge_duplicate_state() to initialize it. - * - * RETURNS: - * A valid drm_bridge_state object or NULL if the allocation fails. - */ - struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge); - - /** - * @atomic_destroy_state: - * - * Destroy a bridge state object previously allocated by - * &drm_bridge_funcs.atomic_duplicate_state(). - * - * The atomic_destroy_state hook is optional. When not implemented the - * core calls kfree() on the state. - */ - void (*atomic_destroy_state)(struct drm_bridge *bridge, - struct drm_bridge_state *state); - - /** - * @atomic_reset: - * - * Reset the bridge to a predefined state (or retrieve its current - * state) and return a &drm_bridge_state object matching this state. - * This function is called at attach time. - * - * The atomic_reset hook is optional. When not implemented the core - * allocates a new state and calls &__drm_atomic_helper_bridge_reset(). - * - * RETURNS: - * A valid drm_bridge_state object in case of success, an ERR_PTR() - * giving the reason of the failure otherwise. - */ - struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge); }; /** @@ -442,8 +380,6 @@ struct drm_bridge_timings { * struct drm_bridge - central DRM bridge control structure */ struct drm_bridge { - /** @base: inherit from &drm_private_object */ - struct drm_private_obj base; /** @dev: DRM device this bridge belongs to */ struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ @@ -468,12 +404,6 @@ struct drm_bridge { void *driver_private; }; -static inline struct drm_bridge * -drm_priv_to_bridge(struct drm_private_obj *priv) -{ - return container_of(priv, struct drm_bridge, base); -} - void drm_bridge_add(struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); struct drm_bridge *of_drm_find_bridge(struct device_node *np); @@ -561,50 +491,6 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); -void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, - struct drm_bridge_state *state); -void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, - struct drm_bridge_state *new); - -static inline struct drm_bridge_state * -drm_atomic_get_bridge_state(struct drm_atomic_state *state, - struct drm_bridge *bridge) -{ - struct drm_private_state *obj_state; - - obj_state = drm_atomic_get_private_obj_state(state, &bridge->base); - if (IS_ERR(obj_state)) - return ERR_CAST(obj_state); - - return drm_priv_to_bridge_state(obj_state); -} - -static inline struct drm_bridge_state * -drm_atomic_get_old_bridge_state(struct drm_atomic_state *state, - struct drm_bridge *bridge) -{ - struct drm_private_state *obj_state; - - obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base); - if (!obj_state) - return NULL; - - return drm_priv_to_bridge_state(obj_state); -} - -static inline struct drm_bridge_state * -drm_atomic_get_new_bridge_state(struct drm_atomic_state *state, - struct drm_bridge *bridge) -{ - struct drm_private_state *obj_state; - - obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base); - if (!obj_state) - return NULL; - - return drm_priv_to_bridge_state(obj_state); -} - #ifdef CONFIG_DRM_PANEL_BRIDGE struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, -- cgit v1.2.3