Skip to content

include: devicetree: Generate defines for map property #87595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 1 addition & 17 deletions dts/bindings/adc/arduino,uno-adc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,4 @@ description: |

compatible: "arduino,uno-adc"

include: base.yaml

properties:
io-channel-map:
type: compound
required: true

io-channel-map-mask:
type: compound

io-channel-map-pass-thru:
type: compound

"#io-channel-cells":
type: int
required: true
description: Number of items to expect in an ADC specifier
include: [base.yaml, io-channel-nexus.yaml]
4 changes: 2 additions & 2 deletions dts/bindings/gpio/gpio-nexus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ properties:
required: true

gpio-map-mask:
type: compound
type: array

gpio-map-pass-thru:
type: compound
type: array

"#gpio-cells":
type: int
Expand Down
20 changes: 20 additions & 0 deletions dts/bindings/iio/io-channel-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) 2025 TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

# Common fields for io-channel nexus nodes

properties:
io-channel-map:
type: compound
required: true

io-channel-map-mask:
type: array

io-channel-map-pass-thru:
type: array

"#io-channel-cells":
type: int
required: true
description: Number of items to expect in the io-channel specifier, such as ADC channels.
20 changes: 20 additions & 0 deletions dts/bindings/interrupt-controller/interrupt-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright (c) 2025 TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

# Common fields for interrupt nexus nodes

properties:
interrupt-map:
type: compound
required: true

interrupt-map-mask:
type: array

interrupt-map-pass-thru:
type: array

"#interrupt-cells":
type: int
required: true
description: Number of items to expect in a interrupt specifier
8 changes: 1 addition & 7 deletions dts/bindings/pcie/host/pci-host-ecam-generic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: PCIe Controller in ECAM mode

compatible: "pci-host-ecam-generic"

include: pcie-controller.yaml
include: [pcie-controller.yaml, interrupt-nexus.yaml]

properties:
reg:
Expand All @@ -22,11 +22,5 @@ properties:
definition of non-prefetchable memory. One or both of prefetchable Memory
and IO Space may also be provided.

interrupt-map-mask:
type: array

interrupt-map:
type: compound

bus-range:
type: array
8 changes: 8 additions & 0 deletions dts/bindings/test/vnd,gpio-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2025, TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

description: VND GPIO nexus

include: [gpio-nexus.yaml]

compatible: "vnd,gpio-nexus"
8 changes: 8 additions & 0 deletions dts/bindings/test/vnd,intr-nexus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2025, TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

description: VND interrupt nexus

include: [interrupt-nexus.yaml]

compatible: "vnd,intr-nexus"
1 change: 1 addition & 0 deletions include/zephyr/devicetree.h
Original file line number Diff line number Diff line change
Expand Up @@ -5343,5 +5343,6 @@
#include <zephyr/devicetree/reset.h>
#include <zephyr/devicetree/mbox.h>
#include <zephyr/devicetree/port-endpoint.h>
#include <zephyr/devicetree/map.h>

