blob: 9959d14dab1255d70b3bf9f3a035b1d5f933b715 [file] [log] [blame]
Ulf Magnusson62d57412018-12-17 20:09:47 +01001# Copyright (c) 2019 Nordic Semiconductor ASA
2# Copyright (c) 2019 Linaro Limited
3# SPDX-License-Identifier: BSD-3-Clause
4
5# Tip: You can view just the documentation with 'pydoc3 edtlib'
6
7"""
8Library for working with .dts files and bindings at a higher level compared to
9dtlib. Deals with things at the level of devices, registers, interrupts,
10compatibles, bindings, etc., as opposed to dtlib, which is just a low-level
11device tree parser.
12
13Each device tree node (dtlib.Node) gets a Device instance, which has all the
14information related to the device, derived from both the device tree and from
15the binding for the device.
16
17Bindings are files that describe device tree nodes. Device tree nodes are
18usually mapped to bindings via their 'compatible = "..."' property, but binding
19data can also come from a 'sub-node:' key in the binding for the parent device
20tree node.
21
22The top-level entry point of the library is the EDT class. EDT.__init__() takes
23a .dts file to parse and the path of a directory containing bindings.
24"""
25
26import os
27import re
28import sys
29
30import yaml
31
Ulf Magnussonc42873f2019-08-13 11:52:10 +020032from dtlib import DT, DTError, to_num, to_nums, TYPE_EMPTY, TYPE_PHANDLE, \
33 TYPE_PHANDLES_AND_NUMS
Ulf Magnusson62d57412018-12-17 20:09:47 +010034
35# NOTE: testedtlib.py is the test suite for this library. It can be run
36# directly.
37
38# Implementation notes
39# --------------------
40#
41# A '_' prefix on an identifier in Python is a convention for marking it private.
42# Please do not access private things. Instead, think of what API you need, and
43# add it.
44#
45# This library is layered on top of dtlib, and is not meant to expose it to
46# clients. This keeps the header generation script simple.
47#
48# General biased advice:
49#
50# - Consider using @property for APIs that don't need parameters. It makes
51# functions look like attributes, which is less awkward in clients, and makes
52# it easy to switch back and forth between variables and functions.
53#
54# - Think about the data type of the thing you're exposing. Exposing something
55# as e.g. a list or a dictionary is often nicer and more flexible than adding
56# a function.
57#
58# - Avoid get_*() prefixes on functions. Name them after the thing they return
59# instead. This often makes the code read more naturally in callers.
60#
61# Also, consider using @property instead of get_*().
62#
63# - Don't expose dtlib stuff directly.
64#
65# - Add documentation for any new APIs you add.
66#
67# The convention here is that docstrings (quoted strings) are used for public
68# APIs, and "doc comments" for internal functions.
69#
70# @properties are documented in the class docstring, as if they were
71# variables. See the existing @properties for a template.
72#
73# - Please use ""-quoted strings instead of ''-quoted strings, just to make
74# things consistent (''-quoting is more common otherwise in Python)
75
76#
77# Public classes
78#
79
80
81class EDT:
82 """
83 Represents a "high-level" view of a device tree, with a list of devices
84 that each have some number of registers, etc.
85
86 These attributes are available on EDT objects:
87
88 devices:
89 A list of Device objects for the devices
90
91 dts_path:
92 The .dts path passed to __init__()
93
Michael Scottb8909432019-08-02 11:42:06 -070094 bindings_dirs:
95 The bindings directory paths passed to __init__()
Ulf Magnusson62d57412018-12-17 20:09:47 +010096 """
Michael Scottb8909432019-08-02 11:42:06 -070097 def __init__(self, dts, bindings_dirs):
Ulf Magnusson62d57412018-12-17 20:09:47 +010098 """
99 EDT constructor. This is the top-level entry point to the library.
100
101 dts:
102 Path to device tree .dts file
103
Michael Scottb8909432019-08-02 11:42:06 -0700104 bindings_dirs:
105 List of paths to directories containing bindings, in YAML format.
106 These directories are recursively searched for .yaml files.
Ulf Magnusson62d57412018-12-17 20:09:47 +0100107 """
108 self.dts_path = dts
Michael Scottb8909432019-08-02 11:42:06 -0700109 self.bindings_dirs = bindings_dirs
Ulf Magnusson62d57412018-12-17 20:09:47 +0100110
111 self._dt = DT(dts)
Ulf Magnussonacf276f2019-08-07 19:33:45 +0200112 _check_dt(self._dt)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100113
Michael Scottb8909432019-08-02 11:42:06 -0700114 self._init_compat2binding(bindings_dirs)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100115 self._init_devices()
116
117 def get_dev(self, path):
118 """
119 Returns the Device at the DT path or alias 'path'. Raises EDTError if
120 the path or alias doesn't exist.
121 """
122 try:
123 return self._node2dev[self._dt.get_node(path)]
124 except DTError as e:
125 _err(e)
126
127 def chosen_dev(self, name):
128 """
129 Returns the Device pointed at by the property named 'name' in /chosen,
130 or None if the property is missing
131 """
132 try:
133 chosen = self._dt.get_node("/chosen")
134 except DTError:
135 # No /chosen node
136 return None
137
138 if name not in chosen.props:
139 return None
140
Ulf Magnusson06b746c2019-08-09 20:38:17 +0200141 # to_path() checks that the node exists
142 return self._node2dev[chosen.props[name].to_path()]
Ulf Magnusson62d57412018-12-17 20:09:47 +0100143
Michael Scottb8909432019-08-02 11:42:06 -0700144 def _init_compat2binding(self, bindings_dirs):
Ulf Magnusson62d57412018-12-17 20:09:47 +0100145 # Creates self._compat2binding. This is a dictionary that maps
146 # (<compatible>, <bus>) tuples (both strings) to (<binding>, <path>)
147 # tuples. <binding> is the binding in parsed PyYAML format, and <path>
148 # the path to the binding (nice for binding-related error messages).
149 #
150 # For example, self._compat2binding["company,dev", "can"] contains the
151 # binding/path for the 'company,dev' device, when it appears on the CAN
152 # bus.
153 #
154 # For bindings that don't specify a bus, <bus> is None, so that e.g.
155 # self._compat2binding["company,notonbus", None] contains the binding.
156 #
157 # Only bindings for 'compatible' strings that appear in the device tree
158 # are loaded.
159
160 dt_compats = _dt_compats(self._dt)
Michael Scottb8909432019-08-02 11:42:06 -0700161 self._binding_paths = _binding_paths(bindings_dirs)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100162
163 # Add '!include foo.yaml' handling.
164 #
165 # Do yaml.Loader.add_constructor() instead of yaml.add_constructor() to be
166 # compatible with both version 3.13 and version 5.1 of PyYAML.
167 #
168 # TODO: Is there some 3.13/5.1-compatible way to only do this once, even
169 # if multiple EDT objects are created?
170 yaml.Loader.add_constructor("!include", self._binding_include)
171
172 self._compat2binding = {}
173 for binding_path in self._binding_paths:
174 compat = _binding_compat(binding_path)
175 if compat in dt_compats:
176 binding = _load_binding(binding_path)
177 self._compat2binding[compat, _binding_bus(binding)] = \
178 (binding, binding_path)
179
180 def _binding_include(self, loader, node):
181 # Implements !include. Returns a list with the YAML structures for the
182 # included files (a single-element list if the !include is for a single
183 # file).
184
185 if isinstance(node, yaml.ScalarNode):
186 # !include foo.yaml
187 return [self._binding_include_file(loader.construct_scalar(node))]
188
189 if isinstance(node, yaml.SequenceNode):
190 # !include [foo.yaml, bar.yaml]
191 return [self._binding_include_file(filename)
192 for filename in loader.construct_sequence(node)]
193
194 _binding_inc_error("unrecognised node type in !include statement")
195
196 def _binding_include_file(self, filename):
197 # _binding_include() helper for loading an !include'd file. !include
198 # takes just the basename of the file, so we need to make sure there
199 # aren't multiple candidates.
200
201 paths = [path for path in self._binding_paths
202 if os.path.basename(path) == filename]
203
204 if not paths:
205 _binding_inc_error("'{}' not found".format(filename))
206
207 if len(paths) > 1:
208 _binding_inc_error("multiple candidates for '{}' in !include: {}"
209 .format(filename, ", ".join(paths)))
210
211 with open(paths[0], encoding="utf-8") as f:
212 return yaml.load(f, Loader=yaml.Loader)
213
214 def _init_devices(self):
215 # Creates a list of devices (Device objects) from the DT nodes, in
Ulf Magnusson71681182019-08-12 14:57:31 +0200216 # self.devices
Ulf Magnusson62d57412018-12-17 20:09:47 +0100217
218 # Maps dtlib.Node's to their corresponding Devices
219 self._node2dev = {}
220
221 self.devices = []
222
223 for node in self._dt.node_iter():
Ulf Magnusson06b746c2019-08-09 20:38:17 +0200224 # Warning: We depend on parent Devices being created before their
225 # children. This is guaranteed by node_iter().
226 dev = Device()
227 dev.edt = self
228 dev._node = node
229 dev._init_binding()
230 dev._init_regs()
231 dev._set_instance_no()
232
Ulf Magnusson62d57412018-12-17 20:09:47 +0100233 self.devices.append(dev)
234 self._node2dev[node] = dev
235
236 for dev in self.devices:
Ulf Magnusson06b746c2019-08-09 20:38:17 +0200237 # Device._init_props() depends on all Device objects having been
238 # created, due to 'type: phandle', so we run it separately.
239 # Property.val is set to the pointed-to Device instance for
240 # phandles, which must exist.
241 dev._init_props()
242
243 for dev in self.devices:
244 # These also depend on all Device objects having been created, and
245 # might also depend on all Device.props having been initialized
246 # (_init_clocks() does as of writing).
Ulf Magnusson62d57412018-12-17 20:09:47 +0100247 dev._init_interrupts()
248 dev._init_gpios()
249 dev._init_pwms()
Jim Paris67f53ba2019-08-07 15:05:23 -0400250 dev._init_iochannels()
Ulf Magnusson62d57412018-12-17 20:09:47 +0100251 dev._init_clocks()
252
253 def __repr__(self):
Michael Scottb8909432019-08-02 11:42:06 -0700254 return "<EDT for '{}', binding directories '{}'>".format(
255 self.dts_path, self.bindings_dirs)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100256
257
258class Device:
259 """
260 Represents a device. There's a one-to-one correspondence between device
261 tree nodes and Devices.
262
263 These attributes are available on Device objects:
264
265 edt:
266 The EDT instance this device is from
267
268 name:
269 The name of the device. This is fetched from the node name.
270
271 unit_addr:
272 An integer with the ...@<unit-address> portion of the node name,
273 translated through any 'ranges' properties on parent nodes, or None if
274 the node name has no unit-address portion
275
276 path:
277 The device tree path of the device
278
279 label:
280 The text from the 'label' property on the DT node of the Device, or None
281 if the node has no 'label'
282
283 parent:
284 The parent Device, or None if there is no parent
285
286 enabled:
287 True unless the device's node has 'status = "disabled"'
288
289 read_only:
290 True if the DT node of the Device has a 'read-only' property, and False
291 otherwise
292
293 instance_no:
294 Dictionary that maps each 'compatible' string for the device to a unique
295 index among all devices that have that 'compatible' string.
296
297 As an example, 'instance_no["foo,led"] == 3' can be read as "this is the
298 fourth foo,led device".
299
300 Only enabled devices (status != "disabled") are counted. 'instance_no' is
301 meaningless for disabled devices.
302
303 matching_compat:
304 The 'compatible' string for the binding that matched the device, or
305 None if the device has no binding
306
307 description:
308 The description string from the binding file for the device, or None if
309 the device has no binding. Trailing whitespace (including newlines) is
310 removed.
311
312 binding_path:
313 The path to the binding file for the device, or None if the device has no
314 binding
315
316 compats:
317 A list of 'compatible' strings for the device, in the same order that
318 they're listed in the .dts file
319
320 regs:
321 A list of Register objects for the device's registers
322
323 props:
324 A dictionary that maps property names to Property objects. Property
325 objects are created for all DT properties on the device that are
326 mentioned in 'properties:' in the binding.
327
328 aliases:
329 A list of aliases for the device. This is fetched from the /aliases node.
330
331 interrupts:
332 A list of Interrupt objects for the interrupts generated by the device
333
334 gpios:
335 A dictionary that maps the <prefix> part in '<prefix>-gpios' properties
336 to a list of GPIO objects (see the GPIO class).
337
338 For example, 'foo-gpios = <&gpio1 1 2 &gpio2 3 4>' makes gpios["foo"] a
339 list of two GPIO objects.
340
341 pwms:
342 A list of PWM objects, derived from the 'pwms' property. The list is
343 empty if the device has no 'pwms' property.
344
Jim Paris67f53ba2019-08-07 15:05:23 -0400345 iochannels:
346 A list of IOChannel objects, derived from the 'io-channels'
347 property. The list is empty if the device has no 'io-channels'
348 property.
349
Ulf Magnusson62d57412018-12-17 20:09:47 +0100350 clocks:
351 A list of Clock objects, derived from the 'clocks' property. The list is
352 empty if the device has no 'clocks' property.
353
354 bus:
355 The bus for the device as specified in its binding, e.g. "i2c" or "spi".
356 None if the binding doesn't specify a bus.
357
358 flash_controller:
359 The flash controller for the device. Only meaningful for devices
360 representing flash partitions.
361 """
362 @property
363 def name(self):
364 "See the class docstring"
365 return self._node.name
366
367 @property
368 def unit_addr(self):
369 "See the class docstring"
370
371 # TODO: Return a plain string here later, like dtlib.Node.unit_addr?
372
373 if "@" not in self.name:
374 return None
375
376 try:
377 addr = int(self.name.split("@", 1)[1], 16)
378 except ValueError:
379 _err("{!r} has non-hex unit address".format(self))
380
381 addr = _translate(addr, self._node)
382
383 if self.regs and self.regs[0].addr != addr:
384 _warn("unit-address and first reg (0x{:x}) don't match for {}"
385 .format(self.regs[0].addr, self.name))
386
387 return addr
388
389 @property
390 def path(self):
391 "See the class docstring"
392 return self._node.path
393
394 @property
395 def label(self):
396 "See the class docstring"
397 if "label" in self._node.props:
398 return self._node.props["label"].to_string()
399 return None
400
401 @property
402 def parent(self):
403 "See the class docstring"
404 return self.edt._node2dev.get(self._node.parent)
405
406 @property
407 def enabled(self):
408 "See the class docstring"
409 return "status" not in self._node.props or \
410 self._node.props["status"].to_string() != "disabled"
411
412 @property
413 def read_only(self):
414 "See the class docstring"
415 return "read-only" in self._node.props
416
417 @property
418 def aliases(self):
419 "See the class docstring"
420 return [alias for alias, node in self._node.dt.alias2node.items()
421 if node is self._node]
422
423 @property
424 def bus(self):
425 "See the class docstring"
426 return _binding_bus(self._binding)
427
428 @property
429 def flash_controller(self):
430 "See the class docstring"
431
432 # The node path might be something like
433 # /flash-controller@4001E000/flash@0/partitions/partition@fc000. We go
434 # up two levels to get the flash and check its compat. The flash
435 # controller might be the flash itself (for cases like NOR flashes).
436 # For the case of 'soc-nv-flash', we assume the controller is the
437 # parent of the flash node.
438
439 if not self.parent or not self.parent.parent:
440 _err("flash partition {!r} lacks parent or grandparent node"
441 .format(self))
442
443 controller = self.parent.parent
444 if controller.matching_compat == "soc-nv-flash":
445 return controller.parent
446 return controller
447
448 def __repr__(self):
449 return "<Device {} in '{}', {}>".format(
450 self.path, self.edt.dts_path,
451 "binding " + self.binding_path if self.binding_path
452 else "no binding")
453
Ulf Magnusson62d57412018-12-17 20:09:47 +0100454 def _init_binding(self):
455 # Initializes Device.matching_compat, Device._binding, and
456 # Device.binding_path.
457 #
458 # Device._binding holds the data from the device's binding file, in the
459 # format returned by PyYAML (plain Python lists, dicts, etc.), or None
460 # if the device has no binding.
461
462 # This relies on the parent of the Device having already been
463 # initialized, which is guaranteed by going through the nodes in
464 # node_iter() order.
465
466 if "compatible" in self._node.props:
467 self.compats = self._node.props["compatible"].to_strings()
468 bus = self._bus_from_parent_binding()
469
470 for compat in self.compats:
471 if (compat, bus) in self.edt._compat2binding:
472 # Binding found
473 self.matching_compat = compat
474 self._binding, self.binding_path = \
475 self.edt._compat2binding[compat, bus]
476
477 self.description = self._binding.get("description")
478 if self.description:
479 self.description = self.description.rstrip()
480
481 return
482 else:
483 # No 'compatible' property. See if the parent has a 'sub-node:' key
484 # that gives the binding.
485
486 self.compats = []
487
488 if self.parent and self.parent._binding and \
489 "sub-node" in self.parent._binding:
490
491 # Binding found
492 self._binding = self.parent._binding["sub-node"]
493 self.binding_path = self.parent.binding_path
494
495 self.description = self.parent._binding.get("description")
496 if self.description:
497 self.description = self.description.rstrip()
498
499 self.matching_compat = self.parent.matching_compat
500 return
501
502 # No binding found
503 self.matching_compat = self._binding = self.binding_path = \
504 self.description = None
505
506 def _bus_from_parent_binding(self):
507 # _init_binding() helper. Returns the bus specified by
508 # 'child: bus: ...' in the parent binding, or None if missing.
509
510 if not self.parent:
511 return None
512
513 binding = self.parent._binding
514 if binding and "child" in binding:
515 return binding["child"].get("bus")
516 return None
517
518 def _init_props(self):
519 # Creates self.props. See the class docstring.
520
521 self.props = {}
522
523 if not self._binding or "properties" not in self._binding:
524 return
525
526 for name, options in self._binding["properties"].items():
527 self._init_prop(name, options)
528
529 def _init_prop(self, name, options):
530 # _init_props() helper for initializing a single property
531
Ulf Magnusson62d57412018-12-17 20:09:47 +0100532 prop_type = options.get("type")
533 if not prop_type:
534 _err("'{}' in {} lacks 'type'".format(name, self.binding_path))
535
Ulf Magnusson62d57412018-12-17 20:09:47 +0100536 val = self._prop_val(name, prop_type,
537 options.get("category") == "optional")
538 if val is None:
Ulf Magnussonc42873f2019-08-13 11:52:10 +0200539 # 'category: optional' property that wasn't there, or a property
540 # type for which we store no data.
Ulf Magnusson62d57412018-12-17 20:09:47 +0100541 return
542
Kumar Gala62bf2672019-08-09 14:51:58 -0500543 enum = options.get("enum")
544 if enum and val not in enum:
545 _err("value of property '{}' on {} in {} ({!r}) is not in 'enum' "
546 "list in {} ({!r})"
547 .format(name, self.path, self.edt.dts_path, val,
548 self.binding_path, enum))
549
Kumar Gala3d143742019-08-09 16:03:46 -0500550 const = options.get("const")
551 if const is not None and val != const:
552 _err("value of property '{}' on {} in {} ({!r}) is different from "
553 "the 'const' value specified in {} ({!r})"
554 .format(name, self.path, self.edt.dts_path, val,
555 self.binding_path, const))
556
Kumar Gala5dd715b2019-08-09 09:49:22 -0500557 # Skip properties that start with '#', like '#size-cells', and mapping
558 # properties like 'gpio-map'/'interrupt-map'
559 if name[0] == "#" or name.endswith("-map"):
560 return
561
Ulf Magnusson62d57412018-12-17 20:09:47 +0100562 prop = Property()
563 prop.dev = self
564 prop.name = name
565 prop.description = options.get("description")
566 if prop.description:
567 prop.description = prop.description.rstrip()
568 prop.val = val
Kumar Gala62bf2672019-08-09 14:51:58 -0500569 prop.enum_index = None if enum is None else enum.index(val)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100570
571 self.props[name] = prop
572
573 def _prop_val(self, name, prop_type, optional):
574 # _init_prop() helper for getting the property's value
575
576 node = self._node
Ulf Magnusson06b746c2019-08-09 20:38:17 +0200577 prop = node.props.get(name)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100578
579 if prop_type == "boolean":
Ulf Magnusson06b746c2019-08-09 20:38:17 +0200580 if not prop:
581 return False
582 if prop.type is not TYPE_EMPTY:
583 _err("'{0}' in {1!r} is defined with 'type: boolean' in {2}, "
584 "but is assigned a value ('{3}') instead of being empty "
585 "('{0};')".format(name, node, self.binding_path, prop))
586 return True
Ulf Magnusson62d57412018-12-17 20:09:47 +0100587
Ulf Magnusson62d57412018-12-17 20:09:47 +0100588 if not prop:
Ulf Magnussonf7f0e0a2019-08-08 21:32:57 +0200589 if not optional and self.enabled:
Ulf Magnusson62d57412018-12-17 20:09:47 +0100590 _err("'{}' is marked as required in 'properties:' in {}, but "
591 "does not appear in {!r}".format(
592 name, self.binding_path, node))
593
594 return None
595
596 if prop_type == "int":
597 return prop.to_num()
598
599 if prop_type == "array":
600 return prop.to_nums()
601
602 if prop_type == "uint8-array":
Ulf Magnusson06b746c2019-08-09 20:38:17 +0200603 return prop.to_bytes()
Ulf Magnusson62d57412018-12-17 20:09:47 +0100604
605 if prop_type == "string":
606 return prop.to_string()
607
608 if prop_type == "string-array":
609 return prop.to_strings()
610
Ulf Magnusson06b746c2019-08-09 20:38:17 +0200611 if prop_type == "phandle":
612 return self.edt._node2dev[prop.to_node()]
613
Ulf Magnussonc42873f2019-08-13 11:52:10 +0200614 if prop_type == "phandles":
615 return [self.edt._node2dev[node] for node in prop.to_nodes()]
616
617 if prop_type == "phandle-array":
618 # This property type only does a type check. No Property object is
619 # created for it.
620 if prop.type not in (TYPE_PHANDLE, TYPE_PHANDLES_AND_NUMS):
621 _err("expected property '{0}' in {1} in {2} to be assigned "
622 "with '{0} = < &foo 1 2 ... &bar 3 4 ... >' (a mix of "
623 "phandles and numbers), not '{3}'"
624 .format(name, node.path, node.dt.filename, prop))
625 return None
626
627 if prop_type == "compound":
628 # Dummy type for properties like that don't fit any of the patterns
629 # above, so that we can require all entries in 'properties:' to
630 # have a 'type: ...'. No Property object is created for it.
631 return None
632
Ulf Magnusson62d57412018-12-17 20:09:47 +0100633 _err("'{}' in 'properties:' in {} has unknown type '{}'"
634 .format(name, self.binding_path, prop_type))
635
636 def _init_regs(self):
Ulf Magnusson95deec12019-08-06 21:51:06 +0200637 # Initializes self.regs
Ulf Magnusson62d57412018-12-17 20:09:47 +0100638
639 node = self._node
640
641 self.regs = []
642
643 if "reg" not in node.props:
644 return
645
646 address_cells = _address_cells(node)
647 size_cells = _size_cells(node)
648
649 for raw_reg in _slice(node, "reg", 4*(address_cells + size_cells)):
650 reg = Register()
651 reg.dev = self
652 reg.addr = _translate(to_num(raw_reg[:4*address_cells]), node)
653 reg.size = to_num(raw_reg[4*address_cells:])
654 if size_cells != 0 and reg.size == 0:
655 _err("zero-sized 'reg' in {!r} seems meaningless (maybe you "
656 "want a size of one or #size-cells = 0 instead)"
657 .format(self._node))
658
659 self.regs.append(reg)
660
Ulf Magnusson95deec12019-08-06 21:51:06 +0200661 _add_names(node, "reg", self.regs)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100662
663 def _init_interrupts(self):
Ulf Magnusson95deec12019-08-06 21:51:06 +0200664 # Initializes self.interrupts
Ulf Magnusson62d57412018-12-17 20:09:47 +0100665
666 node = self._node
667
668 self.interrupts = []
669
670 for controller_node, spec in _interrupts(node):
Ulf Magnusson62d57412018-12-17 20:09:47 +0100671 interrupt = Interrupt()
672 interrupt.dev = self
Ulf Magnusson4985c212019-08-08 21:50:07 +0200673 interrupt.controller = self.edt._node2dev[controller_node]
674 interrupt.specifier = self._named_cells(interrupt.controller, spec,
675 "interrupt")
Ulf Magnusson62d57412018-12-17 20:09:47 +0100676
677 self.interrupts.append(interrupt)
678
Ulf Magnusson95deec12019-08-06 21:51:06 +0200679 _add_names(node, "interrupt", self.interrupts)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100680
681 def _init_gpios(self):
682 # Initializes self.gpios
683
684 self.gpios = {}
685
686 for prefix, gpios in _gpios(self._node).items():
687 self.gpios[prefix] = []
688 for controller_node, spec in gpios:
Ulf Magnusson62d57412018-12-17 20:09:47 +0100689 gpio = GPIO()
690 gpio.dev = self
Ulf Magnusson4985c212019-08-08 21:50:07 +0200691 gpio.controller = self.edt._node2dev[controller_node]
692 gpio.specifier = self._named_cells(gpio.controller, spec,
693 "GPIO")
Ulf Magnusson62d57412018-12-17 20:09:47 +0100694 gpio.name = prefix
695
696 self.gpios[prefix].append(gpio)
697
698 def _init_clocks(self):
699 # Initializes self.clocks
700
Ulf Magnusson95deec12019-08-06 21:51:06 +0200701 self.clocks = self._simple_phandle_val_list("clock", Clock)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100702
Ulf Magnusson95deec12019-08-06 21:51:06 +0200703 # Initialize Clock.frequency
704 for clock in self.clocks:
705 controller = clock.controller
Ulf Magnusson62d57412018-12-17 20:09:47 +0100706 if "fixed-clock" in controller.compats:
707 if "clock-frequency" not in controller.props:
708 _err("{!r} is a 'fixed-clock', but either lacks a "
709 "'clock-frequency' property or does not have "
710 "it specified in its binding".format(controller))
711
712 clock.frequency = controller.props["clock-frequency"].val
713 else:
714 clock.frequency = None
715
Ulf Magnusson62d57412018-12-17 20:09:47 +0100716 def _init_pwms(self):
717 # Initializes self.pwms
718
Ulf Magnusson95deec12019-08-06 21:51:06 +0200719 self.pwms = self._simple_phandle_val_list("pwm", PWM)
Ulf Magnusson62d57412018-12-17 20:09:47 +0100720
Jim Paris67f53ba2019-08-07 15:05:23 -0400721 def _init_iochannels(self):
722 # Initializes self.iochannels
723
724 self.iochannels = self._simple_phandle_val_list("io-channel", IOChannel)
725
Ulf Magnusson95deec12019-08-06 21:51:06 +0200726 def _simple_phandle_val_list(self, name, cls):
727 # Helper for parsing properties like
728 #
729 # <name>s = <phandle value phandle value ...>
730 # (e.g., gpios = <&foo 1 2 &bar 3 4>)
731 #
732 # , where each phandle points to a node that has a
733 #
734 # #<name>-cells = <size>
735 #
736 # property that gives the number of cells in the value after the
737 # phandle. Also parses any
738 #
739 # <name>-names = "...", "...", ...
740 #
741 # Arguments:
742 #
743 # name:
744 # The <name>, e.g. "clock" or "pwm". Note: no -s in the argument.
745 #
746 # cls:
747 # A class object. Instances of this class will be created and the
748 # 'dev', 'controller', 'specifier', and 'name' fields initialized.
749 # See the documentation for e.g. the PWM class.
750 #
751 # Returns a list of 'cls' instances.
Ulf Magnusson62d57412018-12-17 20:09:47 +0100752
Ulf Magnusson95deec12019-08-06 21:51:06 +0200753 prop = self._node.props.get(name + "s")
754 if not prop:
755 return []
Ulf Magnusson62d57412018-12-17 20:09:47 +0100756
Ulf Magnusson95deec12019-08-06 21:51:06 +0200757 res = []
Ulf Magnusson62d57412018-12-17 20:09:47 +0100758
Ulf Magnusson95deec12019-08-06 21:51:06 +0200759 for controller_node, spec in _phandle_val_list(prop, name):
760 obj = cls()
761 obj.dev = self
762 obj.controller = self.edt._node2dev[controller_node]
763 obj.specifier = self._named_cells(obj.controller, spec, name)
764
765 res.append(obj)
766
767 _add_names(self._node, name, res)
768
769 return res
Ulf Magnusson62d57412018-12-17 20:09:47 +0100770
771 def _named_cells(self, controller, spec, controller_s):
772 # _init_{interrupts,gpios}() helper. Returns a dictionary that maps
773 # #cell names given in the binding for 'controller' to cell values.
774 # 'spec' is the raw interrupt/GPIO data, and 'controller_s' a string
775 # that gives the context (for error messages).
776
777 if not controller._binding:
778 _err("{} controller {!r} for {!r} lacks binding"
779 .format(controller_s, controller._node, self._node))
780
781 if "#cells" in controller._binding:
782 cell_names = controller._binding["#cells"]
783 if not isinstance(cell_names, list):
784 _err("binding for {} controller {!r} has malformed #cells array"
785 .format(controller_s, controller._node))
786 else:
787 # Treat no #cells in the binding the same as an empty #cells, so
788 # that bindings don't have to have an empty #cells for e.g.
789 # '#clock-cells = <0>'.
790 cell_names = []
791
792 spec_list = to_nums(spec)
793 if len(spec_list) != len(cell_names):
794 _err("unexpected #cells length in binding for {!r} - {} instead "
795 "of {}".format(controller._node, len(cell_names),
796 len(spec_list)))
797
798 return dict(zip(cell_names, spec_list))
799
800 def _set_instance_no(self):
801 # Initializes self.instance_no
802
803 self.instance_no = {}
804
805 for compat in self.compats:
806 self.instance_no[compat] = 0
807 for other_dev in self.edt.devices:
808 if compat in other_dev.compats and other_dev.enabled:
809 self.instance_no[compat] += 1
810
811
812class Register:
813 """
814 Represents a register on a device.
815
816 These attributes are available on Register objects:
817
818 dev:
819 The Device instance this register is from
820
821 name:
822 The name of the register as given in the 'reg-names' property, or None if
823 there is no 'reg-names' property
824
825 addr:
826 The starting address of the register, in the parent address space. Any
827 'ranges' properties are taken into account.
828
829 size:
830 The length of the register in bytes
831 """
832 def __repr__(self):
833 fields = []
834
835 if self.name is not None:
836 fields.append("name: " + self.name)
837 fields.append("addr: " + hex(self.addr))
838 fields.append("size: " + hex(self.size))
839
840 return "<Register, {}>".format(", ".join(fields))
841
842
843class Interrupt:
844 """
845 Represents an interrupt generated by a device.
846
847 These attributes are available on Interrupt objects:
848
849 dev:
850 The Device instance that generated the interrupt
851
852 name:
853 The name of the interrupt as given in the 'interrupt-names' property, or
854 None if there is no 'interrupt-names' property
855
856 controller:
857 The Device instance for the controller the interrupt gets sent to. Any
858 'interrupt-map' is taken into account, so that this is the final
859 controller node.
860
861 specifier:
862 A dictionary that maps names from the #cells portion of the binding to
863 cell values in the interrupt specifier. 'interrupts = <1 2>' might give
864 {"irq": 1, "level": 2}, for example.
865 """
866 def __repr__(self):
867 fields = []
868
869 if self.name is not None:
870 fields.append("name: " + self.name)
871
872 fields.append("target: {}".format(self.controller))
873 fields.append("specifier: {}".format(self.specifier))
874
875 return "<Interrupt, {}>".format(", ".join(fields))
876
877
878class GPIO:
879 """
880 Represents a GPIO used by a device.
881
882 These attributes are available on GPIO objects:
883
884 dev:
885 The Device instance that uses the GPIO
886
887 name:
888 The name of the gpio as extracted out of the "<NAME>-gpios" property. If
889 the property is just "gpios" than there is no name.
890
891 controller:
892 The Device instance for the controller of the GPIO
893
894 specifier:
895 A dictionary that maps names from the #cells portion of the binding to
896 cell values in the gpio specifier. 'foo-gpios = <&gpioc 5 0>' might give
897 {"pin": 5, "flags": 0}, for example.
898 """
899 def __repr__(self):
900 fields = []
901
902 if self.name is not None:
903 fields.append("name: " + self.name)
904
905 fields.append("target: {}".format(self.controller))
906 fields.append("specifier: {}".format(self.specifier))
907
908 return "<GPIO, {}>".format(", ".join(fields))
909
910
911class Clock:
912 """
913 Represents a clock used by a device.
914
915 These attributes are available on Clock objects:
916
917 dev:
918 The Device instance that uses the clock
919
920 name:
921 The name of the clock as given in the 'clock-names' property, or
922 None if there is no 'clock-names' property
923
924 controller:
925 The Device instance for the controller of the clock.
926
927 frequency:
928 The frequency of the clock for fixed clocks ('fixed-clock' in
929 'compatible'), as an integer. Derived from the 'clock-frequency'
930 property. None if the clock is not a fixed clock.
931
932 specifier:
933 A dictionary that maps names from the #cells portion of the binding to
934 cell values in the clock specifier
935 """
936 def __repr__(self):
937 fields = []
938
939 if self.name is not None:
940 fields.append("name: " + self.name)
941
942 if self.frequency is not None:
943 fields.append("frequency: {}".format(self.frequency))
944
945 fields.append("target: {}".format(self.controller))
946 fields.append("specifier: {}".format(self.specifier))
947
948 return "<Clock, {}>".format(", ".join(fields))
949
950
951class PWM:
952 """
953 Represents a PWM used by a device.
954
955 These attributes are available on PWM objects:
956
957 dev:
958 The Device instance that uses the PWM
959
960 name:
961 The name of the pwm as given in the 'pwm-names' property, or the
962 node name if the 'pwm-names' property doesn't exist.
963
964 controller:
965 The Device instance for the controller of the PWM
966
967 specifier:
968 A dictionary that maps names from the #cells portion of the binding to
969 cell values in the pwm specifier. 'pwms = <&pwm 0 5000000>' might give
970 {"channel": 0, "period": 5000000}, for example.
971 """
972 def __repr__(self):
973 fields = []
974
975 if self.name is not None:
976 fields.append("name: " + self.name)
977
978 fields.append("target: {}".format(self.controller))
979 fields.append("specifier: {}".format(self.specifier))
980
981 return "<PWM, {}>".format(", ".join(fields))
982
983
Jim Paris67f53ba2019-08-07 15:05:23 -0400984class IOChannel:
985 """
986 Represents an IO channel used by a device, similar to the property used
987 by the Linux IIO bindings and described at:
988 https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/iio-bindings.txt
989
990 These attributes are available on IO channel objects:
991
992 dev:
993 The Device instance that uses the IO channel
994
995 name:
996 The name of the IO channel as given in the 'io-channel-names' property,
997 or the node name if the 'io-channel-names' property doesn't exist.
998
999 controller:
1000 The Device instance for the controller of the IO channel
1001
1002 specifier:
1003 A dictionary that maps names from the #cells portion of the binding to
1004 cell values in the io-channel specifier. 'io-channels = <&adc 3>' might
1005 give {"input": 3}, for example.
1006 """
1007 def __repr__(self):
1008 fields = []
1009
1010 if self.name is not None:
1011 fields.append("name: " + self.name)
1012
1013 fields.append("target: {}".format(self.controller))
1014 fields.append("specifier: {}".format(self.specifier))
1015
1016 return "<IOChannel, {}>".format(", ".join(fields))
1017
1018
Ulf Magnusson62d57412018-12-17 20:09:47 +01001019class Property:
1020 """
1021 Represents a property on a Device, as set in its DT node and with
1022 additional info from the 'properties:' section of the binding.
1023
Ulf Magnussonc42873f2019-08-13 11:52:10 +02001024 Only properties mentioned in 'properties:' get created. Properties with
1025 type 'phandle-array' or type 'compound' do not get Property instance. These
1026 types only exist for type checking.
Ulf Magnusson62d57412018-12-17 20:09:47 +01001027
1028 These attributes are available on Property objects:
1029
1030 dev:
1031 The Device instance the property is on
1032
1033 name:
1034 The name of the property
1035
1036 description:
1037 The description string from the property as given in the binding, or None
1038 if missing. Trailing whitespace (including newlines) is removed.
1039
1040 val:
Ulf Magnusson06b746c2019-08-09 20:38:17 +02001041 The value of the property, with the format determined by the 'type:' key
Ulf Magnussonc42873f2019-08-13 11:52:10 +02001042 from the binding.
1043
1044 For 'type: phandle' properties, this is the pointed-to Device instance.
1045
1046 For 'type: phandles' properties, this is a list of the pointed-to Device
1047 instances.
Ulf Magnusson62d57412018-12-17 20:09:47 +01001048
1049 enum_index:
1050 The index of the property's value in the 'enum:' list in the binding, or
1051 None if the binding has no 'enum:'
1052 """
1053 def __repr__(self):
1054 fields = ["name: " + self.name,
1055 # repr() to deal with lists
1056 "value: " + repr(self.val)]
1057
1058 if self.enum_index is not None:
1059 fields.append("enum index: {}".format(self.enum_index))
1060
1061 return "<Property, {}>".format(", ".join(fields))
1062
1063
1064class EDTError(Exception):
1065 "Exception raised for Extended Device Tree-related errors"
1066
1067
1068#
1069# Public global functions
1070#
1071
1072
1073def spi_dev_cs_gpio(dev):
1074 # Returns an SPI device's GPIO chip select if it exists, as a GPIO
1075 # instance, and None otherwise. See
1076 # Documentation/devicetree/bindings/spi/spi-bus.txt in the Linux kernel.
1077
1078 if dev.bus == "spi" and dev.parent:
1079 parent_cs = dev.parent.gpios.get("cs")
1080 if parent_cs:
1081 # cs-gpios is indexed by the unit address
1082 cs_index = dev.regs[0].addr
1083 if cs_index >= len(parent_cs):
1084 _err("index from 'regs' in {!r} ({}) is >= number of cs-gpios "
1085 "in {!r} ({})".format(
1086 dev, cs_index, dev.parent, len(parent_cs)))
1087
1088 return parent_cs[cs_index]
1089
1090 return None
1091
1092
1093#
1094# Private global functions
1095#
1096
1097
1098def _dt_compats(dt):
1099 # Returns a set() with all 'compatible' strings in the device tree
1100 # represented by dt (a dtlib.DT instance)
1101
1102 return {compat
1103 for node in dt.node_iter()
1104 if "compatible" in node.props
1105 for compat in node.props["compatible"].to_strings()}
1106
1107
Michael Scottb8909432019-08-02 11:42:06 -07001108def _binding_paths(bindings_dirs):
Ulf Magnusson62d57412018-12-17 20:09:47 +01001109 # Returns a list with the paths to all bindings (.yaml files) in
Michael Scottb8909432019-08-02 11:42:06 -07001110 # 'bindings_dirs'
Ulf Magnusson62d57412018-12-17 20:09:47 +01001111
Michael Scottb8909432019-08-02 11:42:06 -07001112 binding_paths = []
1113
1114 for bindings_dir in bindings_dirs:
1115 for root, _, filenames in os.walk(bindings_dir):
1116 for filename in filenames:
1117 if filename.endswith(".yaml"):
1118 binding_paths.append(os.path.join(root, filename))
1119
1120 return binding_paths
Ulf Magnusson62d57412018-12-17 20:09:47 +01001121
1122
1123def _binding_compat(binding_path):
1124 # Returns the compatible string specified in the binding at 'binding_path'.
1125 # Uses a regex to avoid having to parse the bindings, which is slow when
1126 # done for all bindings.
1127
Paul Sokolovsky04da7ea2019-08-05 16:19:45 +03001128 with open(binding_path, encoding="utf-8") as binding:
Ulf Magnusson62d57412018-12-17 20:09:47 +01001129 for line in binding:
1130 match = re.match(r'\s+constraint:\s*"([^"]*)"', line)
1131 if match:
1132 return match.group(1)
1133
1134 return None
1135
1136
1137def _binding_bus(binding):
1138 # Returns the bus specified in 'binding' (the bus the device described by
1139 # 'binding' is on), e.g. "i2c", or None if 'binding' is None or doesn't
1140 # specify a bus
1141
1142 if binding and "parent" in binding:
1143 return binding["parent"].get("bus")
1144 return None
1145
1146
1147def _binding_inc_error(msg):
1148 # Helper for reporting errors in the !include implementation
1149
1150 raise yaml.constructor.ConstructorError(None, None, "error: " + msg)
1151
1152
1153def _load_binding(path):
1154 # Loads a top-level binding .yaml file from 'path', also handling any
1155 # !include'd files. Returns the parsed PyYAML output (Python
1156 # lists/dictionaries/strings/etc. representing the file).
1157
1158 with open(path, encoding="utf-8") as f:
1159 return _merge_included_bindings(yaml.load(f, Loader=yaml.Loader), path)
1160
1161
1162def _merge_included_bindings(binding, binding_path):
1163 # Merges any bindings in the 'inherits:' section of 'binding' into the top
1164 # level of 'binding'. !includes have already been processed at this point,
1165 # and leave the data for the included binding(s) in 'inherits:'.
1166 #
1167 # Properties in 'binding' take precedence over properties from included
1168 # bindings.
1169
1170 # Currently, we require that each !include'd file is a well-formed
1171 # binding in itself
1172 _check_binding(binding, binding_path)
1173
1174 if "inherits" in binding:
1175 for inherited in binding.pop("inherits"):
1176 _merge_props(
1177 binding, _merge_included_bindings(inherited, binding_path),
1178 None, binding_path)
1179
1180 return binding
1181
1182
1183def _merge_props(to_dict, from_dict, parent, binding_path):
1184 # Recursively merges 'from_dict' into 'to_dict', to implement !include. If
1185 # a key exists in both 'from_dict' and 'to_dict', then the value in
1186 # 'to_dict' takes precedence.
1187 #
1188 # 'parent' is the name of the parent key containing 'to_dict' and
1189 # 'from_dict', and 'binding_path' is the path to the top-level binding.
1190 # These are used to generate errors for sketchy property overwrites.
1191
1192 for prop in from_dict:
1193 if isinstance(to_dict.get(prop), dict) and \
1194 isinstance(from_dict[prop], dict):
1195 _merge_props(to_dict[prop], from_dict[prop], prop, binding_path)
1196 elif prop not in to_dict:
1197 to_dict[prop] = from_dict[prop]
1198 elif _bad_overwrite(to_dict, from_dict, prop):
1199 _err("{} (in '{}'): '{}' from !included file overwritten "
1200 "('{}' replaced with '{}')".format(
1201 binding_path, parent, prop, from_dict[prop],
1202 to_dict[prop]))
1203
1204
1205def _bad_overwrite(to_dict, from_dict, prop):
1206 # _merge_props() helper. Returns True in cases where it's bad that
1207 # to_dict[prop] takes precedence over from_dict[prop].
1208
1209 # These are overridden deliberately
1210 if prop in {"title", "description"}:
1211 return False
1212
1213 if to_dict[prop] == from_dict[prop]:
1214 return False
1215
1216 # Allow a property to be made required when it previously was optional
1217 # without a warning
1218 if prop == "category" and to_dict["category"] == "required" and \
1219 from_dict["category"] == "optional":
1220 return False
1221
1222 return True
1223
1224
1225def _check_binding(binding, binding_path):
1226 # Does sanity checking on 'binding'
1227
1228 for prop in "title", "description":
1229 if prop not in binding:
1230 _err("missing '{}' property in {}".format(prop, binding_path))
1231
1232 for prop in "title", "description":
1233 if not isinstance(binding[prop], str) or not binding[prop]:
1234 _err("missing, malformed, or empty '{}' in {}"
1235 .format(prop, binding_path))
1236
1237 ok_top = {"title", "description", "inherits", "properties", "#cells",
1238 "parent", "child", "sub-node"}
1239
1240 for prop in binding:
1241 if prop not in ok_top:
1242 _err("unknown key '{}' in {}, expected one of {}"
1243 .format(prop, binding_path, ", ".join(ok_top)))
1244
1245 for pc in "parent", "child":
1246 if pc in binding:
1247 # Just 'bus:' is expected at the moment
1248 if binding[pc].keys() != {"bus"}:
1249 _err("expected (just) 'bus:' in '{}:' in {}"
1250 .format(pc, binding_path))
1251
1252 if not isinstance(binding[pc]["bus"], str):
1253 _err("malformed '{}: bus:' value in {}, expected string"
1254 .format(pc, binding_path))
1255
Ulf Magnussone703b492019-08-14 11:58:56 +02001256 _check_binding_properties(binding, binding_path)
1257
1258 if "sub-node" in binding:
1259 if binding["sub-node"].keys() != {"properties"}:
1260 _err("expected (just) 'properties:' in 'sub-node:' in {}"
1261 .format(binding_path))
1262
1263 _check_binding_properties(binding["sub-node"], binding_path)
1264
1265
1266def _check_binding_properties(binding, binding_path):
1267 # _check_binding() helper for checking the contents of 'properties:'
Ulf Magnusson62d57412018-12-17 20:09:47 +01001268
1269 if "properties" not in binding:
1270 return
1271
Kumar Gala3d143742019-08-09 16:03:46 -05001272 ok_prop_keys = {"description", "type", "category", "constraint", "enum",
1273 "const"}
Ulf Magnusson62d57412018-12-17 20:09:47 +01001274 ok_categories = {"required", "optional"}
1275
Ulf Magnussonc0c8dd12019-08-08 21:29:05 +02001276 for prop_name, options in binding["properties"].items():
1277 for key in options:
Ulf Magnusson62d57412018-12-17 20:09:47 +01001278 if key not in ok_prop_keys:
1279 _err("unknown setting '{}' in 'properties: {}: ...' in {}, "
1280 "expected one of {}".format(
Ulf Magnussonc0c8dd12019-08-08 21:29:05 +02001281 key, prop_name, binding_path,
1282 ", ".join(ok_prop_keys)))
Ulf Magnusson62d57412018-12-17 20:09:47 +01001283
Ulf Magnussonc0c8dd12019-08-08 21:29:05 +02001284 if "category" in options and options["category"] not in ok_categories:
Ulf Magnusson62d57412018-12-17 20:09:47 +01001285 _err("unrecognized category '{}' for '{}' in 'properties' in {}, "
1286 "expected one of {}".format(
Ulf Magnussonc0c8dd12019-08-08 21:29:05 +02001287 options["category"], prop_name, binding_path,
Ulf Magnusson62d57412018-12-17 20:09:47 +01001288 ", ".join(ok_categories)))
1289
Ulf Magnussonc0c8dd12019-08-08 21:29:05 +02001290 if "description" in options and \
1291 not isinstance(options["description"], str):
Ulf Magnusson62d57412018-12-17 20:09:47 +01001292 _err("missing, malformed, or empty 'description' for '{}' in "
Ulf Magnussonc0c8dd12019-08-08 21:29:05 +02001293 "'properties' in {}".format(prop_name, binding_path))
Ulf Magnusson62d57412018-12-17 20:09:47 +01001294
Kumar Galacd72ce12019-08-09 14:53:42 -05001295 if "enum" in options and not isinstance(options["enum"], list):
1296 _err("enum in {} for property '{}' is not a list"
1297 .format(binding_path, prop_name))
1298
Kumar Gala3d143742019-08-09 16:03:46 -05001299 if "const" in options and not isinstance(options["const"], (int, str)):
1300 _err("const in {} for property ({}) is not a scalar"
1301 .format(binding_path, prop_name))
1302
Ulf Magnusson62d57412018-12-17 20:09:47 +01001303
1304def _translate(addr, node):
1305 # Recursively translates 'addr' on 'node' to the address space(s) of its
1306 # parent(s), by looking at 'ranges' properties. Returns the translated
1307 # address.
1308
1309 if not node.parent or "ranges" not in node.parent.props:
1310 # No translation
1311 return addr
1312
1313 if not node.parent.props["ranges"].value:
1314 # DT spec.: "If the property is defined with an <empty> value, it
1315 # specifies that the parent and child address space is identical, and
1316 # no address translation is required."
1317 #
1318 # Treat this the same as a 'range' that explicitly does a one-to-one
1319 # mapping, as opposed to there not being any translation.
1320 return _translate(addr, node.parent)
1321
1322 # Gives the size of each component in a translation 3-tuple in 'ranges'
1323 child_address_cells = _address_cells(node)
1324 parent_address_cells = _address_cells(node.parent)
1325 child_size_cells = _size_cells(node)
1326
1327 # Number of cells for one translation 3-tuple in 'ranges'
1328 entry_cells = child_address_cells + parent_address_cells + child_size_cells
1329
1330 for raw_range in _slice(node.parent, "ranges", 4*entry_cells):
1331 child_addr = to_num(raw_range[:4*child_address_cells])
1332 raw_range = raw_range[4*child_address_cells:]
1333
1334 parent_addr = to_num(raw_range[:4*parent_address_cells])
1335 raw_range = raw_range[4*parent_address_cells:]
1336
1337 child_len = to_num(raw_range)
1338
1339 if child_addr <= addr < child_addr + child_len:
1340 # 'addr' is within range of a translation in 'ranges'. Recursively
1341 # translate it and return the result.
1342 return _translate(parent_addr + addr - child_addr, node.parent)
1343
1344 # 'addr' is not within range of any translation in 'ranges'
1345 return addr
1346
1347
1348def _add_names(node, names_ident, objs):
1349 # Helper for registering names from <foo>-names properties.
1350 #
1351 # node:
1352 # Device tree node
1353 #
1354 # names-ident:
Ulf Magnusson95deec12019-08-06 21:51:06 +02001355 # The <foo> part of <foo>-names, e.g. "reg" for "reg-names"
Ulf Magnusson62d57412018-12-17 20:09:47 +01001356 #
1357 # objs:
1358 # list of objects whose .name field should be set
1359
Ulf Magnusson95deec12019-08-06 21:51:06 +02001360 full_names_ident = names_ident + "-names"
1361
1362 if full_names_ident in node.props:
1363 names = node.props[full_names_ident].to_strings()
Ulf Magnusson62d57412018-12-17 20:09:47 +01001364 if len(names) != len(objs):
1365 _err("{} property in {} has {} strings, expected {} strings"
Ulf Magnusson95deec12019-08-06 21:51:06 +02001366 .format(full_names_ident, node.name, len(names), len(objs)))
Ulf Magnusson62d57412018-12-17 20:09:47 +01001367
1368 for obj, name in zip(objs, names):
1369 obj.name = name
1370 else:
1371 for obj in objs:
1372 obj.name = None
1373
1374
1375def _interrupt_parent(node):
1376 # Returns the node pointed at by the closest 'interrupt-parent', searching
1377 # the parents of 'node'. As of writing, this behavior isn't specified in
1378 # the DT spec., but seems to match what some .dts files except.
1379
1380 while node:
1381 if "interrupt-parent" in node.props:
1382 return node.props["interrupt-parent"].to_node()
1383 node = node.parent
1384
1385 _err("{!r} has an 'interrupts' property, but neither the node nor any "
1386 "of its parents has an 'interrupt-parent' property".format(node))
1387
1388
1389def _interrupts(node):
1390 # Returns a list of (<controller>, <specifier>) tuples, with one tuple per
1391 # interrupt generated by 'node'. <controller> is the destination of the
1392 # interrupt (possibly after mapping through an 'interrupt-map'), and
1393 # <specifier> the data associated with the interrupt (as a 'bytes' object).
1394
1395 # Takes precedence over 'interrupts' if both are present
1396 if "interrupts-extended" in node.props:
1397 prop = node.props["interrupts-extended"]
1398 return [_map_interrupt(node, iparent, spec)
Ulf Magnusson95deec12019-08-06 21:51:06 +02001399 for iparent, spec in _phandle_val_list(prop, "interrupt")]
Ulf Magnusson62d57412018-12-17 20:09:47 +01001400
1401 if "interrupts" in node.props:
1402 # Treat 'interrupts' as a special case of 'interrupts-extended', with
1403 # the same interrupt parent for all interrupts
1404
1405 iparent = _interrupt_parent(node)
1406 interrupt_cells = _interrupt_cells(iparent)
1407
1408 return [_map_interrupt(node, iparent, raw)
1409 for raw in _slice(node, "interrupts", 4*interrupt_cells)]
1410
1411 return []
1412
1413
1414def _map_interrupt(child, parent, child_spec):
1415 # Translates an interrupt headed from 'child' to 'parent' with specifier
1416 # 'child_spec' through any 'interrupt-map' properties. Returns a
1417 # (<controller>, <specifier>) tuple with the final destination after
1418 # mapping.
1419
1420 if "interrupt-controller" in parent.props:
1421 return (parent, child_spec)
1422
1423 def own_address_cells(node):
1424 # Used for parents pointed at by 'interrupt-map'. We can't use
1425 # _address_cells(), because it's the #address-cells property on 'node'
1426 # itself that matters.
1427
1428 address_cells = node.props.get("#address-cells")
1429 if not address_cells:
1430 _err("missing #address-cells on {!r} (while handling interrupt-map)"
1431 .format(node))
1432 return address_cells.to_num()
1433
1434 def spec_len_fn(node):
1435 # Can't use _address_cells() here, because it's the #address-cells
1436 # property on 'node' itself that matters
1437 return 4*(own_address_cells(node) + _interrupt_cells(node))
1438
1439 parent, raw_spec = _map(
1440 "interrupt", child, parent, _raw_unit_addr(child) + child_spec,
1441 spec_len_fn)
1442
1443 # Strip the parent unit address part, if any
1444 return (parent, raw_spec[4*own_address_cells(parent):])
1445
1446
Ulf Magnusson62d57412018-12-17 20:09:47 +01001447def _gpios(node):
1448 # Returns a dictionary that maps '<prefix>-gpios' prefixes to lists of
1449 # (<controller>, <specifier>) tuples (possibly after mapping through an
1450 # gpio-map). <controller> is a dtlib.Node.
1451
1452 res = {}
1453
1454 for name, prop in node.props.items():
Kumar Gala8622c342019-08-07 08:40:14 -05001455 if name.endswith("-gpios") or name == "gpios":
Ulf Magnusson62d57412018-12-17 20:09:47 +01001456 # Get the prefix from the property name:
1457 # - gpios -> "" (deprecated, should have a prefix)
1458 # - foo-gpios -> "foo"
1459 # - etc.
1460 prefix = name[:-5]
1461 if prefix.endswith("-"):
1462 prefix = prefix[:-1]
1463
1464 res[prefix] = [
1465 _map_gpio(prop.node, controller, spec)
Ulf Magnusson95deec12019-08-06 21:51:06 +02001466 for controller, spec in _phandle_val_list(prop, "gpio")
Ulf Magnusson62d57412018-12-17 20:09:47 +01001467 ]
1468
1469 return res
1470
1471
1472def _map_gpio(child, parent, child_spec):
1473 # Returns a (<controller>, <specifier>) tuple with the final destination
1474 # after mapping through any 'gpio-map' properties. See _map_interrupt().
1475
1476 if "gpio-map" not in parent.props:
1477 return (parent, child_spec)
1478
1479 return _map("gpio", child, parent, child_spec,
1480 lambda node: 4*_gpio_cells(node))
1481
1482
1483def _map(prefix, child, parent, child_spec, spec_len_fn):
1484 # Common code for mapping through <prefix>-map properties, e.g.
1485 # interrupt-map and gpio-map.
1486 #
1487 # prefix:
1488 # The prefix, e.g. "interrupt" or "gpio"
1489 #
1490 # child:
1491 # The "sender", e.g. the node with 'interrupts = <...>'
1492 #
1493 # parent:
1494 # The "receiver", e.g. a node with 'interrupt-map = <...>' or
1495 # 'interrupt-controller' (no mapping)
1496 #
1497 # child_spec:
1498 # The data associated with the interrupt/GPIO/etc., as a 'bytes' object,
1499 # e.g. <1 2> for 'foo-gpios = <&gpio1 1 2>'.
1500 #
1501 # spec_len_fn:
1502 # Function called on a parent specified in a *-map property to get its
1503 # *-cells value, e.g. #interrupt-cells
1504
1505 map_prop = parent.props.get(prefix + "-map")
1506 if not map_prop:
1507 if prefix + "-controller" not in parent.props:
1508 _err("expected '{}-controller' property on {!r} "
1509 "(referenced by {!r})".format(prefix, parent, child))
1510
1511 # No mapping
1512 return (parent, child_spec)
1513
1514 masked_child_spec = _mask(prefix, child, parent, child_spec)
1515
1516 raw = map_prop.value
1517 while raw:
1518 if len(raw) < len(child_spec):
1519 _err("bad value for {!r}, missing/truncated child specifier"
1520 .format(map_prop))
1521 child_spec_entry = raw[:len(child_spec)]
1522 raw = raw[len(child_spec):]
1523
1524 if len(raw) < 4:
1525 _err("bad value for {!r}, missing/truncated phandle"
1526 .format(map_prop))
1527 phandle = to_num(raw[:4])
1528 raw = raw[4:]
1529
1530 # Parent specified in *-map
1531 map_parent = parent.dt.phandle2node.get(phandle)
1532 if not map_parent:
1533 _err("bad phandle in " + repr(map_prop))
1534
1535 map_parent_spec_len = spec_len_fn(map_parent)
1536 if len(raw) < map_parent_spec_len:
1537 _err("bad value for {!r}, missing/truncated parent specifier"
1538 .format(map_prop))
1539 parent_spec = raw[:map_parent_spec_len]
1540 raw = raw[map_parent_spec_len:]
1541
1542 # Got one *-map row. Check if it matches the child specifier.
1543 if child_spec_entry == masked_child_spec:
1544 # Handle *-map-pass-thru
1545 parent_spec = _pass_thru(
1546 prefix, child, parent, child_spec, parent_spec)
1547
1548 # Found match. Recursively map and return it.
1549 return _map(prefix, parent, map_parent, parent_spec, spec_len_fn)
1550
1551 _err("child specifier for {!r} ({}) does not appear in {!r}"
1552 .format(child, child_spec, map_prop))
1553
1554
1555def _mask(prefix, child, parent, child_spec):
1556 # Common code for handling <prefix>-mask properties, e.g. interrupt-mask.
1557 # See _map() for the parameters.
1558
1559 mask_prop = parent.props.get(prefix + "-map-mask")
1560 if not mask_prop:
1561 # No mask
1562 return child_spec
1563
1564 mask = mask_prop.value
1565 if len(mask) != len(child_spec):
1566 _err("{!r}: expected '{}-mask' in {!r} to be {} bytes, is {} bytes"
1567 .format(child, prefix, parent, len(child_spec), len(mask)))
1568
1569 return _and(child_spec, mask)
1570
1571
1572def _pass_thru(prefix, child, parent, child_spec, parent_spec):
1573 # Common code for handling <prefix>-map-thru properties, e.g.
1574 # interrupt-pass-thru.
1575 #
1576 # parent_spec:
1577 # The parent specifier from the matched entry in the <prefix>-map
1578 # property
1579 #
1580 # See _map() for the other parameters.
1581
1582 pass_thru_prop = parent.props.get(prefix + "-map-pass-thru")
1583 if not pass_thru_prop:
1584 # No pass-thru
1585 return parent_spec
1586
1587 pass_thru = pass_thru_prop.value
1588 if len(pass_thru) != len(child_spec):
1589 _err("{!r}: expected '{}-map-pass-thru' in {!r} to be {} bytes, is {} bytes"
1590 .format(child, prefix, parent, len(child_spec), len(pass_thru)))
1591
1592 res = _or(_and(child_spec, pass_thru),
1593 _and(parent_spec, _not(pass_thru)))
1594
1595 # Truncate to length of parent spec.
1596 return res[-len(parent_spec):]
1597
1598
1599def _raw_unit_addr(node):
1600 # _map_interrupt() helper. Returns the unit address (derived from 'reg' and
1601 # #address-cells) as a raw 'bytes'
1602
1603 if 'reg' not in node.props:
1604 _err("{!r} lacks 'reg' property (needed for 'interrupt-map' unit "
1605 "address lookup)".format(node))
1606
1607 addr_len = 4*_address_cells(node)
1608
1609 if len(node.props['reg'].value) < addr_len:
1610 _err("{!r} has too short 'reg' property (while doing 'interrupt-map' "
1611 "unit address lookup)".format(node))
1612
1613 return node.props['reg'].value[:addr_len]
1614
1615
1616def _and(b1, b2):
1617 # Returns the bitwise AND of the two 'bytes' objects b1 and b2. Pads
1618 # with ones on the left if the lengths are not equal.
1619
1620 # Pad on the left, to equal length
1621 maxlen = max(len(b1), len(b2))
1622 return bytes(x & y for x, y in zip(b1.rjust(maxlen, b'\xff'),
1623 b2.rjust(maxlen, b'\xff')))
1624
1625
1626def _or(b1, b2):
1627 # Returns the bitwise OR of the two 'bytes' objects b1 and b2. Pads with
1628 # zeros on the left if the lengths are not equal.
1629
1630 # Pad on the left, to equal length
1631 maxlen = max(len(b1), len(b2))
1632 return bytes(x | y for x, y in zip(b1.rjust(maxlen, b'\x00'),
1633 b2.rjust(maxlen, b'\x00')))
1634
1635
1636def _not(b):
1637 # Returns the bitwise not of the 'bytes' object 'b'
1638
1639 # ANDing with 0xFF avoids negative numbers
1640 return bytes(~x & 0xFF for x in b)
1641
1642
Ulf Magnusson95deec12019-08-06 21:51:06 +02001643def _phandle_val_list(prop, n_cells_name):
1644 # Parses a '<phandle> <value> <phandle> <value> ...' value. The number of
1645 # cells that make up each <value> is derived from the node pointed at by
1646 # the preceding <phandle>.
Ulf Magnusson62d57412018-12-17 20:09:47 +01001647 #
1648 # prop:
1649 # dtlib.Property with value to parse
1650 #
Ulf Magnusson95deec12019-08-06 21:51:06 +02001651 # n_cells_name:
1652 # The <name> part of the #<name>-cells property to look for on the nodes
1653 # the phandles point to, e.g. "gpio" for #gpio-cells.
Ulf Magnusson62d57412018-12-17 20:09:47 +01001654 #
1655 # Returns a list of (<node>, <value>) tuples, where <node> is the node
Ulf Magnusson95deec12019-08-06 21:51:06 +02001656 # pointed at by <phandle>.
1657
1658 full_n_cells_name = "#{}-cells".format(n_cells_name)
Ulf Magnusson62d57412018-12-17 20:09:47 +01001659
1660 res = []
1661
1662 raw = prop.value
1663 while raw:
1664 if len(raw) < 4:
1665 # Not enough room for phandle
1666 _err("bad value for " + repr(prop))
1667 phandle = to_num(raw[:4])
1668 raw = raw[4:]
1669
1670 node = prop.node.dt.phandle2node.get(phandle)
1671 if not node:
1672 _err("bad phandle in " + repr(prop))
1673
Ulf Magnusson95deec12019-08-06 21:51:06 +02001674 if full_n_cells_name not in node.props:
1675 _err("{!r} lacks {}".format(node, full_n_cells_name))
1676
1677 n_cells = node.props[full_n_cells_name].to_num()
Ulf Magnusson62d57412018-12-17 20:09:47 +01001678 if len(raw) < 4*n_cells:
1679 _err("missing data after phandle in " + repr(prop))
1680
1681 res.append((node, raw[:4*n_cells]))
1682 raw = raw[4*n_cells:]
1683
1684 return res
1685
1686
1687def _address_cells(node):
1688 # Returns the #address-cells setting for 'node', giving the number of <u32>
1689 # cells used to encode the address in the 'reg' property
1690
1691 if "#address-cells" in node.parent.props:
1692 return node.parent.props["#address-cells"].to_num()
1693 return 2 # Default value per DT spec.
1694
1695
1696def _size_cells(node):
1697 # Returns the #size-cells setting for 'node', giving the number of <u32>
1698 # cells used to encode the size in the 'reg' property
1699
1700 if "#size-cells" in node.parent.props:
1701 return node.parent.props["#size-cells"].to_num()
1702 return 1 # Default value per DT spec.
1703
1704
1705def _interrupt_cells(node):
1706 # Returns the #interrupt-cells property value on 'node', erroring out if
1707 # 'node' has no #interrupt-cells property
1708
1709 if "#interrupt-cells" not in node.props:
1710 _err("{!r} lacks #interrupt-cells".format(node))
1711 return node.props["#interrupt-cells"].to_num()
1712
1713
1714def _gpio_cells(node):
1715 if "#gpio-cells" not in node.props:
1716 _err("{!r} lacks #gpio-cells".format(node))
1717 return node.props["#gpio-cells"].to_num()
1718
1719
Ulf Magnusson62d57412018-12-17 20:09:47 +01001720def _slice(node, prop_name, size):
1721 # Splits node.props[prop_name].value into 'size'-sized chunks, returning a
1722 # list of chunks. Raises EDTError if the length of the property is not
1723 # evenly divisible by 'size'.
1724
1725 raw = node.props[prop_name].value
1726 if len(raw) % size:
1727 _err("'{}' property in {!r} has length {}, which is not evenly "
1728 "divisible by {}".format(prop_name, node, len(raw), size))
1729
1730 return [raw[i:i + size] for i in range(0, len(raw), size)]
1731
1732
Ulf Magnussonacf276f2019-08-07 19:33:45 +02001733def _check_dt(dt):
1734 # Does devicetree sanity checks. dtlib is meant to be general and
1735 # anything-goes except for very special properties like phandle, but in
1736 # edtlib we can be pickier.
1737
1738 # Check that 'status' has one of the values given in the devicetree spec.
1739
1740 ok_status = {"okay", "disabled", "reserved", "fail", "fail-sss"}
1741
1742 for node in dt.node_iter():
1743 if "status" in node.props:
1744 try:
1745 status_val = node.props["status"].to_string()
1746 except DTError as e:
1747 # The error message gives the path
1748 _err(str(e))
1749
1750 if status_val not in ok_status:
1751 _err("unknown 'status' value \"{}\" in {} in {}, expected one "
1752 "of {} (see the devicetree specification)"
1753 .format(status_val, node.path, node.dt.filename,
1754 ", ".join(ok_status)))
1755
1756
Ulf Magnusson62d57412018-12-17 20:09:47 +01001757def _err(msg):
1758 raise EDTError(msg)
1759
1760
1761def _warn(msg):
1762 print("warning: " + msg, file=sys.stderr)