python-devicetree
This is part of an ongoing effort to extract the Zephyr Project’s devicetree tools to a standalone location for wider use.
This is version 0.0.2. It is based on the Zephyr tools as of commit f5409dec01.
Quickstart
$ pip3 install devicetree
$ python3
[...]
>>> from devicetree import edtlib, dtlib
Then you should be able to use edtlib and dtlib in the same way Zephyr does with its in-tree versions of these modules.
This is meant as a way to get started. Breaking API changes to make this code easier to use standalone are possible.
dtlib
This is the low-level DTS parser.
A library for extracting information from .dts (devicetree) files. See the documentation for the DT and Node classes for more information.
The top-level entry point of the library is the DT class. DT.__init__() takes a .dts file to parse and a list of directories to search for any /include/d files.
- class devicetree.dtlib.DT(filename: str, include_path: Iterable[str] = (), force: bool = False)
Represents a devicetree parsed from a .dts file (or from many files, if the .dts file /include/s other files). Creating many instances of this class is fine. The library has no global state.
These attributes are available on DT instances:
- root:
A Node instance representing the root (/) node.
- alias2node:
A dictionary that maps maps alias strings (from /aliases) to Node instances
- label2node:
A dictionary that maps each node label (a string) to the Node instance for the node.
- label2prop:
A dictionary that maps each property label (a string) to a Property instance.
- label2prop_offset:
A dictionary that maps each label (a string) within a property value (e.g., ‘x = label_1: < 1 label2: 2 >;’) to a (prop, offset) tuple, where ‘prop’ is a Property instance and ‘offset’ the byte offset (0 for label_1 and 4 for label_2 in the example).
- phandle2node:
A dictionary that maps each phandle (a number) to a Node instance.
- memreserves:
A list of (labels, address, length) tuples for the /memreserve/s in the .dts file, in the same order as they appear in the file.
‘labels’ is a possibly empty set with all labels preceding the memreserve (e.g., ‘label1: label2: /memreserve/ …’). ‘address’ and ‘length’ are numbers.
- filename:
The filename passed to the DT constructor.
- __init__(filename: str, include_path: Iterable[str] = (), force: bool = False)
Parses a DTS file to create a DT instance. Raises OSError if ‘filename’ can’t be opened, and DTError for any parse errors.
- filename:
Path to the .dts file to parse.
- include_path:
An iterable (e.g. list or tuple) containing paths to search for /include/d and /incbin/’d files. By default, files are only looked up relative to the .dts file that contains the /include/ or /incbin/.
- force:
Try not to raise DTError even if the input tree has errors. For experimental use; results not guaranteed.
- get_node(path: str) devicetree.dtlib.Node
Returns the Node instance for the node with path or alias ‘path’ (a string). Raises DTError if the path or alias doesn’t exist.
For example, both dt.get_node(“/foo/bar”) and dt.get_node(“bar-alias”) will return the ‘bar’ node below:
/dts-v1/;
- / {
- foo {
- bar_label: bar {
baz { };
};
};
- aliases {
bar-alias = &bar-label;
};
};
Fetching subnodes via aliases is supported: dt.get_node(“bar-alias/baz”) returns the ‘baz’ node.
- has_node(path: str) bool
Returns True if the path or alias ‘path’ exists. See Node.get_node().
- node_iter() Iterable[devicetree.dtlib.Node]
Returns a generator for iterating over all nodes in the devicetree.
For example, this will print the name of each node that has a property called ‘foo’:
- for node in dt.node_iter():
- if “foo” in node.props:
print(node.name)
- property root: devicetree.dtlib.Node
See the class documentation.
- class devicetree.dtlib.Node(name: str, parent: Optional[devicetree.dtlib.Node], dt: devicetree.dtlib.DT)
Represents a node in the devicetree (‘node-name { … };’).
These attributes are available on Node instances:
- name:
The name of the node (a string).
- unit_addr:
The portion after the ‘@’ in the node’s name, or the empty string if the name has no ‘@’ in it.
Note that this is a string. Run int(node.unit_addr, 16) to get an integer.
- props:
A collections.OrderedDict that maps the properties defined on the node to their values. ‘props’ is indexed by property name (a string), and values are Property objects.
To convert property values to Python numbers or strings, use dtlib.to_num(), dtlib.to_nums(), or dtlib.to_string().
Property values are represented as ‘bytes’ arrays to support the full generality of DTS, which allows assignments like
x = “foo”, < 0x12345678 >, [ 9A ];
This gives x the value b”foo0x12x34x56x78x9A”. Numbers in DTS are stored in big-endian format.
- nodes:
A collections.OrderedDict containing the subnodes of the node, indexed by name.
- labels:
A list with all labels pointing to the node, in the same order as the labels appear, but with duplicates removed.
‘label_1: label_2: node { … };’ gives ‘labels’ the value [“label_1”, “label_2”].
- parent:
The parent Node of the node. ‘None’ for the root node.
- path:
The path to the node as a string, e.g. “/foo/bar”.
- dt:
The DT instance this node belongs to.
- class devicetree.dtlib.Property(node: devicetree.dtlib.Node, name: str)
Represents a property (‘x = …’).
These attributes are available on Property instances:
- name:
The name of the property (a string).
- value:
The value of the property, as a ‘bytes’ string. Numbers are stored in big-endian format, and strings are null-terminated. Putting multiple comma-separated values in an assignment (e.g., ‘x = < 1 >, “foo”’) will concatenate the values.
See the to_*() methods for converting the value to other types.
- type:
The type of the property, inferred from the syntax used in the assignment. This is one of the following constants (with example assignments):
Assignment | Property.type —————————-+———————— foo; | dtlib.Type.EMPTY foo = []; | dtlib.Type.BYTES foo = [01 02]; | dtlib.Type.BYTES foo = /bits/ 8 <1>; | dtlib.Type.BYTES foo = <1>; | dtlib.Type.NUM foo = <>; | dtlib.Type.NUMS foo = <1 2 3>; | dtlib.Type.NUMS foo = <1 2>, <3>; | dtlib.Type.NUMS foo = “foo”; | dtlib.Type.STRING foo = “foo”, “bar”; | dtlib.Type.STRINGS foo = <&l>; | dtlib.Type.PHANDLE foo = <&l1 &l2 &l3>; | dtlib.Type.PHANDLES foo = <&l1 &l2>, <&l3>; | dtlib.Type.PHANDLES foo = <&l1 1 2 &l2 3 4>; | dtlib.Type.PHANDLES_AND_NUMS foo = <&l1 1 2>, <&l2 3 4>; | dtlib.Type.PHANDLES_AND_NUMS foo = &l; | dtlib.Type.PATH Anything else | dtlib.Type.COMPOUND
Anything else includes properties mixing phandle (<&label>) and node path (&label) references with other data.
Data labels in the property value do not influence the type.
- labels:
A list with all labels pointing to the property, in the same order as the labels appear, but with duplicates removed.
‘label_1: label2: x = …’ gives ‘labels’ the value {“label_1”, “label_2”}.
- offset_labels:
A dictionary that maps any labels within the property’s value to their offset, in bytes. For example, ‘x = < 0 label_1: 1 label_2: >’ gives ‘offset_labels’ the value {“label_1”: 4, “label_2”: 8}.
Iteration order will match the order of the labels on Python versions that preserve dict insertion order.
- node:
The Node the property is on.
- class devicetree.dtlib.DTError
Exception raised for devicetree-related errors
edtlib
This is the higher level representation that incorporates standard conventions for well known properties as well as extra information in Zephyr’s bindings syntax.
Library for working with devicetrees at a higher level compared to dtlib. Like dtlib, this library presents a tree of devicetree nodes, but the nodes are augmented with information from bindings and include some interpretation of properties. Some of this interpretation is based on conventions established by the Linux kernel, so the Documentation/devicetree/bindings in the Linux source code is sometimes good reference material.
Bindings are YAML files that describe devicetree nodes. Devicetree nodes are usually mapped to bindings via their ‘compatible = “…”’ property, but a binding can also come from a ‘child-binding:’ key in the binding for the parent devicetree node.
Each devicetree node (dtlib.Node) gets a corresponding edtlib.Node instance, which has all the information related to the node.
The top-level entry points for the library are the EDT and Binding classes. See their constructor docstrings for details. There is also a bindings_from_paths() helper function.
- class devicetree.edtlib.EDT(dts, bindings_dirs, warn_reg_unit_address_mismatch=True, default_prop_types=True, support_fixed_partitions_on_any_bus=True, infer_binding_for_paths=None, vendor_prefixes=None, werror=False)
Represents a devicetree augmented with information from bindings.
These attributes are available on EDT objects:
- nodes:
A list of Node objects for the nodes that appear in the devicetree
- compat2nodes:
A collections.defaultdict that maps each ‘compatible’ string that appears on some Node to a list of Nodes with that compatible.
- compat2okay:
Like compat2nodes, but just for nodes with status ‘okay’.
- label2node:
A collections.OrderedDict that maps a node label to the node with that label.
- dep_ord2node:
A collections.OrderedDict that maps an ordinal to the node with that dependency ordinal.
- chosen_nodes:
A collections.OrderedDict that maps the properties defined on the devicetree’s /chosen node to their values. ‘chosen’ is indexed by property name (a string), and values are converted to Node objects. Note that properties of the /chosen node which can’t be converted to a Node are not included in the value.
- dts_path:
The .dts path passed to __init__()
- dts_source:
The final DTS source code of the loaded devicetree after merging nodes and processing /delete-node/ and /delete-property/, as a string
- bindings_dirs:
The bindings directory paths passed to __init__()
- scc_order:
A list of lists of Nodes. All elements of each list depend on each other, and the Nodes in any list do not depend on any Node in a subsequent list. Each list defines a Strongly Connected Component (SCC) of the graph.
For an acyclic graph each list will be a singleton. Cycles will be represented by lists with multiple nodes. Cycles are not expected to be present in devicetree graphs.
The standard library’s pickle module can be used to marshal and unmarshal EDT objects.
- __init__(dts, bindings_dirs, warn_reg_unit_address_mismatch=True, default_prop_types=True, support_fixed_partitions_on_any_bus=True, infer_binding_for_paths=None, vendor_prefixes=None, werror=False)
EDT constructor.
- dts:
Path to devicetree .dts file
- bindings_dirs:
List of paths to directories containing bindings, in YAML format. These directories are recursively searched for .yaml files.
- warn_reg_unit_address_mismatch (default: True):
If True, a warning is logged if a node has a ‘reg’ property where the address of the first entry does not match the unit address of the node
- default_prop_types (default: True):
If True, default property types will be used when a node has no bindings.
- support_fixed_partitions_on_any_bus (default True):
If True, set the Node.bus for ‘fixed-partitions’ compatible nodes to None. This allows ‘fixed-partitions’ binding to match regardless of the bus the ‘fixed-partition’ is under.
- infer_binding_for_paths (default: None):
An iterable of devicetree paths identifying nodes for which bindings should be inferred from the node content. (Child nodes are not processed.) Pass none if no nodes should support inferred bindings.
- vendor_prefixes (default: None):
A dict mapping vendor prefixes in compatible properties to their descriptions. If given, compatibles in the form “manufacturer,device” for which “manufacturer” is neither a key in the dict nor a specially exempt set of grandfathered-in cases will cause warnings.
- werror (default: False):
If True, some edtlib specific warnings become errors. This currently errors out if ‘dts’ has any deprecated properties set, or an unknown vendor prefix is used.
- class devicetree.edtlib.Binding(path, fname2path, raw=None, require_compatible=True, require_description=True)
Represents a parsed binding.
These attributes are available on Binding objects:
- path:
The absolute path to the file defining the binding.
- description:
The free-form description of the binding.
- compatible:
The compatible string the binding matches.
This may be None. For example, it’s None when the Binding is inferred from node properties. It can also be None for Binding objects created using ‘child-binding:’ with no compatible.
- prop2specs:
A collections.OrderedDict mapping property names to PropertySpec objects describing those properties’ values.
- specifier2cells:
A collections.OrderedDict that maps specifier space names (like “gpio”, “clock”, “pwm”, etc.) to lists of cell names.
For example, if the binding YAML contains ‘pin’ and ‘flags’ cell names for the ‘gpio’ specifier space, like this:
gpio-cells: - pin - flags
Then the Binding object will have a ‘specifier2cells’ attribute mapping “gpio” to [“pin”, “flags”]. A missing key should be interpreted as zero cells.
- raw:
The binding as an object parsed from YAML.
- bus:
If nodes with this binding’s ‘compatible’ describe a bus, a string describing the bus type (like “i2c”). None otherwise.
- on_bus:
If nodes with this binding’s ‘compatible’ appear on a bus, a string describing the bus type (like “i2c”). None otherwise.
- child_binding:
If this binding describes the properties of child nodes, then this is a Binding object for those children; it is None otherwise. A Binding object’s ‘child_binding.child_binding’ is not None if there are multiple levels of ‘child-binding’ descriptions in the binding.
- __init__(path, fname2path, raw=None, require_compatible=True, require_description=True)
Binding constructor.
- path:
Path to binding YAML file. May be None.
- fname2path:
Map from include files to their absolute paths. Must not be None, but may be empty.
- raw:
Optional raw content in the binding. This does not have to have any “include:” lines resolved. May be left out, in which case ‘path’ is opened and read. This can be used to resolve child bindings, for example.
- require_compatible:
If True, it is an error if the binding does not contain a “compatible:” line. If False, a missing “compatible:” is not an error. Either way, “compatible:” must be a string if it is present in the binding.
- require_description:
If True, it is an error if the binding does not contain a “description:” line. If False, a missing “description:” is not an error. Either way, “description:” must be a string if it is present in the binding.
- class devicetree.edtlib.PropertySpec(name, binding)
Represents a “property specification”, i.e. the description of a property provided by a binding file, like its type and description.
These attributes are available on PropertySpec objects:
- binding:
The Binding object which defined this property.
- name:
The property’s name.
- path:
The file where this property was defined. In case a binding includes other bindings, this is the file where the property was last modified.
- type:
The type of the property as a string, as given in the binding.
- description:
The free-form description of the property as a string, or None.
- enum:
A list of values the property may take as given in the binding, or None.
- enum_tokenizable:
True if enum is not None and all the values in it are tokenizable; False otherwise.
A property must have string type and an “enum:” in its binding to be tokenizable. Additionally, the “enum:” values must be unique after converting all non-alphanumeric characters to underscores (so “foo bar” and “foo_bar” in the same “enum:” would not be tokenizable).
- enum_upper_tokenizable:
Like ‘enum_tokenizable’, with the additional restriction that the “enum:” values must be unique after uppercasing and converting non-alphanumeric characters to underscores.
- const:
The property’s constant value as given in the binding, or None.
- default:
The property’s default value as given in the binding, or None.
- deprecated:
True if the property is deprecated; False otherwise.
- required:
True if the property is marked required; False otherwise.
- specifier_space:
The specifier space for the property as given in the binding, or None.
- class devicetree.edtlib.Node
Represents a devicetree node, augmented with information from bindings, and with some interpretation of devicetree properties. There’s a one-to-one correspondence between devicetree nodes and Nodes.
These attributes are available on Node objects:
- edt:
The EDT instance this node is from
- name:
The name of the node
- unit_addr:
An integer with the …@<unit-address> portion of the node name, translated through any ‘ranges’ properties on parent nodes, or None if the node name has no unit-address portion
- description:
The description string from the binding for the node, or None if the node has no binding. Leading and trailing whitespace (including newlines) is removed.
- path:
The devicetree path of the node
- label:
The text from the ‘label’ property on the node, or None if the node has no ‘label’
- labels:
A list of all of the devicetree labels for the node, in the same order as the labels appear, but with duplicates removed.
This corresponds to the actual devicetree source labels, unlike the “label” attribute, which is the value of a devicetree property named “label”.
- parent:
The Node instance for the devicetree parent of the Node, or None if the node is the root node
- children:
A dictionary with the Node instances for the devicetree children of the node, indexed by name
- dep_ordinal:
A non-negative integer value such that the value for a Node is less than the value for all Nodes that depend on it.
The ordinal is defined for all Nodes, and is unique among nodes in its EDT ‘nodes’ list.
- required_by:
A list with the nodes that directly depend on the node
- depends_on:
A list with the nodes that the node directly depends on
- status:
The node’s status property value, as a string, or “okay” if the node has no status property set. If the node’s status property is “ok”, it is converted to “okay” for consistency.
- read_only:
True if the node has a ‘read-only’ property, and False otherwise
- matching_compat:
The ‘compatible’ string for the binding that matched the node, or None if the node has no binding
- binding_path:
The path to the binding file for the node, or None if the node has no binding
- compats:
A list of ‘compatible’ strings for the node, in the same order that they’re listed in the .dts file
- ranges:
A list if Range objects extracted from the node’s ranges property. The list is empty if the node does not have a range property.
- regs:
A list of Register objects for the node’s registers
- props:
A collections.OrderedDict that maps property names to Property objects. Property objects are created for all devicetree properties on the node that are mentioned in ‘properties:’ in the binding.
- aliases:
A list of aliases for the node. This is fetched from the /aliases node.
- interrupts:
A list of ControllerAndData objects for the interrupts generated by the node. The list is empty if the node does not generate interrupts.
- pinctrls:
A list of PinCtrl objects for the pinctrl-<index> properties on the node, sorted by index. The list is empty if the node does not have any pinctrl-<index> properties.
- bus:
If the node is a bus node (has a ‘bus:’ key in its binding), then this attribute holds the bus type, e.g. “i2c” or “spi”. If the node is not a bus node, then this attribute is None.
- on_bus:
The bus the node appears on, e.g. “i2c” or “spi”. The bus is determined by searching upwards for a parent node whose binding has a ‘bus:’ key, returning the value of the first ‘bus:’ key found. If none of the node’s parents has a ‘bus:’ key, this attribute is None.
- bus_node:
Like on_bus, but contains the Node for the bus controller, or None if the node is not on a bus.
- flash_controller:
The flash controller for the node. Only meaningful for nodes representing flash partitions.
- spi_cs_gpio:
The device’s SPI GPIO chip select as a ControllerAndData instance, if it exists, and None otherwise. See Documentation/devicetree/bindings/spi/spi-controller.yaml in the Linux kernel.
- class devicetree.edtlib.Property(spec, val, node)
Represents a property on a Node, as set in its DT node and with additional info from the ‘properties:’ section of the binding.
Only properties mentioned in ‘properties:’ get created. Properties of type ‘compound’ currently do not get Property instances, as it’s not clear what to generate for them.
These attributes are available on Property objects. Several are just convenience accessors for attributes on the PropertySpec object accessible via the ‘spec’ attribute.
These attributes are available on Property objects:
- node:
The Node instance the property is on
- spec:
The PropertySpec object which specifies this property.
- name:
Convenience for spec.name.
- description:
Convenience for spec.name with leading and trailing whitespace (including newlines) removed.
- type:
Convenience for spec.type.
- val:
The value of the property, with the format determined by spec.type, which comes from the ‘type:’ string in the binding.
For ‘type: int/array/string/string-array’, ‘val’ is what you’d expect (a Python integer or string, or a list of them)
For ‘type: phandle’ and ‘type: path’, ‘val’ is the pointed-to Node instance
For ‘type: phandles’, ‘val’ is a list of the pointed-to Node instances
For ‘type: phandle-array’, ‘val’ is a list of ControllerAndData instances. See the documentation for that class.
- val_as_token:
The value of the property as a token, i.e. with non-alphanumeric characters replaced with underscores. This is only safe to access if self.enum_tokenizable returns True.
- enum_index:
The index of ‘val’ in ‘spec.enum’ (which comes from the ‘enum:’ list in the binding), or None if spec.enum is None.
- class devicetree.edtlib.Register
Represents a register on a node.
These attributes are available on Register objects:
- node:
The Node instance this register is from
- name:
The name of the register as given in the ‘reg-names’ property, or None if there is no ‘reg-names’ property
- addr:
The starting address of the register, in the parent address space, or None if #address-cells is zero. Any ‘ranges’ properties are taken into account.
- size:
The length of the register in bytes
- class devicetree.edtlib.ControllerAndData
Represents an entry in an ‘interrupts’ or ‘type: phandle-array’ property value, e.g. <&ctrl-1 4 0> in
cs-gpios = <&ctrl-1 4 0 &ctrl-2 3 4>;
These attributes are available on ControllerAndData objects:
- node:
The Node instance the property appears on
- controller:
The Node instance for the controller (e.g. the controller the interrupt gets sent to for interrupts)
- data:
A dictionary that maps names from the *-cells key in the binding for the controller to data values, e.g. {“pin”: 4, “flags”: 0} for the example above.
‘interrupts = <1 2>’ might give {“irq”: 1, “level”: 2}.
- name:
The name of the entry as given in ‘interrupt-names’/’gpio-names’/’pwm-names’/etc., or None if there is no *-names property
- basename:
Basename for the controller when supporting named cells
- class devicetree.edtlib.PinCtrl
Represents a pin control configuration for a set of pins on a device, e.g. pinctrl-0 or pinctrl-1.
These attributes are available on PinCtrl objects:
- node:
The Node instance the pinctrl-* property is on
- name:
The name of the configuration, as given in pinctrl-names, or None if there is no pinctrl-names property
- name_as_token:
Like ‘name’, but with non-alphanumeric characters converted to underscores.
- conf_nodes:
A list of Node instances for the pin configuration nodes, e.g. the nodes pointed at by &state_1 and &state_2 in
pinctrl-0 = <&state_1 &state_2>;
- class devicetree.edtlib.EDTError
Exception raised for devicetree- and binding-related errors