#endif /* ZEPHYR_INCLUDE_DEVICETREE_H_ */
263 changes: 263 additions & 0 deletions include/zephyr/devicetree/map.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/*
* Copyright (c) 2025 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_DEVICETREE_MAP_H_
#define ZEPHYR_INCLUDE_DEVICETREE_MAP_H_

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup devicetree-map Devicetree Map API
*
* @brief Helper macros for handling map properties.
*
* This module provides helper macros that facilitate interrupt mapping and
* specifier mapping based on DeviceTree specifications. It enables the extraction
* and interpretation of mapping data represented as phandle-arrays.
*
* In a typical DeviceTree fragment, properties ending with "-map" specify:
* - The child specifier to be mapped.
* - The parent node (phandle) to which the mapping applies.
* - The parent specifier associated with the mapping.
*
* For example, when the following DeviceTree snippet are defined:
*
* @code{.dts}
* n: node {
* gpio-map = <0 1 &gpio0 2 3>, <4 5 &gpio0 6 7>;
* };
* @endcode
*
* In the first mapping entry:
* - `0 1` are the child specifiers.
* - &gpio0 is the parent node.
* - `2 3` are the parent specifiers.
*
* Since map properties are implemented as phandle-arrays, macros such as
* DT_PHANDLE_BY_IDX() and DT_PHA_BY_IDX() can be used to access individual elements.
*
* Both child and parent specifiers are treated as cells in a phandle-array.
* By default, each group of specifiers is given a sequential cell name
* (child_specifier_0, child_specifier_1, ..., parent_specifier_0, ...).
*
* If cell names are specified in dt-bindings, they will be used for the child specifier cell names.
* Parent specifiers always use the default naming convention.
*
* Example usage:
*
* A mapping entry is a phandle-array whose elements can be referenced as follows:
* - Child specifiers can be accessed via names such as `child_specifier_0`,
* `child_specifier_1`, ...
* - The parent node is accessed via DT_PHANDLE_BY_IDX().
* - Parent specifiers are accessed via names such as `parent_specifier_0`,
* `parent_specifier_1`, ...
*
* @code{.c}
* int cspec_0 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, child_specifier_0); // 0
* int cspec_1 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, child_specifier_1); // 1
* const struct device *parent =
* device_get_binding(DT_PHANDLE_BY_IDX(DT_NODELABEL(n), gpio_map, 0)); // &gpio0
* int pspec_0 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, parent_specifier_0); // 2
* int pspec_1 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, parent_specifier_1); // 3
* @endcode
*
* The map helper API also provides the following macros for convenient access to
* specific parts of a mapping entry:
* - DT_MAP_CHILD_SPECIFIER_ARGS()
* - DT_MAP_PARENT_SPECIFIER_ARGS()
* - DT_MAP_PARENT_ARG()
*
* These macros extract, respectively, the child specifier arguments, the parent specifier
* arguments, and the parent node argument from a mapping element identified by its node ID,
* property name, and index.
*
* For instance:
*
* @code{.c}
* #define SRC_AND_DST(node_id, prop, idx) \
* { GET_ARG_N(1, DT_MAP_CHILD_SPECIFIER_ARGS(node_id, prop, idx)), \
* GET_ARG_N(1, DT_MAP_PARENT_SPECIFIER_ARGS(node_id, prop, idx)) }
*
* int src_and_dst[2][] = {
* DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(n), gpio_map, SRC_AND_DST, (,))
* };
* @endcode
*
* The above expansion yields:
*
* @code{.c}
* int src_and_dst[2][] = {{0, 2}, {4, 6}};
* @endcode
*
* @ingroup devicetree
* @{
*/

/**
* @brief Extracts a specified range of arguments.
*
* This helper macro first skips a given number of arguments and then selects
* the first @p len arguments from the remaining list.
*
* @param start The number of arguments to skip.
* @param len The number of arguments to extract after skipping.
* @param ... The list of input arguments.
*/
#define DT_MAP_HELPER_DO_ARGS_RANGE(start, len, ...) \
GET_ARGS_FIRST_N(len, GET_ARGS_LESS_N(start, __VA_ARGS__))

/**
* @brief Extracts a range of mapping arguments for a specific field.
*
* This macro concatenates the field name with the appropriate suffixes to determine
* the starting index and length of the arguments for a map entry, and then extracts
* those arguments.
*
* @param name The mapping field name (e.g., CHILD_SPECIFIER, PARENT).
* @param node_id The node identifier.
* @param prop The property name in lowercase and underscores.
* @param idx The index of the mapping entry.
* @param ... Additional arguments corresponding to the mapping entry.
*/
#define DT_MAP_HELPER_ARGS_RANGE(name, node_id, prop, idx, ...) \
DT_MAP_HELPER_DO_ARGS_RANGE(DT_CAT3(DT_MAP_, name, _IDX)(node_id, prop, idx), \
DT_CAT3(DT_MAP_, name, _LEN)(node_id, prop, idx), __VA_ARGS__)

/**
* @brief Retrieves the mapping entry at the specified index.
*
* @param node_id The node identifier.
* @param prop The property name in lowercase with underscores.
* @param idx The mapping entry index.
* @return The mapping entry as a list of comma-separated values.
*/
#define DT_MAP_IDX(node_id, prop, idx) DT_CAT5(node_id, _P_, prop, _MAP_IDX_, idx)

