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 # 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. 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 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 sys
import textwrap 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: class DT:
""" """
Represents a device tree parsed from a .dts file (or from many files, if Represents a devicetree parsed from a .dts file (or from many files, if the
the .dts file /include/s other files). Creating many instances of this .dts file /include/s other files). Creating many instances of this class is
class is fine. The library has no global state. fine. The library has no global state.
These attributes are available on DT instances: These attributes are available on DT instances:
@ -160,7 +163,7 @@ class DT:
def node_iter(self): 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 For example, this will print the name of each node that has a property
called 'foo': called 'foo':
@ -173,8 +176,8 @@ class DT:
def __str__(self): def __str__(self):
""" """
Returns a DTS representation of the device tree. Called automatically Returns a DTS representation of the devicetree. Called automatically if
if the DT instance is print()ed. the DT instance is print()ed.
""" """
s = "/dts-v1/;\n\n" s = "/dts-v1/;\n\n"
@ -1165,7 +1168,7 @@ class DT:
class Node: class Node:
r""" 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: These attributes are available on Node instances:
@ -1721,7 +1724,7 @@ class Property:
def to_num(data, length=None, signed=False): def to_num(data, length=None, signed=False):
""" """
Converts the 'bytes' array 'data' to a number. The value is expected to be 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): length (default: None):
The expected length of the value in bytes, as a simple type check. If 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): def to_nums(data, length=4, signed=False):
""" """
Like Property.to_nums(), but takes an arbitrary 'bytes' array. The values 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_is_bytes(data)
_check_length_positive(length) _check_length_positive(length)
@ -1844,7 +1847,7 @@ _escape_table = str.maketrans({
class DTError(Exception): class DTError(Exception):
"Exception raised for Device Tree-related errors" "Exception raised for devicetree-related errors"
_Token = collections.namedtuple("Token", "id val") _Token = collections.namedtuple("Token", "id val")

View file

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

View file

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

View file

@ -40,109 +40,109 @@ def run():
# Test interrupts # Test interrupts
# #
verify_streq(edt.get_dev("/interrupt-parent-test/node").interrupts, verify_streq(edt.get_node("/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}>]") "[<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, verify_streq(edt.get_node("/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}>]") "[<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, verify_streq(edt.get_node("/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}>]") "[<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, verify_streq(edt.get_node("/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}>]") "[<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, verify_streq(edt.get_node("/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}>]") "[<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 # Test GPIOs
# #
verify_streq(edt.get_dev("/gpio-test/node").gpios, verify_streq(edt.get_node("/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}>]}") "{'': [<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 # Test clocks
# #
verify_streq(edt.get_dev("/clock-test/node").clocks, verify_streq(edt.get_node("/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}>]") "[<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 # Test PWMs
# #
verify_streq(edt.get_dev("/pwm-test/node").pwms, verify_streq(edt.get_node("/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}>]") "[<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 # Test IO channels
# #
verify_streq(edt.get_dev("/io-channel-test/node").iochannels, verify_streq(edt.get_node("/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}>]") "[<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' # 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>]") "[<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>]") "[<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>]") "[<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>]") "[<Register, addr: 0x30000000200000001, size: 0x1>]")
# #
# Test Device.parent and Device.children # 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, verify_streq(edt.get_node("/parent/child-1").parent,
"<Device /parent in 'test.dts', no binding>") "<Node /parent in 'test.dts', no binding>")
verify_streq(edt.get_dev("/parent/child-2/grandchild").parent, verify_streq(edt.get_node("/parent/child-2/grandchild").parent,
"<Device /parent/child-2 in 'test.dts', no binding>") "<Node /parent/child-2 in 'test.dts', no binding>")
verify_streq(edt.get_dev("/parent").children, verify_streq(edt.get_node("/parent").children,
"{'child-1': <Device /parent/child-1 in 'test.dts', no binding>, 'child-2': <Device /parent/child-2 in 'test.dts', no binding>}") "{'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 ...' # 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") "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>}") "{'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:' # 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") "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-bindings/device-on-bar-bus.yaml")
# #
# Test 'child-binding:' # Test 'child-binding:'
# #
child1 = edt.get_dev("/child-binding/child-1") child1 = edt.get_node("/child-binding/child-1")
child2 = edt.get_dev("/child-binding/child-2") child2 = edt.get_node("/child-binding/child-2")
grandchild = edt.get_dev("/child-binding/child-1/grandchild") grandchild = edt.get_node("/child-binding/child-1/grandchild")
verify_streq(child1.binding_path, "test-bindings/child-binding.yaml") verify_streq(child1.binding_path, "test-bindings/child-binding.yaml")
verify_streq(child1.description, "child node") verify_streq(child1.description, "child node")
@ -160,21 +160,21 @@ def run():
# Test deprecated 'sub-node:' key (replaced with 'child-binding:') # 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>}") "{'child-prop': <Property, name: child-prop, type: int, value: 3>}")
# #
# Test Device.property (derived from DT and 'properties:' in the binding) # Test Device.property (derived from DT and 'properties:' in the binding)
# #
verify_streq(edt.get_dev("/props").props, 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: <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>]>}") 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 # 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>}") 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"]) 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") "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") "test-bindings-2/multidir.yaml")

View file

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