blob: 1d69ad38e2e35a3f31826c275621f930e0a17f44 [file] [log] [blame]
Tom Rini4549e782018-05-06 18:27:01 -04001/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
Simon Glasscf2064d2017-05-27 07:38:11 -06002/*
3 * pylibfdt - Flat Device Tree manipulation in Python
4 * Copyright (C) 2017 Google, Inc.
5 * Written by Simon Glass <sjg@chromium.org>
Simon Glasscf2064d2017-05-27 07:38:11 -06006 */
7
8%module libfdt
9
Simon Glassc79d18c2017-08-13 16:02:54 -060010%include <stdint.i>
11
Simon Glasscf2064d2017-05-27 07:38:11 -060012%{
13#define SWIG_FILE_WITH_INIT
14#include "libfdt.h"
Simon Glass3def0cf2018-07-06 10:27:20 -060015
16/*
17 * We rename this function here to avoid problems with swig, since we also have
18 * a struct called fdt_property. That struct causes swig to create a class in
19 * libfdt.py called fdt_property(), which confuses things.
20 */
Simon Glass97de5322019-10-31 07:43:01 -060021static int fdt_property_stub(void *fdt, const char *name, const void *val,
Simon Glass50c59522018-07-26 14:02:13 -060022 int len)
Simon Glass3def0cf2018-07-06 10:27:20 -060023{
24 return fdt_property(fdt, name, val, len);
25}
26
Simon Glasscf2064d2017-05-27 07:38:11 -060027%}
28
29%pythoncode %{
30
31import struct
32
33# Error codes, corresponding to FDT_ERR_... in libfdt.h
34(NOTFOUND,
35 EXISTS,
36 NOSPACE,
37 BADOFFSET,
38 BADPATH,
39 BADPHANDLE,
40 BADSTATE,
41 TRUNCATED,
42 BADMAGIC,
43 BADVERSION,
44 BADSTRUCTURE,
45 BADLAYOUT,
46 INTERNAL,
47 BADNCELLS,
48 BADVALUE,
49 BADOVERLAY,
50 NOPHANDLES) = QUIET_ALL = range(1, 18)
51# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
52# altogether. All # functions passed this value will return an error instead
53# of raising an exception.
54
55# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
56# instead of raising an exception.
57QUIET_NOTFOUND = (NOTFOUND,)
Simon Glass50c59522018-07-26 14:02:13 -060058QUIET_NOSPACE = (NOSPACE,)
Simon Glasscf2064d2017-05-27 07:38:11 -060059
60
61class FdtException(Exception):
62 """An exception caused by an error such as one of the codes above"""
63 def __init__(self, err):
64 self.err = err
65
66 def __str__(self):
67 return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
68
69def strerror(fdt_err):
70 """Get the string for an error number
71
72 Args:
73 fdt_err: Error number (-ve)
74
75 Returns:
76 String containing the associated error
77 """
78 return fdt_strerror(fdt_err)
79
80def check_err(val, quiet=()):
81 """Raise an error if the return value is -ve
82
83 This is used to check for errors returned by libfdt C functions.
84
85 Args:
86 val: Return value from a libfdt function
87 quiet: Errors to ignore (empty to raise on all errors)
88
89 Returns:
90 val if val >= 0
91
92 Raises
93 FdtException if val < 0
94 """
Simon Glass903fe172019-10-31 07:43:00 -060095 if isinstance(val, int) and val < 0:
Simon Glasscf2064d2017-05-27 07:38:11 -060096 if -val not in quiet:
97 raise FdtException(val)
98 return val
99
100def check_err_null(val, quiet=()):
101 """Raise an error if the return value is NULL
102
103 This is used to check for a NULL return value from certain libfdt C
104 functions
105
106 Args:
107 val: Return value from a libfdt function
108 quiet: Errors to ignore (empty to raise on all errors)
109
110 Returns:
111 val if val is a list, None if not
112
113 Raises
114 FdtException if val indicates an error was reported and the error
115 is not in @quiet.
116 """
117 # Normally a list is returned which contains the data and its length.
118 # If we get just an integer error code, it means the function failed.
119 if not isinstance(val, list):
120 if -val not in quiet:
121 raise FdtException(val)
122 return val
123
Simon Glass50c59522018-07-26 14:02:13 -0600124class FdtRo(object):
125 """Class for a read-only device-tree
Simon Glass3def0cf2018-07-06 10:27:20 -0600126
Simon Glass50c59522018-07-26 14:02:13 -0600127 This is a base class used by FdtRw (read-write access) and FdtSw
128 (sequential-write access). It implements read-only access to the
129 device tree.
Simon Glasscf2064d2017-05-27 07:38:11 -0600130
Simon Glass50c59522018-07-26 14:02:13 -0600131 Here are the three classes and when you should use them:
Simon Glasscf2064d2017-05-27 07:38:11 -0600132
Simon Glass50c59522018-07-26 14:02:13 -0600133 FdtRo - read-only access to an existing FDT
134 FdtRw - read-write access to an existing FDT (most common case)
135 FdtSw - for creating a new FDT, as well as allowing read-only access
Simon Glasscf2064d2017-05-27 07:38:11 -0600136 """
137 def __init__(self, data):
138 self._fdt = bytearray(data)
139 check_err(fdt_check_header(self._fdt));
140
Simon Glass3def0cf2018-07-06 10:27:20 -0600141 def as_bytearray(self):
142 """Get the device tree contents as a bytearray
143
144 This can be passed directly to libfdt functions that access a
145 const void * for the device tree.
146
147 Returns:
148 bytearray containing the device tree
149 """
150 return bytearray(self._fdt)
151
152 def next_node(self, nodeoffset, depth, quiet=()):
153 """Find the next subnode
154
155 Args:
156 nodeoffset: Node offset of previous node
Simon Glass50c59522018-07-26 14:02:13 -0600157 depth: The depth of the node at nodeoffset. This is used to
158 calculate the depth of the returned node
Simon Glass3def0cf2018-07-06 10:27:20 -0600159 quiet: Errors to ignore (empty to raise on all errors)
160
161 Returns:
Simon Glass50c59522018-07-26 14:02:13 -0600162 Typle:
163 Offset of the next node, if any, else a -ve error
164 Depth of the returned node, if any, else undefined
Simon Glass3def0cf2018-07-06 10:27:20 -0600165
166 Raises:
167 FdtException if no more nodes found or other error occurs
168 """
169 return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
170
171 def first_subnode(self, nodeoffset, quiet=()):
172 """Find the first subnode of a parent node
173
174 Args:
175 nodeoffset: Node offset of parent node
176 quiet: Errors to ignore (empty to raise on all errors)
177
178 Returns:
179 The offset of the first subnode, if any
180
181 Raises:
182 FdtException if no subnodes found or other error occurs
183 """
184 return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
185
186 def next_subnode(self, nodeoffset, quiet=()):
187 """Find the next subnode
188
189 Args:
190 nodeoffset: Node offset of previous subnode
191 quiet: Errors to ignore (empty to raise on all errors)
192
193 Returns:
194 The offset of the next subnode, if any
195
196 Raises:
197 FdtException if no more subnodes found or other error occurs
198 """
199 return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
200
201 def magic(self):
202 """Return the magic word from the header
203
204 Returns:
205 Magic word
206 """
Simon Glass50c59522018-07-26 14:02:13 -0600207 return fdt_magic(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600208
209 def totalsize(self):
210 """Return the total size of the device tree
211
212 Returns:
213 Total tree size in bytes
214 """
Simon Glass50c59522018-07-26 14:02:13 -0600215 return fdt_totalsize(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600216
217 def off_dt_struct(self):
218 """Return the start of the device-tree struct area
219
220 Returns:
221 Start offset of struct area
222 """
Simon Glass50c59522018-07-26 14:02:13 -0600223 return fdt_off_dt_struct(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600224
225 def off_dt_strings(self):
226 """Return the start of the device-tree string area
227
228 Returns:
229 Start offset of string area
230 """
Simon Glass50c59522018-07-26 14:02:13 -0600231 return fdt_off_dt_strings(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600232
233 def off_mem_rsvmap(self):
234 """Return the start of the memory reserve map
235
236 Returns:
237 Start offset of memory reserve map
238 """
Simon Glass50c59522018-07-26 14:02:13 -0600239 return fdt_off_mem_rsvmap(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600240
241 def version(self):
242 """Return the version of the device tree
243
244 Returns:
245 Version number of the device tree
246 """
Simon Glass50c59522018-07-26 14:02:13 -0600247 return fdt_version(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600248
249 def last_comp_version(self):
250 """Return the last compatible version of the device tree
251
252 Returns:
253 Last compatible version number of the device tree
254 """
Simon Glass50c59522018-07-26 14:02:13 -0600255 return fdt_last_comp_version(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600256
257 def boot_cpuid_phys(self):
258 """Return the physical boot CPU ID
259
260 Returns:
261 Physical boot CPU ID
262 """
Simon Glass50c59522018-07-26 14:02:13 -0600263 return fdt_boot_cpuid_phys(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600264
265 def size_dt_strings(self):
266 """Return the start of the device-tree string area
267
268 Returns:
269 Start offset of string area
270 """
Simon Glass50c59522018-07-26 14:02:13 -0600271 return fdt_size_dt_strings(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600272
273 def size_dt_struct(self):
274 """Return the start of the device-tree struct area
275
276 Returns:
277 Start offset of struct area
278 """
Simon Glass50c59522018-07-26 14:02:13 -0600279 return fdt_size_dt_struct(self._fdt)
Simon Glass3def0cf2018-07-06 10:27:20 -0600280
281 def num_mem_rsv(self, quiet=()):
282 """Return the number of memory reserve-map records
283
284 Returns:
285 Number of memory reserve-map records
286 """
287 return check_err(fdt_num_mem_rsv(self._fdt), quiet)
288
289 def get_mem_rsv(self, index, quiet=()):
290 """Return the indexed memory reserve-map record
291
292 Args:
293 index: Record to return (0=first)
294
295 Returns:
296 Number of memory reserve-map records
297 """
298 return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
299
Simon Glass93c94b82017-08-29 14:15:46 -0600300 def subnode_offset(self, parentoffset, name, quiet=()):
301 """Get the offset of a named subnode
302
303 Args:
304 parentoffset: Offset of the parent node to check
305 name: Name of the required subnode, e.g. 'subnode@1'
306 quiet: Errors to ignore (empty to raise on all errors)
307
308 Returns:
309 The node offset of the found node, if any
310
311 Raises
312 FdtException if there is no node with that name, or other error
313 """
314 return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
315 quiet)
316
Simon Glasscf2064d2017-05-27 07:38:11 -0600317 def path_offset(self, path, quiet=()):
318 """Get the offset for a given path
319
320 Args:
321 path: Path to the required node, e.g. '/node@3/subnode@1'
322 quiet: Errors to ignore (empty to raise on all errors)
323
324 Returns:
325 Node offset
326
327 Raises
328 FdtException if the path is not valid or not found
329 """
330 return check_err(fdt_path_offset(self._fdt, path), quiet)
331
Simon Glass3def0cf2018-07-06 10:27:20 -0600332 def get_name(self, nodeoffset):
333 """Get the name of a node
334
335 Args:
336 nodeoffset: Offset of node to check
337
338 Returns:
339 Node name
340
341 Raises:
342 FdtException on error (e.g. nodeoffset is invalid)
343 """
344 return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
345
Simon Glasscf2064d2017-05-27 07:38:11 -0600346 def first_property_offset(self, nodeoffset, quiet=()):
347 """Get the offset of the first property in a node offset
348
349 Args:
350 nodeoffset: Offset to the node to check
351 quiet: Errors to ignore (empty to raise on all errors)
352
353 Returns:
354 Offset of the first property
355
356 Raises
357 FdtException if the associated node has no properties, or some
358 other error occurred
359 """
360 return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
361 quiet)
362
363 def next_property_offset(self, prop_offset, quiet=()):
364 """Get the next property in a node
365
366 Args:
367 prop_offset: Offset of the previous property
368 quiet: Errors to ignore (empty to raise on all errors)
369
370 Returns:
371 Offset of the next property
372
373 Raises:
374 FdtException if the associated node has no more properties, or
375 some other error occurred
376 """
377 return check_err(fdt_next_property_offset(self._fdt, prop_offset),
378 quiet)
379
Simon Glasscf2064d2017-05-27 07:38:11 -0600380 def get_property_by_offset(self, prop_offset, quiet=()):
381 """Obtains a property that can be examined
382
383 Args:
384 prop_offset: Offset of property (e.g. from first_property_offset())
385 quiet: Errors to ignore (empty to raise on all errors)
386
387 Returns:
388 Property object, or None if not found
389
390 Raises:
391 FdtException on error (e.g. invalid prop_offset or device
392 tree format)
393 """
394 pdata = check_err_null(
395 fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
396 if isinstance(pdata, (int)):
397 return pdata
398 return Property(pdata[0], pdata[1])
399
Simon Glasscf2064d2017-05-27 07:38:11 -0600400 def getprop(self, nodeoffset, prop_name, quiet=()):
401 """Get a property from a node
402
403 Args:
404 nodeoffset: Node offset containing property to get
405 prop_name: Name of property to get
406 quiet: Errors to ignore (empty to raise on all errors)
407
408 Returns:
Simon Glass50c59522018-07-26 14:02:13 -0600409 Value of property as a Property object (which can be used as a
410 bytearray/string), or -ve error number. On failure, returns an
411 integer error
Simon Glasscf2064d2017-05-27 07:38:11 -0600412
413 Raises:
414 FdtError if any error occurs (e.g. the property is not found)
415 """
416 pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
417 quiet)
418 if isinstance(pdata, (int)):
419 return pdata
Simon Glass903fe172019-10-31 07:43:00 -0600420 return Property(prop_name, bytes(pdata[0]))
Simon Glasscf2064d2017-05-27 07:38:11 -0600421
Simon Glass93c94b82017-08-29 14:15:46 -0600422 def get_phandle(self, nodeoffset):
423 """Get the phandle of a node
424
425 Args:
426 nodeoffset: Node offset to check
427
428 Returns:
429 phandle of node, or 0 if the node has no phandle or another error
430 occurs
431 """
432 return fdt_get_phandle(self._fdt, nodeoffset)
433
Simon Glass903fe172019-10-31 07:43:00 -0600434 def get_alias(self, name):
435 """Get the full path referenced by a given alias
436
437 Args:
438 name: name of the alias to lookup
439
440 Returns:
441 Full path to the node for the alias named 'name', if it exists
442 None, if the given alias or the /aliases node does not exist
443 """
444 return fdt_get_alias(self._fdt, name)
445
Simon Glass93c94b82017-08-29 14:15:46 -0600446 def parent_offset(self, nodeoffset, quiet=()):
447 """Get the offset of a node's parent
448
449 Args:
450 nodeoffset: Node offset to check
451 quiet: Errors to ignore (empty to raise on all errors)
452
453 Returns:
454 The offset of the parent node, if any
455
456 Raises:
457 FdtException if no parent found or other error occurs
458 """
459 return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
460
Simon Glass50c59522018-07-26 14:02:13 -0600461 def node_offset_by_phandle(self, phandle, quiet=()):
462 """Get the offset of a node with the given phandle
463
464 Args:
465 phandle: Phandle to search for
466 quiet: Errors to ignore (empty to raise on all errors)
467
468 Returns:
469 The offset of node with that phandle, if any
470
471 Raises:
472 FdtException if no node found or other error occurs
473 """
474 return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
475
476
477class Fdt(FdtRo):
478 """Device tree class, supporting all operations
479
480 The Fdt object is created is created from a device tree binary file,
481 e.g. with something like:
482
483 fdt = Fdt(open("filename.dtb").read())
484
485 Operations can then be performed using the methods in this class. Each
486 method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
487
488 All methods raise an FdtException if an error occurs. To avoid this
489 behaviour a 'quiet' parameter is provided for some functions. This
490 defaults to empty, but you can pass a list of errors that you expect.
491 If one of these errors occurs, the function will return an error number
492 (e.g. -NOTFOUND).
493 """
494 def __init__(self, data):
495 FdtRo.__init__(self, data)
496
497 @staticmethod
498 def create_empty_tree(size, quiet=()):
499 """Create an empty device tree ready for use
500
501 Args:
502 size: Size of device tree in bytes
503
504 Returns:
505 Fdt object containing the device tree
506 """
507 data = bytearray(size)
508 err = check_err(fdt_create_empty_tree(data, size), quiet)
509 if err:
510 return err
511 return Fdt(data)
512
513 def resize(self, size, quiet=()):
514 """Move the device tree into a larger or smaller space
515
516 This creates a new device tree of size @size and moves the existing
517 device tree contents over to that. It can be used to create more space
518 in a device tree. Note that the Fdt object remains the same, but it
519 now has a new bytearray holding the contents.
520
521 Args:
522 size: Required new size of device tree in bytes
523 """
524 fdt = bytearray(size)
525 err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
526 if err:
527 return err
528 self._fdt = fdt
529
530 def pack(self, quiet=()):
531 """Pack the device tree to remove unused space
532
533 This adjusts the tree in place.
534
535 Args:
536 quiet: Errors to ignore (empty to raise on all errors)
537
538 Returns:
539 Error code, or 0 if OK
540
541 Raises:
542 FdtException if any error occurs
543 """
544 err = check_err(fdt_pack(self._fdt), quiet)
545 if err:
546 return err
547 del self._fdt[self.totalsize():]
548 return err
549
Simon Glass3def0cf2018-07-06 10:27:20 -0600550 def set_name(self, nodeoffset, name, quiet=()):
551 """Set the name of a node
552
553 Args:
554 nodeoffset: Node offset of node to update
Simon Glass50c59522018-07-26 14:02:13 -0600555 name: New node name (string without \0)
Simon Glass3def0cf2018-07-06 10:27:20 -0600556
557 Returns:
558 Error code, or 0 if OK
559
560 Raises:
561 FdtException if no parent found or other error occurs
562 """
Simon Glass50c59522018-07-26 14:02:13 -0600563 if chr(0) in name:
564 raise ValueError('Property contains embedded nul characters')
Simon Glass3def0cf2018-07-06 10:27:20 -0600565 return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
566
567 def setprop(self, nodeoffset, prop_name, val, quiet=()):
568 """Set the value of a property
569
570 Args:
571 nodeoffset: Node offset containing the property to create/update
572 prop_name: Name of property
573 val: Value to write (string or bytearray)
574 quiet: Errors to ignore (empty to raise on all errors)
575
576 Returns:
577 Error code, or 0 if OK
578
579 Raises:
580 FdtException if no parent found or other error occurs
581 """
582 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
583 len(val)), quiet)
584
585 def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
586 """Set the value of a property
587
588 Args:
589 nodeoffset: Node offset containing the property to create/update
590 prop_name: Name of property
591 val: Value to write (integer)
592 quiet: Errors to ignore (empty to raise on all errors)
593
594 Returns:
595 Error code, or 0 if OK
596
597 Raises:
598 FdtException if no parent found or other error occurs
599 """
600 return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
601 quiet)
602
603 def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
604 """Set the value of a property
605
606 Args:
607 nodeoffset: Node offset containing the property to create/update
608 prop_name: Name of property
609 val: Value to write (integer)
610 quiet: Errors to ignore (empty to raise on all errors)
611
612 Returns:
613 Error code, or 0 if OK
614
615 Raises:
616 FdtException if no parent found or other error occurs
617 """
618 return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
619 quiet)
620
621 def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
622 """Set the string value of a property
623
624 The property is set to the string, with a nul terminator added
625
626 Args:
627 nodeoffset: Node offset containing the property to create/update
628 prop_name: Name of property
Simon Glass50c59522018-07-26 14:02:13 -0600629 val: Value to write (string without nul terminator). Unicode is
630 supposed by encoding to UTF-8
Simon Glass3def0cf2018-07-06 10:27:20 -0600631 quiet: Errors to ignore (empty to raise on all errors)
632
633 Returns:
634 Error code, or 0 if OK
635
636 Raises:
637 FdtException if no parent found or other error occurs
638 """
Simon Glassb4cf5f12019-10-31 07:42:59 -0600639 val = val.encode('utf-8') + b'\0'
Simon Glass3def0cf2018-07-06 10:27:20 -0600640 return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
641 val, len(val)), quiet)
642
Simon Glass34967c22018-09-14 04:57:06 -0600643 def delprop(self, nodeoffset, prop_name, quiet=()):
Simon Glass3def0cf2018-07-06 10:27:20 -0600644 """Delete a property from a node
645
646 Args:
647 nodeoffset: Node offset containing property to delete
648 prop_name: Name of property to delete
Simon Glass34967c22018-09-14 04:57:06 -0600649 quiet: Errors to ignore (empty to raise on all errors)
650
651 Returns:
652 Error code, or 0 if OK
Simon Glass3def0cf2018-07-06 10:27:20 -0600653
654 Raises:
655 FdtError if the property does not exist, or another error occurs
656 """
Simon Glass34967c22018-09-14 04:57:06 -0600657 return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
Simon Glass3def0cf2018-07-06 10:27:20 -0600658
Simon Glass34967c22018-09-14 04:57:06 -0600659 def add_subnode(self, parentoffset, name, quiet=()):
660 """Add a new subnode to a node
661
662 Args:
663 parentoffset: Parent offset to add the subnode to
664 name: Name of node to add
665
666 Returns:
667 offset of the node created, or negative error code on failure
668
669 Raises:
670 FdtError if there is not enough space, or another error occurs
671 """
672 return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
673
674 def del_node(self, nodeoffset, quiet=()):
Simon Glassc640ed02018-07-06 10:27:22 -0600675 """Delete a node
676
677 Args:
Simon Glass34967c22018-09-14 04:57:06 -0600678 nodeoffset: Offset of node to delete
679
680 Returns:
681 Error code, or 0 if OK
Simon Glassc640ed02018-07-06 10:27:22 -0600682
683 Raises:
Simon Glass34967c22018-09-14 04:57:06 -0600684 FdtError if an error occurs
Simon Glassc640ed02018-07-06 10:27:22 -0600685 """
Simon Glass34967c22018-09-14 04:57:06 -0600686 return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
Simon Glassc640ed02018-07-06 10:27:22 -0600687
Simon Glass3def0cf2018-07-06 10:27:20 -0600688
689class Property(bytearray):
Simon Glasscf2064d2017-05-27 07:38:11 -0600690 """Holds a device tree property name and value.
691
692 This holds a copy of a property taken from the device tree. It does not
693 reference the device tree, so if anything changes in the device tree,
694 a Property object will remain valid.
695
696 Properties:
697 name: Property name
Simon Glass3def0cf2018-07-06 10:27:20 -0600698 value: Property value as a bytearray
Simon Glasscf2064d2017-05-27 07:38:11 -0600699 """
700 def __init__(self, name, value):
Simon Glass3def0cf2018-07-06 10:27:20 -0600701 bytearray.__init__(self, value)
Simon Glasscf2064d2017-05-27 07:38:11 -0600702 self.name = name
Simon Glass3def0cf2018-07-06 10:27:20 -0600703
704 def as_cell(self, fmt):
705 return struct.unpack('>' + fmt, self)[0]
706
707 def as_uint32(self):
708 return self.as_cell('L')
709
710 def as_int32(self):
711 return self.as_cell('l')
712
713 def as_uint64(self):
714 return self.as_cell('Q')
715
716 def as_int64(self):
717 return self.as_cell('q')
718
719 def as_str(self):
Simon Glass50c59522018-07-26 14:02:13 -0600720 """Unicode is supported by decoding from UTF-8"""
721 if self[-1] != 0:
722 raise ValueError('Property lacks nul termination')
723 if 0 in self[:-1]:
724 raise ValueError('Property contains embedded nul characters')
725 return self[:-1].decode('utf-8')
Simon Glass3def0cf2018-07-06 10:27:20 -0600726
727
Simon Glass50c59522018-07-26 14:02:13 -0600728class FdtSw(FdtRo):
Simon Glass3def0cf2018-07-06 10:27:20 -0600729 """Software interface to create a device tree from scratch
730
731 The methods in this class work by adding to an existing 'partial' device
732 tree buffer of a fixed size created by instantiating this class. When the
Simon Glass50c59522018-07-26 14:02:13 -0600733 tree is complete, call as_fdt() to obtain a device tree ready to be used.
Simon Glass3def0cf2018-07-06 10:27:20 -0600734
735 Similarly with nodes, a new node is started with begin_node() and finished
736 with end_node().
737
738 The context manager functions can be used to make this a bit easier:
739
740 # First create the device tree with a node and property:
Simon Glass50c59522018-07-26 14:02:13 -0600741 sw = FdtSw()
Simon Glass903fe172019-10-31 07:43:00 -0600742 sw.finish_reservemap()
743 with sw.add_node(''):
744 with sw.add_node('node'):
745 sw.property_u32('reg', 2)
Simon Glass50c59522018-07-26 14:02:13 -0600746 fdt = sw.as_fdt()
Simon Glass3def0cf2018-07-06 10:27:20 -0600747
748 # Now we can use it as a real device tree
749 fdt.setprop_u32(0, 'reg', 3)
Simon Glass50c59522018-07-26 14:02:13 -0600750
751 The size hint provides a starting size for the space to be used by the
752 device tree. This will be increased automatically as needed as new items
753 are added to the tree.
Simon Glass3def0cf2018-07-06 10:27:20 -0600754 """
Simon Glass50c59522018-07-26 14:02:13 -0600755 INC_SIZE = 1024 # Expand size by this much when out of space
756
757 def __init__(self, size_hint=None):
758 """Create a new FdtSw object
759
760 Args:
761 size_hint: A hint as to the initial size to use
762
763 Raises:
764 ValueError if size_hint is negative
765
766 Returns:
767 FdtSw object on success, else integer error code (if not raising)
768 """
769 if not size_hint:
770 size_hint = self.INC_SIZE
771 fdtsw = bytearray(size_hint)
772 err = check_err(fdt_create(fdtsw, size_hint))
Simon Glass3def0cf2018-07-06 10:27:20 -0600773 if err:
774 return err
Simon Glass50c59522018-07-26 14:02:13 -0600775 self._fdt = fdtsw
Simon Glass3def0cf2018-07-06 10:27:20 -0600776
Simon Glass50c59522018-07-26 14:02:13 -0600777 def as_fdt(self):
Simon Glass3def0cf2018-07-06 10:27:20 -0600778 """Convert a FdtSw into an Fdt so it can be accessed as normal
779
Simon Glass50c59522018-07-26 14:02:13 -0600780 Creates a new Fdt object from the work-in-progress device tree. This
781 does not call fdt_finish() on the current object, so it is possible to
782 add more nodes/properties and call as_fdt() again to get an updated
783 tree.
Simon Glass3def0cf2018-07-06 10:27:20 -0600784
785 Returns:
786 Fdt object allowing access to the newly created device tree
787 """
Simon Glass50c59522018-07-26 14:02:13 -0600788 fdtsw = bytearray(self._fdt)
Simon Glass211cfa52020-09-01 05:13:56 -0600789 while self.check_space(fdt_finish(fdtsw)):
790 fdtsw = bytearray(self._fdt)
Simon Glass50c59522018-07-26 14:02:13 -0600791 return Fdt(fdtsw)
Simon Glass3def0cf2018-07-06 10:27:20 -0600792
Simon Glass50c59522018-07-26 14:02:13 -0600793 def check_space(self, val):
794 """Check if we need to add more space to the FDT
795
796 This should be called with the error code from an operation. If this is
797 -NOSPACE then the FDT will be expanded to have more space, and True will
798 be returned, indicating that the operation needs to be tried again.
799
800 Args:
801 val: Return value from the operation that was attempted
802
803 Returns:
804 True if the operation must be retried, else False
805 """
806 if check_err(val, QUIET_NOSPACE) < 0:
807 self.resize(len(self._fdt) + self.INC_SIZE)
808 return True
809 return False
810
811 def resize(self, size):
Simon Glass3def0cf2018-07-06 10:27:20 -0600812 """Resize the buffer to accommodate a larger tree
813
814 Args:
815 size: New size of tree
Simon Glass3def0cf2018-07-06 10:27:20 -0600816
817 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600818 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600819 """
820 fdt = bytearray(size)
Simon Glass50c59522018-07-26 14:02:13 -0600821 err = check_err(fdt_resize(self._fdt, fdt, size))
822 self._fdt = fdt
Simon Glass3def0cf2018-07-06 10:27:20 -0600823
Simon Glass50c59522018-07-26 14:02:13 -0600824 def add_reservemap_entry(self, addr, size):
Simon Glass3def0cf2018-07-06 10:27:20 -0600825 """Add a new memory reserve map entry
826
827 Once finished adding, you must call finish_reservemap().
828
829 Args:
830 addr: 64-bit start address
831 size: 64-bit size
Simon Glass3def0cf2018-07-06 10:27:20 -0600832
833 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600834 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600835 """
Simon Glass50c59522018-07-26 14:02:13 -0600836 while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
837 size)):
838 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600839
Simon Glass50c59522018-07-26 14:02:13 -0600840 def finish_reservemap(self):
Simon Glass3def0cf2018-07-06 10:27:20 -0600841 """Indicate that there are no more reserve map entries to add
842
Simon Glass3def0cf2018-07-06 10:27:20 -0600843 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600844 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600845 """
Simon Glass50c59522018-07-26 14:02:13 -0600846 while self.check_space(fdt_finish_reservemap(self._fdt)):
847 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600848
Simon Glass50c59522018-07-26 14:02:13 -0600849 def begin_node(self, name):
Simon Glass3def0cf2018-07-06 10:27:20 -0600850 """Begin a new node
851
852 Use this before adding properties to the node. Then call end_node() to
853 finish it. You can also use the context manager as shown in the FdtSw
854 class comment.
855
856 Args:
857 name: Name of node to begin
Simon Glass3def0cf2018-07-06 10:27:20 -0600858
859 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600860 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600861 """
Simon Glass50c59522018-07-26 14:02:13 -0600862 while self.check_space(fdt_begin_node(self._fdt, name)):
863 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600864
Simon Glass50c59522018-07-26 14:02:13 -0600865 def property_string(self, name, string):
Simon Glass3def0cf2018-07-06 10:27:20 -0600866 """Add a property with a string value
867
868 The string will be nul-terminated when written to the device tree
869
870 Args:
871 name: Name of property to add
872 string: String value of property
Simon Glass3def0cf2018-07-06 10:27:20 -0600873
874 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600875 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600876 """
Simon Glass50c59522018-07-26 14:02:13 -0600877 while self.check_space(fdt_property_string(self._fdt, name, string)):
878 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600879
Simon Glass50c59522018-07-26 14:02:13 -0600880 def property_u32(self, name, val):
Simon Glass3def0cf2018-07-06 10:27:20 -0600881 """Add a property with a 32-bit value
882
883 Write a single-cell value to the device tree
884
885 Args:
886 name: Name of property to add
887 val: Value of property
Simon Glass3def0cf2018-07-06 10:27:20 -0600888
889 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600890 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600891 """
Simon Glass50c59522018-07-26 14:02:13 -0600892 while self.check_space(fdt_property_u32(self._fdt, name, val)):
893 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600894
Simon Glass50c59522018-07-26 14:02:13 -0600895 def property_u64(self, name, val):
Simon Glass3def0cf2018-07-06 10:27:20 -0600896 """Add a property with a 64-bit value
897
898 Write a double-cell value to the device tree in big-endian format
899
900 Args:
901 name: Name of property to add
902 val: Value of property
Simon Glass3def0cf2018-07-06 10:27:20 -0600903
904 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600905 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600906 """
Simon Glass50c59522018-07-26 14:02:13 -0600907 while self.check_space(fdt_property_u64(self._fdt, name, val)):
908 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600909
Simon Glass50c59522018-07-26 14:02:13 -0600910 def property_cell(self, name, val):
Simon Glass3def0cf2018-07-06 10:27:20 -0600911 """Add a property with a single-cell value
912
913 Write a single-cell value to the device tree
914
915 Args:
916 name: Name of property to add
917 val: Value of property
918 quiet: Errors to ignore (empty to raise on all errors)
919
920 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600921 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600922 """
Simon Glass50c59522018-07-26 14:02:13 -0600923 while self.check_space(fdt_property_cell(self._fdt, name, val)):
924 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600925
Simon Glass50c59522018-07-26 14:02:13 -0600926 def property(self, name, val):
Simon Glass3def0cf2018-07-06 10:27:20 -0600927 """Add a property
928
929 Write a new property with the given value to the device tree. The value
930 is taken as is and is not nul-terminated
931
932 Args:
933 name: Name of property to add
934 val: Value of property
935 quiet: Errors to ignore (empty to raise on all errors)
936
937 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600938 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600939 """
Simon Glass50c59522018-07-26 14:02:13 -0600940 while self.check_space(fdt_property_stub(self._fdt, name, val,
941 len(val))):
942 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600943
Simon Glass50c59522018-07-26 14:02:13 -0600944 def end_node(self):
Simon Glass3def0cf2018-07-06 10:27:20 -0600945 """End a node
946
947 Use this after adding properties to a node to close it off. You can also
948 use the context manager as shown in the FdtSw class comment.
949
950 Args:
951 quiet: Errors to ignore (empty to raise on all errors)
952
953 Raises:
Simon Glass50c59522018-07-26 14:02:13 -0600954 FdtException on any error
Simon Glass3def0cf2018-07-06 10:27:20 -0600955 """
Simon Glass50c59522018-07-26 14:02:13 -0600956 while self.check_space(fdt_end_node(self._fdt)):
957 pass
Simon Glass3def0cf2018-07-06 10:27:20 -0600958
Simon Glass50c59522018-07-26 14:02:13 -0600959 def add_node(self, name):
Simon Glass3def0cf2018-07-06 10:27:20 -0600960 """Create a new context for adding a node
961
962 When used in a 'with' clause this starts a new node and finishes it
963 afterward.
964
965 Args:
966 name: Name of node to add
967 """
Simon Glass50c59522018-07-26 14:02:13 -0600968 return NodeAdder(self, name)
Simon Glass3def0cf2018-07-06 10:27:20 -0600969
970
971class NodeAdder():
972 """Class to provide a node context
973
974 This allows you to add nodes in a more natural way:
975
Simon Glass50c59522018-07-26 14:02:13 -0600976 with fdtsw.add_node('name'):
Simon Glass3def0cf2018-07-06 10:27:20 -0600977 fdtsw.property_string('test', 'value')
978
979 The node is automatically completed with a call to end_node() when the
980 context exits.
981 """
Simon Glass50c59522018-07-26 14:02:13 -0600982 def __init__(self, fdtsw, name):
983 self._fdt = fdtsw
Simon Glass3def0cf2018-07-06 10:27:20 -0600984 self._name = name
985
986 def __enter__(self):
Simon Glass50c59522018-07-26 14:02:13 -0600987 self._fdt.begin_node(self._name)
Simon Glass3def0cf2018-07-06 10:27:20 -0600988
989 def __exit__(self, type, value, traceback):
Simon Glass50c59522018-07-26 14:02:13 -0600990 self._fdt.end_node()
Simon Glasscf2064d2017-05-27 07:38:11 -0600991%}
992
993%rename(fdt_property) fdt_property_func;
994
Simon Glass50c59522018-07-26 14:02:13 -0600995/*
996 * fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
997 * so use the same type here.
998 */
999typedef uint32_t fdt32_t;
Simon Glasscf2064d2017-05-27 07:38:11 -06001000
1001%include "libfdt/fdt.h"
1002
1003%include "typemaps.i"
1004
1005/* Most functions don't change the device tree, so use a const void * */
1006%typemap(in) (const void *)(const void *fdt) {
1007 if (!PyByteArray_Check($input)) {
1008 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1009 "', argument " "$argnum"" of type '" "$type""'");
1010 }
1011 $1 = (void *)PyByteArray_AsString($input);
1012 fdt = $1;
1013 fdt = fdt; /* avoid unused variable warning */
1014}
1015
1016/* Some functions do change the device tree, so use void * */
1017%typemap(in) (void *)(const void *fdt) {
1018 if (!PyByteArray_Check($input)) {
1019 SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
1020 "', argument " "$argnum"" of type '" "$type""'");
1021 }
1022 $1 = PyByteArray_AsString($input);
1023 fdt = $1;
1024 fdt = fdt; /* avoid unused variable warning */
1025}
1026
Simon Glass3def0cf2018-07-06 10:27:20 -06001027/* typemap used for fdt_get_property_by_offset() */
Simon Glasscf2064d2017-05-27 07:38:11 -06001028%typemap(out) (struct fdt_property *) {
1029 PyObject *buff;
1030
1031 if ($1) {
1032 resultobj = PyString_FromString(
1033 fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
1034 buff = PyByteArray_FromStringAndSize(
1035 (const char *)($1 + 1), fdt32_to_cpu($1->len));
1036 resultobj = SWIG_Python_AppendOutput(resultobj, buff);
1037 }
1038}
1039
1040%apply int *OUTPUT { int *lenp };
1041
1042/* typemap used for fdt_getprop() */
1043%typemap(out) (const void *) {
1044 if (!$1)
1045 $result = Py_None;
1046 else
Simon Glass903fe172019-10-31 07:43:00 -06001047 %#if PY_VERSION_HEX >= 0x03000000
1048 $result = Py_BuildValue("y#", $1, *arg4);
1049 %#else
1050 $result = Py_BuildValue("s#", $1, *arg4);
1051 %#endif
Simon Glasscf2064d2017-05-27 07:38:11 -06001052}
1053
Simon Glass3def0cf2018-07-06 10:27:20 -06001054/* typemap used for fdt_setprop() */
1055%typemap(in) (const void *val) {
Simon Glass903fe172019-10-31 07:43:00 -06001056 %#if PY_VERSION_HEX >= 0x03000000
1057 if (!PyBytes_Check($input)) {
1058 SWIG_exception_fail(SWIG_TypeError, "bytes expected in method '" "$symname"
1059 "', argument " "$argnum"" of type '" "$type""'");
1060 }
1061 $1 = PyBytes_AsString($input);
1062 %#else
1063 $1 = PyString_AsString($input); /* char *str */
1064 %#endif
Simon Glass3def0cf2018-07-06 10:27:20 -06001065}
1066
1067/* typemaps used for fdt_next_node() */
1068%typemap(in, numinputs=1) int *depth (int depth) {
1069 depth = (int) PyInt_AsLong($input);
1070 $1 = &depth;
1071}
1072
1073%typemap(argout) int *depth {
1074 PyObject *val = Py_BuildValue("i", *arg$argnum);
1075 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1076}
1077
1078%apply int *depth { int *depth };
1079
1080/* typemaps for fdt_get_mem_rsv */
1081%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
1082 $1 = &temp;
1083}
1084
1085%typemap(argout) uint64_t * {
Simon Glass903fe172019-10-31 07:43:00 -06001086 PyObject *val = PyLong_FromUnsignedLongLong(*arg$argnum);
Simon Glass3def0cf2018-07-06 10:27:20 -06001087 if (!result) {
1088 if (PyTuple_GET_SIZE(resultobj) == 0)
1089 resultobj = val;
1090 else
1091 resultobj = SWIG_Python_AppendOutput(resultobj, val);
1092 }
1093}
1094
Simon Glasscf2064d2017-05-27 07:38:11 -06001095/* We have both struct fdt_property and a function fdt_property() */
1096%warnfilter(302) fdt_property;
1097
1098/* These are macros in the header so have to be redefined here */
Simon Glass50c59522018-07-26 14:02:13 -06001099uint32_t fdt_magic(const void *fdt);
1100uint32_t fdt_totalsize(const void *fdt);
1101uint32_t fdt_off_dt_struct(const void *fdt);
1102uint32_t fdt_off_dt_strings(const void *fdt);
1103uint32_t fdt_off_mem_rsvmap(const void *fdt);
1104uint32_t fdt_version(const void *fdt);
1105uint32_t fdt_last_comp_version(const void *fdt);
1106uint32_t fdt_boot_cpuid_phys(const void *fdt);
1107uint32_t fdt_size_dt_strings(const void *fdt);
1108uint32_t fdt_size_dt_struct(const void *fdt);
1109
Simon Glass3def0cf2018-07-06 10:27:20 -06001110int fdt_property_string(void *fdt, const char *name, const char *val);
1111int fdt_property_cell(void *fdt, const char *name, uint32_t val);
1112
1113/*
1114 * This function has a stub since the name fdt_property is used for both a
1115 * function and a struct, which confuses SWIG.
1116 */
Simon Glass97de5322019-10-31 07:43:01 -06001117int fdt_property_stub(void *fdt, const char *name, const void *val, int len);
Simon Glasscf2064d2017-05-27 07:38:11 -06001118
1119%include <../libfdt/libfdt.h>