dts: edtlib: Turn Node.instance_no into EDT.compat2enabled
Add an EDT.compat2enabled attribute that maps compatibles to enabled devicetree nodes that implement them. For example, EDT.compat2enabled["foo"] is a list of all enabled nodes with "foo" in the 'compatible' property. The old Node.instance_no functionality can be implemented in terms of EDT.compat2enabled, so remove Node.instance_no. EDT.compat2enabled is more flexible and easier to understand. Simplify main() in gen_defines.py by using EDT.compat2enabled to generate the DT_COMPAT_<compatible> existence macros. The behavior is slightly different now, as DT_COMPAT_<compatible> is generated for enabled nodes that don't have a binding as well, but that might be an improvement overall. It probably doesn't hurt at least. EDT.compat2enabled simplifies the implementation of the new $(dt_compat_get_str) preprocessor function in https://github.com/zephyrproject-rtos/zephyr/pull/21560. That was the original motivation. Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
This commit is contained in:
parent
1b394ad153
commit
88db84b89b
4 changed files with 75 additions and 34 deletions
|
@ -65,7 +65,7 @@ a .dts file to parse and a list of paths to directories containing bindings.
|
|||
# - Please use ""-quoted strings instead of ''-quoted strings, just to make
|
||||
# things consistent (''-quoting is more common otherwise in Python)
|
||||
|
||||
from collections import OrderedDict
|
||||
from collections import OrderedDict, defaultdict
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
@ -96,6 +96,25 @@ class EDT:
|
|||
nodes:
|
||||
A list of Node objects for the nodes that appear in the devicetree
|
||||
|
||||
compat2enabled:
|
||||
A collections.defaultdict that maps each 'compatible' string that appears
|
||||
on some enabled Node to a list of enabled Nodes.
|
||||
|
||||
For example, edt.compat2enabled["bar"] would include the 'foo' and 'bar'
|
||||
nodes below.
|
||||
|
||||
foo {
|
||||
compatible = "bar";
|
||||
status = "okay";
|
||||
...
|
||||
};
|
||||
bar {
|
||||
compatible = "foo", "bar", "baz";
|
||||
status = "okay";
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
dts_path:
|
||||
The .dts path passed to __init__()
|
||||
|
||||
|
@ -128,6 +147,7 @@ class EDT:
|
|||
|
||||
self._init_compat2binding(bindings_dirs)
|
||||
self._init_nodes()
|
||||
self._init_compat2enabled()
|
||||
|
||||
self._define_order()
|
||||
|
||||
|
@ -443,7 +463,6 @@ class EDT:
|
|||
node.bus_node = node._bus_node()
|
||||
node._init_binding()
|
||||
node._init_regs()
|
||||
node._set_instance_no()
|
||||
|
||||
self.nodes.append(node)
|
||||
self._node2enode[dt_node] = node
|
||||
|
@ -456,6 +475,15 @@ class EDT:
|
|||
node._init_interrupts()
|
||||
node._init_pinctrls()
|
||||
|
||||
def _init_compat2enabled(self):
|
||||
# Creates self.compat2enabled
|
||||
|
||||
self.compat2enabled = defaultdict(list)
|
||||
for node in self.nodes:
|
||||
if node.enabled:
|
||||
for compat in node.compats:
|
||||
self.compat2enabled[compat].append(node)
|
||||
|
||||
def _check_binding(self, binding, binding_path):
|
||||
# Does sanity checking on 'binding'. Only takes 'self' for the sake of
|
||||
# self._warn().
|
||||
|
@ -689,16 +717,6 @@ class Node:
|
|||
read_only:
|
||||
True if the node has a 'read-only' property, and False otherwise
|
||||
|
||||
instance_no:
|
||||
Dictionary that maps each 'compatible' string for the node to a unique
|
||||
index among all nodes that have that 'compatible' string.
|
||||
|
||||
As an example, 'instance_no["foo,led"] == 3' can be read as "this is the
|
||||
fourth foo,led node".
|
||||
|
||||
Only enabled nodes (status != "disabled") are counted. 'instance_no' is
|
||||
meaningless for disabled nodes.
|
||||
|
||||
matching_compat:
|
||||
The 'compatible' string for the binding that matched the node, or None if
|
||||
the node has no binding
|
||||
|
@ -1297,17 +1315,6 @@ class Node:
|
|||
|
||||
return OrderedDict(zip(cell_names, data_list))
|
||||
|
||||
def _set_instance_no(self):
|
||||
# Initializes self.instance_no
|
||||
|
||||
self.instance_no = {}
|
||||
|
||||
for compat in self.compats:
|
||||
self.instance_no[compat] = 0
|
||||
for other_node in self.edt.nodes:
|
||||
if compat in other_node.compats and other_node.enabled:
|
||||
self.instance_no[compat] += 1
|
||||
|
||||
|
||||
class Register:
|
||||
"""
|
||||
|
|
|
@ -42,8 +42,6 @@ def main():
|
|||
|
||||
write_top_comment(edt)
|
||||
|
||||
active_compats = set()
|
||||
|
||||
for node in edt.nodes:
|
||||
if node.enabled and node.matching_compat:
|
||||
# Skip 'fixed-partitions' devices since they are handled by
|
||||
|
@ -60,10 +58,8 @@ def main():
|
|||
write_bus(node)
|
||||
write_existence_flags(node)
|
||||
|
||||
active_compats.update(node.compats)
|
||||
|
||||
out_comment("Active compatibles (mentioned in DTS + binding found)")
|
||||
for compat in sorted(active_compats):
|
||||
out_comment("Compatibles appearing on enabled nodes")
|
||||
for compat in sorted(edt.compat2enabled):
|
||||
#define DT_COMPAT_<COMPAT> 1
|
||||
out(f"COMPAT_{str2ident(compat)}", 1)
|
||||
|
||||
|
@ -272,12 +268,13 @@ def write_bus(node):
|
|||
def write_existence_flags(node):
|
||||
# Generate #defines of the form
|
||||
#
|
||||
# #define DT_INST_<INSTANCE>_<COMPAT> 1
|
||||
# #define DT_INST_<instance no.>_<compatible string> 1
|
||||
#
|
||||
# These are flags for which devices exist.
|
||||
# for enabled nodes. These are flags for which devices exist.
|
||||
|
||||
for compat in node.compats:
|
||||
out(f"INST_{node.instance_no[compat]}_{str2ident(compat)}", 1)
|
||||
instance_no = node.edt.compat2enabled[compat].index(node)
|
||||
out(f"INST_{instance_no}_{str2ident(compat)}", 1)
|
||||
|
||||
|
||||
def node_ident(node):
|
||||
|
@ -337,8 +334,11 @@ def node_instance_aliases(node):
|
|||
# This is a list since a node can have multiple 'compatible' strings, each
|
||||
# with their own instance number.
|
||||
|
||||
return [f"INST_{node.instance_no[compat]}_{str2ident(compat)}"
|
||||
for compat in node.compats]
|
||||
res = []
|
||||
for compat in node.compats:
|
||||
instance_no = node.edt.compat2enabled[compat].index(node)
|
||||
res.append(f"INST_{instance_no}_{str2ident(compat)}")
|
||||
return res
|
||||
|
||||
|
||||
def write_addr_size(edt, prop_name, prefix):
|
||||
|
|
|
@ -294,6 +294,31 @@
|
|||
default-not-used = <234>;
|
||||
};
|
||||
|
||||
//
|
||||
// For testing EDT.compat2enabled
|
||||
//
|
||||
|
||||
compat2enabled {
|
||||
foo-1 {
|
||||
status = "okay";
|
||||
compatible = "compat2enabled";
|
||||
};
|
||||
foo-disabled {
|
||||
status = "disabled";
|
||||
compatible = "compat2enabled";
|
||||
};
|
||||
foo-2 {
|
||||
// No 'status', which is also treated as enabled
|
||||
compatible = "compat2enabled";
|
||||
};
|
||||
// Should not create an entry in compat2enabled, since all nodes
|
||||
// with the compatible are disabled
|
||||
bar {
|
||||
status = "disabled";
|
||||
compatible = "compat2enabled-disabled";
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// For testing 'bus:' and 'on-bus:'
|
||||
//
|
||||
|
|
|
@ -164,6 +164,15 @@ warning: "#cells:" in test-bindings/deprecated.yaml is deprecated and will be re
|
|||
verify_streq(edt.get_node("/deprecated/sub-node").props,
|
||||
"OrderedDict([('foos', <Property, name: foos, type: phandle-array, value: [<ControllerAndData, controller: <Node /deprecated in 'test.dts', binding test-bindings/deprecated.yaml>, data: OrderedDict([('foo', 1), ('bar', 2)])>]>)])")
|
||||
|
||||
#
|
||||
# Test EDT.compat2enabled
|
||||
#
|
||||
|
||||
verify_streq(edt.compat2enabled["compat2enabled"], "[<Node /compat2enabled/foo-1 in 'test.dts', no binding>, <Node /compat2enabled/foo-2 in 'test.dts', no binding>]")
|
||||
|
||||
if "compat2enabled-disabled" in edt.compat2enabled:
|
||||
fail("'compat2enabled-disabled' should not appear in edt.compat2enabled")
|
||||
|
||||
#
|
||||
# Test Node.props (derived from DT and 'properties:' in the binding)
|
||||
#
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue