Re: Device tree representation of (hotplug) connectors: discussion at ELCE

David Gibson
2025-09-15T04:54:30Z

[-- Attachment #1: Type: text/plain, Size: 14805 bytes --]

On Thu, Sep 11, 2025 at 10:48:28AM +0200, Herve Codina wrote:
> Hi David,
>
> On Wed, 10 Sep 2025 14:33:45 +1000
> David Gibson <david@gibson.dropbear.id.au> wrote:
>
> > On Tue, Sep 09, 2025 at 11:41:26AM +0200, Herve Codina wrote:
> > > Hi David,
> > >
> > > On Tue, 9 Sep 2025 15:09:18 +1000
> > > David Gibson <david@gibson.dropbear.id.au> wrote:
> > >
> > > ...
> > >
> > > > > I think that a connector is something with a bunch of resources provided
> > > > > by the board where the connector is soldered. Those resources are wired
> > > > > to the connector and defined by the connector pinout.
> > > > >
> > > > > 3v3 ------- Pin 0
> > > > > i2c_scl ------- Pin 1
> > > > > i2c_sda ------- Pin 2
> > > > > gpio A ------- Pin 3
> > > > > gpio B ------- Pin 4
> > > > > gnd ------- Pin 5
> > > > >
> > > > > IMHO, this need to be described and defined in the base board and an addon can
> > > > > only reference resources wired and described by the connector node.
> > > >
> > > > Yes, that's exactly what I'm proposing too.
> > > >
> > > > > Now, questions are:
> > > > > - 1) How to describe a connector?
> > > > > - 2) How to reference resources provided at connector level from an add-on?
> > > >
> > > > Right.
> > > >
> > > > > Our current approach was:
> > > > > ---- base board DT ----
> > > > > connector0 {
> > > > > gpio-map = <0 &gpio0 12>, /* gpio A wired to gpio 12 of gpio0 controller */
> > > > > <1 &gpio2 10; /* gpio B wired to gpio 10 of gpio2 controller */
> > > > > i2c-one {
> > > > > compatible = "i2c-bus-extension";
> > > > > i2c-parent = <i2c5>; /* i2c-one wired to i2c5 controller */
> > > > > };
> > > > >
> > > > > i2c-two {
> > > > > compatible = "i2c-bus-extension";
> > > > > i2c-parent = <i2c6>; /* i2c-two wired to i2c6 controller */
> > > > > };
> > > > >
> > > > > /*
> > > > > * From the addon we need to reference:
> > > > > * - The connector itself,
> > > > > * - Maybe some pinctrl related to signals wired to the connector,
> > > > > * - In some cases the i2c bus (HDMI, ddc-i2c-bus = <&i2c-two>;)
> > > > > *
> > > > > * This was solved introducing the controversial export-symbols node.
> > > > > */
> > > >
> > > > I think the type of connector should also be named on both sides (with
> > > > 'compatible' or something like it).
> > >
> > > It makes sense.
> > >
> > > >
> > > > > };
> > > > >
> > > > > ---- addon board DT ----
> > > > > {
> > > > > some-node {
> > > > > compatible = "foo,bar";
> > > > > reset-gpios = <&connector 0>; /* gpio A used as a reset gpio */
> > > > > ddc-i2c-bus = <&i2c-two>;
> > > > > }
> > > > >
> > > > > i2c-one {
> > > > > eeprom@10 {
> > > > > compatible = "baz,eeprom"
> > > > > reg = 10;
> > > > > };
> > > > > };
> > > > > };
> > > > >
> > > > > The addon board DT can only be applied at a connector node.
> > > >
> > > > Right. This is not how overlays work now. By the nature of how
> > > > they're built they apply global updates to the base tree. That means
> > > > we need to spec a new way of describing addons that *is* restricted to
> > > > a particular connector slot (or slots, as Geert points out). Since we
> > > > have that opportunity, we should _not_ try to make it a minimal
> > > > extension to existing overlay format, but define a new and better
> > > > encoding, designed to meet the problems you're looking to address.
> > >
> > > On the kernel side, overlays can be applied at a specific node.
> > > The node is chosen when the overlay is apply.
> > > https://elixir.bootlin.com/linux/v6.16/source/drivers/of/overlay.c#L970
> >
> > Huh, I wasn't aware that had already been merged.
> >
> > > This allows to apply an overlay to a specific node without any modification
> > > of the overlay dtb (dtbo).
> > >
> > > Ajush proposed an update to support this feature in fdtoverlay
> > > https://lore.kernel.org/all/20250313-fdtoverlay-target-v1-0-dd5924e12bd3@beagleboard.org/
> >
> > Yes, and I've been disinclined to merge it because I think extending
> > overlays in this way, without a more wide-ranging redesign, is not a
> > great idea.
> >
> > > ...
> > > >
> > > > > > > > 3) bus-reg / bus-ranges
> > > > > > > >
> > > > > > > > One thing that makes connector plugins a bit awkward is that they
> > > > > > > > often need to add things to multiple buses on the host system (MMIO &
> > > > > > > > i2c for a simple case). This means that once resolved the plugin
> > > > > > > > isn't neatly a single subtree. That's one factor making removal
> > > > >
> > > > > It can be a single subtree if decoupling is present at connector node available
> > > > > in the base device tree.
> > > >
> > > > Right - allowing that decoupling is exactly what I'm proposing bus-reg
> > > > for. Note that the case of an addon that plugs into multiple
> > > > connectors that Geert pointed out complicates this again.
> > >
> > > Geert's use case needs to be clarified.
> > >
> > > Suppose a base board with 2 connectors:
> > > - connA
> > > - connB
> > >
> > > Case 1: Addons are independant
> > > +--------+
> > > connA <----> | AddonA |
> > > +--------+
> > > +--------+
> > > connB <---------------->| AddonB |
> > > +--------+
> > >
> > > With addonA and B two addon board each connected at one connector without any
> > > relationship between addon A and B
> > >
> > > Case 2: Only one Addons using ressources from both connector
> > >
> > > +------+
> > > connA <-----> |Addon |
> > > | |
> > > connB <-----> | |
> > > +------+
> >
> > Case 2 is what I'm talking about. Case 1 is the easy one.
> >
> > > The addon is connected to both connector and uses ressources from connA and
> > > connB in a dependent manner.
> > >
> > >
> > > The Case 2 can be solved using a connector that described both connA and connB.
> > > Having the split connA and connB is a mechanical point of view.
> >
> > I don't think that's a good solution, because it means you have to
> > make that decision at the board layer. If I understand his case
> > correctly, you have a board where you could do either case 1 or case 2
> > at runtime. We'd want the differences between these cases to only be
> > reflected on the addon device tree, not the base board device tree.
>
> Based on my understanding of Geer's use-case, I think decision at base
> board level will be needed.
>
> base board addon board
> connA +--------+conn1
> connB +--------+conn2
> connC +
>
> Or
>
> base board addon board
> connA +--------+conn1
> connB + ,---+conn2
> connC +---'

