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>
The DTS language permits zeroing out phandles in a phandle array to
say "there's nothing at this index", and dtlib manages that correctly,
but edtlib and gen_defines.py aren't equipped to do so.
Fix this by allowing None elements in the lists of ControllerAndData
values returned by edtlib for such properties.
Handle that in gen_defines.py by setting the generated
DT_N_<node>_P_<prop>_IDX_<i>_EXISTS macro to 0 in such cases.
The DT_N_<node>_P_<prop>_LEN macro still accounts for the entire
length of the phandle-array; it's just that some indexes may be
missing data.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
These are likely enough defined by mistake to emit a warning for.
Adjust tests to match, tweaking the test_warnings() setup: now that
we've got several test cases, it's a bit cleaner not to have to
copy/paste the ('edtlib', WARNING, ...) part of every expected log
record tuple.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
The edtlib strategy for emitting warnings is to print directly to
standard error. This in turn requires hacks to drop stored references
to stderr in various _warn_file attributes so the EDT objects can be
pickled.
In general, I think it's not really appropriate for library modules
like edtlib to be printing to stderr directly. The user should be able
to configure logging for general utility data munging modules like
this as they please, and not just deciding what file to print to.
Move this around so the standard logging module is used instead. We
can preserve backwards compatibility in gen_defines by customizing the
'edtlib' logging module behavior so it prints the exact same thing it
always has.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Add enum_tokenizable and enum_upper_tokenizable to PropertySpec. These
allow a PropertySpec to declare that it both has an enumeration of
values and all of them are strings which are "tokenizable". Don't
bother extending Property with these; the user can access the
information through Property.spec now, so the extra delegation is
unnecessary.
See the docstrings for details on what "tokenizable" means. The basic
idea is that we should be able to use the DT binding's enum values as
C 'enum' enumerators in a "reasonable way".
Add val_as_token to Property. This produces a canonical token for the
property value.
Add tests for this feature in particular and property enumerations in
general.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
In the 'normal' case of a property whose definition is taken from a
binding YAML file, a fair number (three at present) of the attributes
available on Property objects are directly taken from the
corresponding PropertySpec object.
Refactor the internals of how a Property gets initialized so that it
has a direct reference to its PropertySpec, and make those attributes
properties which just delegate to the PropertySpec (which in turn just
delegate to the binding). Additionally, expose the PropertySpec
directly.
This will make it easier to extend the Property class with additional
attributes that normally come from the PropertySpec without having to
touch all the locations where Property.__init__ is called.
In the case of the 'default' properties, we handle this by dummying
out some PropertySpec objects. These dummy PropertySpecs in turn
require a dummy Binding.
This change has the advantage that it improves the degree to which
these defaults are checked, e.g. it makes sure that 'status' is one of
the permitted values.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Fixes: #29758
Commit 7165b77a81 ("scripts: edtlib:
refactor for first class bindings") introduced a Binding class.
Its child_binding instance attribute has a compatible which can be
None. Adjust this behavior so the child Binding object has the same
compatible as the parent binding which ultimately has a compatible.
Without this, sanitycheck's expr_parser is doing some matching on
compatibles in child nodes that is producing unexpected results.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This is a convenience function for creating a bunch of Binding objects
from files in a directory.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Add the ability to mark a property as 'deprecated' to get a warning that
it will be removed in the future.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
_prop_val comment referred to one of the arguments called "optional"
however the code has changed to call that argument "required" now. Fix
up the comment block to use the correct argument name and semantics of
that argument.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
Add two new types: Binding and PropertySpec.
- Binding is a first-class abstraction for a devicetree binding
file as defined by a YAML file in the Zephyr syntax.
- PropertySpec is a helper type which represents a property
definition within a Binding.
Make the Binding constructor a new entry point to the library. This
enables users to deal with bindings as standalone entities, apart from
how they characterize a particular devicetree.
Rework the EDT and Node internals that deal with bindings as dict
values to use the Binding type instead. To make this less ambiguous,
use the variable name 'raw' when we're dealing with a binding as it's
parsed from YAML, and 'binding' when we're dealing with a Python
Binding object.
This commit drops support for the following legacy bindings keys
- '#cells': use '*-cells' instead (e.g. 'gpio-cells', 'pwm-cells')
- "child-bus: foo" and "child: bus: foo": use "bus:" instead
- "parent-bus" and "parent: bus: ": use "on-bus:" instead
Officially, legacy bindings have been gone since
6bf761fc0a ("dts: Remove support for deprecated DTS binding
syntax"), so this is vestigial code, and I couldn't find any in-tree
users.
It also drops the convention in this file that ""-strings are
preferred.
I honestly don't understand why this was ever enforced; the file
itself admits single quotes are common in Python and we use them
elsewhere in Zephyr's Python code.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
The legacy macros were first deprecated in Zephyr v2.3. Now that
Zephyr v2.4 has been released, that makes two releases where these
macros have been deprecated, so it's OK to remove them.
This leaves support for legacy binding syntax in place. Removing that
is left to future work.
We need to update various pieces of documentation related to flash
partitions that never got updated when the new API was introduced.
Consolidate this information in the flash_map.h API reference page,
since that's really where users will run into it. This also gives us
the opportunity to improve this documentation.
Adjust a couple of kconfigfunctions.py and sanitycheck bits to use
non-legacy edtlib APIs.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Each controller node in a phandle-array may set the number of cells in
a specifier as any nonnegative integer. Currently, we don't allow
this in edtlib in the case where there are multiple controllers in a
phandle-array property all of which have 0 cells in the relevant
specifier, which is not correct. Fix this, add a regression test, and
improve the error message while we are here.
Fixes: #28709
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Add a lookup table for finding a node by its dependency ordinal.
Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Make the scc_order method a property instead. This is in keeping with
the "General biased advice" at the top of file.
The actual order is therefore lazily initialized in this commit and
the order is not computed by the time __init__() returns. The next
commit will invoke scc_order by the time the constructor returns.
This is preparation work for adding a lookup table from dependency
ordinals to nodes. The combination of these two changes will make
intializing that lookup table a bit easier.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Use the pytest test framework in the dtlib.py and edtlib.py test
suites (testdtlib.py and testedtlib.py respectively).
The goal here is not to change what is being tested. The existing test
suite is excellent and very thorough.
However, it is made up of executable scripts where all of the tests
are run using a hand-rolled framework in a single function per file.
This is a bit all-or-nothing and prevents various nice features
available in the de-facto standard pytest test framework from being
used.
In particular, pytest can:
- drop into a debugger (pdb) when there is a problem
- accept a pattern which specifies a subset of tests to run
- print very detailed error messages about the actual and expected
results in various traceback formats from brief to very verbose
- gather coverage data for the python scripts being tested (via plugin)
- run tests in parallel (via plugin)
- It's easy in pytest to run tests with temporary directories
using the tmp_path and other fixtures. This us avoid
temporarily dirtying the working tree as is done now.
Moving to pytest lets us leverage all of these things without any loss
in ease of use (in fact, some things are nicer in pytest):
- Any function that starts with "test_" is automatically picked up and
run. No need for rolling up lists of functions into a test suite.
- Tests are written using ordinary Python 'assert'
statements.
- Pytest magic unpacks the AST of failed asserts to print details on
what went wrong in really nice ways. For example, it will show you
exactly what parts of two strings that are expected to be equal
differ.
For the most part, this is a pretty mechanical conversion:
- extract helpers and test cases into separate functions
- insert temporary paths and adjust tests accordingly to not match
file names exactly
- use 'assert CONDITION' instead of 'if not CONDITION: fail()'
There are a few cases where making this happen required slightly
larger changes than that, but they are limited.
Move the checks from check_compliance.py to a new GitHub workflow,
removing hacks that are no longer needed.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Clean up of devicetree tooling removed generation of information
present in devicetree in nodes that have no compatible, or for extra
properties not defined by a binding. Discussion proposed that these
properties should be allowed, but only in a defined node /zephyr,user.
For that node infer bindings based on the presence of properties.
Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
We only have one use of _binding_compat and it doesn't need self, so
just fold it into _init_compat2binding.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
We deprecated a number of aspects of the DTS binding syntax in Zephyr
2.1. Remove the support for the deprecated syntax. Remove from docs
about the deprecated syntax as well.
Removed reference in release-notes-2.1.rst to legacy_binding_syntax
since that anchor doesn't exist anymore.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
We have a use case for saving the EDT object to be able to open it up
again later. It would be convenient to be able to do this with the
pickle module from stdlib.
The only thing stopping us from doing that appears to be the open
reference to sys.stderr that's held the edt object even after
EDT.__init__ exits. However, there doesn't seem to be a need to keep
holding on to this object, and in fact it would be a little bit nicer
to drop the reference in case something else (even in the same Python
process that created it originally) wants the EDT object around, but
might want the warn file closed if its refcount zeroes out.
Just drop the reference at the end of __init__ and make EDT._warn()
throw an exception if it's attempted to be used after the constructor
exits.
Make pickle-ability an API guarantee so we can treat any regressions
as bugs going forward.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
I can't see a good reason to be doing this in the Node class's
unit_addr accessor. Move it up to the edtlib initialization so it only
happens once.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Some updates to the reference page for the "core" APIs, and associated
follow-ups in the guides:
- centralize documentation of chosen zephyr nodes in a non-legacy
file, provide a reference to them from the intro page in the guide
- review doxygen docstrings and correct errors for generic APIs
- add introductory text to each section in the API reference
- add missing hardware-specific pages
Documentation for layers built on top of these is mostly left to future
commits, but I do have a smattering of fixes in the guides that I
noticed while I was doing this.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
If we have a fixed-partition on a flash device that is for example on
a spi controller we will not get a binding match currently. This is
because we expect a match between both the compatible and the fact that
fixed-partition node is a decendant of the spi bus.
To address this we treat fixed-partitions as if they are on no bus.
This has the effect of causing a binding match as well as ensuring that
when we process the fixed-partition node we will do anything special to
it because of the bus it happens to be under (for example SPI CS_GPIO
processing).
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
Setup node.compats right after we create the Node. This allows access
to the compats information in _bus_node.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
These look up tables generalize the compat2enabled map in a way we
will need to make the API more flexible in Zephyr.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
Let's get the actual node status, instead of relying on enabled.
Leave enabled in place for gen_legacy_defines.py's sake.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
If a devicetree node doesn't have a matching binding we will at least
populate a common standard set of properties for that node. The list of
standard properties is:
compatible
status
reg
reg-names
label
interrupt
interrupts-extended
interrupt-names
interrupt-controller
This allows us to handle cases like memory nodes that don't have any
compatible property, we can still generate the reg values.
We limit this to known properties as for any other property we can not
fully determine the property type without a binding and thus we can't
ensure the generation for that property is correct or may not change.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
It's a common operation to want to find a node based on its label. Add
a lookup table to make this easier.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
If the #address-cells property for a register is 0 than we set the addr
value of the reg to None. Similar, if #size-cells is 0 than we set the
size value to None for the reg.
Fixup kconfigfunctions.py to handle reg.size and reg.addr being None.
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
This returns the entire logical {name: Node} dictionary which is
currently being accessed element by element via chosen_node(name).
It will be used in a new gen_defines.py for moving the handling of
chosen nodes into C from Python.
Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
spi_dev_cs_gpio() takes a Node and returns the chip select GPIO for it.
Having that information available directly from Node is neater, so turn
it into a Node.spi_cs_gpio property instead.
That gets rid of the only public global function in edtlib, which might
make the API design clearer too.
Tested with the sensortile_box board, which uses SPI chip select.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
It's better to allow per-instance EDT configuration than to set a global
variable on the edtlib module. Enable/disable the warning for reg/unit
address mismatches via a flag to EDT.__init__(), instead of via a global
variable. That makes it consistent too.
Another option would be to pass the 'dtc' flags to EDT.__init__(), but
it makes the interface a bit ugly. Maybe if it needs to emulate lots of
other flags later.
Clarify that edtlib itself isn't meant to have any state in the comment
at the top of the module.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Single-bus warning in python parsing of device tree is suppressed if
this is also suppresed in the device tree compiler.
Signed-off-by: Andrei Gansari <andrei.gansari@nxp.com>
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>
Show how the element size was calculated in the error message when a
'reg', 'ranges', or 'interrupts' property has the wrong size. This
should help with debugging. Also mention that #*-cells properties come
from the parent node, which can be subtle.
Came up in https://github.com/zephyrproject-rtos/zephyr/issues/21607
(though it seems the comment disappeared).
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Add binding support for a 'path' property type, for properties that are
assigned node paths. Usually, paths are assigned with path references
like 'foo = &label' (common in /chosen), but plain strings are accepted
as well as long as they're valid paths.
The 'path' type is mostly for completeness at this point, but might be
useful for https://github.com/zephyrproject-rtos/zephyr/issues/21623.
The support is there already in dtlib.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
For the following devicetree, view 'nested' as being on the bus.
Previously, only 'node' was considered to be on the bus.
some-bus {
compatible = "foo,bus-controller";
node {
nested {
compatible = "foo,device-on-bus";
};
};
};
In practice, this means that a 'bus:' key in the binding for
'foo,bus-controller' will now get matched up to an 'on-bus:' key in the
binding for 'foo,device-on-bus'.
Change the meaning of Node.bus and add two new attributes Node.on_bus
and Node.bus_node, with these meanings:
Node.bus:
The bus type (as a string) if the node is a bus controller, and
None otherwise
Node.on_bus:
The bus type (as a string) if the node appears on a bus, and None
otherwise. The bus type is determined from the closest parent
that's a bus controller.
Node.bus_node:
The node for the bus controller if the node appears on a bus, and
None otherwise
It's a bit redundant to have both Node.bus_node and Node.on_bus, since
Node.on_bus is the same as Node.bus_node.bus, but Node.on_bus is pretty
handy to save some None checks.
Also update gen_defines.py to use Node.on_bus and Node.bus_node instead
of Node.parent wherever the code deals with buses.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
I keep mixing these up, so that's probably a sign that the names are
bad. The root of the problem is that "parent-bus" can be read as both
"this is the parent bus" and as "the parent bus is this".
Use 'bus:' for the bus "provider" and 'on-bus:' for nodes on the bus
instead, which is less confusing.
Support the old keys for backwards compatibility, along with a
deprecation warning.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Most bindings look something like this:
title: Foo
description: This binding provides a base representation of Foo
That kind of description doesn't add any useful information, as it's
just the title along with some copy-pasted text. I'm not sure what "base
representation" was supposed to mean originally either.
Many bindings also put something that's closer to a description in the
title, because it's not clear what's expected or how the title is used.
In reality, the title isn't used anywhere. 'description:' on the other
hand shows up as a comment in the generated header.
Deprecate 'title:' and generate a long informative warning if it shows
up in a binding.
Next commits will clean up the 'description:' strings (bringing them
closer to 'title:' in most cases) and remove 'title:' from all bindings.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
A property may be optional with a default in a base yaml, then
overridden to be required in a subordinate file. Don't prevent this
by complaining about having a default on a required property.
Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
Erroring out for 'status = "ok"' broke backwards compatibility for a
downstream project. Accept it instead.
Maybe the error could be selectively re-enabled later.
The rest of the code only checks for 'status = "disabled"' (like the old
scripts), so no other updates are needed.
(It's a bit weird that we duplicate the property check in base.yaml.
Thinking of including base.yaml implicitly. Could clean things up then.)
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>