Commit Graph

69 Commits

Author SHA1 Message Date
Kumar Gala
e75ac55d23 edtlib: handle include in child-binding
Support the ability for there to be an include in a child-binding
section.

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2020-04-15 08:27:42 -05:00
Kumar Gala
8af311ab3b edtlib: allow register addr / size to be None
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>
2020-03-24 10:11:20 -05:00
Martí Bolívar
0de9a08e94 scripts: dts: edtlib: add EDT.chosen_nodes property
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>
2020-03-24 10:11:20 -05:00
Martí Bolívar
7846fd103d edtlib: add 'labels' attribute to Node class
This corresponds to the attribute by the same name in dtlib.Node.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2020-03-11 07:59:38 -06:00
Ulf Magnusson
8cacb9fd8c dts: edtlib: Turn global spi_dev_cs_gpio() into Node.spi_cs_gpio
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>
2020-03-11 07:59:38 -06:00
Ulf Magnusson
35166c45d9 dts: edtlib/gen_defines: Fix API design re. dtc flags
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>
2020-03-11 07:59:38 -06:00
Andrei Gansari
e87fec1554 scripts: simple-bus warning suppression
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>
2020-02-05 13:04:44 -06:00
Ulf Magnusson
a758af4988 dts: edtlib: Add an EDT.dts_source attribute that holds the source code
EDT.dts_source is the source code of the loaded .dts file, after merging
nodes.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2020-01-30 04:27:39 -06:00
Ulf Magnusson
88db84b89b 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>
2020-01-29 09:46:38 -06:00
Ulf Magnusson
57b2d2749c dts: edtlib: Improve error for wrong reg/ranges/interrupts size
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>
2020-01-13 13:49:33 +01:00
Ulf Magnusson
23a5b4963b dts: edtlib: Add 'type: path' for path references
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>
2020-01-08 08:02:00 -06:00
Ulf Magnusson
5e55eda30e scripts: edtlib: Support nested nodes on buses
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>
2019-12-19 11:02:28 +01:00
Ulf Magnusson
379145ffce scripts: edtlib: Rename 'child-bus:'/'parent-bus:' to 'bus:'/'on-bus:'
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>
2019-12-19 11:02:28 +01:00
Ulf Magnusson
36b7ca44b8 scripts: edtlib.py: Deprecate 'title:'
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>
2019-12-18 11:52:45 +01:00
Peter Bigot
bed6eb9ed9 dts: edtlib: remove diagnostic on required with default
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>
2019-12-12 07:55:34 -06:00
Ulf Magnusson
fc5cd772da scripts: dts: Accept 'status = "ok"'
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>
2019-12-09 12:49:32 -05:00
Martí Bolívar
59e2f230e0 scripts: dts: improve error message on compatible type error
Print the offending value and its type.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
2019-11-13 15:07:29 -06:00
Ulf Magnusson
d55ed93636 scripts: edtlib: Move imports after overview comment
Might make the comment easier to spot.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-11-12 17:57:50 -06:00
Ulf Magnusson
72158858ac scripts: dtlib/edtlib: Make output consistent on Python 3.5-
Python 3.5 and earlier do not preserve dictionary insertion order when
iterating over dictionaries, and do not give the same order between
runs. This broke the dtlib and edtlib test suites and made the output
jump around randomly between runs. It also made device INST_<n> numbers
non-deterministic, which broke some code on Python 3.5 (though
hardcoding device instance numbers in the code might be a bit shaky).

Fix it by using collections.OrderedDict instead of plain dict wherever
order matters. This makes the output identical on all supported Python
versions. It also allows testdtlib.py and testedtlib.py to run in CI,
which uses Python 3.5.

Fixes: #20571

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-11-12 17:57:50 -06:00
Ulf Magnusson
0e23994d23 scripts: edtlib: Avoid modifying the global yaml.(C)Loader
edtlib is a library, and modifying yaml.(C)Loader directly interferes
with any binding loading in edtlib clients. To avoid that, add a custom
loader for bindings.

Internally, PyYAML does this, which is why defining a separate class
works:

    @classmethod
    def add_constructor(cls, tag, constructor):
        if not 'yaml_constructors' in cls.__dict__:
            cls.yaml_constructors = cls.yaml_constructors.copy()
        cls.yaml_constructors[tag] = constructor

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-11-12 17:57:50 -06:00
Ulf Magnusson
2e1d2889e2 dts: edtlib: Turn edt.required_by()/depends_on() into Node attributes
Turns

    edt.required_by(node)
    edt.depends_on(node)

