← Zephyr Documents build/dts/api-usage.html · build/dts/api-usage.rst 공식 원문 ↗

Zephyr 3.7.0 · Build · Devicetree · C API

C/C++에서 Devicetree 접근

DT_PATH부터 DT_PROP, reg·IRQ·phandle·driver instance macro와 generated macro 문법까지 연결합니다.

Official pathbuild/dts/api-usage.html
Source filebuild/dts/api-usage.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

Part 1

요약·해설

공식 DTS와 429줄 ABNF를 포함한 code block 13개, Linux runtime DTB와 Zephyr compile-time macro 차이를 보존했습니다.

Header

zephyr/devicetree.h

Node

PATH · LABEL · ALIAS

Property

REG · IRQ · PHANDLE

Grammar

429-line ABNF

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 9E82DAED43A94C5D442ACAB074D4E7A9D2AF49EEF20BC9212D03AA848906E316
.. _dt-from-c:

Devicetree access from C/C++
############################

This guide describes Zephyr's ``<zephyr/devicetree.h>`` API for reading the
devicetree from C source files. It assumes you're familiar with the concepts in
:ref:`devicetree-intro` and :ref:`dt-bindings`. See :ref:`dt-reference` for
reference material.

A note for Linux developers
***************************

Linux developers familiar with devicetree should be warned that the API
described here differs significantly from how devicetree is used on Linux.

Instead of generating a C header with all the devicetree data which is then
abstracted behind a macro API, the Linux kernel would instead read the
devicetree data structure in its binary form. The binary representation is
parsed at runtime, for example 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.

.. _dt-node-identifiers:

Node identifiers
****************

To get information about a particular devicetree node, you need a *node
identifier* for it. This is a just a C macro that refers to the node.

These are the main ways to get a node identifier:

By path
   Use :c:func:`DT_PATH()` along with the node's full path in the devicetree,
   starting from the root node. This is mostly useful if you happen to know the
   exact node you're looking for.

By node label
   Use :c:func:`DT_NODELABEL()` to get a node identifier from a :ref:`node
   label <dt-node-labels>`. Node labels are often provided by SoC :file:`.dtsi`
   files to give nodes names that match the SoC datasheet, like ``i2c1``,
   ``spi2``, etc.

By alias
   Use :c:func:`DT_ALIAS()` to get a node identifier for a property of the
   special ``/aliases`` node. This is sometimes done by applications (like
   :zephyr:code-sample:`blinky`, which uses the ``led0`` alias) that need to
   refer to *some* device of a particular type ("the board's user LED") but
   don't care which one is used.

By instance number
   This is done primarily by device drivers, as instance numbers are a way to
   refer to individual nodes based on a matching compatible. Get these with
   :c:func:`DT_INST()`, but be careful doing so. See below.

By chosen node
   Use :c:func:`DT_CHOSEN()` to get a node identifier for ``/chosen`` node
   properties.

By parent/child
   Use :c:func:`DT_PARENT()` and :c:func:`DT_CHILD()` to get a node identifier
   for a parent or child node, starting from a node identifier you already have.

Two node identifiers which refer to the same node are identical and can be used
interchangeably.

.. _dt-node-main-ex:

Here's a DTS fragment for some imaginary hardware we'll return to throughout
this file for examples:

.. literalinclude:: ../../../../build/dts/main-example.dts
   :language: devicetree
   :start-after: start-after-here

Here are a few ways to get node identifiers for the ``i2c@40002000`` node:

- ``DT_PATH(soc, i2c_40002000)``
- ``DT_NODELABEL(i2c1)``
- ``DT_ALIAS(sensor_controller)``
- ``DT_INST(x, vnd_soc_i2c)`` for some unknown number ``x``. See the
  :c:func:`DT_INST()` documentation for details.

.. important::

   Non-alphanumeric characters like dash (``-``) and the at sign (``@``) in
   devicetree names are converted to underscores (``_``). The names in a DTS
   are also converted to lowercase.

.. _node-ids-are-not-values:

Node identifiers are not values
*******************************

There is no way to store one in a variable. You cannot write:

.. code-block:: c

   /* These will give you compiler errors: */

   void *i2c_0 = DT_INST(0, vnd_soc_i2c);
   unsigned int i2c_1 = DT_INST(1, vnd_soc_i2c);
   long my_i2c = DT_NODELABEL(i2c1);

If you want something short to save typing, use C macros:

.. code-block:: c

   /* Use something like this instead: */

   #define MY_I2C DT_NODELABEL(i2c1)

   #define INST(i) DT_INST(i, vnd_soc_i2c)
   #define I2C_0 INST(0)
   #define I2C_1 INST(1)

Property access
***************

The right API to use to read property values depends on the node and property.

- :ref:`dt-checking-property-exists`
- :ref:`simple-properties`
- :ref:`reg-properties`
- :ref:`interrupts-properties`
- :ref:`phandle-properties`

.. _dt-checking-property-exists:

Checking properties and values
==============================

You can use :c:func:`DT_NODE_HAS_PROP()` to check if a node has a property. For
the :ref:`example devicetree <dt-node-main-ex>` above:

.. code-block:: c

   DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), clock_frequency)  /* expands to 1 */
   DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), not_a_property)   /* expands to 0 */

.. _simple-properties:

Simple properties
=================

Use ``DT_PROP(node_id, property)`` to read basic integer, boolean, string,
numeric array, and string array properties.

For example, to read the ``clock-frequency`` property's value in the
:ref:`above example <dt-node-main-ex>`:

