Skip to content

Commit 0c68dfd

Browse files
committed
include: devicetree: Add port and endpoint macro header
Add port and endpoint DT macros to retrieve the node id of the interested port/endpoint from its id. Also, add helpers to retrieve the peer remote device node from its local endpoint interface. Signed-off-by: Phi Bang Nguyen <[email protected]> Co-developed-by: Josuah Demangeon <[email protected]>
1 parent 6682a10 commit 0c68dfd

File tree

2 files changed

+276
-0
lines changed

2 files changed

+276
-0
lines changed

include/zephyr/devicetree.h

+1
Original file line numberDiff line numberDiff line change
@@ -5242,5 +5242,6 @@
52425242
#include <zephyr/devicetree/can.h>
52435243
#include <zephyr/devicetree/reset.h>
52445244
#include <zephyr/devicetree/mbox.h>
5245+
#include <zephyr/devicetree/port-endpoint.h>
52455246

52465247
#endif /* ZEPHYR_INCLUDE_DEVICETREE_H_ */
+275
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
/**
2+
* @file
3+
* @brief Port / Endpoint Devicetree macro public API header file.
4+
*/
5+
6+
/*
7+
* Copyright 2024 NXP
8+
* Copyright (c) 2024 tinyVision.ai Inc
9+
*
10+
* SPDX-License-Identifier: Apache-2.0
11+
*/
12+
13+
#ifndef ZEPHYR_INCLUDE_DEVICETREE_PORT_ENDPOINT_H_
14+
#define ZEPHYR_INCLUDE_DEVICETREE_PORT_ENDPOINT_H_
15+
16+
#ifdef __cplusplus
17+
extern "C" {
18+
#endif
19+
20+
/**
21+
* @defgroup devicetree-port-endpoint Devicetree Port Endpoint API
22+
* @ingroup devicetree
23+
* @{
24+
*/
25+
26+
/**
27+
* @brief Helper for @ref DT_INST_PORT_BY_ID
28+
*
29+
* This behaves the same way as @ref DT_INST_PORT_BY_ID but does not work if there is only
30+
* a single port without address.
31+
*
32+
* @param inst instance number
33+
* @param pid port ID
34+
* @return port node associated with @p pid
35+
*/
36+
#define _DT_INST_PORT_BY_ID(inst, pid) \
37+
COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, ports)), \
38+
(DT_CHILD(DT_INST_CHILD(inst, ports), port_##pid)), (DT_INST_CHILD(inst, port_##pid)))
39+
40+
/**
41+
* @brief Get a port node from its id
42+
*
43+
* Given a device instance number, return a port node specified by its ID.
44+
* It handles various ways of how a port could be defined.
45+
*
46+
* Example usage with DT_INST_PORT_BY_ID() to get the @c port@0 or @c port node:
47+
*
48+
* @code{.c}
49+
* DT_INST_PORT_BY_ID(inst, 0)
50+
* @endcode
51+
*
52+
* Example devicetree fragment:
53+
*
54+
* @code{.dts}
55+
* &device {
56+
* ports {
57+
* #address-cells = <1>;
58+
* #size-cells = <0>;
59+
* port@0 {
60+
* reg = <0x0>;
61+
* };
62+
* };
63+
* };
64+
* @endcode
65+
*
66+
* @code{.dts}
67+
* &device {
68+
* #address-cells = <1>;
69+
* #size-cells = <0>;
70+
* port@0 {
71+
* reg = <0x0>;
72+
* };
73+
* };
74+
* @endcode
75+
*
76+
* @code{.dts}
77+
* &device {
78+
* port {
79+
* };
80+
* };
81+
* @endcode
82+
*
83+
* @param inst instance number
84+
* @param pid port ID
85+
* @return port node associated with @p pid
86+
*/
87+
#define DT_INST_PORT_BY_ID(inst, pid) \
88+
COND_CODE_1(DT_NODE_EXISTS(_DT_INST_PORT_BY_ID(inst, pid)), \
89+
(_DT_INST_PORT_BY_ID(inst, pid)), (DT_INST_CHILD(inst, port)))
90+
91+
/**
92+
* @brief Helper for @ref DT_INST_ENDPOINT_BY_ID
93+
*
94+
* This behaves the same way as @ref DT_INST_PORT_BY_ID but does not work if there is only
95+
* a single endpoint without address.
96+
*
97+
* @param inst instance number
98+
* @param pid port ID
99+
* @param eid endpoint ID
100+
* @return endpoint node associated with @p eid and @p pid
101+
*/
102+
#define _DT_INST_ENDPOINT_BY_ID(inst, pid, eid) \
103+
DT_CHILD(DT_INST_PORT_BY_ID(inst, pid), endpoint_##eid)
104+
105+
/**
106+
* @brief Get an endpoint node from its id and its parent port id
107+
*
108+
* Given a device instance number, a port ID and an endpoint ID, return the endpoint node.
109+
* It handles various ways of how a port and an endpoint could be defined as described in
110+
* @ref DT_INST_PORT_BY_ID and below.
111+
*
112+
* Example usage with DT_INST_ENDPOINT_BY_ID() to get the @c endpoint or @c endpoint@0 node:
113+
*
114+
* @code{.c}
115+
* DT_INST_ENDPOINT_BY_ID(inst, 0, 0)
116+
* @endcode
117+
*
118+
* Example devicetree fragment:
119+
*
120+
* @code{.dts}
121+
* &device {
122+
* port {
123+
* endpoint {
124+
* };
125+
* };
126+
* };
127+
* @endcode
128+
*
129+
* @code{.dts}
130+
* &device {
131+
* port {
132+
* #address-cells = <1>;
133+
* #size-cells = <0>;
134+
* endpoint@0 {
135+
* reg = <0x0>;
136+
* };
137+
* };
138+
* };
139+
* @endcode
140+
*
141+
* @code{.dts}
142+
* &device {
143+
* ports {
144+
* #address-cells = <1>;
145+
* #size-cells = <0>;
146+
* port@0 {
147+
* reg = <0x0>;
148+
* #address-cells = <1>;
149+
* #size-cells = <0>;
150+
* endpoint@0 {
151+
* reg = <0x0>;
152+
* };
153+
* };
154+
* };
155+
* };
156+
* @endcode
157+
*
158+
* @param inst instance number
159+
* @param pid port ID
160+
* @param eid endpoint ID
161+
* @return endpoint node associated with @p eid and @p pid
162+
*/
163+
#define DT_INST_ENDPOINT_BY_ID(inst, pid, eid) \
164+
COND_CODE_1(DT_NODE_EXISTS(_DT_INST_ENDPOINT_BY_ID(inst, pid, eid)), \
165+
(_DT_INST_ENDPOINT_BY_ID(inst, pid, eid)), \
166+
(DT_CHILD(DT_INST_PORT_BY_ID(inst, pid), endpoint)))
167+
168+
/**
169+
* @brief Get the device node from its endpoint node.
170+
*
171+
* Given an endpoint node id, return its device node id.
172+
* This handles various ways of how a port and an endpoint could be defined as described in
173+
* @ref DT_NODE_BY_ENDPOINT.
174+
*
175+
* Example usage with DT_NODE_BY_ENDPOINT() to get the @c &device node from its @c ep0 node:
176+
*
177+
* @code{.c}
178+
* DT_NODE_BY_ENDPOINT(DT_NODELABEL(ep0))
179+
* @endcode
180+
*
181+
* Example devicetree fragment:
182+
*
183+
* @code{.dts}
184+
* &device {
185+
* port {
186+
* #address-cells = <1>;
187+
* #size-cells = <0>;
188+
* ep0: endpoint@0 {
189+
* reg = <0x0>;
190+
* };
191+
* };
192+
* };
193+
* @endcode
194+
*
195+
* @code{.dts}
196+
* &device {
197+
* ports {
198+
* #address-cells = <1>;
199+
* #size-cells = <0>;
200+
* port@0 {
201+
* reg = <0x0>;
202+
* #address-cells = <1>;
203+
* #size-cells = <0>;
204+
* ep0: endpoint@0 {
205+
* reg = <0x0>;
206+
* };
207+
* };
208+
* };
209+
* };
210+
* @endcode
211+
*
212+
* @param ep endpoint node
213+
* @return device node associated with @p ep
214+
*/
215+
#define DT_NODE_BY_ENDPOINT(ep) \
216+
COND_CODE_1(DT_NODE_EXISTS(DT_CHILD(DT_PARENT(DT_GPARENT(ep)), ports)), \
217+
(DT_PARENT(DT_GPARENT(ep))), (DT_GPARENT(ep)))
218+
219+
/**
220+
* @brief Get the remote device node from a local endpoint node.
221+
*
222+
* Given an endpoint node id, return the remote device node that connects to this device via this
223+
* local endpoint. This handles various ways of how a port and an endpoint could be defined as
224+
* described in @ref DT_INST_PORT_BY_ID and @ref DT_INST_ENDPOINT_BY_ID.
225+
*
226+
* Example usage with DT_NODE_REMOTE_DEVICE() to get the remote device node @c &device1 from the
227+
* local endpoint @c endpoint@0 node of the device @c &device0 node:
228+
*
229+
* @code{.c}
230+
* DT_NODE_REMOTE_DEVICE(DT_NODELABEL(device0_ep_out))
231+
* @endcode
232+
*
233+
* Example devicetree fragment:
234+
*
235+
* @code{.dts}
236+
* &device0 {
237+
* port {
238+
* #address-cells = <1>;
239+
* #size-cells = <0>;
240+
* device0_ep_out: endpoint@0 {
241+
* reg = <0x0>;
242+
* remote-endpoint-label = "device1_ep_in";
243+
* };
244+
* };
245+
* };
246+
*
247+
* &device1 {
248+
* ports {
249+
* #address-cells = <1>;
250+
* #size-cells = <0>;
251+
* port@0 {
252+
* reg = <0x0>;
253+
* device1_ep_in: endpoint {
254+
* remote-endpoint-label = "device0_ep_out";
255+
* };
256+
* };
257+
* };
258+
* };
259+
* @endcode
260+
*
261+
* @param ep endpoint node
262+
* @return remote device node that connects to this device via @p ep
263+
*/
264+
#define DT_NODE_REMOTE_DEVICE(ep) \
265+
DT_NODE_BY_ENDPOINT(DT_NODELABEL(DT_STRING_TOKEN(ep, remote_endpoint_label)))
266+
267+
/**
268+
* @}
269+
*/
270+
271+
#ifdef __cplusplus
272+
}
273+
#endif
274+
275+
#endif /* ZEPHYR_INCLUDE_DEVICETREE_PORT_ENDPOINT_H_ */

0 commit comments

Comments
 (0)