I'm not sure what you mean by a decision at the base board level. I
certainly don't think this should be in the base DT. I'd see this as
a runtime parameter needed when you apply/insert/activate the addon.
That's not really any different from addons with a single connector.
To allow for base boards with multiple instances of that connector
you'd need to specify at insert time which instance you're attaching
to.

That information could be supplied by the user, or in the case of
connectors that can be probed in some way (e.g. an EEPROM) the
connector driver could supply the information.

Which does make me think, considering this case says to me that
conceptualizing the choice of where to plug an addon as "subnode in
the base tree it goes under" is not a good idea. That's not really
going to work for a multiple connector addon.

So, we can specify where an addon goes by which "connector" it
attaches to. That connector would have an explicit entry in the base
tree, but it could reference multiple places to add nodes within that
base tree. Which means thinking about it that way, we might not need
'bus-reg' / 'bus-ranges' after all, and in some cases maybe not bus
extensions either.

Adding nodes in multiple places makes removal a bunch more complicated
(although it's still much better than overlays being able to modify
*anywhere*).

> Or any other combination that would match.
>
> From the addon board point of view, the only think we can
> say is "me, as an addon board, I need a connector of type 'foo' and a
> connector of type 'bar'".

Agreed.

> Also, at base board level, statically defined in the DT
> connA is described (type 'foo'), connB and connC are
> described (type 'bar').
>
> The choice to map connA to the type 'foo' connector expected by the addon
> and the choice to map connB or connC to the type 'bar' connector expected by
> the addon can only be done at runtime and probably with the help of a driver
> that have the knowledge of the 3 connectors.

Agreed.

> I have the feeling that the choice of physical connectors to which the addon
> board is connected to is a human choice when the board is connected.

Yes. Although if the addons have an EEPROM, or some other sort of ID
register, it may be possible for some connector drivers to probe this.

