Skip to content

Commit 7d636f4

Browse files
committed
include: devicetree: Generate defines for map property
This change introduces generating definitions corresponding to `*-map` property, which was currently discarded. The `*-map` data is like a two-dimensional array, so it is difficult to handle with the existing APIs, so we will also provide new APIs. Signed-off-by: TOKITA Hiroshi <[email protected]>
1 parent 2bab58e commit 7d636f4

File tree

11 files changed

+455
-3
lines changed

11 files changed

+455
-3
lines changed

dts/bindings/gpio/gpio-nexus.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
properties:
77
gpio-map:
8-
type: compound
8+
type: phandle-array
99
required: true
1010

1111
gpio-map-mask:

dts/bindings/iio/io-channel-nexus.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
properties:
77
io-channel-map:
8-
type: compound
8+
type: phandle-array
99
required: true
1010

1111
io-channel-map-mask:

dts/bindings/interrupt-controller/interrupt-nexus.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
properties:
77
interrupt-map:
8-
type: compound
8+
type: phandle-array
99
required: true
1010

1111
interrupt-map-mask:

dts/bindings/test/vnd,gpio-nexus.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025, TOKITA Hiroshi
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: VND GPIO nexus
5+
6+
include: [gpio-nexus.yaml]
7+
8+
compatible: "vnd,gpio-nexus"

dts/bindings/test/vnd,intr-nexus.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025, TOKITA Hiroshi
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: VND interrupt nexus
5+
6+
include: [interrupt-nexus.yaml]
7+
8+
compatible: "vnd,intr-nexus"

include/zephyr/devicetree.h

+1
Original file line numberDiff line numberDiff line change
@@ -5343,5 +5343,6 @@
53435343
#include <zephyr/devicetree/reset.h>
53445344
#include <zephyr/devicetree/mbox.h>
53455345
#include <zephyr/devicetree/port-endpoint.h>
5346+
#include <zephyr/devicetree/map.h>
53465347

53475348
#endif /* ZEPHYR_INCLUDE_DEVICETREE_H_ */

include/zephyr/devicetree/map.h

