[PATCH 08/60] drm/bridge: Extend bridge API to disable connector creation

Laurent Pinchart laurent.pinchart at ideasonboard.com
Thu Aug 8 14:25:25 UTC 2019


Hi Andrzej,

On Wed, Jul 17, 2019 at 08:39:47AM +0200, Andrzej Hajda wrote:
> On 07.07.2019 20:18, Laurent Pinchart wrote:
> > Most bridge drivers create a DRM connector to model the connector at the
> > output of the bridge. This model is historical and has worked pretty
> > well so far, but causes several issues:
> >
> > - It prevents supporting more complex display pipelines where DRM
> > connector operations are split over multiple components. For instance a
> > pipeline with a bridge connected to the DDC signals to read EDID data,
> > and another one connected to the HPD signal to detect connection and
> > disconnection, will not be possible to support through this model.
> >
> > - It requires every bridge driver to implement similar connector
> > handling code, resulting in code duplication.
> >
> > - It assumes that a bridge will either be wired to a connector or to
> > another bridge, but doesn't support bridges that can be used in both
> > positions very well (although there is some ad-hoc support for this in
> > the analogix_dp bridge driver).
> >
> > In order to solve these issues, ownership of the connector should be
> > moved to the display controller driver (where it can be implemented
> > using helpers provided by the core).
> >
> > Extend the bridge API to allow disabling connector creation in bridge
> > drivers as a first step towards the new model. The new create_connector
> > argument to the bridge .attach() operation tells the bridge driver
> > whether to create a connector. Set the argument to true unconditionally,
> > and modify all existing bridge drivers to return an error when connector
> > creation is not requested as they don't support this feature yet.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > ---
> >  drivers/gpu/drm/arc/arcpgu_hdmi.c                        | 2 +-
> >  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c         | 2 +-
> >  drivers/gpu/drm/bridge/adv7511/adv7511_drv.c             | 6 +++++-
> >  drivers/gpu/drm/bridge/analogix-anx78xx.c                | 6 +++++-
> >  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c       | 8 ++++++--
> >  drivers/gpu/drm/bridge/cdns-dsi.c                        | 6 ++++--
> >  drivers/gpu/drm/bridge/lvds-encoder.c                    | 4 ++--
> >  drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 6 +++++-
> >  drivers/gpu/drm/bridge/nxp-ptn3460.c                     | 6 +++++-
> >  drivers/gpu/drm/bridge/panel.c                           | 5 ++++-
> >  drivers/gpu/drm/bridge/parade-ps8622.c                   | 5 ++++-
> >  drivers/gpu/drm/bridge/sii902x.c                         | 6 +++++-
> >  drivers/gpu/drm/bridge/sil-sii8620.c                     | 2 +-
> >  drivers/gpu/drm/bridge/simple-bridge.c                   | 6 +++++-
> >  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c                | 8 ++++++--
> >  drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c            | 8 +++++---
> >  drivers/gpu/drm/bridge/tc358764.c                        | 5 ++++-
> >  drivers/gpu/drm/bridge/tc358767.c                        | 5 ++++-
> >  drivers/gpu/drm/bridge/thc63lvd1024.c                    | 5 +++--
> >  drivers/gpu/drm/bridge/ti-sn65dsi86.c                    | 5 ++++-
> >  drivers/gpu/drm/bridge/ti-tfp410.c                       | 5 ++++-
> >  drivers/gpu/drm/drm_bridge.c                             | 5 +++--
> >  drivers/gpu/drm/drm_simple_kms_helper.c                  | 2 +-
> >  drivers/gpu/drm/exynos/exynos_dp.c                       | 3 ++-
> >  drivers/gpu/drm/exynos/exynos_drm_dsi.c                  | 4 ++--
> >  drivers/gpu/drm/exynos/exynos_hdmi.c                     | 2 +-
> >  drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c                | 2 +-
> >  drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c             | 2 +-
> >  drivers/gpu/drm/i2c/tda998x_drv.c                        | 8 ++++++--
> >  drivers/gpu/drm/imx/imx-ldb.c                            | 2 +-
> >  drivers/gpu/drm/imx/parallel-display.c                   | 2 +-
> >  drivers/gpu/drm/mcde/mcde_dsi.c                          | 6 +++++-
> >  drivers/gpu/drm/mediatek/mtk_dpi.c                       | 2 +-
> >  drivers/gpu/drm/mediatek/mtk_dsi.c                       | 2 +-
> >  drivers/gpu/drm/mediatek/mtk_hdmi.c                      | 8 ++++++--
> >  drivers/gpu/drm/msm/dsi/dsi_manager.c                    | 4 ++--
> >  drivers/gpu/drm/msm/edp/edp_bridge.c                     | 2 +-
> >  drivers/gpu/drm/msm/hdmi/hdmi_bridge.c                   | 2 +-
> >  drivers/gpu/drm/omapdrm/omap_drv.c                       | 3 ++-
> >  drivers/gpu/drm/rcar-du/rcar_du_encoder.c                | 2 +-
> >  drivers/gpu/drm/rcar-du/rcar_lvds.c                      | 7 +++++--
> >  drivers/gpu/drm/rockchip/rockchip_lvds.c                 | 2 +-
> >  drivers/gpu/drm/rockchip/rockchip_rgb.c                  | 2 +-
> >  drivers/gpu/drm/sti/sti_dvo.c                            | 2 +-
> >  drivers/gpu/drm/sti/sti_hda.c                            | 2 +-
> >  drivers/gpu/drm/sti/sti_hdmi.c                           | 2 +-
> >  drivers/gpu/drm/stm/ltdc.c                               | 2 +-
> >  drivers/gpu/drm/sun4i/sun4i_lvds.c                       | 2 +-
> >  drivers/gpu/drm/sun4i/sun4i_rgb.c                        | 2 +-
> >  drivers/gpu/drm/tilcdc/tilcdc_external.c                 | 2 +-
> >  drivers/gpu/drm/vc4/vc4_dpi.c                            | 2 +-
> >  drivers/gpu/drm/vc4/vc4_dsi.c                            | 2 +-
> >  include/drm/drm_bridge.h                                 | 4 ++--
> >  53 files changed, 140 insertions(+), 67 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c
> > index 98aac743cc26..739f2358f1d5 100644
> > --- a/drivers/gpu/drm/arc/arcpgu_hdmi.c
> > +++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c
> > @@ -39,7 +39,7 @@ int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np)
> >  		return ret;
> >  
> >  	/* Link drm_bridge to encoder */
> > -	ret = drm_bridge_attach(encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, bridge, NULL, true);
> 
> Few suggestions:
> 
> 1. Maybe it would be more convenient to add flags argument instead of bool:
> 
> - code should be more readable: ret = drm_bridge_attach(encoder, bridge,
> NULL, DRM_BRIDGE_FLAG_NO_CONNECTOR)
> 
> - it can be easily expanded later with other flags, there at least two
> drivers which would benefit from DRM_BRIDGE_FLAG_NO_CHAINING flag.

