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>
This commit is contained in:
Ulf Magnusson 2019-09-23 05:14:18 +02:00 committed by Kumar Gala
commit 73ac1466fb
5 changed files with 418 additions and 415 deletions

View file

@ -8,7 +8,7 @@
# pylint: disable=undefined-variable
"""
A library for extracting information from .dts (Device Tree) files. See the
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
@ -23,14 +23,17 @@ import re
import sys
import textwrap
# NOTE: testdtlib.py is the test suite for this library. It can be run directly.
# NOTE: testdtlib.py is the test suite for this library. It can be run directly
# as a script:
#
# ./testdtlib.py
class DT:
"""
Represents a device tree 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.
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:
@ -160,7 +163,7 @@ class DT:
def node_iter(self):
"""
Returns a generator for iterating over all nodes in the device tree.
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':
@ -173,8 +176,8 @@ class DT:
def __str__(self):
"""
Returns a DTS representation of the device tree. Called automatically
if the DT instance is print()ed.
Returns a DTS representation of the devicetree. Called automatically if
the DT instance is print()ed.
"""
s = "/dts-v1/;\n\n"
@ -1165,7 +1168,7 @@ class DT:
class Node:
r"""
Represents a node in the device tree ('node-name { ... };').
Represents a node in the devicetree ('node-name { ... };').
These attributes are available on Node instances:
@ -1721,7 +1724,7 @@ class Property:
def to_num(data, length=None, signed=False):
"""
Converts the 'bytes' array 'data' to a number. The value is expected to be
in big-endian format, which is standard in Device Tree.
in big-endian format, which is standard in devicetree.
length (default: None):
The expected length of the value in bytes, as a simple type check. If
@ -1743,7 +1746,7 @@ def to_num(data, length=None, signed=False):
def to_nums(data, length=4, signed=False):
"""
Like Property.to_nums(), but takes an arbitrary 'bytes' array. The values
are assumed to be in big-endian format, which is standard in Device Tree.
are assumed to be in big-endian format, which is standard in devicetree.
"""
_check_is_bytes(data)
_check_length_positive(length)
@ -1844,7 +1847,7 @@ _escape_table = str.maketrans({
class DTError(Exception):
"Exception raised for Device Tree-related errors"
"Exception raised for devicetree-related errors"
_Token = collections.namedtuple("Token", "id val")

View file

@ -5,22 +5,21 @@
# Tip: You can view just the documentation with 'pydoc3 edtlib'
"""
Library for working with .dts files and bindings at a higher level compared to
dtlib. Deals with things at the level of devices, registers, interrupts,
compatibles, bindings, etc., as opposed to dtlib, which is just a low-level
device tree parser.
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.
Each device tree node (dtlib.Node) gets a Device instance, which has all the
information related to the device, derived from both the device tree and from
the binding for the device.
Bindings are 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.
Bindings are files that describe device tree nodes. Device tree 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
device tree 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 point of the library is the EDT class. EDT.__init__() takes
a .dts file to parse and the path of a directory containing bindings.
a .dts file to parse and a list of paths to directories containing bindings.
"""
import os
@ -33,7 +32,9 @@ from dtlib import DT, DTError, to_num, to_nums, TYPE_EMPTY, TYPE_NUMS, \
TYPE_PHANDLE, TYPE_PHANDLES_AND_NUMS
# NOTE: testedtlib.py is the test suite for this library. It can be run
# directly.
# directly as a script:
#
# ./testedtlib.py
# Implementation notes
# --------------------
@ -80,13 +81,12 @@ from dtlib import DT, DTError, to_num, to_nums, TYPE_EMPTY, TYPE_NUMS, \
class EDT:
"""
Represents a "high-level" view of a device tree, with a list of devices
that each have some number of registers, etc.
Represents a devicetree augmented with information from bindings.
These attributes are available on EDT objects:
devices:
A list of Device objects for the devices
nodes:
A list of Node objects for the nodes that appear in the devicetree
dts_path:
The .dts path passed to __init__()
@ -99,7 +99,7 @@ class EDT:
EDT constructor. This is the top-level entry point to the library.
dts:
Path to device tree .dts file
Path to devicetree .dts file
bindings_dirs:
List of paths to directories containing bindings, in YAML format.
@ -112,22 +112,22 @@ class EDT:
_check_dt(self._dt)
self._init_compat2binding(bindings_dirs)
self._init_devices()
self._init_nodes()
def get_dev(self, path):
def get_node(self, path):
"""
Returns the Device at the DT path or alias 'path'. Raises EDTError if
the path or alias doesn't exist.
Returns the Node at the DT path or alias 'path'. Raises EDTError if the
path or alias doesn't exist.
"""
try:
return self._node2dev[self._dt.get_node(path)]
return self._node2enode[self._dt.get_node(path)]
except DTError as e:
_err(e)
def chosen_dev(self, name):
def chosen_node(self, name):
"""
Returns the Device pointed at by the property named 'name' in /chosen,
or None if the property is missing
Returns the Node pointed at by the property named 'name' in /chosen, or
None if the property is missing
"""
try:
chosen = self._dt.get_node("/chosen")
@ -139,7 +139,7 @@ class EDT:
return None
# to_path() checks that the node exists
return self._node2dev[chosen.props[name].to_path()]
return self._node2enode[chosen.props[name].to_path()]
def _init_compat2binding(self, bindings_dirs):
# Creates self._compat2binding. This is a dictionary that maps
@ -154,7 +154,7 @@ class EDT:
# For bindings that don't specify a bus, <bus> is None, so that e.g.
# self._compat2binding["company,notonbus", None] contains the binding.
#
# Only bindings for 'compatible' strings that appear in the device tree
# Only bindings for 'compatible' strings that appear in the devicetree
# are loaded.
# Add legacy '!include foo.yaml' handling. Do
@ -296,63 +296,63 @@ class EDT:
yaml.load(f, Loader=yaml.Loader),
paths[0])
def _init_devices(self):
# Creates a list of devices (Device objects) from the DT nodes, in
# self.devices
def _init_nodes(self):
# Creates a list of edtlib.Node objects from the dtlib.Node objects, in
# self.nodes
# Maps dtlib.Node's to their corresponding Devices
self._node2dev = {}
# Maps each dtlib.Node to its corresponding edtlib.Node
self._node2enode = {}
self.devices = []
self.nodes = []
for node in self._dt.node_iter():
# Warning: We depend on parent Devices being created before their
for dt_node in self._dt.node_iter():
# Warning: We depend on parent Nodes being created before their
# children. This is guaranteed by node_iter().
dev = Device()
dev.edt = self
dev._node = node
dev._init_binding()
dev._init_regs()
dev._set_instance_no()
node = Node()
node.edt = self
node._node = dt_node
node._init_binding()
node._init_regs()
node._set_instance_no()
self.devices.append(dev)
self._node2dev[node] = dev
self.nodes.append(node)
self._node2enode[dt_node] = node
for dev in self.devices:
# Device._init_props() depends on all Device objects having been
for node in self.nodes:
# Node._init_props() depends on all Node objects having been
# created, due to 'type: phandle', so we run it separately.
# Property.val is set to the pointed-to Device instance for
# phandles, which must exist.
dev._init_props()
# Property.val is set to the pointed-to Node instance for phandles,
# which must exist.
node._init_props()
for dev in self.devices:
# These also depend on all Device objects having been created, and
# might also depend on all Device.props having been initialized
for node in self.nodes:
# These also depend on all Node objects having been created, and
# might also depend on all Node.props having been initialized
# (_init_clocks() does as of writing).
dev._init_interrupts()
dev._init_gpios()
dev._init_pwms()
dev._init_iochannels()
dev._init_clocks()
node._init_interrupts()
node._init_gpios()
node._init_pwms()
node._init_iochannels()
node._init_clocks()
def __repr__(self):
return "<EDT for '{}', binding directories '{}'>".format(
self.dts_path, self.bindings_dirs)
class Device:
class Node:
"""
Represents a device, which is a devicetree node augmented with information
from bindings and some interpretation of devicetree properties. There's a
one-to-one correspondence between device tree nodes and Devices.
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 Device objects:
These attributes are available on Node objects:
edt:
The EDT instance this device is from
The EDT instance this node is from
name:
The name of the device. This is fetched from the node name.
The name of the node
unit_addr:
An integer with the ...@<unit-address> portion of the node name,
@ -360,67 +360,65 @@ class Device:
the node name has no unit-address portion
path:
The device tree path of the device
The devicetree path of the node
label:
The text from the 'label' property on the DT node of the Device, or None
if the node has no 'label'
The text from the 'label' property on the node, or None if the node has
no 'label'
parent:
The Device instance for the devicetree parent of the Device, or None if
there is no 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 Device instances for the devicetree children of the
Device, indexed by name
A dictionary with the Node instances for the devicetree children of the
node, indexed by name
enabled:
True unless the device's node has 'status = "disabled"'
True unless the node has 'status = "disabled"'
read_only:
True if the DT node of the Device has a 'read-only' property, and False
otherwise
True if the node has a 'read-only' property, and False otherwise
instance_no:
Dictionary that maps each 'compatible' string for the device to a unique
index among all devices that have that 'compatible' string.
Dictionary that maps each 'compatible' string for the node to a unique
index among all nodes that have that 'compatible' string.
As an example, 'instance_no["foo,led"] == 3' can be read as "this is the
fourth foo,led device".
fourth foo,led node".
Only enabled devices (status != "disabled") are counted. 'instance_no' is
meaningless for disabled devices.
Only enabled nodes (status != "disabled") are counted. 'instance_no' is
meaningless for disabled nodes.
matching_compat:
The 'compatible' string for the binding that matched the device, or
None if the device has no binding
The 'compatible' string for the binding that matched the node, or None if
the node has no binding
description:
The description string from the binding file for the device, or None if
the device has no binding. Trailing whitespace (including newlines) is
removed.
The description string from the binding file for the node, or None if the
node has no binding. Trailing whitespace (including newlines) is removed.
binding_path:
The path to the binding file for the device, or None if the device has no
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 device, in the same order that
A list of 'compatible' strings for the node, in the same order that
they're listed in the .dts file
regs:
A list of Register objects for the device's registers
A list of Register objects for the node's registers
props:
A dictionary that maps property names to Property objects. Property
objects are created for all DT properties on the device that are
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 device. This is fetched from the /aliases node.
A list of aliases for the node. This is fetched from the /aliases node.
interrupts:
A list of Interrupt objects for the interrupts generated by the device
A list of Interrupt objects for the interrupts generated by the node
gpios:
A dictionary that maps the <prefix> part in '<prefix>-gpios' properties
@ -431,24 +429,23 @@ class Device:
pwms:
A list of PWM objects, derived from the 'pwms' property. The list is
empty if the device has no 'pwms' property.
empty if the node has no 'pwms' property.
iochannels:
A list of IOChannel objects, derived from the 'io-channels'
property. The list is empty if the device has no 'io-channels'
property.
A list of IOChannel objects, derived from the 'io-channels' property. The
list is empty if the node has no 'io-channels' property.
clocks:
A list of Clock objects, derived from the 'clocks' property. The list is
empty if the device has no 'clocks' property.
empty if the node has no 'clocks' property.
bus:
The bus for the device as specified in its binding, e.g. "i2c" or "spi".
The bus for the node as specified in its binding, e.g. "i2c" or "spi".
None if the binding doesn't specify a bus.
flash_controller:
The flash controller for the device. Only meaningful for devices
representing flash partitions.
The flash controller for the node. Only meaningful for nodes representing
flash partitions.
"""
@property
def name(self):
@ -492,15 +489,15 @@ class Device:
@property
def parent(self):
"See the class docstring"
return self.edt._node2dev.get(self._node.parent)
return self.edt._node2enode.get(self._node.parent)
@property
def children(self):
"See the class docstring"
# Could be initialized statically too to preserve identity, but not
# sure if needed. Parent Devices being initialized before their
# children would need to be kept in mind.
return {name: self.edt._node2dev[node]
# sure if needed. Parent nodes being initialized before their children
# would need to be kept in mind.
return {name: self.edt._node2enode[node]
for name, node in self._node.nodes.items()}
@property
@ -546,20 +543,20 @@ class Device:
return controller
def __repr__(self):
return "<Device {} in '{}', {}>".format(
return "<Node {} in '{}', {}>".format(
self.path, self.edt.dts_path,
"binding " + self.binding_path if self.binding_path
else "no binding")
def _init_binding(self):
# Initializes Device.matching_compat, Device._binding, and
# Device.binding_path.
# Initializes Node.matching_compat, Node._binding, and
# Node.binding_path.
#
# Device._binding holds the data from the device's binding file, in the
# Node._binding holds the data from the node's binding file, in the
# format returned by PyYAML (plain Python lists, dicts, etc.), or None
# if the device has no binding.
# if the node has no binding.
# This relies on the parent of the Device having already been
# This relies on the parent of the node having already been
# initialized, which is guaranteed by going through the nodes in
# node_iter() order.
@ -696,7 +693,7 @@ class Device:
return
prop = Property()
prop.dev = self
prop.node = self
prop.name = name
prop.description = options.get("description")
if prop.description:
@ -768,10 +765,10 @@ class Device:
return prop.to_strings()
if prop_type == "phandle":
return self.edt._node2dev[prop.to_node()]
return self.edt._node2enode[prop.to_node()]
if prop_type == "phandles":
return [self.edt._node2dev[node] for node in prop.to_nodes()]
return [self.edt._node2enode[node] for node in prop.to_nodes()]
if prop_type == "phandle-array":
# This property type only does a type check. No Property object is
@ -831,7 +828,7 @@ class Device:
for raw_reg in _slice(node, "reg", 4*(address_cells + size_cells)):
reg = Register()
reg.dev = self
reg.node = self
reg.addr = _translate(to_num(raw_reg[:4*address_cells]), node)
reg.size = to_num(raw_reg[4*address_cells:])
if size_cells != 0 and reg.size == 0:
@ -852,8 +849,8 @@ class Device:
for controller_node, spec in _interrupts(node):
interrupt = Interrupt()
interrupt.dev = self
interrupt.controller = self.edt._node2dev[controller_node]
interrupt.node = self
interrupt.controller = self.edt._node2enode[controller_node]
interrupt.specifier = self._named_cells(interrupt.controller, spec,
"interrupt")
@ -870,8 +867,8 @@ class Device:
self.gpios[prefix] = []
for controller_node, spec in gpios:
gpio = GPIO()
gpio.dev = self
gpio.controller = self.edt._node2dev[controller_node]
gpio.node = self
gpio.controller = self.edt._node2enode[controller_node]
gpio.specifier = self._named_cells(gpio.controller, spec,
"GPIO")
gpio.name = prefix
@ -928,7 +925,7 @@ class Device:
#
# cls:
# A class object. Instances of this class will be created and the
# 'dev', 'controller', 'specifier', and 'name' fields initialized.
# 'node', 'controller', 'specifier', and 'name' fields initialized.
# See the documentation for e.g. the PWM class.
#
# Returns a list of 'cls' instances.
@ -941,8 +938,8 @@ class Device:
for controller_node, spec in _phandle_val_list(prop, name):
obj = cls()
obj.dev = self
obj.controller = self.edt._node2dev[controller_node]
obj.node = self
obj.controller = self.edt._node2enode[controller_node]
obj.specifier = self._named_cells(obj.controller, spec, name)
res.append(obj)
@ -987,19 +984,19 @@ class Device:
for compat in self.compats:
self.instance_no[compat] = 0
for other_dev in self.edt.devices:
if compat in other_dev.compats and other_dev.enabled:
for other_node in self.edt.nodes:
if compat in other_node.compats and other_node.enabled:
self.instance_no[compat] += 1
class Register:
"""
Represents a register on a device.
Represents a register on a node.
These attributes are available on Register objects:
dev:
The Device instance this register is from
node:
The Node instance this register is from
name:
The name of the register as given in the 'reg-names' property, or None if
@ -1025,19 +1022,19 @@ class Register:
class Interrupt:
"""
Represents an interrupt generated by a device.
Represents an interrupt generated by a node.
These attributes are available on Interrupt objects:
dev:
The Device instance that generated the interrupt
node:
The Node instance that generated the interrupt
name:
The name of the interrupt as given in the 'interrupt-names' property, or
None if there is no 'interrupt-names' property
controller:
The Device instance for the controller the interrupt gets sent to. Any
The Node instance for the controller the interrupt gets sent to. Any
'interrupt-map' is taken into account, so that this is the final
controller node.
@ -1060,19 +1057,19 @@ class Interrupt:
class GPIO:
"""
Represents a GPIO used by a device.
Represents a GPIO used by a node.
These attributes are available on GPIO objects:
dev:
The Device instance that uses the GPIO
node:
The Node instance that uses the GPIO
name:
The name of the gpio as extracted out of the "<NAME>-gpios" property. If
the property is just "gpios" than there is no name.
controller:
The Device instance for the controller of the GPIO
The Node instance for the controller of the GPIO
specifier:
A dictionary that maps names from the #cells portion of the binding to
@ -1093,19 +1090,19 @@ class GPIO:
class Clock:
"""
Represents a clock used by a device.
Represents a clock used by a node.
These attributes are available on Clock objects:
dev:
The Device instance that uses the clock
node:
The Node instance that uses the clock
name:
The name of the clock as given in the 'clock-names' property, or
None if there is no 'clock-names' property
controller:
The Device instance for the controller of the clock.
The Node instance for the controller of the clock.
frequency:
The frequency of the clock for fixed clocks ('fixed-clock' in
@ -1133,19 +1130,19 @@ class Clock:
class PWM:
"""
Represents a PWM used by a device.
Represents a PWM used by a node.
These attributes are available on PWM objects:
dev:
The Device instance that uses the PWM
node:
The Node instance that uses the PWM
name:
The name of the pwm as given in the 'pwm-names' property, or the
node name if the 'pwm-names' property doesn't exist.
controller:
The Device instance for the controller of the PWM
The Node instance for the controller of the PWM
specifier:
A dictionary that maps names from the #cells portion of the binding to
@ -1166,21 +1163,21 @@ class PWM:
class IOChannel:
"""
Represents an IO channel used by a device, similar to the property used
Represents an IO channel used by a node, similar to the property used
by the Linux IIO bindings and described at:
https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/iio-bindings.txt
These attributes are available on IO channel objects:
dev:
The Device instance that uses the IO channel
node:
The Node instance that uses the IO channel
name:
The name of the IO channel as given in the 'io-channel-names' property,
or the node name if the 'io-channel-names' property doesn't exist.
controller:
The Device instance for the controller of the IO channel
The Node instance for the controller of the IO channel
specifier:
A dictionary that maps names from the #cells portion of the binding to
@ -1201,7 +1198,7 @@ class IOChannel:
class Property:
"""
Represents a property on a Device, as set in its DT node and with
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 with
@ -1210,8 +1207,8 @@ class Property:
These attributes are available on Property objects:
dev:
The Device instance the property is on
node:
The Node instance the property is on
name:
The name of the property
@ -1227,9 +1224,9 @@ class Property:
The value of the property, with the format determined by the 'type:' key
from the binding.
For 'type: phandle' properties, this is the pointed-to Device instance.
For 'type: phandle' properties, this is the pointed-to Node instance.
For 'type: phandles' properties, this is a list of the pointed-to Device
For 'type: phandles' properties, this is a list of the pointed-to Node
instances.
enum_index:
@ -1249,7 +1246,7 @@ class Property:
class EDTError(Exception):
"Exception raised for Extended Device Tree-related errors"
"Exception raised for devicetree- and binding-related errors"
#
@ -1257,20 +1254,20 @@ class EDTError(Exception):
#
def spi_dev_cs_gpio(dev):
def spi_dev_cs_gpio(node):
# Returns an SPI device's GPIO chip select if it exists, as a GPIO
# instance, and None otherwise. See
# Documentation/devicetree/bindings/spi/spi-bus.txt in the Linux kernel.
if dev.bus == "spi" and dev.parent:
parent_cs = dev.parent.gpios.get("cs")
if node.bus == "spi" and node.parent:
parent_cs = node.parent.gpios.get("cs")
if parent_cs:
# cs-gpios is indexed by the unit address
cs_index = dev.regs[0].addr
cs_index = node.regs[0].addr
if cs_index >= len(parent_cs):
_err("index from 'regs' in {!r} ({}) is >= number of cs-gpios "
"in {!r} ({})".format(
dev, cs_index, dev.parent, len(parent_cs)))
node, cs_index, node.parent, len(parent_cs)))
return parent_cs[cs_index]
@ -1283,7 +1280,7 @@ def spi_dev_cs_gpio(dev):
def _dt_compats(dt):
# Returns a set() with all 'compatible' strings in the device tree
# Returns a set() with all 'compatible' strings in the devicetree
# represented by dt (a dtlib.DT instance)
return {compat
@ -1647,6 +1644,9 @@ def _translate(addr, node):
# Recursively translates 'addr' on 'node' to the address space(s) of its
# parent(s), by looking at 'ranges' properties. Returns the translated
# address.
#
# node:
# dtlib.Node instance
if not node.parent or "ranges" not in node.parent.props:
# No translation
@ -1691,7 +1691,7 @@ def _add_names(node, names_ident, objs):
# Helper for registering names from <foo>-names properties.
#
# node:
# Device tree node
# edtlib.Node instance
#
# names-ident:
# The <foo> part of <foo>-names, e.g. "reg" for "reg-names"

View file

@ -5,10 +5,10 @@
# SPDX-License-Identifier: BSD-3-Clause
# This script uses edtlib to generate a header file and a .conf file (both
# containing the same values) from a device tree (.dts) file. Information from
# containing the same values) from a devicetree (.dts) file. Information from
# binding files in YAML format is used as well.
#
# Bindings are files that describe device tree nodes. Device tree nodes are
# Bindings are files that describe devicetree nodes. Devicetree nodes are
# usually mapped to bindings via their 'compatible = "..."' property.
#
# See the docstring/comments at the top of edtlib.py for more information.
@ -33,7 +33,7 @@ def main():
try:
edt = edtlib.EDT(args.dts, args.bindings_dirs)
except edtlib.EDTError as e:
sys.exit("device tree error: " + str(e))
sys.exit("devicetree error: " + str(e))
conf_file = open(args.conf_out, "w", encoding="utf-8")
header_file = open(args.header_out, "w", encoding="utf-8")
@ -45,33 +45,33 @@ def main():
active_compats = set()
for dev in edt.devices:
if dev.enabled and dev.matching_compat:
for node in edt.nodes:
if node.enabled and node.matching_compat:
# Skip 'fixed-partitions' devices since they are handled by
# write_flash() and would generate extra spurious #defines
if dev.matching_compat == "fixed-partitions":
if node.matching_compat == "fixed-partitions":
continue
out_comment("Device tree node: " + dev.path)
out_comment("Devicetree node: " + node.path)
out_comment("Binding (compatible = {}): {}".format(
dev.matching_compat, dev.binding_path),
node.matching_compat, node.binding_path),
blank_before=False)
out_comment("Binding description: " + dev.description,
out_comment("Binding description: " + node.description,
blank_before=False)
write_regs(dev)
write_irqs(dev)
for gpios in dev.gpios.values():
write_phandle_val_list(dev, gpios, "GPIO")
write_phandle_val_list(dev, dev.pwms, "PWM")
write_phandle_val_list(dev, dev.iochannels, "IO_CHANNEL")
write_clocks(dev)
write_spi_dev(dev)
write_props(dev)
write_bus(dev)
write_existence_flags(dev)
write_regs(node)
write_irqs(node)
for gpios in node.gpios.values():
write_phandle_val_list(node, gpios, "GPIO")
write_phandle_val_list(node, node.pwms, "PWM")
write_phandle_val_list(node, node.iochannels, "IO_CHANNEL")
write_clocks(node)
write_spi_dev(node)
write_props(node)
write_bus(node)
write_existence_flags(node)
active_compats.update(dev.compats)
active_compats.update(node.compats)
out_comment("Active compatibles (mentioned in DTS + binding found)")
for compat in sorted(active_compats):
@ -83,20 +83,20 @@ def main():
write_addr_size(edt, "zephyr,ccm", "CCM")
write_addr_size(edt, "zephyr,dtcm", "DTCM")
write_flash(edt.chosen_dev("zephyr,flash"))
write_code_partition(edt.chosen_dev("zephyr,code-partition"))
write_flash(edt.chosen_node("zephyr,flash"))
write_code_partition(edt.chosen_node("zephyr,code-partition"))
flash_index = 0
for dev in edt.devices:
if dev.name.startswith("partition@"):
write_flash_partition(dev, flash_index)
for node in edt.nodes:
if node.name.startswith("partition@"):
write_flash_partition(node, flash_index)
flash_index += 1
out_comment("Number of flash partitions")
if flash_index != 0:
out("FLASH_AREA_NUM", flash_index)
print("Device tree configuration written to " + args.conf_out)
print("Devicetree configuration written to " + args.conf_out)
def parse_args():
@ -115,8 +115,8 @@ def parse_args():
return parser.parse_args()
def write_regs(dev):
# Writes address/size output for the registers in dev's 'reg' property
def write_regs(node):
# Writes address/size output for the registers in the node's 'reg' property
def reg_addr_name_alias(reg):
return str2ident(reg.name) + "_BASE_ADDRESS" if reg.name else None
@ -124,20 +124,20 @@ def write_regs(dev):
def reg_size_name_alias(reg):
return str2ident(reg.name) + "_SIZE" if reg.name else None
for reg in dev.regs:
out_dev(dev, reg_addr_ident(reg), hex(reg.addr),
for reg in node.regs:
out_dev(node, reg_addr_ident(reg), hex(reg.addr),
name_alias=reg_addr_name_alias(reg))
if reg.size:
out_dev(dev, reg_size_ident(reg), reg.size,
out_dev(node, reg_size_ident(reg), reg.size,
name_alias=reg_size_name_alias(reg))
def write_props(dev):
def write_props(node):
# Writes any properties defined in the "properties" section of the binding
# for the device
# for the node
for prop in dev.props.values():
for prop in node.props.values():
# Skip #size-cell and other property starting with #. Also skip mapping
# properties like 'gpio-map'.
if prop.name[0] == "#" or prop.name.endswith("-map"):
@ -160,64 +160,65 @@ def write_props(dev):
ident = str2ident(prop.name)
if prop.type == "boolean":
out_dev(dev, ident, 1 if prop.val else 0)
out_dev(node, ident, 1 if prop.val else 0)
elif prop.type == "string":
out_dev_s(dev, ident, prop.val)
out_dev_s(node, ident, prop.val)
elif prop.type == "int":
out_dev(dev, ident, prop.val)
out_dev(node, ident, prop.val)
elif prop.type == "array":
for i, val in enumerate(prop.val):
out_dev(dev, "{}_{}".format(ident, i), val)
out_dev(node, "{}_{}".format(ident, i), val)
elif prop.type == "string-array":
for i, val in enumerate(prop.val):
out_dev_s(dev, "{}_{}".format(ident, i), val)
out_dev_s(node, "{}_{}".format(ident, i), val)
elif prop.type == "uint8-array":
out_dev(dev, ident,
out_dev(node, ident,
"{ " + ", ".join("0x{:02x}".format(b) for b in prop.val) + " }")
# Generate DT_..._ENUM if there's an 'enum:' key in the binding
if prop.enum_index is not None:
out_dev(dev, ident + "_ENUM", prop.enum_index)
out_dev(node, ident + "_ENUM", prop.enum_index)
def write_bus(dev):
def write_bus(node):
# Generate bus-related #defines
if not dev.bus:
if not node.bus:
return
if dev.parent.label is None:
err("missing 'label' property on {!r}".format(dev.parent))
if node.parent.label is None:
err("missing 'label' property on {!r}".format(node.parent))
# #define DT_<DEV-IDENT>_BUS_NAME <BUS-LABEL>
out_dev_s(dev, "BUS_NAME", str2ident(dev.parent.label))
out_dev_s(node, "BUS_NAME", str2ident(node.parent.label))
for compat in dev.compats:
for compat in node.compats:
# #define DT_<COMPAT>_BUS_<BUS-TYPE> 1
out("{}_BUS_{}".format(str2ident(compat), str2ident(dev.bus)), 1)
out("{}_BUS_{}".format(str2ident(compat), str2ident(node.bus)), 1)
def write_existence_flags(dev):
def write_existence_flags(node):
# Generate #defines of the form
#
# #define DT_INST_<INSTANCE>_<COMPAT> 1
#
# These are flags for which devices exist.
for compat in dev.compats:
out("INST_{}_{}".format(dev.instance_no[compat], str2ident(compat)), 1)
for compat in node.compats:
out("INST_{}_{}".format(node.instance_no[compat],
str2ident(compat)), 1)
def reg_addr_ident(reg):
# Returns the identifier (e.g., macro name) to be used for the address of
# 'reg' in the output
dev = reg.dev
node = reg.node
# NOTE: to maintain compat wit the old script we special case if there's
# only a single register (we drop the '_0').
if len(dev.regs) > 1:
return "BASE_ADDRESS_{}".format(dev.regs.index(reg))
if len(node.regs) > 1:
return "BASE_ADDRESS_{}".format(node.regs.index(reg))
else:
return "BASE_ADDRESS"
@ -226,61 +227,61 @@ def reg_size_ident(reg):
# Returns the identifier (e.g., macro name) to be used for the size of
# 'reg' in the output
dev = reg.dev
node = reg.node
# NOTE: to maintain compat wit the old script we special case if there's
# only a single register (we drop the '_0').
if len(dev.regs) > 1:
return "SIZE_{}".format(dev.regs.index(reg))
if len(node.regs) > 1:
return "SIZE_{}".format(node.regs.index(reg))
else:
return "SIZE"
def dev_ident(dev):
# Returns an identifier for the Device 'dev'. Used when building e.g. macro
# names.
def dev_ident(node):
# Returns an identifier for the device given by 'node'. Used when building
# e.g. macro names.
# TODO: Handle PWM on STM
# TODO: Better document the rules of how we generate things
ident = ""
if dev.bus:
if node.bus:
ident += "{}_{:X}_".format(
str2ident(dev.parent.matching_compat), dev.parent.unit_addr)
str2ident(node.parent.matching_compat), node.parent.unit_addr)
ident += "{}_".format(str2ident(dev.matching_compat))
ident += "{}_".format(str2ident(node.matching_compat))
if dev.unit_addr is not None:
ident += "{:X}".format(dev.unit_addr)
elif dev.parent.unit_addr is not None:
ident += "{:X}_{}".format(dev.parent.unit_addr, str2ident(dev.name))
if node.unit_addr is not None:
ident += "{:X}".format(node.unit_addr)
elif node.parent.unit_addr is not None:
ident += "{:X}_{}".format(node.parent.unit_addr, str2ident(node.name))
else:
# This is a bit of a hack
ident += "{}".format(str2ident(dev.name))
ident += "{}".format(str2ident(node.name))
return ident
def dev_aliases(dev):
# Returns a list of aliases for the Device 'dev', used e.g. when building
# macro names
def dev_aliases(node):
# Returns a list of aliases for the device given by 'node', used e.g. when
# building macro names
return dev_path_aliases(dev) + dev_instance_aliases(dev)
return dev_path_aliases(node) + dev_instance_aliases(node)
def dev_path_aliases(dev):
# Returns a list of aliases for the Device 'dev', based on the aliases
# registered for the device, in the /aliases node. Used when building e.g.
def dev_path_aliases(node):
# Returns a list of aliases for the device given by 'node', based on the
# aliases registered for it, in the /aliases node. Used when building e.g.
# macro names.
if dev.matching_compat is None:
if node.matching_compat is None:
return []
compat_s = str2ident(dev.matching_compat)
compat_s = str2ident(node.matching_compat)
aliases = []
for alias in dev.aliases:
for alias in node.aliases:
aliases.append("ALIAS_{}".format(str2ident(alias)))
# TODO: See if we can remove or deprecate this form
aliases.append("{}_{}".format(compat_s, str2ident(alias)))
@ -288,112 +289,112 @@ def dev_path_aliases(dev):
return aliases
def dev_instance_aliases(dev):
# Returns a list of aliases for the Device 'dev', based on the instance
# number of the device (based on how many instances of that particular
# device there are).
def dev_instance_aliases(node):
# Returns a list of aliases for the device given by 'node', based on the
# instance number of the device (based on how many instances of that
# particular device there are).
#
# This is a list since a device can have multiple 'compatible' strings,
# each with their own instance number.
return ["INST_{}_{}".format(dev.instance_no[compat], str2ident(compat))
for compat in dev.compats]
return ["INST_{}_{}".format(node.instance_no[compat], str2ident(compat))
for compat in node.compats]
def write_addr_size(edt, prop_name, prefix):
# Writes <prefix>_BASE_ADDRESS and <prefix>_SIZE for the device
# pointed at by the /chosen property named 'prop_name', if it exists
# Writes <prefix>_BASE_ADDRESS and <prefix>_SIZE for the node pointed at by
# the /chosen property named 'prop_name', if it exists
dev = edt.chosen_dev(prop_name)
if not dev:
node = edt.chosen_node(prop_name)
if not node:
return
if not dev.regs:
if not node.regs:
err("missing 'reg' property in node pointed at by /chosen/{} ({!r})"
.format(prop_name, dev))
.format(prop_name, node))
out_comment("/chosen/{} ({})".format(prop_name, dev.path))
out("{}_BASE_ADDRESS".format(prefix), hex(dev.regs[0].addr))
out("{}_SIZE".format(prefix), dev.regs[0].size//1024)
out_comment("/chosen/{} ({})".format(prop_name, node.path))
out("{}_BASE_ADDRESS".format(prefix), hex(node.regs[0].addr))
out("{}_SIZE".format(prefix), node.regs[0].size//1024)
def write_flash(flash_dev):
def write_flash(flash_node):
# Writes output for the node pointed at by the zephyr,flash property in
# /chosen
out_comment("/chosen/zephyr,flash ({})"
.format(flash_dev.path if flash_dev else "missing"))
.format(flash_node.path if flash_node else "missing"))
if not flash_dev:
# No flash device. Write dummy values.
if not flash_node:
# No flash node. Write dummy values.
out("FLASH_BASE_ADDRESS", 0)
out("FLASH_SIZE", 0)
return
if len(flash_dev.regs) != 1:
if len(flash_node.regs) != 1:
err("expected zephyr,flash to have a single register, has {}"
.format(len(flash_dev.regs)))
.format(len(flash_node.regs)))
if flash_dev.bus == "spi" and len(flash_dev.parent.regs) == 2:
reg = flash_dev.parent.regs[1] # QSPI flash
if flash_node.bus == "spi" and len(flash_node.parent.regs) == 2:
reg = flash_node.parent.regs[1] # QSPI flash
else:
reg = flash_dev.regs[0]
reg = flash_node.regs[0]
out("FLASH_BASE_ADDRESS", hex(reg.addr))
if reg.size:
out("FLASH_SIZE", reg.size//1024)
if "erase-block-size" in flash_dev.props:
out("FLASH_ERASE_BLOCK_SIZE", flash_dev.props["erase-block-size"].val)
if "erase-block-size" in flash_node.props:
out("FLASH_ERASE_BLOCK_SIZE", flash_node.props["erase-block-size"].val)
if "write-block-size" in flash_dev.props:
out("FLASH_WRITE_BLOCK_SIZE", flash_dev.props["write-block-size"].val)
if "write-block-size" in flash_node.props:
out("FLASH_WRITE_BLOCK_SIZE", flash_node.props["write-block-size"].val)
def write_code_partition(code_dev):
def write_code_partition(code_node):
# Writes output for the node pointed at by the zephyr,code-partition
# property in /chosen
out_comment("/chosen/zephyr,code-partition ({})"
.format(code_dev.path if code_dev else "missing"))
.format(code_node.path if code_node else "missing"))
if not code_dev:
if not code_node:
# No code partition. Write dummy values.
out("CODE_PARTITION_OFFSET", 0)
out("CODE_PARTITION_SIZE", 0)
return
if not code_dev.regs:
err("missing 'regs' property on {!r}".format(code_dev))
if not code_node.regs:
err("missing 'regs' property on {!r}".format(code_node))
out("CODE_PARTITION_OFFSET", code_dev.regs[0].addr)
out("CODE_PARTITION_SIZE", code_dev.regs[0].size)
out("CODE_PARTITION_OFFSET", code_node.regs[0].addr)
out("CODE_PARTITION_SIZE", code_node.regs[0].size)
def write_flash_partition(partition_dev, index):
out_comment("Flash partition at " + partition_dev.path)
def write_flash_partition(partition_node, index):
out_comment("Flash partition at " + partition_node.path)
if partition_dev.label is None:
err("missing 'label' property on {!r}".format(partition_dev))
if partition_node.label is None:
err("missing 'label' property on {!r}".format(partition_node))
# Generate label-based identifiers
write_flash_partition_prefix(
"FLASH_AREA_" + str2ident(partition_dev.label), partition_dev, index)
"FLASH_AREA_" + str2ident(partition_node.label), partition_node, index)
# Generate index-based identifiers
write_flash_partition_prefix(
"FLASH_AREA_{}".format(index), partition_dev, index)
"FLASH_AREA_{}".format(index), partition_node, index)
def write_flash_partition_prefix(prefix, partition_dev, index):
def write_flash_partition_prefix(prefix, partition_node, index):
# write_flash_partition() helper. Generates identifiers starting with
# 'prefix'.
out("{}_ID".format(prefix), index)
out("{}_READ_ONLY".format(prefix), 1 if partition_dev.read_only else 0)
out("{}_READ_ONLY".format(prefix), 1 if partition_node.read_only else 0)
for i, reg in enumerate(partition_dev.regs):
for i, reg in enumerate(partition_node.regs):
# Also add aliases that point to the first sector (TODO: get rid of the
# aliases?)
out("{}_OFFSET_{}".format(prefix, i), reg.addr,
@ -401,13 +402,14 @@ def write_flash_partition_prefix(prefix, partition_dev, index):
out("{}_SIZE_{}".format(prefix, i), reg.size,
aliases=["{}_SIZE".format(prefix)] if i == 0 else [])
controller = partition_dev.flash_controller
controller = partition_node.flash_controller
if controller.label is not None:
out_s("{}_DEV".format(prefix), controller.label)
def write_irqs(dev):
# Writes IRQ num and data for the interrupts in dev's 'interrupt' property
def write_irqs(node):
# Writes IRQ num and data for the interrupts in the node's 'interrupt'
# property
def irq_name_alias(irq, cell_name):
if not irq.name:
@ -433,7 +435,7 @@ def write_irqs(dev):
irq_ctrl = irq_ctrl.interrupts[0].controller
return irq_num
for irq_i, irq in enumerate(dev.interrupts):
for irq_i, irq in enumerate(node.interrupts):
for cell_name, cell_value in irq.specifier.items():
ident = "IRQ_{}".format(irq_i)
if cell_name == "irq":
@ -441,25 +443,25 @@ def write_irqs(dev):
else:
ident += "_" + str2ident(cell_name)
out_dev(dev, ident, cell_value,
out_dev(node, ident, cell_value,
name_alias=irq_name_alias(irq, cell_name))
def write_spi_dev(dev):
def write_spi_dev(node):
# Writes SPI device GPIO chip select data if there is any
cs_gpio = edtlib.spi_dev_cs_gpio(dev)
cs_gpio = edtlib.spi_dev_cs_gpio(node)
if cs_gpio is not None:
write_phandle_val_list_entry(dev, cs_gpio, None, "GPIO")
write_phandle_val_list_entry(node, cs_gpio, None, "GPIO")
def write_phandle_val_list(dev, entries, ident):
def write_phandle_val_list(node, entries, ident):
# Writes output for a phandle/value list, e.g.
#
# pwms = <&pwm-ctrl-1 10 20
# &pwm-ctrl-2 30 40>;
#
# dev:
# node:
# Device used to generate device prefixes (see 'ident' below)
#
# entries:
@ -487,13 +489,13 @@ def write_phandle_val_list(dev, entries, ident):
initializer_vals = []
for i, entry in enumerate(entries):
initializer_vals.append(write_phandle_val_list_entry(
dev, entry, i if len(entries) > 1 else None, ident))
node, entry, i if len(entries) > 1 else None, ident))
if len(entries) > 1:
out_dev(dev, ident + "S_COUNT", len(initializer_vals))
out_dev(dev, ident + "S", "{" + ", ".join(initializer_vals) + "}")
out_dev(node, ident + "S_COUNT", len(initializer_vals))
out_dev(node, ident + "S", "{" + ", ".join(initializer_vals) + "}")
def write_phandle_val_list_entry(dev, entry, i, ident):
def write_phandle_val_list_entry(node, entry, i, ident):
# write_phandle_val_list() helper. We could get rid of it if it wasn't for
# write_spi_dev(). Adds 'i' as an index to identifiers unless it's None.
#
@ -510,7 +512,7 @@ def write_phandle_val_list_entry(dev, entry, i, ident):
if i is not None:
ctrl_ident += "_{}".format(i)
initializer_vals.append(quote_str(entry.controller.label))
out_dev_s(dev, ctrl_ident, entry.controller.label)
out_dev_s(node, ctrl_ident, entry.controller.label)
for cell, val in entry.specifier.items():
cell_ident = ident + "S_" + str2ident(cell) # e.g. PWMS_CHANNEL
@ -520,7 +522,7 @@ def write_phandle_val_list_entry(dev, entry, i, ident):
# Backwards compatibility (see above)
if i is not None:
cell_ident += "_{}".format(i)
out_dev(dev, cell_ident, val)
out_dev(node, cell_ident, val)
initializer_vals += entry.specifier.values()
@ -529,20 +531,20 @@ def write_phandle_val_list_entry(dev, entry, i, ident):
initializer_ident += "_" + str2ident(entry.name)
if i is not None:
initializer_ident += "_{}".format(i)
return out_dev(dev, initializer_ident,
return out_dev(node, initializer_ident,
"{" + ", ".join(map(str, initializer_vals)) + "}")
def write_clocks(dev):
# Writes clock controller and specifier info for the clock in dev's 'clock'
# property
def write_clocks(node):
# Writes clock controller and specifier info for the clock in the node's
# 'clock' property
for clock_i, clock in enumerate(dev.clocks):
for clock_i, clock in enumerate(node.clocks):
if clock.controller.label is not None:
out_dev_s(dev, "CLOCK_CONTROLLER", clock.controller.label)
out_dev_s(node, "CLOCK_CONTROLLER", clock.controller.label)
if clock.frequency is not None:
out_dev(dev, "CLOCKS_CLOCK_FREQUENCY", clock.frequency)
out_dev(node, "CLOCKS_CLOCK_FREQUENCY", clock.frequency)
for spec, val in clock.specifier.items():
if clock_i == 0:
@ -550,7 +552,7 @@ def write_clocks(dev):
else:
clk_name_alias = None
out_dev(dev, "CLOCK_{}_{}".format(str2ident(spec), clock_i), val,
out_dev(node, "CLOCK_{}_{}".format(str2ident(spec), clock_i), val,
name_alias=clk_name_alias)
@ -566,7 +568,7 @@ def str2ident(s):
.upper()
def out_dev(dev, ident, val, name_alias=None):
def out_dev(node, ident, val, name_alias=None):
# Writes an
#
# <device prefix>_<ident> = <val>
@ -584,24 +586,24 @@ def out_dev(dev, ident, val, name_alias=None):
# 'name_alias' is used for reg-names and the like.
#
# Returns the identifier used for the macro that provides the value
# for 'ident' within 'dev', e.g. DT_MFG_MODEL_CTL_GPIOS_PIN.
# for 'ident' within 'node', e.g. DT_MFG_MODEL_CTL_GPIOS_PIN.
dev_prefix = dev_ident(dev)
dev_prefix = dev_ident(node)
aliases = [alias + "_" + ident for alias in dev_aliases(dev)]
aliases = [alias + "_" + ident for alias in dev_aliases(node)]
if name_alias is not None:
aliases.append(dev_prefix + "_" + name_alias)
aliases += [alias + "_" + name_alias for alias in dev_aliases(dev)]
aliases += [alias + "_" + name_alias for alias in dev_aliases(node)]
return out(dev_prefix + "_" + ident, val, aliases)
def out_dev_s(dev, ident, s):
def out_dev_s(node, ident, s):
# Like out_dev(), but emits 's' as a string literal
#
# Returns the generated macro name for 'ident'.
return out_dev(dev, ident, quote_str(s))
return out_dev(node, ident, quote_str(s))
def out_s(ident, val):

View file

@ -40,109 +40,109 @@ def run():
# Test interrupts
#
verify_streq(edt.get_dev("/interrupt-parent-test/node").interrupts,
"[<Interrupt, name: foo, target: <Device /interrupt-parent-test/controller in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 1, 'two': 2, 'three': 3}>, <Interrupt, name: bar, target: <Device /interrupt-parent-test/controller in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 4, 'two': 5, 'three': 6}>]")
verify_streq(edt.get_node("/interrupt-parent-test/node").interrupts,
"[<Interrupt, name: foo, target: <Node /interrupt-parent-test/controller in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 1, 'two': 2, 'three': 3}>, <Interrupt, name: bar, target: <Node /interrupt-parent-test/controller in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 4, 'two': 5, 'three': 6}>]")
verify_streq(edt.get_dev("/interrupts-extended-test/node").interrupts,
"[<Interrupt, target: <Device /interrupts-extended-test/controller-0 in 'test.dts', binding test-bindings/interrupt-1-cell.yaml>, specifier: {'one': 1}>, <Interrupt, target: <Device /interrupts-extended-test/controller-1 in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 2, 'two': 3}>, <Interrupt, target: <Device /interrupts-extended-test/controller-2 in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 4, 'two': 5, 'three': 6}>]")
verify_streq(edt.get_node("/interrupts-extended-test/node").interrupts,
"[<Interrupt, target: <Node /interrupts-extended-test/controller-0 in 'test.dts', binding test-bindings/interrupt-1-cell.yaml>, specifier: {'one': 1}>, <Interrupt, target: <Node /interrupts-extended-test/controller-1 in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 2, 'two': 3}>, <Interrupt, target: <Node /interrupts-extended-test/controller-2 in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 4, 'two': 5, 'three': 6}>]")
verify_streq(edt.get_dev("/interrupt-map-test/node@0").interrupts,
"[<Interrupt, target: <Device /interrupt-map-test/controller-0 in 'test.dts', binding test-bindings/interrupt-1-cell.yaml>, specifier: {'one': 0}>, <Interrupt, target: <Device /interrupt-map-test/controller-1 in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 0, 'two': 1}>, <Interrupt, target: <Device /interrupt-map-test/controller-2 in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 0, 'two': 0, 'three': 2}>]")
verify_streq(edt.get_node("/interrupt-map-test/node@0").interrupts,
"[<Interrupt, target: <Node /interrupt-map-test/controller-0 in 'test.dts', binding test-bindings/interrupt-1-cell.yaml>, specifier: {'one': 0}>, <Interrupt, target: <Node /interrupt-map-test/controller-1 in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 0, 'two': 1}>, <Interrupt, target: <Node /interrupt-map-test/controller-2 in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 0, 'two': 0, 'three': 2}>]")
verify_streq(edt.get_dev("/interrupt-map-test/node@1").interrupts,
"[<Interrupt, target: <Device /interrupt-map-test/controller-0 in 'test.dts', binding test-bindings/interrupt-1-cell.yaml>, specifier: {'one': 3}>, <Interrupt, target: <Device /interrupt-map-test/controller-1 in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 0, 'two': 4}>, <Interrupt, target: <Device /interrupt-map-test/controller-2 in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 0, 'two': 0, 'three': 5}>]")
verify_streq(edt.get_node("/interrupt-map-test/node@1").interrupts,
"[<Interrupt, target: <Node /interrupt-map-test/controller-0 in 'test.dts', binding test-bindings/interrupt-1-cell.yaml>, specifier: {'one': 3}>, <Interrupt, target: <Node /interrupt-map-test/controller-1 in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 0, 'two': 4}>, <Interrupt, target: <Node /interrupt-map-test/controller-2 in 'test.dts', binding test-bindings/interrupt-3-cell.yaml>, specifier: {'one': 0, 'two': 0, 'three': 5}>]")
verify_streq(edt.get_dev("/interrupt-map-bitops-test/node@70000000E").interrupts,
"[<Interrupt, target: <Device /interrupt-map-bitops-test/controller in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 3, 'two': 2}>]")
verify_streq(edt.get_node("/interrupt-map-bitops-test/node@70000000E").interrupts,
"[<Interrupt, target: <Node /interrupt-map-bitops-test/controller in 'test.dts', binding test-bindings/interrupt-2-cell.yaml>, specifier: {'one': 3, 'two': 2}>]")
#
# Test GPIOs
#
verify_streq(edt.get_dev("/gpio-test/node").gpios,
"{'': [<GPIO, name: , target: <Device /gpio-test/controller-0 in 'test.dts', binding test-bindings/gpio-1-cell.yaml>, specifier: {'one': 1}>, <GPIO, name: , target: <Device /gpio-test/controller-1 in 'test.dts', binding test-bindings/gpio-2-cell.yaml>, specifier: {'one': 2, 'two': 3}>], 'foo': [<GPIO, name: foo, target: <Device /gpio-test/controller-1 in 'test.dts', binding test-bindings/gpio-2-cell.yaml>, specifier: {'one': 4, 'two': 5}>], 'bar': [<GPIO, name: bar, target: <Device /gpio-test/controller-1 in 'test.dts', binding test-bindings/gpio-2-cell.yaml>, specifier: {'one': 6, 'two': 7}>]}")
verify_streq(edt.get_node("/gpio-test/node").gpios,
"{'': [<GPIO, name: , target: <Node /gpio-test/controller-0 in 'test.dts', binding test-bindings/gpio-1-cell.yaml>, specifier: {'one': 1}>, <GPIO, name: , target: <Node /gpio-test/controller-1 in 'test.dts', binding test-bindings/gpio-2-cell.yaml>, specifier: {'one': 2, 'two': 3}>], 'foo': [<GPIO, name: foo, target: <Node /gpio-test/controller-1 in 'test.dts', binding test-bindings/gpio-2-cell.yaml>, specifier: {'one': 4, 'two': 5}>], 'bar': [<GPIO, name: bar, target: <Node /gpio-test/controller-1 in 'test.dts', binding test-bindings/gpio-2-cell.yaml>, specifier: {'one': 6, 'two': 7}>]}")
#
# Test clocks
#
verify_streq(edt.get_dev("/clock-test/node").clocks,
"[<Clock, name: fixed, frequency: 123, target: <Device /clock-test/fixed-clock in 'test.dts', binding test-bindings/fixed-clock.yaml>, specifier: {}>, <Clock, name: one-cell, target: <Device /clock-test/clock-1 in 'test.dts', binding test-bindings/clock-1-cell.yaml>, specifier: {'one': 1}>, <Clock, name: two-cell, target: <Device /clock-test/clock-2 in 'test.dts', binding test-bindings/clock-2-cell.yaml>, specifier: {'one': 1, 'two': 2}>]")
verify_streq(edt.get_node("/clock-test/node").clocks,
"[<Clock, name: fixed, frequency: 123, target: <Node /clock-test/fixed-clock in 'test.dts', binding test-bindings/fixed-clock.yaml>, specifier: {}>, <Clock, name: one-cell, target: <Node /clock-test/clock-1 in 'test.dts', binding test-bindings/clock-1-cell.yaml>, specifier: {'one': 1}>, <Clock, name: two-cell, target: <Node /clock-test/clock-2 in 'test.dts', binding test-bindings/clock-2-cell.yaml>, specifier: {'one': 1, 'two': 2}>]")
#
# Test PWMs
#
verify_streq(edt.get_dev("/pwm-test/node").pwms,
"[<PWM, name: zero-cell, target: <Device /pwm-test/pwm-0 in 'test.dts', binding test-bindings/pwm-0-cell.yaml>, specifier: {}>, <PWM, name: one-cell, target: <Device /pwm-test/pwm-1 in 'test.dts', binding test-bindings/pwm-1-cell.yaml>, specifier: {'one': 1}>]")
verify_streq(edt.get_node("/pwm-test/node").pwms,
"[<PWM, name: zero-cell, target: <Node /pwm-test/pwm-0 in 'test.dts', binding test-bindings/pwm-0-cell.yaml>, specifier: {}>, <PWM, name: one-cell, target: <Node /pwm-test/pwm-1 in 'test.dts', binding test-bindings/pwm-1-cell.yaml>, specifier: {'one': 1}>]")
#
# Test IO channels
#
verify_streq(edt.get_dev("/io-channel-test/node").iochannels,
"[<IOChannel, name: io-channel, target: <Device /io-channel-test/io-channel in 'test.dts', binding test-bindings/io-channel.yaml>, specifier: {'one': 1}>]")
verify_streq(edt.get_node("/io-channel-test/node").iochannels,
"[<IOChannel, name: io-channel, target: <Node /io-channel-test/io-channel in 'test.dts', binding test-bindings/io-channel.yaml>, specifier: {'one': 1}>]")
#
# Test 'reg'
#
verify_streq(edt.get_dev("/reg-zero-address-cells/node").regs,
verify_streq(edt.get_node("/reg-zero-address-cells/node").regs,
"[<Register, addr: 0x0, size: 0x1>, <Register, addr: 0x0, size: 0x2>]")
verify_streq(edt.get_dev("/reg-zero-size-cells/node").regs,
verify_streq(edt.get_node("/reg-zero-size-cells/node").regs,
"[<Register, addr: 0x1, size: 0x0>, <Register, addr: 0x2, size: 0x0>]")
verify_streq(edt.get_dev("/reg-ranges/parent/node").regs,
verify_streq(edt.get_node("/reg-ranges/parent/node").regs,
"[<Register, addr: 0x5, size: 0x1>, <Register, addr: 0xe0000000f, size: 0x1>, <Register, addr: 0xc0000000e, size: 0x1>, <Register, addr: 0xc0000000d, size: 0x1>, <Register, addr: 0xa0000000b, size: 0x1>, <Register, addr: 0x0, size: 0x1>]")
verify_streq(edt.get_dev("/reg-nested-ranges/grandparent/parent/node").regs,
verify_streq(edt.get_node("/reg-nested-ranges/grandparent/parent/node").regs,
"[<Register, addr: 0x30000000200000001, size: 0x1>]")
#
# Test Device.parent and Device.children
#
verify_eq(edt.get_dev("/").parent, None)
verify_eq(edt.get_node("/").parent, None)
verify_streq(edt.get_dev("/parent/child-1").parent,
"<Device /parent in 'test.dts', no binding>")
verify_streq(edt.get_node("/parent/child-1").parent,
"<Node /parent in 'test.dts', no binding>")
verify_streq(edt.get_dev("/parent/child-2/grandchild").parent,
"<Device /parent/child-2 in 'test.dts', no binding>")
verify_streq(edt.get_node("/parent/child-2/grandchild").parent,
"<Node /parent/child-2 in 'test.dts', no binding>")
verify_streq(edt.get_dev("/parent").children,
"{'child-1': <Device /parent/child-1 in 'test.dts', no binding>, 'child-2': <Device /parent/child-2 in 'test.dts', no binding>}")
verify_streq(edt.get_node("/parent").children,
"{'child-1': <Node /parent/child-1 in 'test.dts', no binding>, 'child-2': <Node /parent/child-2 in 'test.dts', no binding>}")
verify_eq(edt.get_dev("/parent/child-1").children, {})
verify_eq(edt.get_node("/parent/child-1").children, {})
#
# Test 'include:' and the legacy 'inherits: !include ...'
#
verify_streq(edt.get_dev("/binding-include").description,
verify_streq(edt.get_node("/binding-include").description,
"Parent binding")
verify_streq(edt.get_dev("/binding-include").props,
verify_streq(edt.get_node("/binding-include").props,
"{'foo': <Property, name: foo, type: int, value: 0>, 'bar': <Property, name: bar, type: int, value: 1>, 'baz': <Property, name: baz, type: int, value: 2>, 'qaz': <Property, name: qaz, type: int, value: 3>}")
#
# Test 'child/parent-bus:'
#
verify_streq(edt.get_dev("/buses/foo-bus/node").binding_path,
verify_streq(edt.get_node("/buses/foo-bus/node").binding_path,
"test-bindings/device-on-foo-bus.yaml")
verify_streq(edt.get_dev("/buses/bar-bus/node").binding_path,
verify_streq(edt.get_node("/buses/bar-bus/node").binding_path,
"test-bindings/device-on-bar-bus.yaml")
#
# Test 'child-binding:'
#
child1 = edt.get_dev("/child-binding/child-1")
child2 = edt.get_dev("/child-binding/child-2")
grandchild = edt.get_dev("/child-binding/child-1/grandchild")
child1 = edt.get_node("/child-binding/child-1")
child2 = edt.get_node("/child-binding/child-2")
grandchild = edt.get_node("/child-binding/child-1/grandchild")
verify_streq(child1.binding_path, "test-bindings/child-binding.yaml")
verify_streq(child1.description, "child node")
@ -160,21 +160,21 @@ def run():
# Test deprecated 'sub-node:' key (replaced with 'child-binding:')
#
verify_streq(edt.get_dev("/deprecated/sub-node").props,
verify_streq(edt.get_node("/deprecated/sub-node").props,
"{'child-prop': <Property, name: child-prop, type: int, value: 3>}")
#
# Test Device.property (derived from DT and 'properties:' in the binding)
#
verify_streq(edt.get_dev("/props").props,
r"{'nonexistent-boolean': <Property, name: nonexistent-boolean, type: boolean, value: False>, 'existent-boolean': <Property, name: existent-boolean, type: boolean, value: True>, 'int': <Property, name: int, type: int, value: 1>, 'array': <Property, name: array, type: array, value: [1, 2, 3]>, 'uint8-array': <Property, name: uint8-array, type: uint8-array, value: b'\x124'>, 'string': <Property, name: string, type: string, value: 'foo'>, 'string-array': <Property, name: string-array, type: string-array, value: ['foo', 'bar', 'baz']>, 'phandle-ref': <Property, name: phandle-ref, type: phandle, value: <Device /props/node in 'test.dts', no binding>>, 'phandle-refs': <Property, name: phandle-refs, type: phandles, value: [<Device /props/node in 'test.dts', no binding>, <Device /props/node2 in 'test.dts', no binding>]>}")
verify_streq(edt.get_node("/props").props,
r"{'nonexistent-boolean': <Property, name: nonexistent-boolean, type: boolean, value: False>, 'existent-boolean': <Property, name: existent-boolean, type: boolean, value: True>, 'int': <Property, name: int, type: int, value: 1>, 'array': <Property, name: array, type: array, value: [1, 2, 3]>, 'uint8-array': <Property, name: uint8-array, type: uint8-array, value: b'\x124'>, 'string': <Property, name: string, type: string, value: 'foo'>, 'string-array': <Property, name: string-array, type: string-array, value: ['foo', 'bar', 'baz']>, 'phandle-ref': <Property, name: phandle-ref, type: phandle, value: <Node /props/node in 'test.dts', no binding>>, 'phandle-refs': <Property, name: phandle-refs, type: phandles, value: [<Node /props/node in 'test.dts', no binding>, <Node /props/node2 in 'test.dts', no binding>]>}")
#
# Test property default values given in bindings
#
verify_streq(edt.get_dev("/defaults").props,
verify_streq(edt.get_node("/defaults").props,
r"{'int': <Property, name: int, type: int, value: 123>, 'array': <Property, name: array, type: array, value: [1, 2, 3]>, 'uint8-array': <Property, name: uint8-array, type: uint8-array, value: b'\x89\xab\xcd'>, 'string': <Property, name: string, type: string, value: 'hello'>, 'string-array': <Property, name: string-array, type: string-array, value: ['hello', 'there']>, 'default-not-used': <Property, name: default-not-used, type: int, value: 234>}")
#
@ -183,10 +183,10 @@ def run():
edt = edtlib.EDT("test-multidir.dts", ["test-bindings", "test-bindings-2"])
verify_streq(edt.get_dev("/in-dir-1").binding_path,
verify_streq(edt.get_node("/in-dir-1").binding_path,
"test-bindings/multidir.yaml")
verify_streq(edt.get_dev("/in-dir-2").binding_path,
verify_streq(edt.get_node("/in-dir-2").binding_path,
"test-bindings-2/multidir.yaml")

View file

@ -121,54 +121,54 @@ def dt_str_val(kconf, _, name):
def dt_chosen_label(kconf, _, chosen):
"""
This function takes a 'chosen' property and treats that property as a path
to a EDT device. If it finds a EDT device, it will look to see if that
device has a "label" property and return the value of that "label", if not
we return an empty string.
to an EDT node. If it finds an EDT node, it will look to see if that node
has a "label" property and return the value of that "label", if not we
return an empty string.
"""
if doc_mode or edt is None:
return ""
dev = edt.chosen_dev(chosen)
if not dev:
node = edt.chosen_node(chosen)
if not node:
return ""
if "label" not in dev.props:
if "label" not in node.props:
return ""
return dev.props["label"].val
return node.props["label"].val
def _dev_reg_addr(dev, index, unit):
if not dev:
def _node_reg_addr(node, index, unit):
if not node:
return "0x0"
if not dev.regs:
if not node.regs:
return "0x0"
if int(index) >= len(dev.regs):
if int(index) >= len(node.regs):
return "0x0"
return hex(dev.regs[int(index)].addr >> _dt_units_to_scale(unit))
return hex(node.regs[int(index)].addr >> _dt_units_to_scale(unit))
def _dev_reg_size(dev, index, unit):
if not dev:
def _node_reg_size(node, index, unit):
if not node:
return "0"
if not dev.regs:
if not node.regs:
return "0"
if int(index) >= len(dev.regs):
if int(index) >= len(node.regs):
return "0"
return str(dev.regs[int(index)].size >> _dt_units_to_scale(unit))
return str(node.regs[int(index)].size >> _dt_units_to_scale(unit))
def dt_chosen_reg_addr(kconf, _, chosen, index=0, unit=None):
"""
This function takes a 'chosen' property and treats that property as a path
to a EDT device. If it finds a EDT device, it will look to see if that
device has a register at the give 'index' and return the address value of
to an EDT node. If it finds an EDT node, it will look to see if that
nodnode has a register at the given 'index' and return the address value of
that reg, if not we return 0.
The function will divide the value based on 'unit':
@ -180,17 +180,17 @@ def dt_chosen_reg_addr(kconf, _, chosen, index=0, unit=None):
if doc_mode or edt is None:
return "0x0"
dev = edt.chosen_dev(chosen)
node = edt.chosen_node(chosen)
return _dev_reg_addr(dev, index, unit)
return _node_reg_addr(node, index, unit)
def dt_chosen_reg_size(kconf, _, chosen, index=0, unit=None):
"""
This function takes a 'chosen' property and treats that property as a path
to a EDT device. If it finds a EDT device, it will look to see if that
device has a register at the give 'index' and return the size value of
that reg, if not we return 0.
to an EDT node. If it finds an EDT node, it will look to see if that node
has a register at the given 'index' and return the size value of that reg,
if not we return 0.
The function will divide the value based on 'unit':
None No division
@ -201,17 +201,16 @@ def dt_chosen_reg_size(kconf, _, chosen, index=0, unit=None):
if doc_mode or edt is None:
return "0"
dev = edt.chosen_dev(chosen)
node = edt.chosen_node(chosen)
return _dev_reg_size(dev, index, unit)
return _node_reg_size(node, index, unit)
def dt_node_reg_addr(kconf, _, path, index=0, unit=None):
"""
This function takes a 'path' and looks for a EDT device at that path.
If it finds a EDT device, it will look to see if that device has a
register at the give 'index' and return the address value of that reg, if
not we return 0.
This function takes a 'path' and looks for an EDT node at that path. If it
finds an EDT node, it will look to see if that node has a register at the
given 'index' and return the address value of that reg, if not we return 0.
The function will divide the value based on 'unit':
None No division
@ -223,19 +222,18 @@ def dt_node_reg_addr(kconf, _, path, index=0, unit=None):
return "0"
try:
dev = edt.get_dev(path)
node = edt.get_node(path)
except edtlib.EDTError:
return "0"
return _dev_reg_addr(dev, index, unit)
return _node_reg_addr(node, index, unit)
def dt_node_reg_size(kconf, _, path, index=0, unit=None):
"""
This function takes a 'path' and looks for a EDT device at that path.
If it finds a EDT device, it will look to see if that device has a
register at the give 'index' and return the size value of that reg, if
not we return 0.
This function takes a 'path' and looks for an EDT node at that path. If it
finds an EDT node, it will look to see if that node has a register at the
given 'index' and return the size value of that reg, if not we return 0.
The function will divide the value based on 'unit':
None No division
@ -247,35 +245,35 @@ def dt_node_reg_size(kconf, _, path, index=0, unit=None):
return "0"
try:
dev = edt.get_dev(path)
node = edt.get_node(path)
except edtlib.EDTError:
return "0"
return _dev_reg_size(dev, index, unit)
return _node_reg_size(node, index, unit)
def dt_node_has_bool_prop(kconf, _, path, prop):
"""
This function takes a 'path' and looks for a EDT device at that path.
If it finds a EDT device, it will look to see if that device has a
boolean property by the name of 'prop'. If the 'prop' exists it will
return "y" otherwise we return "n".
This function takes a 'path' and looks for an EDT node at that path. If it
finds an EDT node, it will look to see if that node has a boolean property
by the name of 'prop'. If the 'prop' exists it will return "y" otherwise
we return "n".
"""
if doc_mode or edt is None:
return "n"
try:
dev = edt.get_dev(path)
node = edt.get_node(path)
except edtlib.EDTError:
return "n"
if prop not in dev.props:
if prop not in node.props:
return "n"
if dev.props[prop].type != "boolean":
if node.props[prop].type != "boolean":
return "n"
if dev.props[prop].val:
if node.props[prop].val:
return "y"
return "n"
@ -284,13 +282,13 @@ def dt_node_has_bool_prop(kconf, _, path, prop):
def dt_compat_enabled(kconf, _, compat):
"""
This function takes a 'compat' and returns "y" if we find an "enabled"
compatible device in the EDT otherwise we return "n"
compatible node in the EDT otherwise we return "n"
"""
if doc_mode or edt is None:
return "n"
for dev in edt.devices:
if compat in dev.compats and dev.enabled:
for node in edt.nodes:
if compat in node.compats and node.enabled:
return "y"
return "n"