.. code-block:: c

   DT_PROP(DT_PATH(soc, i2c_40002000), clock_frequency)  /* This is 100000, */
   DT_PROP(DT_NODELABEL(i2c1), clock_frequency)          /* and so is this, */
   DT_PROP(DT_ALIAS(sensor_controller), clock_frequency) /* and this. */

.. important::

   The DTS property ``clock-frequency`` is spelled ``clock_frequency`` in C.
   That is, properties also need special characters converted to underscores.
   Their names are also forced to lowercase.

Properties with ``string`` and ``boolean`` types work the exact same way. The
``DT_PROP()`` macro expands to a string literal in the case of strings, and the
number 0 or 1 in the case of booleans. For example:

.. code-block:: c

   #define I2C1 DT_NODELABEL(i2c1)

   DT_PROP(I2C1, status)  /* expands to the string literal "okay" */

.. note::

   Don't use DT_NODE_HAS_PROP() for boolean properties. Use DT_PROP() instead
   as shown above. It will expand to either 0 or 1 depending on if the property
   is present or absent.

Properties with type ``array``, ``uint8-array``, and ``string-array`` work
similarly, except ``DT_PROP()`` expands to an array initializer in these cases.
Here is an example devicetree fragment:

.. code-block:: devicetree

   foo: foo@1234 {
           a = <1000 2000 3000>; /* array */
           b = [aa bb cc dd];    /* uint8-array */
           c = "bar", "baz";     /* string-array */
   };

Its properties can be accessed like this:

.. code-block:: c

   #define FOO DT_NODELABEL(foo)

   int a[] = DT_PROP(FOO, a);           /* {1000, 2000, 3000} */
   unsigned char b[] = DT_PROP(FOO, b); /* {0xaa, 0xbb, 0xcc, 0xdd} */
   char* c[] = DT_PROP(FOO, c);         /* {"foo", "bar"} */

You can use :c:func:`DT_PROP_LEN()` to get logical array lengths in number of
elements.

.. code-block:: c

   size_t a_len = DT_PROP_LEN(FOO, a); /* 3 */
   size_t b_len = DT_PROP_LEN(FOO, b); /* 4 */
   size_t c_len = DT_PROP_LEN(FOO, c); /* 2 */

``DT_PROP_LEN()`` cannot be used with the special ``reg`` or ``interrupts``
properties. These have alternative macros which are described next.

.. _reg-properties:

reg properties
==============

See :ref:`dt-important-props` for an introduction to ``reg``.

Given a node identifier ``node_id``, ``DT_NUM_REGS(node_id)`` is the
total number of register blocks in the node's ``reg`` property.

You **cannot** read register block addresses and lengths with ``DT_PROP(node,
reg)``. Instead, if a node only has one register block, use
:c:func:`DT_REG_ADDR` or :c:func:`DT_REG_SIZE`:

- ``DT_REG_ADDR(node_id)``: the given node's register block address
- ``DT_REG_SIZE(node_id)``: its size

Use :c:func:`DT_REG_ADDR_BY_IDX` or :c:func:`DT_REG_SIZE_BY_IDX` instead if the
node has multiple register blocks:

- ``DT_REG_ADDR_BY_IDX(node_id, idx)``: address of register block at index
  ``idx``
- ``DT_REG_SIZE_BY_IDX(node_id, idx)``: size of block at index ``idx``

The ``idx`` argument to these must be an integer literal or a macro that
expands to one without requiring any arithmetic. In particular, ``idx`` cannot
be a variable. This won't work:

.. code-block:: c

   /* This will cause a compiler error. */

   for (size_t i = 0; i < DT_NUM_REGS(node_id); i++) {
           size_t addr = DT_REG_ADDR_BY_IDX(node_id, i);
   }

.. _interrupts-properties:

interrupts properties
=====================

See :ref:`dt-important-props` for a brief introduction to ``interrupts``.

Given a node identifier ``node_id``, ``DT_NUM_IRQS(node_id)`` is the total
number of interrupt specifiers in the node's ``interrupts`` property.

The most general purpose API macro for accessing these is
:c:func:`DT_IRQ_BY_IDX`:

.. code-block:: c

   DT_IRQ_BY_IDX(node_id, idx, val)

Here, ``idx`` is the logical index into the ``interrupts`` array, i.e. it is
the index of an individual interrupt specifier in the property. The ``val``
argument is the name of a cell within the interrupt specifier. To use this
macro, check the bindings file for the node you are interested in to find the
``val`` names.

Most Zephyr devicetree bindings have a cell named ``irq``, which is the
interrupt number. You can use :c:func:`DT_IRQN` as a convenient way to get a
processed view of this value.

.. warning::

   Here, "processed" reflects Zephyr's devicetree :ref:`dt-scripts`, which
   change the ``irq`` number in :ref:`zephyr.dts <devicetree-in-out-files>` to
   handle hardware constraints on some SoCs and in accordance with Zephyr's
   multilevel interrupt numbering.

   This is currently not very well documented, and you'll need to read the
   scripts' source code and existing drivers for more details if you are writing
   a device driver.

.. _phandle-properties:

phandle properties
==================

.. note::

   See :ref:`dt-phandles` for a detailed guide to phandles.

Property values can refer to other nodes using the ``&another-node`` phandle
syntax introduced in :ref:`dt-writing-property-values`. Properties which
contain phandles have type ``phandle``, ``phandles``, or ``phandle-array`` in
their bindings. We'll call these "phandle properties" for short.