Please note that I think this flag should disappear once drivers get
converted to the new model. This will however take some time. I'm not
opposed to turning the book into a flag though. I was hoping to receive
more review comments on this particular patch, but as that's not the
case, I can already proceed with the change.

What would the DRM_BRIDGE_FLAG_NO_CHAINING flag be used for ?

> 2. If the patch can be applied atomically it is OK as is, if not you can
> use preprocessor vararg magic to support new and old syntax, sth like:
> 
> #define _drm_bridge_attach(encoder, bridge, prev, flags, optarg...)
> __drm_bridge_attach(encoder, bridge, prev, flags)
> 
> #define drm_bridge_attach(encoder, bridge, prev, optarg...)
> _drm_bridge_attach(encoder, bridge, prev, ##optarg, 0)

Good point. I'll try to do this atomically, but if it fails I'll follow
your suggestion.

> 3. Maybe more convenient would be to just set the flags directly before
> attachment:
> 
>     bridge->dont_create_connector = true;
> 
>     ret = drm_bridge_attach(encoder, bridge, NULL);
> 
>     This way it will be still expandable, and less changes.

Bridges that are chained would need to set the dont_create_connector
flag of the next bridge. It would be a bit ugly, but would make this
patch smaller. On the other hand we would need to keep the if
(!create_connector) check in the .attach() handlers, and it would be
easier to miss it in bridge drivers (current or new) than with an
explicit argument to the .attach() operation. I would thus have a
preference for the new argument to .attach(). Especially if it can help
you with DRM_BRIDGE_FLAG_NO_CHAINING :-)