into

    node.required_by
    node.depends_on

which might be a bit more readable.

One drawback is that @property hides that there's some slight overhead
in accessing them, but I suspect it won't be meaningful. Caching could
be added if it ever turns out to be.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-11-06 17:33:59 -08:00
Ulf Magnusson
eef8d19a27 dts: edtlib: Add simple generic support for pinctrl-<index> properties
(pinctrl-<index> is documented in
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt in
Linux.)

Add a new Node.pin_states property, derived from any pinctrl-<index>
properties on the node. Node.pin_states holds a list of PinState
objects, where each PinState represents a single pinctrl-<index>
property.

For example, Node.pin_states will have two elements for the 'device'
node below:

	device {
		pinctrl-0 = <&state_0>;
		pinctrl-1 = <&state_1 &state_2>;
		pinctrl-names = "default", "sleep";
	};
	pincontroller {
		state_0: state_0 {
			...
		};
		state_1: state_1 {
			...
		};
		state_2: state_2 {
			...
		};
	};

Each PinState holds the list of configurations nodes in
PinState.conf_nodes. For the node above, node.pin_states[1].conf_nodes
will contain the pincontroller/state_1 and pincontroller/state_2 nodes,
for example.

The new functionality isn't used by gen_defines.py yet, so this change
is a no-op in itself, except it adds some error checking for
pinctrl-<index> properties.

If needed, support for #pinctrl-cells and 'pinmux' (not the same thing
as the 'pinmux' properties in Zephyr I think) could be added separately
later. Not sure what belongs in edtlib.py there yet.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-11-06 21:39:13 +01:00
Peter A. Bigot
ea956f4ac3 scripts: dts: add dependency information to edtlib
Device tree nodes have a dependency on their parents, as well as other
nodes.  To ensure driver instances are initialized in the proper we
need to identify these dependencies and construct a total order on
nodes that ensures no node is initialized before something it depends
on.

Add a Graph class that calculates a partial order on nodes, taking
into account the potential for cycles in the dependency graph.

When generating devicetree value headers calculate the dependency
graph and document the order and dependencies in the derived files.
In the future these dependencies may be expressed in binding data.

Signed-off-by: Peter A. Bigot <pab@pabigot.com>
2019-11-05 17:03:23 +01:00
Ulf Magnusson
f3f88a8e58 scripts: dts: Format multi-line comments nicely
Multi-line comments were stuck as-is between /* and */ in the generated
header, which looks ugly and confusing e.g. for multi-line
binding/property descriptions.

Use this format for multi-line comments in the header instead:

    /*
     * First line
     * Second line
     *
     * Line after blank line
     */

Also clean up the output a bit by turning some things that were separate
comments into a single multi-line comment. Add some air and reduce line
lengths too.

Before:

    /*  Generated by gen_defines.py  */
    /*  DTS input file: hifive1.dts.pre.tmp  */
    /*  Directories with bindings: $ZEPHYR_BASE/dts/bindings  */

    /*  Devicetree node: /cpus/cpu@0/interrupt-controller  */
    /*  Binding (compatible = riscv,cpu-intc): $ZEPHYR_BASE/... */
    /*  Binding description: This binding describes the RISC-V ...

    Some extra lines
    for testing  */
    #define DT_INST_0_RISCV_CPU_INTC                    1

After:

    /*
     * Generated by gen_defines.py
     *
     * DTS input file:
     *   hifive1.dts.pre.tmp
     *
     * Directories with bindings:
     *   $ZEPHYR_BASE/dts/bindings
     */

    /*
     * Devicetree node:
     *   /cpus/cpu@0/interrupt-controller
     *
     * Binding (compatible = riscv,cpu-intc):
     *   $ZEPHYR_BASE/dts/bindings/interrupt-controller/...
     *
     * Description:
     *   This binding describes the RISC-V CPU Interrupt Controller
     *
     *   Some extra lines
     *   for testing
     */
    #define DT_INST_0_RISCV_CPU_INTC                    1

