Skip to content

Commit

Permalink
include: devicetree: Add port and endpoint macro header
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
ngphibang authored and kartben committed Dec 6, 2024
1 parent c4e840a commit 0a90167
Show file tree
Hide file tree
Showing 2 changed files with 276 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/zephyr/devicetree.h
Original file line number Diff line number Diff line change
Expand Up @@ -5242,5 +5242,6 @@
#include <zephyr/devicetree/can.h>
#include <zephyr/devicetree/reset.h>
#include <zephyr/devicetree/mbox.h>
#include <zephyr/devicetree/port-endpoint.h>

#endif /* ZEPHYR_INCLUDE_DEVICETREE_H_ */
275 changes: 275 additions & 0 deletions include/zephyr/devicetree/port-endpoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
/**
* @file
* @brief Port / Endpoint Devicetree macro public API header file.
*/

/*
* Copyright 2024 NXP
* Copyright (c) 2024 tinyVision.ai Inc
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_DEVICETREE_PORT_ENDPOINT_H_
#define ZEPHYR_INCLUDE_DEVICETREE_PORT_ENDPOINT_H_

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup devicetree-port-endpoint Devicetree Port Endpoint API
* @ingroup devicetree
* @{
*/

/**
* @brief Helper for @ref DT_INST_PORT_BY_ID
*
* This behaves the same way as @ref DT_INST_PORT_BY_ID but does not work if there is only
* a single port without address.
*
* @param inst instance number
* @param pid port ID
* @return port node associated with @p pid
*/
#define _DT_INST_PORT_BY_ID(inst, pid) \
COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, ports)), \
(DT_CHILD(DT_INST_CHILD(inst, ports), port_##pid)), (DT_INST_CHILD(inst, port_##pid)))

/**
* @brief Get a port node from its id
*
* Given a device instance number, return a port node specified by its ID.
* It handles various ways of how a port could be defined.
*
* Example usage with DT_INST_PORT_BY_ID() to get the @c port@0 or @c port node:
*
* @code{.c}
* DT_INST_PORT_BY_ID(inst, 0)
* @endcode
*
* Example devicetree fragment:
*
* @code{.dts}
* &device {
* ports {
* #address-cells = <1>;
* #size-cells = <0>;
* port@0 {
* reg = <0x0>;
* };
* };
* };
* @endcode
*
* @code{.dts}
* &device {
* #address-cells = <1>;
* #size-cells = <0>;
* port@0 {
* reg = <0x0>;
* };
* };
* @endcode
*
* @code{.dts}
* &device {
* port {
* };
* };
* @endcode
*
* @param inst instance number
* @param pid port ID
* @return port node associated with @p pid
*/
#define DT_INST_PORT_BY_ID(inst, pid) \
COND_CODE_1(DT_NODE_EXISTS(_DT_INST_PORT_BY_ID(inst, pid)), \
(_DT_INST_PORT_BY_ID(inst, pid)), (DT_INST_CHILD(inst, port)))

/**
* @brief Helper for @ref DT_INST_ENDPOINT_BY_ID
*
* This behaves the same way as @ref DT_INST_PORT_BY_ID but does not work if there is only
* a single endpoint without address.
*
* @param inst instance number
* @param pid port ID
* @param eid endpoint ID
* @return endpoint node associated with @p eid and @p pid
*/
#define _DT_INST_ENDPOINT_BY_ID(inst, pid, eid) \
DT_CHILD(DT_INST_PORT_BY_ID(inst, pid), endpoint_##eid)

/**
* @brief Get an endpoint node from its id and its parent port id
*
* Given a device instance number, a port ID and an endpoint ID, return the endpoint node.
* It handles various ways of how a port and an endpoint could be defined as described in
* @ref DT_INST_PORT_BY_ID and below.
*
* Example usage with DT_INST_ENDPOINT_BY_ID() to get the @c endpoint or @c endpoint@0 node:
*
* @code{.c}
* DT_INST_ENDPOINT_BY_ID(inst, 0, 0)
* @endcode
*
* Example devicetree fragment:
*
* @code{.dts}
* &device {
* port {
* endpoint {
* };
* };
* };
* @endcode
*
* @code{.dts}
* &device {
* port {
* #address-cells = <1>;
* #size-cells = <0>;
* endpoint@0 {
* reg = <0x0>;
* };
* };
* };
* @endcode
*
* @code{.dts}
* &device {
* ports {
* #address-cells = <1>;
* #size-cells = <0>;
* port@0 {
* reg = <0x0>;
* #address-cells = <1>;
* #size-cells = <0>;
* endpoint@0 {
* reg = <0x0>;
* };
* };
* };
* };
* @endcode
*
* @param inst instance number
* @param pid port ID
* @param eid endpoint ID
* @return endpoint node associated with @p eid and @p pid
*/
#define DT_INST_ENDPOINT_BY_ID(inst, pid, eid) \
COND_CODE_1(DT_NODE_EXISTS(_DT_INST_ENDPOINT_BY_ID(inst, pid, eid)), \
(_DT_INST_ENDPOINT_BY_ID(inst, pid, eid)), \
(DT_CHILD(DT_INST_PORT_BY_ID(inst, pid), endpoint)))

/**
* @brief Get the device node from its endpoint node.
*
* Given an endpoint node id, return its device node id.
* This handles various ways of how a port and an endpoint could be defined as described in
* @ref DT_NODE_BY_ENDPOINT.
*
* Example usage with DT_NODE_BY_ENDPOINT() to get the @c &device node from its @c ep0 node:
*
* @code{.c}
* DT_NODE_BY_ENDPOINT(DT_NODELABEL(ep0))
* @endcode
*
* Example devicetree fragment:
*
* @code{.dts}
* &device {
* port {
* #address-cells = <1>;
* #size-cells = <0>;
* ep0: endpoint@0 {
* reg = <0x0>;
* };
* };
* };
* @endcode
*
* @code{.dts}
* &device {
* ports {
* #address-cells = <1>;
* #size-cells = <0>;
* port@0 {
* reg = <0x0>;
* #address-cells = <1>;
* #size-cells = <0>;
* ep0: endpoint@0 {
* reg = <0x0>;
* };
* };
* };
* };
* @endcode
*
* @param ep endpoint node
* @return device node associated with @p ep
*/
#define DT_NODE_BY_ENDPOINT(ep) \
COND_CODE_1(DT_NODE_EXISTS(DT_CHILD(DT_PARENT(DT_GPARENT(ep)), ports)), \
(DT_PARENT(DT_GPARENT(ep))), (DT_GPARENT(ep)))

/**
* @brief Get the remote device node from a local endpoint node.
*
* Given an endpoint node id, return the remote device node that connects to this device via this
* local endpoint. This handles various ways of how a port and an endpoint could be defined as
* described in @ref DT_INST_PORT_BY_ID and @ref DT_INST_ENDPOINT_BY_ID.
*
* Example usage with DT_NODE_REMOTE_DEVICE() to get the remote device node @c &device1 from the
* local endpoint @c endpoint@0 node of the device @c &device0 node:
*
* @code{.c}
* DT_NODE_REMOTE_DEVICE(DT_NODELABEL(device0_ep_out))
* @endcode
*
* Example devicetree fragment:
*
* @code{.dts}
* &device0 {
* port {
* #address-cells = <1>;
* #size-cells = <0>;
* device0_ep_out: endpoint@0 {
* reg = <0x0>;
* remote-endpoint-label = "device1_ep_in";
* };
* };
* };
*
* &device1 {
* ports {
* #address-cells = <1>;
* #size-cells = <0>;
* port@0 {
* reg = <0x0>;
* device1_ep_in: endpoint {
* remote-endpoint-label = "device0_ep_out";
* };
* };
* };
* };
* @endcode
*
* @param ep endpoint node
* @return remote device node that connects to this device via @p ep
*/
#define DT_NODE_REMOTE_DEVICE(ep) \
DT_NODE_BY_ENDPOINT(DT_NODELABEL(DT_STRING_TOKEN(ep, remote_endpoint_label)))

/**
* @}
*/

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_DEVICETREE_PORT_ENDPOINT_H_ */

0 comments on commit 0a90167

Please sign in to comment.