> > > Also adding and Addon on only one part (connA for instance) should not be an issue
> > > if the connector describe both parts.
> > >
> > > but well, here again I can miss something.
> > > Geert, can you provide details?
> > >
> > > ...
> > >
> > > > > > >
> > > > > > > There is an i2c-bus-extension [1] and spi-bus-extension proposal to do the
> > > > > > > same. But, if we can figure out a common way for all buses, that would be
> > > > > > > great.
> > > > >
> > > > > Exactly, this is the purpose of bus extensions.
> > > >
> > > > Right, but redefining it for each bus type seems silly.
> > >
> > > Nexus node properties are re-defined for each kind of resources (interrupt,
> > > gpio, pwm, ...).
> >
> > Yes, for historical reasons. In IEE1275 days, interrupts was
> > basically the only thing that worked this way. gpio and pwm were
> > added much later using interrupts as a model. If we were designing
> > from scratch having a common way of defining a nexus would make sense
> > too.
> >
> > > Why not for bus extensions.
> >
> > So that we don't need to keep defining new bindings for it.
> >
> > > Also I am pretty sure that some bus extension will need to define some
> > > properties specific to the bus related to the extension.
> >
> > Maybe, but then only those buses that specifically need it need the
> > extra binding.
> >
> > > > > Also, I don't thing that the 'ranges' property should be used for that purpose.
> > > > > The 'ranges' property is used to translate addresses from child addresses space
> > > > > to parent addresses space.
> > > >
> > > > The rationale for bus-ranges is that the add-on board could re-expose
> > > > one of the buses on the connector (say MMIO for simplicity) to several
> > > > chips physically included on the addon board. We don't want those
> > > > sub-chips to need different device nodes depending on whether they're
> > > > on an addon board or wired directly onto a main board. bus-ranges
> > > > would allow the root of the connector to create a subtree in which
> > > > regular MMIO (or whatever) devices can be described, and then routed
> > > > via the connector onto the bus on the main board.
> > >
> > > bus extensions supports this feature without bus-regs nor bus-ranges.
> >
> > bus-reg & bus-ranges allow it for any bus without having to create a
> > new binding.
> >
> > > A bus extension ended by a sub node in the connector node.
> > > Applying the addon DT at the connector node allow the addon to had
> > > subnode to the extension node.
> >
> > I don't really understand what point you're making here.
>
> Hardware:
> +------------------+ +----------------------+
> | base board | | addon board |
> | +------+ | | |
> | | i2c0 | +-----------+ +------------+ |
> | | +----+ connector +----+ eeprom @10 | |
> | | | +-----------+ +------------+ |
> | +------+ | | |
> +------------------+ +----------------------+
>
> base board DT:
> connector {
> i2c-ctrl {
> compatible = "i2c-bus-extension";
> i2c-parent = <&i2c0>;
> };
> };
>
> addon board DT:
> i2c-ctrl {
> eeprom@10 {
> compatible = "foo,eeprom";
> reg = <10>;
> };
> };
>
> Once addon board DT is applied at the base board connector node, the full
> DT is:
> connector {
> i2c-ctrl {
> compatible = "i2c-bus-extension";
> i2c-parent = <&i2c0>;
>
> eeprom@10 {
> compatible = "foo,eeprom";
> reg = <10>;
> };
> };
> };
>
> I probably didn't understand the bus-reg and bus-range usage.
> In order to clarify my understanding, using the same hardware example above,
> can you provide an example of description using bus-reg &
> bus-ranges?

Thoughts above suggest a different direction, but here's what I was
thinking before:

base board:

connector {
/export/ "i2c" &i2c0;
};

addon:
eeprom@10 {
compatible = "foo,eeprom";
bus-reg = <&i2c 0x10>;
}

Or, if the addon had multiple i2c devices, maybe something like:

board-i2c {
compatible = "i2c-simple-bridge";
bus-ranges = <&i2c 0 0x3ff>; /* Whole addr space */
eeprom@10 {
compatible = "foo,eeprom";
reg = <0x10>;
}
widget@20 {
compatible = "vendor,widget";
reg = <0x20>;
}
}

Writing that, I realise I2C introduces some complications for this.
Because it has #size-cells = <0>, ranges doesn't really work (without
listing every single address to be translated). Likewise, because we
always need the parent bus phandle, we can't use the trick of an empty
'ranges' to mean an identity mapping.

We could invent encodings to address those, but given the addon with
multiple connectors case provides another incentive for a single
connector to allow adding nodes in multiple (but strictly enumerated)
places in the base device tree provides a better approach.

--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]