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
|
# - Please use ""-quoted strings instead of ''-quoted strings, just to make
|
||||||
# things consistent (''-quoting is more common otherwise in Python)
|
# things consistent (''-quoting is more common otherwise in Python)
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict, defaultdict
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
@ -96,6 +96,25 @@ class EDT:
|
||||||
nodes:
|
nodes:
|
||||||
A list of Node objects for the nodes that appear in the devicetree
|
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:
|
dts_path:
|
||||||
The .dts path passed to __init__()
|
The .dts path passed to __init__()
|
||||||
|
|
||||||
|
@ -128,6 +147,7 @@ class EDT:
|
||||||
|
|
||||||
self._init_compat2binding(bindings_dirs)
|
self._init_compat2binding(bindings_dirs)
|
||||||
self._init_nodes()
|
self._init_nodes()
|
||||||
|
self._init_compat2enabled()
|
||||||
|
|
||||||
self._define_order()
|
self._define_order()
|
||||||
|
|
||||||
|
@ -443,7 +463,6 @@ class EDT:
|
||||||
node.bus_node = node._bus_node()
|
node.bus_node = node._bus_node()
|
||||||
node._init_binding()
|
node._init_binding()
|
||||||
node._init_regs()
|
node._init_regs()
|
||||||
node._set_instance_no()
|
|
||||||
|
|
||||||
self.nodes.append(node)
|
self.nodes.append(node)
|
||||||
self._node2enode[dt_node] = node
|
self._node2enode[dt_node] = node
|
||||||
|
@ -456,6 +475,15 @@ class EDT:
|
||||||
node._init_interrupts()
|
node._init_interrupts()
|
||||||
node._init_pinctrls()
|
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):
|
def _check_binding(self, binding, binding_path):
|
||||||
# Does sanity checking on 'binding'. Only takes 'self' for the sake of
|
# Does sanity checking on 'binding'. Only takes 'self' for the sake of
|
||||||
# self._warn().
|
# self._warn().
|
||||||
|
@ -689,16 +717,6 @@ class Node:
|
||||||
read_only:
|
read_only:
|
||||||
True if the node has a 'read-only' property, and False otherwise
|
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:
|
matching_compat:
|
||||||
The 'compatible' string for the binding that matched the node, or None if
|
The 'compatible' string for the binding that matched the node, or None if
|
||||||
the node has no binding
|
the node has no binding
|
||||||
|
@ -1297,17 +1315,6 @@ class Node:
|
||||||
|
|
||||||
return OrderedDict(zip(cell_names, data_list))
|
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:
|
class Register:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -42,8 +42,6 @@ def main():
|
||||||
|
|
||||||
write_top_comment(edt)
|
write_top_comment(edt)
|
||||||
|
|
||||||
active_compats = set()
|
|
||||||
|
|
||||||
for node in edt.nodes:
|
for node in edt.nodes:
|
||||||
if node.enabled and node.matching_compat:
|
if node.enabled and node.matching_compat:
|
||||||
# Skip 'fixed-partitions' devices since they are handled by
|
# Skip 'fixed-partitions' devices since they are handled by
|
||||||
|
@ -60,10 +58,8 @@ def main():
|
||||||
write_bus(node)
|
write_bus(node)
|
||||||
write_existence_flags(node)
|
write_existence_flags(node)
|
||||||
|
|
||||||
active_compats.update(node.compats)
|
out_comment("Compatibles appearing on enabled nodes")
|
||||||
|
for compat in sorted(edt.compat2enabled):
|
||||||
out_comment("Active compatibles (mentioned in DTS + binding found)")
|
|
||||||
for compat in sorted(active_compats):
|
|
||||||
#define DT_COMPAT_<COMPAT> 1
|
#define DT_COMPAT_<COMPAT> 1
|
||||||
out(f"COMPAT_{str2ident(compat)}", 1)
|
out(f"COMPAT_{str2ident(compat)}", 1)
|
||||||
|
|
||||||
|
@ -272,12 +268,13 @@ def write_bus(node):
|
||||||
def write_existence_flags(node):
|
def write_existence_flags(node):
|
||||||
# Generate #defines of the form
|
# 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:
|
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):
|
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
|
# This is a list since a node can have multiple 'compatible' strings, each
|
||||||
# with their own instance number.
|
# with their own instance number.
|
||||||
|
|
||||||
return [f"INST_{node.instance_no[compat]}_{str2ident(compat)}"
|
res = []
|
||||||
for compat in node.compats]
|
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):
|
def write_addr_size(edt, prop_name, prefix):
|
||||||
|
|
|
@ -294,6 +294,31 @@
|
||||||
default-not-used = <234>;
|
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:'
|
// 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,
|
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)])>]>)])")
|
"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)
|
# Test Node.props (derived from DT and 'properties:' in the binding)
|
||||||
#
|
#
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue