On Thu, Oct 09, 2025 at 12:10:42PM +0800, Damon Ding wrote:
> Hi Luca,
> 
> On 10/2/2025 12:09 AM, Luca Ceresoli wrote:
> > Hello Damon,
> > 
> > On Tue, 30 Sep 2025 17:09:13 +0800
> > Damon Ding <[email protected]> wrote:
> > 
> > > When multiple bridges are present, EDID detection capability
> > > (DRM_BRIDGE_OP_EDID) takes precedence over modes detection
> > > (DRM_BRIDGE_OP_MODES). To ensure the above two capabilities are
> > > determined by the last bridge in the chain, we handle three cases:
> > > 
> > > Case 1: The later bridge declares only DRM_BRIDGE_OP_MODES
> > >   - If the previous bridge declares DRM_BRIDGE_OP_EDID, set
> > >     &drm_bridge_connector.bridge_edid to NULL and set
> > >     &drm_bridge_connector.bridge_modes to the later bridge.
> > >   - Ensure modes detection capability of the later bridge will not
> > >     be ignored.
> > > 
> > > Case 2: The later bridge declares only DRM_BRIDGE_OP_EDID
> > >   - If the previous bridge declares DRM_BRIDGE_OP_MODES, set
> > >     &drm_bridge_connector.bridge_modes to NULL and set
> > >     &drm_bridge_connector.bridge_edid to the later bridge.
> > >   - Although EDID detection capability has higher priority, this
> > >     operation is for balance and makes sense.
> > > 
> > > Case 3: the later bridge declares both of them
> > >   - Assign later bridge as &drm_bridge_connector.bridge_edid and
> > >     and &drm_bridge_connector.bridge_modes to this bridge.
> > >   - Just leave transfer of these two capabilities as before.
> > 
> > I think the whole explanation can be more concisely rewritten as:
> > 
> > If the later bridge declares OP_EDID, OP_MODES or both, then both
> > .bridge_modes and .bridge_edid should be set to NULL (if any was set
> > from a previous bridge), and then .bridge_modes and/or .bridge_edid be
> > set to the later bridge as is done already.
> > 
> > Does this look correct (i.e. does it convey the same meaning)?
> > 
> > > --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> > > +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
> > > @@ -640,6 +640,7 @@ struct drm_connector 
> > > *drm_bridge_connector_init(struct drm_device *drm,
> > >           struct drm_connector *connector;
> > >           struct i2c_adapter *ddc = NULL;
> > >           struct drm_bridge *bridge, *panel_bridge = NULL;
> > > + struct drm_bridge *pre_bridge_edid, *pre_bridge_modes;
> > >           unsigned int supported_formats = BIT(HDMI_COLORSPACE_RGB);
> > >           unsigned int max_bpc = 8;
> > >           bool support_hdcp = false;
> > > @@ -668,6 +669,9 @@ struct drm_connector 
> > > *drm_bridge_connector_init(struct drm_device *drm,
> > >            */
> > >           connector_type = DRM_MODE_CONNECTOR_Unknown;
> > >           drm_for_each_bridge_in_chain(encoder, bridge) {
> > > +         pre_bridge_edid = bridge_connector->bridge_edid;
> > > +         pre_bridge_modes = bridge_connector->bridge_modes;
> > > +
> > >                   if (!bridge->interlace_allowed)
> > >                           connector->interlace_allowed = false;
> > >                   if (!bridge->ycbcr_420_allowed)
> > > @@ -681,6 +685,44 @@ struct drm_connector 
> > > *drm_bridge_connector_init(struct drm_device *drm,
> > >                           bridge_connector->bridge_detect = bridge;
> > >                   if (bridge->ops & DRM_BRIDGE_OP_MODES)
> > >                           bridge_connector->bridge_modes = bridge;
> > > +
> > > +         /*
> > > +          * When multiple bridges are present, EDID detection capability
> > > +          * (DRM_BRIDGE_OP_EDID) takes precedence over modes detection
> > > +          * (DRM_BRIDGE_OP_MODES). To ensure the above two capabilities
> > > +          * are determined by the last bridge in the chain, we handle
> > > +          * three cases:
> > > +          *
> > > +          * Case 1: The later bridge declares only DRM_BRIDGE_OP_MODES
> > > +          *  - If the previous bridge declares DRM_BRIDGE_OP_EDID, set
> > > +          *    &drm_bridge_connector.bridge_edid to NULL and set
> > > +          *    &drm_bridge_connector.bridge_modes to the later bridge.
> > > +          *  - Ensure modes detection capability of the later bridge
> > > +          *    will not be ignored.
> > > +          *
> > > +          * Case 2: The later bridge declares only DRM_BRIDGE_OP_EDID
> > > +          *  - If the previous bridge declares DRM_BRIDGE_OP_MODES, set
> > > +          *    &drm_bridge_connector.bridge_modes to NULL and set
> > > +          *    &drm_bridge_connector.bridge_edid to the later bridge.
> > > +          *  - Although EDID detection capability has higher priority,
> > > +          *    this operation is for balance and makes sense.
> > > +          *
> > > +          * Case 3: the later bridge declares both of them
> > > +          *  - Assign later bridge as &drm_bridge_connector.bridge_edid
> > > +          *    and &drm_bridge_connector.bridge_modes to this bridge.
> > > +          *  - Just leave transfer of these two capabilities as before.
> > > +          */
> > > +         if (bridge->ops & DRM_BRIDGE_OP_EDID &&
> > > +             !(bridge->ops & DRM_BRIDGE_OP_MODES)) {
> > > +                 if (pre_bridge_modes)
> > > +                         bridge_connector->bridge_modes = NULL;
> > > +         }
> > > +         if (bridge->ops & DRM_BRIDGE_OP_MODES &&
> > > +             !(bridge->ops & DRM_BRIDGE_OP_EDID)) {
> > > +                 if (pre_bridge_edid)
> > > +                         bridge_connector->bridge_edid = NULL;
> > > +         }
> > > +
> > 
> > If the above rewrite is correct, then I think this patch can be
> > rewritten in a simple way (build tested only):
> > 
> > diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c 
> > b/drivers/gpu/drm/display/drm_bridge_connector.c
> > index a5bdd6c10643..bd5dbafe88bc 100644
> > --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> > +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
> > @@ -672,14 +672,18 @@ struct drm_connector 
> > *drm_bridge_connector_init(struct drm_device *drm,
> >                  if (!bridge->ycbcr_420_allowed)
> >                          connector->ycbcr_420_allowed = false;
> > -               if (bridge->ops & DRM_BRIDGE_OP_EDID)
> > -                       bridge_connector->bridge_edid = bridge;
> > +               if (bridge->ops & DRM_BRIDGE_OP_EDID || bridge->ops & 
> > DRM_BRIDGE_OP_MODES) {
> > +                       bridge_connector->bridge_edid = NULL;
> > +                       bridge_connector->bridge_modes = NULL;
> > +                       if (bridge->ops & DRM_BRIDGE_OP_EDID)
> > +                               bridge_connector->bridge_edid = bridge;
> > +                       if (bridge->ops & DRM_BRIDGE_OP_MODES)
> > +                               bridge_connector->bridge_modes = bridge;
> > +               }
> >                  if (bridge->ops & DRM_BRIDGE_OP_HPD)
> >                          bridge_connector->bridge_hpd = bridge;
> >                  if (bridge->ops & DRM_BRIDGE_OP_DETECT)
> >                          bridge_connector->bridge_detect = bridge;
> > -               if (bridge->ops & DRM_BRIDGE_OP_MODES)
> > -                       bridge_connector->bridge_modes = bridge;
> >                  if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
> >                          if (bridge_connector->bridge_hdmi)
> >                                  return ERR_PTR(-EBUSY);
> > 
> 
> Yes, this is correct and maintains functional equivalence with the previous
> implementation.
> 
> I previously attempted to implement this feature by modifying the logic in
> this section. However, that approach would obscure the explicit propagation
> semantics of the bridge chain flags (OP_EDID/OP_HPD/OP_DETECT/OP_MODES).
> Therefore, I finally decided to implemented it as a specific check after
> this code block.
> 
> Dmitry, what's your take on this?

I think I prefer Luca's code, it is simpler and easier to understand. It
doesn't need a huge comment, something like "leave the last bridge which
provides either OP_EDID or OP_MODES" should be enough.

> 
> > Another thing to note is that this patch conflicts with [0], which I
> > plan to apply in the next few days. The two patches are orthogonal but
> > they insist on the same lines (those assigning
> > bridge_connector->bridge_* = bridge). Not a big deal, whichever patch
> > comes later will be easily adapted. Just wanted to ensure you are aware.
> > 
> > [0] 
> > https://lore.kernel.org/all/20250926-drm-bridge-alloc-getput-bridge-connector-v2-1-138b4bb70...@bootlin.com/
> > 
> 
> This is indeed a clever approach to the managing bridge resource cleanup in
> drm_bridge_connector. Thanks a lot for the heads-up! I'll resolve this
> conflict and rebase the patch series.
> 
> Apologies for the delayed reply as I was on vacation. ;-)
> 
> Best regards,
> Damon
> 

-- 
With best wishes
Dmitry

Reply via email to