mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-04 20:42:40 +00:00
This is joint work with Kumar Gala (see signed-off-by). Document the changes to the generated node macros in macros.bnf, moving the old file to legacy-macros.bnf and putting it in its own section. The actual generated macros are now a low-level detail, so rewrite the foregoing sections as examples in terms of the new <devicetree.h> APIs. Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no> Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
1152 lines
37 KiB
ReStructuredText
1152 lines
37 KiB
ReStructuredText
.. _dt-legacy-macros:
|
|
|
|
Legacy devicetree macros
|
|
########################
|
|
|
|
.. warning::
|
|
|
|
You can still use the macros documented in this file, but support
|
|
for them will be removed eventually.
|
|
|
|
See :ref:`dt-from-c` for a usage guide for the new API.
|
|
|
|
This page describes legacy C preprocessor macros which Zephyr's :ref:`build
|
|
system <build_overview>` generates from a devicetree. It assumes you're
|
|
familiar with the concepts in :ref:`devicetree-intro` and :ref:`dt-bindings`.
|
|
|
|
These macros have somewhat inconsistent names, and their use in new code is
|
|
discouraged. See :ref:`dt-from-c` for the recommended API.
|
|
|
|
These macros are generated by the :ref:`devicetree scripts <dt-scripts>`,
|
|
start with ``DT_``, and use all-uppercase.
|
|
|
|
.. _dt-legacy-node-identifiers:
|
|
|
|
Legacy node identifiers
|
|
***********************
|
|
|
|
Macros generated from individual devicetree nodes or their properties start
|
|
with ``DT_<node>``, where ``<node>`` is a C identifier for the devicetree node.
|
|
This section describes the different ``<node>`` values in the legacy macros.
|
|
|
|
.. _dt-legacy-node-main-ex:
|
|
|
|
We'll use the following DTS fragment from the :ref:`FRDM-K64F <frdm_k64f>`
|
|
board's devicetree as the main example throughout this section.
|
|
|
|
.. code-block:: DTS
|
|
|
|
/ {
|
|
|
|
aliases {
|
|
i2c-0 = &i2c0;
|
|
};
|
|
|
|
soc {
|
|
i2c0: i2c@40066000 {
|
|
compatible = "nxp,kinetis-i2c";
|
|
reg = <0x40066000 0x1000>;
|
|
status = "okay";
|
|
/* ... */
|
|
|
|
fxos8700@1d {
|
|
compatible = "nxp,fxos8700";
|
|
status = "okay";
|
|
/* ... */
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
The binding for the "nxp,fxos8700" :ref:`compatible property
|
|
<dt-important-props>` contains this line:
|
|
|
|
.. code-block:: yaml
|
|
|
|
on-bus: i2c
|
|
|
|
The generated macros for this example can be found in a build directory for the
|
|
:ref:`FXOS8700 sample application <fxos8700>` built for the ``frdm_k64f``
|
|
board, in the file
|
|
:file:`build/zephyr/include/generated/devicetree_legacy_unfixed.h`.
|
|
|
|
Here is part of :file:`devicetree_legacy_unfixed.h` showing some of the macros
|
|
for the node labeled ``i2c0``. Notice the comment with the node's path in the
|
|
devicetree and its dependency relationships with other nodes.
|
|
|
|
.. code-block:: c
|
|
|
|
/*
|
|
* Devicetree node:
|
|
* /soc/i2c@40066000
|
|
*
|
|
* Binding (compatible = nxp,kinetis-i2c):
|
|
* $ZEPHYR_BASE/dts/bindings/i2c/nxp,kinetis-i2c.yaml
|
|
*
|
|
* Dependency Ordinal: 66
|
|
*
|
|
* Requires:
|
|
* 6 /soc
|
|
* ...
|
|
*
|
|
* Supports:
|
|
* 67 /soc/i2c@40066000/fxos8700@1d
|
|
*
|
|
* Description:
|
|
* Kinetis I2C node
|
|
*/
|
|
#define DT_NXP_KINETIS_I2C_40066000_BASE_ADDRESS 0x40066000
|
|
#define DT_NXP_KINETIS_I2C_40066000_SIZE 4096
|
|
#define DT_ALIAS_I2C_0_BASE_ADDRESS DT_NXP_KINETIS_I2C_40066000_BASE_ADDRESS
|
|
#define DT_ALIAS_I2C_0_SIZE DT_NXP_KINETIS_I2C_40066000_SIZE
|
|
#define DT_INST_0_NXP_KINETIS_I2C_BASE_ADDRESS DT_NXP_KINETIS_I2C_40066000_BASE_ADDRESS
|
|
#define DT_INST_0_NXP_KINETIS_I2C_SIZE DT_NXP_KINETIS_I2C_40066000_SIZE
|
|
|
|
Most macros are generated for individual nodes or their properties. Some macros
|
|
are generated for "global" information about the entire devicetree.
|
|
|
|
In this example, the node identifiers for ``i2c@40066000`` are:
|
|
|
|
- ``NXP_KINETIS_I2C_40066000``
|
|
- ``ALIAS_I2C_0``
|
|
- ``INST_0_NXP_KINETIS_I2C``
|
|
|
|
In general, the following ``DT_<node>`` macro prefixes are created for each
|
|
node.
|
|
|
|
``DT_(<bus>_)<compatible>_<unit-address>``
|
|
The node's compatible property converted to a C identifier, followed by its
|
|
:ref:`unit address <dt-unit-address>`. If the node has multiple compatible
|
|
strings, the one for its :ref:`matching binding <dt-binding-compat>` is
|
|
used.
|
|
|
|
If the node appears on a bus (and therefore has ``on-bus:`` in its binding,
|
|
like ``fxos8700@1d`` does), then the compatible string and unit address of
|
|
the bus node is put before the compatible string for the node itself. If
|
|
the node does not appear on a bus (no ``on-bus:`` in the binding, like
|
|
``i2c@40066000``) then there will be no ``<bus>_`` portion in the node
|
|
identifier.
|
|
|
|
The ``i2c@40066000`` node identifier is ``NXP_KINETIS_I2C_40066000``:
|
|
|
|
- there is no ``<bus>_`` portion
|
|
- ``<compatible>`` is ``NXP_KINETIS_I2C``, which is its
|
|
compatible ``"nxp,kinetis-i2c"`` converted to a C identifier
|
|
by uppercasing and replacing non-alphanumeric characters with underscores
|
|
- ``<unit-address>`` is ``40066000``
|
|
|
|
The ``fxos8700@1d`` node identifier is
|
|
``NXP_KINETIS_I2C_40066000_NXP_FXOS8700_1D``:
|
|
|
|
- ``<bus>`` is ``NXP_KINETIS_I2C_40066000``
|
|
- ``<compatible>`` is ``NXP_FXOS8700``
|
|
- ``<unit-address>`` is ``1D``
|
|
|
|
If the node has no unit address, the unit address of the parent node plus
|
|
the node's name converted to a C identifier is used for ``<unit-address>``
|
|
instead. If the parent node has no unit address either, the name of the
|
|
node is used as a fallback.
|
|
|
|
For example, take this DTS fragment:
|
|
|
|
.. code-block:: DTS
|
|
|
|
ethernet@400c0004 {
|
|
compatible = "nxp,kinetis-ethernet";
|
|
reg = <0x400c0004 0x620>;
|
|
status = "okay";
|
|
ptp {
|
|
compatible = "nxp,kinetis-ptp";
|
|
status = "okay";
|
|
interrupts = <0x52 0x0>;
|
|
};
|
|
};
|
|
|
|
The ``ptp`` node identifier is ``NXP_KINETIS_PTP_400C0004_PTP``:
|
|
|
|
- there is no ``<bus>_`` portion
|
|
- ``<compatible>`` is ``NXP_KINETIS_PTP``
|
|
- ``<unit-address>`` is ``400C0004_PTP``, which combines its parent's unit
|
|
address and the node's name converted to a C identifier
|
|
|
|
Here is another example DTS fragment.
|
|
|
|
.. code-block:: DTS
|
|
|
|
soc {
|
|
temp1 {
|
|
compatible = "nxp,kinetis-temperature";
|
|
status = "okay";
|
|
};
|
|
};
|
|
|
|
The ``temp1`` node identifier is ``NXP_KINETIS_TEMPERATURE_TEMP1``:
|
|
|
|
- there is no ``<bus>_`` portion
|
|
- ``<compatible>`` is ``NXP_KINETIS_TEMPERATURE``
|
|
- ``<unit-address>`` is the fallback value ``TEMP1``, because neither
|
|
the node nor its parent have a unit address
|
|
|
|
``DT_INST_<instance-number>_<compatible>``
|
|
An instance number for the node, combined with its compatible
|
|
converted to a C identifier.
|
|
|
|
The instance number is a unique index among all enabled
|
|
(``status = "okay"``) nodes that have a particular compatible string,
|
|
starting from zero.
|
|
|
|
The ``i2c@40066000`` node identifier in the :ref:`main example
|
|
<dt-legacy-node-main-ex>` is ``INST_0_NXP_KINETIS_I2C``:
|
|
|
|
- ``<instance-number>`` is 0 because it was the first node with compatible
|
|
"nxp,kinetis-i2c" that the devicetree scripts happened to discover as they
|
|
walked the tree
|
|
- ``<compatible>`` is ``NXP_KINETIS_I2C``
|
|
|
|
As another example, if there are two enabled nodes that have ``compatible =
|
|
"foo,uart"``, then these node identifiers get generated:
|
|
|
|
.. code-block:: none
|
|
|
|
INST_0_FOO_UART
|
|
INST_1_FOO_UART
|
|
|
|
.. warning::
|
|
|
|
Instance numbers are simple indexes among enabled nodes with the same
|
|
compatible. They **in no way reflect** any numbering scheme that might
|
|
exist in SoC documentation, node labels or unit addresses, or properties
|
|
of the /aliases node.
|
|
|
|
There is no guarantee that the same node will have the same instance
|
|
number between application builds. The only guarantee is that instance
|
|
numbers will start at 0, be contiguous, and be assigned for each enabled
|
|
node with a matching compatible.
|
|
|
|
``DT_ALIAS_<alias>``
|
|
Generated from the names of any properties in the ``/aliases`` node.
|
|
See :ref:`dt-alias-chosen` for an overview.
|
|
|
|
Here is a simple example.
|
|
|
|
.. code-block:: DTS
|
|
|
|
/ {
|
|
aliases {
|
|
uart-1 = &my_uart;
|
|
};
|
|
|
|
my_uart: uart@12345 { /* ... */ };
|
|
};
|
|
|
|
The ``uart@12345`` node identifier is ``ALIAS_UART_1``: ``<alias>`` is
|
|
``UART_1`` by uppercasing ``uart-1`` and replacing non-alphanumeric
|
|
characters with underscores. The alias refers to ``uart@12345`` using its
|
|
:ref:`label <dt-node-labels>` ``my_uart``.
|
|
|
|
For such a simple concept, dealing with aliases can be surprisingly tricky
|
|
due to multiple names which have only minor differences.
|
|
|
|
For a real-world example, the ``i2c@40066000`` node's alias identifier in
|
|
the :ref:`main example <dt-legacy-node-main-ex>` is ``ALIAS_I2C_0``:
|
|
``<alias>`` is ``I2C_0`` because the property ``i2c-0 = &i2c0;`` in the
|
|
``/aliases`` node "points at" ``i2c@40066000`` using its label ``i2c0``.
|
|
The alias name ``i2c-0`` is converted to C identifier ``I2C_0``.
|
|
|
|
The differences between ``i2c-0``, ``&i2c0``, ``i2c0``, and
|
|
``i2c@40006000`` in this example are very subtle and can be quite confusing
|
|
at first. Here is some more clarification:
|
|
|
|
- ``i2c-0`` is the *name* of a property in the ``/aliases`` node; this is
|
|
the alias name
|
|
- ``&i2c0`` is that property's *value*, which is the *phandle* of the
|
|
the node with label ``i2c0``
|
|
- ``i2c@40006000`` is the name of the node which happens to have label
|
|
``i2c0`` in this example
|
|
|
|
See the devicetree specification for full details.
|
|
|
|
.. note::
|
|
|
|
Another ``DT_<compatible>_<alias>`` form is also
|
|
generated for aliases. For the example above, assuming the compatible
|
|
string for the ``&uart1`` node is ``"foo,uart"``, this gives
|
|
``DT_FOO_UART_UART_1``.
|
|
|
|
.. _legacy-property-macros:
|
|
|
|
Macros generated for properties
|
|
*******************************
|
|
|
|
Macros for node property values have the form ``DT_<node>_<property>``, where
|
|
``<node>`` is a :ref:`node identifier <dt-legacy-node-identifiers>` and ``<property>``
|
|
identifies the property. The macros generated for a property usually depend on
|
|
its ``type:`` key in the matching devicetree binding.
|
|
|
|
The following general purpose rules apply in most cases:
|
|
|
|
- :ref:`generic-legacy-macros`
|
|
- :ref:`phandle-array-legacy-macros`
|
|
- :ref:`enum-legacy-macros`
|
|
|
|
However, some "special" properties get individual treatment:
|
|
|
|
- :ref:`reg_legacy_macros`
|
|
- :ref:`irq_legacy_macros`
|
|
- :ref:`clk_legacy_macros`
|
|
- :ref:`spi_cs_legacy_macros`
|
|
|
|
No macros are currently generated for properties with type ``phandle``,
|
|
``phandles``, ``path``, or ``compound``.
|
|
|
|
.. _generic-legacy-macros:
|
|
|
|
Generic property macros
|
|
=======================
|
|
|
|
This section documents the macros generated for non-"special" properties by
|
|
example. These properties are handled based on their devicetree binding
|
|
``type:`` keys.
|
|
|
|
In the generic case, the ``<property>`` portion of a ``DT_<node>_<property>``
|
|
macro begins with the property's name converted to a C identifier by
|
|
uppercasing it and replacing non-alphanumeric characters with underscores. For
|
|
example, a ``baud-rate`` property has a ``<property>`` portion that starts with
|
|
``BAUD_RATE``.
|
|
|
|
The table below gives the values generated for simple types. Note that an index
|
|
is added at the end of identifiers generated from properties with ``array`` or
|
|
``string-array`` type, and that ``array`` properties generate an additional
|
|
compound initializer (``{ ... }``).
|
|
|
|
|
|
|
|
+------------------+------------------------+----------------------------------------+
|
|
| Type | Property and value | Generated macros |
|
|
+==================+========================+========================================+
|
|
| ``int`` | ``foo = <1>`` | ``#define DT_<node>_FOO 1`` |
|
|
+------------------+------------------------+----------------------------------------+
|
|
| ``array`` | ``foo = <1 2>`` | | ``#define DT_<node>_FOO_0 1`` |
|
|
| | | | ``#define DT_<node>_FOO_1 2`` |
|
|
| | | | ``#define DT_<node>_FOO {1, 2}`` |
|
|
+------------------+------------------------+----------------------------------------+
|
|
| ``string`` | ``foo = "bar"`` | ``#define DT_<node>_FOO "bar"`` |
|
|
+------------------+------------------------+----------------------------------------+
|
|
| ``string-array`` | ``foo = "bar", "baz"`` | | ``#define DT_<node>_FOO_0 "bar"`` |
|
|
| | | | ``#define DT_<node>_FOO_1 "baz"`` |
|
|
+------------------+------------------------+----------------------------------------+
|
|
| ``uint8-array`` | ``foo = [01 02]`` | ``#define DT_<node>_FOO {0x01, 0x02}`` |
|
|
+------------------+------------------------+----------------------------------------+
|
|
|
|
For ``type: boolean``, the generated macro is set to 1 if the property exists
|
|
on the node, and to 0 otherwise:
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_<node>_FOO 0/1
|
|
|
|
For non-boolean types the property macros are not generated if the binding's
|
|
``category`` is ``optional`` and the property is not present in the devicetree
|
|
source.
|
|
|
|
.. _phandle-array-legacy-macros:
|
|
|
|
Properties with type ``phandle-array``
|
|
======================================
|
|
|
|
The generation for properties with type ``phandle-array`` is the most complex.
|
|
To understand it, it is a good idea to first go through the documentation for
|
|
``phandle-array`` in :ref:`dt-bindings`.
|
|
|
|
Take the following devicetree nodes and binding contents as an example:
|
|
|
|
.. code-block:: DTS
|
|
:caption: Devicetree nodes for PWM controllers
|
|
|
|
pwm_ctrl_0: pwm-controller-0 {
|
|
label = "pwm-0";
|
|
#pwm-cells = <2>;
|
|
/* ... */
|
|
};
|
|
|
|
pwm_ctrl_1: pwm-controller-1 {
|
|
label = "pwm-1";
|
|
#pwm-cells = <2>;
|
|
/* ... */
|
|
};
|
|
|
|
.. code-block:: yaml
|
|
:caption: ``pwm-cells`` declaration in binding for ``vendor,pwm-controller``
|
|
|
|
pwm-cells:
|
|
- channel
|
|
- period
|
|
|
|
Assume the property assignment looks like this:
|
|
|
|
.. code-block:: DTS
|
|
|
|
pwm-user@0 {
|
|
status = "okay";
|
|
pwms = <&pwm_ctrl_0 1 10>, <&pwm_ctrl_1 2 20>;
|
|
pwm-names = "first", "second";
|
|
/* ... */
|
|
};
|
|
|
|
These macros then get generated.
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_<node>_PWMS_CONTROLLER_0 "pwm-0"
|
|
#define DT_<node>_PWMS_CHANNEL_0 1
|
|
#define DT_<node>_PWMS_PERIOD_0 10
|
|
|
|
#define DT_<node>_PWMS_CONTROLLER_1 "pwm-1"
|
|
#define DT_<node>_PWMS_CHANNEL_1 2
|
|
#define DT_<node>_PWMS_PERIOD_1 20
|
|
|
|
#define DT_<node>_PWMS_NAMES_0 "first"
|
|
#define DT_<node>_PWMS_NAMES_1 "second"
|
|
|
|
#define DT_<node>_FIRST_PWMS_CONTROLLER DT_<node>_PWMS_CONTROLLER_0
|
|
#define DT_<node>_FIRST_PWMS_CHANNEL DT_<node>_PWMS_CHANNEL_0
|
|
#define DT_<node>_FIRST_PWMS_PERIOD DT_<node>_PWMS_PERIOD_0
|
|
|
|
#define DT_<node>_SECOND_PWMS_CONTROLLER DT_<node>_PWMS_CONTROLLER_1
|
|
#define DT_<node>_SECOND_PWMS_CHANNEL DT_<node>_PWMS_CHANNEL_1
|
|
#define DT_<node>_SECOND_PWMS_PERIOD DT_<node>_PWMS_PERIOD_1
|
|
|
|
/* Initializers */
|
|
|
|
#define DT_<node>_PWMS_0 {"pwm-0", 1, 10}
|
|
#define DT_<node>_PWMS_1 {"pwm-1", 2, 20}
|
|
#define DT_<node>_PWMS {DT_<node>_PWMS_0, DT_<node>_PWMS_1}
|
|
#define DT_<node>_PWMS_COUNT 2
|
|
|
|
Macros with a ``*_0`` suffix deal with the first entry in ``pwms``
|
|
(``<&pwm_ctrl_0 1 10>``). Macros with a ``*_1`` suffix deal with the second
|
|
entry (``<&pwm_ctrl_1 2 20>``). The index suffix is only added if there's more
|
|
than one entry in the property.
|
|
|
|
The ``DT_<node>_PWMS_CONTROLLER(_<index>)`` macros are set to the string from
|
|
the ``label`` property of the referenced controller. The
|
|
``DT_<node>_PWMS_CHANNEL(_<index>)`` and ``DT_<node>_PWMS_PERIOD(_<index>)``
|
|
macros are set to the values of the corresponding cells in the ``pwms``
|
|
property, with macro names generated from the strings in ``pwm-cells:`` in
|
|
the binding for the controller.
|
|
|
|
The macros in the ``/* Initializers */`` section provide the same information
|
|
as ``DT_<node>_PWMS_{CONTROLLER,CHANNEL,PERIOD}(_<index>)``, except as compound
|
|
initializers that can be used to initialize C ``struct`` variables.
|
|
|
|
If a ``pwm-names`` property exists on the same node as ``pwms`` (more
|
|
generally, if a ``foo-names`` property is defined next to a ``foo`` property
|
|
with type ``phandle-array``), it gives a list of strings that name each entry
|
|
in ``pwms``. The names are used to generate extra macro names with the name
|
|
instead of an index, like ``DT_<node>_FIRST_PWMS_CONTROLLER`` above.
|
|
|
|
.. _enum-legacy-macros:
|
|
|
|
Properties with ``enum:`` in the binding
|
|
========================================
|
|
|
|
Properties declared with an ``enum:`` key in their binding generate a macro
|
|
that gives the the zero-based index of the property's value in the ``enum:``
|
|
list.
|
|
|
|
Take this binding declaration as an example:
|
|
|
|
.. code-block:: yaml
|
|
|
|
properties:
|
|
foo:
|
|
type: string
|
|
enum:
|
|
- one
|
|
- two
|
|
- three
|
|
|
|
The property ``foo = "three"`` then generates this macro:
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_<node>_FOO_ENUM 2
|
|
|
|
.. _reg_legacy_macros:
|
|
|
|
``reg`` property macros
|
|
=======================
|
|
|
|
``reg`` properties generate the macros ``DT_<node>_BASE_ADDRESS(_<index>)`` and
|
|
``DT_<node>_SIZE(_<index>)``. ``<index>`` is a numeric index starting from 0,
|
|
which is only added if there's more than one register defined in ``reg``.
|
|
|
|
For example, the ``reg = <0x4004700 0x1060>`` assignment in the example
|
|
devicetree above gives these macros:
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_<node>_BASE_ADDRESS 0x40047000
|
|
#define DT_<node>_SIZE 4192
|
|
|
|
.. note::
|
|
|
|
The length of the address and size portions of ``reg`` is determined from
|
|
the ``#address-cells`` and ``#size-cells`` properties. See the devicetree
|
|
specification for more information.
|
|
|
|
In this case, both ``#address-cells`` and ``#size-cells`` are 1, and there's
|
|
just a single register in ``reg``. Four numbers would give two registers.
|
|
|
|
If a ``reg-names`` property exists on the same node as ``reg``, it gives a list
|
|
of strings that names each register in ``reg``. The names are used to generate
|
|
extra macros. For example, ``reg-names = "foo"`` together with the example node
|
|
generates these macros:
|
|
|
|
.. code-block:: c
|
|
|
|
#define DT_<node>_FOO_BASE_ADDRESS 0x40047000
|
|
#define DT_<node>_FOO_SIZE 4192
|
|
|
|
.. _irq_legacy_macros:
|
|
|
|
``interrupts`` property macros
|
|
==============================
|
|
|
|
Take these devicetree nodes as an example:
|
|
|
|
.. code-block:: DTS
|
|
|
|
timer@123 {
|
|
interrupts = <1 5 2 6>;
|
|
interrupt-parent = <&intc>;
|
|
/* ... */
|
|
};
|
|
|
|
intc: interrupt-controller { /* ... */ };
|
|
|
|
Assume that the binding for ``interrupt-controller`` has these lines:
|
|
|
|
.. code-block:: yaml
|
|
|
|
interrupt-cells:
|
|
- irq
|
|
- priority
|
|
|
|
Then these macros get generated for ``timer@123``:
|
|
|
|
.. code-block:: c
|
|
|
|
#define DT_<node>_IRQ_0 1
|
|
#define DT_<node>_IRQ_0_PRIORITY 5
|
|
#define DT_<node>_IRQ_1 2
|
|
#define DT_<node>_IRQ_1_PRIORITY 6
|
|
|
|
These macros have the the format ``DT_<node>_IRQ_<index>(_<name>)``, where
|
|
``<node>`` is the node identifier for ``timer@123``, ``<index>`` is an index
|
|
that identifies the particular interrupt, and ``<name>`` is the identifier for
|
|
the cell value (a number within ``interrupts = <...>``), taken from the
|
|
binding.
|
|
|
|
Bindings for interrupt controllers are expected to declare a cell named ``irq``
|
|
in ``interrupt-cells``, giving the interrupt number. The ``_<name>`` suffix is
|
|
skipped for macros generated from ``irq`` cells, which is why there's e.g. a
|
|
``DT_<node>_IRQ_0`` macro and no ``DT_<node>_IRQ_0_IRQ`` macro.
|
|
|
|
If the interrupt controller in turn generates other interrupts, Zephyr uses a
|
|
multi-level interrupt encoding for the interrupt numbers at each level. See
|
|
:ref:`multi_level_interrupts` for more information.
|
|
|
|
There is also hard-coded logic for mapping Arm GIC interrupts to linear IRQ
|
|
numbers. See the source code for details.
|
|
|
|
Additional macros that use names instead of indices for interrupts can be
|
|
generated by including an ``interrupt-names`` property on the
|
|
interrupt-generating node. For example, this node:
|
|
|
|
.. code-block:: DTS
|
|
|
|
timer@456 {
|
|
interrupts = <10 50 20 60>;
|
|
interrupt-parent = <&intc>;
|
|
interrupt-names = "timer-a", "timer-b";
|
|
/* ... */
|
|
};
|
|
|
|
generates these macros:
|
|
|
|
.. code-block:: c
|
|
|
|
#define DT_<node>_IRQ_TIMER_A 1
|
|
#define DT_<node>_IRQ_TIMER_A_PRIORITY 5
|
|
#define DT_<node>_IRQ_TIMER_B 2
|
|
#define DT_<node>_IRQ_TIMER_B_PRIORITY 6
|
|
|
|
.. _clk_legacy_macros:
|
|
|
|
``clocks`` property macros
|
|
==========================
|
|
|
|
``clocks`` work the same as other :ref:`phandle-array-legacy-macros`, except the
|
|
generated macros have ``CLOCK`` in them instead of ``CLOCKS``, giving for
|
|
example ``DT_<node>_CLOCK_CONTROLLER_0`` instead of
|
|
``DT_<node>_CLOCKS_CONTROLLER_0``.
|
|
|
|
If a ``clocks`` controller node has a ``"fixed-clock"`` compatible, it
|
|
must also have a ``clock-frequency`` property giving its frequency in Hertz.
|
|
In this case, an additional macro is generated:
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_<node>_CLOCKS_CLOCK_FREQUENCY <frequency>
|
|
|
|
.. _spi_cs_legacy_macros:
|
|
|
|
``cs-gpios`` property macros
|
|
============================
|
|
|
|
.. boards/arm/sensortile_box/sensortile_box.dts has a real-world example
|
|
|
|
Take these devicetree nodes as an example. where the binding for
|
|
``vendor,spi-controller`` is assumed to have ``bus: spi``, and the bindings for
|
|
the SPI slaves are assumed to have ``on-bus: spi``:
|
|
|
|
.. code-block:: DTS
|
|
|
|
gpioa: gpio@400ff000 {
|
|
compatible = "vendor,gpio-ctlr";
|
|
reg = <0x400ff000 0x40>;
|
|
label = "GPIOA";
|
|
gpio-controller;
|
|
#gpio-cells = <0x1>;
|
|
};
|
|
|
|
spi {
|
|
compatible = "vendor,spi-controller";
|
|
cs-gpios = <&gpioa 1>, <&gpioa 2>;
|
|
spi-slave@0 {
|
|
compatible = "vendor,foo-spi-device";
|
|
reg = <0>;
|
|
};
|
|
spi-slave@1 {
|
|
compatible = "vendor,bar-spi-device";
|
|
reg = <1>;
|
|
};
|
|
};
|
|
|
|
Here, the unit address of the SPI slaves (0 and 1) is taken as a chip select
|
|
number, which is used as an index into ``cs-gpios`` (a ``phandle-array``).
|
|
``spi-slave@0`` is matched to ``<&gpioa 1>``, and ``spi-slave@1`` to
|
|
``<&gpiob 2>``.
|
|
|
|
The output for ``spi-slave@0`` and ``spi-slave@1`` is the same as if the
|
|
devicetree had looked like this:
|
|
|
|
.. code-block:: DTS
|
|
|
|
gpioa: gpio@400ff000 {
|
|
compatible = "vendor,gpio-ctlr";
|
|
reg = <0x400ff000 0x40>;
|
|
label = "GPIOA";
|
|
gpio-controller;
|
|
#gpio-cells = <1>;
|
|
};
|
|
|
|
spi {
|
|
compatible = "vendor,spi-controller";
|
|
spi-slave@0 {
|
|
compatible = "vendor,foo-spi-device";
|
|
reg = <0>;
|
|
cs-gpios = <&gpioa 1>;
|
|
};
|
|
spi-slave@1 {
|
|
compatible = "vendor,bar-spi-device";
|
|
reg = <1>;
|
|
cs-gpios = <&gpioa 2>;
|
|
};
|
|
};
|
|
|
|
See the ``phandle-array`` section in :ref:`generic-legacy-macros` for more
|
|
information.
|
|
|
|
For example, since the node labeled ``gpioa`` has property
|
|
``label = "GPIOA"`` and 1 and 2 are pin numbers, macros like the following
|
|
will be generated for ``spi-slave@0``:
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_<node>_CS_GPIOS_CONTROLLER "GPIOA"
|
|
#define DT_<node>_CS_GPIOS_PIN 1
|
|
|
|
.. _other-macros:
|
|
|
|
Other macros
|
|
************
|
|
|
|
These are generated in addition to macros generated for :ref:`properties
|
|
<legacy-property-macros>`.
|
|
|
|
- :ref:`dt-existence-legacy-macros`
|
|
- :ref:`bus-legacy-macros`
|
|
- :ref:`flash-legacy-macros`
|
|
|
|
.. _dt-existence-legacy-macros:
|
|
|
|
Node existence flags
|
|
====================
|
|
|
|
An "existence flag" is a macro which is defined when the devicetree contains
|
|
nodes matching some criterion.
|
|
|
|
Existence flags are generated for each compatible property that appears on an
|
|
enabled node:
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_COMPAT_<compatible> 1
|
|
|
|
An existence flag is also written for all enabled nodes with a matching
|
|
compatible:
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_INST_<instance-number>_<compatible> 1
|
|
|
|
For the ``i2c@40066000`` node in the :ref:`example <dt-legacy-node-main-ex>` above,
|
|
assuming the node is the first node with ``compatible = "nxp,kinetis-i2c"``,
|
|
the following existence flags would be generated:
|
|
|
|
.. code-block:: c
|
|
|
|
/* At least one node had compatible nxp,kinetis-i2c: */
|
|
#define DT_COMPAT_NXP_KINETIS_I2C 1
|
|
|
|
/* Instance 0 of compatible nxp,kinetis-i2c exists: */
|
|
#define DT_INST_0_NXP_KINETIS_I2C 1
|
|
|
|
If additional nodes had compatible ``nxp,kinetis-i2c``, additional existence
|
|
flags would be generated:
|
|
|
|
.. code-block:: c
|
|
|
|
#define DT_INST_1_NXP_KINETIS_I2C 1
|
|
#define DT_INST_2_NXP_KINETIS_I2C 1
|
|
/* ... and so on, one for each node with this compatible. */
|
|
|
|
.. _bus-legacy-macros:
|
|
|
|
Bus-related macros
|
|
==================
|
|
|
|
These macros get generated for nodes that appear on buses (have ``on-bus:`` in
|
|
their binding):
|
|
|
|
.. code-block:: none
|
|
|
|
#define DT_<node>_BUS_NAME "<bus-label>"
|
|
#define DT_<compatible>_BUS_<bus-name> 1
|
|
|
|
``<bus-label>`` is taken from the ``label`` property on the bus node, which
|
|
must exist. ``<bus-name>`` is the identifier for the bus as given in
|
|
``on-bus:`` in the binding.
|
|
|
|
.. _flash-legacy-macros:
|
|
|
|
Macros generated from flash partitions
|
|
======================================
|
|
|
|
.. note::
|
|
|
|
This section only covers flash partitions. See :ref:`dt-alias-chosen` for
|
|
some other flash-related macros that get generated from devicetree, via
|
|
``/chosen``.
|
|
|
|
If a node has a name that looks like ``partition@<unit-address>``, it is
|
|
assumed to represent a flash partition.
|
|
|
|
Assume the devicetree has this:
|
|
|
|
.. code-block:: DTS
|
|
|
|
flash@0 {
|
|
/* ... */
|
|
label = "foo-flash";
|
|
|
|
partitions {
|
|
/* ... */
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
boot_partition: partition@0 {
|
|
label = "mcuboot";
|
|
reg = <0x00000000 0x00010000>;
|
|
read-only;
|
|
};
|
|
slot0_partition: partition@10000 {
|
|
label = "image-0";
|
|
reg = <0x00010000 0x00020000
|
|
0x00040000 0x00010000>;
|
|
};
|
|
/* ... */
|
|
};
|
|
|
|
These macros then get generated:
|
|
|
|
.. code-block:: c
|
|
|
|
#define DT_FLASH_AREA_MCUBOOT_ID 0
|
|
#define DT_FLASH_AREA_MCUBOOT_READ_ONLY 1
|
|
#define DT_FLASH_AREA_MCUBOOT_OFFSET_0 0x0
|
|
#define DT_FLASH_AREA_MCUBOOT_SIZE_0 0x10000
|
|
#define DT_FLASH_AREA_MCUBOOT_OFFSET DT_FLASH_AREA_MCUBOOT_OFFSET_0
|
|
#define DT_FLASH_AREA_MCUBOOT_SIZE DT_FLASH_AREA_MCUBOOT_SIZE_0
|
|
#define DT_FLASH_AREA_MCUBOOT_DEV "foo-flash"
|
|
|
|
#define DT_FLASH_AREA_IMAGE_0_ID 0
|
|
#define DT_FLASH_AREA_IMAGE_0_READ_ONLY 1
|
|
#define DT_FLASH_AREA_IMAGE_0_OFFSET_0 0x10000
|
|
#define DT_FLASH_AREA_IMAGE_0_SIZE_0 0x20000
|
|
#define DT_FLASH_AREA_IMAGE_0_OFFSET_1 0x40000
|
|
#define DT_FLASH_AREA_IMAGE_0_SIZE_1 0x10000
|
|
#define DT_FLASH_AREA_IMAGE_0_OFFSET DT_FLASH_AREA_IMAGE_0_OFFSET_0
|
|
#define DT_FLASH_AREA_IMAGE_0_SIZE DT_FLASH_AREA_IMAGE_0_SIZE_0
|
|
#define DT_FLASH_AREA_IMAGE_0_DEV "foo-flash"
|
|
|
|
/* Same macros, just with index instead of label */
|
|
#define DT_FLASH_AREA_0_ID 0
|
|
#define DT_FLASH_AREA_0_READ_ONLY 1
|
|
...
|
|
|
|
The ``*_ID`` macro gives the zero-based index for the partition.
|
|
|
|
The ``*_OFFSET_<index>`` and ``*_SIZE_<index>`` macros give the offset and size
|
|
for each partition, derived from ``reg``. The ``*_OFFSET`` and ``*_SIZE``
|
|
macros, with no index, are aliases that point to the first sector (with index
|
|
0).
|
|
|
|
.. _dt-alias-chosen:
|
|
|
|
``aliases`` and ``chosen`` nodes
|
|
================================
|
|
|
|
Using an alias with a common name for a particular node makes it easier for you
|
|
to write board-independent source code. Devicetree ``aliases`` nodes are used
|
|
for this purpose, by mapping certain generic, commonly used names to specific
|
|
hardware resources:
|
|
|
|
.. code-block:: yaml
|
|
|
|
aliases {
|
|
led0 = &led0;
|
|
sw0 = &button0;
|
|
sw1 = &button1;
|
|
uart-0 = &uart0;
|
|
uart-1 = &uart1;
|
|
};
|
|
|
|
Certain software subsystems require a specific hardware resource to bind to in
|
|
order to function properly. Some of those subsystems are used with many
|
|
different boards, which makes using the devicetree ``chosen`` nodes very
|
|
convenient. By doing so, the software subsystem can rely on having the specific
|
|
hardware peripheral assigned to it. In the following example we bind the shell
|
|
to ``uart1`` in this board:
|
|
|
|
.. code-block:: yaml
|
|
|
|
chosen {
|
|
zephyr,shell-uart = &uart1;
|
|
};
|
|
|
|
The table below lists Zephyr-specific ``chosen`` properties. The macro
|
|
identifiers that start with ``CONFIG_*`` are generated from Kconfig symbols
|
|
that reference devicetree data via the :ref:`Kconfig preprocessor
|
|
<kconfig-functions>`.
|
|
|
|
.. note::
|
|
|
|
Since the particular devicetree isn't known while generating Kconfig
|
|
documentation, the Kconfig symbol reference pages linked below do not
|
|
include information derived from devicetree. Instead, you might see e.g. an
|
|
empty default:
|
|
|
|
.. code-block:: none
|
|
|
|
default "" if HAS_DTS
|
|
|
|
To see how the preprocessor is used for a symbol, look it up directly in the
|
|
:file:`Kconfig` file where it is defined instead. The reference page for the
|
|
symbol gives the definition location.
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
|
|
* - ``chosen`` node name
|
|
- Generated macros
|
|
|
|
* - ``zephyr,flash``
|
|
- ``DT_FLASH_BASE_ADDRESS``/``DT_FLASH_SIZE``/``DT_FLASH_ERASE_BLOCK_SIZE``/``DT_FLASH_WRITE_BLOCK_SIZE``
|
|
* - ``zephyr,code-partition``
|
|
- ``DT_CODE_PARTITION_OFFSET``/``DT_CODE_PARTITION_SIZE``
|
|
* - ``zephyr,sram``
|
|
- :option:`CONFIG_SRAM_BASE_ADDRESS`/:option:`CONFIG_SRAM_SIZE`
|
|
* - ``zephyr,ccm``
|
|
- ``DT_CCM_BASE_ADDRESS``/``DT_CCM_SIZE``
|
|
* - ``zephyr,dtcm``
|
|
- ``DT_DTCM_BASE_ADDRESS``/``DT_DTCM_SIZE``
|
|
* - ``zephyr,ipc_shm``
|
|
- ``DT_IPC_SHM_BASE_ADDRESS``/``DT_IPC_SHM_SIZE``
|
|
* - ``zephyr,console``
|
|
- :option:`CONFIG_UART_CONSOLE_ON_DEV_NAME`
|
|
* - ``zephyr,shell-uart``
|
|
- :option:`CONFIG_UART_SHELL_ON_DEV_NAME`
|
|
* - ``zephyr,bt-uart``
|
|
- :option:`CONFIG_BT_UART_ON_DEV_NAME`
|
|
* - ``zephyr,uart-pipe``
|
|
- :option:`CONFIG_UART_PIPE_ON_DEV_NAME`
|
|
* - ``zephyr,bt-mon-uart``
|
|
- :option:`CONFIG_BT_MONITOR_ON_DEV_NAME`
|
|
* - ``zephyr,bt-c2h-uart``
|
|
- :option:`CONFIG_BT_CTLR_TO_HOST_UART_DEV_NAME`
|
|
* - ``zephyr,uart-mcumgr``
|
|
- :option:`CONFIG_UART_MCUMGR_ON_DEV_NAME`
|
|
|
|
.. _legacy_flash_partitions:
|
|
|
|
Legacy flash partitions
|
|
***********************
|
|
|
|
Devicetree can be used to describe a partition layout for any flash
|
|
device in the system.
|
|
|
|
Two important uses for this mechanism are:
|
|
|
|
#. To force the Zephyr image to be linked into a specific area on
|
|
Flash.
|
|
|
|
This is useful, for example, if the Zephyr image must be linked at
|
|
some offset from the flash device's start, to be loaded by a
|
|
bootloader at runtime.
|
|
|
|
#. To generate compile-time definitions for the partition layout,
|
|
which can be shared by Zephyr subsystems and applications to
|
|
operate on specific areas in flash.
|
|
|
|
This is useful, for example, to create areas for storing file
|
|
systems or other persistent state. These defines only describe the
|
|
boundaries of each partition. They don't, for example, initialize a
|
|
partition's flash contents with a file system.
|
|
|
|
Partitions are generally managed using device tree overlays. See
|
|
:ref:`set-devicetree-overlays` for examples.
|
|
|
|
Defining Partitions
|
|
===================
|
|
|
|
The partition layout for a flash device is described inside the
|
|
``partitions`` child node of the flash device's node in the device
|
|
tree.
|
|
|
|
You can define partitions for any flash device on the system.
|
|
|
|
Most Zephyr-supported SoCs with flash support in device tree
|
|
will define a label ``flash0``. This label refers to the primary
|
|
on-die flash programmed to run Zephyr. To generate partitions
|
|
for this device, add the following snippet to a device tree overlay
|
|
file:
|
|
|
|
.. code-block:: DTS
|
|
|
|
&flash0 {
|
|
partitions {
|
|
compatible = "fixed-partitions";
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
/* Define your partitions here; see below */
|
|
};
|
|
};
|
|
|
|
To define partitions for another flash device, modify the above to
|
|
either use its label or provide a complete path to the flash device
|
|
node in the device tree.
|
|
|
|
The content of the ``partitions`` node looks like this:
|
|
|
|
.. code-block:: DTS
|
|
|
|
partitions {
|
|
compatible = "fixed-partitions";
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
partition1_label: partition@START_OFFSET_1 {
|
|
label = "partition1_name";
|
|
reg = <0xSTART_OFFSET_1 0xSIZE_1>;
|
|
};
|
|
|
|
/* ... */
|
|
|
|
partitionN_label: partition@START_OFFSET_N {
|
|
label = "partitionN_name";
|
|
reg = <0xSTART_OFFSET_N 0xSIZE_N>;
|
|
};
|
|
};
|
|
|
|
Where:
|
|
|
|
- ``partitionX_label`` are device tree labels that can be used
|
|
elsewhere in the device tree to refer to the partition
|
|
|
|
- ``partitionX_name`` controls how defines generated by the Zephyr
|
|
build system for this partition will be named
|
|
|
|
- ``START_OFFSET_x`` is the start offset in hexadecimal notation of
|
|
the partition from the beginning of the flash device
|
|
|
|
- ``SIZE_x`` is the hexadecimal size, in bytes, of the flash partition
|
|
|
|
The partitions do not have to cover the entire flash device. The
|
|
device tree compiler currently does not check if partitions overlap;
|
|
you must ensure they do not when defining them.
|
|
|
|
Example Primary Flash Partition Layout
|
|
======================================
|
|
|
|
Here is a complete (but hypothetical) example device tree overlay
|
|
snippet illustrating these ideas. Notice how the partitions do not
|
|
overlap, but also do not cover the entire device.
|
|
|
|
.. code-block:: DTS
|
|
|
|
&flash0 {
|
|
partitions {
|
|
compatible = "fixed-partitions";
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
code_dts_label: partition@8000 {
|
|
label = "zephyr-code";
|
|
reg = <0x00008000 0x34000>;
|
|
};
|
|
|
|
data_dts_label: partition@70000 {
|
|
label = "application-data";
|
|
reg = <0x00070000 0xD000>;
|
|
};
|
|
};
|
|
};
|
|
|
|
Linking Zephyr Within a Partition
|
|
=================================
|
|
|
|
To force the linker to output a Zephyr image within a given flash
|
|
partition, add this to a device tree overlay:
|
|
|
|
.. code-block:: DTS
|
|
|
|
/ {
|
|
chosen {
|
|
zephyr,code-partition = &slot0_partition;
|
|
};
|
|
};
|
|
|
|
Then, enable the :option:`CONFIG_USE_DT_CODE_PARTITION` Kconfig option.
|
|
|
|
Flash Partition Macros
|
|
======================
|
|
|
|
The Zephyr build system generates definitions for each flash device
|
|
partition. These definitions are available to any files which
|
|
include ``<zephyr.h>``.
|
|
|
|
Consider this flash partition:
|
|
|
|
.. code-block:: DTS
|
|
|
|
dts_label: partition@START_OFFSET {
|
|
label = "def-name";
|
|
reg = <0xSTART_OFFSET 0xSIZE>;
|
|
};
|
|
|
|
The build system will generate the following corresponding defines:
|
|
|
|
.. code-block:: c
|
|
|
|
#define DT_FLASH_AREA_DEF_NAME_DEV "def-name"
|
|
#define DT_FLASH_AREA_DEF_NAME_OFFSET_0 0xSTART_OFFSET
|
|
#define DT_FLASH_AREA_DEF_NAME_SIZE_0 0xSIZE
|
|
#define DT_FLASH_AREA_DEF_NAME_OFFSET DT_FLASH_AREA_DEF_NAME_OFFSET_0
|
|
#define DT_FLASH_AREA_DEF_NAME_SIZE DT_FLASH_AREA_DEF_NAME_SIZE_0
|
|
|
|
As you can see, the ``label`` property is capitalized when forming the
|
|
macro names. Other simple conversions to ensure it is a valid C
|
|
identifier, such as converting "-" to "_", are also performed. The
|
|
offsets and sizes are available as well.
|
|
|
|
.. _mcuboot_partitions:
|
|
|
|
MCUboot Partitions
|
|
==================
|
|
|
|
`MCUboot`_ is a secure bootloader for 32-bit microcontrollers.
|
|
|
|
Some Zephyr boards provide definitions for the flash partitions which
|
|
are required to build MCUboot itself, as well as any applications
|
|
which must be chain-loaded by MCUboot.
|
|
|
|
The device tree labels for these partitions are:
|
|
|
|
**boot_partition**
|
|
This is the partition where the bootloader is expected to be
|
|
placed. MCUboot's build system will attempt to link the MCUboot
|
|
image into this partition.
|
|
|
|
**slot0_partition**
|
|
MCUboot loads the executable application image from this
|
|
partition. Any application bootable by MCUboot must be linked to run
|
|
from this partition.
|
|
|
|
**slot1_partition**
|
|
This is the partition which stores firmware upgrade images. Zephyr
|
|
applications which receive firmware updates must ensure the upgrade
|
|
images are placed in this partition (the Zephyr DFU subsystem can be
|
|
used for this purpose). MCUboot checks for upgrade images in this
|
|
partition, and can move them to ``slot0_partition`` for execution.
|
|
The ``slot0_partition`` and ``slot1_partition`` must be the same
|
|
size.
|
|
|
|
**scratch_partition**
|
|
This partition is used as temporary storage while swapping the
|
|
contents of ``slot0_partition`` and ``slot1_partition``.
|
|
|
|
.. important::
|
|
|
|
Upgrade images are only temporarily stored in ``slot1_partition``.
|
|
They must be linked to execute of out of ``slot0_partition``.
|
|
|
|
See the `MCUboot documentation`_ for more details on these partitions.
|
|
|
|
.. _MCUboot: https://mcuboot.com/
|
|
|
|
.. _MCUboot documentation:
|
|
https://github.com/runtimeco/mcuboot/blob/master/docs/design.md#image-slots
|
|
|
|
File System Partitions
|
|
======================
|
|
|
|
**storage_partition**
|
|
This is the area where e.g. LittleFS or NVS or FCB expects its partition.
|
|
|
|
ABNF grammar
|
|
************
|
|
|
|
This section contains an Augmented Backus-Naur Form grammar for the macros
|
|
generated from a devicetree. See `RFC 7405`_ (which extends `RFC 5234`_) for a
|
|
syntax specification.
|
|
|
|
.. literalinclude:: legacy-macros.bnf
|
|
:language: abnf
|
|
|
|
.. _RFC 7405: https://tools.ietf.org/html/rfc7405
|
|
.. _RFC 5234: https://tools.ietf.org/html/rfc5234
|