You can convert a phandle to a node identifier using :c:func:`DT_PHANDLE`,
:c:func:`DT_PHANDLE_BY_IDX`, or :c:func:`DT_PHANDLE_BY_NAME`, depending on the
type of property you are working with.

One common use case for phandle properties is referring to other hardware in
the tree. In this case, you usually want to convert the devicetree-level
phandle to a Zephyr driver-level :ref:`struct device <device_model_api>`.
See :ref:`dt-get-device` for ways to do that.

Another common use case is accessing specifier values in a phandle array. The
general purpose APIs for this are :c:func:`DT_PHA_BY_IDX` and :c:func:`DT_PHA`.
There are also hardware-specific shorthands like :c:func:`DT_GPIO_CTLR_BY_IDX`,
:c:func:`DT_GPIO_CTLR`,
:c:func:`DT_GPIO_PIN_BY_IDX`, :c:func:`DT_GPIO_PIN`,
:c:func:`DT_GPIO_FLAGS_BY_IDX`, and :c:func:`DT_GPIO_FLAGS`.

See :c:func:`DT_PHA_HAS_CELL_AT_IDX` and :c:func:`DT_PROP_HAS_IDX` for ways to
check if a specifier value is present in a phandle property.

.. _other-devicetree-apis:

Other APIs
**********

Here are pointers to some other available APIs.

- :c:func:`DT_CHOSEN`, :c:func:`DT_HAS_CHOSEN`: for properties
  of the special ``/chosen`` node
- :c:func:`DT_HAS_COMPAT_STATUS_OKAY`, :c:func:`DT_NODE_HAS_COMPAT`: global-
  and node-specific tests related to the ``compatible`` property
- :c:func:`DT_BUS`: get a node's bus controller, if there is one
- :c:func:`DT_ENUM_IDX`: for properties whose values are among a fixed list of
  choices
- :ref:`devicetree-flash-api`: APIs for managing fixed flash partitions.
  Also see :ref:`flash_map_api`, which wraps this in a more user-friendly API.

Device driver conveniences
**************************

Special purpose macros are available for writing device drivers, which usually
rely on :ref:`instance identifiers <dt-node-identifiers>`.

To use these, you must define ``DT_DRV_COMPAT`` to the ``compat`` value your
driver implements support for. This ``compat`` value is what you would pass to
:c:func:`DT_INST`.

If you do that, you can access the properties of individual instances of your
compatible with less typing, like this:

.. code-block:: c

   #include <zephyr/devicetree.h>

   #define DT_DRV_COMPAT my_driver_compat

   /* This is same thing as DT_INST(0, my_driver_compat): */
   DT_DRV_INST(0)

   /*
    * This is the same thing as
    * DT_PROP(DT_INST(0, my_driver_compat), clock_frequency)
    */
   DT_INST_PROP(0, clock_frequency)

See :ref:`devicetree-inst-apis` for a generic API reference.

Hardware specific APIs
**********************

Convenience macros built on top of the above APIs are also defined to help
readability for hardware specific code. See :ref:`devicetree-hw-api` for
details.

Generated macros
****************

While the :file:`zephyr/devicetree.h` API is not generated, it does rely on a
generated C header which is put into every application build directory:
:ref:`devicetree_generated.h <dt-outputs>`. This file contains macros with
devicetree data.

These macros have tricky naming conventions which the :ref:`devicetree_api` API
abstracts away. They should be considered an implementation detail, but it's
useful to understand them since they will frequently be seen in compiler error
messages.

This section contains an Augmented Backus-Naur Form grammar for these
generated macros, with examples and more details in comments. See `RFC 7405`_
(which extends `RFC 5234`_) for a syntax specification.

.. literalinclude:: ../../../../build/dts/macros.bnf
   :language: abnf

.. _RFC 7405: https://tools.ietf.org/html/rfc7405
.. _RFC 5234: https://tools.ietf.org/html/rfc5234

Part 3

한국어 전문 번역

C/C++에서 Devicetree 접근

이 문서는 C source file에서 devicetree를 읽는 Zephyr <zephyr/devicetree.h> API를 설명합니다. Devicetree 기본 개념과 binding을 이미 알고 있다고 가정합니다.

Linux developer를 위한 주의

Linux kernel은 일반적으로 binary devicetree data structure를 runtime에 읽고 parsing해 driver를 load·initialize합니다. Zephyr는 모든 devicetree data를 C header로 생성하고 macro API 뒤에 추상화합니다. Zephyr가 지원하는 resource-constrained device에는 DTB와 runtime 처리 code의 크기가 부담되기 때문입니다.

Node identifier

특정 devicetree node 정보를 얻으려면 그 node를 가리키는 C macro인 node identifier가 필요합니다. 주요 획득 방법은 다음과 같습니다.

  • Path: Root부터 시작하는 전체 path를 DT_PATH()에 전달합니다. 찾는 node의 정확한 path를 알 때 유용합니다.
  • Node label: DT_NODELABEL()로 node label을 identifier로 바꿉니다. SoC DTSI가 datasheet 이름과 맞춘 i2c1, spi2 같은 label을 자주 제공합니다.
  • Alias: 특별한 /aliases node property를 DT_ALIAS()로 가져옵니다. blinkyled0처럼 특정 구현보다 ‘board user LED’라는 역할이 중요할 때 사용합니다.
  • Instance number: Compatible이 일치하는 개별 node를 DT_INST()로 얻습니다. 주로 device driver가 사용하며 instance 번호에 대한 보장을 주의해야 합니다.
  • Chosen node: /chosen property는 DT_CHOSEN()으로 가져옵니다.
  • Parent/child: 이미 가진 identifier에서 DT_PARENT()DT_CHILD()로 parent 또는 child identifier를 만듭니다.

