Add a callback to be called by the drivers when the drm_connector is created at the end of the drm_bridge chain. This allows bridges to perform additional setup, like setting up the HDMI connector properties. Note, for now only drm_bridge_connector uses this callback. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> --- drivers/gpu/drm/drm_bridge.c | 38 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_bridge_connector.c | 8 +++++++ include/drm/drm_bridge.h | 15 ++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 521a71c61b16..375982a02bcf 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -580,6 +580,44 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_bridge_chain_mode_set); +/** + * drm_bridge_chain_setup_connector - call all bridges to perform additional setup + * of the attached drm_connector + * @bridge: bridge control structure + * @connector: connector that is used at the end of the bridge chain + * + * Calls &drm_bridge_funcs.setup_connector for all the bridges in the encoder + * chain, starting from the first bridge to the last. If at least one bridge + * does not accept the connector the function returns the error code. + * + * Note: the bridge passed should be the one closest to the encoder. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_bridge_chain_setup_connector(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct drm_encoder *encoder; + int ret; + + if (!bridge) + return 0; + + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (!bridge->funcs->setup_connector) + continue; + + ret = bridge->funcs->setup_connector(bridge, connector); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL(drm_bridge_chain_setup_connector); + /** * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 982552c9f92c..a0d0d2cc72c7 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -402,6 +402,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, if (panel_bridge) drm_panel_bridge_set_orientation(connector, panel_bridge); + ret = drm_bridge_chain_setup_connector(drm_bridge_chain_get_first_bridge(encoder), + connector); + if (ret) { + drm_connector_cleanup(connector); + kfree(bridge_connector); + return ERR_PTR(ret); + } + return connector; } EXPORT_SYMBOL_GPL(drm_bridge_connector_init); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 3606e1a7f965..9806fce126f2 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -84,6 +84,19 @@ struct drm_bridge_funcs { */ void (*detach)(struct drm_bridge *bridge); + /** + * @setup_connector: + * + * Perform additional setup of the connector once it is created. + * + * The @setup_connector callback is optional. + * + * RETURNS: + * + * Zero on success, error code on failure. + */ + int (*setup_connector)(struct drm_bridge *bridge, struct drm_connector *connector); + /** * @mode_valid: * @@ -877,6 +890,8 @@ void drm_atomic_bridge_chain_pre_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); +int drm_bridge_chain_setup_connector(struct drm_bridge *bridge, + struct drm_connector *connector); u32 * drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, -- 2.39.2