+273
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
/*
2+
* Copyright (c) 2025 TOKITA Hiroshi
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_DEVICETREE_MAP_H_
8+
#define ZEPHYR_INCLUDE_DEVICETREE_MAP_H_
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
/**
15+
* @defgroup devicetree-map Devicetree Map API
16+
*
17+
* @brief Helper macros for handling map properties.
18+
*
19+
* This module provides helper macros that facilitate interrupt mapping and
20+
* specifier mapping based on DeviceTree specifications. It enables the extraction
21+
* and interpretation of mapping data represented as phandle-arrays.
22+
*
23+
* In a typical DeviceTree fragment, properties ending with "-map" specify:
24+
* - The child specifier to be mapped.
25+
* - The parent node (phandle) to which the mapping applies.
26+
* - The parent specifier associated with the mapping.
27+
*
28+
* For example, when the following DeviceTree snippet are defined:
29+
*
30+
* @code{.dts}
31+
* n: node {
32+
* gpio-map = <0 1 &gpio0 2 3>, <4 5 &gpio0 6 7>;
33+
* };
34+
* @endcode
35+
*
36+
* In the first mapping entry:
37+
* - `0 1` are the child specifiers.
38+
* - &gpio0 is the parent node.
39+
* - `2 3` are the parent specifiers.
40+
*
41+
* Since map properties are implemented as phandle-arrays, macros such as
42+
* DT_PHANDLE_BY_IDX() and DT_PHA_BY_IDX() can be used to access individual elements.
43+
*
44+
* Both child and parent specifiers are treated as cells in a phandle-array.
45+
* By default, each group of specifiers is given a sequential cell name
46+
* (child_specifier_0, child_specifier_1, ..., parent_specifier_0, ...).
47+
*
48+
* If cell names are specified in dt-bindings, they will be used for the child specifier cell names.
49+
* Parent specifiers always use the default naming convention.
50+
*
51+
* Example usage:
52+
*
53+
* A mapping entry is a phandle-array whose elements can be referenced as follows:
54+
* - Child specifiers can be accessed via names such as `child_specifier_0`,
55+
* `child_specifier_1`, ...
56+
* - The parent node is accessed via DT_PHANDLE_BY_IDX().
57+
* - Parent specifiers are accessed via names such as `parent_specifier_0`,
58+
* `parent_specifier_1`, ...
59+
*
60+
* @code{.c}
61+
* int cspec_0 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, child_specifier_0); // 0
62+
* int cspec_1 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, child_specifier_1); // 1
63+
* const struct device *parent =
64+
* device_get_binding(DT_PHANDLE_BY_IDX(DT_NODELABEL(n), gpio_map, 0)); // &gpio0
65+
* int pspec_0 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, parent_specifier_0); // 2
66+
* int pspec_1 = DT_PHA_BY_IDX(DT_NODELABEL(n), gpio_map, 0, parent_specifier_1); // 3
67+
* @endcode
68+
*
69+
* The map helper API also provides the following macros for convenient access to
70+
* specific parts of a mapping entry:
71+
* - DT_MAP_CHILD_SPECIFIER_ARGS()
72+
* - DT_MAP_PARENT_SPECIFIER_ARGS()
73+
* - DT_MAP_PARENT_ARG()
74+
*
75+
* These macros extract, respectively, the child specifier arguments, the parent specifier
76+
* arguments, and the parent node argument from a mapping element identified by its node ID,
77+
* property name, and index.
78+
*
79+
* For instance:
80+
*
81+
* @code{.c}
82+
* #define SRC_AND_DST(node_id, prop, idx) \
83+
* { GET_ARG_N(1, DT_MAP_CHILD_SPECIFIER_ARGS(node_id, prop, idx)), \
84+
* GET_ARG_N(1, DT_MAP_PARENT_SPECIFIER_ARGS(node_id, prop, idx)) }
85+
*
86+
* int src_and_dst[2][] = {
87+
* DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(n), gpio_map, SRC_AND_DST, (,))
88+
* };
89+
* @endcode
90+
*
91+
* The above expansion yields:
92+
*
93+
* @code{.c}
94+
* int src_and_dst[2][] = {{0, 2}, {4, 6}};
95+
* @endcode
96+
*
97+
* @ingroup devicetree
98+
* @{
99+
*/
100+
101+
/**
102+
* @brief Extracts a specified range of arguments.
103+
*
104+
* This helper macro first skips a given number of arguments and then selects
105+
* the first @p len arguments from the remaining list.
106+
*
107+
* @param start The number of arguments to skip.
108+
* @param len The number of arguments to extract after skipping.
109+
* @param ... The list of input arguments.
110+
*/
111+
#define DT_MAP_HELPER_DO_ARGS_RANGE(start, len, ...) \
112+
GET_ARGS_FIRST_N(len, GET_ARGS_LESS_N(start, __VA_ARGS__))
113+
114+
/**
115+
* @brief Extracts a range of mapping arguments for a specific field.
116+
*
117+
* This macro concatenates the field name with the appropriate suffixes to determine
118+
* the starting index and length of the arguments for a map entry, and then extracts
119+
* those arguments.
120+
*
121+
* @param name The mapping field name (e.g., CHILD_SPECIFIER, PARENT).
122+
* @param node_id The node identifier.
123+
* @param prop The property name in lowercase and underscores.
124+
* @param idx The index of the mapping entry.
125+
* @param ... Additional arguments corresponding to the mapping entry.
126+
*/
127+
#define DT_MAP_HELPER_ARGS_RANGE(name, node_id, prop, idx, ...) \
128+
DT_MAP_HELPER_DO_ARGS_RANGE(DT_CAT3(DT_MAP_, name, _IDX)(node_id, prop, idx), \
129+
DT_CAT3(DT_MAP_, name, _LEN)(node_id, prop, idx), __VA_ARGS__)
130+
131+
/**
132+
* @brief Extracts arguments by skipping a specified number of elements.
133+
*
134+
* This helper macro applies GET_ARGS_LESS_N to the provided argument list.
135+
*
136+
* @param N The number of arguments to skip.
137+
* @param ... The list of input arguments.
138+
*/
139+
#define DT_MAP_HELPER_ARGS_LESS_N(N, ...) GET_ARGS_LESS_N(N, __VA_ARGS__)
140+
141+
/**
142+
* @brief Retrieves the mapping entry at the specified index.
143+
*
144+
* @param node_id The node identifier.
145+
* @param prop The property name in lowercase with underscores.
146+
* @param idx The mapping entry index.
147+
* @return The mapping entry as a list of comma-separated values.
148+
*/
149+
#define DT_MAP_IDX(node_id, prop, idx) DT_CAT5(node_id, _P_, prop, _MAP_IDX_, idx)
150+
151+
/**
152+
* @brief Returns the number of mapping entries for the given property.
153+
*
154+
* @param node_id The node identifier.
155+
* @param prop The property name in lowercase with underscores.
156+
* @return The total count of mapping entries.
157+
*/
158+
#define DT_MAP_LEN(node_id, prop) DT_CAT4(node_id, _P_, prop, _MAP_LEN)
159+
160+
/**
161+
* @brief Retrieves the starting index of the child specifier cell within a mapping entry.
162+
*
163+
* @param node_id The node identifier.
164+
* @param prop The property name.
165+
* @param idx The mapping entry index.
166+
* @return The starting index of the child specifier cell.
167+
*/
168+
#define DT_MAP_CHILD_SPECIFIER_IDX(node_id, prop, idx) \
169+
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, CHILD_SPECIFIER_IDX)
170+
171+
/**
172+
* @brief Returns the length (number of cells) of the child specifier within a mapping entry.
173+
*
174+
* @param node_id The node identifier.
175+
* @param prop The property name.
176+
* @param idx The mapping entry index.
177+
* @return The length (in cells) of the child specifier.
178+
*/
179+
#define DT_MAP_CHILD_SPECIFIER_LEN(node_id, prop, idx) \
180+
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, CHILD_SPECIFIER_LEN)
181+
182+
/**
183+
* @brief Retrieves the starting index of the parent cell in a mapping entry.
184+
*
185+
* @param node_id The node identifier.
186+
* @param prop The property name.
187+
* @param idx The mapping entry index.
188+
* @return The starting index of the parent cell.
189+
*/
190+
#define DT_MAP_PARENT_IDX(node_id, prop, idx) \
191+
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_IDX)
192+
193+
/**
194+
* @brief Returns the length (number of cells) of the parent cell in a mapping entry.
195+
*
196+
* @param node_id The node identifier.
197+
* @param prop The property name.
198+
* @param idx The mapping entry index.
199+
* @return The length (in cells) of the parent cell.
200+
*/
201+
#define DT_MAP_PARENT_LEN(node_id, prop, idx) \
202+
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_LEN)
203+
204+
/**
205+
* @brief Retrieves the starting index of the parent specifier cell within a mapping entry.
206+
*
207+
* @param node_id The node identifier.
208+
* @param prop The property name.
209+
* @param idx The mapping entry index.
210+
* @return The starting index of the parent specifier cell.
211+
*/
212+
#define DT_MAP_PARENT_SPECIFIER_IDX(node_id, prop, idx) \
213+
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_SPECIFIER_IDX)
214+
215+
/**
216+
* @brief Returns the length (number of cells) of the parent specifier in a mapping entry.
217+
*
218+
* @param node_id The node identifier.
219+
* @param prop The property name.
220+
* @param idx The mapping entry index.
221+
* @return The length (in cells) of the parent specifier.
222+
*/
223+
#define DT_MAP_PARENT_SPECIFIER_LEN(node_id, prop, idx) \
224+
DT_CAT7(node_id, _P_, prop, _MAP_IDX_, idx, _, PARENT_SPECIFIER_LEN)
225+
226+
/**
227+
* @brief Extracts the child specifier arguments from a mapping entry.
228+
*
229+
* This macro returns the comma-separated list of arguments for the child specifier.
230+
*
231+
* @param node_id The node identifier.
232+
* @param prop The property name in lowercase with underscores.
233+
* @param idx The mapping entry index.
234+
* @return The child specifier arguments.
235+
*/
236+
#define DT_MAP_CHILD_SPECIFIER_ARGS(node_id, prop, idx) \
237+
DT_MAP_HELPER_ARGS_RANGE(CHILD_SPECIFIER, node_id, prop, idx, \
238+
DT_MAP_IDX(node_id, prop, idx))
239+
240+
/**
241+
* @brief Extracts the parent node argument from a mapping entry.
242+
*
243+
* @param node_id The node identifier.
244+
* @param prop The property name in lowercase with underscores.
245+
* @param idx The mapping entry index.
246+
* @return The parent node argument.
247+
*/
248+
#define DT_MAP_PARENT_ARG(node_id, prop, idx) \
249+
DT_MAP_HELPER_ARGS_RANGE(PARENT, node_id, prop, idx, DT_MAP_IDX(node_id, prop, idx))
250+
251+
/**
252+
* @brief Extracts the parent specifier arguments from a mapping entry.
253+
*
254+
* This macro returns the comma-separated list of arguments for the parent specifier.
255+
*
256+
* @param node_id The node identifier.
257+
* @param prop The property name in lowercase with underscores.
258+
* @param idx The mapping entry index.
259+
* @return The parent specifier arguments.
260+
*/
261+
#define DT_MAP_PARENT_SPECIFIER_ARGS(node_id, prop, idx) \
262+
DT_MAP_HELPER_ARGS_RANGE(PARENT_SPECIFIER, node_id, prop, idx, \
263+
DT_MAP_IDX(node_id, prop, idx))
264+
265+
/**
266+
* @}
267+
*/
268+
269+
#ifdef __cplusplus
270+
}
271+
#endif
272+
273+
#endif /* ZEPHYR_INCLUDE_DEVICETREE_MAP_H_ */