같은 node를 가리키는 두 node identifier는 동일하며 서로 바꾸어 사용할 수 있습니다.

공통 예제 DTS

이 문서의 뒤 예제는 다음 가상 hardware fragment를 사용합니다.

/dts-v1/;

/ {

	aliases {
		sensor-controller = &i2c1;
	};

	soc {
		i2c1: i2c@40002000 {
			compatible = "vnd,soc-i2c";
			label = "I2C_1";
			reg = <0x40002000 0x1000>;
			status = "okay";
			clock-frequency = < 100000 >;
		};
	};
};

i2c@40002000 node는 다음 방식으로 참조할 수 있습니다.

  • DT_PATH(soc, i2c_40002000)
  • DT_NODELABEL(i2c1)
  • DT_ALIAS(sensor_controller)
  • Compatible vnd,soc-i2c의 알 수 없는 instance 번호 x에 대해 DT_INST(x, vnd_soc_i2c)

Node identifier는 값이 아님

Node identifier는 C value가 아니므로 variable에 저장할 수 없습니다.

/* These will give you compiler errors: */

void *i2c_0 = DT_INST(0, vnd_soc_i2c);
unsigned int i2c_1 = DT_INST(1, vnd_soc_i2c);
long my_i2c = DT_NODELABEL(i2c1);

짧은 이름이 필요하면 C macro를 정의합니다.

/* Use something like this instead: */

#define MY_I2C DT_NODELABEL(i2c1)

#define INST(i) DT_INST(i, vnd_soc_i2c)
#define I2C_0 INST(0)
#define I2C_1 INST(1)

Property 접근

Property를 읽는 API는 node와 property 종류에 따라 다릅니다. 존재 검사, simple property, reg, interrupts, phandle property를 구분해야 합니다.

Property와 값 확인

DT_NODE_HAS_PROP()는 node에 property가 있는지 compile time에 1 또는 0으로 알려 줍니다.

DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), clock_frequency)  /* expands to 1 */
DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), not_a_property)   /* expands to 0 */

Simple property

DT_PROP(node_id, property)는 기본 integer, boolean, string, numeric array, string array를 읽습니다.

DT_PROP(DT_PATH(soc, i2c_40002000), clock_frequency)  /* This is 100000, */
DT_PROP(DT_NODELABEL(i2c1), clock_frequency)          /* and so is this, */
DT_PROP(DT_ALIAS(sensor_controller), clock_frequency) /* and this. */

String과 boolean도 같은 macro를 사용합니다. String은 string literal로, boolean은 property 존재 여부에 따라 0 또는 1로 확장됩니다.

#define I2C1 DT_NODELABEL(i2c1)

DT_PROP(I2C1, status)  /* expands to the string literal "okay" */

array, uint8-array, string-array는 array initializer로 확장됩니다. 예제 DTS는 다음과 같습니다.

foo: foo@1234 {
        a = <1000 2000 3000>; /* array */
        b = [aa bb cc dd];    /* uint8-array */
        c = "bar", "baz";     /* string-array */
};

C에서는 다음처럼 사용합니다.

#define FOO DT_NODELABEL(foo)

int a[] = DT_PROP(FOO, a);           /* {1000, 2000, 3000} */
unsigned char b[] = DT_PROP(FOO, b); /* {0xaa, 0xbb, 0xcc, 0xdd} */
char* c[] = DT_PROP(FOO, c);         /* {"foo", "bar"} */

DT_PROP_LEN()은 logical element 수를 반환합니다.

size_t a_len = DT_PROP_LEN(FOO, a); /* 3 */
size_t b_len = DT_PROP_LEN(FOO, b); /* 4 */
size_t c_len = DT_PROP_LEN(FOO, c); /* 2 */

reginterrupts는 special property이므로 DT_PROP_LEN()을 사용할 수 없고 전용 macro를 써야 합니다.

reg property

DT_NUM_REGS(node_id)reg에 든 register block 수입니다. DT_PROP(node, reg)로 address와 length를 읽을 수는 없습니다.

  • Block이 하나면 DT_REG_ADDR(node_id)DT_REG_SIZE(node_id)
  • 여러 block이면 DT_REG_ADDR_BY_IDX(node_id, idx)DT_REG_SIZE_BY_IDX(node_id, idx)

idx는 integer literal 또는 산술 없이 literal로 확장되는 macro여야 하며 variable은 허용되지 않습니다. 따라서 다음 loop는 compile error를 냅니다.

/* This will cause a compiler error. */

for (size_t i = 0; i < DT_NUM_REGS(node_id); i++) {
        size_t addr = DT_REG_ADDR_BY_IDX(node_id, i);
}

interrupts property

DT_NUM_IRQS(node_id)interrupts의 interrupt specifier 수입니다. 가장 일반적인 접근 macro는 다음과 같습니다.

DT_IRQ_BY_IDX(node_id, idx, val)

idx는 specifier의 logical index이고 val은 specifier 내부 cell 이름입니다. Binding file에서 해당 node가 사용하는 cell 이름을 확인해야 합니다. 대부분 Zephyr binding은 interrupt 번호를 뜻하는 irq cell을 가지며, DT_IRQN으로 처리된 값을 편리하게 얻을 수 있습니다.

Phandle property

