| .. _dt-phandles: |
| |
| Phandles |
| ######## |
| |
| The devicetree concept of a *phandle* is very similar to pointers in |
| C. You can use phandles to refer to nodes in devicetree similarly to the way |
| you can use pointers to refer to structures in C. |
| |
| .. contents:: Contents |
| :local: |
| |
| Getting phandles |
| **************** |
| |
| The usual way to get a phandle for a devicetree node is from one of its node |
| labels. For example, with this devicetree: |
| |
| .. code-block:: DTS |
| |
| / { |
| lbl_a: node-1 {}; |
| lbl_b: lbl_c: node-2 {}; |
| }; |
| |
| You can write the phandle for: |
| |
| - ``/node-1`` as ``&lbl_a`` |
| - ``/node-2`` as either ``&lbl_b`` or ``&lbl_c`` |
| |
| Notice how the ``&nodelabel`` devicetree syntax is similar to the "address of" |
| C syntax. |
| |
| Using phandles |
| ************** |
| |
| .. note:: |
| |
| "Type" in this section refers to one of the type names documented in |
| :ref:`dt-bindings-properties` in the devicetree bindings documentation. |
| |
| Here are the main ways you will use phandles. |
| |
| One node: phandle type |
| ====================== |
| |
| You can use phandles to refer to ``node-b`` from ``node-a``, where ``node-b`` |
| is related to ``node-a`` in some way. |
| |
| One common example is when ``node-a`` represents some hardware that |
| generates an interrupt, and ``node-b`` represents the interrupt |
| controller that receives the asserted interrupt. In this case, you could |
| write: |
| |
| .. code-block:: DTS |
| |
| node_b: node-b { |
| interrupt-controller; |
| }; |
| |
| node-a { |
| interrupt-parent = <&node_b>; |
| }; |
| |
| This uses the standard ``interrupt-parent`` property defined in the |
| devicetree specification to capture the relationship between the two nodes. |
| |
| These properties have type ``phandle``. |
| |
| Zero or more nodes: phandles type |
| ================================= |
| |
| You can use phandles to make an array of references to other nodes. |
| |
| One common example occurs in :ref:`pin control <pinctrl-guide>`. Pin control |
| properties like ``pinctrl-0``, ``pinctrl-1`` etc. may contain multiple |
| phandles, each of which "points" to a node containing information related to |
| pin configuration for that hardware peripheral. Here's an example of six |
| phandles in a single property: |
| |
| .. code-block:: DTS |
| |
| pinctrl-0 = <&quadspi_clk_pe10 &quadspi_ncs_pe11 |
| &quadspi_bk1_io0_pe12 &quadspi_bk1_io1_pe13 |
| &quadspi_bk1_io2_pe14 &quadspi_bk1_io3_pe15>; |
| |
| These properties have type ``phandles``. |
| |
| Zero or more nodes with metadata: phandle-array type |
| ==================================================== |
| |
| You can use phandles to refer to and configure one or more resources that are |
| "owned" by some other node. |
| |
| This is the most complex case. There are examples and more details in the |
| next section. |
| |
| These properties have type ``phandle-array``. |
| |
| .. _dt-phandle-arrays: |
| |
| phandle-array properties |
| ************************ |
| |
| These properties are commonly used to specify a resource that is owned by |
| another node along with additional metadata about the resource. |
| |
| High level description |
| ====================== |
| |
| Usually, properties with this type are written like ``phandle-array-prop`` in |
| this example: |
| |
| .. code-block:: dts |
| |
| node { |
| phandle-array-prop = <&foo 1 2>, <&bar 3>, <&baz 4 5>; |
| }; |
| |
| That is, the property's value is written as a comma-separated sequence of |
| "groups", where each "group" is written inside of angle brackets (``< ... >``). |
| Each "group" starts with a phandle (``&foo``, ``&bar``, ``&baz``). The values |
| that follow the phandle in each "group" are called *specifiers*. There are |
| three specifiers in the above example: |
| |
| #. ``1 2`` |
| #. ``3`` |
| #. ``4 5`` |
| |
| The phandle in each "group" is used to "point" to the hardware that controls |
| the resource you are interested in. The specifier describes the resource |
| itself, along with any additional necessary metadata. |
| |
| The rest of this section describes a common example. Subsequent sections |
| document more rules about how to use phandle-array properties in practice. |
| |
| Example phandle-arrays: GPIOs |
| ============================= |
| |
| Perhaps the most common use case for phandle-array properties is specifying one |
| or more GPIOs on your SoC that another chip on your board connects to. For that |
| reason, we'll focus on that use case here. However, there are **many other use |
| cases** that are handled in devicetree with phandle-array properties. |
| |
| For example, consider an external chip with an interrupt pin that is connected |
| to a GPIO on your SoC. You will typically need to provide that GPIO's |
| information (GPIO controller and pin number) to the :ref:`device driver |
| <device_model_api>` for that chip. You usually also need to provide other |
| metadata about the GPIO, like whether it is active low or high, what kind of |
| internal pull resistor within the SoC should be enabled in order to communicate |
| with the device, etc., to the driver. |
| |
| In the devicetree, there will be a node that represents the GPIO controller |
| that controls a group of pins. This reflects the way GPIO IP blocks are usually |
| developed in hardware. Therefore, there is no single node in the devicetree |
| that represents a GPIO pin, and you can't use a single phandle to represent it. |
| |
| Instead, you would use a phandle-array property, like this: |
| |
| .. code-block:: |
| |
| my-external-ic { |
| irq-gpios = <&gpioX pin flags>; |
| }; |
| |
| In this example, ``irq-gpios`` is a phandle-array property with just one |
| "group" in its value. ``&gpioX`` is the phandle for the GPIO controller node |
| that controls the pin. ``pin`` is the pin number (0, 1, 2, ...). ``flags`` is a |
| bit mask describing pin metadata (for example ``(GPIO_ACTIVE_LOW | |
| GPIO_PULL_UP)``); see :zephyr_file:`include/zephyr/dt-bindings/gpio/gpio.h` for |
| more details. |
| |
| The device driver handling the ``my-external-ic`` node can then use the |
| ``irq-gpios`` property's value to set up interrupt handling for the chip as it |
| is used on your board. This lets you configure the device driver in devicetree, |
| without changing the driver's source code. |
| |
| Such properties can contain multiple values as well: |
| |
| .. code-block:: |
| |
| my-other-external-ic { |
| handshake-gpios = <&gpioX pinX flagsX>, <&gpioY pinY flagsY>; |
| }; |
| |
| The above example specifies two pins: |
| |
| - ``pinX`` on the GPIO controller with phandle ``&gpioX``, flags ``flagsX`` |
| - ``pinY`` on ``&gpioY``, flags ``flagsY`` |
| |
| You may be wondering how the "pin and flags" convention is established and |
| enforced. To answer this question, we'll need to introduce a concept called |
| specifier spaces before moving on to some information about devicetree |
| bindings. |
| |
| .. _dt-specifier-spaces: |
| |
| Specifier spaces |
| **************** |
| |
| *Specifier spaces* are a way to allow nodes to describe how you should |
| use them in phandle-array properties. |
| |
| We'll start with an abstract, high level description of how specifier spaces |
| work in DTS files, before moving on to a concrete example and providing |
| references to further reading for how this all works in practice using DTS |
| files and bindings files. |
| |
| High level description |
| ====================== |
| |
| As described above, a phandle-array property is a sequence of "groups" of |
| phandles followed by some number of cells: |
| |
| .. code-block:: dts |
| |
| node { |
| phandle-array-prop = <&foo 1 2>, <&bar 3>; |
| }; |
| |
| The cells that follow each phandle are called a *specifier*. In this example, |
| there are two specifiers: |
| |
| #. ``1 2``: two cells |
| #. ``3``: one cell |
| |
| Every phandle-array property has an associated *specifier space*. This sounds |
| complex, but it's really just a way to assign a meaning to the cells that |
| follow each phandle in a hardware specific way. Every specifier space has a |
| unique name. There are a few "standard" names for commonly used hardware, but |
| you can create your own as well. |
| |
| Devicetree nodes encode the number of cells that must appear in a specifier, by |
| name, using the ``#SPACE_NAME-cells`` property. For example, let's assume that |
| ``phandle-array-prop``\ 's specifier space is named ``baz``. Then we would need |
| the ``foo`` and ``bar`` nodes to have the following ``#baz-cells`` properties: |
| |
| .. code-block:: DTS |
| |
| foo: node@1000 { |
| #baz-cells = <2>; |
| }; |
| |
| bar: node@2000 { |
| #baz-cells = <1>; |
| }; |
| |
| Without the ``#baz-cells`` property, the devicetree tooling would not be able |
| to validate the number of cells in each specifier in ``phandle-array-prop``. |
| |
| This flexibility allows you to write down an array of hardware resources in a |
| single devicetree property, even though the amount of metadata you need to |
| describe each resource might be different for different nodes. |
| |
| A single node can also have different numbers of cells in different specifier |
| spaces. For example, we might have: |
| |
| .. code-block:: DTS |
| |
| foo: node@1000 { |
| #baz-cells = <2>; |
| #bob-cells = <1>; |
| }; |
| |
| |
| With that, if ``phandle-array-prop-2`` has specifier space ``bob``, we could |
| write: |
| |
| .. code-block:: DTS |
| |
| node { |
| phandle-array-prop = <&foo 1 2>, <&bar 3>; |
| phandle-array-prop-2 = <&foo 4>; |
| }; |
| |
| This flexibility allows you to have a node that manages multiple different |
| kinds of resources at the same time. The node describes the amount of metadata |
| needed to describe each kind of resource (how many cells are needed in each |
| case) using different ``#SPACE_NAME-cells`` properties. |
| |
| Example specifier space: gpio |
| ============================= |
| |
| From the above example, you're already familiar with how one specifier space |
| works: in the "gpio" space, specifiers almost always have two cells: |
| |
| #. a pin number |
| #. a bit mask of flags related to the pin |
| |
| Therefore, almost all GPIO controller nodes you will see in practice will look |
| like this: |
| |
| .. code-block:: DTS |
| |
| gpioX: gpio-controller@deadbeef { |
| gpio-controller; |
| #gpio-cells = <2>; |
| }; |
| |
| Associating properties with specifier spaces |
| ******************************************** |
| |
| Above, we have described that: |
| |
| - each phandle-array property has an associated specifier space |
| - specifier spaces are identified by name |
| - devicetree nodes use ``#SPECIFIER_NAME-cells`` properties to |
| configure the number of cells which must appear in a specifier |
| |
| In this section, we explain how phandle-array properties get their specifier |
| spaces. |
| |
| High level description |
| ====================== |
| |
| In general, a ``phandle-array`` property named ``foos`` implicitly has |
| specifier space ``foo``. For example: |
| |
| .. code-block:: YAML |
| |
| properties: |
| dmas: |
| type: phandle-array |
| pwms: |
| type: phandle-array |
| |
| The ``dmas`` property's specifier space is "dma". The ``pwm`` property's |
| specifier space is ``pwm``. |
| |
| Special case: GPIO |
| ================== |
| |
| ``*-gpios`` properties are special-cased so that e.g. ``foo-gpios`` resolves to |
| ``#gpio-cells`` rather than ``#foo-gpio-cells``. |
| |
| Manually specifying a space |
| =========================== |
| |
| You can manually specify the specifier space for any ``phandle-array`` |
| property. See :ref:`dt-bindings-specifier-space`. |
| |
| Naming the cells in a specifier |
| ******************************* |
| |
| You should name the cells in each specifier space your hardware supports when |
| writing bindings. For details on how to do this, see :ref:`dt-bindings-cells`. |
| |
| This allows C code to query information about and retrieve the values of cells |
| in a specifier by name using devicetree APIs like these: |
| |
| - :c:macro:`DT_PHA_BY_IDX` |
| - :c:macro:`DT_PHA_BY_NAME` |
| |
| This feature and these macros are used internally by numerous hardware-specific |
| APIs. Here are a few examples: |
| |
| - :c:macro:`DT_GPIO_PIN_BY_IDX` |
| - :c:macro:`DT_PWMS_CHANNEL_BY_IDX` |
| - :c:macro:`DT_DMAS_CELL_BY_NAME` |
| - :c:macro:`DT_IO_CHANNELS_INPUT_BY_IDX` |
| - :c:macro:`DT_CLOCKS_CELL_BY_NAME` |
| |
| See also |
| ******** |
| |
| - :ref:`dt-writing-property-values`: how to write phandles in devicetree |
| properties |
| |
| - :ref:`dt-bindings-properties`: how to write bindings for properties with |
| phandle types (``phandle``, ``phandles``, ``phandle-array``) |
| |
| - :ref:`dt-bindings-specifier-space`: how to manually specify a phandle-array |
| property's specifier space |