scripts/dts/gen_defines.py

+30
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,36 @@ def phandle_macros(prop: edtlib.Property, macro: str) -> dict:
832832

833833
ret.update(controller_and_data_macros(entry, i, macro))
834834

835+
if prop.name.endswith("-map"):
836+
ret.update(map_macros(prop, macro))
837+
838+
return ret
839+
840+
841+
def map_macros(prop: edtlib.Property, macro: str) -> dict:
842+
ret = {}
843+
844+
for i, cd in enumerate(prop.val):
845+
parent_specifier_len = len([k for k in cd.data if k.startswith('parent_specifier_')])
846+
child_specifiers = list(cd.data.values())[:-parent_specifier_len]
847+
parent_specifiers = list(cd.data.values())[-parent_specifier_len:]
848+
child_specifier_len = len(child_specifiers)
849+
850+
args = []
851+
args.extend([str(v) for v in child_specifiers])
852+
args.extend(["DT_" + node_z_path_id(cd.controller)])
853+
args.extend([str(v) for v in parent_specifiers])
854+
855+
ret[f"{macro}_MAP_IDX_{i}_CHILD_SPECIFIER_IDX"] = 0
856+
ret[f"{macro}_MAP_IDX_{i}_CHILD_SPECIFIER_LEN"] = child_specifier_len
857+
ret[f"{macro}_MAP_IDX_{i}_PARENT_IDX"] = child_specifier_len
858+
ret[f"{macro}_MAP_IDX_{i}_PARENT_LEN"] = 1
859+
ret[f"{macro}_MAP_IDX_{i}_PARENT_SPECIFIER_IDX"] = child_specifier_len + 1
860+
ret[f"{macro}_MAP_IDX_{i}_PARENT_SPECIFIER_LEN"] = parent_specifier_len
861+
ret[f"{macro}_MAP_IDX_{i}"] = ", ".join(args)
862+
863+
ret[f"{macro}_MAP_LEN"] = len(prop.val)
864+
835865
return ret
836866

837867

0 commit comments

Comments
 (0)