&another-node syntax로 다른 node를 참조하는 property의 binding type은 phandle, phandles, phandle-array입니다. Property 종류에 따라 DT_PHANDLE, DT_PHANDLE_BY_IDX, DT_PHANDLE_BY_NAME으로 node identifier를 얻습니다.

다른 hardware를 가리키는 phandle을 Zephyr driver 수준의 struct device로 바꾸려면 device 획득 API를 사용합니다. Phandle-array specifier value는 DT_PHA_BY_IDXDT_PHA로 읽습니다. GPIO 전용 shortcut으로 controller, pin, flag의 index/name variant가 있습니다: DT_GPIO_CTLR_BY_IDX, DT_GPIO_CTLR, DT_GPIO_PIN_BY_IDX, DT_GPIO_PIN, DT_GPIO_FLAGS_BY_IDX, DT_GPIO_FLAGS.

DT_PHA_HAS_CELL_AT_IDXDT_PROP_HAS_IDX로 phandle property의 specifier value 존재 여부를 확인할 수 있습니다.

그 밖의 API

  • DT_CHOSEN, DT_HAS_CHOSEN: 특별한 /chosen node property
  • DT_HAS_COMPAT_STATUS_OKAY, DT_NODE_HAS_COMPAT: compatible의 global·node별 검사
  • DT_BUS: 존재할 경우 node의 bus controller
  • DT_ENUM_IDX: 고정 choice 목록 중 property 값의 index
  • Fixed flash partition 관리 API와 이를 더 편리하게 감싼 flash map API

Device driver 편의 macro

Device driver는 보통 instance identifier 기반 전용 macro를 사용합니다. 먼저 driver가 지원하는 compatible을 lowercase+underscore 형태로 DT_DRV_COMPAT에 정의해야 합니다. 그러면 instance property를 더 짧게 쓸 수 있습니다.

#include <zephyr/devicetree.h>

#define DT_DRV_COMPAT my_driver_compat

/* This is same thing as DT_INST(0, my_driver_compat): */
DT_DRV_INST(0)

/*
 * This is the same thing as
 * DT_PROP(DT_INST(0, my_driver_compat), clock_frequency)
 */
DT_INST_PROP(0, clock_frequency)

Hardware-specific code의 가독성을 높이는 상위 convenience macro도 제공됩니다.

Generated macro

zephyr/devicetree.h API 자체는 generated file이 아니지만, 모든 application build directory의 devicetree_generated.h에 생성된 devicetree data macro를 사용합니다. 이 macro의 까다로운 naming convention은 public API가 감추므로 implementation detail로 보아야 하지만 compiler error에 자주 나타나기 때문에 이해할 가치가 있습니다.

다음은 generated macro naming을 설명하는 전체 Augmented Backus-Naur Form 문법입니다. 문법 표기는 RFC 7405와 RFC 5234를 따릅니다.

; An RFC 7405 ABNF grammar for devicetree macros.
;
; This does *not* cover macros pulled out of DT via Kconfig,
; like CONFIG_SRAM_BASE_ADDRESS, etc. It only describes the
; ones that start with DT_ and are directly generated.

; --------------------------------------------------------------------
; dt-macro: the top level nonterminal for a devicetree macro
;
; A dt-macro starts with uppercase "DT_", and is one of:
;
; - a <node-macro>, generated for a particular node
; - some <other-macro>, a catch-all for other types of macros
dt-macro = node-macro / other-macro

; --------------------------------------------------------------------
; node-macro: a macro related to a node

; A macro about a property value
node-macro =  property-macro
; A macro about the pinctrl properties in a node.
node-macro =/ pinctrl-macro
; A macro about the GPIO hog properties in a node.
node-macro =/ gpiohogs-macro
; EXISTS macro: node exists in the devicetree
node-macro =/ %s"DT_N" path-id %s"_EXISTS"
; Bus macros: the plain BUS is a way to access a node's bus controller.
; The additional dt-name suffix is added to match that node's bus type;
; the dt-name in this case is something like "spi" or "i2c".
node-macro =/ %s"DT_N" path-id %s"_BUS" ["_" dt-name]
; The reg property is special and has its own macros.
node-macro =/ %s"DT_N" path-id %s"_REG_NUM"
node-macro =/ %s"DT_N" path-id %s"_REG_IDX_" DIGIT "_EXISTS"
node-macro =/ %s"DT_N" path-id %s"_REG_IDX_" DIGIT
              %s"_VAL_" ( %s"ADDRESS" / %s"SIZE")
node-macro =/ %s"DT_N" path-id %s"_REG_NAME_" dt-name
              %s"_VAL_" ( %s"ADDRESS" / %s"SIZE")
node-macro =/ %s"DT_N" path-id %s"_REG_NAME_" dt-name "_EXISTS"
; The interrupts property is also special.
node-macro =/ %s"DT_N" path-id %s"_IRQ_NUM"
node-macro =/ %s"DT_N" path-id %s"_IRQ_LEVEL"
node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT "_EXISTS"
node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT
              %s"_VAL_" dt-name [ %s"_EXISTS" ]
node-macro =/ %s"DT_N" path-id %s"_CONTROLLER"
node-macro =/ %s"DT_N" path-id %s"_IRQ_NAME_" dt-name
              %s"_VAL_" dt-name [ %s"_EXISTS" ]
