[PATCH v22 4/8] drm: bridge: Cadence: Add MHDP8501 DP/HDMI driver
Laurentiu Palcu
laurentiu.palcu at oss.nxp.com
Mon Apr 27 07:35:55 PDT 2026
Hi Luca,
On Mon, Apr 27, 2026 at 02:59:51PM +0200, Luca Ceresoli wrote:
> Hello Laurentiu,
>
> On Fri Apr 24, 2026 at 1:07 PM CEST, Laurentiu Palcu wrote:
> > From: Sandor Yu <Sandor.yu at nxp.com>
> >
> > Add a new DRM DisplayPort and HDMI bridge driver for Candence MHDP8501
> > used in i.MX8MQ SOC. MHDP8501 could support HDMI or DisplayPort
> > standards according embedded Firmware running in the uCPU.
> >
> > For iMX8MQ SOC, the DisplayPort/HDMI FW was loaded and activated by
> > SOC's ROM code. Bootload binary included respective specific firmware
> > is required.
> >
> > Driver will check display connector type and
> > then load the corresponding driver.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu at nxp.com>
> > Co-developed-by: Laurentiu Palcu <laurentiu.palcu at oss.nxp.com>
> > Signed-off-by: Laurentiu Palcu <laurentiu.palcu at oss.nxp.com>
>
> ...
>
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c
> ...
> > +enum drm_connector_status cdns_mhdp8501_detect(struct drm_bridge *bridge,
> > + struct drm_connector *connector)
> > +{
> > + struct cdns_mhdp8501_device *mhdp = bridge->driver_private;
>
> Please don't use driver_private. Write a oneliner function wrapping
> container_of(). There are many examples in bridges,
> e.g. bridge_to_sn65dsi83().
ack
>
> > +static int cdns_mhdp8501_get_bridge_type(struct device_node *out_ep,
> > + int *bridge_type)
> > +{
> > + struct device_node *incoming_ep, *node, *ep;
> > + int ret = -ENODEV;
> > +
> > + incoming_ep = of_graph_get_remote_endpoint(out_ep);
> > + if (!incoming_ep)
> > + return -ENODEV;
> > +
> > + node = of_graph_get_port_parent(incoming_ep);
> > + if (!node) {
> > + of_node_put(incoming_ep);
> > + return -ENODEV;
> > + }
> > +
> > + if (of_device_is_compatible(node, "hdmi-connector")) {
> > + *bridge_type = DRM_MODE_CONNECTOR_HDMIA;
> > + ret = 0;
> > + } else if (of_device_is_compatible(node, "dp-connector")) {
> > + *bridge_type = DRM_MODE_CONNECTOR_DisplayPort;
> > + ret = 0;
> > + } else {
> > + for_each_endpoint_of_node(node, ep) {
> > + if (ep == incoming_ep)
> > + continue;
> > +
> > + ret = cdns_mhdp8501_get_bridge_type(ep, bridge_type);
> > + if (!ret) {
> > + of_node_put(ep);
> > + break;
> > + }
> > + }
> > + }
>
> I don't follow what this logic is doing. Can you provide a practical
> example of the "next node" (@node variable) where you fall in the else
> case?
The else would be hit when there's another bridge after this one. But I
don't have a practical example since, on the i.MX8MQ, there is no other
bridge after it. However, as reviewers pointed out in earlier patchset
iterations, we needed to make it generic.
>
> Also, while this resursion will probably work in most, if not all,
> realistic cases, it could take incorrect decisions. Consider the case there
> in the else branch your @node points to some node having two input
> endpoints: ep0 is the incoming_ep and ep1 is another input endpoint. In
> such case you would recurse on ep1 and return its bridge type, which
> however has nothing to to with the output and might be incorrect.
I believe you are right, I assumed each bridge has only one input
endpoint and one output endpoint... :/
>
> Another question is whether this driver should have two compatible strings,
> one for hdmi and one for dp, and set the bridge_type based on that. This
> would make it a lot simpler and remove the need for this function.
I think this is a good idea. I see no reason why having 2 different
compatibles wouldn't work. I'll give it a try.
>
> But if I guess right from the code, this device can output either hdmi or
> dp, and the implementation infers the type based on this device tree
> walk. Is it the case?
Yes, based on the PHY firmware (which is loaded by the ROM) we can have
HDMI or DP functionality.
>
> > +static int cdns_mhdp8501_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct cdns_mhdp8501_device *mhdp;
> > + const struct drm_bridge_funcs *bridge_funcs;
> > + enum phy_mode phy_mode;
> > + struct resource *res;
> > + u32 lane_mapping;
> > + int bridge_type;
> > + u32 reg;
> > + int ret;
> > +
> > + ret = cdns_mhdp8501_dt_parse(pdev, &bridge_type, &lane_mapping);
> > + if (ret < 0)
> > + return ret;
> > +
> > + ret = devm_of_platform_populate(dev);
> > + if (ret)
> > + return ret;
> > +
> > + bridge_funcs = (bridge_type == DRM_MODE_CONNECTOR_HDMIA) ?
> > + &cdns_hdmi_bridge_funcs : &cdns_dp_bridge_funcs;
> > +
> > + mhdp = devm_drm_bridge_alloc(dev, struct cdns_mhdp8501_device,
> > + bridge, bridge_funcs);
> > + if (!mhdp)
> > + return -ENOMEM;
> > +
> > + mhdp->dev = dev;
> > + mhdp->bridge_type = bridge_type;
> > + mhdp->lane_mapping = lane_mapping;
> > +
> > + mhdp->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
> > + if (IS_ERR(mhdp->next_bridge))
> > + return dev_err_probe(dev, PTR_ERR(mhdp->next_bridge),
> > + "failed to get next bridge\n");
>
> devm_drm_of_get_bridge() is there to either create a new panel_bridge
> wrapping a panel or return an existing bridge. However based on the
> cdns_mhdp8501_get_bridge_type() code it seems to me that you will always
> have another bridge after this bridge. And so instead of
> devm_drm_of_get_bridge() you should use of_drm_find_and_get_bridge(),
> which handles bridge refcounting.
Ok, I'll switch to of_drm_find_and_get_bridge().
>
> When switching to it, you additionally can use the drm_bridge::next_bridge
> pointer instead of having your mhdp->next_bridge. This will simplify
> putting the bridge reference. An example of its usage is in [0].
>
> [0] https://lore.kernel.org/lkml/20260109-drm-bridge-alloc-getput-drm_of_find_bridge-2-v2-4-8bad3ef90b9f@bootlin.com/
>
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c
> ...
> > +static int cdns_dp_bridge_attach(struct drm_bridge *bridge,
> > + struct drm_encoder *encoder,
> > + enum drm_bridge_attach_flags flags)
> > +{
> > + struct cdns_mhdp8501_device *mhdp = bridge->driver_private;
> > + int ret;
> > +
> > + ret = drm_bridge_attach(encoder, mhdp->next_bridge, bridge,
> > + flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> > + if (ret < 0)
> > + return ret;
> > +
> > + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> > + dev_err(mhdp->dev, "do not support creating a drm_connector\n");
> > + return -EINVAL;
> > + }
>
> Any good reason for doing this check after calling drm_bridge_attach()? It
> looks to me that you should first check for valid arguments, and if they
> pass take any actions.
There's no good reason for this. I'll move the check at the beginning.
>
> Same below for the HDMI version.
will do.
Thank you for your review.
--
Thanks,
Laurentiu
More information about the linux-phy
mailing list