/**
* @brief Returns the number of mapping entries for the given property.
*
* @param node_id The node identifier.
* @param prop The property name in lowercase with underscores.
* @return The total count of mapping entries.
*/
#define DT_MAP_LEN(node_id, prop) DT_CAT4(node_id, _P_, prop, _MAP_LEN)

/**
* @brief Retrieves the starting index of the child specifier cell within a mapping entry.
*
* @param node_id The node identifier.
* @param prop The property name.
* @param idx The mapping entry index.
* @return The starting index of the child specifier cell.
*/
#define DT_MAP_CHILD_SPECIFIER_IDX(node_id, prop, idx) \
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, CHILD_SPECIFIER_IDX)

/**
* @brief Returns the length (number of cells) of the child specifier within a mapping entry.
*
* @param node_id The node identifier.
* @param prop The property name.
* @param idx The mapping entry index.
* @return The length (in cells) of the child specifier.
*/
#define DT_MAP_CHILD_SPECIFIER_LEN(node_id, prop, idx) \
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, CHILD_SPECIFIER_LEN)

/**
* @brief Retrieves the starting index of the parent cell in a mapping entry.
*
* @param node_id The node identifier.
* @param prop The property name.
* @param idx The mapping entry index.
* @return The starting index of the parent cell.
*/
#define DT_MAP_PARENT_IDX(node_id, prop, idx) \
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_IDX)

/**
* @brief Returns the length (number of cells) of the parent cell in a mapping entry.
*
* @param node_id The node identifier.
* @param prop The property name.
* @param idx The mapping entry index.
* @return The length (in cells) of the parent cell.
*/
#define DT_MAP_PARENT_LEN(node_id, prop, idx) \
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_LEN)

/**
* @brief Retrieves the starting index of the parent specifier cell within a mapping entry.
*
* @param node_id The node identifier.
* @param prop The property name.
* @param idx The mapping entry index.
* @return The starting index of the parent specifier cell.
*/
#define DT_MAP_PARENT_SPECIFIER_IDX(node_id, prop, idx) \
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_SPECIFIER_IDX)

/**
* @brief Returns the length (number of cells) of the parent specifier in a mapping entry.
*
* @param node_id The node identifier.
* @param prop The property name.
* @param idx The mapping entry index.
* @return The length (in cells) of the parent specifier.
*/
#define DT_MAP_PARENT_SPECIFIER_LEN(node_id, prop, idx) \
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_SPECIFIER_LEN)

/**
* @brief Extracts the child specifier arguments from a mapping entry.
*
* This macro returns the comma-separated list of arguments for the child specifier.
*
* @param node_id The node identifier.
* @param prop The property name in lowercase with underscores.
* @param idx The mapping entry index.
* @return The child specifier arguments.
*/
#define DT_MAP_CHILD_SPECIFIER_ARGS(node_id, prop, idx) \
DT_MAP_HELPER_ARGS_RANGE(CHILD_SPECIFIER, node_id, prop, idx, \
DT_MAP_IDX(node_id, prop, idx))

/**
* @brief Extracts the parent node argument from a mapping entry.
*
* @param node_id The node identifier.
* @param prop The property name in lowercase with underscores.
* @param idx The mapping entry index.
* @return The parent node argument.
*/
#define DT_MAP_PARENT_ARG(node_id, prop, idx) \
DT_MAP_HELPER_ARGS_RANGE(PARENT, node_id, prop, idx, DT_MAP_IDX(node_id, prop, idx))

/**
* @brief Extracts the parent specifier arguments from a mapping entry.
*
* This macro returns the comma-separated list of arguments for the parent specifier.
*
* @param node_id The node identifier.
* @param prop The property name in lowercase with underscores.
* @param idx The mapping entry index.
* @return The parent specifier arguments.
*/
#define DT_MAP_PARENT_SPECIFIER_ARGS(node_id, prop, idx) \
DT_MAP_HELPER_ARGS_RANGE(PARENT_SPECIFIER, node_id, prop, idx, \
DT_MAP_IDX(node_id, prop, idx))

/**
* @}
*/

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_DEVICETREE_MAP_H_ */
Loading
Loading