node-macro =/ %s"DT_N" path-id %s"_IRQ_NAME_" dt-name "_CONTROLLER"
; The ranges property is also special.
node-macro =/ %s"DT_N" path-id %s"_RANGES_NUM"
node-macro =/ %s"DT_N" path-id %s"_RANGES_IDX_" DIGIT "_EXISTS"
node-macro =/ %s"DT_N" path-id %s"_RANGES_IDX_" DIGIT
              %s"_VAL_" ( %s"CHILD_BUS_FLAGS" / %s"CHILD_BUS_ADDRESS" /
                          %s"PARENT_BUS_ADDRESS" / %s"LENGTH")
node-macro =/ %s"DT_N" path-id %s"_RANGES_IDX_" DIGIT
              %s"_VAL_CHILD_BUS_FLAGS_EXISTS"
node-macro =/ %s"DT_N" path-id %s"_FOREACH_RANGE"
; Subnodes of the fixed-partitions compatible get macros which contain
; a unique ordinal value for each partition
node-macro =/ %s"DT_N" path-id %s"_PARTITION_ID" DIGIT
; Macros are generated for each of a node's compatibles;
; dt-name in this case is something like "vnd_device".
node-macro =/ %s"DT_N" path-id %s"_COMPAT_MATCHES_" dt-name
node-macro =/ %s"DT_N" path-id %s"_COMPAT_VENDOR_IDX_" DIGIT "_EXISTS"
node-macro =/ %s"DT_N" path-id %s"_COMPAT_VENDOR_IDX_" DIGIT
node-macro =/ %s"DT_N" path-id %s"_COMPAT_MODEL_IDX_" DIGIT "_EXISTS"
node-macro =/ %s"DT_N" path-id %s"_COMPAT_MODEL_IDX_" DIGIT
; Every non-root node gets one of these macros, which expands to the node
; identifier for that node's parent in the devicetree.
node-macro =/ %s"DT_N" path-id %s"_PARENT"
; These are used internally by DT_FOREACH_PROP_ELEM(_SEP)(_VARGS), which
; iterates over each property element.
node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM"
node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM_SEP"
node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM_VARGS"
node-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_PROP_ELEM_SEP_VARGS"
; These are used by DT_CHILD_NUM and DT_CHILD_NUM_STATUS_OKAY macros
node-macro =/ %s"DT_N" path-id %s"_CHILD_NUM"
node-macro =/ %s"DT_N" path-id %s"_CHILD_NUM_STATUS_OKAY"
; These are used internally by DT_FOREACH_CHILD, which iterates over
; each child node.
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD"
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_SEP"
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_VARGS"
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_SEP_VARGS"
; These are used internally by DT_FOREACH_CHILD_STATUS_OKAY, which iterates
; over each child node with status "okay".
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_STATUS_OKAY"
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_STATUS_OKAY_SEP"
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_STATUS_OKAY_VARGS"
node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_STATUS_OKAY_SEP_VARGS"
; These are used internally by DT_FOREACH_NODELABEL and
; DT_FOREACH_NODELABEL_VARGS, which iterate over a node's node labels.
node-macro =/ %s"DT_N" path-id %s"_FOREACH_NODELABEL" [ %s"_VARGS" ]
; These are used internally by DT_NUM_NODELABELS
node-macro =/ %s"DT_N" path-id %s"_NODELABEL_NUM"
; The node's zero-based index in the list of it's parent's child nodes.
node-macro =/ %s"DT_N" path-id %s"_CHILD_IDX"
; The node's status macro; dt-name in this case is something like "okay"
; or "disabled".
node-macro =/ %s"DT_N" path-id %s"_STATUS_" dt-name
; The node's dependency ordinal. This is a non-negative integer
; value that is used to represent dependency information.
node-macro =/ %s"DT_N" path-id %s"_ORD"
; The node's path, as a string literal
node-macro =/ %s"DT_N" path-id %s"_PATH"
; The node's name@unit-addr, as a string literal
node-macro =/ %s"DT_N" path-id %s"_FULL_NAME"
; The dependency ordinals of a node's requirements (direct dependencies).
node-macro =/ %s"DT_N" path-id %s"_REQUIRES_ORDS"
; The dependency ordinals of a node supports (reverse direct dependencies).
node-macro =/ %s"DT_N" path-id %s"_SUPPORTS_ORDS"

; --------------------------------------------------------------------
; pinctrl-macro: a macro related to the pinctrl properties in a node
;
; These are a bit of a special case because they kind of form an array,
; but the array indexes correspond to pinctrl-DIGIT properties in a node.
;
; So they're related to a node, but not just one property within the node.
;
; The following examples assume something like this:
;
;      foo {
;              pinctrl-0 = <&bar>;
;              pinctrl-1 = <&baz>;
;              pinctrl-names = "default", "sleep";
;      };

; Total number of pinctrl-DIGIT properties in the node. May be zero.
;
;   #define DT_N_<node path>_PINCTRL_NUM 2
pinctrl-macro = %s"DT_N" path-id %s"_PINCTRL_NUM"
; A given pinctrl-DIGIT property exists.
;
;     #define DT_N_<node path>_PINCTRL_IDX_0_EXISTS 1
;     #define DT_N_<node path>_PINCTRL_IDX_1_EXISTS 1
pinctrl-macro =/ %s"DT_N" path-id %s"_PINCTRL_IDX_" DIGIT %s"_EXISTS"
; A given pinctrl property name exists.
;
;     #define DT_N_<node path>_PINCTRL_NAME_default_EXISTS 1
;     #define DT_N_<node path>_PINCTRL_NAME_sleep_EXISTS 1
pinctrl-macro =/ %s"DT_N" path-id %s"_PINCTRL_NAME_" dt-name %s"_EXISTS"
; The corresponding index number of a named pinctrl property.
;
;     #define DT_N_<node path>_PINCTRL_NAME_default_IDX 0
;     #define DT_N_<node path>_PINCTRL_NAME_sleep_IDX 1
pinctrl-macro =/ %s"DT_N" path-id %s"_PINCTRL_NAME_" dt-name %s"_IDX"
; The node identifier for the phandle in a named pinctrl property.
;
;    #define DT_N_<node path>_PINCTRL_NAME_default_IDX_0_PH <node id for 'bar'>
;
; There's no need for a separate macro for access by index: that's
; covered by property-macro. We only need this because the map from
; names to properties is implicit in the structure of the DT.
pinctrl-macro =/ %s"DT_N" path-id %s"_PINCTRL_NAME_" dt-name %s"_IDX_" DIGIT %s"_PH"

