mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-02 23:51:56 +00:00
There are two set of code supporting x86_64: x86_64 using x32 ABI, and x86 long mode, and this consolidates both into one x86_64 architecture and SoC supporting truly 64-bit mode. () Removes the x86_64:x32 architecture and SoC, and replaces them with the existing x86 long mode arch and SoC. () Replace qemu_x86_64 with qemu_x86_long as qemu_x86_64. () Updates samples and tests to remove reference to qemu_x86_long. () Renames CONFIG_X86_LONGMODE to CONFIG_X86_64. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
789 lines
29 KiB
ReStructuredText
789 lines
29 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 "devicetree". 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 can use a devicetree to generate C language code. This
|
|
code generation uses rules in additional files called :ref:`devicetree bindings
|
|
<bindings>` to control how devicetree data is converted to C definitions. The
|
|
generated code can be included by Zephyr :ref:`device drivers <device_drivers>`
|
|
and other C sources. The C macros generated by this process all begin with
|
|
``DT_``.
|
|
|
|
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 full set of Zephyr-specific ``chosen`` nodes follows:
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
|
|
* - ``chosen`` node name
|
|
- Generated symbol
|
|
|
|
* - ``zephyr,flash``
|
|
- ``CONFIG_FLASH``
|
|
* - ``zephyr,sram``
|
|
- ``CONFIG_SRAM_SIZE``/``CONFIG_SRAM_BASE_ADDRESS``
|
|
(via ``DT_SRAM_SIZE``/``DT_SRAM_BASE_ADDRESS``)
|
|
* - ``zephyr,ccm``
|
|
- ``DT_CCM``
|
|
* - ``zephyr,console``
|
|
- ``DT_UART_CONSOLE_ON_DEV_NAME``
|
|
* - ``zephyr,shell-uart``
|
|
- ``DT_UART_SHELL_ON_DEV_NAME``
|
|
* - ``zephyr,bt-uart``
|
|
- ``DT_BT_UART_ON_DEV_NAME``
|
|
* - ``zephyr,uart-pipe``
|
|
- ``DT_UART_PIPE_ON_DEV_NAME``
|
|
* - ``zephyr,bt-mon-uart``
|
|
- ``DT_BT_MONITOR_ON_DEV_NAME``
|
|
* - ``zephyr,uart-mcumgr``
|
|
- ``DT_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
|
|
|
|
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
|
|
|
|
parent-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
|