Also tweak Node.description and Property.description in edtlib to be
strip()ed instead of rstrip()ed. There's probably no reason to
preserving leading whitespace in them either.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-10-30 08:15:31 +01:00
Ulf Magnusson
b92ceb78dd scripts: edtlib/extract_dts_includes.py: Speed up 2x+ with yaml.CLoader
Use the LibYAML-based yaml.CLoader if available instead of yaml.Loader,
which is written in Python and slow. See
https://pyyaml.org/wiki/PyYAMLDocumentation.

This speeds up gen_defines.py from 0.2s to 0.07s on my system, for
-DBOARD=hifive1. It should also make scripts/kconfig/kconfig.py faster,
because it indirectly uses edtlib via
scripts/kconfig/kconfigfunctions.py.

yaml.CLoader seems to be available out of the box when installing with
pip on Ubuntu at least.

Helps with https://github.com/zephyrproject-rtos/zephyr/issues/20104.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-10-30 07:52:27 +01:00
Ulf Magnusson
e311380584 scripts: edtlib: Forbid multiple bindings with the same compatible
Previously, if two bindings had the same 'compatible:'/'parent-bus:'
values, the binding that happened to be loaded last would get used.

Turn it into an error instead. This avoids tricking people into thinking
that bindings get loaded in a defined order.

Maybe overriding bindings could be allowed later, if we need it.

Fixes: #19536

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-10-15 10:34:44 +02:00
Ulf Magnusson
72bfa83670 scripts: edtlib: Turn Node.description into a @property
Simplifies the code a bit.

Looks like the description wasn't rstrip()ed when it came from a
'child-binding:' either. This also indirectly fixes that.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-10-15 10:34:44 +02:00
Ulf Magnusson
0c4f4a91b0 scripts: edtlib: Fix broken 'required: true' check for booleans
Node._prop_val() returned too early for non-existent booleans, letting
missing 'required: true' booleans slip through without an error.

Fix it by rearranging the code to always do the 'required' check before
returning.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-10-03 16:29:11 -07:00
Ulf Magnusson
bc22b3a020 scripts: testedtlib.py: Simplify warning test a tiny bit
verify_eq() can be used instead of verify_streq(), since
warnings.getvalue() already returns a string.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-10-03 05:57:26 -07:00
Ulf Magnusson
7c26c17be6 scripts: edtlib: Add easy redirection of warnings
Add a 'warn_file' parameter to EDT.__init__() that gives a 'file' object
to write warnings to. Use it to capture and verify warnings generated
for deprecated features in testedtlib.py. This indirectly gets rid of
possibly broken-looking output when running it.

Because any function that writes warnings now needs to use EDT._warn()
(as self._warn()), some functions were moved into the EDT class.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-10-02 11:49:58 -07:00
Ulf Magnusson
567c348167 scripts: dts: Generalize '#cells' to allow multiple sources
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>
2019-10-02 11:49:58 -07:00
Ulf Magnusson
b97ed9e4b4 scripts: dts: Generalize handling of phandle-array types
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>
2019-09-26 15:30:23 -07:00
Ulf Magnusson
6b8750490d scripts: edtlib: Rename Interrupt/GPIO/etc. 'specifier' field to 'data'
'Specifier' is devicetree specalese for data associated with interrupts,
GPIOs, etc., e.g. <1 2> and <3 4> in

    pwms = <&ctrl-1 1 2 &ctrl-2 3 4>;

It's probably unnecessarily confusing to call it that. Call it 'data'
instead, which is a bit more straightforward.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-26 05:23:28 -07:00
Ulf Magnusson
73ac1466fb scripts: edtlib: Call nodes "nodes" instead of "devices"
edtlib.Device is just a devicetree node augmented with binding
information and some interpretation of properties. Rename it to
edtlib.Node to make that clearer. That also avoids calling things like
flash partition nodes "devices", which is a bit confusing.

I called it edtlib.Device instead of edtlib.Node originally to avoid
confusion with dtlib.Node, but in retrospect it probably makes it more
confusing on the whole. Something like edtlib.ENode might work too, but
it's probably overkill. Clients of edtlib.py only interact with
edtlib.Node, so the only potential for confusion is within edtlib.py
itself, and it doesn't get too bad there either.

