Skip to content
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

devicetree: add phandles support for chosen properties #84890

Open
wants to merge 1 commit 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
6 changes: 3 additions & 3 deletions cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4362,7 +4362,7 @@ function(dt_has_chosen var)
endif()
endforeach()

get_target_property(exists devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
get_target_property(exists devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}-0")

if(${exists} STREQUAL exists-NOTFOUND)
set(${var} FALSE PARENT_SCOPE)
Expand All @@ -4374,7 +4374,7 @@ endfunction()
# Usage:
# dt_chosen(<var> PROPERTY <prop>)
#
# Get a node path for a /chosen node property.
# Get path of the 1st node in a /chosen node property.
#
# The node's path will be returned in the <var> parameter. The
# variable will be left undefined if the chosen node does not exist.
Expand All @@ -4397,7 +4397,7 @@ function(dt_chosen var)
endif()
endforeach()

get_target_property(${var} devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
get_target_property(${var} devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}-0")

if(${${var}} STREQUAL ${var}-NOTFOUND)
set(${var} PARENT_SCOPE)
Expand Down
61 changes: 58 additions & 3 deletions include/zephyr/devicetree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2909,18 +2909,73 @@
* This is only valid to call if `DT_HAS_CHOSEN(prop)` is 1.
* @param prop lowercase-and-underscores property name for
* the /chosen node
* @return a node identifier for the chosen node property
* @return a node identifier for the 1st node of the chosen property
*/
#define DT_CHOSEN(prop) DT_CAT(DT_CHOSEN_, prop)
#define DT_CHOSEN(prop) DT_CAT3(DT_CHOSEN_, prop, _0)

/**
* @brief Test if the devicetree has a `/chosen` node
* @param prop lowercase-and-underscores devicetree property
* @return 1 if the chosen property exists and refers to a node,
* 0 otherwise
*/
#define DT_HAS_CHOSEN(prop) IS_ENABLED(DT_CAT3(DT_CHOSEN_, prop, _EXISTS))
#define DT_HAS_CHOSEN(prop) IS_ENABLED(DT_CAT4(DT_CHOSEN_, prop, _0, _EXISTS))

/**
* @brief Get a node identifier for a `/chosen` node property at an index.
*
* When a `/chosen` node's value at a logical index contains a phandle, this
* macro returns a node identifier for the node with that phandle.
*
* Example devicetree fragment:
*
* @code{.dts}
* chosen {
* zephyr,foo = <&n2 &n3>;
* };
*
* n2: node-2 { ... };
* n3: node-3 { ... };
* @endcode
*
* Above, `zephyr,foo` chosen property has two elements:
*
* - index 0 has phandle `&n2`, which is `node-2`'s phandle
* - index 1 has phandle `&n3`, which is `node-3`'s phandle
*
* Example usage:
*
* @code{.c}
*
* DT_CHOSEN_NODE_BY_IDX(zephyr_foo, 0) // node identifier for node-2
* DT_CHOSEN_NODE_BY_IDX(zephyr_foo, 1) // node identifier for node-3
* @endcode
*
* This is only valid to call if `DT_CHOSEN_HAS_NODE_IDX(prop, idx)` is 1.
* @param prop lowercase-and-underscores `/chosen` node property name
* @param idx index into @p prop
* @return node identifier for the node with the phandle at that index
*/
#define DT_CHOSEN_NODE_BY_IDX(prop, idx) DT_CAT3(DT_CHOSEN_, prop, _##idx)

/**
* @brief Test if @p prop of devicetree `/chosen` node has phandle of index @p idx
* @param prop lowercase-and-underscores devicetree property
* @param idx index into @p prop
* @return 1 if phandle of index idx of chosen property exists and refers to a node,
* 0 otherwise
*/
#define DT_CHOSEN_HAS_NODE_IDX(prop, idx) IS_ENABLED(DT_CAT4(DT_CHOSEN_, prop, _##idx, _EXISTS))

/**
* @brief Get number of phandles assigned to @p prop of devicetree `/chosen` node
* @param prop lowercase-and-underscores devicetree property
* @return number of phandles of `/chosen` node property
*/
#define DT_CHOSEN_NODES_NBR(prop) \
COND_CODE_1(DT_HAS_CHOSEN(prop), \
(DT_CAT3(DT_CHOSEN_, prop, _NODES_NBR)), \
(0))
/**
* @}
*/
Expand Down
9 changes: 6 additions & 3 deletions scripts/dts/gen_defines.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,9 +881,12 @@ def write_chosen(edt: edtlib.EDT):

out_comment("Chosen nodes\n")
chosen = {}
for name, node in edt.chosen_nodes.items():
chosen[f"DT_CHOSEN_{str2ident(name)}"] = f"DT_{node.z_path_id}"
chosen[f"DT_CHOSEN_{str2ident(name)}_EXISTS"] = 1
for name, prop_nodes_list in edt.chosen_props_nodes.items():
chosen[f"DT_CHOSEN_{str2ident(name)}_NODES_NBR"] = len(prop_nodes_list)
for node_index, node in enumerate(prop_nodes_list):
chosen[f"DT_CHOSEN_{str2ident(name)}_{node_index}"] = f"DT_{node.z_path_id}"
chosen[f"DT_CHOSEN_{str2ident(name)}_{node_index}_EXISTS"] = 1

max_len = max(map(len, chosen), default=0)
for macro, value in chosen.items():
out_define(macro, value, width=max_len)
Expand Down
8 changes: 4 additions & 4 deletions scripts/dts/gen_dts_cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ def main():
# macros.bnf for C macros.

cmake_props = []
chosen_nodes = edt.chosen_nodes
for node in chosen_nodes:
path = chosen_nodes[node].path
cmake_props.append(f'"DT_CHOSEN|{node}" "{path}"')
chosen_nodes = edt.chosen_props_nodes
for prop_name in chosen_nodes:
for index, node in enumerate(chosen_nodes[prop_name]):
cmake_props.append(f'"DT_CHOSEN|{prop_name}-{index}" "{node.path}"')

# The separate loop over edt.nodes here is meant to keep
# all of the alias-related properties in one place.
Expand Down
33 changes: 21 additions & 12 deletions scripts/dts/python-devicetree/src/devicetree/edtlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1902,11 +1902,11 @@ class EDT:
dep_ord2node:
A dict that maps an ordinal to the node with that dependency ordinal.

chosen_nodes:
chosen_props_nodes:
A dict that maps the properties defined on the devicetree's /chosen
node to their values. 'chosen' is indexed by property name (a string),
and values are converted to Node objects. Note that properties of the
/chosen node which can't be converted to a Node are not included in
node to a list of nodes. 'chosen' is indexed by property name (a string),
and values are converted to a list of Node objects. Note that properties
of the /chosen node which can't be converted to nodes are not included in
the value.

dts_path:
Expand Down Expand Up @@ -2048,31 +2048,40 @@ def get_node(self, path: str) -> Node:
_err(e)

@property
def chosen_nodes(self) -> dict[str, Node]:
ret: dict[str, Node] = {}
def chosen_props_nodes(self) -> dict[str, list[Node]]:
ret: dict[str, list[Node]] = {}

try:
chosen = self._dt.get_node("/chosen")
except DTError:
return ret

for name, prop in chosen.props.items():
for prop_name, prop in chosen.props.items():
try:
node = prop.to_path()
if prop.type == Type.PHANDLES:
ret[prop_name] = [self._node2enode[node] for node in prop.to_nodes()]
else:
ret[prop_name] = [self._node2enode[prop.to_path()]]
except DTError:
# DTS value is not phandle or string, or path doesn't exist
# DTS value is not phandle, phandles, or string, or path doesn't exist
continue

ret[name] = self._node2enode[node]

return ret

def chosen_prop_nodes(self, name: str) -> Optional[list[Node]]:
"""
Returns a list of Nodes pointed at by the property named 'name' in /chosen, or
None if the property is missing
"""
return self.chosen_props_nodes.get(name)

def chosen_node(self, name: str) -> Optional[Node]:
"""
Returns the Node pointed at by the property named 'name' in /chosen, or
None if the property is missing
"""
return self.chosen_nodes.get(name)
nodes = self.chosen_props_nodes.get(name)
return nodes[0] if nodes else None

@property
def dts_source(self) -> str:
Expand Down
Loading