; --------------------------------------------------------------------
; gpiohogs-macro: a macro related to GPIO hog nodes
;
; The following examples assume something like this:
;
;     gpio1: gpio@... {
;       compatible = "vnd,gpio";
;       #gpio-cells = <2>;
;
;       node-1 {
;               gpio-hog;
;               gpios = <0x0 0x10>, <0x1 0x20>;
;               output-high;
;       };
;
;       node-2 {
;               gpio-hog;
;               gpios = <0x2 0x30>;
;               output-low;
;       };
;     };
;
; Bindings fragment for the vnd,gpio compatible:
;
;     gpio-cells:
;       - pin
;       - flags

; The node contains GPIO hogs.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_EXISTS 1
;   #define DT_N_<node-2 path>_GPIO_HOGS_EXISTS 1
gpioshogs-macro = %s"DT_N" path-id %s"_GPIO_HOGS_EXISTS"
; Number of hogged GPIOs in a node.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_NUM 2
;   #define DT_N_<node-2 path>_GPIO_HOGS_NUM 1
gpioshogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_NUM"
; A given logical GPIO hog array index exists.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_0_EXISTS 1
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_1_EXISTS 1
;   #define DT_N_<node-2 path>_GPIO_HOGS_IDX_0_EXISTS 1
gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_EXISTS"
; The node identifier for the phandle of a logical index in the GPIO hogs array.
; These macros are currently unused by Zephyr.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_0_PH <node id for 'gpio1'>
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_1_PH <node id for 'gpio1'>
;   #define DT_N_<node-2 path>_GPIO_HOGS_IDX_0_PH <node id for 'gpio1'>
gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_PH"
; The pin cell of a logical index in the GPIO hogs array exists.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_0_VAL_pin_EXISTS 1
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_1_VAL_pin_EXISTS 1
;   #define DT_N_<node-2 path>_GPIO_HOGS_IDX_0_VAL_pin_EXISTS 1
gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_VAL_pin_EXISTS"
; The value of the pin cell of a logical index in the GPIO hogs array.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_0_VAL_pin 0
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_1_VAL_pin 1
;   #define DT_N_<node-2 path>_GPIO_HOGS_IDX_0_VAL_pin 2
gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_VAL_pin"
; The flags cell of a logical index in the GPIO hogs array exists.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_0_VAL_flags_EXISTS 1
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_1_VAL_flags_EXISTS 1
;   #define DT_N_<node-2 path>_GPIO_HOGS_IDX_0_VAL_flags_EXISTS 1
gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_VAL_flags_EXISTS"
; The value of the flags cell of a logical index in the GPIO hogs array.
;
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_0_VAL_flags 0x10
;   #define DT_N_<node-1 path>_GPIO_HOGS_IDX_1_VAL_flags 0x20
;   #define DT_N_<node-2 path>_GPIO_HOGS_IDX_0_VAL_flags 0x30
gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_VAL_flags"

; --------------------------------------------------------------------
; property-macro: a macro related to a node property
;
; These combine a node identifier with a "lowercase-and-underscores form"
; property name. The value expands to something related to the property's
; value.
;
; The optional prop-suf suffix is when there's some specialized
; subvalue that deserves its own macro, like the macros for an array
; property's individual elements
;
; The "plain vanilla" macro for a property's value, with no prop-suf,
; looks like this:
;
;   DT_N_<node path>_P_<property name>
;
; Components:
;
; - path-id: node's devicetree path converted to a C token
; - prop-id: node's property name converted to a C token
; - prop-suf: an optional property-specific suffix
property-macro =  %s"DT_N" path-id %s"_P_" prop-id [prop-suf]

; --------------------------------------------------------------------
; path-id: a node's path-based macro identifier
;
; This in "lowercase-and-underscores" form. I.e. it is
; the node's devicetree path converted to a C token by changing:
;
; - each slash (/) to _S_
; - all letters to lowercase
; - non-alphanumerics characters to underscores
;
; For example, the leaf node "bar-BAZ" in this devicetree:
;
;   / {
;           foo@123 {
;                   bar-BAZ {};
;           };
;   };
;
; has path-id "_S_foo_123_S_bar_baz".
path-id = 1*( %s"_S_" dt-name )

; ----------------------------------------------------------------------
; prop-id: a property identifier
;
; A property name converted to a C token by changing:
;
; - all letters to lowercase
; - non-alphanumeric characters to underscores
;
; Example node:
;
;   chosen {
;       zephyr,console = &uart1;
;       WHY,AM_I_SHOUTING = "unclear";
;   };
;
; The 'zephyr,console' property has prop-id 'zephyr_console'.
; 'WHY,AM_I_SHOUTING' has prop-id 'why_am_i_shouting'.
prop-id = dt-name

