The display-connector bridge is the last bridge in the chain on platforms using drm_bridge_connector, and is responsible for the physical connector interface.
Implement the atomic_sro_readout_state hook and wire up the default drm_atomic_helper_bridge_compare_state() as the compare hook. Reviewed-by: Maarten Lankhorst <[email protected]> Signed-off-by: Maxime Ripard <[email protected]> --- drivers/gpu/drm/bridge/display-connector.c | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index eb3412ec30a0..781684da1da4 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -15,5 +15,8 @@ #include <linux/workqueue.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic_state_readout.h> +#include <drm/drm_atomic_state_readout_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_edid.h> @@ -214,4 +217,68 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, } +/* + * Reconstruct the bridge bus configuration from the previous bridge's + * readout state and the connector's display_info. + * + * During normal atomic check, drm_atomic_bridge_chain_select_bus_fmts() + * and drm_atomic_bridge_propagate_bus_flags() walk the bridge chain to + * negotiate formats and propagate flags. During SRO readout, those + * functions do not run, so each bridge must reconstruct its own state. + * + * The SRO infrastructure traverses bridges from first to last, so the + * previous bridge's state is already available. The input bus + * configuration is taken from the previous bridge's output. The output + * bus format comes from the connector's display_info, since this bridge + * is the last in the chain and acts as a passthrough to the connector. + * Bus flags are also taken from display_info, matching the default + * propagation behavior of drm_atomic_bridge_propagate_bus_flags(). + */ +static int +display_connector_readout_state(struct drm_bridge *bridge, + struct drm_atomic_sro_state *state, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_display_info *di = &conn_state->connector->display_info; + struct drm_bridge *prev_bridge __free(drm_bridge_put) = + drm_bridge_get_prev_bridge(bridge); + + if (prev_bridge) { + struct drm_private_state *prev_priv_state = + drm_atomic_sro_get_private_obj_state(state, + &prev_bridge->base); + + if (prev_priv_state) { + struct drm_bridge_state *prev_bridge_state = + drm_priv_to_bridge_state(prev_priv_state); + + bridge_state->input_bus_cfg.format = + prev_bridge_state->output_bus_cfg.format; + bridge_state->input_bus_cfg.flags = + prev_bridge_state->output_bus_cfg.flags; + goto out_input; + } + } + + /* + * The previous bridge might not have readout support, so we + * can't treat a missing state as an error. + */ + bridge_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; + bridge_state->input_bus_cfg.flags = di->bus_flags; + +out_input: + + if (di->num_bus_formats && di->bus_formats) + bridge_state->output_bus_cfg.format = di->bus_formats[0]; + else + bridge_state->output_bus_cfg.format = MEDIA_BUS_FMT_FIXED; + + bridge_state->output_bus_cfg.flags = di->bus_flags; + + return 0; +} + static const struct drm_bridge_funcs display_connector_bridge_funcs = { .attach = display_connector_attach, @@ -226,4 +293,6 @@ static const struct drm_bridge_funcs display_connector_bridge_funcs = { .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_sro_readout_state = display_connector_readout_state, + .atomic_sro_compare_state = drm_atomic_helper_bridge_compare_state, }; -- 2.55.0