Piggyback some documentation nits, and consistently write it
"devicetree" instead of "device tree", to match the spec.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-26 05:23:28 -07:00
Ulf Magnusson
4c6ea2d160 scripts: edtlib: Skip fully loading bindings in more cases
As a slightly hairy but important optimization inherited from the old
scripts, the binding loading code only looks at binding files whose raw
text contains one of the compatible strings from the devicetree. For
such files, a second pass parses the file as YAML and tries to extract a
compatible string, and skips the file if it fails (e.g. due to spurious
text matches in 'include'd binding fragments).

Until now, the binding would always get fully loaded (have 'include'd
files merged in, checks run, etc.) if the second pass managed to extract
a compatible.

Do slightly better by only fully loading the binding if the extracted
compatible from the second pass appears in the devicetree. This gets rid
of unnecessary binding loading in rare cases.

Discovered by test-bindings/deprecated.yaml getting loaded even when
everything that referenced it in test.dts was commented out, because it
happened to mention 'child-binding' in a comment.

Also add a check for YAML errors in the second pass, to be slightly more
robust. Print a warning if a file that isn't valid YAML is found.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-22 09:17:53 -05:00
Ulf Magnusson
110526ec0e scripts: edtlib: Add a Device.children attribute with child Devices
API oversight. This was meant to be there all along together with
Device.parent, for navigating the devicetree, but since a need for it
never came up in gen_defines.py, it got overlooked.

Devices are just devicetree nodes augmented with binding information and
some interpretation of devicetree properties. I wonder if the name
should be changed to something like edtlib.Node to make that clearer.
Calling something like a flash partition a "device" is a bit weird, as
Galak pointed out.

I think I went with Device originally to avoid confusion with
dtlib.Node, but since edtlib users don't directly interact with dtlib,
it might not be that confusing in practice.

Piggyback some documentation clarifications.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-21 09:10:36 -05:00
Ulf Magnusson
0b1ab4ab09 scripts: dts: Replace 'sub-node:' with more general 'child-binding:'
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>
2019-09-19 08:39:22 -05:00
Ulf Magnusson
1ebe945643 scripts: dts: Change 'child/parent: bus: ...' to 'child/parent-bus:'
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>
2019-09-17 14:37:43 -05:00
Ulf Magnusson
2845d8f404 scripts: edtlib: Make order irrelevant when including multiple files
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>
2019-09-11 07:50:30 -05:00
Ulf Magnusson
b918e25921 dts: scripts: Require properties to be declared in bindings
Except for a few special properties like 'interrupts' and '#size-cells',
require all devicetree properties on nodes with bindings to be declared
in the binding.

This will help catch misspellings, and makes refactoring and cleanups
safer.

Suggested by Peter A. Bigot.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-10 07:42:02 -05:00
Ulf Magnusson
ff1f75293e dts: edtlib: Support giving missing properties a default value
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>
2019-09-09 08:47:49 -05:00
Ulf Magnusson
a0fceff1a2 scripts: dts: Simplify and improve 'compatible' matching
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>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
cff38cf0ef scripts: edtlib: Fix bad block indentation
Reported by pylint.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
8f22529e74 scripts: edtlib: Make _binding_include() global to fix pylint warning
Doesn't use 'self'. Fixes this pylint warning:

    scripts/dts/edtlib.py:272:4: R0201: Method could be a function
    (no-self-use)

Fixing pylint warnings for a CI check.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
8d317bc665 scripts: edtlib: Add backwards compatibility for 'category:'
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>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
d834b69bd9 scripts: dts: Improve syntax and code for including binding files
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>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
fcd665a26c dts: bindings: Have 'required: true/false' instead of 'category: ...'
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>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
14138c3b9b dts: edtlib: Improve how we get the compatible string from bindings
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>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
1480ad9ce7 dts: edtlib: Sanity-check the final merged binding only
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>
2019-09-07 10:25:02 -05:00
Ulf Magnusson
378254ad13 dts: edtlib: Sanity-check 'ranges' assignment syntax
Require either type TYPE_EMPTY ('ranges;') or TYPE_NUMS
('ranges = < 1 2 ... >;').

Putting the check in _check_dt() means it will run for all nodes,
including nodes without bindings, which is handy.

The _split() function already gives a decent error message if 'ranges'
has unexpected length, so skip checking the length.

Signed-off-by: Ulf Magnusson <Ulf.Magnusson@nordicsemi.no>
2019-09-07 10:25:02 -05:00