From 0a9016731f68ac16402961a21faa49ad1ae21bb2 Mon Sep 17 00:00:00 2001 From: Phi Bang Nguyen Date: Wed, 30 Oct 2024 18:31:25 +0100 Subject: [PATCH] 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 Co-developed-by: Josuah Demangeon --- include/zephyr/devicetree.h | 1 + include/zephyr/devicetree/port-endpoint.h | 275 ++++++++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 include/zephyr/devicetree/port-endpoint.h diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 3b50512f50688d..55b428cbb38426 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -5242,5 +5242,6 @@ #include #include #include +#include #endif /* ZEPHYR_INCLUDE_DEVICETREE_H_ */ diff --git a/include/zephyr/devicetree/port-endpoint.h b/include/zephyr/devicetree/port-endpoint.h new file mode 100644 index 00000000000000..08ff0ee35fa470 --- /dev/null +++ b/include/zephyr/devicetree/port-endpoint.h @@ -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_ */