edtlib: add Range property on Node, used for PCIe I/O and memory regions
As described in IEEE Std 1275-1994, the PCIe bindings uses the ranges property to describe the PCI I/O and memory regions. Add parsing of this property in edtlib. Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
This commit is contained in:
parent
224468f35b
commit
cd6a5648d7
|
@ -419,6 +419,7 @@ class EDT:
|
|||
node.bus_node = node._bus_node(self._fixed_partitions_no_bus)
|
||||
node._init_binding()
|
||||
node._init_regs()
|
||||
node._init_ranges()
|
||||
|
||||
self.nodes.append(node)
|
||||
self._node2enode[dt_node] = node
|
||||
|
@ -613,6 +614,10 @@ class Node:
|
|||
A list of 'compatible' strings for the node, in the same order that
|
||||
they're listed in the .dts file
|
||||
|
||||
ranges:
|
||||
A list if Range objects extracted from the node's ranges property.
|
||||
The list is empty if the node does not have a range property.
|
||||
|
||||
regs:
|
||||
A list of Register objects for the node's registers
|
||||
|
||||
|
@ -1134,6 +1139,67 @@ class Node:
|
|||
f"{self.edt.dts_path}, but is not declared in "
|
||||
f"'properties:' in {self.binding_path}")
|
||||
|
||||
def _init_ranges(self):
|
||||
# Initializes self.ranges
|
||||
node = self._node
|
||||
|
||||
self.ranges = []
|
||||
|
||||
if "ranges" not in node.props:
|
||||
return
|
||||
|
||||
child_address_cells = node.props.get("#address-cells")
|
||||
parent_address_cells = _address_cells(node)
|
||||
if child_address_cells is None:
|
||||
child_address_cells = 2 # Default value per DT spec.
|
||||
else:
|
||||
child_address_cells = child_address_cells.to_num()
|
||||
child_size_cells = node.props.get("#size-cells")
|
||||
if child_size_cells is None:
|
||||
child_size_cells = 1 # Default value per DT spec.
|
||||
else:
|
||||
child_size_cells = child_size_cells.to_num()
|
||||
|
||||
# Number of cells for one translation 3-tuple in 'ranges'
|
||||
entry_cells = child_address_cells + parent_address_cells + child_size_cells
|
||||
|
||||
if entry_cells == 0:
|
||||
if len(node.props["ranges"].value) == 0:
|
||||
return
|
||||
else:
|
||||
_err(f"'ranges' should be empty in {self._node.path} since "
|
||||
f"<#address-cells> = {child_address_cells}, "
|
||||
f"<#address-cells for parent> = {parent_address_cells} and "
|
||||
f"<#size-cells> = {child_size_cells}")
|
||||
|
||||
for raw_range in _slice(node, "ranges", 4*entry_cells,
|
||||
f"4*(<#address-cells> (= {child_address_cells}) + "
|
||||
"<#address-cells for parent> "
|
||||
f"(= {parent_address_cells}) + "
|
||||
f"<#size-cells> (= {child_size_cells}))"):
|
||||
|
||||
range = Range()
|
||||
range.node = self
|
||||
range.child_bus_cells = child_address_cells
|
||||
if child_address_cells == 0:
|
||||
range.child_bus_addr = None
|
||||
else:
|
||||
range.child_bus_addr = to_num(raw_range[:4*child_address_cells])
|
||||
range.parent_bus_cells = parent_address_cells
|
||||
if parent_address_cells == 0:
|
||||
range.parent_bus_addr = None
|
||||
else:
|
||||
range.parent_bus_addr = to_num(raw_range[(4*child_address_cells):\
|
||||
(4*child_address_cells + 4*parent_address_cells)])
|
||||
range.length_cells = child_size_cells
|
||||
if child_size_cells == 0:
|
||||
range.length = None
|
||||
else:
|
||||
range.length = to_num(raw_range[(4*child_address_cells + \
|
||||
4*parent_address_cells):])
|
||||
|
||||
self.ranges.append(range)
|
||||
|
||||
def _init_regs(self):
|
||||
# Initializes self.regs
|
||||
|
||||
|
@ -1316,6 +1382,55 @@ class Node:
|
|||
return OrderedDict(zip(cell_names, data_list))
|
||||
|
||||
|
||||
class Range:
|
||||
"""
|
||||
Represents a translation range on a node as described by the 'ranges' property.
|
||||
|
||||
These attributes are available on Range objects:
|
||||
|
||||
node:
|
||||
The Node instance this range is from
|
||||
|
||||
child_bus_cells:
|
||||
Is the number of cells (4-bytes wide words) describing the child bus address.
|
||||
|
||||
child_bus_addr:
|
||||
Is a physical address within the child bus address space, or None if the
|
||||
child address-cells is equal 0.
|
||||
|
||||
parent_bus_cells:
|
||||
Is the number of cells (4-bytes wide words) describing the parent bus address.
|
||||
|
||||
parent_bus_addr:
|
||||
Is a physical address within the parent bus address space, or None if the
|
||||
parent address-cells is equal 0.
|
||||
|
||||
length_cells:
|
||||
Is the number of cells (4-bytes wide words) describing the size of range in
|
||||
the child address space.
|
||||
|
||||
length:
|
||||
Specifies the size of the range in the child address space, or None if the
|
||||
child size-cells is equal 0.
|
||||
"""
|
||||
def __repr__(self):
|
||||
fields = []
|
||||
|
||||
if self.child_bus_cells is not None:
|
||||
fields.append("child-bus-cells: " + hex(self.child_bus_cells))
|
||||
if self.child_bus_addr is not None:
|
||||
fields.append("child-bus-addr: " + hex(self.child_bus_addr))
|
||||
if self.parent_bus_cells is not None:
|
||||
fields.append("parent-bus-cells: " + hex(self.parent_bus_cells))
|
||||
if self.parent_bus_addr is not None:
|
||||
fields.append("parent-bus-addr: " + hex(self.parent_bus_addr))
|
||||
if self.length_cells is not None:
|
||||
fields.append("length-cells " + hex(self.length_cells))
|
||||
if self.length is not None:
|
||||
fields.append("length " + hex(self.length))
|
||||
|
||||
return "<Range, {}>".format(", ".join(fields))
|
||||
|
||||
class Register:
|
||||
"""
|
||||
Represents a register on a node.
|
||||
|
|
Loading…
Reference in a new issue