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>
The child_binding object should default to having a path and
compatible that matches the parent's. Mark it as xfail because the
compatible part is failing.
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>
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>
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>
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>
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>
Implement a nice generalization suggested by Bobby Noelte.
Instead of having a generic #cells key in bindings, have source-specific
*-cells keys. Some examples:
interrupt-cells:
- irq
- priority
- flags
gpio-cells:
- pin
- flags
pwm-cells:
- channel
- period
This makes bindings a bit easier to read, and allows a node to be a
controller for many different 'phandle-array' properties.
The prefix before *-cells is derived from the property name, meaning
there's no fixed set of *-cells keys. This is possible because of the
earlier 'phandle-array' generalization.
The older #cells key is supported for backwards compatibility, but
generates a deprecation warning.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Generating generic information for 'type: phandle-array' properties in
edtlib was difficult due to defining phandle-array as just a list of
phandles and numbers. To make sense of a phandle-array property like
'pwms', you have to know that #pwm-cells is expected to appear on
each referenced controller, and that the binding for the controller has
a #cells.
Because of this, handling of various 'type: phandle-array' properties
was previously hardcoded in edtlib and exposed through properties like
Node.pwms, instead of through the generic Node.props (though with a lot
of shared code).
In practice, it turns out that all 'type: phandle-array' properties in
Zephyr work exactly the same way: They all have names that end in -s,
the 's' is removed to derive the name of related properties, and they
all look up #cells in the binding for the controller, which gives names
to the data values.
Strengthen the definition of 'type: phandle-array' to mean a property
that works exactly like the existing phandle-array properties (which
also means requiring that the name ends in -s). This removes a ton of
hardcoding from edtlib and allows new 'type: phandle-array' properties
to be added without making any code changes.
If we ever need a property type that's a list of phandles and numbers
but that doesn't follow this scheme, then we could add a separate type
for it. We should check if the standard scheme is fine first though.
The only property type for which no information is generated is now
'compound'.
There's some inconsistency in how we generate identifiers for clocks
compared to other 'type: phandle-array' properties, so keep
special-casing them for now in gen_defines.py (see the comment in
write_clocks()).
This change also enabled a bunch of other simplifications, like reusing
the ControllerAndData class for interrupts.
Piggyback generalization of *-map properties so that they work for any
phandle-array properties. It's now possible to have things like
'io-channel-map', if you need to.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Deprecate 'sub-node:' and add a more general 'child-binding:' mechanism
to bindings. Keep supporting 'sub-node:', but print a deprecation
warning when it's used.
Like 'sub-node:', 'child-binding:' gives a binding to child nodes, but
the binding is required to be a complete binding, and is treated (and
checked) like a normal binding.
'child-binding:' can in turn contain another 'child-binding:', up to any
number of levels. This is automatic from treating it like a normal
binding, and from the code initializing parent Devices before child
Devices.
This lets nodes give bindings to grandchildren.
For example, take this devicetree fragment:
parent {
compatible = "foo";
child-1 {
grandchild-1 {
...
};
grandchild-2 {
...
};
};
child-2 {
grandchild-3 {
...
};
};
};
The binding for 'foo' could provide bindings for grandchild-1/2/3 like
this:
compatible: "foo"
# Binding for children
child-binding:
title: ...
description: ...
...
# Binding for grandchildren
child-binding:
title: ...
description: ...
properties:
...
Due to implementation issues with the old devicetree scripts, only two
levels of 'child-binding:' is supported for now. This limitation will go
away in Zephyr 2.2.
Piggyback shortening 'description:' and 'title:' in some bindings that
provide child bindings. This makes the generated header a bit neater.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Instead of
child:
bus: foo
parent:
bus: bar
, have
child-bus: foo
parent-bus: bar
'bus' is the only key that ever appears under 'child' and 'parent'.
Support the old keys for backwards compatibility, with a deprecation
warning if they're used.
Also add 'child/parent-bus' tests to the edtlib test suite. It was
untested before.
I also considered putting more stuff under 'child' and 'parent', but
there's not much point when there's just a few keys I think. Top-level
stuff is cleaner and easier to read.
I'm planning to add a 'child-binding' key a bit later (like 'sub-node',
but more flexible), and child-* is consistent with that.
Also add an unrelated test-bindings/grandchild-3.yaml that was
accidentally left out earlier.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
When foo.yaml set some property 'required: true' and bar.yaml set the
same property 'required: false', the check for changing
'required: false' to 'required: true' would raise an error for
include: [bar.yaml, foo.yaml]
(with that particular order due to implementation details).
The order files are included in shouldn't matter. To fix it, change the
logic so that 'required' values are ORed together between included files
(so that 'required: true' is always respected), and remove the
'required' true-to-false check when merging included files.
Keep the true-to-false check when merging the (merged) included files
into the main binding (the binding with the 'include:' in it). This
might give a good organization, and the old scripts do it too.
Piggyback two fixes/cleanups:
- 'compatible' should be allowed to appear in included files
- No need to allow an 'inherits' key in _check_binding(), because
it has been removed before then, when merging bindings
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
For missing optional properties, it can be handy to generate a default
value instead of no value, to cut down on #ifdefs.
Allow a default value to be specified in the binding, via a new
'default: <default value>' setting for properties in bindings.
Defaults are supported for both scalar and array types. YAML arrays are
used to specify the value for array types.
'default:' also appears in json-schema, with the same meaning.
Include misc. sanity checks, like the 'default' value matching 'type'.
The documentation changes in binding-template.yaml explain the syntax.
Suggested by Peter A. Bigot in
https://github.com/zephyrproject-rtos/zephyr/issues/17829.
Fixes: #17829
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Instead of
properties:
compatible:
constraint: "foo"
, just have
compatible: "foo"
at the top level of the binding.
For backwards compatibility, the old 'properties: compatible: ...' form
is still accepted for now, and is treated the same as a single-element
'compatible:'.
The old syntax was inspired by dt-schema (though it isn't
dt-schema-compatible), which is in turn a thin wrapper around
json-schema (the idea is to transform .dts files into YAML and then
verify them).
Maybe the idea was to gradually switch the syntax over to dt-schema and
then be able to use unmodified dt-schema bindings, but dt-schema is
really a different kind of tool (a completely standalone linter), and
works very differently from our stuff (see schemas/dt-core.yaml in the
dt-schema repo to get an idea of just how differently).
Better to keep it simple.
This commit also piggybacks some clarifications to the binding template
re. '#cells:'.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Having backwards compatibility for !include and 'constraint:' is silly
without also having backwards compatibility for 'category:', because
that forces a binding change anyway.
Add backwards compatibility for 'category:', and just print a
deprecation warning when it's used.
Also move tests for deprecated features into a dedicated
test-bindings/deprecated.yaml binding, instead of piggybacking on other
tests.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Have
include: foo.dts
include: [foo.dts, bar.dts]
instead of
inherits:
!include foo.dts
inherits:
!include [foo.dts, bar.dts]
This is a nicer and shorter and less cryptic syntax, and will make it
possible to get rid of the custom PyYAML constructor for '!include'
later.
'inherits: !include ...' is still supported for backwards compatibility
for now. Later on, I'm planning to mass-replace it, add a deprecation
warning if it's used, and document 'include:'. Then the '!include'
implementation can be removed a bit later.
'!include' has caused issues in the past (see the comment above the
add_constructor() call), gets iffy with multiple EDT instances, and
makes the code harder to follow.
I'm guessing '!include' might've been intended to be useful outside of
'inherits:' originally, but that's the only place where it's used. It's
undocumented that it's possible to put it elsewhere.
To implement the backwards compatibility, the code just transforms
inherits:
!include foo.dts
into
inherits:
- foo.dts
and treats 'inherits:' similarly to 'include:'. Previously, !include
inserted the contents of the included file instead.
Some more sanity checks for 'include:'/'inherits:' are included as well.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
The 'category: required/optional' setting for properties is just a
yes/no thing. Using a boolean makes it clearer, so have
'required: true/false' instead.
Print a clear error when 'category:' is used:
edtlib.EDTError: please put 'required: true' instead of 'category:
required' in 'properties: foo: ...' in
test-bindings/sub-node-parent.yaml - 'category' has been removed
The old scripts in scripts/dts/ ignore this setting, and only print a
warning if 'category: required' in an inherited binding is changed to
'category: optional'. Remove that code, since the new scripts already
have the same check.
The replacement was done with
git ls-files 'dts/bindings/*.yaml' | xargs sed -i \
-e 's/category:\s*required/required: true/' \
-e 's/category:\s*optional/required: false/'
dts/binding-template.yaml is updated as well.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Use Galak's idea from
https://github.com/zephyrproject-rtos/zephyr/pull/18313 to read the
'properties: compatible: constraint: "foo"' string from bindings in a
more robust way.
First, check if any of the compatible strings are in the file (needed as
an optimization). If any of them are, do a more careful check for the
'properties: compatible: constraint: ...' value matching a compatible,
to filter out false positives from comments and the like.
This commit a no-op in itself besides making things a bit more robust,
but it'll make later work easier (supporting multiple compatibles for a
binding, in a dt-schema-like way).
Co-authored-by: Kumar Gala <kumar.gala@linaro.org>
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Sanity-checking each !included file separately was inherited from the
old scripts. It makes it messy to check that combinations of fields make
sense, e.g. to check 'const:' or 'default:' against 'type:', since those
fields might come from different files (this is handy, since it makes
sense to just add/change a 'const:' value, for example).
Drop the requirement that each !included file is a complete binding in
itself, and treat them as binding fragments instead. Only check the
final merged binding.
This also means that !included files no longer need to have a
'description:' or 'title:' (those have always been unused for !included
files), so remove those, and add comments that explain what the
fragments are for instead. That should demystify bindings a bit.
Also fix the descriptions of i2c.yaml, i2s.yaml, spi.yaml, and
uart.yaml. They're for controllers, not devices. These are copy-paste
error from the corresponding device .yaml files.
Piggyback some indentation consistency nits in binding-template.yaml.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Add two new type-checked property types 'phandles' and 'phandle-array'
to edtlib.
'phandles' is for pure lists of phandles, with no other data, like
foo = < &bar &baz ... >
'phandle-array' is for lists of phandles and (possibly) numbers, like
foo = < &bar 1 2 &baz 3 4 ... >
dt-schema also has the 'phandle-array' type.
Property.val (in edtlib) is set to an array of Device objects for the
'phandles' type.
For the 'phandle-array' type, no Property object is created. This type
is only used for type checking.
Also refactor how types that do not create a Property object
('phandle-array' and 'compound') are handled. Have _prop_val() return
None for them.
The new types are implemented with two new TYPE_PHANDLES and
TYPE_PHANDLES_AND_NUMS types at the dtlib level. There is also a new
Property.to_nodes() functions for fetching the Nodes for an array of
phandles, with type checking.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
The contents of 'sub-node:' was assigned as-is as the binding, bypassing
_check_binding(). This also hid an error in
test-bindings/sub-node-parent.yaml.
Require 'sub-node:' to just have 'properties:' in it, and sanity-check
the properties like for regular bindings.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Add a 'const' property to bindings for any properties that are expected
to have a specifi known value. For example, #address-cells for an I2C
bus should always be '1'. So we can do something like the following in
the I2C bus binding:
"#address-cells":
type: int
category: required
const: 1
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Property type-checking has been pretty rudimentary until now, only
checking things like the length being divisible by 4 for 'type: array',
and strings being null-terminated. In particular, no checking was done
for 'type: uint8-array', letting
jedec-id = < 0xc8 0x28 0x17 >;
slip through when
jedec-id = [ 0xc8 0x28 0x17 ];
was intended.
Fix it by adding a syntax-based type checker:
1. Add Property.type, which gives a high-level type for the property,
derived from the markers added in the previous commit.
This includes types like TYPE_EMPTY ('foo;'),
TYPE_NUM ('foo = < 3 >;'), TYPE_BYTES ('foo = [ 01 02 ];'),
TYPE_STRINGS ('foo = "bar", "baz"'),
TYPE_PHANDLE ('foo = < &bar >;'), and TYPE_COMPOUND (everything not
recognized).
See the Property.type docstring in dtlib for more info.
2. Use the high-level type in
Property.to_num()/to_string()/to_node()/etc. to verify that the
property was assigned in an expected way for the type.
If the assignment looks bad, give a helpful error:
expected property 'nums' on /foo/bar in some.dts to be assigned
with 'nums = < (number) (number) ... >', not 'nums = "oops";'
Some other related changes are included as well:
- There's a new Property.to_bytes() function that works like accessing
Property.bytes, except with an added check for the value being
assigned like 'foo = [ ... ]'.
This function solves problems like the jedec-id one.
- There's a new Property.to_path() function for fetching the
referenced node for assignments like 'foo = &node;', with type
checking. (Strings are accepted too, as long as they give the path
to an existing node.)
This function is used for /chosen and /aliases.
- A new 'type: phandle' type can now be given in bindings, for
properties that are assigned like 'foo = < &node >;'.
- Property.__str__() now displays phandles and path references as they
were written (e.g. '< &foo >' instead of '< 0x1 >', if the
allocated phandle happened to be 1).
- Property.to_num() and Property.to_nums() no longer take a 'length'
parameter, because it makes no sense with the type checking.
- The global dtlib.to_string() and dtlib.to_strings() functions were
removed, because they're not that useful.
- More tests were added, along with misc. minor cleanup in various
places.
- Probably other stuff I forgot.
The more strict type checking in dtlib indirectly makes some parts of
edtlib more strict as well (wherever Property.to_*() is used).
Fixes: #18131
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Add two bindings
test-bindings/multidir.yaml
test-bindings-2/multidir.yaml
and a new test-multidir.dts with two nodes that use them.
Verify that the two bindings were found by checking the
Device.binding_path attribute for the two device nodes.
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
Add a new DTS/binding parser to scripts/dts/ for generating
generated_dts_board.conf and generated_dts_board_unfixed.h.
The old code is kept to generate some deprecated defines, using the
--deprecated-only flag. It will be removed later.
The new parser is implemented in three files in scripts/dts/:
dtlib.py:
A low-level .dts parsing library. This is similar to devicetree.py in
the old code, but is a general robust DTS parser that doesn't rely on
preprocessing.
edtlib.py (e for extended):
A library built on top of dtlib.py that brings together data from DTS
files and bindings and creates Device instances with all the data for
a device.
gen_defines.py:
A script that uses edtlib.py to generate generated_dts_board.conf and
generated_dts_board_unfixed.h. Corresponds to extract_dts_includes.py
and the files in extract/ in the old code.
testdtlib.py:
Test suite for dtlib.py. Can be run directly as a script.
testedtlib.py (uses test.dts and test-bindings/):
Test suite for edtlib.py. Can be run directly as a script.
The test suites will be run automatically in CI.
The new code turns some things that were warnings (or not checked) in
the old code into errors, like missing properties that are specified
with 'category: required' in the binding for the node.
The code includes lots of documentation and tries to give helpful error
messages instead of Python errors.
Co-authored-by: Kumar Gala <kumar.gala@linaro.org>
Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>