; ----------------------------------------------------------------------
; prop-suf: a property-specific macro suffix
;
; Extra macros are generated for properties:
;
; - that are special to the specification ("reg", "interrupts", etc.)
; - with array types (uint8-array, phandle-array, etc.)
; - with "enum:" in their bindings
; - that have zephyr device API specific macros for phandle-arrays
; - related to phandle specifier names ("foo-names")
;
; Here are some examples:
;
; - _EXISTS: property, index or name existence flag
; - _SIZE: logical property length
; - _IDX_<i>: values of individual array elements
; - _IDX_<DIGIT>_VAL_<dt-name>: values of individual specifier
;   cells within a phandle array
; - _ADDR_<i>: for reg properties, the i-th register block address
; - _LEN_<i>: for reg properties, the i-th register block length
;
; The different cases are not exhaustively documented here to avoid
; this file going stale. Please see devicetree.h if you need to know
; the details.
prop-suf = 1*( "_" gen-name ["_" dt-name] )

; --------------------------------------------------------------------
; other-macro: grab bag for everything that isn't a node-macro.

; See examples below.
other-macro =  %s"DT_N_" alternate-id
; Total count of enabled instances of a compatible.
other-macro =/ %s"DT_N_INST_" dt-name %s"_NUM_OKAY"
; These are used internally by DT_FOREACH_NODE and
; DT_FOREACH_STATUS_OKAY_NODE respectively.
other-macro =/ %s"DT_FOREACH_HELPER"
other-macro =/ %s"DT_FOREACH_OKAY_HELPER"
; These are used internally by DT_FOREACH_STATUS_OKAY,
; which iterates over each enabled node of a compatible.
other-macro =/ %s"DT_FOREACH_OKAY_" dt-name
other-macro =/ %s"DT_FOREACH_OKAY_VARGS_" dt-name
; These are used internally by DT_INST_FOREACH_STATUS_OKAY,
; which iterates over each enabled instance of a compatible.
other-macro =/ %s"DT_FOREACH_OKAY_INST_" dt-name
other-macro =/ %s"DT_FOREACH_OKAY_INST_VARGS_" dt-name
; E.g.: #define DT_CHOSEN_zephyr_flash
other-macro =/ %s"DT_CHOSEN_" dt-name
; Declares that a compatible has at least one node on a bus.
; Example:
;
;   #define DT_COMPAT_vnd_dev_BUS_spi 1
other-macro =/ %s"DT_COMPAT_" dt-name %s"_BUS_" dt-name
; Declares that a compatible has at least one status "okay" node.
; Example:
;
;   #define DT_COMPAT_HAS_OKAY_vnd_dev 1
other-macro =/ %s"DT_COMPAT_HAS_OKAY_" dt-name
; Currently used to allow mapping a lowercase-and-underscores "label"
; property to a fixed-partitions node. See the flash map API docs
; for an example.
other-macro =/ %s"DT_COMPAT_" dt-name %s"_LABEL_" dt-name

; --------------------------------------------------------------------
; alternate-id: another way to specify a node besides a path-id
;
; Example devicetree:
;
;   / {
;           aliases {
;                   dev = &dev_1;
;           };
;
;           soc {
;               dev_1: device@123 {
;                   compatible = "vnd,device";
;               };
;           };
;   };
;
; Node device@123 has these alternate-id values:
;
; - ALIAS_dev
; - NODELABEL_dev_1
; - INST_0_vnd_device
;
; The full alternate-id macros are:
;
;   #define DT_N_INST_0_vnd_device     DT_N_S_soc_S_device_123
;   #define DT_N_ALIAS_dev             DT_N_S_soc_S_device_123
;   #define DT_N_NODELABEL_dev_1       DT_N_S_soc_S_device_123
;
; These mainly exist to allow pasting an alternate-id macro onto a
; "_P_<prop-id>" to access node properties given a node's alias, etc.
;
; Notice that "inst"-type IDs have a leading instance identifier,
; which is generated by the devicetree scripts. The other types of
; alternate-id begin immediately with names taken from the devicetree.
alternate-id =  ( %s"ALIAS" / %s"NODELABEL" ) dt-name
alternate-id =/ %s"INST_" 1*DIGIT "_" dt-name

; --------------------------------------------------------------------
; miscellaneous helper definitions

; A dt-name is one or more:
; - lowercase ASCII letters (a-z)
; - numbers (0-9)
; - underscores ("_")
;
; They are the result of converting names or combinations of names
; from devicetree to a valid component of a C identifier by
; lowercasing letters (in practice, this is a no-op) and converting
; non-alphanumeric characters to underscores.
;
; You'll see these referred to as "lowercase-and-underscores" forms of
; various devicetree identifiers throughout the documentation.
dt-name = 1*( lower / DIGIT / "_" )

; gen-name is used as a stand-in for a component of a generated macro
; name which does not come from devicetree (dt-name covers that case).
;
; - uppercase ASCII letters (a-z)
; - numbers (0-9)
; - underscores ("_")
gen-name = upper 1*( upper / DIGIT / "_" )

; "lowercase ASCII letter" turns out to be pretty annoying to specify
; in RFC-7405 syntax.
;
; This is just ASCII letters a (0x61) through z (0x7a).
lower = %x61-7A

; "uppercase ASCII letter" in RFC-7405 syntax
upper = %x41-5A

참고 규격

Source

출처

원문 파일의 단락, directive, 표, 코드, symbol, 경로는 영어 원문 영역에 그대로 보존했습니다.