Re: [PATCH v3] Add new `export-symbols` node

Ayush Singh <[email protected]> Wed, 30 Apr 2025 13:02:42 +0530
Newsgroups org.kernel.vger.devicetree-spec,org.kernel.vger.linux-devicetree
Message-ID <[email protected]>
On 4/30/25 01:21, Andrew Davis wrote:

> On 4/29/25 2:15 PM, Ayush Singh wrote:
>> On 4/11/25 13:30, Ayush Singh wrote:
>>
>>> `export-symbols` is designed to be a local replacement of global
>>> `__symbols__` allowing nodes to define aliases to nodes in a tree, 
>>> which
>>> will take precedence over the aliases defined in the global 
>>> `__symbols__`.
>>>
>>> Having a way to allow node local aliases helps in usecases such as
>>> connectors and addon-boards, by allowing decoupling of
>>> overlays/devicetree nodes of addon-board from the base connector.
>>>
>>> Reviewed-by: Herve Codina <[email protected]>
>>> Reviewed-by: Luca Ceresoli <[email protected]>
>>> Signed-off-by: Ayush Singh <[email protected]>
>>> ---
>>> This patch series follows the initial RFC [9] sent a few weeks ago. I
>>> will be reiterating the RFC here for anyone who might be seeing this 
>>> the
>>> first time, since there was not much feedback in that thread.
>>>
>>> The patch series adds export-symbols to base devicetree 
>>> specification to
>>> allow for support of base board + runtime connector setups using 
>>> devicetree
>>> overlays. The idea was actually proposed in the linux kernel mailing 
>>> list
>>> by Herve Codina [0] with the devicetree schema and linux kernel
>>> implementation. Initial implementations for devicetree compiler [1] and
>>> fdtoverlay [2] have also been sent to the mailing lists.
>>>
>>> Introduction
>>> *************
>>>
>>> There are a lot of setups, especially in embedded systems that 
>>> consist of
>>> a base connector and addon boards that can be connected to this 
>>> connector.
>>> Here are some examples:
>>> - MikroBus
>>> - GE SUNH
>>> - BeagleCapes, etc
>>>
>>> Some of these connectors have runtime detection capabilities (GE SUNH),
>>> while some do not (MikroBUS without 1-wire EEPROM). The goal is to 
>>> decouple
>>> the connector on base device tree with the overlay for addon boards. 
>>> This
>>> will allow having 1 overlay for each board that would work with 
>>> connector
>>> devicetree on any board.
>>>
>>> Linux kernel already provides APIs to apply overlays at specific nodes
>>> [10], and I have a patch series to have similar functionality in
>>> fdtoverlay [11]. This is to allow writing overlays for addon-boards,
>>> that will be expected to be applied to the connector nodes, instead of
>>> on the global tree.
>>>
>>> One of the issue was referencing resources available on the base board
>>> device tree from the addon overlay device tree. Using a nexus node [3]
>>> helps decoupling some resources like GPIO and PWM from the overlay.
>>> However, that still leaves things like pinmux, i2c adapter, etc.
>>>
>>> The `export-symbols` node solves this issue.
>>>
>>> The idea of export-symbols is to have something similar to the global
>>> `__symbols__` node but local to a specific node. Symbols listed in this
>>> export-symbols are local and visible only when an overlay is applied 
>>> on a
>>> node having an export-symbols subnode. This allows specifying the
>>> phandles to i2c adapter, pinmux, etc, per connector. Since the names
>>> used for these phandles for each connector can be standardized, it 
>>> would
>>> allow having the same addon-board overaly work for connectors on
>>> different boards (or multiple connectors on the same board).
>>>
>>> Note: `export-symbols` properties differ from __symbols__ since they 
>>> are
>>> phandles, not path references. This is much easier to work with in
>>> overlays as described in [7].
>>>
>>> Using export-symbols, our example becomes:
>>>
>>>      soc_gpio: gpio-controller {
>>>        #gpio-cells = <2>;
>>>      };
>>>
>>>      connector1: connector1 {
>>>          /*
>>>           * Nexus node for the GPIO available on the connector.
>>>           * GPIO 0 (Pin A GPIO) is connected to GPIO 12 of the SoC gpio
>>>           * controller
>>>           */
>>>          #gpio-cells = <2>;
>>>          gpio-map = <0 0 &soc_gpio 12 0>;
>>>          gpio-map-mask = <0xf 0x0>;
>>>          gpio-map-pass-thru = <0x0 0xf>;
>>>
>>>          export-symbols {
>>>         GPIO_CONNECTOR = <&connector1>;
>>>         PIN_33_GPIO_PINMUX = <&p1_33_gpio>;
>>>          };
>>>      };
>>>
>>> Our overlay can use thi
>>>
>>>     leds {
>>>        pinctrl-names = "default";
>>>        pinctrl-0 = <&PIN_33_GPIO_PINMUX>;
>>>
>>>        led-1 {
>>>            gpios = <&GPIO_CONNECTOR 33 GPIO_ACTIVE_HIGH>;
>>>        };
>>>     };
>>>
>>> It used the P1_33 pin in the connector it is applied on.
>>>
>>> A board with two connectors can be described with:
>>>
>>>      connector1: connector1 {
>>>          ...
>>>          export-symbols {
>>>         GPIO_CONNECTOR = <&connector1>;
>>>         PIN_33_GPIO_PINMUX = <&p1_33_gpio>;
>>>          };
>>>      };
>>>
>>>      connector2: connector2 {
>>>          ...
>>>          export-symbols {
>>>         GPIO_CONNECTOR = <&connector2>;
>>>         PIN_33_GPIO_PINMUX = <&p3_33_gpio>;
>>>          };
>>>      };
>>>
>>> In that case, the same overlay with unresolved `GPIO_CONNECTOR` and
>>> `PIN_33_GPIO_PINMUX` symbol can be applied on both connectors and the
>>> correct symbol resolution will be done.
>>>
>>> Alternatives
>>> *************
>>>
>>> Some alternative approaches that were considered:
>>>
>>> 1. Using aliases.
>>>
>>>     Currently, it is not possible to update aliases in device tree 
>>> overlays.
>>>     I sent a patch a few weeks ago to add this support [4]. However, 
>>> as was
>>>     outlined by Rob, this can break existing drivers that used the 
>>> unused
>>>     indexes for devices not present in the aliases list.
>>>
>>> 2. Add support for phandles in `__symbols__`
>>>
>>>     This has been discussed in the following patch series [5]. However,
>>>     since there is no way to distinguish between strings and 
>>> phandles in
>>>     devicetree (everything is bytestring), the type guessing is 
>>> awkward.
>>>     Also, the export-symbol solution is much more flexible than 
>>> extending
>>>     the old `__symbols__` node.
>>>
>>> 3. Add support for path reference resolution to overlays
>>>
>>>     An approach using `__symbols__` was proposed by Andrew Davis [6].
>>>     However, currently, it is difficult to support path reference 
>>> resolution
>>>     support to overlays [7]. This limitation makes it difficult to 
>>> support
>>>     connector chaining (MikroBUS -> Grove -> Addon board), which is 
>>> possible
>>>     in some connectors.
>>>
>>> Some other benefits to export-symbols
>>> **************************************
>>>
>>> 1. No need to enable generation of all symbols in base devicetree
>>>     Since the nodes used by connector are referenced by properties in
>>>     `export-symbols`, the symbols table entries for these nodes will be
>>>     generated, even if symbols generation is not enabled globally. This
>>>     can help save space, specially in constrained devices.
>>>
>>> 2. Enables scoping symbol resolution
>>>     Does not pollute the global symbols, and can be useful outside 
>>> addon
>>>     board setups.
>>>
>>> Why add to specification?
>>> **************************
>>>
>>> I would like the ability to share the addon board overlays with
>>> ZephyrRTOS, which also has boards that support MikroBUS (like 
>>> BeagleConnect
>>> Freedom [8]) and U-Boot. So it would make more sense if this node is 
>>> part
>>> of the specification instead of linux specific.
>>>
>>> [0]: 
>>> https://lore.kernel.org/all/[email protected]/
>>> [1]: 
>>> https://lore.kernel.org/all/[email protected]/
>>> [2]: 
>>> https://lore.kernel.org/devicetree-compiler/[email protected]/T/#t
>>> [3] 
>>> https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter2-devicetree-basics.rst#nexus-nodes-and-specifier-mapping
>>> [4]: 
>>> https://lore.kernel.org/all/[email protected]/T/#t
>>> [5]: 
>>> https://lore.kernel.org/devicetree-compiler/[email protected]/T/#mbbc181b0ef394b85b76b2024d7e209ebe70f7003
>>> [6]: https://lore.kernel.org/lkml/[email protected]/
>>> [7]: 
>>> https://lore.kernel.org/devicetree-compiler/[email protected]/T/#m8259c8754f680b9da7b91f7b7dd89f10da91d8ed
>>> [8]: https://www.beagleboard.org/boards/beagleconnect-freedom
>>> [9]: 
>>> https://lore.kernel.org/devicetree-spec/[email protected]/T/#mc339a0ae0c886ca46da0f7bb679518fa8b0b3007
>>> [10]: 
>>> https://docs.kernel.org/devicetree/kernel-api.html#c.of_overlay_fdt_apply
>>> [11]: 
>>> https://lore.kernel.org/devicetree-compiler/[email protected]/T/#t
>>>
>>> Best Regards,
>>> Ayush Singh
>>> ---
>>> Changes in v3:
>>> - Add trailer
>>> - CC linux-devicetree
>>> - Link to v2: 
>>> https://lore.kernel.org/r/[email protected]
>>>
>>> Changes in v2:
>>> - Improve examples. More focus on export-symbols and less on nexus 
>>> nodes
>>> - Fix typo.
>>> - Link to v1: 
>>> https://lore.kernel.org/r/[email protected]
>>> ---
>>>   source/chapter3-devicenodes.rst | 89 
>>> +++++++++++++++++++++++++++++++++++++++++
>>>   1 file changed, 89 insertions(+)
>>>
>>> diff --git a/source/chapter3-devicenodes.rst 
>>> b/source/chapter3-devicenodes.rst
>>> index 
>>> 8080321d6e60d6b1e86c81af86c6850246a0223b..2c3bbc2c81bacd71fcf3b389a31237344f995ba7 
>>> 100644
>>> --- a/source/chapter3-devicenodes.rst
>>> +++ b/source/chapter3-devicenodes.rst
>>> @@ -988,3 +988,92 @@ each with their own on-chip L2 and a shared L3.
>>>               };
>>>           };
>>>       };
>>> +
>>> +``*/export-symbols`` node
>>> +-------------------------
>>> +A devicetree node may have an export-symbols child node
>>> +(`*/export-symbols`) that defines one or more export-symbol 
>>> properties.
>>> +
>>> +Each property of the `export-symbols` node defines an alias local 
>>> to it's
>>> +parent. The property name specifies the alias name. The property value
>>> +specifies the phandle to a node in the devicetree. For example, the
>>> +property ``serial0 = <&main_uart0>`` defines ``serial0`` as the 
>>> local alias
>>> +to ``main_uart0``.
>>> +
>>> +Alias names shall be lowercase text strings of 1 to 31 characters 
>>> from the
>>> +following set of characters.
>>> +
>>> +.. tabularcolumns:: | c p{8cm} |
>>> +.. table:: Valid characters for alias names
>>> +
>>> +   ========= ================
>>> +   Character Description
>>> +   ========= ================
>>> +   0-9       digit
>>> +   a-z       lowercase letter
>>> +   \-        dash
>>> +   ========= ================
>>> +
>>> +An alias value is a phandle to a node in the devicetree.
>>> +
>>> +Resolution of nodes using `export-symbols` follows the following rules
>>> +depending on the context:
>>> +
>>> +No target involved
>>> +~~~~~~~~~~~~~~~~~~~
>>> +Properties of parent node use symbols from ``export-symbols``, but 
>>> none of
>>> +the subnodes will be able to use them. For example, the following 
>>> code will
>>> +resolve properly:
>>> +
>>> +.. code-block:: dts
>>> +
>>> +    / {
>>> +        parent {
>>> +            led = <&local_gpio 0 GPIO_ACTIVE_HIGH>;
>>> +
>>> +            export-symbols {
>>> +                local_gpio = <&gpio0>;
>>> +            };
>>> +        };
>>> +    }
>>> +
>>> +However, the code below is not valid:
>>> +
>>> +.. code-block:: dts
>>> +
>>> +    / {
>>> +        parent {
>>> +            child {
>>> +                /* child node cannot access export-symbols */
>>> +                led = <&local_gpio 0 GPIO_ACTIVE_HIGH>;
>>> +            };
>>> +
>>> +            export-symbols {
>>> +                local_gpio = <&gpio0>;
>>> +            };
>>> +        };
>>> +    }
>>> +
>>> +Target is used in the base devicetree or overlays
>>> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> +Any node/subnode property is free to use symbols from 
>>> ``export-symbols``
>>> +defined in the parent. To provide a concrete exampe, the following is
>>> +valid:
>>> +
>>> +.. code-block:: dts
>>> +
>>> +    / {
>>> +        parent {
>>> +            export-symbols {
>>> +                local_gpio = <&gpio0>;
>>> +            };
>>> +        };
>>> +    }
>>> +
>>> +    &parent {
>>> +        led = <&local_gpio 0 GPIO_ACTIVE_HIGH>;
>>> +
>>> +        child {
>>> +            led = <&local_gpio 0 GPIO_ACTIVE_HIGH>;
>>> +        };
>>> +    };
>>>
>>> ---
>>> base-commit: 5688e1c0b961d2ca5a32e3b624a9f4a9b433184f
>>> change-id: 20250225-export-symbols-3524f124cd93
>>>
>>> Best regards,
>>
>>
>> I have a very basic pocketbeagle2 connector driver with overlay for 
>> techlab cape [0]. It only uses export-symbols for pinmuxes for now, 
>> but might provide an example of use outside of nexus nodes.
>>
>>
>> [0]: https://github.com/Ayush1325/linux/tree/b4/beagle-cape
>>
>
> You have proven my point here. You were only able to model the GPIO
> attached devices: buttons and LEDs. Nothing else of this cape was
> modeled, nor could it be modeled with this solution.