> >  	if (ret)
> >  		drm_encoder_cleanup(encoder);
> >  
> > diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> > index f73d8a92274e..606841d2c0b0 100644
> > --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> > +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> > @@ -123,7 +123,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
> >  	}
> >  
> >  	if (bridge) {
> > -		ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> > +		ret = drm_bridge_attach(&output->encoder, bridge, NULL, true);
> >  		if (!ret)
> >  			return 0;
> >  
> > diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> > index f6d2681f6927..c67ba30edec4 100644
> > --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> > +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> > @@ -847,11 +847,15 @@ static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
> >  	adv7511_mode_set(adv, mode, adj_mode);
> >  }
> >  
> > -static int adv7511_bridge_attach(struct drm_bridge *bridge)
> > +static int adv7511_bridge_attach(struct drm_bridge *bridge,
> > +				 bool create_connector)
> >  {
> >  	struct adv7511 *adv = bridge_to_adv7511(bridge);
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Parent encoder object not found");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c
> > index 3c7cc5af735c..f72755e59e12 100644
> > --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c
> > +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c
> > @@ -998,11 +998,15 @@ static const struct drm_connector_funcs anx78xx_connector_funcs = {
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int anx78xx_bridge_attach(struct drm_bridge *bridge)
> > +static int anx78xx_bridge_attach(struct drm_bridge *bridge,
> > +				 bool create_connector)
> >  {
> >  	struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
> >  	int err;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Parent encoder object not found");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> > index 3f7f4880be09..f6a1bdcc09d6 100644
> > --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> > +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> > @@ -1179,13 +1179,17 @@ static const struct drm_connector_funcs analogix_dp_connector_funcs = {
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int analogix_dp_bridge_attach(struct drm_bridge *bridge)
> > +static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
> > +				     bool create_connector)
> >  {
> >  	struct analogix_dp_device *dp = bridge->driver_private;
> >  	struct drm_encoder *encoder = dp->encoder;
> >  	struct drm_connector *connector = NULL;
> >  	int ret = 0;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Parent encoder object not found");
> >  		return -ENODEV;
> > @@ -1463,7 +1467,7 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
> >  	bridge->driver_private = dp;
> >  	bridge->funcs = &analogix_dp_bridge_funcs;
> >  
> > -	ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(dp->encoder, bridge, NULL, true);
> >  	if (ret) {
> >  		DRM_ERROR("failed to attach drm bridge\n");
> >  		return -EINVAL;
> > diff --git a/drivers/gpu/drm/bridge/cdns-dsi.c b/drivers/gpu/drm/bridge/cdns-dsi.c
> > index 6166dca6be81..45f50852cfbb 100644
> > --- a/drivers/gpu/drm/bridge/cdns-dsi.c
> > +++ b/drivers/gpu/drm/bridge/cdns-dsi.c
> > @@ -645,7 +645,8 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi,
> >  	return 0;
> >  }
> >  
> > -static int cdns_dsi_bridge_attach(struct drm_bridge *bridge)
> > +static int cdns_dsi_bridge_attach(struct drm_bridge *bridge,
> > +				  bool create_connector)
> >  {
> >  	struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
> >  	struct cdns_dsi *dsi = input_to_dsi(input);
> > @@ -657,7 +658,8 @@ static int cdns_dsi_bridge_attach(struct drm_bridge *bridge)
> >  		return -ENOTSUPP;
> >  	}
> >  
> > -	return drm_bridge_attach(bridge->encoder, output->bridge, bridge);
> > +	return drm_bridge_attach(bridge->encoder, output->bridge, bridge,
> > +				 create_connector);
> >  }
> >  
> >  static enum drm_mode_status
> > diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c
> > index 2ab2c234f26c..bafab97521af 100644
> > --- a/drivers/gpu/drm/bridge/lvds-encoder.c
> > +++ b/drivers/gpu/drm/bridge/lvds-encoder.c
> > @@ -18,14 +18,14 @@ struct lvds_encoder {
> >  	struct gpio_desc *powerdown_gpio;
> >  };
> >  
> > -static int lvds_encoder_attach(struct drm_bridge *bridge)
> > +static int lvds_encoder_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct lvds_encoder *lvds_encoder = container_of(bridge,
> >  							 struct lvds_encoder,
> >  							 bridge);
> >  
> >  	return drm_bridge_attach(bridge->encoder, lvds_encoder->panel_bridge,
> > -				 bridge);
> > +				 bridge, create_connector);
> >  }
> >  
> >  static void lvds_encoder_enable(struct drm_bridge *bridge)
> > diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
> > index 79311f8354bd..4250e2235f50 100644
> > --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
> > +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
> > @@ -206,13 +206,17 @@ static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
> >  	return IRQ_HANDLED;
> >  }
> >  
> > -static int ge_b850v3_lvds_attach(struct drm_bridge *bridge)
> > +static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
> > +				 bool create_connector)
> >  {
> >  	struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector;
> >  	struct i2c_client *stdp4028_i2c
> >  			= ge_b850v3_lvds_ptr->stdp4028_i2c;
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Parent encoder object not found");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
> > index 98bc650b8c95..6bef439261da 100644
> > --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
> > +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
> > @@ -238,11 +238,15 @@ static const struct drm_connector_funcs ptn3460_connector_funcs = {
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int ptn3460_bridge_attach(struct drm_bridge *bridge)
> > +static int ptn3460_bridge_attach(struct drm_bridge *bridge,
> > +				 bool create_connector)
> >  {
> >  	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Parent encoder object not found");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
> > index b12ae3a4c5f1..98ad4abf2409 100644
> > --- a/drivers/gpu/drm/bridge/panel.c
> > +++ b/drivers/gpu/drm/bridge/panel.c
> > @@ -52,12 +52,15 @@ static const struct drm_connector_funcs panel_bridge_connector_funcs = {
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int panel_bridge_attach(struct drm_bridge *bridge)
> > +static int panel_bridge_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
> >  	struct drm_connector *connector = &panel_bridge->connector;
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Missing encoder\n");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
> > index 2d88146e4836..b9243d51489b 100644
> > --- a/drivers/gpu/drm/bridge/parade-ps8622.c
> > +++ b/drivers/gpu/drm/bridge/parade-ps8622.c
> > @@ -476,11 +476,14 @@ static const struct drm_connector_funcs ps8622_connector_funcs = {
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int ps8622_attach(struct drm_bridge *bridge)
> > +static int ps8622_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Parent encoder object not found");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
> > index dd7aa466b280..18904b1082b6 100644
> > --- a/drivers/gpu/drm/bridge/sii902x.c
> > +++ b/drivers/gpu/drm/bridge/sii902x.c
> > @@ -396,12 +396,16 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
> >  	mutex_unlock(&sii902x->mutex);
> >  }
> >  
> > -static int sii902x_bridge_attach(struct drm_bridge *bridge)
> > +static int sii902x_bridge_attach(struct drm_bridge *bridge,
> > +				 bool create_connector)
> >  {
> >  	struct sii902x *sii902x = bridge_to_sii902x(bridge);
> >  	struct drm_device *drm = bridge->dev;
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	drm_connector_helper_add(&sii902x->connector,
> >  				 &sii902x_connector_helper_funcs);
> >  
> > diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
> > index 0cc293a6ac24..ea6529df7d9c 100644
> > --- a/drivers/gpu/drm/bridge/sil-sii8620.c
> > +++ b/drivers/gpu/drm/bridge/sil-sii8620.c
> > @@ -2203,7 +2203,7 @@ static inline struct sii8620 *bridge_to_sii8620(struct drm_bridge *bridge)
> >  	return container_of(bridge, struct sii8620, bridge);
> >  }
> >  
> > -static int sii8620_attach(struct drm_bridge *bridge)
> > +static int sii8620_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct sii8620 *ctx = bridge_to_sii8620(bridge);
> >  
> > diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
> > index 7495b9bef865..86885eb6e28d 100644
> > --- a/drivers/gpu/drm/bridge/simple-bridge.c
> > +++ b/drivers/gpu/drm/bridge/simple-bridge.c
> > @@ -108,11 +108,15 @@ static const struct drm_connector_funcs simple_bridge_con_funcs = {
> >  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int simple_bridge_attach(struct drm_bridge *bridge)
> > +static int simple_bridge_attach(struct drm_bridge *bridge,
> > +				bool create_connector)
> >  {
> >  	struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return 0;
> > +
> >  	if (!bridge->encoder) {
> >  		DRM_ERROR("Missing encoder\n");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > index c6490949d9db..930d67c618dd 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> > @@ -2174,12 +2174,16 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
> >  	.get_modes = dw_hdmi_connector_get_modes,
> >  };
> >  
> > -static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
> > +static int dw_hdmi_bridge_attach(struct drm_bridge *bridge,
> > +				 bool create_connector)
> >  {
> >  	struct dw_hdmi *hdmi = bridge->driver_private;
> >  	struct drm_encoder *encoder = bridge->encoder;
> >  	struct drm_connector *connector = &hdmi->connector;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	connector->interlace_allowed = 1;
> >  	connector->polled = DRM_CONNECTOR_POLL_HPD;
> >  
> > @@ -2857,7 +2861,7 @@ struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
> >  	if (IS_ERR(hdmi))
> >  		return hdmi;
> >  
> > -	ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, true);
> >  	if (ret) {
> >  		dw_hdmi_remove(hdmi);
> >  		DRM_ERROR("Failed to initialize bridge with drm\n");
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
> > index 281c58bab1a1..05cf97ad524f 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
> > @@ -906,7 +906,8 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
> >  	return mode_status;
> >  }
> >  
> > -static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge)
> > +static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
> > +				     bool create_connector)
> >  {
> >  	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
> >  
> > @@ -919,7 +920,8 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge)
> >  	bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI;
> >  
> >  	/* Attach the panel-bridge to the dsi bridge */
> > -	return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge);
> > +	return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge,
> > +				 create_connector);
> >  }
> >  
> >  static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
> > @@ -1064,7 +1066,7 @@ int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder)
> >  {
> >  	int ret;
> >  
> > -	ret = drm_bridge_attach(encoder, &dsi->bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, &dsi->bridge, NULL, true);
> >  	if (ret) {
> >  		DRM_ERROR("Failed to initialize bridge with drm\n");
> >  		return ret;
> > diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
> > index 170f162ffa55..6016f3aae42f 100644
> > --- a/drivers/gpu/drm/bridge/tc358764.c
> > +++ b/drivers/gpu/drm/bridge/tc358764.c
> > @@ -348,12 +348,15 @@ static void tc358764_enable(struct drm_bridge *bridge)
> >  		dev_err(ctx->dev, "error enabling panel (%d)\n", ret);
> >  }
> >  
> > -static int tc358764_attach(struct drm_bridge *bridge)
> > +static int tc358764_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct tc358764 *ctx = bridge_to_tc358764(bridge);
> >  	struct drm_device *drm = bridge->dev;
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	ctx->connector.polled = DRM_CONNECTOR_POLL_HPD;
> >  	ret = drm_connector_init(drm, &ctx->connector,
> >  				 &tc358764_connector_funcs,
> > diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
> > index 13ade28a36a8..e2b2d2660adc 100644
> > --- a/drivers/gpu/drm/bridge/tc358767.c
> > +++ b/drivers/gpu/drm/bridge/tc358767.c
> > @@ -1273,13 +1273,16 @@ static const struct drm_connector_funcs tc_connector_funcs = {
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int tc_bridge_attach(struct drm_bridge *bridge)
> > +static int tc_bridge_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
> >  	struct tc_data *tc = bridge_to_tc(bridge);
> >  	struct drm_device *drm = bridge->dev;
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	/* Create DP/eDP connector */
> >  	drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs);
> >  	ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs,
> > diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c
> > index 3d74129b2995..86f3b96f95db 100644
> > --- a/drivers/gpu/drm/bridge/thc63lvd1024.c
> > +++ b/drivers/gpu/drm/bridge/thc63lvd1024.c
> > @@ -42,11 +42,12 @@ static inline struct thc63_dev *to_thc63(struct drm_bridge *bridge)
> >  	return container_of(bridge, struct thc63_dev, bridge);
> >  }
> >  
> > -static int thc63_attach(struct drm_bridge *bridge)
> > +static int thc63_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct thc63_dev *thc63 = to_thc63(bridge);
> >  
> > -	return drm_bridge_attach(bridge->encoder, thc63->next, bridge);
> > +	return drm_bridge_attach(bridge->encoder, thc63->next, bridge,
> > +				 create_connector);
> >  }
> >  
> >  static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge,
> > diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> > index b77a52d05061..dbe265f7112d 100644
> > --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> > +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> > @@ -224,7 +224,7 @@ static int ti_sn_bridge_parse_regulators(struct ti_sn_bridge *pdata)
> >  				       pdata->supplies);
> >  }
> >  
> > -static int ti_sn_bridge_attach(struct drm_bridge *bridge)
> > +static int ti_sn_bridge_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	int ret, val;
> >  	struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
> > @@ -235,6 +235,9 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge)
> >  						   .node = NULL,
> >  						 };
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	ret = drm_connector_init(bridge->dev, &pdata->connector,
> >  				 &ti_sn_bridge_connector_funcs,
> >  				 DRM_MODE_CONNECTOR_eDP);
> > diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
> > index 4e76b2b27374..8d4690e436c3 100644
> > --- a/drivers/gpu/drm/bridge/ti-tfp410.c
> > +++ b/drivers/gpu/drm/bridge/ti-tfp410.c
> > @@ -121,11 +121,14 @@ static const struct drm_connector_funcs tfp410_con_funcs = {
> >  	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
> >  };
> >  
> > -static int tfp410_attach(struct drm_bridge *bridge)
> > +static int tfp410_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	if (!bridge->encoder) {
> >  		dev_err(dvi->dev, "Missing encoder\n");
> >  		return -ENODEV;
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index cba537c99e43..519577f363e3 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -95,6 +95,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
> >   * @encoder: DRM encoder
> >   * @bridge: bridge to attach
> >   * @previous: previous bridge in the chain (optional)
> > + * @create_connector: true if the bridge should create a drm_connector
> >   *
> >   * Called by a kms driver to link the bridge to an encoder's chain. The previous
> >   * argument specifies the previous bridge in the chain. If NULL, the bridge is
> > @@ -112,7 +113,7 @@ EXPORT_SYMBOL(drm_bridge_remove);
> >   * Zero on success, error code on failure
> >   */
> >  int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> > -		      struct drm_bridge *previous)
> > +		      struct drm_bridge *previous, bool create_connector)
> >  {
> >  	int ret;
> >  
> > @@ -129,7 +130,7 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> >  	bridge->encoder = encoder;
> >  
> >  	if (bridge->funcs->attach) {
> > -		ret = bridge->funcs->attach(bridge);
> > +		ret = bridge->funcs->attach(bridge, create_connector);
> >  		if (ret < 0) {
> >  			bridge->dev = NULL;
> >  			bridge->encoder = NULL;
> > diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> > index b11910f14c46..a367ef1e5081 100644
> > --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> > +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> > @@ -228,7 +228,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
> >  int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> >  					  struct drm_bridge *bridge)
> >  {
> > -	return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> > +	return drm_bridge_attach(&pipe->encoder, bridge, NULL, true);
> >  }
> >  EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
> >  
> > diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> > index 3a0f0ba8c63a..02b98e6ca52d 100644
> > --- a/drivers/gpu/drm/exynos/exynos_dp.c
> > +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> > @@ -105,7 +105,8 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
> >  
> >  	/* Pre-empt DP connector creation if there's a bridge */
> >  	if (dp->ptn_bridge) {
> > -		ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> > +		ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge,
> > +					true);
> >  		if (ret) {
> >  			DRM_DEV_ERROR(dp->dev,
> >  				      "Failed to attach bridge to drm\n");
> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > index 5f6f523821a2..768acc79d10c 100644
> > --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > @@ -1522,7 +1522,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
> >  
> >  	out_bridge  = of_drm_find_bridge(device->dev.of_node);
> >  	if (out_bridge) {
> > -		drm_bridge_attach(encoder, out_bridge, NULL);
> > +		drm_bridge_attach(encoder, out_bridge, NULL, true);
> >  		dsi->out_bridge = out_bridge;
> >  		encoder->bridge = NULL;
> >  	} else {
> > @@ -1698,7 +1698,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> >  	if (dsi->in_bridge_node) {
> >  		in_bridge = of_drm_find_bridge(dsi->in_bridge_node);
> >  		if (in_bridge)
> > -			drm_bridge_attach(encoder, in_bridge, NULL);
> > +			drm_bridge_attach(encoder, in_bridge, NULL, true);
> >  	}
> >  
> >  	return mipi_dsi_host_register(&dsi->dsi_host);
> > diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> > index bc1565f1822a..808c98101d56 100644
> > --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> > +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> > @@ -952,7 +952,7 @@ static int hdmi_create_connector(struct drm_encoder *encoder)
> >  	drm_connector_attach_encoder(connector, encoder);
> >  
> >  	if (hdata->bridge) {
> > -		ret = drm_bridge_attach(encoder, hdata->bridge, NULL);
> > +		ret = drm_bridge_attach(encoder, hdata->bridge, NULL, true);
> >  		if (ret)
> >  			DRM_DEV_ERROR(hdata->dev, "Failed to attach bridge\n");
> >  	}
> > diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> > index c49e9e3740f8..8d22618ccf2e 100644
> > --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> > +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> > @@ -159,5 +159,5 @@ int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> >  		return fsl_dcu_attach_panel(fsl_dev, panel);
> >  	}
> >  
> > -	return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> > +	return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL, true);
> >  }
> > diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> > index 3d6c45097f51..eac8ec1512ab 100644
> > --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> > +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> > @@ -780,7 +780,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
> >  	int ret;
> >  
> >  	/* associate the bridge to dsi encoder */
> > -	ret = drm_bridge_attach(encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, bridge, NULL, true);
> >  	if (ret) {
> >  		DRM_ERROR("failed to attach external bridge\n");
> >  		return ret;
> > diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
> > index 3d368c43185f..6b2e648b6c4d 100644
> > --- a/drivers/gpu/drm/i2c/tda998x_drv.c
> > +++ b/drivers/gpu/drm/i2c/tda998x_drv.c
> > @@ -1366,10 +1366,14 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
> >  
> >  /* DRM bridge functions */
> >  
> > -static int tda998x_bridge_attach(struct drm_bridge *bridge)
> > +static int tda998x_bridge_attach(struct drm_bridge *bridge,
> > +				 bool create_connector)
> >  {
> >  	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	return tda998x_connector_init(priv, bridge->dev);
> >  }
> >  
> > @@ -2033,7 +2037,7 @@ static int tda998x_encoder_init(struct device *dev, struct drm_device *drm)
> >  	if (ret)
> >  		goto err_encoder;
> >  
> > -	ret = drm_bridge_attach(&priv->encoder, &priv->bridge, NULL);
> > +	ret = drm_bridge_attach(&priv->encoder, &priv->bridge, NULL, true);
> >  	if (ret)
> >  		goto err_bridge;
> >  
> > diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> > index 383733302280..845ead25ade7 100644
> > --- a/drivers/gpu/drm/imx/imx-ldb.c
> > +++ b/drivers/gpu/drm/imx/imx-ldb.c
> > @@ -446,7 +446,7 @@ static int imx_ldb_register(struct drm_device *drm,
> >  
> >  	if (imx_ldb_ch->bridge) {
> >  		ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> > -					imx_ldb_ch->bridge, NULL);
> > +					imx_ldb_ch->bridge, NULL, true);
> >  		if (ret) {
> >  			DRM_ERROR("Failed to initialize bridge with drm\n");
> >  			return ret;
> > diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> > index 1a76de1e8e7b..cd746592d2a7 100644
> > --- a/drivers/gpu/drm/imx/parallel-display.c
> > +++ b/drivers/gpu/drm/imx/parallel-display.c
> > @@ -182,7 +182,7 @@ static int imx_pd_register(struct drm_device *drm,
> >  		drm_panel_attach(imxpd->panel, &imxpd->connector);
> >  
> >  	if (imxpd->bridge) {
> > -		ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> > +		ret = drm_bridge_attach(encoder, imxpd->bridge, NULL, true);
> >  		if (ret < 0) {
> >  			dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> >  				ret);
> > diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
> > index 07f7090d08b3..f2deadc980f8 100644
> > --- a/drivers/gpu/drm/mcde/mcde_dsi.c
> > +++ b/drivers/gpu/drm/mcde/mcde_dsi.c
> > @@ -817,12 +817,16 @@ mcde_dsi_connector_helper_funcs = {
> >  	.get_modes = mcde_dsi_get_modes,
> >  };
> >  
> > -static int mcde_dsi_bridge_attach(struct drm_bridge *bridge)
> > +static int mcde_dsi_bridge_attach(struct drm_bridge *bridge,
> > +				  bool create_connector)
> >  {
> >  	struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
> >  	struct drm_device *drm = bridge->dev;
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	drm_connector_helper_add(&d->connector,
> >  				 &mcde_dsi_connector_helper_funcs);
> >  
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > index bacd989cc9aa..1ff27bb17016 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> > @@ -604,7 +604,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
> >  	/* Currently DPI0 is fixed to be driven by OVL1 */
> >  	dpi->encoder.possible_crtcs = BIT(1);
> >  
> > -	ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> > +	ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL, true);
> >  	if (ret) {
> >  		dev_err(dev, "Failed to attach bridge: %d\n", ret);
> >  		goto err_cleanup;
> > diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > index b91c4616644a..9c5bac48b44f 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> > @@ -819,7 +819,7 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
> >  
> >  	/* If there's a bridge, attach to it and let it create the connector */
> >  	if (dsi->bridge) {
> > -		ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> > +		ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL, true);
> >  		if (ret) {
> >  			DRM_ERROR("Failed to attach bridge to drm\n");
> >  			goto err_encoder_cleanup;
> > diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> > index 5d6a9f094df5..d3248a881cf0 100644
> > --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> > +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> > @@ -1290,11 +1290,15 @@ static void mtk_hdmi_hpd_event(bool hpd, struct device *dev)
> >   * Bridge callbacks
> >   */
> >  
> > -static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> > +static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge,
> > +				  bool create_connector)
> >  {
> >  	struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> >  	int ret;
> >  
> > +	if (!create_connector)
> > +		return -EINVAL;
> > +
> >  	ret = drm_connector_init(bridge->encoder->dev, &hdmi->conn,
> >  				 &mtk_hdmi_connector_funcs,
> >  				 DRM_MODE_CONNECTOR_HDMIA);
> > @@ -1318,7 +1322,7 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> >  
> >  	if (hdmi->next_bridge) {
> >  		ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> > -					bridge);
> > +					bridge, create_connector);
> >  		if (ret) {
> >  			dev_err(hdmi->dev,
> >  				"Failed to attach external bridge: %d\n", ret);
> > diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> > index 271aa7bbca92..ca733086041a 100644
> > --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> > +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> > @@ -664,7 +664,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> >  	bridge = &dsi_bridge->base;
> >  	bridge->funcs = &dsi_mgr_bridge_funcs;
> >  
> > -	ret = drm_bridge_attach(encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, bridge, NULL, true);
> >  	if (ret)
> >  		goto fail;
> >  
> > @@ -693,7 +693,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> >  	encoder = msm_dsi->encoder;
> >  
> >  	/* link the internal dsi bridge to the external bridge */
> > -	drm_bridge_attach(encoder, ext_bridge, int_bridge);
> > +	drm_bridge_attach(encoder, ext_bridge, int_bridge, true);
> >  
> >  	/*
> >  	 * we need the drm_connector created by the external bridge
> > diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
> > index 2950bba4aca9..32a463c84cc1 100644
> > --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> > +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> > @@ -91,7 +91,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> >  	bridge = &edp_bridge->base;
> >  	bridge->funcs = &edp_bridge_funcs;
> >  
> > -	ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(edp->encoder, bridge, NULL, true);
> >  	if (ret)
> >  		goto fail;
> >  
> > diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > index 03197b8959ba..d7738aafcff8 100644
> > --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> > @@ -296,7 +296,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> >  	bridge = &hdmi_bridge->base;
> >  	bridge->funcs = &msm_hdmi_bridge_funcs;
> >  
> > -	ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(hdmi->encoder, bridge, NULL, true);
> >  	if (ret)
> >  		goto fail;
> >  
> > diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> > index 672e0f8ad11c..837d0cd20dd1 100644
> > --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> > +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> > @@ -301,7 +301,8 @@ static int omap_modeset_init(struct drm_device *dev)
> >  
> >  		if (pipe->output->bridge) {
> >  			ret = drm_bridge_attach(pipe->encoder,
> > -						pipe->output->bridge, NULL);
> > +						pipe->output->bridge, NULL,
> > +						true);
> >  			if (ret < 0)
> >  				return ret;
> >  		}
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> > index 0f00bdfe2366..74c2ae5ce687 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
> > @@ -120,7 +120,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
> >  	 * Attach the bridge to the encoder. The bridge will create the
> >  	 * connector.
> >  	 */
> > -	ret = drm_bridge_attach(encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, bridge, NULL, true);
> >  	if (ret) {
> >  		drm_encoder_cleanup(encoder);
> >  		return ret;
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > index 1c62578590f4..a8d8b05c4731 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > @@ -605,7 +605,7 @@ static void rcar_lvds_mode_set(struct drm_bridge *bridge,
> >  	rcar_lvds_get_lvds_mode(lvds);
> >  }
> >  
> > -static int rcar_lvds_attach(struct drm_bridge *bridge)
> > +static int rcar_lvds_attach(struct drm_bridge *bridge, bool create_connector)
> >  {
> >  	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
> >  	struct drm_connector *connector = &lvds->connector;
> > @@ -615,7 +615,10 @@ static int rcar_lvds_attach(struct drm_bridge *bridge)
> >  	/* If we have a next bridge just attach it. */
> >  	if (lvds->next_bridge)
> >  		return drm_bridge_attach(bridge->encoder, lvds->next_bridge,
> > -					 bridge);
> > +					 bridge, create_connector);
> > +
> > +	if (!create_connector)
> > +		return -EINVAL;
> >  
> >  	/* Otherwise if we have a panel, create a connector. */
> >  	if (!lvds->panel)
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
> > index 830858a809e5..7ca412d294b2 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
> > @@ -440,7 +440,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
> >  			goto err_free_connector;
> >  		}
> >  	} else {
> > -		ret = drm_bridge_attach(encoder, lvds->bridge, NULL);
> > +		ret = drm_bridge_attach(encoder, lvds->bridge, NULL, true);
> >  		if (ret) {
> >  			DRM_DEV_ERROR(drm_dev->dev,
> >  				      "failed to attach bridge: %d\n", ret);
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
> > index ce4d82d293e4..8218bbd09a72 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
> > @@ -143,7 +143,7 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
> >  
> >  	rgb->bridge = bridge;
> >  
> > -	ret = drm_bridge_attach(encoder, rgb->bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, rgb->bridge, NULL, true);
> >  	if (ret) {
> >  		DRM_DEV_ERROR(drm_dev->dev,
> >  			      "failed to attach bridge: %d\n", ret);
> > diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> > index 9e6d5d8b7030..f09209621568 100644
> > --- a/drivers/gpu/drm/sti/sti_dvo.c
> > +++ b/drivers/gpu/drm/sti/sti_dvo.c
> > @@ -468,7 +468,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
> >  	bridge->of_node = dvo->dev.of_node;
> >  	drm_bridge_add(bridge);
> >  
> > -	err = drm_bridge_attach(encoder, bridge, NULL);
> > +	err = drm_bridge_attach(encoder, bridge, NULL, true);
> >  	if (err) {
> >  		DRM_ERROR("Failed to attach bridge\n");
> >  		return err;
> > diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> > index 94e404f13234..87e0fb742dc8 100644
> > --- a/drivers/gpu/drm/sti/sti_hda.c
> > +++ b/drivers/gpu/drm/sti/sti_hda.c
> > @@ -700,7 +700,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
> >  
> >  	bridge->driver_private = hda;
> >  	bridge->funcs = &sti_hda_bridge_funcs;
> > -	drm_bridge_attach(encoder, bridge, NULL);
> > +	drm_bridge_attach(encoder, bridge, NULL, true);
> >  
> >  	connector->encoder = encoder;
> >  
> > diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> > index f03d617edc4c..8c0ffe6833f9 100644
> > --- a/drivers/gpu/drm/sti/sti_hdmi.c
> > +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> > @@ -1276,7 +1276,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
> >  
> >  	bridge->driver_private = hdmi;
> >  	bridge->funcs = &sti_hdmi_bridge_funcs;
> > -	drm_bridge_attach(encoder, bridge, NULL);
> > +	drm_bridge_attach(encoder, bridge, NULL, true);
> >  
> >  	connector->encoder = encoder;
> >  
> > diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c
> > index 2fe6c4a8d915..10a9f848c5f6 100644
> > --- a/drivers/gpu/drm/stm/ltdc.c
> > +++ b/drivers/gpu/drm/stm/ltdc.c
> > @@ -1053,7 +1053,7 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
> >  	drm_encoder_init(ddev, encoder, &ltdc_encoder_funcs,
> >  			 DRM_MODE_ENCODER_DPI, NULL);
> >  
> > -	ret = drm_bridge_attach(encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(encoder, bridge, NULL, true);
> >  	if (ret) {
> >  		drm_encoder_cleanup(encoder);
> >  		return -EINVAL;
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c
> > index 3a3ba99fed22..3e5170fa1e67 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c
> > @@ -155,7 +155,7 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon)
> >  	}
> >  
> >  	if (bridge) {
> > -		ret = drm_bridge_attach(encoder, bridge, NULL);
> > +		ret = drm_bridge_attach(encoder, bridge, NULL, true);
> >  		if (ret) {
> >  			dev_err(drm->dev, "Couldn't attach our bridge\n");
> >  			goto err_cleanup_connector;
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> > index a901ec689b62..3f8629445fbb 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> > @@ -252,7 +252,7 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon)
> >  	}
> >  
> >  	if (rgb->bridge) {
> > -		ret = drm_bridge_attach(encoder, rgb->bridge, NULL);
> > +		ret = drm_bridge_attach(encoder, rgb->bridge, NULL, true);
> >  		if (ret) {
> >  			dev_err(drm->dev, "Couldn't attach our bridge\n");
> >  			goto err_cleanup_connector;
> > diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
> > index e9969cd36610..ec693c11e455 100644
> > --- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
> > +++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
> > @@ -168,7 +168,7 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
> >  
> >  	priv->external_encoder->possible_crtcs = BIT(0);
> >  
> > -	ret = drm_bridge_attach(priv->external_encoder, bridge, NULL);
> > +	ret = drm_bridge_attach(priv->external_encoder, bridge, NULL, true);
> >  	if (ret) {
> >  		dev_err(ddev->dev, "drm_bridge_attach() failed %d\n", ret);
> >  		return ret;
> > diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
> > index 34f90ca8f479..2d7c5cf0d468 100644
> > --- a/drivers/gpu/drm/vc4/vc4_dpi.c
> > +++ b/drivers/gpu/drm/vc4/vc4_dpi.c
> > @@ -262,7 +262,7 @@ static int vc4_dpi_init_bridge(struct vc4_dpi *dpi)
> >  	if (panel)
> >  		bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DPI);
> >  
> > -	return drm_bridge_attach(dpi->encoder, bridge, NULL);
> > +	return drm_bridge_attach(dpi->encoder, bridge, NULL, true);
> >  }
> >  
> >  static int vc4_dpi_bind(struct device *dev, struct device *master, void *data)
> > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> > index 2ea4e20b7b8a..3edd7ffc7383 100644
> > --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> > @@ -1607,7 +1607,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
> >  			 DRM_MODE_ENCODER_DSI, NULL);
> >  	drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
> >  
> > -	ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
> > +	ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL, true);
> >  	if (ret) {
> >  		dev_err(dev, "bridge attach failed: %d\n", ret);
> >  		return ret;
> > diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> > index 7616f6562fe4..08dc15f93ded 100644
> > --- a/include/drm/drm_bridge.h
> > +++ b/include/drm/drm_bridge.h
> > @@ -48,7 +48,7 @@ struct drm_bridge_funcs {
> >  	 *
> >  	 * Zero on success, error code on failure.
> >  	 */
> > -	int (*attach)(struct drm_bridge *bridge);
> > +	int (*attach)(struct drm_bridge *bridge, bool create_connector);
> >  
> >  	/**
> >  	 * @detach:
> > @@ -404,7 +404,7 @@ 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);
> >  int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> > -		      struct drm_bridge *previous);
> > +		      struct drm_bridge *previous, bool create_connector);
> >  
> >  bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> >  			   const struct drm_display_mode *mode,

-- 
Regards,

Laurent Pinchart


More information about the dri-devel mailing list