It's cryptic that some identifiers for devicetree-related stuff start with DT_*, while others start with CONFIG_*. Explain what's going on, and link to the Kconfig preprocessor documentation. Also remove an early mention of bindings that might be confusing. Bindings are much more about checking devicetree conformance than about controlling output, though they do some of that too. Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
803 lines
30 KiB
ReStructuredText
803 lines
30 KiB
ReStructuredText
.. _device-tree:
|
|
|
|
Devicetree
|
|
##########
|
|
|
|
Zephyr uses the *devicetree* data structure to describe the hardware available
|
|
on a board, as well as its initial configuration in an application. Note that
|
|
"devicetree" -- without spaces -- is preferred to "device tree". The
|
|
`Devicetree specification`_ fully defines this data structure and its source
|
|
and binary representations.
|
|
|
|
.. _device-tree-intro:
|
|
|
|
Introduction
|
|
************
|
|
|
|
.. _Devicetree specification: https://www.devicetree.org/
|
|
|
|
This figure shows how devicetree fits into the Zephyr build system:
|
|
|
|
.. figure:: zephyr_dt_build_flow.png
|
|
:figclass: align-center
|
|
|
|
Devicetree build flow
|
|
|
|
Zephyr's build system generates C preprocessor macros from devicetree
|
|
definitions. These macros can be referenced in :ref:`device drivers
|
|
<device_drivers>` and other C code. All macro identifiers that are directly
|
|
generated by the devicetree scripts start with ``DT_*``.
|
|
|
|
Some devicetree-related identifiers also start with ``CONFIG_*``, which is the
|
|
identifier prefix used by :ref:`Kconfig <kconfig>`. This happens when
|
|
devicetree-related information is referenced from Kconfig symbol definitions,
|
|
via the :ref:`Kconfig preprocessor <kconfig-functions>`.
|
|
|
|
This differs significantly from how devicetree is used on Linux. The
|
|
Linux kernel would instead read the entire devicetree data structure in its
|
|
binary form, parsing it at runtime in order to load and initialize device
|
|
drivers. Zephyr does not work this way because the size of the devicetree
|
|
binary and associated handling code would be too large to fit comfortably on
|
|
the relatively constrained devices Zephyr supports.
|
|
|
|
As the name indicates, a devicetree is a tree. The human-readable text format
|
|
for this tree is called DTS (for devicetree source), and is defined in the
|
|
Devicetree Specification. Here is an example DTS file:
|
|
|
|
.. code-block:: none
|
|
|
|
/dts-v1/;
|
|
|
|
/ {
|
|
a-node {
|
|
subnode_label: a-sub-node {
|
|
foo = <3>;
|
|
};
|
|
};
|
|
};
|
|
|
|
This example has three nodes:
|
|
|
|
#. A root node
|
|
#. A node named ``a-node``, which is a child of the root node
|
|
#. A node named ``a-sub-node``, which is a child of ``a-node``
|
|
|
|
Nodes can be given *labels*, which are unique shorthands that can be used to
|
|
refer to the labeled node elsewhere in the devicetree. Above, ``a-sub-node``
|
|
has label ``subnode_label``.
|
|
|
|
Devicetree nodes have *paths* identifying their locations in the tree. Like
|
|
Unix file system paths, devicetree paths are strings separated by slashes
|
|
(``/``), and the root node's path is a single slash: ``/``. Otherwise, each
|
|
node's path is formed by concatenating the node's ancestors' names with the
|
|
node's own name, separated by slashes. For example, the full path to
|
|
``a-sub-node`` is ``/a-node/a-sub-node``.
|
|
|
|
Devicetree nodes can also have *properties*. Properties are name/value
|
|
pairs. The values are simple byte arrays. Node ``a-sub-node`` has a property
|
|
named ``foo``, whose value is a 32-bit big-endian unsigned integer with value
|
|
3. The size and type of ``foo``\ 's value are implied by the enclosing angle
|
|
brackets (``<`` and ``>``) in the DTS. Refer to the Devicetree Specification
|
|
for a complete list of ways to write a property value in a DTS file.
|
|
|
|
In practice, devicetree nodes correspond to some hardware, and the node
|
|
hierarchy reflects the hardware's physical layout. For example, let's consider
|
|
a board with three I2C peripherals connected to an I2C bus master on an SoC,
|
|
like this:
|
|
|
|
.. figure:: zephyr_dt_i2c_high_level.png
|
|
:alt: representation of a board with three I2C peripherals
|
|
:figclass: align-center
|
|
|
|
Nodes corresponding to the I2C bus master and each I2C peripheral would be
|
|
present in this board's devicetree. Reflecting the hardware layout, the
|
|
devicetree's peripheral nodes would be children of the bus master node. Similar
|
|
conventions exist for representing other types of hardware in devicetree.
|
|
|
|
The corresponding DTS would look something like this:
|
|
|
|
.. code-block:: none
|
|
|
|
/ {
|
|
soc {
|
|
i2c-bus-master {
|
|
i2c-peripheral-1 {
|
|
};
|
|
i2c-peripheral-2 {
|
|
};
|
|
i2c-peripheral-3 {
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
Properties are used in practice to describe or configure the hardware the node
|
|
represents. For example, an I2C peripheral's node has a property whose value is
|
|
the peripheral's address on the bus.
|
|
|
|
Here's a tree representing the same example, but with real-world node
|
|
names and properties you might see when working with I2C devices.
|
|
|
|
.. figure:: zephyr_dt_i2c_example.png
|
|
:figclass: align-center
|
|
|
|
I2C devicetree example with real-world names and properties
|
|
|
|
Above, node names -- like ``i2c@40003000`` -- are at the top of each node, with
|
|
a gray background, except for the root node, which is shown using its path
|
|
``/``. Properties are shown as ``name=value`` pairs below the node names.
|
|
|
|
Some important properties are:
|
|
|
|
- **compatible**: this says what "kind" of device the node represents. Its
|
|
value is a null-terminated string in the format "vendor,device", like
|
|
``"avago,apds9960"``, or a sequence of these, like ``"ti,hdc",
|
|
"ti,hdc1010"``. The build system uses the compatible property to find the
|
|
right bindings for the node.
|
|
- **label**: the device's name according to Zephyr's :ref:`device_drivers`. The
|
|
value can be passed to :c:func:`device_get_binding()` to retrieve the
|
|
corresponding driver-level :ref:`struct device* <device_struct>`. This
|
|
pointer can then be passed to the correct driver API by application code to
|
|
interact with the device. For example, calling
|
|
``device_get_binding("I2C_0")`` would return a pointer to a device
|
|
structure which could be passed to :ref:`I2C API <i2c_api>` functions like
|
|
:c:func:`i2c_transfer()`. The generated C header will also contain a macro
|
|
which expands to this string.
|
|
- **reg**: information used to address the device. This could be a
|
|
memory-mapped I/O address range (as with ``i2c@40003000``\ 's reg property),
|
|
an I2C bus address (as with ``apds9960@39`` and its devicetree siblings), a
|
|
SPI chip select line, or some other value depending on the kind of device the
|
|
node represents.
|
|
|
|
This tree has the following DTS.
|
|
|
|
.. code-block:: none
|
|
|
|
/ {
|
|
soc {
|
|
i2c@40003000 {
|
|
compatible = "nordic,nrf-twim";
|
|
label = "I2C_0";
|
|
reg = <0x40003000 0x1000>;
|
|
|
|
apds9960@39 {
|
|
compatible = "avago,apds9960";
|
|
label = "APDS9960";
|
|
reg = <0x39>;
|
|
};
|
|
ti_hdc@43 {
|
|
compatible = "ti,hdc", "ti,hdc1010";
|
|
label = "HDC1010;
|
|
reg = <0x43>;
|
|
};
|
|
mma8652fc@1d {
|
|
compatible = "nxp,fxos8700", "nxp,mma8652fc";
|
|
label = "MMA8652FC";
|
|
reg = <0x1d>;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
Input and output files
|
|
**********************
|
|
|
|
The first figure in the :ref:`device-tree-intro` shows how devicetree fits into
|
|
the Zephyr build system. This section describes the input and output files in
|
|
more detail.
|
|
|
|
.. figure:: zephyr_dt_inputs_outputs.png
|
|
:figclass: align-center
|
|
|
|
Devicetree input (green) and output (yellow) files
|
|
|
|
DTS files usually have ``.dts`` or ``.dtsi`` (for Devicetree Source Include)
|
|
extensions. Zephyr's build system looks for a file named :file:`BOARD.dts` in
|
|
the board definition directory; this file contains the board's base
|
|
devicetree. See :ref:`dt_k6x_example` for real-world examples.
|
|
|
|
The build system combines the board's DTS with additional input files called
|
|
*overlays* to produce a final devicetree source file. Overlays are also written
|
|
in the DTS format, but have a :file:`.overlay` extension to make it clear that
|
|
they're overlays. You can specify the overlay files to use at build time using
|
|
the :makevar:`DTC_OVERLAY_FILE` CMake variable described in
|
|
:ref:`important-build-vars`. The build system also looks for devicetree
|
|
overlays in several locations by default; see :ref:`application_dt` for the
|
|
list.
|
|
|
|
Overlays can be used to add or delete nodes from the tree, or to modify node
|
|
properties and their values. Along with Kconfig, devicetree overlays let you
|
|
reconfigure the kernel and device drivers without modifying their source code.
|
|
|
|
Before they are combined, the C preprocessor is run on :file:`BOARD.dts` and any
|
|
overlays. This allows these files to use C macros and include directives.
|
|
|
|
The combined devicetree is written to a DTS file named
|
|
:file:`BOARD.dts_compiled` in the application build directory. This file
|
|
contains the final devicetree.
|
|
|
|
This devicetree and the set of :ref:`bindings` are then used to generate C
|
|
definitions using scripts in :zephyr_file:`scripts/dts/`. These definitions can
|
|
be included via the ``generated_dts_board.h`` header file, which the build
|
|
system places on the C preprocessor include path. This file is not generated;
|
|
it is in :zephyr_file:`include/generated_dts_board.h`. (Its name was chosen
|
|
for backwards compatibility.)
|
|
|
|
**Do not include the generated C headers in the build directory directly**. Use
|
|
``generated_dts_board.h`` instead.
|
|
|
|
Zephyr device drivers typically use information from ``generated_dts_board.h``
|
|
to statically allocate and initialize :ref:`struct device <device_struct>`
|
|
instances. Property values from ``generated_dts_board.h`` are usually stored in
|
|
ROM in the value pointed to by a ``device->config->config_info`` field. For
|
|
example, a ``struct device`` corresponding to an I2C peripheral would store the
|
|
peripheral address in its ``reg`` property there.
|
|
|
|
Application source code with a pointer to the ``struct device`` can then pass
|
|
it to driver APIs in :zephyr_file:`include/drivers/`. These API functions
|
|
usually take a ``struct device*`` as their first argument. This allows the
|
|
driver API to use information from devicetree to interact with the device
|
|
hardware.
|
|
|
|
Temporary "fixup" files are currently required for devicetree support on most
|
|
devices. These fixup files by default reside in the board and soc directories
|
|
and are named ``dts_fixup.h``. These fixup files map the generated include
|
|
information to the current driver/source usage. They exist for historical
|
|
reasons; Zephyr is moving away from needing or using these files.
|
|
|
|
.. _dt_k6x_example:
|
|
|
|
Example: FRDM-K64F and Hexiwear K64
|
|
===================================
|
|
|
|
.. Give the filenames instead of the full paths below, as it's easier to read.
|
|
The cramped 'foo.dts<path>' style avoids extra spaces before commas.
|
|
|
|
The FRDM-K64F and Hexiwear K64 board devicetrees are defined in
|
|
:zephyr_file:`frdm_k64fs.dts <boards/arm/frdm_k64f/frdm_k64f.dts>` and
|
|
:zephyr_file:`hexiwear_k64.dts <boards/arm/hexiwear_k64/hexiwear_k64.dts>`
|
|
respectively. Both boards have NXP SoCs from the same Kinetis SoC family, the
|
|
K6X.
|
|
|
|
Common devicetree definitions for K6X are stored in :zephyr_file:`nxp_k6x.dtsi
|
|
<dts/arm/nxp/nxp_k6x.dtsi>`, which is included by both board :file:`.dts`
|
|
files. :zephyr_file:`nxp_k6x.dtsi<dts/arm/nxp/nxp_k6x.dtsi>` in turn includes
|
|
:zephyr_file:`armv7-m.dtsi<dts/arm/armv7-m.dtsi>`, which has common definitions
|
|
for Arm v7-M cores.
|
|
|
|
Since :zephyr_file:`nxp_k6x.dtsi<dts/arm/nxp/nxp_k6x.dtsi>` is meant to be
|
|
generic across K6X-based boards, it leaves many devices disabled by default
|
|
using ``status`` properties. For example, there is a CAN controller defined as
|
|
follows (with unimportant parts skipped):
|
|
|
|
.. code-block:: none
|
|
|
|
can0: can@40024000 {
|
|
...
|
|
status = "disabled";
|
|
...
|
|
};
|
|
|
|
It is up to the board :file:`.dts` or application overlay files to enable these
|
|
devices as desired, by setting ``status = "okay"``. The board :file:`.dts`
|
|
files are also responsible for any board-specific configuration of the device,
|
|
such as adding nodes for on-board sensors, LEDs, buttons, etc.
|
|
|
|
For example, FRDM-K64 (but not Hexiwear K64) :file:`.dts` enables the CAN
|
|
controller and sets the bus speed:
|
|
|
|
.. code-block:: none
|
|
|
|
&can0 {
|
|
status = "okay";
|
|
bus-speed = <125000>;
|
|
};
|
|
|
|
The ``&can0 { ... };`` syntax adds/overrides properties on the node with label
|
|
``can0``, i.e. the ``can@4002400`` node defined in the :file:`.dtsi` file.
|
|
|
|
Other examples of board-specific customization is pointing properties in
|
|
``aliases`` and ``chosen`` to the right nodes (see :ref:`dt-alias-chosen`), and
|
|
making GPIO/pinmux assignments.
|
|
|
|
.. _dt_vs_kconfig:
|
|
|
|
Devicetree vs Kconfig
|
|
*********************
|
|
|
|
Along with devicetree, Zephyr also uses the Kconfig language to configure the
|
|
source code. Whether to use devicetree or Kconfig for a particular purpose can
|
|
sometimes be confusing. This section should help you decide which one to use.
|
|
|
|
In short:
|
|
|
|
* Use devicetree to describe **hardware** and its **boot-time configuration**.
|
|
Examples include peripherals on a board, boot-time clock frequencies,
|
|
interrupt lines, etc.
|
|
* Use Kconfig to configure **software support** to build into the final
|
|
image. Examples include whether to add networking support, which drivers are
|
|
needed by the application, etc.
|
|
|
|
In other words, devicetree mainly deals with hardware, and Kconfig with
|
|
software.
|
|
|
|
For example, consider a board containing a SoC with 2 UART, or serial port,
|
|
instances.
|
|
|
|
* The fact that the board has this UART **hardware** is described with two UART
|
|
nodes in the devicetree. These provide the UART type (via the ``compatible``
|
|
property) and certain settings such as the address range of the hardware
|
|
peripheral registers in memory (via the ``reg`` property).
|
|
* Additionally, the UART **boot-time configuration** is also described with
|
|
devicetree. This could include configuration such as the RX IRQ line's
|
|
priority and the UART baud rate. These may be modifiable at runtime, but
|
|
their boot-time configuration is described in devicetree.
|
|
* Whether or not to include **software support** for UART in the build is
|
|
controlled via Kconfig. Applications which do not need to use the UARTs can
|
|
remove the driver source code from the build using Kconfig, even though the
|
|
board's devicetree still includes UART nodes.
|
|
|
|
As another example, consider a device with a 2.4GHz, multi-protocol radio
|
|
supporting both the Bluetooth Low Energy and 802.15.4 wireless technologies.
|
|
|
|
* Devicetree should be used to describe the presence of the radio **hardware**,
|
|
what driver or drivers it's compatible with, etc.
|
|
* **Boot-time configuration** for the radio, such as TX power in dBm, should
|
|
also be specified using devicetree.
|
|
* Kconfig should determine which **software features** should be built for the
|
|
radio, such as selecting a BLE or 802.15.4 protocol stack.
|
|
|
|
There are two noteworthy **exceptions** to these rules:
|
|
|
|
* Devicetree's ``chosen`` keyword, which allows the user to select a specific
|
|
instance of a hardware device to be used for a particular purpose. An example
|
|
of this is selecting a particular UART for use as the system's console.
|
|
* Devicetree's ``status`` keyword, which allows the user to enable or disable a
|
|
particular instance of a hardware device. This takes precedence over related
|
|
Kconfig options which serve a similar purpose.
|
|
|
|
Currently supported boards
|
|
**************************
|
|
|
|
Devicetree is currently supported on all embedded targets except posix
|
|
(boards/posix).
|
|
|
|
Adding support for a board
|
|
**************************
|
|
|
|
Adding devicetree support for a given board requires adding a number of files.
|
|
These files will contain the DTS information that describes a platform, the
|
|
bindings in YAML format, and any fixup files required to support the platform.
|
|
|
|
It is best practice to separate common peripheral information that could be
|
|
used across multiple cores, SoC families, or boards in :file:`.dtsi` files,
|
|
reserving the :file:`.dts` suffix for the primary DTS file for a given board.
|
|
|
|
Devicetree Source File Template
|
|
===============================
|
|
|
|
A board's :file:`.dts` file contains at least a version line, optional
|
|
includes, and a root node definition with ``model`` and ``compatible``
|
|
properties. These property values denote the particular board.
|
|
|
|
.. code-block:: none
|
|
|
|
/dts-v1/;
|
|
|
|
#include <vendor/soc.dtsi>
|
|
|
|
/ {
|
|
model = "Human readable board name";
|
|
compatible = "vendor,soc-on-your-board's-mcu";
|
|
/* rest of file */
|
|
};
|
|
|
|
You can use other board :file:`.dts` files as a starting point.
|
|
|
|
The following is a more precise list of required files:
|
|
|
|
* Base architecture support
|
|
|
|
* Add architecture-specific DTS directory, if not already present.
|
|
Example: dts/arm for Arm.
|
|
* Add target specific devicetree files for base SoC. These should be
|
|
.dtsi files to be included in the board-specific devicetree files.
|
|
* Add target specific YAML binding files in the dts/bindings/ directory.
|
|
Create the yaml directory if not present.
|
|
|
|
* SoC family support
|
|
|
|
* Add one or more SoC family .dtsi files that describe the hardware
|
|
for a set of devices. The file should contain all the relevant
|
|
nodes and base configuration that would be applicable to all boards
|
|
utilizing that SoC family.
|
|
* Add SoC family YAML binding files that describe the nodes present in the .dtsi file.
|
|
|
|
* Board specific support
|
|
|
|
* Add a board level .dts file that includes the SoC family .dtsi files
|
|
and enables the nodes required for that specific board.
|
|
* Board .dts file should specify the SRAM and FLASH devices, if present.
|
|
|
|
* Flash device node might specify flash partitions. For more details see
|
|
:ref:`flash_partitions`
|
|
|
|
* Add board-specific YAML binding files, if required. This would occur if the
|
|
board has additional hardware that is not covered by the SoC family
|
|
.dtsi/.yaml files.
|
|
|
|
* Fixup files
|
|
|
|
* Fixup files contain mappings from existing Kconfig options to the actual
|
|
underlying DTS derived configuration #defines. Fixup files are temporary
|
|
artifacts until additional DTS changes are made to make them unnecessary.
|
|
|
|
* Overlay Files (optional)
|
|
|
|
* Overlay files contain tweaks or changes to the SoC and Board support files
|
|
described above. They can be used to modify devicetree configurations
|
|
without having to change the SoC and Board files. See
|
|
:ref:`application_dt` for more information on overlay files and the Zephyr
|
|
build system.
|
|
|
|
.. _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>`.
|
|
|
|
.. 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``
|
|
- ``CONFIG_SRAM_BASE_ADDRESS``/``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``
|
|
- ``CONFIG_UART_CONSOLE_ON_DEV_NAME``
|
|
* - ``zephyr,shell-uart``
|
|
- ``CONFIG_UART_SHELL_ON_DEV_NAME``
|
|
* - ``zephyr,bt-uart``
|
|
- ``CONFIG_BT_UART_ON_DEV_NAME``
|
|
* - ``zephyr,uart-pipe``
|
|
- ``CONFIG_UART_PIPE_ON_DEV_NAME``
|
|
* - ``zephyr,bt-mon-uart``
|
|
- ``CONFIG_BT_MONITOR_ON_DEV_NAME``
|
|
* - ``zephyr,bt-c2h-uart``
|
|
- ``CONFIG_BT_CTLR_TO_HOST_UART_DEV_NAME``
|
|
* - ``zephyr,uart-mcumgr``
|
|
- ``CONFIG_UART_MCUMGR_ON_DEV_NAME``
|
|
|
|
|
|
Adding support for devicetree in drivers
|
|
****************************************
|
|
|
|
As drivers and other source code is converted over to make use of devicetree
|
|
generated information, these drivers may require changes to match the generated
|
|
#define information.
|
|
|
|
|
|
Source Tree Hierarchy
|
|
*********************
|
|
|
|
The devicetree files are located in a couple of different directories. The
|
|
directory split is done based on architecture, and there is also a common
|
|
directory where architecture agnostic devicetree and YAML binding files are
|
|
located.
|
|
|
|
Assuming the current working directory is the ZEPHYR_BASE, the directory
|
|
hierarchy looks like the following::
|
|
|
|
dts/common/
|
|
dts/<ARCH>/
|
|
dts/bindings/
|
|
boards/<ARCH>/<BOARD>/
|
|
|
|
The common directory contains a ``skeleton.dtsi`` which provides devicetree root
|
|
node definition. The bindings subdirectory contains YAML binding files used
|
|
to instruct how the python DTS parsing script should extract nodes information
|
|
in a format that will be usable by the system.
|
|
|
|
Example: Subset of DTS/YAML files for NXP FRDM K64F (Subject to Change)::
|
|
|
|
dts/arm/armv7-m.dtsi
|
|
dts/arm/k6x/nxp_k6x.dtsi
|
|
boards/arm/frdm_k64f/frdm_k64f.dts
|
|
dts/bindings/interrupt-controller/arm,v7m-nvic.yaml
|
|
dts/bindings/gpio/nxp,kinetis-gpio.yaml
|
|
dts/bindings/pinctrl/nxp,kinetis-pinmux.yaml
|
|
dts/bindings/serial/nxp,kinetis-uart.yaml
|
|
|
|
.. _bindings:
|
|
|
|
Devicetree Bindings
|
|
*******************
|
|
|
|
``.dts`` files describe the available hardware devices, but don't tell the
|
|
system which pieces of information are useful, or what kind of configuration
|
|
output (``#define``'s) should be generated. *Bindings* provide this
|
|
information. Bindings are files in YAML format.
|
|
|
|
Configuration output is only generated for devices that have bindings.
|
|
|
|
Nodes are mapped to bindings via their ``compatible`` string(s). Take
|
|
the following node as an example:
|
|
|
|
.. code-block:: none
|
|
|
|
bar-device {
|
|
compatible = "foo-company,bar-device";
|
|
...
|
|
};
|
|
|
|
This node would get mapped to a binding with this in it:
|
|
|
|
.. code-block:: yaml
|
|
|
|
compatible: "foo-company,bar-device"
|
|
|
|
You might also run across this legacy syntax, which works the same way:
|
|
|
|
.. code-block:: yaml
|
|
|
|
...
|
|
|
|
properties:
|
|
compatible:
|
|
constraint: "foo-company,bar-device"
|
|
|
|
...
|
|
|
|
Bindings are stored in :zephyr_file:`dts/bindings/`. The filename usually
|
|
matches the ``compatible`` string.
|
|
|
|
If a node has more than one ``compatible`` string, then the first binding found
|
|
is used, going from the first string to the last. For example, a node with
|
|
``compatible = "foo-company,bar-device", "generic-bar-device"`` would get
|
|
mapped to the binding for ``generic-bar-device`` if there is no binding for
|
|
``foo-company,bar-device``.
|
|
|
|
If a node appears on a bus (e.g. I2C or SPI), then the bus type is also taken
|
|
into account when mapping nodes to bindings. See the description of ``parent``
|
|
and ``child`` in the template below.
|
|
|
|
Below is a template that shows the format of binding files, stored in
|
|
:zephyr_file:`dts/binding-template.yaml`.
|
|
|
|
.. literalinclude:: ../../../dts/binding-template.yaml
|
|
:language: yaml
|
|
|
|
.. _legacy_binding_syntax:
|
|
|
|
Legacy binding syntax
|
|
=====================
|
|
|
|
Various parts of the binding syntax were simplified and generalized for the
|
|
Zephyr 2.1 release.
|
|
|
|
The binding below shows various legacy syntax.
|
|
|
|
.. code-block:: yaml
|
|
|
|
title: ...
|
|
description: ...
|
|
|
|
inherits:
|
|
!include foo.yaml
|
|
|
|
parent:
|
|
bus: spi
|
|
|
|
parent-bus: spi
|
|
|
|
properties:
|
|
compatible:
|
|
constraint: "company,device"
|
|
type: string-array
|
|
|
|
frequency:
|
|
type: int
|
|
category: optional
|
|
|
|
sub-node:
|
|
properties:
|
|
child-prop:
|
|
type: int
|
|
category: required
|
|
|
|
# Assume this is a binding for an interrupt controller
|
|
"#cells":
|
|
- irq
|
|
- priority
|
|
- flags
|
|
|
|
This should now be written like this:
|
|
|
|
.. code-block:: yaml
|
|
|
|
title: ...
|
|
description: ...
|
|
|
|
compatible: "company,device"
|
|
|
|
include: foo.yaml
|
|
|
|
bus: spi
|
|
|
|
properties:
|
|
frequency:
|
|
type: int
|
|
required: false
|
|
|
|
child-binding:
|
|
title: ...
|
|
description: ...
|
|
|
|
properties:
|
|
child-prop:
|
|
type: int
|
|
required: true
|
|
|
|
interrupt-cells:
|
|
- irq
|
|
- priority
|
|
- cells
|
|
|
|
The legacy syntax is still supported for backwards compatibility, but generates
|
|
deprecation warnings. Support will be dropped in the Zephyr 2.3 release.
|
|
|
|
Include files generation
|
|
************************
|
|
|
|
At build time, after a board's ``.dts`` file has been processed by the DTC
|
|
(Devicetree Compiler), a corresponding ``.dts_compiled`` file is generated
|
|
under the ``zephyr`` directory.
|
|
This ``.dts_compiled`` file is processed by the python DTS parsing script
|
|
and generates an include file named
|
|
``include/generated/generated_dts_board_unfixed.h``
|
|
that holds all the information extracted from the DTS file with
|
|
the format specified by the YAML bindings. For example:
|
|
|
|
.. code-block:: c
|
|
|
|
/* gpio_keys */
|
|
#define DT_GPIO_KEYS_0 1
|
|
|
|
/* button_0 */
|
|
#define DT_GPIO_KEYS_BUTTON_0_GPIOS_CONTROLLER "GPIO_2"
|
|
#define DT_GPIO_KEYS_BUTTON_0_GPIOS_FLAGS 0
|
|
#define DT_GPIO_KEYS_BUTTON_0_GPIOS_PIN 6
|
|
#define DT_GPIO_KEYS_BUTTON_0_LABEL "User SW2"
|
|
|
|
#define DT_GPIO_KEYS_SW1_GPIOS_CONTROLLER DT_GPIO_KEYS_BUTTON_0_GPIOS_CONTROLLER
|
|
#define DT_GPIO_KEYS_SW1_GPIOS_FLAGS DT_GPIO_KEYS_BUTTON_0_GPIOS_FLAGS
|
|
#define DT_GPIO_KEYS_SW1_GPIOS_PIN DT_GPIO_KEYS_BUTTON_0_GPIOS_PIN
|
|
#define DT_ALIAS_SW1_GPIOS_CONTROLLE DT_GPIO_KEYS_BUTTON_0_GPIOS_CONTROLLER
|
|
#define DT_ALIAS_SW1_GPIOS_FLAGS DT_GPIO_KEYS_BUTTON_0_GPIOS_FLAGS
|
|
#define DT_ALIAS_SW1_GPIOS_PIN DT_GPIO_KEYS_BUTTON_0_GPIOS_PIN
|
|
#define DT_ALIAS_SW1_LABEL DT_GPIO_KEYS_BUTTON_0_LABEL
|
|
|
|
|
|
Additionally, a file named ``generated_dts_board_fixups.h`` is
|
|
generated in the same directory concatenating all board-related fixup files.
|
|
|
|
The include file ``include/generated_dts_board.h`` includes both these generated
|
|
files, giving Zephyr C source files access to the board's devicetree information.
|
|
|
|
GPIO Nexus Nodes
|
|
****************
|
|
|
|
Each board has a set of General Purpose Input/Output (GPIO)
|
|
peripherals that can be accessed through the :ref:`GPIO<gpio>` module.
|
|
Many boards provide headers that allow :ref:`shields<shields>` from
|
|
other vendors to be mounted on their boards. Each shield identifies
|
|
its hardware in a devicetree overlay.
|
|
|
|
GPIOs accessed by the shield peripherals must be identified using the
|
|
shield GPIO abstraction, for example from the ``arduino-r3-header``
|
|
compatible. Boards that provide the header must map the header pins
|
|
to SOC-specific pins. This is accomplished by including a `nexus
|
|
node`_ that looks like the following into the board devicetree file:
|
|
|
|
.. _nexus node:
|
|
https://github.com/devicetree-org/devicetree-specification/blob/4b1dac80eaca45b4babf5299452a951008a5d864/source/devicetree-basics.rst#nexus-nodes-and-specifier-mapping
|
|
|
|
.. code-block:: none
|
|
|
|
arduino_header: connector {
|
|
compatible = "arduino-header-r3";
|
|
#gpio-cells = <2>;
|
|
gpio-map-mask = <0xffffffff 0xffffffc0>;
|
|
gpio-map-pass-thru = <0 0x3f>;
|
|
gpio-map = <0 0 &gpioa 0 0>, /* A0 */
|
|
<1 0 &gpioa 1 0>, /* A1 */
|
|
<2 0 &gpioa 4 0>, /* A2 */
|
|
<3 0 &gpiob 0 0>, /* A3 */
|
|
<4 0 &gpioc 1 0>, /* A4 */
|
|
<5 0 &gpioc 0 0>, /* A5 */
|
|
<6 0 &gpioa 3 0>, /* D0 */
|
|
<7 0 &gpioa 2 0>, /* D1 */
|
|
<8 0 &gpioa 10 0>, /* D2 */
|
|
<9 0 &gpiob 3 0>, /* D3 */
|
|
<10 0 &gpiob 5 0>, /* D4 */
|
|
<11 0 &gpiob 4 0>, /* D5 */
|
|
<12 0 &gpiob 10 0>, /* D6 */
|
|
<13 0 &gpioa 8 0>, /* D7 */
|
|
<14 0 &gpioa 9 0>, /* D8 */
|
|
<15 0 &gpioc 7 0>, /* D9 */
|
|
<16 0 &gpiob 6 0>, /* D10 */
|
|
<17 0 &gpioa 7 0>, /* D11 */
|
|
<18 0 &gpioa 6 0>, /* D12 */
|
|
<19 0 &gpioa 5 0>, /* D13 */
|
|
<20 0 &gpiob 9 0>, /* D14 */
|
|
<21 0 &gpiob 8 0>; /* D15 */
|
|
};
|
|
|
|
This specifies how Arduino pin references like ``<&arduino_header 11
|
|
0>`` are converted to SOC gpio pin references like ``<&gpiob 4 0>``.
|
|
|
|
In Zephyr GPIO specifiers generally have two parameters (indicated by
|
|
``#gpio-cells = <2>``): the pin number and a set of flags. The low 6
|
|
bits of the flags correspond to features that can be configured in
|
|
devicetree. In some cases it's necessary to use a non-zero flag value
|
|
to tell the driver how a particular pin behaves, as with:
|
|
|
|
.. code-block:: none
|
|
|
|
drdy-gpios = <&arduino_header 11 GPIO_ACTIVE_LOW>;
|
|
|
|
After preprocessing this becomes ``<&arduino_header 11 1>``. Normally
|
|
the presence of such a flag would cause the map lookup to fail,
|
|
because there is no map entry with a non-zero flags value. The
|
|
``gpio-map-mask`` property specifies that, for lookup, all bits of the
|
|
pin and all but the low 6 bits of the flags are used to identify the
|
|
specifier. Then the ``gpio-map-pass-thru`` specifies that the low 6
|
|
bits of the flags are copied over, so the SOC GPIO reference becomes
|
|
``<&gpiob 4 1>`` as intended.
|
|
|
|
See `nexus node`_ for more information about this capability.
|
|
|
|
.. include:: flash_partitions.inc
|