Skip to content

Commit 4ba3878

Browse files
Johan Hedbergjhedberg
authored andcommitted
edtlib: Match any parent bus when binding lacks an explicit on-bus
There are some drivers in the tree that support devices on multiple different buses, although so far this has not been represented in device tree using the bus concept. In order to convert these drivers & bindings to refer to a formal bus in device tree we need to be able to match bindings which lack an explicit "on-bus: ..." value against any parent bus. This will also be needed for any external bindings, since those would not be aware of on-bus (as it's a Zephyhr-specific extension). The two drivers I'm particularly targeting is the ns16550 UART driver (drivers/serial/uart_ns16550.c) and the DW I2C driver (drivers/i2c/i2c_dw.c). They both support devices with a fixed MMIO address as well as devices connected and discovered over PCIe. The only issue is that instead of encoding the bus information the proper DT way these bindings use a special "pcie" property in the DT node entries to indicate whether the node is on the PCIe bus or not. Being able to convert the above two drivers to use the DT bus concept allow the removal of "hacks" like this: if DT_INST_PROP(0, pcie) || \ DT_INST_PROP(1, pcie) || \ DT_INST_PROP(2, pcie) || \ DT_INST_PROP(3, pcie) to the more intuitive: if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) This also has the benefit that the driver doesn't need to make any arbitrary assumptions of how many matching devices there may be but works for any number of matches. This is already a problem now since e.g. the ns16550 driver assumes a maximum of 4 nodes, whereas dts/x86/elkhart_lake.dtsi defines up to 9 different ns16550 nodes. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
1 parent 2b49266 commit 4ba3878

File tree

5 files changed

+54
-16
lines changed

5 files changed

+54
-16
lines changed

dts/binding-template.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,12 @@ bus: <string describing bus type, e.g. "i2c">
6969
#
7070
# When looking for a binding for a node, the code checks if the binding for the
7171
# parent node contains 'bus: <bus type>'. If it does, then only bindings with a
72-
# matching 'on-bus: <bus type>' are considered. This allows the same type of
73-
# device to have different bindings depending on what bus it appears on.
72+
# matching 'on-bus: <bus type>' and bindings without an explicit 'on-bus'
73+
# are considered. Bindings with an explicit 'on-bus: <bus type>' are looked
74+
# for first, and if none is found bindings without an explicit `on-bus` are
75+
# attempted. These two tests are done for each item in the `compatible` array
76+
# in the order specified. This allows the same type of device to have different
77+
# bindings depending on what bus it appears on.
7478
on-bus: <string describing bus type, e.g. "i2c">
7579

7680
# 'properties' describes properties on the node, e.g.

scripts/dts/edtlib.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -768,13 +768,22 @@ def _init_binding(self):
768768
on_bus = self.on_bus
769769

770770
for compat in self.compats:
771+
# When matching, respect the order of the 'compatible' entries,
772+
# and for each one first try to match against an explicitly
773+
# specified bus (if any) and then against any bus. This is so
774+
# that matching against bindings which do not specify a bus
775+
# works the same way in Zephyr as it does elsewhere.
771776
if (compat, on_bus) in self.edt._compat2binding:
772-
# Binding found
773777
binding = self.edt._compat2binding[compat, on_bus]
774-
self.binding_path = binding.path
775-
self.matching_compat = compat
776-
self._binding = binding
777-
return
778+
elif (compat, None) in self.edt._compat2binding:
779+
binding = self.edt._compat2binding[compat, None]
780+
else:
781+
continue
782+
783+
self.binding_path = binding.path
784+
self.matching_compat = compat
785+
self._binding = binding
786+
return
778787
else:
779788
# No 'compatible' property. See if the parent binding has
780789
# a compatible. This can come from one or more levels of
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
description: Device on any bus
4+
5+
compatible: "on-any-bus"

scripts/dts/test.dts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,19 +332,25 @@
332332
// they appear on different buses
333333
foo-bus {
334334
compatible = "foo-bus";
335-
node {
336-
compatible = "on-bus";
335+
node1 {
336+
compatible = "on-bus", "on-any-bus";
337337
nested {
338338
compatible = "on-bus";
339339
};
340340
};
341+
node2 {
342+
compatible = "on-any-bus", "on-bus";
343+
};
341344
};
342345
bar-bus {
343346
compatible = "bar-bus";
344347
node {
345348
compatible = "on-bus";
346349
};
347350
};
351+
no-bus-node {
352+
compatible = "on-any-bus";
353+
};
348354
};
349355

350356
//

scripts/dts/testedtlib.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,23 +124,37 @@ def test_bus():
124124
assert edt.get_node("/buses/foo-bus").on_bus is None
125125
assert edt.get_node("/buses/foo-bus").bus_node is None
126126

127-
# foo-bus/node is not a bus node...
128-
assert edt.get_node("/buses/foo-bus/node").bus is None
127+
# foo-bus/node1 is not a bus node...
128+
assert edt.get_node("/buses/foo-bus/node1").bus is None
129129
# ...but is on a bus
130-
assert edt.get_node("/buses/foo-bus/node").on_bus == "foo"
131-
assert edt.get_node("/buses/foo-bus/node").bus_node.path == \
130+
assert edt.get_node("/buses/foo-bus/node1").on_bus == "foo"
131+
assert edt.get_node("/buses/foo-bus/node1").bus_node.path == \
132132
"/buses/foo-bus"
133133

134+
# foo-bus/node2 is not a bus node...
135+
assert edt.get_node("/buses/foo-bus/node2").bus is None
136+
# ...but is on a bus
137+
assert edt.get_node("/buses/foo-bus/node2").on_bus == "foo"
138+
139+
# no-bus-node is not a bus node...
140+
assert edt.get_node("/buses/no-bus-node").bus is None
141+
# ... and is not on a bus
142+
assert edt.get_node("/buses/no-bus-node").on_bus is None
143+
134144
# Same compatible string, but different bindings from being on different
135145
# buses
136-
assert str(edt.get_node("/buses/foo-bus/node").binding_path) == \
146+
assert str(edt.get_node("/buses/foo-bus/node1").binding_path) == \
137147
hpath("test-bindings/device-on-foo-bus.yaml")
148+
assert str(edt.get_node("/buses/foo-bus/node2").binding_path) == \
149+
hpath("test-bindings/device-on-any-bus.yaml")
138150
assert str(edt.get_node("/buses/bar-bus/node").binding_path) == \
139151
hpath("test-bindings/device-on-bar-bus.yaml")
152+
assert str(edt.get_node("/buses/no-bus-node").binding_path) == \
153+
hpath("test-bindings/device-on-any-bus.yaml")
140154

141155
# foo-bus/node/nested also appears on the foo-bus bus
142-
assert edt.get_node("/buses/foo-bus/node/nested").on_bus == "foo"
143-
assert str(edt.get_node("/buses/foo-bus/node/nested").binding_path) == \
156+
assert edt.get_node("/buses/foo-bus/node1/nested").on_bus == "foo"
157+
assert str(edt.get_node("/buses/foo-bus/node1/nested").binding_path) == \
144158
hpath("test-bindings/device-on-foo-bus.yaml")
145159

146160
def test_child_binding():

0 commit comments

Comments
 (0)