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. Signed-off-by: Maxime Ripard <[email protected]> --- drivers/gpu/drm/bridge/display-connector.c | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index eb3412ec30a0..7f285b7c1e84 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -12,11 +12,14 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/workqueue.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic_sro.h> +#include <drm/drm_atomic_sro_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_edid.h> struct display_connector { struct drm_bridge bridge; @@ -211,10 +214,69 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, return prev_bridge->funcs->atomic_get_input_bus_fmts(prev_bridge, prev_bridge_state, crtc_state, conn_state, output_fmt, num_input_fmts); } +/* + * 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); + struct drm_bridge_state *prev_bridge_state; + + if (!prev_priv_state) + return -ENODEV; + + 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; + } else { + bridge_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED; + bridge_state->input_bus_cfg.flags = di->bus_flags; + } + + 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, .destroy = display_connector_destroy, .detect = display_connector_bridge_detect, .hpd_enable = display_connector_hpd_enable, @@ -223,10 +285,12 @@ static const struct drm_bridge_funcs display_connector_bridge_funcs = { .atomic_get_output_bus_fmts = display_connector_get_output_bus_fmts, .atomic_get_input_bus_fmts = display_connector_get_input_bus_fmts, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .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, }; static irqreturn_t display_connector_hpd_irq(int irq, void *arg) { struct display_connector *conn = arg; -- 2.55.0