For i2c, I first need to implement the i2c bus extensions [0]. Something 
similar for SPI, UART, etc. Somewhat long list of things.


>
> Your example fails to do even the most fundamental task: the overlay
> is still specific to just one host board. Go connect this cape to
> an original PocketBeagle and try to apply the overlay to its DTS..


Once I make the connector node a gpio and pwm nexus node, it will not be 
specific to just one host board. But yes, the current one is like that.


>
> What you did with "export-symbols" in this example could have been
> done exactly the same with normal overlays. These "examples" keep
> showing "what" the "export-symbols" node does, not "why" it is
> needed or better than just normal __symbols__.
>
> Andrew


No, it cannot be. When using `__symbols__`, the changes are not 
contained to a single devicetree nodes. As you can see even in the 
current form of the overlay, any modifications happen inside the 
connector node. Nothing outside of the connector node is modified at 
runtime.

I am not here to argue whether runtime global devicetree manipulation is 
an okay thing to do. I would be fine with it if upstream is okay with 
it. But neither sysfs based, nor configfs based patches for dynamic 
devicetree are being considered for that exact reason.

I am working from the assumption that upstream will not accept a global 
devicetree manipulation solution. So for local node based solution, 
export-symbols are essential. If I misunderstood something in this very 
basic assumption, then feel free to correct me.

Do note, that any solution cannot just stay as a static, apply using 
fdtoverlay kind of thing. It needs to allow for dynamic discovery using 
both EEPROM or something similar, and a fallback using sysfs or configfs.


Best Regards,

Ayush Singh


[0]: 
https://lore.kernel.org/devicetree-spec/[email protected]/T/#m5ae5b64b0e7fcae709127b99c8aa10fc28fb1ea8